You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by ga...@apache.org on 2015/07/01 18:18:42 UTC
[3/4] hive git commit: HIVE-11055 HPL/SQL - Implementing Procedural
SQL in Hive (PL/HQL Contribution) (Dmitry Tolpeko via gates)
http://git-wip-us.apache.org/repos/asf/hive/blob/052643cb/hplsql/src/main/java/org/apache/hive/hplsql/Exec.java
----------------------------------------------------------------------
diff --git a/hplsql/src/main/java/org/apache/hive/hplsql/Exec.java b/hplsql/src/main/java/org/apache/hive/hplsql/Exec.java
new file mode 100644
index 0000000..9ec8959
--- /dev/null
+++ b/hplsql/src/main/java/org/apache/hive/hplsql/Exec.java
@@ -0,0 +1,1950 @@
+/**
+ * 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.math.BigDecimal;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Stack;
+import java.util.Iterator;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.misc.NotNull;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.apache.commons.io.FileUtils;
+import org.apache.hive.hplsql.functions.*;
+
+/**
+ * HPL/SQL script executor
+ *
+ */
+public class Exec extends HplsqlBaseVisitor<Integer> {
+
+ public static final String VERSION = "HPL/SQL 0.3.11";
+ public static final String SQLCODE = "SQLCODE";
+ public static final String SQLSTATE = "SQLSTATE";
+ public static final String HOSTCODE = "HOSTCODE";
+
+ Exec exec = null;
+ ParseTree tree = null;
+
+ public enum OnError {EXCEPTION, SETERROR, STOP};
+
+ // Scopes of execution (code blocks) with own local variables, parameters and exception handlers
+ Stack<Scope> scopes = new Stack<Scope>();
+ Scope currentScope;
+
+ Stack<Var> stack = new Stack<Var>();
+ Stack<String> labels = new Stack<String>();
+
+ Stack<Signal> signals = new Stack<Signal>();
+ Signal currentSignal;
+ Scope currentHandlerScope;
+ boolean resignal = false;
+
+ HashMap<String, String> managedTables = new HashMap<String, String>();
+ HashMap<String, String> objectMap = new HashMap<String, String>();
+ HashMap<String, String> objectConnMap = new HashMap<String, String>();
+
+ public ArrayList<String> stmtConnList = new ArrayList<String>();
+
+ Arguments arguments = new Arguments();
+ public Conf conf;
+ Expression expr;
+ Function function;
+ Converter converter;
+ Select select;
+ Stmt stmt;
+ Conn conn;
+
+ int rowCount = 0;
+
+ String execString;
+ String execFile;
+ String execMain;
+ StringBuilder localUdf = new StringBuilder();
+ boolean initRoutines = false;
+ public boolean buildSql = false;
+ boolean udfRegistered = false;
+ boolean udfRun = false;
+
+ boolean dotHplsqlrcExists = false;
+ boolean hplsqlrcExists = false;
+
+ boolean trace = false;
+ boolean info = true;
+ boolean offline = false;
+
+ Exec() {
+ exec = this;
+ }
+
+ Exec(Exec exec) {
+ this.exec = exec;
+ }
+
+ /**
+ * Set a variable using a value from the parameter or the stack
+ */
+ public Var setVariable(String name, Var value) {
+ if (value == null || value == Var.Empty) {
+ if (exec.stack.empty()) {
+ return Var.Empty;
+ }
+ value = exec.stack.pop();
+ }
+ if (name.startsWith("hplsql.")) {
+ exec.conf.setOption(name, value.toString());
+ return Var.Empty;
+ }
+ Var var = findVariable(name);
+ if (var != null) {
+ var.cast(value);
+ }
+ else {
+ var = new Var(value);
+ var.setName(name);
+ exec.currentScope.addVariable(var);
+ }
+ return var;
+ }
+
+ public Var setVariable(String name) {
+ return setVariable(name, Var.Empty);
+ }
+
+ public Var setVariable(String name, String value) {
+ return setVariable(name, new Var(value));
+ }
+
+ public Var setVariable(String name, int value) {
+ return setVariable(name, new Var(new Long(value)));
+ }
+
+ /**
+ * Set variable to NULL
+ */
+ public Var setVariableToNull(String name) {
+ Var var = findVariable(name);
+ if (var != null) {
+ var.removeValue();
+ }
+ else {
+ var = new Var();
+ var.setName(name);
+ exec.currentScope.addVariable(var);
+ }
+ return var;
+ }
+
+ /**
+ * Add a local variable to the current scope
+ */
+ public void addVariable(Var var) {
+ if (exec.currentScope != null) {
+ exec.currentScope.addVariable(var);
+ }
+ }
+
+ /**
+ * Add a condition handler to the current scope
+ */
+ public void addHandler(Handler handler) {
+ if (exec.currentScope != null) {
+ exec.currentScope.addHandler(handler);
+ }
+ }
+
+ /**
+ * Push a value to the stack
+ */
+ public void stackPush(Var var) {
+ exec.stack.push(var);
+ }
+
+ /**
+ * Push a string value to the stack
+ */
+ public void stackPush(String val) {
+ exec.stack.push(new Var(val));
+ }
+
+ public void stackPush(StringBuilder val) {
+ stackPush(val.toString());
+ }
+
+ /**
+ * Push a boolean value to the stack
+ */
+ public void stackPush(boolean val) {
+ exec.stack.push(new Var(val));
+ }
+
+ /**
+ * Select a value from the stack, but not remove
+ */
+ public Var stackPeek() {
+ return exec.stack.peek();
+ }
+
+ /**
+ * Pop a value from the stack
+ */
+ public Var stackPop() {
+ if (!exec.stack.isEmpty()) {
+ return exec.stack.pop();
+ }
+ return null;
+ }
+
+ /**
+ * Find an existing variable by name
+ */
+ public Var findVariable(String name) {
+ Scope cur = exec.currentScope;
+ String name2 = null;
+ if (name.startsWith(":")) {
+ name2 = name.substring(1);
+ }
+ while (cur != null) {
+ for (Var v : cur.vars) {
+ if (name.equalsIgnoreCase(v.getName()) ||
+ (name2 != null && name2.equalsIgnoreCase(v.getName()))) {
+ return v;
+ }
+ }
+ cur = cur.parent;
+ }
+ return null;
+ }
+
+ public Var findVariable(Var name) {
+ return findVariable(name.getName());
+ }
+
+ /**
+ * Enter a new scope
+ */
+ public void enterScope(Scope.Type type) {
+ exec.currentScope = new Scope(exec.currentScope, type);
+ exec.scopes.push(exec.currentScope);
+ }
+
+ /**
+ * Leave the current scope
+ */
+ public void leaveScope() {
+ if (!exec.signals.empty()) {
+ Scope scope = exec.scopes.peek();
+ Signal signal = exec.signals.peek();
+ if (exec.conf.onError != OnError.SETERROR) {
+ runExitHandler();
+ }
+ if (signal.type == Signal.Type.LEAVE_ROUTINE && scope.type == Scope.Type.ROUTINE) {
+ exec.signals.pop();
+ }
+ }
+ exec.currentScope = exec.scopes.pop().getParent();
+ }
+
+ /**
+ * Send a signal
+ */
+ public void signal(Signal signal) {
+ exec.signals.push(signal);
+ }
+
+ public void signal(Signal.Type type, String value, Exception exception) {
+ signal(new Signal(type, value, exception));
+ }
+
+ public void signal(Signal.Type type, String value) {
+ signal(type, value, null);
+ }
+
+ public void signal(Signal.Type type) {
+ signal(type, null, null);
+ }
+
+ public void signal(Query query) {
+ setSqlCode(query.getException());
+ signal(Signal.Type.SQLEXCEPTION, query.errorText(), query.getException());
+ }
+
+ public void signal(Exception exception) {
+ setSqlCode(exception);
+ signal(Signal.Type.SQLEXCEPTION, exception.getMessage(), exception);
+ }
+
+ /**
+ * Resignal the condition
+ */
+ public void resignal() {
+ resignal(exec.currentSignal);
+ }
+
+ public void resignal(Signal signal) {
+ if (signal != null) {
+ exec.resignal = true;
+ signal(signal);
+ }
+ }
+
+ /**
+ * Run CONTINUE handlers
+ */
+ boolean runContinueHandler() {
+ Scope cur = exec.currentScope;
+ exec.currentSignal = exec.signals.pop();
+ while (cur != null) {
+ for (Handler h : cur.handlers) {
+ if (h.execType != Handler.ExecType.CONTINUE) {
+ continue;
+ }
+ if ((h.type != Signal.Type.USERDEFINED && h.type == exec.currentSignal.type) ||
+ (h.type == Signal.Type.USERDEFINED && h.type == exec.currentSignal.type &&
+ h.value.equalsIgnoreCase(exec.currentSignal.value))) {
+ trace(h.ctx, "CONTINUE HANDLER");
+ enterScope(Scope.Type.HANDLER);
+ exec.currentHandlerScope = h.scope;
+ visit(h.ctx.single_block_stmt());
+ leaveScope();
+ exec.currentSignal = null;
+ return true;
+ }
+ }
+ cur = cur.parent;
+ }
+ exec.signals.push(exec.currentSignal);
+ exec.currentSignal = null;
+ return false;
+ }
+
+ /**
+ * Run EXIT handler defined for the current scope
+ */
+ boolean runExitHandler() {
+ exec.currentSignal = exec.signals.pop();
+ for (Handler h : currentScope.handlers) {
+ if (h.execType != Handler.ExecType.EXIT) {
+ continue;
+ }
+ if ((h.type != Signal.Type.USERDEFINED && h.type == exec.currentSignal.type) ||
+ (h.type == Signal.Type.USERDEFINED && h.type == exec.currentSignal.type &&
+ h.value.equalsIgnoreCase(currentSignal.value))) {
+ trace(h.ctx, "EXIT HANDLER");
+ enterScope(Scope.Type.HANDLER);
+ exec.currentHandlerScope = h.scope;
+ visit(h.ctx.single_block_stmt());
+ leaveScope();
+ exec.currentSignal = null;
+ return true;
+ }
+ }
+ exec.signals.push(exec.currentSignal);
+ exec.currentSignal = null;
+ return false;
+ }
+
+ /**
+ * Pop the last signal
+ */
+ public Signal signalPop() {
+ if (!exec.signals.empty()) {
+ return exec.signals.pop();
+ }
+ return null;
+ }
+
+ /**
+ * Peek the last signal
+ */
+ public Signal signalPeek() {
+ if (!exec.signals.empty()) {
+ return exec.signals.peek();
+ }
+ return null;
+ }
+
+ /**
+ * Pop the current label
+ */
+ public String labelPop() {
+ if(!exec.labels.empty()) {
+ return exec.labels.pop();
+ }
+ return "";
+ }
+
+ /**
+ * Execute a SQL query (SELECT)
+ */
+ public Query executeQuery(ParserRuleContext ctx, Query query, String connProfile) {
+ if (!exec.offline) {
+ exec.rowCount = 0;
+ exec.conn.executeQuery(query, connProfile);
+ return query;
+ }
+ setSqlNoData();
+ trace(ctx, "Not executed - offline mode set");
+ return query;
+ }
+
+ public Query executeQuery(ParserRuleContext ctx, String sql, String connProfile) {
+ return executeQuery(ctx, new Query(sql), connProfile);
+ }
+
+ /**
+ * Execute a SQL statement
+ */
+ public Query executeSql(ParserRuleContext ctx, String sql, String connProfile) {
+ if (!exec.offline) {
+ exec.rowCount = 0;
+ Query query = conn.executeSql(sql, connProfile);
+ exec.rowCount = query.getRowCount();
+ return query;
+ }
+ trace(ctx, "Not executed - offline mode set");
+ return new Query("");
+ }
+
+ /**
+ * Close the query object
+ */
+ public void closeQuery(Query query, String conn) {
+ if(!exec.offline) {
+ exec.conn.closeQuery(query, conn);
+ }
+ }
+
+ /**
+ * Register JARs, FILEs and CREATE TEMPORARY FUNCTION for UDF call
+ */
+ public void registerUdf() {
+ if (udfRegistered) {
+ return;
+ }
+ ArrayList<String> sql = new ArrayList<String>();
+ String dir = Utils.getExecDir();
+ sql.add("ADD JAR " + dir + "hplsql.jar");
+ sql.add("ADD JAR " + dir + "antlr-runtime-4.5.jar");
+ sql.add("ADD FILE " + dir + Conf.SITE_XML);
+ if (dotHplsqlrcExists) {
+ sql.add("ADD FILE " + dir + Conf.DOT_HPLSQLRC);
+ }
+ if (hplsqlrcExists) {
+ sql.add("ADD FILE " + dir + Conf.HPLSQLRC);
+ }
+ String lu = createLocalUdf();
+ if (lu != null) {
+ sql.add("ADD FILE " + lu);
+ }
+ sql.add("CREATE TEMPORARY FUNCTION hplsql AS 'org.apache.hive.hplsql.Udf'");
+ exec.conn.addPreSql(exec.conf.defaultConnection, sql);
+ udfRegistered = true;
+ }
+
+ /**
+ * Initialize options
+ */
+ void initOptions() {
+ Iterator<Map.Entry<String,String>> i = exec.conf.iterator();
+ while (i.hasNext()) {
+ Entry<String,String> item = (Entry<String,String>)i.next();
+ String key = (String)item.getKey();
+ String value = (String)item.getValue();
+ if (key == null || value == null) {
+ continue;
+ }
+ else if (key.compareToIgnoreCase(Conf.CONN_DEFAULT) == 0) {
+ exec.conf.defaultConnection = value;
+ }
+ else if (key.startsWith("hplsql.conn.init.")) {
+ exec.conn.addConnectionInit(key.substring(16), value);
+ }
+ else if (key.startsWith(Conf.CONN_CONVERT)) {
+ exec.conf.setConnectionConvert(key.substring(19), value);
+ }
+ else if (key.startsWith("hplsql.conn.")) {
+ exec.conn.addConnection(key.substring(11), value);
+ }
+ else if (key.startsWith("hplsql.")) {
+ exec.conf.setOption(key, value);
+ }
+ }
+ }
+
+ /**
+ * Set SQLCODE
+ */
+ public void setSqlCode(int sqlcode) {
+ Var var = findVariable(SQLCODE);
+ if (var != null) {
+ var.setValue(new Long(sqlcode));
+ }
+ }
+
+ public void setSqlCode(Exception exception) {
+ if (exception instanceof SQLException) {
+ setSqlCode(((SQLException)exception).getErrorCode());
+ setSqlState(((SQLException)exception).getSQLState());
+ }
+ else {
+ setSqlCode(-1);
+ setSqlState("02000");
+ }
+ }
+
+ /**
+ * Set SQLSTATE
+ */
+ public void setSqlState(String sqlstate) {
+ Var var = findVariable(SQLSTATE);
+ if (var != null) {
+ var.setValue(sqlstate);
+ }
+ }
+
+ /**
+ * Set HOSTCODE
+ */
+ public void setHostCode(int code) {
+ Var var = findVariable(HOSTCODE);
+ if (var != null) {
+ var.setValue(new Long(code));
+ }
+ }
+
+ /**
+ * Set successful execution for SQL
+ */
+ public void setSqlSuccess() {
+ setSqlCode(0);
+ setSqlState("00000");
+ }
+
+ /**
+ * Set SQL_NO_DATA as the result of SQL execution
+ */
+ public void setSqlNoData() {
+ setSqlCode(100);
+ setSqlState("01000");
+ }
+
+ /**
+ * Compile and run PL/HQL script
+ */
+ public Integer run(String[] args) throws Exception {
+ if (init(args) != 0) {
+ return 1;
+ }
+ Var result = run();
+ if (result != null) {
+ System.out.println(result.toString());
+ }
+ cleanup();
+ printExceptions();
+ return getProgramReturnCode();
+ }
+
+ /**
+ * Run already compiled PL/HQL script (also used from Hive UDF)
+ */
+ public Var run() {
+ if (tree == null) {
+ return null;
+ }
+ if (execMain != null) {
+ initRoutines = true;
+ visit(tree);
+ initRoutines = false;
+ exec.function.execProc(execMain);
+ }
+ else {
+ visit(tree);
+ }
+ return stackPop();
+ }
+
+ /**
+ * Initialize PL/HQL
+ */
+ Integer init(String[] args) throws Exception {
+ if (!parseArguments(args)) {
+ return 1;
+ }
+ conf = new Conf();
+ conf.init();
+ conn = new Conn(this);
+ initOptions();
+
+ expr = new Expression(this);
+ select = new Select(this);
+ stmt = new Stmt(this);
+ converter = new Converter(this);
+
+ function = new Function(this);
+ new FunctionDatetime(this).register(function);
+ new FunctionMisc(this).register(function);
+ new FunctionString(this).register(function);
+ new FunctionOra(this).register(function);
+
+ enterScope(Scope.Type.FILE);
+ addVariable(new Var(SQLCODE, Var.Type.BIGINT, 0L));
+ addVariable(new Var(SQLSTATE, Var.Type.STRING, "00000"));
+ addVariable(new Var(HOSTCODE, Var.Type.BIGINT, 0L));
+
+ for (Map.Entry<String, String> v : arguments.getVars().entrySet()) {
+ addVariable(new Var(v.getKey(), Var.Type.STRING, v.getValue()));
+ }
+ InputStream input = null;
+ if (execString != null) {
+ input = new ByteArrayInputStream(execString.getBytes("UTF-8"));
+ }
+ else {
+ input = new FileInputStream(execFile);
+ }
+ HplsqlLexer lexer = new HplsqlLexer(new ANTLRInputStream(input));
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ HplsqlParser parser = new HplsqlParser(tokens);
+ tree = parser.program();
+ if (trace) {
+ System.err.println("Configuration file: " + conf.getLocation());
+ System.err.println("Parser tree: " + tree.toStringTree(parser));
+ }
+ includeRcFile();
+ return 0;
+ }
+
+ /**
+ * Parse command line arguments
+ */
+ boolean parseArguments(String[] args) {
+ boolean parsed = arguments.parse(args);
+ if (parsed && arguments.hasVersionOption()) {
+ System.err.println(VERSION);
+ return false;
+ }
+ if (!parsed || arguments.hasHelpOption() ||
+ (arguments.getExecString() == null && arguments.getFileName() == null)) {
+ arguments.printHelp();
+ return false;
+ }
+ execString = arguments.getExecString();
+ execFile = arguments.getFileName();
+ execMain = arguments.getMain();
+ if (arguments.hasTraceOption()) {
+ trace = true;
+ }
+ if (arguments.hasOfflineOption()) {
+ offline = true;
+ }
+ if (execString != null && execFile != null) {
+ System.err.println("The '-e' and '-f' options cannot be specified simultaneously.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Include statements from .hplsqlrc and hplsql rc files
+ */
+ void includeRcFile() {
+ if (includeFile(Conf.DOT_HPLSQLRC)) {
+ dotHplsqlrcExists = true;
+ }
+ else {
+ if (includeFile(Conf.HPLSQLRC)) {
+ hplsqlrcExists = true;
+ }
+ }
+ if (udfRun) {
+ includeFile(Conf.HPLSQL_LOCALS_SQL);
+ }
+ }
+
+ /**
+ * Include statements from a file
+ */
+ boolean includeFile(String file) {
+ try {
+ String content = FileUtils.readFileToString(new java.io.File(file), "UTF-8");
+ if (content != null && !content.isEmpty()) {
+ if (trace) {
+ trace(null, "INLCUDE CONTENT " + file + " (non-empty)");
+ }
+ new Exec(this).include(content);
+ return true;
+ }
+ }
+ catch (Exception e) {}
+ return false;
+ }
+
+ /**
+ * Execute statements from an include file
+ */
+ void include(String content) throws Exception {
+ InputStream input = new ByteArrayInputStream(content.getBytes("UTF-8"));
+ HplsqlLexer lexer = new HplsqlLexer(new ANTLRInputStream(input));
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ HplsqlParser parser = new HplsqlParser(tokens);
+ ParseTree tree = parser.program();
+ visit(tree);
+ }
+
+ /**
+ * Start executing PL/HQL script
+ */
+ @Override
+ public Integer visitProgram(HplsqlParser.ProgramContext ctx) {
+ enterScope(Scope.Type.FILE);
+ Integer rc = visitChildren(ctx);
+ leaveScope();
+ return rc;
+ }
+
+ /**
+ * Enter BEGIN-END block
+ */
+ @Override
+ public Integer visitBegin_end_block(HplsqlParser.Begin_end_blockContext ctx) {
+ enterScope(Scope.Type.BEGIN_END);
+ Integer rc = visitChildren(ctx);
+ leaveScope();
+ return rc;
+ }
+
+ /**
+ * Free resources before exit
+ */
+ void cleanup() {
+ for (Map.Entry<String, String> i : managedTables.entrySet()) {
+ String sql = "DROP TABLE IF EXISTS " + i.getValue();
+ Query query = executeSql(null, sql, exec.conf.defaultConnection);
+ closeQuery(query, exec.conf.defaultConnection);
+ if (trace) {
+ trace(null, sql);
+ }
+ }
+ }
+
+ /**
+ * Output information about unhandled exceptions
+ */
+ void printExceptions() {
+ while (!signals.empty()) {
+ Signal sig = signals.pop();
+ if (sig.type == Signal.Type.SQLEXCEPTION) {
+ System.err.println("Unhandled exception in PL/HQL");
+ }
+ if (sig.exception != null) {
+ sig.exception.printStackTrace();
+ }
+ else if (sig.value != null) {
+ System.err.println(sig.value);
+ }
+ }
+ }
+
+ /**
+ * Get the program return code
+ */
+ Integer getProgramReturnCode() {
+ Integer rc = 0;
+ if(!signals.empty()) {
+ Signal sig = signals.pop();
+ if(sig.type == Signal.Type.LEAVE_ROUTINE && sig.value != null) {
+ try {
+ rc = Integer.parseInt(sig.value);
+ }
+ catch(NumberFormatException e) {
+ rc = 1;
+ }
+ }
+ }
+ return rc;
+ }
+
+ /**
+ * Executing a statement
+ */
+ @Override
+ public Integer visitStmt(HplsqlParser.StmtContext ctx) {
+ if (ctx.semicolon_stmt() != null) {
+ return 0;
+ }
+ if (initRoutines && ctx.create_procedure_stmt() == null && ctx.create_function_stmt() == null) {
+ return 0;
+ }
+ if (exec.resignal) {
+ if (exec.currentScope != exec.currentHandlerScope.parent) {
+ return 0;
+ }
+ exec.resignal = false;
+ }
+ if (!exec.signals.empty() && exec.conf.onError != OnError.SETERROR) {
+ if (!runContinueHandler()) {
+ return 0;
+ }
+ }
+ Var prevResult = stackPop();
+ if (prevResult != null) {
+ System.out.println(prevResult.toString());
+ }
+ return visitChildren(ctx);
+ }
+
+ /**
+ * Executing or building SELECT statement
+ */
+ @Override
+ public Integer visitSelect_stmt(HplsqlParser.Select_stmtContext ctx) {
+ return exec.select.select(ctx);
+ }
+
+ @Override
+ public Integer visitCte_select_stmt(HplsqlParser.Cte_select_stmtContext ctx) {
+ return exec.select.cte(ctx);
+ }
+
+ @Override
+ public Integer visitFullselect_stmt(HplsqlParser.Fullselect_stmtContext ctx) {
+ return exec.select.fullselect(ctx);
+ }
+
+ @Override
+ public Integer visitSubselect_stmt(HplsqlParser.Subselect_stmtContext ctx) {
+ return exec.select.subselect(ctx);
+ }
+
+ @Override
+ public Integer visitSelect_list(HplsqlParser.Select_listContext ctx) {
+ return exec.select.selectList(ctx);
+ }
+
+ @Override
+ public Integer visitFrom_clause(HplsqlParser.From_clauseContext ctx) {
+ return exec.select.from(ctx);
+ }
+
+ @Override
+ public Integer visitFrom_table_name_clause(HplsqlParser.From_table_name_clauseContext ctx) {
+ return exec.select.fromTable(ctx);
+ }
+
+ @Override
+ public Integer visitFrom_join_clause(HplsqlParser.From_join_clauseContext ctx) {
+ return exec.select.fromJoin(ctx);
+ }
+
+ @Override
+ public Integer visitFrom_table_values_clause(HplsqlParser.From_table_values_clauseContext ctx) {
+ return exec.select.fromTableValues(ctx);
+ }
+
+ @Override
+ public Integer visitWhere_clause(HplsqlParser.Where_clauseContext ctx) {
+ return exec.select.where(ctx);
+ }
+
+ @Override
+ public Integer visitSelect_options_item(HplsqlParser.Select_options_itemContext ctx) {
+ return exec.select.option(ctx);
+ }
+
+ /**
+ * Table name
+ */
+ @Override
+ public Integer visitTable_name(HplsqlParser.Table_nameContext ctx) {
+ String name = ctx.getText().toUpperCase();
+ String actualName = exec.managedTables.get(name);
+ String conn = exec.objectConnMap.get(name);
+ if (conn == null) {
+ conn = conf.defaultConnection;
+ }
+ stmtConnList.add(conn);
+ if (actualName != null) {
+ stackPush(actualName);
+ return 0;
+ }
+ actualName = exec.objectMap.get(name);
+ if (actualName != null) {
+ stackPush(actualName);
+ return 0;
+ }
+ stackPush(ctx.getText());
+ return 0;
+ }
+
+ /**
+ * SQL INSERT statement
+ */
+ @Override
+ public Integer visitInsert_stmt(HplsqlParser.Insert_stmtContext ctx) {
+ return exec.stmt.insert(ctx);
+ }
+
+ /**
+ * EXCEPTION block
+ */
+ @Override
+ public Integer visitException_block_item(HplsqlParser.Exception_block_itemContext ctx) {
+ if (exec.signals.empty()) {
+ return 0;
+ }
+ if (exec.conf.onError == OnError.SETERROR || exec.conf.onError == OnError.STOP) {
+ exec.signals.pop();
+ return 0;
+ }
+ if (ctx.L_ID().toString().equalsIgnoreCase("OTHERS")) {
+ trace(ctx, "EXCEPTION HANDLER");
+ exec.signals.pop();
+ enterScope(Scope.Type.HANDLER);
+ visit(ctx.block());
+ leaveScope();
+ }
+ return 0;
+ }
+
+ /**
+ * DECLARE variable statement
+ */
+ @Override
+ public Integer visitDeclare_var_item(HplsqlParser.Declare_var_itemContext ctx) {
+ String type = ctx.dtype().getText();
+ String len = null;
+ String scale = null;
+ Var default_ = null;
+ if (ctx.dtype_len() != null) {
+ len = ctx.dtype_len().L_INT(0).getText();
+ if (ctx.dtype_len().L_INT(1) != null) {
+ scale = ctx.dtype_len().L_INT(1).getText();
+ }
+ }
+ if (ctx.dtype_default() != null) {
+ default_ = evalPop(ctx.dtype_default());
+ }
+ int cnt = ctx.ident().size(); // Number of variables declared with the same data type and default
+ for (int i = 0; i < cnt; i++) {
+ String name = ctx.ident(i).getText();
+ Var var = new Var(name, type, len, scale, default_);
+ addVariable(var);
+ if (trace) {
+ if (default_ != null) {
+ trace(ctx, "DECLARE " + name + " " + type + " = " + var.toSqlString());
+ }
+ else {
+ trace(ctx, "DECLARE " + name + " " + type);
+ }
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * DECLARE cursor statement
+ */
+ @Override
+ public Integer visitDeclare_cursor_item(HplsqlParser.Declare_cursor_itemContext ctx) {
+ return exec.stmt.declareCursor(ctx);
+ }
+
+ /**
+ * DROP statement
+ */
+ @Override
+ public Integer visitDrop_stmt(HplsqlParser.Drop_stmtContext ctx) {
+ return exec.stmt.drop(ctx);
+ }
+
+ /**
+ * OPEN cursor statement
+ */
+ @Override
+ public Integer visitOpen_stmt(HplsqlParser.Open_stmtContext ctx) {
+ return exec.stmt.open(ctx);
+ }
+
+ /**
+ * FETCH cursor statement
+ */
+ @Override
+ public Integer visitFetch_stmt(HplsqlParser.Fetch_stmtContext ctx) {
+ return exec.stmt.fetch(ctx);
+ }
+
+ /**
+ * CLOSE cursor statement
+ */
+ @Override
+ public Integer visitClose_stmt(HplsqlParser.Close_stmtContext ctx) {
+ return exec.stmt.close(ctx);
+ }
+
+ /**
+ * COPY statement
+ */
+ @Override
+ public Integer visitCopy_stmt(HplsqlParser.Copy_stmtContext ctx) {
+ return new Copy(exec).run(ctx);
+ }
+
+ /**
+ * COPY FROM LOCAL statement
+ */
+ @Override
+ public Integer visitCopy_from_local_stmt(HplsqlParser.Copy_from_local_stmtContext ctx) {
+ return new Copy(exec).runFromLocal(ctx);
+ }
+
+ /**
+ * DECLARE HANDLER statement
+ */
+ @Override
+ public Integer visitDeclare_handler_item(HplsqlParser.Declare_handler_itemContext ctx) {
+ trace(ctx, "DECLARE HANDLER");
+ Handler.ExecType execType = Handler.ExecType.EXIT;
+ Signal.Type type = Signal.Type.SQLEXCEPTION;
+ String value = null;
+ if (ctx.T_CONTINUE() != null) {
+ execType = Handler.ExecType.CONTINUE;
+ }
+ if (ctx.ident() != null) {
+ type = Signal.Type.USERDEFINED;
+ value = ctx.ident().getText();
+ }
+ else if (ctx.T_NOT() != null && ctx.T_FOUND() != null) {
+ type = Signal.Type.NOTFOUND;
+ }
+ addHandler(new Handler(execType, type, value, exec.currentScope, ctx));
+ return 0;
+ }
+
+ /**
+ * DECLARE CONDITION
+ */
+ @Override
+ public Integer visitDeclare_condition_item(HplsqlParser.Declare_condition_itemContext ctx) {
+ return 0;
+ }
+
+ /**
+ * DECLARE TEMPORARY TABLE statement
+ */
+ @Override
+ public Integer visitDeclare_temporary_table_item(HplsqlParser.Declare_temporary_table_itemContext ctx) {
+ return exec.stmt.declareTemporaryTable(ctx);
+ }
+
+ /**
+ * CREATE TABLE statement
+ */
+ @Override
+ public Integer visitCreate_table_stmt(HplsqlParser.Create_table_stmtContext ctx) {
+ return exec.stmt.createTable(ctx);
+ }
+
+ @Override
+ public Integer visitCreate_table_options_hive_item(HplsqlParser.Create_table_options_hive_itemContext ctx) {
+ return exec.stmt.createTableHiveOptions(ctx);
+ }
+
+ /**
+ * CREATE LOCAL TEMPORARY | VOLATILE TABLE statement
+ */
+ @Override
+ public Integer visitCreate_local_temp_table_stmt(HplsqlParser.Create_local_temp_table_stmtContext ctx) {
+ return exec.stmt.createLocalTemporaryTable(ctx);
+ }
+
+ /**
+ * CREATE FUNCTION statement
+ */
+ @Override
+ public Integer visitCreate_function_stmt(HplsqlParser.Create_function_stmtContext ctx) {
+ exec.function.addUserFunction(ctx);
+ addLocalUdf(ctx);
+ return 0;
+ }
+
+ /**
+ * CREATE PROCEDURE statement
+ */
+ @Override
+ public Integer visitCreate_procedure_stmt(HplsqlParser.Create_procedure_stmtContext ctx) {
+ exec.function.addUserProcedure(ctx);
+ addLocalUdf(ctx); // Add procedures as they can be invoked by functions
+ return 0;
+ }
+
+ /**
+ * CREATE INDEX statement
+ */
+ @Override
+ public Integer visitCreate_index_stmt(HplsqlParser.Create_index_stmtContext ctx) {
+ return 0;
+ }
+
+ /**
+ * Add functions and procedures defined in the current script
+ */
+ void addLocalUdf(ParserRuleContext ctx) {
+ if (exec == this) {
+ localUdf.append(exec.getFormattedText(ctx));
+ localUdf.append("\n");
+ }
+ }
+
+ /**
+ * Save local functions and procedures to a file (will be added to the distributed cache)
+ */
+ String createLocalUdf() {
+ if(localUdf.length() == 0) {
+ return null;
+ }
+ try {
+ String file = System.getProperty("user.dir") + "/" + Conf.HPLSQL_LOCALS_SQL;
+ PrintWriter writer = new PrintWriter(file, "UTF-8");
+ writer.print(localUdf);
+ writer.close();
+ return file;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Assignment statement for single value
+ */
+ @Override
+ public Integer visitAssignment_stmt_single_item(HplsqlParser.Assignment_stmt_single_itemContext ctx) {
+ String name = ctx.ident().getText();
+ visit(ctx.expr());
+ Var var = setVariable(name);
+ if (trace) {
+ trace(ctx, "SET " + name + " = " + var.toSqlString());
+ }
+ return 0;
+ }
+
+ /**
+ * Assignment statement for multiple values
+ */
+ @Override
+ public Integer visitAssignment_stmt_multiple_item(HplsqlParser.Assignment_stmt_multiple_itemContext ctx) {
+ int cnt = ctx.ident().size();
+ 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 = setVariable(name);
+ if (trace) {
+ trace(ctx, "SET " + name + " = " + var.toString());
+ }
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Assignment from SELECT statement
+ */
+ @Override
+ public Integer visitAssignment_stmt_select_item(HplsqlParser.Assignment_stmt_select_itemContext ctx) {
+ return stmt.assignFromSelect(ctx);
+ }
+
+ /**
+ * Evaluate an expression
+ */
+ @Override
+ public Integer visitExpr(HplsqlParser.ExprContext ctx) {
+ if (exec.buildSql) {
+ exec.expr.execSql(ctx);
+ }
+ else {
+ exec.expr.exec(ctx);
+ }
+ return 0;
+ }
+
+ /**
+ * Evaluate a boolean expression
+ */
+ @Override
+ public Integer visitBool_expr(HplsqlParser.Bool_exprContext ctx) {
+ if (exec.buildSql) {
+ exec.expr.execBoolSql(ctx);
+ }
+ else {
+ exec.expr.execBool(ctx);
+ }
+ return 0;
+ }
+
+ @Override
+ public Integer visitBool_expr_binary(HplsqlParser.Bool_expr_binaryContext ctx) {
+ if (exec.buildSql) {
+ exec.expr.execBoolBinarySql(ctx);
+ }
+ else {
+ exec.expr.execBoolBinary(ctx);
+ }
+ return 0;
+ }
+
+ @Override
+ public Integer visitBool_expr_unary(HplsqlParser.Bool_expr_unaryContext ctx) {
+ if (exec.buildSql) {
+ exec.expr.execBoolUnarySql(ctx);
+ }
+ else {
+ exec.expr.execBoolUnary(ctx);
+ }
+ return 0;
+ }
+
+ /**
+ * Function call
+ */
+ @Override
+ public Integer visitExpr_func(HplsqlParser.Expr_funcContext ctx) {
+ String name = ctx.ident().getText();
+ if (exec.buildSql) {
+ exec.function.execSql(name, ctx.expr_func_params());
+ }
+ else {
+ exec.function.exec(name, ctx.expr_func_params());
+ }
+ return 0;
+ }
+
+ /**
+ * Aggregate or window function call
+ */
+ @Override
+ public Integer visitExpr_agg_window_func(HplsqlParser.Expr_agg_window_funcContext ctx) {
+ exec.function.execAggWindowSql(ctx);
+ return 0;
+ }
+
+ /**
+ * Function with specific syntax
+ */
+ @Override
+ public Integer visitExpr_spec_func(HplsqlParser.Expr_spec_funcContext ctx) {
+ if (exec.buildSql) {
+ exec.function.specExecSql(ctx);
+ }
+ else {
+ exec.function.specExec(ctx);
+ }
+ return 0;
+ }
+
+ /**
+ * INCLUDE statement
+ */
+ @Override
+ public Integer visitInclude_stmt(@NotNull HplsqlParser.Include_stmtContext ctx) {
+ return exec.stmt.include(ctx);
+ }
+
+ /**
+ * IF statement (PL/SQL syntax)
+ */
+ @Override
+ public Integer visitIf_plsql_stmt(HplsqlParser.If_plsql_stmtContext ctx) {
+ return exec.stmt.ifPlsql(ctx);
+ }
+
+ /**
+ * IF statement (Transact-SQL syntax)
+ */
+ @Override
+ public Integer visitIf_tsql_stmt(HplsqlParser.If_tsql_stmtContext ctx) {
+ return exec.stmt.ifTsql(ctx);
+ }
+
+ /**
+ * USE statement
+ */
+ @Override
+ public Integer visitUse_stmt(HplsqlParser.Use_stmtContext ctx) {
+ return exec.stmt.use(ctx);
+ }
+
+ /**
+ * VALUES statement
+ */
+ @Override
+ public Integer visitValues_into_stmt(HplsqlParser.Values_into_stmtContext ctx) {
+ return exec.stmt.values(ctx);
+ }
+
+ /**
+ * WHILE statement
+ */
+ @Override
+ public Integer visitWhile_stmt(HplsqlParser.While_stmtContext ctx) {
+ return exec.stmt.while_(ctx);
+ }
+
+ /**
+ * FOR cursor statement
+ */
+ @Override
+ public Integer visitFor_cursor_stmt(HplsqlParser.For_cursor_stmtContext ctx) {
+ return exec.stmt.forCursor(ctx);
+ }
+
+ /**
+ * FOR (integer range) statement
+ */
+ @Override
+ public Integer visitFor_range_stmt(HplsqlParser.For_range_stmtContext ctx) {
+ return exec.stmt.forRange(ctx);
+ }
+
+ /**
+ * EXEC, EXECUTE and EXECUTE IMMEDIATE statement to execute dynamic SQL
+ */
+ @Override
+ public Integer visitExec_stmt(HplsqlParser.Exec_stmtContext ctx) {
+ return exec.stmt.exec(ctx);
+ }
+
+ /**
+ * CALL statement
+ */
+ @Override
+ public Integer visitCall_stmt(HplsqlParser.Call_stmtContext ctx) {
+ if (exec.function.execProc(ctx.expr_func_params(), ctx.ident().getText())) {
+ return 0;
+ }
+ return -1;
+ }
+
+ /**
+ * EXIT statement (leave the specified loop with a condition)
+ */
+ @Override
+ public Integer visitExit_stmt(HplsqlParser.Exit_stmtContext ctx) {
+ return exec.stmt.exit(ctx);
+ }
+
+ /**
+ * BREAK statement (leave the innermost loop unconditionally)
+ */
+ @Override
+ public Integer visitBreak_stmt(HplsqlParser.Break_stmtContext ctx) {
+ return exec.stmt.break_(ctx);
+ }
+
+ /**
+ * LEAVE statement (leave the specified loop unconditionally)
+ */
+ @Override
+ public Integer visitLeave_stmt(HplsqlParser.Leave_stmtContext ctx) {
+ return exec.stmt.leave(ctx);
+ }
+
+ /**
+ * PRINT statement
+ */
+ @Override
+ public Integer visitPrint_stmt(HplsqlParser.Print_stmtContext ctx) {
+ return exec.stmt.print(ctx);
+ }
+
+ /**
+ * SIGNAL statement
+ */
+ @Override
+ public Integer visitSignal_stmt(HplsqlParser.Signal_stmtContext ctx) {
+ return exec.stmt.signal(ctx);
+ }
+
+ /**
+ * RESIGNAL statement
+ */
+ @Override
+ public Integer visitResignal_stmt(HplsqlParser.Resignal_stmtContext ctx) {
+ return exec.stmt.resignal(ctx);
+ }
+
+ /**
+ * RETURN statement
+ */
+ @Override
+ public Integer visitReturn_stmt(HplsqlParser.Return_stmtContext ctx) {
+ return exec.stmt.return_(ctx);
+ }
+
+ /**
+ * MAP OBJECT statement
+ */
+ @Override
+ public Integer visitMap_object_stmt(HplsqlParser.Map_object_stmtContext ctx) {
+ String source = evalPop(ctx.expr(0)).toString();
+ String target = null;
+ String conn = null;
+ if (ctx.T_TO() != null) {
+ target = evalPop(ctx.expr(1)).toString();
+ exec.objectMap.put(source.toUpperCase(), target);
+ }
+ if (ctx.T_AT() != null) {
+ if (ctx.T_TO() == null) {
+ conn = evalPop(ctx.expr(1)).toString();
+ }
+ else {
+ conn = evalPop(ctx.expr(2)).toString();
+ }
+ exec.objectConnMap.put(source.toUpperCase(), conn);
+ }
+ if (trace) {
+ String log = "MAP OBJECT " + source;
+ if (target != null) {
+ log += " AS " + target;
+ }
+ if (conn != null) {
+ log += " AT " + conn;
+ }
+ trace(ctx, log);
+ }
+ return 0;
+ }
+
+ /**
+ * UPDATE statement
+ */
+ @Override
+ public Integer visitUpdate_stmt(HplsqlParser.Update_stmtContext ctx) {
+ return stmt.update(ctx);
+ }
+
+ /**
+ * DELETE statement
+ */
+ @Override
+ public Integer visitDelete_stmt(HplsqlParser.Delete_stmtContext ctx) {
+ return stmt.delete(ctx);
+ }
+
+ /**
+ * MERGE statement
+ */
+ @Override
+ public Integer visitMerge_stmt(HplsqlParser.Merge_stmtContext ctx) {
+ return stmt.merge(ctx);
+ }
+
+ /**
+ * Run a Hive command line
+ */
+ @Override
+ public Integer visitHive(@NotNull HplsqlParser.HiveContext ctx) {
+ trace(ctx, "HIVE");
+ ArrayList<String> cmd = new ArrayList<String>();
+ cmd.add("hive");
+ Var params = new Var(Var.Type.STRINGLIST, cmd);
+ stackPush(params);
+ visitChildren(ctx);
+ stackPop();
+ try {
+ String[] cmdarr = new String[cmd.size()];
+ cmd.toArray(cmdarr);
+ if(trace) {
+ trace(ctx, "HIVE Parameters: " + Utils.toString(cmdarr, ' '));
+ }
+ if (!offline) {
+ Process p = Runtime.getRuntime().exec(cmdarr);
+ new StreamGobbler(p.getInputStream()).start();
+ new StreamGobbler(p.getErrorStream()).start();
+ int rc = p.waitFor();
+ if (trace) {
+ trace(ctx, "HIVE Process exit code: " + rc);
+ }
+ }
+ } catch (Exception e) {
+ setSqlCode(-1);
+ signal(Signal.Type.SQLEXCEPTION, e.getMessage(), e);
+ return -1;
+ }
+ return 0;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Integer visitHive_item(HplsqlParser.Hive_itemContext ctx) {
+ Var params = stackPeek();
+ ArrayList<String> a = (ArrayList<String>)params.value;
+ if(ctx.P_e() != null) {
+ a.add("-e");
+ a.add(evalPop(ctx.expr()).toString());
+ }
+ else if(ctx.P_f() != null) {
+ a.add("-f");
+ a.add(evalPop(ctx.expr()).toString());
+ }
+ else if(ctx.P_hiveconf() != null) {
+ a.add("-hiveconf");
+ a.add(ctx.L_ID().toString() + "=" + evalPop(ctx.expr()).toString());
+ }
+ return 0;
+ }
+
+ /**
+ * Executing OS command
+ */
+ @Override
+ public Integer visitHost_cmd(HplsqlParser.Host_cmdContext ctx) {
+ trace(ctx, "HOST");
+ execHost(ctx, ctx.start.getInputStream().getText(
+ new org.antlr.v4.runtime.misc.Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex())));
+ return 0;
+ }
+
+ @Override
+ public Integer visitHost_stmt(HplsqlParser.Host_stmtContext ctx) {
+ trace(ctx, "HOST");
+ execHost(ctx, evalPop(ctx.expr()).toString());
+ return 0;
+ }
+
+ public void execHost(ParserRuleContext ctx, String cmd) {
+ try {
+ if (trace) {
+ trace(ctx, "HOST Command: " + cmd);
+ }
+ Process p = Runtime.getRuntime().exec(cmd);
+ new StreamGobbler(p.getInputStream()).start();
+ new StreamGobbler(p.getErrorStream()).start();
+ int rc = p.waitFor();
+ if (trace) {
+ trace(ctx, "HOST Process exit code: " + rc);
+ }
+ setHostCode(rc);
+ } catch (Exception e) {
+ setHostCode(1);
+ signal(Signal.Type.SQLEXCEPTION);
+ }
+ }
+
+ /**
+ * Standalone expression (as a statement)
+ */
+ @Override
+ public Integer visitExpr_stmt(HplsqlParser.Expr_stmtContext ctx) {
+ visitChildren(ctx);
+ return 0;
+ }
+
+ /**
+ * String concatenation operator
+ */
+ @Override
+ public Integer visitExpr_concat(HplsqlParser.Expr_concatContext ctx) {
+ if (exec.buildSql) {
+ exec.expr.operatorConcatSql(ctx);
+ }
+ else {
+ exec.expr.operatorConcat(ctx);
+ }
+ return 0;
+ }
+
+ /**
+ * Simple CASE expression
+ */
+ @Override
+ public Integer visitExpr_case_simple(HplsqlParser.Expr_case_simpleContext ctx) {
+ if (exec.buildSql) {
+ exec.expr.execSimpleCaseSql(ctx);
+ }
+ else {
+ exec.expr.execSimpleCase(ctx);
+ }
+ return 0;
+ }
+
+ /**
+ * Searched CASE expression
+ */
+ @Override
+ public Integer visitExpr_case_searched(HplsqlParser.Expr_case_searchedContext ctx) {
+ if (exec.buildSql) {
+ exec.expr.execSearchedCaseSql(ctx);
+ }
+ else {
+ exec.expr.execSearchedCase(ctx);
+ }
+ return 0;
+ }
+
+ /**
+ * GET DIAGNOSTICS EXCEPTION statement
+ */
+ @Override
+ public Integer visitGet_diag_stmt_exception_item(HplsqlParser.Get_diag_stmt_exception_itemContext ctx) {
+ return exec.stmt.getDiagnosticsException(ctx);
+ }
+
+ /**
+ * GET DIAGNOSTICS ROW_COUNT statement
+ */
+ @Override
+ public Integer visitGet_diag_stmt_rowcount_item(HplsqlParser.Get_diag_stmt_rowcount_itemContext ctx) {
+ return exec.stmt.getDiagnosticsRowCount(ctx);
+ }
+
+ /**
+ * GRANT statement
+ */
+ @Override
+ public Integer visitGrant_stmt(HplsqlParser.Grant_stmtContext ctx) {
+ trace(ctx, "GRANT");
+ return 0;
+ }
+
+ /**
+ * Label
+ */
+ @Override
+ public Integer visitLabel(HplsqlParser.LabelContext ctx) {
+ exec.labels.push(ctx.L_ID().toString());
+ return 0;
+ }
+
+ /**
+ * Identifier
+ */
+ @Override
+ public Integer visitIdent(HplsqlParser.IdentContext ctx) {
+ String ident = ctx.getText();
+ Var var = findVariable(ident);
+ if (var != null) {
+ if (!exec.buildSql) {
+ exec.stackPush(var);
+ }
+ else {
+ exec.stackPush(new Var(ident, Var.Type.STRING, var.toSqlString()));
+ }
+ }
+ else {
+ exec.stackPush(new Var(Var.Type.IDENT, ident));
+ }
+ return 0;
+ }
+
+ /**
+ * Single quoted string literal
+ */
+ @Override
+ public Integer visitSingle_quotedString(HplsqlParser.Single_quotedStringContext ctx) {
+ if (exec.buildSql) {
+ exec.stackPush(ctx.getText());
+ }
+ else {
+ exec.stackPush(Utils.unquoteString(ctx.getText()));
+ }
+ return 0;
+ }
+
+ /**
+ * Integer literal, signed or unsigned
+ */
+ @Override
+ public Integer visitInt_number(HplsqlParser.Int_numberContext ctx) {
+ exec.stack.push(new Var(new Long(ctx.getText())));
+ return 0;
+ }
+
+ /**
+ * Interval number (1 DAYS i.e)
+ */
+ @Override
+ public Integer visitInterval_number(HplsqlParser.Interval_numberContext ctx) {
+ int num = evalPop(ctx.int_number()).intValue();
+ Interval interval = new Interval().set(num, ctx.interval_item().getText());
+ stackPush(new Var(interval));
+ return 0;
+ }
+
+ /**
+ * Decimal literal, signed or unsigned
+ */
+ @Override
+ public Integer visitDec_number(HplsqlParser.Dec_numberContext ctx) {
+ stackPush(new Var(new BigDecimal(ctx.getText())));
+ return 0;
+ }
+
+ /**
+ * NULL constant
+ */
+ @Override
+ public Integer visitNull_const(HplsqlParser.Null_constContext ctx) {
+ stackPush(new Var());
+ return 0;
+ }
+
+ /**
+ * DATE 'YYYY-MM-DD' literal
+ */
+ @Override
+ public Integer visitDate_literal(HplsqlParser.Date_literalContext ctx) {
+ String str = evalPop(ctx.string()).toString();
+ stackPush(new Var(Var.Type.DATE, Utils.toDate(str)));
+ return 0;
+ }
+
+ /**
+ * TIMESTAMP 'YYYY-MM-DD HH:MI:SS.FFF' literal
+ */
+ @Override
+ public Integer visitTimestamp_literal(HplsqlParser.Timestamp_literalContext ctx) {
+ String str = evalPop(ctx.string()).toString();
+ int len = str.length();
+ int precision = 0;
+ if (len > 19 && len <= 29) {
+ precision = len - 20;
+ if (precision > 3) {
+ precision = 3;
+ }
+ }
+ stackPush(new Var(Utils.toTimestamp(str), precision));
+ return 0;
+ }
+
+ /**
+ * Define the connection profile to execute the current statement
+ */
+ String getStatementConnection() {
+ if (exec.stmtConnList.contains(exec.conf.defaultConnection)) {
+ return exec.conf.defaultConnection;
+ }
+ else if (!exec.stmtConnList.isEmpty()) {
+ return exec.stmtConnList.get(0);
+ }
+ return exec.conf.defaultConnection;
+ }
+
+ /**
+ * Define the connection profile for the specified object
+ * @return
+ */
+ String getObjectConnection(String name) {
+ String conn = exec.objectConnMap.get(name.toUpperCase());
+ if (conn != null) {
+ return conn;
+ }
+ return exec.conf.defaultConnection;
+ }
+
+ /**
+ * Get the connection (open the new connection if not available)
+ * @throws Exception
+ */
+ Connection getConnection(String conn) throws Exception {
+ return exec.conn.getConnection(conn);
+ }
+
+ /**
+ * Return the connection to the pool
+ */
+ void returnConnection(String name, Connection conn) {
+ exec.conn.returnConnection(name, conn);
+ }
+
+ /**
+ * Define the database type by profile name
+ */
+ Conn.Type getConnectionType(String conn) {
+ return exec.conn.getType(conn);
+ }
+
+ /**
+ * Get the current database type
+ */
+ public Conn.Type getConnectionType() {
+ return getConnectionType(exec.conf.defaultConnection);
+ }
+
+ /**
+ * Add managed temporary table
+ */
+ public void addManagedTable(String name, String managedName) {
+ exec.managedTables.put(name, managedName);
+ }
+
+ /**
+ * Get node text including spaces
+ */
+ String getText(ParserRuleContext ctx) {
+ return ctx.start.getInputStream().getText(new org.antlr.v4.runtime.misc.Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
+ }
+
+ String getText(ParserRuleContext ctx, Token start, Token stop) {
+ return ctx.start.getInputStream().getText(new org.antlr.v4.runtime.misc.Interval(start.getStartIndex(), stop.getStopIndex()));
+ }
+
+ /**
+ * 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) {
+ visit(ctx);
+ if (!exec.stack.isEmpty()) {
+ return stackPop();
+ }
+ return new Var(def);
+ }
+
+ /**
+ * Evaluate the data type and length
+ *
+ */
+ String evalPop(HplsqlParser.DtypeContext type, HplsqlParser.Dtype_lenContext len) {
+ if (isConvert(exec.conf.defaultConnection)) {
+ return exec.converter.dataType(type, len);
+ }
+ return getText(type, type.getStart(), len.getStop());
+ }
+
+ /**
+ * Evaluate the expression to NULL
+ */
+ void evalNull() {
+ stackPush(Var.Null);
+ }
+
+ /**
+ * Get formatted text between 2 tokens
+ */
+ public String getFormattedText(ParserRuleContext ctx) {
+ return ctx.start.getInputStream().getText(
+ new org.antlr.v4.runtime.misc.Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
+ }
+
+ /**
+ * Flag whether executed from UDF or not
+ */
+ void setUdfRun(boolean udfRun) {
+ this.udfRun = udfRun;
+ }
+
+ /**
+ * Whether on-the-fly SQL conversion is required for the connection
+ */
+ boolean isConvert(String connName) {
+ return exec.conf.getConnectionConvert(connName);
+ }
+
+ /**
+ * Increment the row count
+ */
+ public int incRowCount() {
+ return exec.rowCount++;
+ }
+
+ /**
+ * Set the row count
+ */
+ public void setRowCount(int rowCount) {
+ exec.rowCount = rowCount;
+ }
+
+ /**
+ * Trace information
+ */
+ public void trace(ParserRuleContext ctx, String message) {
+ if (!trace) {
+ return;
+ }
+ if (ctx != null) {
+ System.out.println("Ln:" + ctx.getStart().getLine() + " " + message);
+ }
+ else {
+ System.out.println(message);
+ }
+ }
+
+ /**
+ * Informational messages
+ */
+ public void info(ParserRuleContext ctx, String message) {
+ if (!info) {
+ return;
+ }
+ if (ctx != null) {
+ System.err.println("Ln:" + ctx.getStart().getLine() + " " + message);
+ }
+ else {
+ System.err.println(message);
+ }
+ }
+
+ public Stack<Var> getStack() {
+ return exec.stack;
+ }
+
+ public int getRowCount() {
+ return exec.rowCount;
+ }
+
+ public Conf getConf() {
+ return exec.conf;
+ }
+
+ public boolean getTrace() {
+ return exec.trace;
+ }
+
+ public boolean getInfo() {
+ return exec.info;
+ }
+
+ public boolean getOffline() {
+ return exec.offline;
+ }
+}
http://git-wip-us.apache.org/repos/asf/hive/blob/052643cb/hplsql/src/main/java/org/apache/hive/hplsql/Expression.java
----------------------------------------------------------------------
diff --git a/hplsql/src/main/java/org/apache/hive/hplsql/Expression.java b/hplsql/src/main/java/org/apache/hive/hplsql/Expression.java
new file mode 100644
index 0000000..f8b01e1
--- /dev/null
+++ b/hplsql/src/main/java/org/apache/hive/hplsql/Expression.java
@@ -0,0 +1,574 @@
+/**
+ * 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.Date;
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.apache.hive.hplsql.Var.Type;
+
+/**
+ * Expressions
+ */
+public class Expression {
+
+ Exec exec;
+ boolean trace = false;
+
+ Expression(Exec e) {
+ exec = e;
+ trace = exec.getTrace();
+ }
+
+ /**
+ * Evaluate an expression
+ */
+ public void exec(HplsqlParser.ExprContext ctx) {
+ if (ctx.T_ADD() != null) {
+ operatorAdd(ctx);
+ }
+ else if (ctx.T_SUB() != null) {
+ operatorSub(ctx);
+ }
+ else if (ctx.interval_item() != null) {
+ createInterval(ctx);
+ }
+ else {
+ visitChildren(ctx);
+ }
+ }
+
+ /**
+ * Evaluate an expression in executable SQL statement
+ */
+ public void execSql(HplsqlParser.ExprContext ctx) {
+ StringBuilder sql = new StringBuilder();
+ if (ctx.T_OPEN_P() != null) {
+ sql.append("(");
+ sql.append(evalPop(ctx.expr(0)).toString());
+ sql.append(")");
+ }
+ else if (ctx.T_ADD() != null) {
+ sql.append(evalPop(ctx.expr(0)).toString());
+ sql.append(" + ");
+ sql.append(evalPop(ctx.expr(1)).toString());
+ }
+ else if (ctx.T_SUB() != null) {
+ sql.append(evalPop(ctx.expr(0)).toString());
+ sql.append(" - ");
+ sql.append(evalPop(ctx.expr(1)).toString());
+ }
+ else if (ctx.interval_item() != null) {
+ sql.append(exec.getFormattedText(ctx));
+ }
+ else {
+ visitChildren(ctx);
+ sql.append(exec.stackPop().toString());
+ }
+ exec.stackPush(sql);
+ }
+
+ /**
+ * Evaluate a boolean expression
+ */
+ public void execBool(HplsqlParser.Bool_exprContext ctx) {
+ if (ctx.T_OPEN_P() != null) {
+ eval(ctx.bool_expr(0));
+ return;
+ }
+ else if (ctx.bool_expr_atom() != null) {
+ eval(ctx.bool_expr_atom());
+ return;
+ }
+ Var result = evalPop(ctx.bool_expr(0));
+ if (ctx.bool_expr_logical_operator() != null) {
+ if (ctx.bool_expr_logical_operator().T_AND() != null) {
+ if (result.isTrue()) {
+ result = evalPop(ctx.bool_expr(1));
+ }
+ }
+ else if (ctx.bool_expr_logical_operator().T_OR() != null) {
+ if (!result.isTrue()) {
+ result = evalPop(ctx.bool_expr(1));
+ }
+ }
+ }
+ exec.stackPush(result);
+ }
+
+ /**
+ * Evaluate a boolean expression in executable SQL statement
+ */
+ public void execBoolSql(HplsqlParser.Bool_exprContext ctx) {
+ StringBuilder sql = new StringBuilder();
+ if (ctx.T_OPEN_P() != null) {
+ sql.append("(");
+ sql.append(evalPop(ctx.bool_expr(0)).toString());
+ sql.append(")");
+ }
+ else if (ctx.bool_expr_atom() != null) {
+ sql.append(evalPop(ctx.bool_expr_atom()).toString());
+ }
+ else if (ctx.bool_expr_logical_operator() != null) {
+ sql.append(evalPop(ctx.bool_expr(0)).toString());
+ sql.append(" " + ctx.bool_expr_logical_operator().getText() + " ");
+ sql.append(evalPop(ctx.bool_expr(1)).toString());
+ }
+ exec.stackPush(sql);
+ }
+
+ /**
+ * Binary boolean expression
+ */
+ public Integer execBoolBinary(HplsqlParser.Bool_expr_binaryContext ctx) {
+ HplsqlParser.Bool_expr_binary_operatorContext op = ctx.bool_expr_binary_operator();
+ if (op.T_EQUAL() != null || op.T_EQUAL2() != null) {
+ operatorEqual(ctx, true);
+ }
+ else if (op.T_NOTEQUAL() != null || op.T_NOTEQUAL2() != null) {
+ operatorEqual(ctx, false);
+ }
+ else if (op.T_GREATER() != null || op.T_LESS() != null || op.T_GREATEREQUAL() != null || op.T_LESSEQUAL() != null) {
+ operatorCompare(ctx, op);
+ }
+ else {
+ exec.stackPush(false);
+ }
+ return 0;
+ }
+
+ /**
+ * Binary boolean expression in executable SQL statement
+ */
+ public Integer execBoolBinarySql(HplsqlParser.Bool_expr_binaryContext ctx) {
+ StringBuilder sql = new StringBuilder();
+ sql.append(evalPop(ctx.expr(0)).toString());
+ sql.append(" " + exec.getFormattedText(ctx.bool_expr_binary_operator()) + " ");
+ sql.append(evalPop(ctx.expr(1)).toString());
+ exec.stackPush(sql);
+ return 0;
+ }
+
+ /**
+ * Unary boolean expression
+ */
+ public Integer execBoolUnary(HplsqlParser.Bool_expr_unaryContext ctx) {
+ boolean val = false;
+ if (ctx.T_IS() != null) {
+ val = evalPop(ctx.expr(0)).isNull();
+ if (ctx.T_NOT() != null) {
+ val = !val;
+ }
+ }
+ else if (ctx.T_BETWEEN() != null) {
+ Var v = evalPop(ctx.expr(0));
+ Var v1 = evalPop(ctx.expr(1));
+ int cmp = v.compareTo(v1);
+ if (cmp >= 0) {
+ Var v2 = evalPop(ctx.expr(2));
+ cmp = v.compareTo(v2);
+ if (cmp <= 0) {
+ val = true;
+ }
+ }
+ }
+ exec.stackPush(val);
+ return 0;
+ }
+
+ /**
+ * Unary boolean expression in executable SQL statement
+ */
+ public Integer execBoolUnarySql(HplsqlParser.Bool_expr_unaryContext ctx) {
+ StringBuilder sql = new StringBuilder();
+ if (ctx.T_IS() != null) {
+ sql.append(evalPop(ctx.expr(0)).toString());
+ sql.append(" " + exec.getText(ctx, ctx.T_IS().getSymbol(), ctx.T_NULL().getSymbol()));
+ }
+ else if (ctx.T_BETWEEN() != null) {
+ sql.append(evalPop(ctx.expr(0)).toString());
+ sql.append(" " + ctx.T_BETWEEN().getText() + " ");
+ sql.append(evalPop(ctx.expr(1)).toString());
+ sql.append(" " + ctx.T_AND().getText() + " ");
+ sql.append(evalPop(ctx.expr(2)).toString());
+ }
+ else if (ctx.bool_expr_single_in() != null) {
+ singleInClauseSql(ctx.bool_expr_single_in(), sql);
+ }
+ else if (ctx.bool_expr_multi_in() != null) {
+ multiInClauseSql(ctx.bool_expr_multi_in(), sql);
+ }
+ exec.stackPush(sql);
+ return 0;
+ }
+
+ /**
+ * Single value IN clause in executable SQL statement
+ */
+ public void singleInClauseSql(HplsqlParser.Bool_expr_single_inContext ctx, StringBuilder sql) {
+ sql.append(evalPop(ctx.expr(0)).toString());
+ if (ctx.T_NOT() != null) {
+ sql.append(" " + ctx.T_NOT().getText());
+ }
+ sql.append(" " + ctx.T_IN().getText() + " (");
+ if (ctx.select_stmt() != null) {
+ sql.append(evalPop(ctx.select_stmt()));
+ }
+ else {
+ int cnt = ctx.expr().size();
+ for (int i = 1; i < cnt; i++) {
+ sql.append(evalPop(ctx.expr(i)).toString());
+ if (i + 1 < cnt) {
+ sql.append(", ");
+ }
+ }
+ }
+ sql.append(")");
+ }
+
+ /**
+ * Multi-value IN clause in executable SQL statement
+ */
+ public void multiInClauseSql(HplsqlParser.Bool_expr_multi_inContext ctx, StringBuilder sql) {
+ int cnt = ctx.expr().size();
+ sql.append("(");
+ for (int i = 0; i < cnt; i++) {
+ sql.append(evalPop(ctx.expr(i)).toString());
+ if (i + 1 < cnt) {
+ sql.append(", ");
+ }
+ }
+ sql.append(")");
+ if (ctx.T_NOT() != null) {
+ sql.append(" " + ctx.T_NOT().getText());
+ }
+ sql.append(" " + ctx.T_IN().getText() + " (");
+ if (ctx.select_stmt() != null) {
+ sql.append(evalPop(ctx.select_stmt()));
+ }
+ sql.append(")");
+ }
+
+ /**
+ * Addition operator
+ */
+ public void operatorAdd(HplsqlParser.ExprContext ctx) {
+ Var v1 = evalPop(ctx.expr(0));
+ Var v2 = evalPop(ctx.expr(1));
+ if (v1.value == null || v2.value == null) {
+ evalNull();
+ }
+ else if (v1.type == Type.BIGINT && v2.type == Type.BIGINT) {
+ exec.stackPush(new Var((Long)v1.value + (Long)v2.value));
+ }
+ else if (v1.type == Type.BIGINT && v2.type == Type.DATE) {
+ exec.stackPush(changeDateByInt((Date)v2.value, (Long)v1.value, true /*add*/));
+ }
+ else if (v1.type == Type.DATE && v2.type == Type.BIGINT) {
+ exec.stackPush(changeDateByInt((Date)v1.value, (Long)v2.value, true /*add*/));
+ }
+ else if (v1.type == Type.DATE && v2.type == Type.INTERVAL) {
+ exec.stackPush(new Var(((Interval)v2.value).dateChange((Date)v1.value, true /*add*/)));
+ }
+ else if (v1.type == Type.TIMESTAMP && v2.type == Type.INTERVAL) {
+ exec.stackPush(new Var(((Interval)v2.value).timestampChange((Timestamp)v1.value, true /*add*/), v1.scale));
+ }
+ }
+
+ /**
+ * Subtraction operator
+ */
+ public void operatorSub(HplsqlParser.ExprContext ctx) {
+ Var v1 = evalPop(ctx.expr(0));
+ Var v2 = evalPop(ctx.expr(1));
+ if (v1.value == null || v2.value == null) {
+ evalNull();
+ }
+ else if (v1.type == Type.BIGINT && v2.type == Type.BIGINT) {
+ exec.stackPush(new Var((Long)v1.value - (Long)v2.value));
+ }
+ else if (v1.type == Type.DATE && v2.type == Type.BIGINT) {
+ exec.stackPush(changeDateByInt((Date)v1.value, (Long)v2.value, false /*subtract*/));
+ }
+ else if (v1.type == Type.DATE && v2.type == Type.INTERVAL) {
+ exec.stackPush(new Var(((Interval)v2.value).dateChange((Date)v1.value, false /*subtract*/)));
+ }
+ else if (v1.type == Type.TIMESTAMP && v2.type == Type.INTERVAL) {
+ exec.stackPush(new Var(((Interval)v2.value).timestampChange((Timestamp)v1.value, false /*subtract*/), v1.scale));
+ }
+ }
+
+ /**
+ * Add or subtract the specified number of days from DATE
+ */
+ public Var changeDateByInt(Date d, Long i, boolean add) {
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(d.getTime());
+ int days = i.intValue();
+ if(!add) {
+ days *= -1;
+ }
+ c.add(Calendar.DAY_OF_MONTH, days);
+ return new Var(new Date(c.getTimeInMillis()));
+ }
+
+ /**
+ * Equality operator
+ */
+ public void operatorEqual(HplsqlParser.Bool_expr_binaryContext ctx, boolean equal) {
+ Var v1 = evalPop(ctx.expr(0));
+ Var v2 = evalPop(ctx.expr(1));
+ boolean eq = v1.equals(v2);
+ if (!equal) {
+ eq = !eq;
+ }
+ exec.stackPush(eq);
+ }
+
+ /**
+ * Comparison operator
+ */
+ public void operatorCompare(HplsqlParser.Bool_expr_binaryContext ctx, HplsqlParser.Bool_expr_binary_operatorContext op) {
+ Var v1 = evalPop(ctx.expr(0));
+ Var v2 = evalPop(ctx.expr(1));
+ int cmp = v1.compareTo(v2);
+ boolean bool = false;
+ if (op.T_GREATER() != null) {
+ if (cmp > 0) {
+ bool = true;
+ }
+ }
+ else if (op.T_GREATEREQUAL() != null) {
+ if (cmp >= 0) {
+ bool = true;
+ }
+ }
+ if (op.T_LESS() != null) {
+ if (cmp < 0) {
+ bool = true;
+ }
+ }
+ else if (op.T_LESSEQUAL() != null) {
+ if (cmp <= 0) {
+ bool = true;
+ }
+ }
+ exec.stackPush(bool);
+ }
+
+ /**
+ * String concatenation operator
+ */
+ public void operatorConcat(HplsqlParser.Expr_concatContext ctx) {
+ StringBuilder val = new StringBuilder();
+ int cnt = ctx.expr_concat_item().size();
+ boolean nulls = true;
+ for (int i = 0; i < cnt; i++) {
+ Var c = evalPop(ctx.expr_concat_item(i));
+ if (!c.isNull()) {
+ val.append(c.toString());
+ nulls = false;
+ }
+ }
+ if (nulls) {
+ evalNull();
+ }
+ else {
+ evalString(val);
+ }
+ }
+
+ /**
+ * String concatenation operator in executable SQL statement
+ */
+ public void operatorConcatSql(HplsqlParser.Expr_concatContext ctx) {
+ StringBuilder sql = new StringBuilder();
+ sql.append("CONCAT(");
+ int cnt = ctx.expr_concat_item().size();
+ for (int i = 0; i < cnt; i++) {
+ sql.append(evalPop(ctx.expr_concat_item(i)).toString());
+ if (i + 1 < cnt) {
+ sql.append(", ");
+ }
+ }
+ sql.append(")");
+ exec.stackPush(sql);
+ }
+
+ /**
+ * Simple CASE expression
+ */
+ public void execSimpleCase(HplsqlParser.Expr_case_simpleContext ctx) {
+ int i = 1;
+ int cnt = ctx.expr().size();
+ boolean found = false;
+ Var val = evalPop(ctx.expr(0));
+ while(i < cnt) {
+ Var when = evalPop(ctx.expr(i));
+ if(val.compareTo(when) == 0) {
+ visit(ctx.expr(i + 1));
+ found = true;
+ break;
+ }
+ i += 2;
+ }
+ if(!found) {
+ if(ctx.T_ELSE() != null) {
+ visit(ctx.expr(cnt - 1));
+ }
+ else {
+ evalNull();
+ }
+ }
+ }
+
+ /**
+ * Simple CASE expression in executable SQL statement
+ */
+ public void execSimpleCaseSql(HplsqlParser.Expr_case_simpleContext ctx) {
+ StringBuilder sql = new StringBuilder();
+ sql.append("CASE ");
+ sql.append(evalPop(ctx.expr(0)).toString());
+ int cnt = ctx.T_WHEN().size();
+ for (int i = 0; i < cnt; i++) {
+ sql.append(" WHEN ");
+ sql.append(evalPop(ctx.expr(i * 2 + 1)).toString());
+ sql.append(" THEN ");
+ sql.append(evalPop(ctx.expr(i * 2 + 2)).toString());
+ }
+ if (ctx.T_ELSE() != null) {
+ sql.append(" ELSE ");
+ sql.append(evalPop(ctx.expr(cnt * 2 + 1)).toString());
+ }
+ sql.append(" END");
+ exec.stackPush(sql);
+ }
+
+ /**
+ * Searched CASE expression
+ */
+ public void execSearchedCase(HplsqlParser.Expr_case_searchedContext ctx) {
+ int cnt = ctx.bool_expr().size();
+ boolean found = false;
+ for(int i = 0; i < cnt; i++) {
+ if(evalPop(ctx.bool_expr(i)).isTrue()) {
+ visit(ctx.expr(i));
+ found = true;
+ break;
+ }
+ }
+ if(!found) {
+ if(ctx.T_ELSE() != null) {
+ visit(ctx.expr(cnt));
+ }
+ else {
+ evalNull();
+ }
+ }
+ }
+
+ /**
+ * Searched CASE expression in executable SQL statement
+ */
+ public void execSearchedCaseSql(HplsqlParser.Expr_case_searchedContext ctx) {
+ StringBuilder sql = new StringBuilder();
+ sql.append("CASE");
+ int cnt = ctx.T_WHEN().size();
+ for (int i = 0; i < cnt; i++) {
+ sql.append(" WHEN ");
+ sql.append(evalPop(ctx.bool_expr(i)).toString());
+ sql.append(" THEN ");
+ sql.append(evalPop(ctx.expr(i)).toString());
+ }
+ if (ctx.T_ELSE() != null) {
+ sql.append(" ELSE ");
+ sql.append(evalPop(ctx.expr(cnt)).toString());
+ }
+ sql.append(" END");
+ exec.stackPush(sql);
+ }
+
+ /**
+ * Create an interval variable
+ */
+ public void createInterval(HplsqlParser.ExprContext ctx) {
+ int num = evalPop(ctx.expr(0)).intValue();
+ Interval interval = new Interval().set(num, ctx.interval_item().getText());
+ exec.stackPush(new Var(interval));
+ }
+
+ /**
+ * Evaluate the expression and push the value to the stack
+ */
+ void eval(ParserRuleContext ctx) {
+ visit(ctx);
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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 to NULL
+ */
+ void evalNull() {
+ exec.stackPush(Var.Null);
+ }
+
+ /**
+ * Execute rules
+ */
+ Integer visit(ParserRuleContext ctx) {
+ return exec.visit(ctx);
+ }
+
+ /**
+ * Execute children rules
+ */
+ Integer visitChildren(ParserRuleContext ctx) {
+ return exec.visitChildren(ctx);
+ }
+
+ /**
+ * Trace information
+ */
+ public void trace(ParserRuleContext ctx, String message) {
+ exec.trace(ctx, message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/hive/blob/052643cb/hplsql/src/main/java/org/apache/hive/hplsql/File.java
----------------------------------------------------------------------
diff --git a/hplsql/src/main/java/org/apache/hive/hplsql/File.java b/hplsql/src/main/java/org/apache/hive/hplsql/File.java
new file mode 100644
index 0000000..6a8ddfe
--- /dev/null
+++ b/hplsql/src/main/java/org/apache/hive/hplsql/File.java
@@ -0,0 +1,132 @@
+/**
+ * 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.io.IOException;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.fs.Path;
+
+/**
+ * HDFS file operations
+ */
+public class File {
+ Path path;
+ FileSystem fs;
+ FSDataInputStream in;
+ FSDataOutputStream out;
+
+ /**
+ * Create FileSystem object
+ */
+ public FileSystem createFs() throws IOException {
+ fs = FileSystem.get(new Configuration());
+ return fs;
+ }
+
+ /**
+ * Create a file
+ */
+ public void create(String dir, String file, boolean overwrite) {
+ path = new Path(dir, file);
+ try {
+ if (fs == null) {
+ fs = FileSystem.get(new Configuration());
+ }
+ out = fs.create(path, overwrite);
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Open an existing file
+ */
+ public void open(String dir, String file) {
+ path = new Path(dir, file);
+ try {
+ if (fs == null) {
+ fs = FileSystem.get(new Configuration());
+ }
+ in = fs.open(path);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Read a character from input
+ * @throws IOException
+ */
+ public char readChar() throws IOException {
+ return in.readChar();
+ }
+
+ /**
+ * Write string to file
+ */
+ public void writeString(String str) {
+ try {
+ out.writeChars(str);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Close a file
+ */
+ public void close() {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ if (out != null) {
+ out.close();
+ }
+ in = null;
+ out = null;
+ path = null;
+ fs = null;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Get the fully-qualified path
+ * NOTE: FileSystem.resolvePath() is not available in Hadoop 1.2.1
+ * @throws IOException
+ */
+ public Path resolvePath(Path path) throws IOException {
+ return fs.getFileStatus(path).getPath();
+ }
+
+ @Override
+ public String toString() {
+ if (path != null) {
+ return "FILE <" + path.toString() + ">";
+ }
+ return "FILE <null>";
+ }
+}
http://git-wip-us.apache.org/repos/asf/hive/blob/052643cb/hplsql/src/main/java/org/apache/hive/hplsql/Handler.java
----------------------------------------------------------------------
diff --git a/hplsql/src/main/java/org/apache/hive/hplsql/Handler.java b/hplsql/src/main/java/org/apache/hive/hplsql/Handler.java
new file mode 100644
index 0000000..6c292ef
--- /dev/null
+++ b/hplsql/src/main/java/org/apache/hive/hplsql/Handler.java
@@ -0,0 +1,41 @@
+/**
+ * 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 org.apache.hive.hplsql.Signal.Type;
+
+/**
+ * HPL/SQL condition and exception handler
+ */
+public class Handler {
+ public enum ExecType { CONTINUE, EXIT };
+ ExecType execType;
+ Type type;
+ String value;
+ Scope scope;
+ HplsqlParser.Declare_handler_itemContext ctx;
+
+ Handler(ExecType execType, Type type, String value, Scope scope, HplsqlParser.Declare_handler_itemContext ctx) {
+ this.execType = execType;
+ this.type = type;
+ this.value = value;
+ this.scope = scope;
+ this.ctx = ctx;
+ }
+}
http://git-wip-us.apache.org/repos/asf/hive/blob/052643cb/hplsql/src/main/java/org/apache/hive/hplsql/Hplsql.java
----------------------------------------------------------------------
diff --git a/hplsql/src/main/java/org/apache/hive/hplsql/Hplsql.java b/hplsql/src/main/java/org/apache/hive/hplsql/Hplsql.java
new file mode 100644
index 0000000..c2545f7
--- /dev/null
+++ b/hplsql/src/main/java/org/apache/hive/hplsql/Hplsql.java
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+public class Hplsql {
+ public static void main(String[] args) throws Exception {
+ System.exit(new Exec().run(args));
+ }
+}
http://git-wip-us.apache.org/repos/asf/hive/blob/052643cb/hplsql/src/main/java/org/apache/hive/hplsql/Interval.java
----------------------------------------------------------------------
diff --git a/hplsql/src/main/java/org/apache/hive/hplsql/Interval.java b/hplsql/src/main/java/org/apache/hive/hplsql/Interval.java
new file mode 100644
index 0000000..92c5d52
--- /dev/null
+++ b/hplsql/src/main/java/org/apache/hive/hplsql/Interval.java
@@ -0,0 +1,109 @@
+/**
+ * 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.Date;
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+/**
+ * Date and time interval
+ */
+public class Interval {
+ int days = 0;
+ int milliseconds = 0;
+
+ /**
+ * Add or subtract interval value to the specified date
+ */
+ public Date dateChange(Date in, boolean add) {
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(in.getTime());
+ calendarChange(c, add);
+ return new Date(c.getTimeInMillis());
+ }
+
+ /**
+ * Add or subtract interval value to the specified timestamp
+ */
+ public Timestamp timestampChange(Timestamp in, boolean add) {
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(in.getTime());
+ calendarChange(c, add);
+ return new Timestamp(c.getTimeInMillis());
+ }
+
+ /**
+ * Add interval value to the specified Calendar value
+ */
+ public Calendar calendarChange(Calendar c, boolean add) {
+ int a = 1;
+ if (!add) {
+ a = -1;
+ }
+ if (days != 0) {
+ c.add(Calendar.DAY_OF_MONTH, days * a);
+ }
+ if (milliseconds != 0) {
+ c.setTimeInMillis(c.getTimeInMillis() + milliseconds * a);
+ }
+ return c;
+ }
+
+ /**
+ * Set interval value
+ */
+ public Interval set(int value, String item) {
+ if (item.compareToIgnoreCase("DAYS") == 0 || item.compareToIgnoreCase("DAY") == 0) {
+ setDays(value);
+ }
+ if (item.compareToIgnoreCase("MICROSECONDS") == 0 || item.compareToIgnoreCase("MICROSECOND") == 0) {
+ setMilliseconds(value);
+ }
+ return this;
+ }
+
+ /**
+ * Set interval items
+ */
+ public void setDays(int days) {
+ this.days = days;
+ }
+
+ public void setMilliseconds(int milliseconds) {
+ this.milliseconds = milliseconds;
+ }
+
+ /**
+ * Convert interval to string
+ */
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ if (days != 0) {
+ s.append(days);
+ s.append(" days");
+ }
+ if (milliseconds != 0) {
+ s.append(milliseconds);
+ s.append(" milliseconds");
+ }
+ return s.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/hive/blob/052643cb/hplsql/src/main/java/org/apache/hive/hplsql/Query.java
----------------------------------------------------------------------
diff --git a/hplsql/src/main/java/org/apache/hive/hplsql/Query.java b/hplsql/src/main/java/org/apache/hive/hplsql/Query.java
new file mode 100644
index 0000000..23d963f
--- /dev/null
+++ b/hplsql/src/main/java/org/apache/hive/hplsql/Query.java
@@ -0,0 +1,155 @@
+/**
+ * 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.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public class Query {
+ String sql;
+ ParserRuleContext sqlExpr;
+ ParserRuleContext sqlSelect;
+
+ Connection conn;
+ Statement stmt;
+ ResultSet rs;
+ Exception exception;
+
+ Query() {
+ }
+
+ Query(String sql) {
+ this.sql = sql;
+ }
+
+ /**
+ * Set query objects
+ */
+ public void set(Connection conn, Statement stmt, ResultSet rs) {
+ this.conn = conn;
+ this.stmt = stmt;
+ this.rs = rs;
+ }
+
+ /**
+ * Get the number of rows
+ */
+ public int getRowCount() {
+ if (!error() && stmt != null) {
+ try {
+ return stmt.getUpdateCount();
+ } catch (SQLException e) {}
+ }
+ return -1;
+ }
+
+ /**
+ * Close statement results
+ */
+ public void closeStatement() {
+ try {
+ if(rs != null) {
+ rs.close();
+ rs = null;
+ }
+ if(stmt != null) {
+ stmt.close();
+ stmt = null;
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Set SQL statement
+ */
+ public void setSql(String sql) {
+ this.sql = sql;
+ }
+
+ /**
+ * Set expression context
+ */
+ public void setExprCtx(ParserRuleContext sqlExpr) {
+ this.sqlExpr = sqlExpr;
+ }
+
+ /**
+ * Set SELECT statement context
+ */
+ public void setSelectCtx(ParserRuleContext sqlSelect) {
+ this.sqlSelect = sqlSelect;
+ }
+
+ /**
+ * Set an execution error
+ */
+ public void setError(Exception e) {
+ exception = e;
+ }
+
+ /**
+ * Print error stack trace
+ */
+ public void printStackTrace() {
+ if(exception != null) {
+ exception.printStackTrace();
+ }
+ }
+
+ /**
+ * Get the result set object
+ */
+ public ResultSet getResultSet() {
+ return rs;
+ }
+
+ /**
+ * Get the connection object
+ */
+ public Connection getConnection() {
+ return conn;
+ }
+
+ /**
+ * Return error information
+ */
+ public boolean error() {
+ return exception != null;
+ }
+
+ public String errorText() {
+ if(exception != null) {
+ if(exception instanceof ClassNotFoundException) {
+ return "ClassNotFoundException: " + exception.getMessage();
+ }
+ return exception.getMessage();
+ }
+ return "";
+ }
+
+ public Exception getException() {
+ return exception;
+ }
+}
http://git-wip-us.apache.org/repos/asf/hive/blob/052643cb/hplsql/src/main/java/org/apache/hive/hplsql/Scope.java
----------------------------------------------------------------------
diff --git a/hplsql/src/main/java/org/apache/hive/hplsql/Scope.java b/hplsql/src/main/java/org/apache/hive/hplsql/Scope.java
new file mode 100644
index 0000000..317a94f
--- /dev/null
+++ b/hplsql/src/main/java/org/apache/hive/hplsql/Scope.java
@@ -0,0 +1,69 @@
+/**
+ * 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.util.ArrayList;
+
+/**
+ * HPL/SQL block scope
+ */
+public class Scope {
+
+ // Types
+ public enum Type { FILE, BEGIN_END, LOOP, HANDLER, ROUTINE };
+
+ // Local variables
+ ArrayList<Var> vars = new ArrayList<Var>();
+ // Condition handlers
+ ArrayList<Handler> handlers = new ArrayList<Handler>();
+
+ Scope parent;
+ Type type;
+
+ Scope(Type type) {
+ this.parent = null;
+ this.type = type;
+ }
+
+ Scope(Scope parent, Type type) {
+ this.parent = parent;
+ this.type = type;
+ }
+
+ /**
+ * Add a local variable
+ */
+ void addVariable(Var var) {
+ vars.add(var);
+ }
+
+ /**
+ * Add a condition handler
+ */
+ void addHandler(Handler handler) {
+ handlers.add(handler);
+ }
+
+ /**
+ * Get the parent scope
+ */
+ Scope getParent() {
+ return parent;
+ }
+}