diff --git hplsql/src/main/antlr4/org/apache/hive/hplsql/Hplsql.g4 hplsql/src/main/antlr4/org/apache/hive/hplsql/Hplsql.g4 index bbe7276..a1083ee 100644 --- hplsql/src/main/antlr4/org/apache/hive/hplsql/Hplsql.g4 +++ hplsql/src/main/antlr4/org/apache/hive/hplsql/Hplsql.g4 @@ -50,6 +50,8 @@ stmt : | create_function_stmt | create_index_stmt | create_local_temp_table_stmt + | create_package_stmt + | create_package_body_stmt | create_procedure_stmt | create_table_stmt | declare_stmt @@ -82,6 +84,7 @@ stmt : | label | hive | host + | null_stmt | expr_stmt | semicolon_stmt // Placed here to allow null statements ;;... ; @@ -99,6 +102,10 @@ exception_block_item : T_WHEN L_ID T_THEN block ~(T_WHEN | T_END) ; +null_stmt : // NULL statement (no operation) + T_NULL + ; + expr_stmt : // Standalone expression {!_input.LT(1).getText().equalsIgnoreCase("GO")}? expr ; @@ -161,6 +168,7 @@ declare_stmt_item : declare_var_item : ident (T_COMMA ident)* T_AS? dtype dtype_len? dtype_attr* dtype_default? + | ident T_CONSTANT T_AS? dtype dtype_len? dtype_default ; declare_condition_item : // Condition declaration @@ -280,6 +288,9 @@ create_table_options_mssql_item : dtype : // Data types T_CHAR | T_BIGINT + | T_BINARY_DOUBLE + | T_BINARY_FLOAT + | T_BINARY_INTEGER | T_BIT | T_DATE | T_DATETIME @@ -293,7 +304,12 @@ dtype : // Data types | T_NVARCHAR | T_NUMBER | T_NUMERIC + | T_PLS_INTEGER + | T_REAL | T_RESULT_SET_LOCATOR T_VARYING + | T_SIMPLE_FLOAT + | T_SIMPLE_DOUBLE + | T_SIMPLE_INTEGER | T_SMALLINT | T_SMALLDATETIME | T_STRING @@ -302,6 +318,7 @@ dtype : // Data types | T_TINYINT | T_VARCHAR | T_VARCHAR2 + | T_XML | L_ID ('%' (T_TYPE | T_ROWTYPE))? // User-defined or derived data type ; @@ -310,7 +327,8 @@ dtype_len : // Data type length or size specification ; dtype_attr : - T_CHARACTER T_SET ident + T_NOT? T_NULL + | T_CHARACTER T_SET ident | T_NOT? (T_CASESPECIFIC | T_CS) ; @@ -326,7 +344,35 @@ create_function_stmt : create_function_return : (T_RETURN | T_RETURNS) dtype dtype_len? ; + +create_package_stmt : + (T_ALTER | T_CREATE (T_OR T_REPLACE)? | T_REPLACE)? T_PACKAGE ident (T_AS | T_IS) package_spec T_END (ident T_SEMICOLON)? + ; + +package_spec : + package_spec_item T_SEMICOLON (package_spec_item T_SEMICOLON)* + ; + +package_spec_item : + declare_stmt_item + | T_FUNCTION ident create_routine_params? create_function_return + | (T_PROCEDURE | T_PROC) ident create_routine_params? + ; +create_package_body_stmt : + (T_ALTER | T_CREATE (T_OR T_REPLACE)? | T_REPLACE)? T_PACKAGE T_BODY ident (T_AS | T_IS) package_body T_END (ident T_SEMICOLON)? + ; + +package_body : + package_body_item T_SEMICOLON (package_body_item T_SEMICOLON)* + ; + +package_body_item : + declare_stmt_item + | create_function_stmt + | create_procedure_stmt + ; + create_procedure_stmt : (T_ALTER | T_CREATE (T_OR T_REPLACE)? | T_REPLACE)? (T_PROCEDURE | T_PROC) ident create_routine_params? create_routine_options? (T_AS | T_IS)? label? proc_block (ident T_SEMICOLON)? ; @@ -817,6 +863,7 @@ expr : expr_atom : date_literal | timestamp_literal + | bool_literal | ident | string | dec_number @@ -988,6 +1035,11 @@ dec_number : // Decimal number (positive or negati ('-' | '+')? L_DEC ; +bool_literal : // Boolean literal + T_TRUE + | T_FALSE + ; + null_const : // NULL constant T_NULL ; @@ -1010,7 +1062,10 @@ non_reserved_words : // Tokens that are not reserved words | T_BEGIN | T_BETWEEN | T_BIGINT + | T_BINARY_DOUBLE + | T_BINARY_FLOAT | T_BIT + | T_BODY | T_BREAK | T_BY | T_BYTE @@ -1026,7 +1081,8 @@ non_reserved_words : // Tokens that are not reserved words | T_CLOSE | T_CLUSTERED | T_CMP - | T_COLLECTION + | T_COLLECTION + | T_CONSTANT | T_COPY | T_COMMIT | T_CONCAT @@ -1081,7 +1137,8 @@ non_reserved_words : // Tokens that are not reserved words | T_EXCEPTION | T_EXCLUSIVE | T_EXISTS - | T_EXIT + | T_EXIT + | T_FALSE | T_FETCH | T_FIELDS | T_FILE @@ -1177,6 +1234,7 @@ non_reserved_words : // Tokens that are not reserved words | T_OVER | T_OVERWRITE | T_OWNER + | T_PACKAGE | T_PART_COUNT | T_PART_LOC | T_PARTITION @@ -1190,6 +1248,7 @@ non_reserved_words : // Tokens that are not reserved words | T_PROCEDURE | T_QUOTED_IDENTIFIER | T_RANK + | T_REAL | T_REFERENCES | T_REGEXP | T_RR @@ -1219,6 +1278,8 @@ non_reserved_words : // Tokens that are not reserved words | T_SETS | T_SHARE | T_SIGNAL + | T_SIMPLE_DOUBLE + | T_SIMPLE_FLOAT | T_SMALLDATETIME | T_SMALLINT | T_SQL @@ -1245,6 +1306,7 @@ non_reserved_words : // Tokens that are not reserved words | T_TO | T_TOP | T_TRIM + | T_TRUE // T_UNION reserved word | T_UNIQUE | T_UPDATE @@ -1267,6 +1329,7 @@ non_reserved_words : // Tokens that are not reserved words | T_WITHOUT | T_WORK | T_XACT_ABORT + | T_XML ; // Lexer rules @@ -1286,7 +1349,11 @@ T_BATCHSIZE : B A T C H S I Z E ; T_BEGIN : B E G I N ; T_BETWEEN : B E T W E E N ; T_BIGINT : B I G I N T ; +T_BINARY_DOUBLE : B I N A R Y '_' D O U B L E ; +T_BINARY_FLOAT : B I N A R Y '_' F L O A T ; +T_BINARY_INTEGER : B I N A R Y '_' I N T E G E R ; T_BIT : B I T ; +T_BODY : B O D Y ; T_BREAK : B R E A K ; T_BY : B Y ; T_BYTE : B Y T E ; @@ -1303,6 +1370,7 @@ T_CLOSE : C L O S E ; T_CLUSTERED : C L U S T E R E D; T_CMP : C M P ; T_COLLECTION : C O L L E C T I O N ; +T_CONSTANT : C O N S T A N T ; T_COPY : C O P Y ; T_COMMIT : C O M M I T ; T_CONCAT : C O N C A T; @@ -1353,6 +1421,7 @@ T_EXCEPTION : E X C E P T I O N ; T_EXCLUSIVE : E X C L U S I V E ; T_EXISTS : E X I S T S ; T_EXIT : E X I T ; +T_FALSE : F A L S E ; T_FETCH : F E T C H ; T_FIELDS : F I E L D S ; T_FILE : F I L E ; @@ -1444,9 +1513,11 @@ T_OUTER : O U T E R ; T_OVER : O V E R ; T_OVERWRITE : O V E R W R I T E ; T_OWNER : O W N E R ; +T_PACKAGE : P A C K A G E ; T_PARTITION : P A R T I T I O N ; T_PCTFREE : P C T F R E E ; T_PCTUSED : P C T U S E D ; +T_PLS_INTEGER : P L S '_' I N T E G E R ; T_PRECISION : P R E C I S I O N ; T_PRESERVE : P R E S E R V E ; T_PRIMARY : P R I M A R Y ; @@ -1454,6 +1525,7 @@ T_PRINT : P R I N T ; T_PROC : P R O C ; T_PROCEDURE : P R O C E D U R E; T_QUOTED_IDENTIFIER : Q U O T E D '_' I D E N T I F I E R ; +T_REAL : R E A L ; T_REFERENCES : R E F E R E N C E S ; T_REGEXP : R E G E X P ; T_REPLACE : R E P L A C E ; @@ -1484,6 +1556,9 @@ T_SET : S E T ; T_SETS : S E T S; T_SHARE : S H A R E ; T_SIGNAL : S I G N A L ; +T_SIMPLE_DOUBLE : S I M P L E '_' D O U B L E ; +T_SIMPLE_FLOAT : S I M P L E '_' F L O A T ; +T_SIMPLE_INTEGER : S I M P L E '_' I N T E G E R ; T_SMALLDATETIME : S M A L L D A T E T I M E ; T_SMALLINT : S M A L L I N T ; T_SQL : S Q L ; @@ -1508,6 +1583,7 @@ T_TINYINT : T I N Y I N T ; T_TITLE : T I T L E ; T_TO : T O ; T_TOP : T O P ; +T_TRUE : T R U E ; T_TYPE : T Y P E ; T_UNION : U N I O N ; T_UNIQUE : U N I Q U E ; @@ -1529,6 +1605,7 @@ T_WITH : W I T H ; T_WITHOUT : W I T H O U T ; T_WORK : W O R K ; T_XACT_ABORT : X A C T '_' A B O R T ; +T_XML : X M L ; // Functions with specific syntax T_ACTIVITY_COUNT : A C T I V I T Y '_' C O U N T ; diff --git hplsql/src/main/java/org/apache/hive/hplsql/Cmp.java hplsql/src/main/java/org/apache/hive/hplsql/Cmp.java index ee65a88..78fea8d 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/Cmp.java +++ hplsql/src/main/java/org/apache/hive/hplsql/Cmp.java @@ -41,6 +41,7 @@ int tests = 0; int failedTests = 0; int failedTestsHighDiff = 0; + int failedTestsHighDiff10 = 0; Cmp(Exec e) { exec = e; @@ -102,7 +103,8 @@ Integer run(HplsqlParser.Cmp_stmtContext ctx) { } else { message += "Not Equal, " + failedTests + " of " + tests + " tests failed"; - message += ", " + failedTestsHighDiff + " failed tests with more than 0.01% difference"; + message += ", " + failedTestsHighDiff + " tests with more than 0.01% difference"; + message += ", " + failedTestsHighDiff10 + " tests with more than 10% difference"; } } else { @@ -173,6 +175,9 @@ else if (query2.error()) { if (diff.compareTo(BigDecimal.ZERO) != 0) { m += ", " + diff + "% difference"; failedTestsHighDiff++; + if (diff.compareTo(BigDecimal.TEN) > 0) { + failedTestsHighDiff10++; + } } else { m += ", less then 0.01% difference"; @@ -180,6 +185,7 @@ else if (query2.error()) { } else { failedTestsHighDiff++; + failedTestsHighDiff10++; } } if (trace) { diff --git hplsql/src/main/java/org/apache/hive/hplsql/Conn.java hplsql/src/main/java/org/apache/hive/hplsql/Conn.java index 12f43c9..a0e0958 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/Conn.java +++ hplsql/src/main/java/org/apache/hive/hplsql/Conn.java @@ -176,27 +176,36 @@ synchronized Connection getConnection(String connName) throws Exception { */ Connection openConnection(String connStr) throws Exception { String driver = "org.apache.hadoop.hive.jdbc.HiveDriver"; - String url = "jdbc:hive://"; + StringBuilder url = new StringBuilder(); String usr = ""; String pwd = ""; if (connStr != null) { String[] c = connStr.split(";"); if (c.length >= 1) { driver = c[0]; - } + } if (c.length >= 2) { - url = c[1]; + url.append(c[1]); } - if (c.length >= 3) { - usr = c[2]; + else { + url.append("jdbc:hive://"); } - if (c.length >= 4) { - pwd = c[3]; + for (int i = 2; i < c.length; i++) { + if (c[i].contains("=")) { + url.append(";"); + url.append(c[i]); + } + else if (usr.isEmpty()) { + usr = c[i]; + } + else if (pwd.isEmpty()) { + pwd = c[i]; + } } } Class.forName(driver); timer.start(); - Connection conn = DriverManager.getConnection(url, usr, pwd); + Connection conn = DriverManager.getConnection(url.toString(), usr, pwd); timer.stop(); if (info) { exec.info(null, "Open connection: " + url + " (" + timer.format() + ")"); diff --git hplsql/src/main/java/org/apache/hive/hplsql/Copy.java hplsql/src/main/java/org/apache/hive/hplsql/Copy.java index 9968b24..cd671eb 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/Copy.java +++ hplsql/src/main/java/org/apache/hive/hplsql/Copy.java @@ -193,6 +193,7 @@ void copyToFile(HplsqlParser.Copy_stmtContext ctx, Query query) throws Exception byte[] nullstr = "NULL".getBytes(); int cols = rm.getColumnCount(); int rows = 0; + long bytes = 0; if (trace || info) { String mes = "Query executed: " + cols + " columns, output file: " + filename; if (trace) { @@ -235,19 +236,23 @@ void copyToFile(HplsqlParser.Copy_stmtContext ctx, Query query) throws Exception for (int i = 1; i <= cols; i++) { if (i > 1) { out.write(del); + bytes += del.length; } col = rs.getString(i); if (col != null) { if (sqlInsert) { col = Utils.quoteString(col); } - out.write(col.getBytes()); + byte[] b = col.getBytes(); + out.write(b); + bytes += b.length; } else if (sqlInsert) { out.write(nullstr); } } out.write(rowdel); + bytes += rowdel.length; rows++; } exec.setRowCount(rows); @@ -259,7 +264,7 @@ else if (sqlInsert) { } long elapsed = timer.stop(); if (info) { - info(ctx, "COPY completed: " + rows + " row(s), " + timer.format() + ", " + rows/elapsed/1000 + " rows/sec"); + info(ctx, "COPY completed: " + rows + " row(s), " + Utils.formatSizeInBytes(bytes) + ", " + timer.format() + ", " + rows/elapsed/1000 + " rows/sec"); } } diff --git hplsql/src/main/java/org/apache/hive/hplsql/Exec.java hplsql/src/main/java/org/apache/hive/hplsql/Exec.java index 38b5380..3a80eca 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/Exec.java +++ hplsql/src/main/java/org/apache/hive/hplsql/Exec.java @@ -62,6 +62,7 @@ // Scopes of execution (code blocks) with own local variables, parameters and exception handlers Stack scopes = new Stack(); + Scope globalScope; Scope currentScope; Stack stack = new Stack(); @@ -77,6 +78,9 @@ HashMap objectMap = new HashMap(); HashMap objectConnMap = new HashMap(); HashMap> returnCursors = new HashMap>(); + HashMap packages = new HashMap(); + + Package currentPackageDecl = null; public ArrayList stmtConnList = new ArrayList(); @@ -175,7 +179,10 @@ public Var setVariableToNull(String name) { * Add a local variable to the current scope */ public void addVariable(Var var) { - if (exec.currentScope != null) { + if (currentPackageDecl != null) { + currentPackageDecl.addVariable(var); + } + else if (exec.currentScope != null) { exec.currentScope.addVariable(var); } } @@ -254,7 +261,7 @@ public Var stackPop() { if (!exec.stack.isEmpty()) { return exec.stack.pop(); } - return null; + return Var.Empty; } /** @@ -288,32 +295,51 @@ public String callStackPop() { * Find an existing variable by name */ public Var findVariable(String name) { + Var var = null; String name1 = name; + String name1a = null; + String name2 = null; Scope cur = exec.currentScope; + Package pack = null; + Package packCallContext = exec.getPackageCallContext(); ArrayList qualified = exec.meta.splitIdentifier(name); if (qualified != null) { - name1 = qualified.get(0); - } - String name2 = null; - if (name.startsWith(":")) { - name2 = name.substring(1); + name1 = qualified.get(0); + name2 = qualified.get(1); + pack = findPackage(name1); + if (pack != null) { + var = pack.findVariable(name2); + if (var != null) { + return var; + } + } + } + if (name1.startsWith(":")) { + name1a = name1.substring(1); } while (cur != null) { - for (Var v : cur.vars) { - if (name1.equalsIgnoreCase(v.getName()) || - (name2 != null && name2.equalsIgnoreCase(v.getName()))) { - if (qualified != null) { - if (v.type == Var.Type.ROW && v.value != null) { - Row row = (Row)v.value; - return row.getValue(qualified.get(1)); - } - } - else { - return v; + var = findVariable(cur.vars, name1); + if (var == null && name1a != null) { + var = findVariable(cur.vars, name1a); + } + if (var == null && packCallContext != null) { + var = packCallContext.findVariable(name1); + } + if (var != null) { + if (qualified != null) { + if (var.type == Var.Type.ROW && var.value != null) { + Row row = (Row)var.value; + var = row.getValue(name2); } - } - } - cur = cur.parent; + } + return var; + } + if (cur.type == Scope.Type.ROUTINE) { + cur = exec.globalScope; + } + else { + cur = cur.parent; + } } return null; } @@ -322,6 +348,15 @@ public Var findVariable(Var name) { return findVariable(name.getName()); } + Var findVariable(ArrayList vars, String name) { + for (Var var : vars) { + if (name.equalsIgnoreCase(var.getName())) { + return var; + } + } + return null; + } + /** * Find a cursor variable by name */ @@ -334,11 +369,32 @@ public Var findCursor(String name) { } /** + * Find the package by name + */ + Package findPackage(String name) { + return packages.get(name.toUpperCase()); + } + + /** * Enter a new scope */ + public void enterScope(Scope scope) { + exec.scopes.push(scope); + } + public void enterScope(Scope.Type type) { - exec.currentScope = new Scope(exec.currentScope, type); - exec.scopes.push(exec.currentScope); + enterScope(type, null); + } + + public void enterScope(Scope.Type type, Package pack) { + exec.currentScope = new Scope(exec.currentScope, type, pack); + enterScope(exec.currentScope); + } + + void enterGlobalScope() { + globalScope = new Scope(Scope.Type.GLOBAL); + currentScope = globalScope; + enterScope(globalScope); } /** @@ -663,9 +719,10 @@ public void setSqlNoData() { } /** - * Compile and run PL/HQL script + * Compile and run HPL/SQL script */ public Integer run(String[] args) throws Exception { + enterGlobalScope(); if (init(args) != 0) { return 1; } @@ -673,13 +730,14 @@ public Integer run(String[] args) throws Exception { if (result != null) { System.out.println(result.toString()); } + leaveScope(); cleanup(); - printExceptions(); + printExceptions(); return getProgramReturnCode(); } /** - * Run already compiled PL/HQL script (also used from Hive UDF) + * Run already compiled HPL/SQL script (also used from Hive UDF) */ public Var run() { if (tree == null) { @@ -694,7 +752,10 @@ public Var run() { else { visit(tree); } - return stackPop(); + if (!exec.stack.isEmpty()) { + return exec.stackPop(); + } + return null; } /** @@ -723,7 +784,6 @@ Integer init(String[] args) throws Exception { 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)); @@ -828,13 +888,11 @@ void include(String content) throws Exception { } /** - * Start executing PL/HQL script + * Start executing HPL/SQL script */ @Override public Integer visitProgram(HplsqlParser.ProgramContext ctx) { - enterScope(Scope.Type.FILE); Integer rc = visitChildren(ctx); - leaveScope(); return rc; } @@ -922,9 +980,9 @@ public Integer visitStmt(HplsqlParser.StmtContext ctx) { return 0; } } - Var prevResult = stackPop(); - if (prevResult != null) { - System.out.println(prevResult.toString()); + Var prev = stackPop(); + if (prev != null && prev.value != null) { + System.out.println(prev.toString()); } return visitChildren(ctx); } @@ -1091,7 +1149,10 @@ public Integer visitDeclare_var_item(HplsqlParser.Declare_var_itemContext ctx) { String name = ctx.ident(i).getText(); if (row == null) { Var var = new Var(name, type, len, scale, default_); - addVariable(var); + exec.addVariable(var); + if (ctx.T_CONSTANT() != null) { + var.setConstant(true); + } if (trace) { if (default_ != null) { trace(ctx, "DECLARE " + name + " " + type + " = " + var.toSqlString()); @@ -1102,7 +1163,7 @@ public Integer visitDeclare_var_item(HplsqlParser.Declare_var_itemContext ctx) { } } else { - addVariable(new Var(name, row)); + exec.addVariable(new Var(name, row)); if (trace) { trace(ctx, "DECLARE " + name + " " + ctx.dtype().getText()); } @@ -1287,7 +1348,39 @@ public Integer visitCreate_function_stmt(HplsqlParser.Create_function_stmtContex addLocalUdf(ctx); return 0; } - + + /** + * CREATE PACKAGE specification statement + */ + @Override + public Integer visitCreate_package_stmt(HplsqlParser.Create_package_stmtContext ctx) { + String name = ctx.ident(0).getText().toUpperCase(); + currentPackageDecl = new Package(name, exec); + packages.put(name, currentPackageDecl); + trace(ctx, "CREATE PACKAGE"); + currentPackageDecl.createSpecification(ctx); + currentPackageDecl = null; + return 0; + } + + /** + * CREATE PACKAGE body statement + */ + @Override + public Integer visitCreate_package_body_stmt(HplsqlParser.Create_package_body_stmtContext ctx) { + String name = ctx.ident(0).getText().toUpperCase(); + currentPackageDecl = packages.get(name); + if (currentPackageDecl == null) { + currentPackageDecl = new Package(name, exec); + currentPackageDecl.setAllMembersPublic(true); + packages.put(name, currentPackageDecl); + } + trace(ctx, "CREATE PACKAGE BODY"); + currentPackageDecl.createBody(ctx); + currentPackageDecl = null; + return 0; + } + /** * CREATE PROCEDURE statement */ @@ -1447,7 +1540,21 @@ public Integer visitExpr_func(HplsqlParser.Expr_funcContext ctx) { exec.function.execSql(name, ctx.expr_func_params()); } else { - exec.function.exec(name, ctx.expr_func_params()); + Package packCallContext = exec.getPackageCallContext(); + ArrayList qualified = exec.meta.splitIdentifier(name); + boolean executed = false; + if (qualified != null) { + Package pack = findPackage(qualified.get(0)); + if (pack != null) { + executed = pack.execFunc(qualified.get(1), ctx.expr_func_params()); + } + } + if (!executed && packCallContext != null) { + executed = packCallContext.execFunc(name, ctx.expr_func_params()); + } + if (!executed) { + exec.function.exec(name, ctx.expr_func_params()); + } } return 0; } @@ -1555,15 +1662,25 @@ public Integer visitExec_stmt(HplsqlParser.Exec_stmtContext ctx) { */ @Override public Integer visitCall_stmt(HplsqlParser.Call_stmtContext ctx) { - try { - exec.inCallStmt = true; - if (exec.function.execProc(ctx.expr_func_params(), ctx.ident().getText())) { - return 0; + String name = ctx.ident().getText(); + Package packCallContext = exec.getPackageCallContext(); + ArrayList qualified = exec.meta.splitIdentifier(name); + exec.inCallStmt = true; + boolean executed = false; + if (qualified != null) { + Package pack = findPackage(qualified.get(0)); + if (pack != null) { + executed = pack.execProc(qualified.get(1), ctx.expr_func_params(), true /*trace error if not exists*/); } - } finally { - exec.inCallStmt = false; } - return -1; + if (!executed && packCallContext != null) { + executed = packCallContext.execProc(name, ctx.expr_func_params(), false /*trace error if not exists*/); + } + if (!executed) { + exec.function.execProc(name, ctx.expr_func_params()); + } + exec.inCallStmt = false; + return 0; } /** @@ -1890,7 +2007,7 @@ public Integer visitIdent(HplsqlParser.IdentContext ctx) { } } else { - if (!exec.buildSql && !exec.inCallStmt && exec.function.isProc(ident) && exec.function.execProc(null, ident)) { + if (!exec.buildSql && !exec.inCallStmt && exec.function.isProc(ident) && exec.function.execProc(ident, null)) { return 0; } else { @@ -1942,6 +2059,19 @@ public Integer visitDec_number(HplsqlParser.Dec_numberContext ctx) { stackPush(new Var(new BigDecimal(ctx.getText()))); return 0; } + + /** + * Boolean literal + */ + @Override + public Integer visitBool_literal(HplsqlParser.Bool_literalContext ctx) { + boolean val = true; + if (ctx.T_FALSE() != null) { + val = false; + } + stackPush(new Var(new Boolean(val))); + return 0; + } /** * NULL constant @@ -1991,6 +2121,20 @@ public Integer visitTimestamp_literal(HplsqlParser.Timestamp_literalContext ctx) } /** + * Get the package context within which the current routine is executed + */ + Package getPackageCallContext() { + Scope cur = exec.currentScope; + while (cur != null) { + if (cur.type == Scope.Type.ROUTINE) { + return cur.pack; + } + cur = cur.parent; + } + return null; + } + + /** * Define the connection profile to execute the current statement */ String getStatementConnection() { diff --git hplsql/src/main/java/org/apache/hive/hplsql/Package.java hplsql/src/main/java/org/apache/hive/hplsql/Package.java new file mode 100644 index 0000000..84fa94a --- /dev/null +++ hplsql/src/main/java/org/apache/hive/hplsql/Package.java @@ -0,0 +1,194 @@ +/** + * 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; +import java.util.HashMap; +import java.util.Map; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.apache.hive.hplsql.HplsqlParser.Package_spec_itemContext; +import org.apache.hive.hplsql.HplsqlParser.Package_body_itemContext; +import org.apache.hive.hplsql.HplsqlParser.Create_function_stmtContext; +import org.apache.hive.hplsql.HplsqlParser.Create_procedure_stmtContext; +import org.apache.hive.hplsql.functions.Function; + +/** + * Program package + */ +public class Package { + + String name; + ArrayList vars = new ArrayList(); + ArrayList publicVars = new ArrayList(); + ArrayList publicFuncs = new ArrayList(); + ArrayList publicProcs = new ArrayList(); + + HashMap func = new HashMap(); + HashMap proc = new HashMap(); + + boolean allMembersPublic = false; + + Exec exec; + Function function; + boolean trace = false; + + Package(String name, Exec exec) { + this.name = name; + this.exec = exec; + this.function = new Function(exec); + this.trace = exec.getTrace(); + } + + /** + * Add a local variable + */ + void addVariable(Var var) { + vars.add(var); + } + + /** + * Find the variable by name + */ + Var findVariable(String name) { + for (Var var : vars) { + if (name.equalsIgnoreCase(var.getName())) { + return var; + } + } + return null; + } + + /** + * Create the package specification + */ + void createSpecification(HplsqlParser.Create_package_stmtContext ctx) { + int cnt = ctx.package_spec().package_spec_item().size(); + for (int i = 0; i < cnt; i++) { + Package_spec_itemContext c = ctx.package_spec().package_spec_item(i); + if (c.declare_stmt_item() != null) { + visit(c); + } + else if (c.T_FUNCTION() != null) { + publicFuncs.add(c.ident().getText().toUpperCase()); + } + else if (c.T_PROC() != null || c.T_PROCEDURE() != null) { + publicProcs.add(c.ident().getText().toUpperCase()); + } + } + } + + /** + * Create the package body + */ + void createBody(HplsqlParser.Create_package_body_stmtContext ctx) { + int cnt = ctx.package_body().package_body_item().size(); + for (int i = 0; i < cnt; i++) { + Package_body_itemContext c = ctx.package_body().package_body_item(i); + if (c.declare_stmt_item() != null) { + visit(c); + } + else if (c.create_function_stmt() != null) { + func.put(c.create_function_stmt().ident().getText().toUpperCase(), c.create_function_stmt()); + } + else if (c.create_procedure_stmt() != null) { + proc.put(c.create_procedure_stmt().ident(0).getText().toUpperCase(), c.create_procedure_stmt()); + } + } + } + + /** + * Execute function + */ + public boolean execFunc(String name, HplsqlParser.Expr_func_paramsContext ctx) { + Create_function_stmtContext f = func.get(name.toUpperCase()); + if (f == null) { + return execProc(name, ctx, false /*trace error if not exists*/); + } + if (trace) { + trace(ctx, "EXEC PACKAGE FUNCTION " + this.name + "." + name); + } + ArrayList actualParams = function.getActualCallParameters(ctx); + exec.enterScope(Scope.Type.ROUTINE, this); + function.setCallParameters(ctx, actualParams, f.create_routine_params(), null); + visit(f.single_block_stmt()); + exec.leaveScope(); + return true; + } + + /** + * Execute rocedure + */ + public boolean execProc(String name, HplsqlParser.Expr_func_paramsContext ctx, boolean traceNotExists) { + Create_procedure_stmtContext p = proc.get(name.toUpperCase()); + if (p == null) { + if (trace && traceNotExists) { + trace(ctx, "Package procedure not found: " + this.name + "." + name); + } + return false; + } + if (trace) { + trace(ctx, "EXEC PACKAGE PROCEDURE " + this.name + "." + name); + } + ArrayList actualParams = function.getActualCallParameters(ctx); + HashMap out = new HashMap(); + exec.enterScope(Scope.Type.ROUTINE, this); + exec.callStackPush(name); + if (p.create_routine_params() != null) { + function.setCallParameters(ctx, actualParams, p.create_routine_params(), out); + } + visit(p.proc_block()); + exec.callStackPop(); + exec.leaveScope(); + for (Map.Entry i : out.entrySet()) { // Set OUT parameters + exec.setVariable(i.getKey(), i.getValue()); + } + return true; + } + + /** + * Set whether all members are public (when package specification is missed) or not + */ + void setAllMembersPublic(boolean value) { + allMembersPublic = value; + } + + /** + * 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) { + if (trace) { + exec.trace(ctx, message); + } + } +} diff --git hplsql/src/main/java/org/apache/hive/hplsql/Scope.java hplsql/src/main/java/org/apache/hive/hplsql/Scope.java index 317a94f..5aea2b3 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/Scope.java +++ hplsql/src/main/java/org/apache/hive/hplsql/Scope.java @@ -25,25 +25,30 @@ */ public class Scope { - // Types - public enum Type { FILE, BEGIN_END, LOOP, HANDLER, ROUTINE }; + public enum Type { GLOBAL, BEGIN_END, LOOP, HANDLER, PACKAGE, ROUTINE }; - // Local variables ArrayList vars = new ArrayList(); - // Condition handlers ArrayList handlers = new ArrayList(); - Scope parent; Type type; + Package pack; Scope(Type type) { this.parent = null; this.type = type; + this.pack = null; } Scope(Scope parent, Type type) { this.parent = parent; this.type = type; + this.pack = null; + } + + Scope(Scope parent, Type type, Package pack) { + this.parent = parent; + this.type = type; + this.pack = pack; } /** diff --git hplsql/src/main/java/org/apache/hive/hplsql/Stmt.java hplsql/src/main/java/org/apache/hive/hplsql/Stmt.java index db9ea65..e6ac196 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/Stmt.java +++ hplsql/src/main/java/org/apache/hive/hplsql/Stmt.java @@ -876,7 +876,7 @@ else if (trace) { public Boolean execProc(HplsqlParser.Exec_stmtContext ctx) { String name = evalPop(ctx.expr()).toString(); if (exec.function.isProc(name)) { - if (exec.function.execProc(ctx.expr_func_params(), name)) { + if (exec.function.execProc(name, ctx.expr_func_params())) { return true; } } diff --git hplsql/src/main/java/org/apache/hive/hplsql/Var.java hplsql/src/main/java/org/apache/hive/hplsql/Var.java index 150e8b4..5f7b355 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/Var.java +++ hplsql/src/main/java/org/apache/hive/hplsql/Var.java @@ -47,6 +47,8 @@ int len; int scale; + boolean constant = false; + public Var() { type = Type.NULL; } @@ -155,7 +157,10 @@ public Var(String name, String type, String len, String scale, Var def) { * Cast a new value to the variable */ public Var cast(Var val) { - if (val == null || val.value == null) { + if (constant) { + return this; + } + else if (val == null || val.value == null) { value = null; } else if (type == Type.DERIVED_TYPE) { @@ -179,6 +184,11 @@ else if (val.type == Type.DOUBLE) { value = BigDecimal.valueOf(val.doubleValue()); } } + else if (type == Type.DOUBLE) { + if (val.type == Type.BIGINT || val.type == Type.DECIMAL) { + value = Double.valueOf(val.doubleValue()); + } + } else if (type == Type.DATE) { value = Utils.toDate(val.toString()); } @@ -192,7 +202,7 @@ else if (type == Type.TIMESTAMP) { * Cast a new string value to the variable */ public Var cast(String val) { - if (type == Type.STRING) { + if (!constant && type == Type.STRING) { if (len != 0 ) { int l = val.length(); if (l > len) { @@ -209,27 +219,29 @@ public Var cast(String val) { * Set the new value */ public void setValue(String str) { - if(type == Type.STRING) { + if(!constant && type == Type.STRING) { value = str; } } public Var setValue(Long val) { - if (type == Type.BIGINT) { + if (!constant && type == Type.BIGINT) { value = val; } return this; } public Var setValue(Boolean val) { - if (type == Type.BOOL) { + if (!constant && type == Type.BOOL) { value = val; } return this; } public void setValue(Object value) { - this.value = value; + if (!constant) { + this.value = value; + } } /** @@ -280,7 +292,14 @@ void setType(String type) { */ void setType(int type) { this.type = defineType(type); - } + } + + /** + * Set the variable as constant + */ + void setConstant(boolean constant) { + this.constant = constant; + } /** * Define the data type from string representation @@ -290,16 +309,22 @@ public static Type defineType(String type) { return Type.NULL; } else if (type.equalsIgnoreCase("INT") || type.equalsIgnoreCase("INTEGER") || type.equalsIgnoreCase("BIGINT") || - type.equalsIgnoreCase("SMALLINT") || type.equalsIgnoreCase("TINYINT")) { + type.equalsIgnoreCase("SMALLINT") || type.equalsIgnoreCase("TINYINT") || + type.equalsIgnoreCase("BINARY_INTEGER") || type.equalsIgnoreCase("PLS_INTEGER") || + type.equalsIgnoreCase("SIMPLE_INTEGER")) { return Type.BIGINT; } - else if (type.equalsIgnoreCase("CHAR") || type.equalsIgnoreCase("VARCHAR") || type.equalsIgnoreCase("STRING")) { + else if (type.equalsIgnoreCase("CHAR") || type.equalsIgnoreCase("VARCHAR") || type.equalsIgnoreCase("STRING") || + type.equalsIgnoreCase("XML")) { return Type.STRING; } - else if (type.equalsIgnoreCase("DEC") || type.equalsIgnoreCase("DECIMAL") || type.equalsIgnoreCase("NUMERIC")) { + else if (type.equalsIgnoreCase("DEC") || type.equalsIgnoreCase("DECIMAL") || type.equalsIgnoreCase("NUMERIC") || + type.equalsIgnoreCase("NUMBER")) { return Type.DECIMAL; } - else if (type.equalsIgnoreCase("FLOAT") || type.toUpperCase().startsWith("DOUBLE")) { + else if (type.equalsIgnoreCase("REAL") || type.equalsIgnoreCase("FLOAT") || type.toUpperCase().startsWith("DOUBLE") || + type.equalsIgnoreCase("BINARY_FLOAT") || type.toUpperCase().startsWith("BINARY_DOUBLE") || + type.equalsIgnoreCase("SIMPLE_FLOAT") || type.toUpperCase().startsWith("SIMPLE_DOUBLE")) { return Type.DOUBLE; } else if (type.equalsIgnoreCase("DATE")) { @@ -308,6 +333,9 @@ else if (type.equalsIgnoreCase("DATE")) { else if (type.equalsIgnoreCase("TIMESTAMP")) { return Type.TIMESTAMP; } + else if (type.equalsIgnoreCase("BOOL") || type.equalsIgnoreCase("BOOLEAN")) { + return Type.BOOL; + } else if (type.equalsIgnoreCase("SYS_REFCURSOR")) { return Type.CURSOR; } @@ -489,6 +517,12 @@ public double doubleValue() { if (type == Type.DOUBLE) { return ((Double)value).doubleValue(); } + else if (type == Type.BIGINT) { + return ((Long)value).doubleValue(); + } + else if (type == Type.DECIMAL) { + return ((BigDecimal)value).doubleValue(); + } return -1; } diff --git hplsql/src/main/java/org/apache/hive/hplsql/functions/Function.java hplsql/src/main/java/org/apache/hive/hplsql/functions/Function.java index aa40a0a..70ef995 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/functions/Function.java +++ hplsql/src/main/java/org/apache/hive/hplsql/functions/Function.java @@ -22,6 +22,7 @@ import java.sql.Date; import java.sql.SQLException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.Map; @@ -68,10 +69,10 @@ public void register(Function f) { * Execute a function */ public void exec(String name, HplsqlParser.Expr_func_paramsContext ctx) { - if (execUser(ctx, name)) { + if (execUser(name, ctx)) { return; } - else if (isProc(name) && execProc(ctx, name)) { + else if (isProc(name) && execProc(name, ctx)) { return; } if (name.indexOf(".") != -1) { // Name can be qualified and spaces are allowed between parts @@ -93,6 +94,7 @@ else if (isProc(name) && execProc(ctx, name)) { func.run(ctx); } else { + info(ctx, "Function not found: " + name); evalNull(); } } @@ -130,7 +132,7 @@ public void execAggWindowSql(HplsqlParser.Expr_agg_window_funcContext ctx) { /** * Execute a user-defined function */ - public boolean execUser(HplsqlParser.Expr_func_paramsContext ctx, String name) { + public boolean execUser(String name, HplsqlParser.Expr_func_paramsContext ctx) { HplsqlParser.Create_function_stmtContext userCtx = userMap.get(name.toUpperCase()); if (userCtx == null) { return false; @@ -138,8 +140,9 @@ public boolean execUser(HplsqlParser.Expr_func_paramsContext ctx, String name) { if (trace) { trace(ctx, "EXEC FUNCTION " + name); } + ArrayList actualParams = getActualCallParameters(ctx); exec.enterScope(Scope.Type.ROUTINE); - setCallParameters(ctx, userCtx.create_routine_params(), null); + setCallParameters(ctx, actualParams, userCtx.create_routine_params(), null); visit(userCtx.single_block_stmt()); exec.leaveScope(); return true; @@ -216,7 +219,7 @@ public boolean isProc(String name) { /** * Execute a stored procedure using CALL or EXEC statement passing parameters */ - public boolean execProc(HplsqlParser.Expr_func_paramsContext ctx, String name) { + public boolean execProc(String name, HplsqlParser.Expr_func_paramsContext ctx) { if (trace) { trace(ctx, "EXEC PROCEDURE " + name); } @@ -225,11 +228,12 @@ public boolean execProc(HplsqlParser.Expr_func_paramsContext ctx, String name) { trace(ctx, "Procedure not found"); return false; } + ArrayList actualParams = getActualCallParameters(ctx); HashMap out = new HashMap(); exec.enterScope(Scope.Type.ROUTINE); exec.callStackPush(name); if (procCtx.create_routine_params() != null) { - setCallParameters(ctx, procCtx.create_routine_params(), out); + setCallParameters(ctx, actualParams, procCtx.create_routine_params(), out); } visit(procCtx.proc_block()); exec.callStackPop(); @@ -243,13 +247,13 @@ public boolean execProc(HplsqlParser.Expr_func_paramsContext ctx, String name) { /** * Set parameters for user-defined function call */ - void setCallParameters(HplsqlParser.Expr_func_paramsContext actual, + public void setCallParameters(HplsqlParser.Expr_func_paramsContext actual, ArrayList actualValues, HplsqlParser.Create_routine_paramsContext formal, HashMap out) { - if (actual == null || actual.func_param() == null) { + if (actual == null || actual.func_param() == null || actualValues == null) { return; } - int actualCnt = actual.func_param().size(); + int actualCnt = actualValues.size(); int formalCnt = formal.create_routine_param_item().size(); for (int i = 0; i < actualCnt; i++) { if (i >= formalCnt) { @@ -267,8 +271,7 @@ void setCallParameters(HplsqlParser.Expr_func_paramsContext actual, scale = p.dtype_len().L_INT(1).getText(); } } - Var value = evalPop(a); - Var var = setCallParameter(name, type, len, scale, value); + Var var = setCallParameter(name, type, len, scale, actualValues.get(i)); if (trace) { trace(actual, "SET PARAM " + name + " = " + var.toString()); } @@ -338,6 +341,21 @@ Var setCallParameter(String name, String type, String len, String scale, Var val } /** + * Evaluate actual call parameters + */ + public ArrayList getActualCallParameters(HplsqlParser.Expr_func_paramsContext actual) { + if (actual == null || actual.func_param() == null) { + return null; + } + int cnt = actual.func_param().size(); + ArrayList values = new ArrayList(cnt); + for (int i = 0; i < cnt; i++) { + values.add(evalPop(actual.func_param(i).expr())); + } + return values; + } + + /** * Add a user-defined function */ public void addUserFunction(HplsqlParser.Create_function_stmtContext ctx) { @@ -756,4 +774,8 @@ public void trace(ParserRuleContext ctx, String message) { public void trace(String message) { trace(null, message); } + + public void info(ParserRuleContext ctx, String message) { + exec.info(ctx, message); + } } diff --git hplsql/src/main/java/org/apache/hive/hplsql/functions/FunctionOra.java hplsql/src/main/java/org/apache/hive/hplsql/functions/FunctionOra.java index 405bfab..462d930 100644 --- hplsql/src/main/java/org/apache/hive/hplsql/functions/FunctionOra.java +++ hplsql/src/main/java/org/apache/hive/hplsql/functions/FunctionOra.java @@ -34,33 +34,32 @@ public FunctionOra(Exec e) { @Override public void register(Function f) { f.map.put("DBMS_OUTPUT.PUT_LINE", new FuncCommand() { public void run(HplsqlParser.Expr_func_paramsContext ctx) { - execDbmsOutputPutLine(ctx); }}); + dbmsOutputPutLine(ctx); }}); f.map.put("UTL_FILE.FOPEN", new FuncCommand() { public void run(HplsqlParser.Expr_func_paramsContext ctx) { - execUtlFileFopen(ctx); }}); + utlFileFopen(ctx); }}); f.map.put("UTL_FILE.GET_LINE", new FuncCommand() { public void run(HplsqlParser.Expr_func_paramsContext ctx) { - execUtlFileGetLine(ctx); }}); + utlFileGetLine(ctx); }}); f.map.put("UTL_FILE.PUT_LINE", new FuncCommand() { public void run(HplsqlParser.Expr_func_paramsContext ctx) { - execUtlFilePutLine(ctx); }}); + utlFilePutLine(ctx); }}); f.map.put("UTL_FILE.PUT", new FuncCommand() { public void run(HplsqlParser.Expr_func_paramsContext ctx) { - execUtlFilePut(ctx); }}); + utlFilePut(ctx); }}); f.map.put("UTL_FILE.FCLOSE", new FuncCommand() { public void run(HplsqlParser.Expr_func_paramsContext ctx) { - execUtlFileFclose(ctx); }}); + utlFileFclose(ctx); }}); } /** * Print a text message */ - void execDbmsOutputPutLine(HplsqlParser.Expr_func_paramsContext ctx) { + void dbmsOutputPutLine(HplsqlParser.Expr_func_paramsContext ctx) { if (ctx.func_param().size() > 0) { - visit(ctx.func_param(0).expr()); - System.out.println(exec.stackPop().toString()); + System.out.println(evalPop(ctx.func_param(0).expr())); } } /** * Execute UTL_FILE.FOPEN function */ - public void execUtlFileFopen(HplsqlParser.Expr_func_paramsContext ctx) { + public void utlFileFopen(HplsqlParser.Expr_func_paramsContext ctx) { String dir = ""; String name = ""; boolean write = true; @@ -98,7 +97,7 @@ else if (mode.equalsIgnoreCase("w")) { /** * Read a text line from an open file */ - void execUtlFileGetLine(HplsqlParser.Expr_func_paramsContext ctx) { + void utlFileGetLine(HplsqlParser.Expr_func_paramsContext ctx) { int cnt = ctx.func_param().size(); Var file = null; Var str = null; @@ -152,21 +151,21 @@ else if(trace) { /** * Execute UTL_FILE.PUT_LINE function */ - public void execUtlFilePutLine(HplsqlParser.Expr_func_paramsContext ctx) { - execUtlFilePut(ctx, true /*newline*/); + public void utlFilePutLine(HplsqlParser.Expr_func_paramsContext ctx) { + utlFilePut(ctx, true /*newline*/); } /** * Execute UTL_FILE.PUT function */ - public void execUtlFilePut(HplsqlParser.Expr_func_paramsContext ctx) { - execUtlFilePut(ctx, false /*newline*/); + public void utlFilePut(HplsqlParser.Expr_func_paramsContext ctx) { + utlFilePut(ctx, false /*newline*/); } /** * Write a string to file */ - void execUtlFilePut(HplsqlParser.Expr_func_paramsContext ctx, boolean newline) { + void utlFilePut(HplsqlParser.Expr_func_paramsContext ctx, boolean newline) { int cnt = ctx.func_param().size(); Var file = null; String str = ""; @@ -203,7 +202,7 @@ else if(trace) { /** * Execute UTL_FILE.FCLOSE function */ - void execUtlFileFclose(HplsqlParser.Expr_func_paramsContext ctx) { + void utlFileFclose(HplsqlParser.Expr_func_paramsContext ctx) { int cnt = ctx.func_param().size(); Var file = null; diff --git hplsql/src/main/resources/hplsql-site.xml hplsql/src/main/resources/hplsql-site.xml index 1a3202a..7e2d92d 100644 --- hplsql/src/main/resources/hplsql-site.xml +++ hplsql/src/main/resources/hplsql-site.xml @@ -1,7 +1,7 @@ hplsql.conn.default - hiveconn + hive2conn The default connection profile diff --git hplsql/src/test/java/org/apache/hive/hplsql/TestHplsqlLocal.java hplsql/src/test/java/org/apache/hive/hplsql/TestHplsqlLocal.java index 8299828..042bacf 100644 --- hplsql/src/test/java/org/apache/hive/hplsql/TestHplsqlLocal.java +++ hplsql/src/test/java/org/apache/hive/hplsql/TestHplsqlLocal.java @@ -44,6 +44,11 @@ public void testAssign() throws Exception { } @Test + public void testBool() throws Exception { + run("bool"); + } + + @Test public void testBoolExpr() throws Exception { run("bool_expr"); } @@ -89,6 +94,16 @@ public void testCreateFunction2() throws Exception { } @Test + public void testCreatePackage() throws Exception { + run("create_package"); + } + + @Test + public void testCreatePackage2() throws Exception { + run("create_package2"); + } + + @Test public void testCreateProcedure() throws Exception { run("create_procedure"); } @@ -103,6 +118,11 @@ public void testCreateProcedureNoParams() throws Exception { } @Test + public void testDatatypes() throws Exception { + run("datatypes"); + } + + @Test public void testDate() throws Exception { run("date"); } @@ -118,6 +138,11 @@ public void testDeclare() throws Exception { } @Test + public void testDeclare2() throws Exception { + run("declare2"); + } + + @Test public void testDeclareCondition() throws Exception { run("declare_condition"); } @@ -158,6 +183,11 @@ public void testExpr() throws Exception { } @Test + public void testFloat() throws Exception { + run("float"); + } + + @Test public void testForRange() throws Exception { run("for_range"); } @@ -295,6 +325,16 @@ public void testUpper() throws Exception { public void testValuesInto() throws Exception { run("values_into"); } + + @Test + public void testVarScope() throws Exception { + run("var_scope"); + } + + @Test + public void testVarScope2() throws Exception { + run("var_scope2"); + } @Test public void testWhile() throws Exception { diff --git hplsql/src/test/java/org/apache/hive/hplsql/TestHplsqlOffline.java hplsql/src/test/java/org/apache/hive/hplsql/TestHplsqlOffline.java index 55238ed..b9d80c7 100644 --- hplsql/src/test/java/org/apache/hive/hplsql/TestHplsqlOffline.java +++ hplsql/src/test/java/org/apache/hive/hplsql/TestHplsqlOffline.java @@ -44,6 +44,11 @@ public void testCreateTableOra() throws Exception { } @Test + public void testInsertMysql() throws Exception { + run("insert_mysql"); + } + + @Test public void testSelectDb2() throws Exception { run("select_db2"); } diff --git hplsql/src/test/queries/local/bool.sql hplsql/src/test/queries/local/bool.sql new file mode 100644 index 0000000..f8f07ad --- /dev/null +++ hplsql/src/test/queries/local/bool.sql @@ -0,0 +1,14 @@ +declare b1 bool = true; +declare b2 boolean = false; + +set b1 = false; +set b2 = true; + +if b2 then + print 'ok'; +else + print 'failed'; +end if; + +print b1; +print b2; \ No newline at end of file diff --git hplsql/src/test/queries/local/create_package.sql hplsql/src/test/queries/local/create_package.sql new file mode 100644 index 0000000..c06547c --- /dev/null +++ hplsql/src/test/queries/local/create_package.sql @@ -0,0 +1,60 @@ +create or replace package pack1 as + a int := 3; + function f1 (p1 number, p2 number) return number; + procedure sp1(p1 number); +end; + +create or replace package body pack1 as + b int := 1; + function f1 (p1 number, p2 number) return number + is + begin + dbms_output.put_line('a: ' || a); + dbms_output.put_line('b: ' || b); + dbms_output.put_line('p1: ' || p1); + dbms_output.put_line('p2: ' || p2); + if 1=1 then + dbms_output.put_line('f2: ' || f2()); + end if; + dbms_output.put_line('pack1.f2: ' || pack1.f2()); + sp1(a); + sp2(b); + call sp3(a); + return p1 + p2 + a + b; + end; + + function f2 return number + is + begin + return 1; + end; + + procedure sp1(p1 number) + is + begin + dbms_output.put_line('a: ' || a); + dbms_output.put_line('b: ' || b); + dbms_output.put_line('p1: ' || p1); + end; + + procedure sp3(p1 number) -- private procedure + is + begin + dbms_output.put_line('a: ' || a); + dbms_output.put_line('b: ' || b); + dbms_output.put_line('p1: ' || p1); + end; +end; + +create procedure sp2(p2 number) +is +begin + dbms_output.put_line('pack1.a: ' || pack1.a); + dbms_output.put_line('p2: ' || p2); +end; + +dbms_output.put_line('pack1.a: ' || pack1.a); +dbms_output.put_line('pack1.f1: ' || pack1.f1(3,5)); +pack1.sp1(1); +call pack1.sp1(1); + diff --git hplsql/src/test/queries/local/create_package2.sql hplsql/src/test/queries/local/create_package2.sql new file mode 100644 index 0000000..384153d --- /dev/null +++ hplsql/src/test/queries/local/create_package2.sql @@ -0,0 +1,23 @@ +create or replace package users as + session_count int := 0; + function get_count() return int; + procedure add(name varchar(100)); +end; + +create or replace package body users as + function get_count() return int + is + begin + return session_count; + end; + procedure add(name varchar(100)) + is + begin + session_count = session_count + 1; + end; +end; + +users.add('John'); +users.add('Sarah'); +users.add('Paul'); +print 'Number of users: ' || users.get_count(); \ No newline at end of file diff --git hplsql/src/test/queries/local/datatypes.sql hplsql/src/test/queries/local/datatypes.sql new file mode 100644 index 0000000..a30eecf --- /dev/null +++ hplsql/src/test/queries/local/datatypes.sql @@ -0,0 +1,20 @@ +declare i1 binary_integer default 1; +declare i2 pls_integer default 3; +declare i3 simple_integer default 5; +print i1; +print i2; +print i3; + +declare f1 BINARY_FLOAT DEFAULT 0.1; +declare f2 BINARY_DOUBLE DEFAULT 1.1; +declare f3 SIMPLE_FLOAT DEFAULT 3.1; +declare f4 SIMPLE_DOUBLE DEFAULT 1.3; +declare f5 real default 1.5; +print f1; +print f2; +print f3; +print f4; +print f5; + +declare x1 xml default 'abc'; +print x1; diff --git hplsql/src/test/queries/local/declare2.sql hplsql/src/test/queries/local/declare2.sql new file mode 100644 index 0000000..992d09e --- /dev/null +++ hplsql/src/test/queries/local/declare2.sql @@ -0,0 +1,13 @@ +declare + code char(10) not null := 'a'; + status constant int := 1; +begin + print code; + print status; +end; + +declare + code char(10) not null := 'a'; +begin + null; +end; diff --git hplsql/src/test/queries/local/float.sql hplsql/src/test/queries/local/float.sql new file mode 100644 index 0000000..fde7f21 --- /dev/null +++ hplsql/src/test/queries/local/float.sql @@ -0,0 +1,4 @@ +DECLARE float_test FLOAT DEFAULT 0; +SET float_test = 2.1; +PRINT float_test; +PRINT CHAR(float_test); \ No newline at end of file diff --git hplsql/src/test/queries/local/var_scope.sql hplsql/src/test/queries/local/var_scope.sql new file mode 100644 index 0000000..cedf61b --- /dev/null +++ hplsql/src/test/queries/local/var_scope.sql @@ -0,0 +1,28 @@ +include 'src/test/queries/local/var_scope_include.sql' + +declare i int = 3; + +proc p1 +begin + print 'i: ' || i; + print 'j: ' || j; + print 'k: ' || k; +end; + + +proc p2 +begin + declare j int = 5; + print 'i: ' || i; + print 'j: ' || j; + print 'k: ' || k; + p1(); +end; + +p2(); +print 'i: ' || i; +print 'j: ' || j; +print 'k: ' || k; + + + diff --git hplsql/src/test/queries/local/var_scope2.sql hplsql/src/test/queries/local/var_scope2.sql new file mode 100644 index 0000000..eb25ce5 --- /dev/null +++ hplsql/src/test/queries/local/var_scope2.sql @@ -0,0 +1,30 @@ +declare i int = 3; + +function f1(p1 int) return int +begin + declare j int = 7; + print 'p1: ' || p1; + return f2(j); +end + +function f2(p1 int) return int +begin + print 'p1: ' || p1; + return p1; +end + +proc sp1(p1 int) +begin + declare j int = 7; + print 'p1: ' || p1; + call sp2(j); +end + +proc sp2(p1 int) +begin + print 'p1: ' || p1; +end + + +f1(i); +call sp1(i); diff --git hplsql/src/test/queries/local/var_scope_include.sql hplsql/src/test/queries/local/var_scope_include.sql new file mode 100644 index 0000000..cf91edb --- /dev/null +++ hplsql/src/test/queries/local/var_scope_include.sql @@ -0,0 +1 @@ +declare k int = 7; \ No newline at end of file diff --git hplsql/src/test/queries/offline/insert_mysql.sql hplsql/src/test/queries/offline/insert_mysql.sql new file mode 100644 index 0000000..9ff5611 --- /dev/null +++ hplsql/src/test/queries/offline/insert_mysql.sql @@ -0,0 +1,2 @@ +MAP OBJECT ua TO user_age AT mysqlconn; +INSERT INTO ua(id,age) VALUES(22,33); \ No newline at end of file diff --git hplsql/src/test/results/local/bool.out.txt hplsql/src/test/results/local/bool.out.txt new file mode 100644 index 0000000..999e10a --- /dev/null +++ hplsql/src/test/results/local/bool.out.txt @@ -0,0 +1,12 @@ +Ln:1 DECLARE b1 bool = true +Ln:2 DECLARE b2 boolean = false +Ln:4 SET b1 = false +Ln:5 SET b2 = true +Ln:7 IF +Ln:7 IF TRUE executed +Ln:8 PRINT +ok +Ln:13 PRINT +false +Ln:14 PRINT +true \ No newline at end of file diff --git hplsql/src/test/results/local/create_package.out.txt hplsql/src/test/results/local/create_package.out.txt new file mode 100644 index 0000000..ee7a9a0 --- /dev/null +++ hplsql/src/test/results/local/create_package.out.txt @@ -0,0 +1,47 @@ +Ln:1 CREATE PACKAGE +Ln:2 DECLARE a int = 3 +Ln:7 CREATE PACKAGE BODY +Ln:8 DECLARE b int = 1 +Ln:49 CREATE PROCEDURE sp2 +pack1.a: 3 +Ln:57 EXEC PACKAGE FUNCTION PACK1.f1 +Ln:57 SET PARAM p1 = 3 +Ln:57 SET PARAM p2 = 5 +a: 3 +b: 1 +p1: 3 +p2: 5 +Ln:16 IF +Ln:16 IF TRUE executed +EXEC PACKAGE FUNCTION PACK1.f2 +Ln:29 RETURN +f2: 1 +EXEC PACKAGE FUNCTION PACK1.f2 +Ln:29 RETURN +pack1.f2: 1 +Ln:20 EXEC PACKAGE PROCEDURE PACK1.sp1 +Ln:20 SET PARAM p1 = 3 +a: 3 +b: 1 +p1: 3 +Ln:21 EXEC PROCEDURE sp2 +Ln:21 SET PARAM p2 = 1 +pack1.a: 3 +p2: 1 +Ln:22 EXEC PACKAGE PROCEDURE PACK1.sp3 +Ln:22 SET PARAM p1 = 3 +a: 3 +b: 1 +p1: 3 +Ln:23 RETURN +pack1.f1: +Ln:58 EXEC PACKAGE PROCEDURE PACK1.sp1 +Ln:58 SET PARAM p1 = 1 +a: 3 +b: 1 +p1: 1 +Ln:59 EXEC PACKAGE PROCEDURE PACK1.sp1 +Ln:59 SET PARAM p1 = 1 +a: 3 +b: 1 +p1: 1 \ No newline at end of file diff --git hplsql/src/test/results/local/create_package2.out.txt hplsql/src/test/results/local/create_package2.out.txt new file mode 100644 index 0000000..d8b7c44 --- /dev/null +++ hplsql/src/test/results/local/create_package2.out.txt @@ -0,0 +1,16 @@ +Ln:1 CREATE PACKAGE +Ln:2 DECLARE session_count int = 0 +Ln:7 CREATE PACKAGE BODY +Ln:20 EXEC PACKAGE PROCEDURE USERS.add +Ln:20 SET PARAM name = John +Ln:16 SET session_count = 1 +Ln:21 EXEC PACKAGE PROCEDURE USERS.add +Ln:21 SET PARAM name = Sarah +Ln:16 SET session_count = 2 +Ln:22 EXEC PACKAGE PROCEDURE USERS.add +Ln:22 SET PARAM name = Paul +Ln:16 SET session_count = 3 +Ln:23 PRINT +EXEC PACKAGE FUNCTION USERS.get_count +Ln:11 RETURN +Number of users: 3 \ No newline at end of file diff --git hplsql/src/test/results/local/datatypes.out.txt hplsql/src/test/results/local/datatypes.out.txt new file mode 100644 index 0000000..3434016 --- /dev/null +++ hplsql/src/test/results/local/datatypes.out.txt @@ -0,0 +1,27 @@ +Ln:1 DECLARE i1 binary_integer = 1 +Ln:2 DECLARE i2 pls_integer = 3 +Ln:3 DECLARE i3 simple_integer = 5 +Ln:4 PRINT +1 +Ln:5 PRINT +3 +Ln:6 PRINT +5 +Ln:8 DECLARE f1 BINARY_FLOAT = 0.1 +Ln:9 DECLARE f2 BINARY_DOUBLE = 1.1 +Ln:10 DECLARE f3 SIMPLE_FLOAT = 3.1 +Ln:11 DECLARE f4 SIMPLE_DOUBLE = 1.3 +Ln:12 DECLARE f5 real = 1.5 +Ln:13 PRINT +0.1 +Ln:14 PRINT +1.1 +Ln:15 PRINT +3.1 +Ln:16 PRINT +1.3 +Ln:17 PRINT +1.5 +Ln:19 DECLARE x1 xml = 'abc' +Ln:20 PRINT +abc \ No newline at end of file diff --git hplsql/src/test/results/local/declare2.out.txt hplsql/src/test/results/local/declare2.out.txt new file mode 100644 index 0000000..e22ca78 --- /dev/null +++ hplsql/src/test/results/local/declare2.out.txt @@ -0,0 +1,7 @@ +Ln:2 DECLARE code char = 'a' +Ln:3 DECLARE status int = 1 +Ln:5 PRINT +a +Ln:6 PRINT +1 +Ln:10 DECLARE code char = 'a' \ No newline at end of file diff --git hplsql/src/test/results/local/float.out.txt hplsql/src/test/results/local/float.out.txt new file mode 100644 index 0000000..ced50fa --- /dev/null +++ hplsql/src/test/results/local/float.out.txt @@ -0,0 +1,6 @@ +Ln:1 DECLARE float_test FLOAT = 0.0 +Ln:2 SET float_test = 2.1 +Ln:3 PRINT +2.1 +Ln:4 PRINT +2.1 \ No newline at end of file diff --git hplsql/src/test/results/local/var_scope.out.txt hplsql/src/test/results/local/var_scope.out.txt new file mode 100644 index 0000000..0f53edf --- /dev/null +++ hplsql/src/test/results/local/var_scope.out.txt @@ -0,0 +1,26 @@ +Ln:1 INCLUDE src/test/queries/local/var_scope_include.sql +INLCUDE CONTENT src/test/queries/local/var_scope_include.sql (non-empty) +Ln:3 DECLARE i int = 3 +Ln:5 CREATE PROCEDURE p1 +Ln:13 CREATE PROCEDURE p2 +EXEC PROCEDURE p2 +Ln:15 DECLARE j int = 5 +Ln:16 PRINT +i: 3 +Ln:17 PRINT +j: 5 +Ln:18 PRINT +k: 7 +EXEC PROCEDURE p1 +Ln:7 PRINT +i: 3 +Ln:8 PRINT +j: +Ln:9 PRINT +k: 7 +Ln:23 PRINT +i: 3 +Ln:24 PRINT +j: +Ln:25 PRINT +k: 7 \ No newline at end of file diff --git hplsql/src/test/results/local/var_scope2.out.txt hplsql/src/test/results/local/var_scope2.out.txt new file mode 100644 index 0000000..9780d7f --- /dev/null +++ hplsql/src/test/results/local/var_scope2.out.txt @@ -0,0 +1,26 @@ +Ln:1 DECLARE i int = 3 +Ln:3 CREATE FUNCTION f1 +Ln:10 CREATE FUNCTION f2 +Ln:16 CREATE PROCEDURE sp1 +Ln:23 CREATE PROCEDURE sp2 +Ln:29 EXEC FUNCTION f1 +Ln:29 SET PARAM p1 = 3 +Ln:5 DECLARE j int = 7 +Ln:6 PRINT +p1: 3 +Ln:7 RETURN +Ln:7 EXEC FUNCTION f2 +Ln:7 SET PARAM p1 = 7 +Ln:12 PRINT +p1: 7 +Ln:13 RETURN +7 +Ln:30 EXEC PROCEDURE sp1 +Ln:30 SET PARAM p1 = 3 +Ln:18 DECLARE j int = 7 +Ln:19 PRINT +p1: 3 +Ln:20 EXEC PROCEDURE sp2 +Ln:20 SET PARAM p1 = 7 +Ln:25 PRINT +p1: 7 \ No newline at end of file diff --git hplsql/src/test/results/offline/insert_mysql.out.txt hplsql/src/test/results/offline/insert_mysql.out.txt new file mode 100644 index 0000000..2f94759 --- /dev/null +++ hplsql/src/test/results/offline/insert_mysql.out.txt @@ -0,0 +1,4 @@ +Ln:1 MAP OBJECT ua AS user_age AT mysqlconn +Ln:2 INSERT VALUES +Ln:2 INSERT INTO user_age (id,age) VALUES +(22, 33) \ No newline at end of file