/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hive.hplsql; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Stack; import java.util.UUID; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; import org.apache.hive.hplsql.Var.Type; /** * HPL/SQL statements execution */ public class Stmt { Exec exec = null; Stack<Var> stack = null; Conf conf; Meta meta; boolean trace = false; Stmt(Exec e) { exec = e; stack = exec.getStack(); conf = exec.getConf(); meta = exec.getMeta(); trace = exec.getTrace(); } /** * ALLOCATE CURSOR statement */ public Integer allocateCursor(HplsqlParser.Allocate_cursor_stmtContext ctx) { trace(ctx, "ALLOCATE CURSOR"); String name = ctx.ident(0).getText(); Var cur = null; if (ctx.T_PROCEDURE() != null) { cur = exec.consumeReturnCursor(ctx.ident(1).getText()); } else if (ctx.T_RESULT() != null) { cur = exec.findVariable(ctx.ident(1).getText()); if (cur != null && cur.type != Type.RS_LOCATOR) { cur = null; } } if (cur == null) { trace(ctx, "Cursor for procedure not found: " + name); exec.signal(Signal.Type.SQLEXCEPTION); return -1; } exec.addVariable(new Var(name, Type.CURSOR, cur.value)); return 0; } /** * ASSOCIATE LOCATOR statement */ public Integer associateLocator(HplsqlParser.Associate_locator_stmtContext ctx) { trace(ctx, "ASSOCIATE LOCATOR"); int cnt = ctx.ident().size(); if (cnt < 2) { return -1; } String procedure = ctx.ident(cnt - 1).getText(); for (int i = 0; i < cnt - 1; i++) { Var cur = exec.consumeReturnCursor(procedure); if (cur != null) { String name = ctx.ident(i).getText(); Var loc = exec.findVariable(name); if (loc == null) { loc = new Var(name, Type.RS_LOCATOR, cur.value); exec.addVariable(loc); } else { loc.setValue(cur.value); } } } return 0; } /** * DECLARE cursor statement */ public Integer declareCursor(HplsqlParser.Declare_cursor_itemContext ctx) { String name = ctx.ident().getText(); if (trace) { trace(ctx, "DECLARE CURSOR " + name); } Query query = new Query(); if (ctx.expr() != null) { query.setExprCtx(ctx.expr()); } else if (ctx.select_stmt() != null) { query.setSelectCtx(ctx.select_stmt()); } if (ctx.cursor_with_return() != null) { query.setWithReturn(true); } Var var = new Var(name, Type.CURSOR, query); exec.addVariable(var); return 0; } /** * CREATE TABLE statement */ public Integer createTable(HplsqlParser.Create_table_stmtContext ctx) { trace(ctx, "CREATE TABLE"); StringBuilder sql = new StringBuilder(); exec.append(sql, ctx.T_CREATE(), ctx.T_TABLE()); exec.append(sql, evalPop(ctx.table_name()).toString(), ctx.T_TABLE().getSymbol(), ctx.table_name().getStart()); Token last = ctx.table_name().getStop(); if (ctx.create_table_preoptions() != null) { String preopt = evalPop(ctx.create_table_preoptions()).toString(); if (preopt != null) { sql.append(" " + preopt); } last = ctx.create_table_preoptions().stop; } sql.append(createTableDefinition(ctx.create_table_definition(), last)); trace(ctx, sql.toString()); Query query = exec.executeSql(ctx, sql.toString(), exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * Get CREATE TABLE definition (columns or query) */ String createTableDefinition(HplsqlParser.Create_table_definitionContext ctx, Token last) { StringBuilder sql = new StringBuilder(); HplsqlParser.Create_table_columnsContext colCtx = ctx.create_table_columns(); if (colCtx != null) { int cnt = colCtx.create_table_columns_item().size(); for (int i = 0; i < cnt; i++) { HplsqlParser.Create_table_columns_itemContext col = colCtx.create_table_columns_item(i); if (col.create_table_column_cons() != null) { last = col.getStop(); continue; } exec.append(sql, evalPop(col.column_name()).toString(), last, col.column_name().getStop()); exec.append(sql, exec.evalPop(col.dtype(), col.dtype_len()), col.column_name().getStop(), col.dtype().getStart()); last = col.getStop(); } exec.append(sql, ctx.T_CLOSE_P().getText(), last, ctx.T_CLOSE_P().getSymbol()); } // CREATE TABLE AS SELECT statement else { exec.append(sql, evalPop(ctx.select_stmt()).toString(), last, ctx.select_stmt().getStart()); if (ctx.T_CLOSE_P() != null) { exec.append(sql, ctx.T_CLOSE_P().getText(), ctx.select_stmt().stop, ctx.T_CLOSE_P().getSymbol()); } } HplsqlParser.Create_table_optionsContext options = ctx.create_table_options(); if (options != null) { String opt = evalPop(options).toString(); if (opt != null) { sql.append(" " + opt); } } return sql.toString(); } /** * CREATE TABLE options for Hive */ public Integer createTableHiveOptions(HplsqlParser.Create_table_options_hive_itemContext ctx) { if (ctx.create_table_hive_row_format() != null) { createTableHiveRowFormat(ctx.create_table_hive_row_format()); } else if (ctx.T_STORED() != null) { evalString(exec.getText(ctx)); } return 0; } public Integer createTableHiveRowFormat(HplsqlParser.Create_table_hive_row_formatContext ctx) { StringBuilder sql = new StringBuilder(); sql.append("ROW FORMAT DELIMITED"); int cnt = ctx.create_table_hive_row_format_fields().size(); for (int i = 0; i < cnt; i++) { HplsqlParser.Create_table_hive_row_format_fieldsContext c = ctx.create_table_hive_row_format_fields(i); if (c.T_FIELDS() != null) { sql.append(" FIELDS TERMINATED BY " + evalPop(c.expr(0)).toSqlString()); } else if (c.T_LINES() != null) { sql.append(" LINES TERMINATED BY " + evalPop(c.expr(0)).toSqlString()); } } evalString(sql); return 0; } /** * CREATE TABLE options for MySQL */ public Integer createTableMysqlOptions(HplsqlParser.Create_table_options_mysql_itemContext ctx) { if (ctx.T_COMMENT() != null) { evalString(ctx.T_COMMENT().getText() + " " + evalPop(ctx.expr()).toSqlString()); } return 0; } /** * DECLARE TEMPORARY TABLE statement */ public Integer declareTemporaryTable(HplsqlParser.Declare_temporary_table_itemContext ctx) { trace(ctx, "DECLARE TEMPORARY TABLE"); return createTemporaryTable(ctx.ident(), ctx.create_table_definition(), ctx.create_table_preoptions()); } /** * CREATE DATABASE | SCHEMA statement */ public Integer createDatabase(HplsqlParser.Create_database_stmtContext ctx) { trace(ctx, "CREATE DATABASE"); StringBuilder sql = new StringBuilder(); sql.append(ctx.T_CREATE().getText() + " "); if (ctx.T_DATABASE() != null) { sql.append(ctx.T_DATABASE().getText() + " "); } else { sql.append(ctx.T_SCHEMA().getText() + " "); } if (ctx.T_IF() != null) { sql.append(exec.getText(ctx, ctx.T_IF().getSymbol(), ctx.T_EXISTS().getSymbol()) + " "); } sql.append(evalPop(ctx.expr()).toString()); int cnt = ctx.create_database_option().size(); for (int i = 0; i < cnt; i++) { HplsqlParser.Create_database_optionContext option = ctx.create_database_option(i); if (option.T_COMMENT() != null) { sql.append(" " + option.T_COMMENT().getText() + " " + evalPop(option.expr()).toSqlString()); } else if (option.T_LOCATION() != null) { sql.append(" " + option.T_LOCATION().getText() + " " + evalPop(option.expr()).toSqlString()); } } trace(ctx, sql.toString()); Query query = exec.executeSql(ctx, sql.toString(), exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * CREATE LOCAL TEMPORARY | VOLATILE TABLE statement */ public Integer createLocalTemporaryTable(HplsqlParser.Create_local_temp_table_stmtContext ctx) { trace(ctx, "CREATE LOCAL TEMPORARY TABLE"); return createTemporaryTable(ctx.ident(), ctx.create_table_definition(), ctx.create_table_preoptions()); } /** * Create a temporary table statement */ public Integer createTemporaryTable(HplsqlParser.IdentContext identCtx, HplsqlParser.Create_table_definitionContext defCtx, HplsqlParser.Create_table_preoptionsContext optCtx) { StringBuilder sql = new StringBuilder(); String name = identCtx.getText(); String managedName = null; Token last = identCtx.getStop(); if (optCtx != null) { last = optCtx.stop; } if (conf.tempTables == Conf.TempTables.NATIVE) { sql.append("CREATE TEMPORARY TABLE " + name); sql.append(createTableDefinition(defCtx, last)); } else if (conf.tempTables == Conf.TempTables.MANAGED) { managedName = name + "_" + UUID.randomUUID().toString().replace("-",""); if (!conf.tempTablesSchema.isEmpty()) { managedName = conf.tempTablesSchema + "." + managedName; } sql.append("CREATE TABLE " + managedName); sql.append(createTableDefinition(defCtx, last)); if (!conf.tempTablesLocation.isEmpty()) { sql.append("\nLOCATION '" + conf.tempTablesLocation + "/" + managedName + "'"); } if (trace) { trace(null, "Managed table name: " + managedName); } } if (trace) { trace(null, sql.toString()); } if (sql != null) { Query query = exec.executeSql(null, sql.toString(), exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } if (managedName != null) { exec.addManagedTable(name, managedName); } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); } return 0; } /** * DESCRIBE statement */ public Integer describe(HplsqlParser.Describe_stmtContext ctx) { trace(ctx, "DESCRIBE"); String sql = "DESCRIBE " + evalPop(ctx.table_name()).toString(); trace(ctx, sql); Query query = exec.executeSql(ctx, sql, exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } try { ResultSet rs = query.getResultSet(); ResultSetMetaData rm = null; if (rs != null) { rm = rs.getMetaData(); int cols = rm.getColumnCount(); while (rs.next()) { for (int i = 1; i <= cols; i++) { if (i > 1) { System.out.print("\t"); } System.out.print(rs.getString(i)); } System.out.println(""); } } } catch (SQLException e) { exec.signal(query); exec.closeQuery(query, exec.conf.defaultConnection); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * DROP statement */ public Integer drop(HplsqlParser.Drop_stmtContext ctx) { trace(ctx, "DROP"); String sql = null; if (ctx.T_TABLE() != null) { sql = "DROP TABLE "; if (ctx.T_EXISTS() != null) { sql += "IF EXISTS "; } sql += evalPop(ctx.table_name()).toString(); } else if (ctx.T_DATABASE() != null || ctx.T_SCHEMA() != null) { sql = "DROP DATABASE "; if (ctx.T_EXISTS() != null) { sql += "IF EXISTS "; } sql += evalPop(ctx.expr()).toString(); } if (sql != null) { trace(ctx, sql); Query query = exec.executeSql(ctx, sql, exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); } return 0; } /** * TRUNCATE statement */ public Integer truncate(HplsqlParser.Truncate_stmtContext ctx) { trace(ctx, "TRUNCATE"); String sql = "TRUNCATE TABLE " + evalPop(ctx.table_name()).toString(); trace(ctx, sql); Query query = exec.executeSql(ctx, sql, exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * OPEN cursor statement */ public Integer open(HplsqlParser.Open_stmtContext ctx) { trace(ctx, "OPEN"); Query query = null; Var var = null; String cursor = ctx.L_ID().toString(); String sql = null; if (ctx.T_FOR() != null) { // SELECT statement or dynamic SQL if (ctx.expr() != null) { sql = evalPop(ctx.expr()).toString(); } else { sql = evalPop(ctx.select_stmt()).toString(); } query = new Query(sql); var = exec.findCursor(cursor); // Can be a ref cursor variable if (var == null) { var = new Var(cursor, Type.CURSOR, query); exec.addVariable(var); } else { var.setValue(query); } } else { // Declared cursor var = exec.findVariable(cursor); if (var != null && var.type == Type.CURSOR) { query = (Query)var.value; if (query.sqlExpr != null) { sql = evalPop(query.sqlExpr).toString(); query.setSql(sql); } else if (query.sqlSelect != null) { sql = evalPop(query.sqlSelect).toString(); query.setSql(sql); } } } if (query != null) { if (trace) { trace(ctx, cursor + ": " + sql); } exec.executeQuery(ctx, query, exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } else if (!exec.getOffline()) { exec.setSqlCode(0); } if (query.getWithReturn()) { exec.addReturnCursor(var); } } else { trace(ctx, "Cursor not found: " + cursor); exec.setSqlCode(-1); exec.signal(Signal.Type.SQLEXCEPTION); return 1; } return 0; } /** * FETCH cursor statement */ public Integer fetch(HplsqlParser.Fetch_stmtContext ctx) { trace(ctx, "FETCH"); String name = ctx.L_ID(0).toString(); Var cursor = exec.findCursor(name); if (cursor == null) { trace(ctx, "Cursor not found: " + name); exec.setSqlCode(-1); exec.signal(Signal.Type.SQLEXCEPTION); return 1; } else if (cursor.value == null) { trace(ctx, "Cursor not open: " + name); exec.setSqlCode(-1); exec.signal(Signal.Type.SQLEXCEPTION); return 1; } else if (exec.getOffline()) { exec.setSqlCode(100); exec.signal(Signal.Type.NOTFOUND); return 0; } // Assign values from the row to local variables try { Query query = (Query)cursor.value; ResultSet rs = query.getResultSet(); ResultSetMetaData rsm = null; if(rs != null) { rsm = rs.getMetaData(); } if(rs != null && rsm != null) { int cols = ctx.L_ID().size() - 1; if(rs.next()) { query.setFetch(true); for(int i=1; i <= cols; i++) { Var var = exec.findVariable(ctx.L_ID(i).getText()); if(var != null) { if (var.type != Var.Type.ROW) { var.setValue(rs, rsm, i); } else { var.setValues(rs, rsm); } if (trace) { trace(ctx, var, rs, rsm, i); } } else if(trace) { trace(ctx, "Variable not found: " + ctx.L_ID(i).getText()); } } exec.incRowCount(); exec.setSqlSuccess(); } else { query.setFetch(false); exec.setSqlCode(100); } } else { exec.setSqlCode(-1); } } catch (SQLException e) { exec.setSqlCode(e); exec.signal(Signal.Type.SQLEXCEPTION, e.getMessage(), e); } return 0; } /** * CLOSE cursor statement */ public Integer close(HplsqlParser.Close_stmtContext ctx) { trace(ctx, "CLOSE"); String name = ctx.L_ID().toString(); Var var = exec.findVariable(name); if(var != null && var.type == Type.CURSOR) { exec.closeQuery((Query)var.value, exec.conf.defaultConnection); exec.setSqlCode(0); } else if(trace) { trace(ctx, "Cursor not found: " + name); } return 0; } /** * INCLUDE statement */ public Integer include(HplsqlParser.Include_stmtContext ctx) { String file; if (ctx.file_name() != null) { file = ctx.file_name().getText(); } else { file = evalPop(ctx.expr()).toString(); } trace(ctx, "INCLUDE " + file); exec.includeFile(file, true); return 0; } /** * IF statement (PL/SQL syntax) */ public Integer ifPlsql(HplsqlParser.If_plsql_stmtContext ctx) { boolean trueExecuted = false; trace(ctx, "IF"); if (evalPop(ctx.bool_expr()).isTrue()) { trace(ctx, "IF TRUE executed"); visit(ctx.block()); trueExecuted = true; } else if (ctx.elseif_block() != null) { int cnt = ctx.elseif_block().size(); for (int i = 0; i < cnt; i++) { if (evalPop(ctx.elseif_block(i).bool_expr()).isTrue()) { trace(ctx, "ELSE IF executed"); visit(ctx.elseif_block(i).block()); trueExecuted = true; break; } } } if (!trueExecuted && ctx.else_block() != null) { trace(ctx, "ELSE executed"); visit(ctx.else_block()); } return 0; } /** * IF statement (Transact-SQL syntax) */ public Integer ifTsql(HplsqlParser.If_tsql_stmtContext ctx) { trace(ctx, "IF"); visit(ctx.bool_expr()); if(exec.stackPop().isTrue()) { trace(ctx, "IF TRUE executed"); visit(ctx.single_block_stmt(0)); } else if(ctx.T_ELSE() != null) { trace(ctx, "ELSE executed"); visit(ctx.single_block_stmt(1)); } return 0; } /** * IF statement (BTEQ syntax) */ public Integer ifBteq(HplsqlParser.If_bteq_stmtContext ctx) { trace(ctx, "IF"); visit(ctx.bool_expr()); if (exec.stackPop().isTrue()) { trace(ctx, "IF TRUE executed"); visit(ctx.single_block_stmt()); } return 0; } /** * Assignment from SELECT statement */ public Integer assignFromSelect(HplsqlParser.Assignment_stmt_select_itemContext ctx) { String sql = evalPop(ctx.select_stmt()).toString(); if (trace) { trace(ctx, sql.toString()); } String conn = exec.getStatementConnection(); Query query = exec.executeQuery(ctx, sql.toString(), conn); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); try { ResultSet rs = query.getResultSet(); ResultSetMetaData rm = null; if (rs != null) { rm = rs.getMetaData(); int cnt = ctx.ident().size(); if (rs.next()) { for (int i = 1; i <= cnt; i++) { Var var = exec.findVariable(ctx.ident(i-1).getText()); if (var != null) { var.setValue(rs, rm, i); if (trace) { trace(ctx, "COLUMN: " + rm.getColumnName(i) + ", " + rm.getColumnTypeName(i)); trace(ctx, "SET " + var.getName() + " = " + var.toString()); } } else if(trace) { trace(ctx, "Variable not found: " + ctx.ident(i-1).getText()); } } exec.incRowCount(); exec.setSqlSuccess(); } else { exec.setSqlCode(100); exec.signal(Signal.Type.NOTFOUND); } } } catch (SQLException e) { exec.signal(query); return 1; } finally { exec.closeQuery(query, conn); } return 0; } /** * SQL INSERT statement */ public Integer insert(HplsqlParser.Insert_stmtContext ctx) { exec.stmtConnList.clear(); if (ctx.select_stmt() != null) { return insertSelect(ctx); } return insertValues(ctx); } /** * SQL INSERT SELECT statement */ public Integer insertSelect(HplsqlParser.Insert_stmtContext ctx) { trace(ctx, "INSERT SELECT"); StringBuilder sql = new StringBuilder(); sql.append(ctx.T_INSERT().getText() + " "); if (ctx.T_OVERWRITE() != null) { sql.append(ctx.T_OVERWRITE().getText() + " " + ctx.T_TABLE().getText() + " "); } else { sql.append(ctx.T_INTO().getText() + " "); if (ctx.T_TABLE() != null) { sql.append(ctx.T_TABLE().getText() + " "); } } sql.append(evalPop(ctx.table_name()).toString() + " "); sql.append(evalPop(ctx.select_stmt()).toString()); trace(ctx, sql.toString()); Query query = exec.executeSql(ctx, sql.toString(), exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * SQL INSERT VALUES statement */ public Integer insertValues(HplsqlParser.Insert_stmtContext ctx) { trace(ctx, "INSERT VALUES"); String table = evalPop(ctx.table_name()).toString(); String conn = exec.getObjectConnection(ctx.table_name().getText()); Conn.Type type = exec.getConnectionType(conn); StringBuilder sql = new StringBuilder(); if (type == Conn.Type.HIVE) { sql.append("INSERT INTO TABLE " + table + " "); if (conf.insertValues == Conf.InsertValues.NATIVE) { sql.append("VALUES\n("); } } else { sql.append("INSERT INTO " + table); if (ctx.insert_stmt_cols() != null) { sql.append(" " + exec.getFormattedText(ctx.insert_stmt_cols())); } sql.append(" VALUES\n("); } int rows = ctx.insert_stmt_rows().insert_stmt_row().size(); for (int i = 0; i < rows; i++) { HplsqlParser.Insert_stmt_rowContext row =ctx.insert_stmt_rows().insert_stmt_row(i); int cols = row.expr().size(); for (int j = 0; j < cols; j++) { String value = evalPop(row.expr(j)).toSqlString(); if (j == 0 && type == Conn.Type.HIVE && conf.insertValues == Conf.InsertValues.SELECT ) { sql.append("SELECT "); } sql.append(value); if (j + 1 != cols) { sql.append(", "); } } if (type != Conn.Type.HIVE || conf.insertValues == Conf.InsertValues.NATIVE) { if (i + 1 == rows) { sql.append(")"); } else { sql.append("),\n("); } } else if (type == Conn.Type.HIVE && conf.insertValues == Conf.InsertValues.SELECT) { if (conf.dualTable != null) { sql.append(" FROM " + conf.dualTable); } if (i + 1 < rows) { sql.append("\nUNION ALL\n"); } } } if (trace) { trace(ctx, sql.toString()); } Query query = exec.executeSql(ctx, sql.toString(), conn); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, conn); return 0; } /** * INSERT DIRECTORY statement */ public Integer insertDirectory(HplsqlParser.Insert_directory_stmtContext ctx) { trace(ctx, "INSERT DIRECTORY"); StringBuilder sql = new StringBuilder(); sql.append(ctx.T_INSERT().getText() + " " + ctx.T_OVERWRITE().getText() + " "); if (ctx.T_LOCAL() != null) { sql.append(ctx.T_LOCAL().getText() + " "); } sql.append(ctx.T_DIRECTORY().getText() + " " + evalPop(ctx.expr_file()).toSqlString() + " "); sql.append(evalPop(ctx.expr_select()).toString()); String conn = exec.getStatementConnection(); trace(ctx, sql.toString()); Query query = exec.executeSql(ctx, sql.toString(), conn); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, conn); return 0; } /** * GET DIAGNOSTICS EXCEPTION statement */ public Integer getDiagnosticsException(HplsqlParser.Get_diag_stmt_exception_itemContext ctx) { trace(ctx, "GET DIAGNOSTICS EXCEPTION"); Signal signal = exec.signalPeek(); if (signal == null || (signal != null && signal.type != Signal.Type.SQLEXCEPTION)) { signal = exec.currentSignal; } if (signal != null) { exec.setVariable(ctx.ident().getText(), signal.getValue()); } return 0; } /** * GET DIAGNOSTICS ROW_COUNT statement */ public Integer getDiagnosticsRowCount(HplsqlParser.Get_diag_stmt_rowcount_itemContext ctx) { trace(ctx, "GET DIAGNOSTICS ROW_COUNT"); exec.setVariable(ctx.ident().getText(), exec.getRowCount()); return 0; } /** * USE statement */ public Integer use(HplsqlParser.Use_stmtContext ctx) { trace(ctx, "USE"); return use(ctx, ctx.T_USE().toString() + " " + meta.normalizeIdentifierPart(evalPop(ctx.expr()).toString())); } public Integer use(ParserRuleContext ctx, String sql) { if(trace) { trace(ctx, "SQL statement: " + sql); } Query query = exec.executeSql(ctx, sql, exec.conf.defaultConnection); if(query.error()) { exec.signal(query); return 1; } exec.setSqlCode(0); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * VALUES statement */ public Integer values(HplsqlParser.Values_into_stmtContext ctx) { trace(ctx, "VALUES statement"); int cnt = ctx.ident().size(); // Number of variables and assignment expressions int ecnt = ctx.expr().size(); for (int i = 0; i < cnt; i++) { String name = ctx.ident(i).getText(); if (i < ecnt) { visit(ctx.expr(i)); Var var = exec.setVariable(name); if (trace) { trace(ctx, "SET " + name + " = " + var.toString()); } } } return 0; } /** * WHILE statement */ public Integer while_(HplsqlParser.While_stmtContext ctx) { trace(ctx, "WHILE - ENTERED"); String label = exec.labelPop(); while (true) { if (evalPop(ctx.bool_expr()).isTrue()) { exec.enterScope(Scope.Type.LOOP); visit(ctx.block()); exec.leaveScope(); if (canContinue(label)) { continue; } } break; } trace(ctx, "WHILE - LEFT"); return 0; } /** * FOR cursor statement */ public Integer forCursor(HplsqlParser.For_cursor_stmtContext ctx) { trace(ctx, "FOR CURSOR - ENTERED"); exec.enterScope(Scope.Type.LOOP); String cursor = ctx.L_ID().getText(); String sql = evalPop(ctx.select_stmt()).toString(); trace(ctx, sql); Query query = exec.executeQuery(ctx, sql, exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } trace(ctx, "SELECT completed successfully"); exec.setSqlSuccess(); try { ResultSet rs = query.getResultSet(); if (rs != null) { ResultSetMetaData rm = rs.getMetaData(); int cols = rm.getColumnCount(); Row row = new Row(); for (int i = 1; i <= cols; i++) { row.addColumn(rm.getColumnName(i), rm.getColumnTypeName(i)); } Var var = new Var(cursor, row); exec.addVariable(var); while (rs.next()) { var.setValues(rs, rm); if (trace) { trace(ctx, var, rs, rm, 0); } visit(ctx.block()); exec.incRowCount(); } } } catch (SQLException e) { exec.signal(e); exec.closeQuery(query, exec.conf.defaultConnection); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); exec.leaveScope(); trace(ctx, "FOR CURSOR - LEFT"); return 0; } /** * FOR (integer range) statement */ public Integer forRange(HplsqlParser.For_range_stmtContext ctx) { trace(ctx, "FOR RANGE - ENTERED"); int start = evalPop(ctx.expr(0)).intValue(); int end = evalPop(ctx.expr(1)).intValue(); int step = evalPop(ctx.expr(2), 1L).intValue(); exec.enterScope(Scope.Type.LOOP); Var index = setIndex(start, end, ctx); exec.addVariable(index); for (int i = start; i <= end; i += step) { visit(ctx.block()); updateIndex(step, index, ctx); } exec.leaveScope(); trace(ctx, "FOR RANGE - LEFT"); return 0; } /** * To set the Value index for FOR Statement */ private Var setIndex(int start, int end, HplsqlParser.For_range_stmtContext ctx) { if (ctx.T_REVERSE() == null) return new Var(ctx.L_ID().getText(), new Long(start)); else return new Var(ctx.L_ID().getText(), new Long(end)); } /** * To update the value of index for FOR Statement */ private void updateIndex(int step, Var index, HplsqlParser.For_range_stmtContext ctx) { if (ctx.T_REVERSE() == null) index.increment(new Long(step)); else index.decrement(new Long(step)); } /** * EXEC, EXECUTE and EXECUTE IMMEDIATE statement to execute dynamic SQL or stored procedure */ public Integer exec(HplsqlParser.Exec_stmtContext ctx) { if (execProc(ctx)) { return 0; } trace(ctx, "EXECUTE"); Var vsql = evalPop(ctx.expr()); String sql = vsql.toString(); if (trace) { trace(ctx, "SQL statement: " + sql); } Query query = exec.executeSql(ctx, sql, exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } ResultSet rs = query.getResultSet(); if (rs != null) { try { ResultSetMetaData rm = rs.getMetaData(); if (ctx.T_INTO() != null) { int cols = ctx.L_ID().size(); if (rs.next()) { for (int i = 0; i < cols; i++) { Var var = exec.findVariable(ctx.L_ID(i).getText()); if (var != null) { if (var.type != Var.Type.ROW) { var.setValue(rs, rm, i + 1); } else { var.setValues(rs, rm); } if (trace) { trace(ctx, var, rs, rm, i + 1); } } else if (trace) { trace(ctx, "Variable not found: " + ctx.L_ID(i).getText()); } } exec.setSqlCode(0); } } // Print the results else { int cols = rm.getColumnCount(); while(rs.next()) { for(int i = 1; i <= cols; i++) { if(i > 1) { System.out.print("\t"); } System.out.print(rs.getString(i)); } System.out.println(""); } } } catch(SQLException e) { exec.setSqlCode(e); } } exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * EXEC to execute a stored procedure */ public Boolean execProc(HplsqlParser.Exec_stmtContext ctx) { String name = evalPop(ctx.expr()).toString(); if (exec.function.isProc(name)) { if (exec.function.execProc(name, ctx.expr_func_params(), ctx)) { return true; } } return false; } /** * EXIT statement (leave the specified loop with a condition) */ public Integer exit(HplsqlParser.Exit_stmtContext ctx) { trace(ctx, "EXIT"); String label = ""; if (ctx.L_ID() != null) { label = ctx.L_ID().toString(); } if (ctx.T_WHEN() != null) { if (evalPop(ctx.bool_expr()).isTrue()) { leaveLoop(label); } } else { leaveLoop(label); } return 0; } /** * BREAK statement (leave the innermost loop unconditionally) */ public Integer break_(HplsqlParser.Break_stmtContext ctx) { trace(ctx, "BREAK"); leaveLoop(""); return 0; } /** * LEAVE statement (leave the specified loop unconditionally) */ public Integer leave(HplsqlParser.Leave_stmtContext ctx) { trace(ctx, "LEAVE"); String label = ""; if (ctx.L_ID() != null) { label = ctx.L_ID().toString(); } leaveLoop(label); return 0; } /** * Leave the specified or innermost loop unconditionally */ public void leaveLoop(String value) { exec.signal(Signal.Type.LEAVE_LOOP, value); } /** * UPDATE statement */ public Integer update(HplsqlParser.Update_stmtContext ctx) { trace(ctx, "UPDATE"); String sql = exec.getFormattedText(ctx); trace(ctx, sql); Query query = exec.executeSql(ctx, sql, exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * DELETE statement */ public Integer delete(HplsqlParser.Delete_stmtContext ctx) { trace(ctx, "DELETE"); String table = evalPop(ctx.table_name()).toString(); StringBuilder sql = new StringBuilder(); if (ctx.T_ALL() == null) { sql.append("DELETE FROM " + table); if (ctx.where_clause() != null) { boolean oldBuildSql = exec.buildSql; exec.buildSql = true; sql.append(" " + evalPop(ctx.where_clause()).toString()); exec.buildSql = oldBuildSql; } } else { sql.append("TRUNCATE TABLE " + table); } trace(ctx, sql.toString()); Query query = exec.executeSql(ctx, sql.toString(), exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * MERGE statement */ public Integer merge(HplsqlParser.Merge_stmtContext ctx) { trace(ctx, "MERGE"); String sql = exec.getFormattedText(ctx); trace(ctx, sql); Query query = exec.executeSql(ctx, sql, exec.conf.defaultConnection); if (query.error()) { exec.signal(query); return 1; } exec.setSqlSuccess(); exec.closeQuery(query, exec.conf.defaultConnection); return 0; } /** * PRINT Statement */ public Integer print(HplsqlParser.Print_stmtContext ctx) { trace(ctx, "PRINT"); if (ctx.expr() != null) { System.out.println(evalPop(ctx.expr()).toString()); } return 0; } /** * QUIT Statement */ public Integer quit(HplsqlParser.Quit_stmtContext ctx) { trace(ctx, "QUIT"); String rc = null; if (ctx.expr() != null) { rc = evalPop(ctx.expr()).toString(); } exec.signal(Signal.Type.LEAVE_PROGRAM, rc); return 0; } /** * SET current schema */ public Integer setCurrentSchema(HplsqlParser.Set_current_schema_optionContext ctx) { trace(ctx, "SET CURRENT SCHEMA"); return use(ctx, "USE " + meta.normalizeIdentifierPart(evalPop(ctx.expr()).toString())); } /** * SIGNAL statement */ public Integer signal(HplsqlParser.Signal_stmtContext ctx) { trace(ctx, "SIGNAL"); Signal signal = new Signal(Signal.Type.USERDEFINED, ctx.ident().getText()); exec.signal(signal); return 0; } /** * RESIGNAL statement */ public Integer resignal(HplsqlParser.Resignal_stmtContext ctx) { trace(ctx, "RESIGNAL"); if (ctx.T_SQLSTATE() != null) { String sqlstate = evalPop(ctx.expr(0)).toString(); String text = ""; if (ctx.T_MESSAGE_TEXT() != null) { text = evalPop(ctx.expr(1)).toString(); } SQLException exception = new SQLException(text, sqlstate, -1); Signal signal = new Signal(Signal.Type.SQLEXCEPTION, text, exception); exec.setSqlCode(exception); exec.resignal(signal); } else { exec.resignal(); } return 0; } /** * RETURN statement */ public Integer return_(HplsqlParser.Return_stmtContext ctx) { trace(ctx, "RETURN"); if (ctx.expr() != null) { eval(ctx.expr()); } exec.signal(Signal.Type.LEAVE_ROUTINE); return 0; } /** * Check if an exception is raised or EXIT executed, and we should leave the block */ boolean canContinue(String label) { Signal signal = exec.signalPeek(); if (signal != null && signal.type == Signal.Type.SQLEXCEPTION) { return false; } signal = exec.signalPeek(); if (signal != null && signal.type == Signal.Type.LEAVE_LOOP) { if (signal.value == null || signal.value.isEmpty() || (label != null && label.equalsIgnoreCase(signal.value))) { exec.signalPop(); } return false; } return true; } /** * Evaluate the expression and push the value to the stack */ void eval(ParserRuleContext ctx) { exec.visit(ctx); } /** * Evaluate the expression to specified String value */ void evalString(String string) { exec.stackPush(new Var(string)); } void evalString(StringBuilder string) { evalString(string.toString()); } /** * Evaluate the expression and pop value from the stack */ Var evalPop(ParserRuleContext ctx) { visit(ctx); if (!exec.stack.isEmpty()) { return exec.stackPop(); } return Var.Empty; } Var evalPop(ParserRuleContext ctx, long def) { if (ctx != null) { exec.visit(ctx); return exec.stackPop(); } return new Var(def); } /** * Execute rules */ Integer visit(ParserRuleContext ctx) { return exec.visit(ctx); } /** * Execute children rules */ Integer visitChildren(ParserRuleContext ctx) { return exec.visitChildren(ctx); } /** * Trace information */ void trace(ParserRuleContext ctx, String message) { exec.trace(ctx, message); } void trace(ParserRuleContext ctx, Var var, ResultSet rs, ResultSetMetaData rm, int idx) throws SQLException { exec.trace(ctx, var, rs, rm, idx); } }