diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExecuteImmediateStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExecuteImmediateStatement.java index dafb4e0459..3706ac730f 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExecuteImmediateStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExecuteImmediateStatement.java @@ -26,6 +26,8 @@ import java.util.List; public class OracleExecuteImmediateStatement extends OracleStatementImpl { private SQLExpr dynamicSql; + + private boolean bulkCollect; private final List arguments = new ArrayList(); @@ -86,6 +88,14 @@ public class OracleExecuteImmediateStatement extends OracleStatementImpl { } this.dynamicSql = dynamicSql; } + + public boolean isBulkCollect() { + return bulkCollect; + } + + public void setBulkCollect(boolean bulkCollect) { + this.bulkCollect = bulkCollect; + } public void setDynamicSql(String dynamicSql) { this.setDynamicSql(new SQLCharExpr(dynamicSql)); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java index 5650b2d68d..39a91143b3 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java @@ -49,7 +49,8 @@ public class OracleLexer extends Lexer { map.put("GOTO", Token.GOTO); map.put("IF", Token.IF); map.put("ELSIF", Token.ELSIF); - + map.put("RECORD", Token.RECORD); + map.put("LIMIT", Token.LIMIT); map.put("LOOP", Token.LOOP); map.put("MATCHED", Token.MATCHED); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java index 947ab038c3..44e70205d8 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java @@ -788,7 +788,11 @@ public class OracleStatementParser extends SQLStatementParser { SQLExpr dyanmiacSql = this.exprParser.primary(); stmt.setDynamicSql(dyanmiacSql); - + if (lexer.identifierEquals("BULK")) { + lexer.nextToken(); + acceptIdentifier("COLLECT"); + stmt.setBulkCollect(true); + } if (lexer.token() == Token.INTO) { lexer.nextToken(); @@ -1979,6 +1983,18 @@ public class OracleStatementParser extends SQLStatementParser { } else { throw new ParserException("TODO : " + lexer.info()); } + } else if (lexer.token() == Token.RECORD) { + lexer.nextToken(); + String typeName = "RECORD"; + SQLRecordDataType sqlRecordDataType = new SQLRecordDataType(); + sqlRecordDataType.setDbType(dbType); + sqlRecordDataType.setName(typeName); + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + this.parseColumnsList(sqlRecordDataType.getColumns(), sqlRecordDataType); + accept(Token.RPAREN); + } + dataType = sqlRecordDataType; } else { throw new ParserException("TODO : " + lexer.info()); } @@ -2104,7 +2120,19 @@ public class OracleStatementParser extends SQLStatementParser { break; } } - + + private void parseColumnsList(List columns, SQLObject parent) { + for ( ; ; ) { + SQLColumnDefinition columnDefinition = this.exprParser.parseColumn(); + columns.add(columnDefinition); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + } + public OracleSelectParser createSQLSelectParser() { return new OracleSelectParser(this.exprParser, selectListCache); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java index 9b8669bce4..a87756caad 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java @@ -2612,7 +2612,11 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS public boolean visit(OracleExecuteImmediateStatement x) { print0(ucase ? "EXECUTE IMMEDIATE " : "execute immediate "); x.getDynamicSql().accept(this); - + + if (x.isBulkCollect()) { + print0(ucase ? " BULK COLLECT " : " bulk collect "); + } + List into = x.getInto(); if (into.size() > 0) { print0(ucase ? " INTO " : " into "); diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 4b4b06db45..28b98057a4 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -531,6 +531,11 @@ public class SQLExprParser extends SQLParser { break; } } + } else if (DbType.oracle == dbType) { + lexer.nextTokenValue(); + if (lexer.token == Token.BARBAR) { + sqlExpr = additiveRest(sqlExpr); + } } else { lexer.nextToken(); } @@ -1307,7 +1312,7 @@ public class SQLExprParser extends SQLParser { expr = dotRest(expr); return primaryRest(expr); } else if (lexer.identifierEquals(FnvHash.Constants.SETS) // - && expr.getClass() == SQLIdentifierExpr.class // + && expr.getClass() == SQLIdentifierExpr.class // && "GROUPING".equalsIgnoreCase(((SQLIdentifierExpr) expr).getName())) { SQLGroupingSetExpr groupingSets = new SQLGroupingSetExpr(); lexer.nextToken(); diff --git a/src/main/java/com/alibaba/druid/sql/parser/Token.java b/src/main/java/com/alibaba/druid/sql/parser/Token.java index a03b208b0b..e728c7ba14 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -16,56 +16,56 @@ package com.alibaba.druid.sql.parser; /** - * - * SQL Token + * + * SQL Token * @author wenshao [szujobs@hotmail.com] */ public enum Token { - SELECT("SELECT"), - DELETE("DELETE"), - INSERT("INSERT"), - UPDATE("UPDATE"), + SELECT("SELECT"), + DELETE("DELETE"), + INSERT("INSERT"), + UPDATE("UPDATE"), - FROM("FROM"), - HAVING("HAVING"), - WHERE("WHERE"), - ORDER("ORDER"), + FROM("FROM"), + HAVING("HAVING"), + WHERE("WHERE"), + ORDER("ORDER"), BY("BY"), - GROUP("GROUP"), - INTO("INTO"), - AS("AS"), + GROUP("GROUP"), + INTO("INTO"), + AS("AS"), CREATE("CREATE"), - ALTER("ALTER"), - DROP("DROP"), - SET("SET"), + ALTER("ALTER"), + DROP("DROP"), + SET("SET"), - NULL("NULL"), - NOT("NOT"), + NULL("NULL"), + NOT("NOT"), DISTINCT("DISTINCT"), - TABLE("TABLE"), - TABLESPACE("TABLESPACE"), - VIEW("VIEW"), - SEQUENCE("SEQUENCE"), - TRIGGER("TRIGGER"), - USER("USER"), - INDEX("INDEX"), + TABLE("TABLE"), + TABLESPACE("TABLESPACE"), + VIEW("VIEW"), + SEQUENCE("SEQUENCE"), + TRIGGER("TRIGGER"), + USER("USER"), + INDEX("INDEX"), SESSION("SESSION"), PROCEDURE("PROCEDURE"), FUNCTION("FUNCTION"), - PRIMARY("PRIMARY"), - KEY("KEY"), - DEFAULT("DEFAULT"), - CONSTRAINT("CONSTRAINT"), - CHECK("CHECK"), - UNIQUE("UNIQUE"), - FOREIGN("FOREIGN"), - REFERENCES("REFERENCES"), + PRIMARY("PRIMARY"), + KEY("KEY"), + DEFAULT("DEFAULT"), + CONSTRAINT("CONSTRAINT"), + CHECK("CHECK"), + UNIQUE("UNIQUE"), + FOREIGN("FOREIGN"), + REFERENCES("REFERENCES"), - EXPLAIN("EXPLAIN"), - FOR("FOR"), + EXPLAIN("EXPLAIN"), + FOR("FOR"), IF("IF"), @@ -73,55 +73,55 @@ public enum Token { GLOBAL("GLOBAL"), ALL("ALL"), UNION("UNION"), - EXCEPT("EXCEPT"), - INTERSECT("INTERSECT"), + EXCEPT("EXCEPT"), + INTERSECT("INTERSECT"), MINUS("MINUS"), - INNER("INNER"), - LEFT("LEFT"), - RIGHT("RIGHT"), - FULL("FULL"), - OUTER("OUTER"), + INNER("INNER"), + LEFT("LEFT"), + RIGHT("RIGHT"), + FULL("FULL"), + OUTER("OUTER"), JOIN("JOIN"), STRAIGHT_JOIN("STRAIGHT_JOIN"), ON("ON"), - SCHEMA("SCHEMA"), + SCHEMA("SCHEMA"), CAST("CAST"), COLUMN("COLUMN"), USE("USE"), DATABASE("DATABASE"), TO("TO"), - AND("AND"), - OR("OR"), - XOR("XOR"), - CASE("CASE"), - WHEN("WHEN"), - THEN("THEN"), + AND("AND"), + OR("OR"), + XOR("XOR"), + CASE("CASE"), + WHEN("WHEN"), + THEN("THEN"), ELSE("ELSE"), ELSIF("ELSIF"), - END("END"), - EXISTS("EXISTS"), + END("END"), + EXISTS("EXISTS"), IN("IN"), - NEW("NEW"), - ASC("ASC"), - DESC("DESC"), - IS("IS"), - LIKE("LIKE"), - ESCAPE("ESCAPE"), - BETWEEN("BETWEEN"), - VALUES("VALUES"), + NEW("NEW"), + ASC("ASC"), + DESC("DESC"), + IS("IS"), + LIKE("LIKE"), + ESCAPE("ESCAPE"), + BETWEEN("BETWEEN"), + VALUES("VALUES"), INTERVAL("INTERVAL"), - LOCK("LOCK"), - SOME("SOME"), + LOCK("LOCK"), + SOME("SOME"), ANY("ANY"), TRUNCATE("TRUNCATE"), RETURN("RETURN"), // mysql - TRUE("TRUE"), + TRUE("TRUE"), FALSE("FALSE"), LIMIT("LIMIT"), KILL("KILL"), @@ -211,6 +211,7 @@ public enum Token { COMMIT("COMMIT"), SAVEPOINT("SAVEPOINT"), CROSS("CROSS"), + RECORD("RECORD"), PCTFREE("PCTFREE"), INITRANS("INITRANS"), @@ -253,7 +254,7 @@ public enum Token { // hive - EOF, + EOF, ERROR, IDENTIFIER, HINT, @@ -298,19 +299,19 @@ public enum Token { UPSERT("UPSERT"), // Phoenix - LPAREN("("), - RPAREN(")"), - LBRACE("{"), - RBRACE("}"), - LBRACKET("["), - RBRACKET("]"), - SEMI(";"), - COMMA(","), - DOT("."), - DOTDOT(".."), - DOTDOTDOT("..,"), - EQ("="), - GT(">"), + LPAREN("("), + RPAREN(")"), + LBRACE("{"), + RBRACE("}"), + LBRACKET("["), + RBRACKET("]"), + SEMI(";"), + COMMA(","), + DOT("."), + DOTDOT(".."), + DOTDOTDOT("..,"), + EQ("="), + GT(">"), LT("<"), LT_SUB_GT("<->"), BANG("!"), @@ -324,34 +325,34 @@ public enum Token { QUESQUES("??"), QUESBAR("?|"), QUESAMP("?&"), - COLON(":"), - COLONCOLON("::"), - COLONEQ(":="), + COLON(":"), + COLONCOLON("::"), + COLONEQ(":="), EQEQ("=="), EQGT("=>"), - LTEQ("<="), - LTEQGT("<=>"), - LTGT("<>"), - GTEQ(">="), - BANGEQ("!="), - BANGGT("!>"), + LTEQ("<="), + LTEQGT("<=>"), + LTGT("<>"), + GTEQ(">="), + BANGEQ("!="), + BANGGT("!>"), BANGLT("!<"), - AMPAMP("&&"), - BARBAR("||"), - BARBARSLASH("||/"), - BARSLASH("|/"), - PLUS("+"), - SUB("-"), - SUBGT("->"), - SUBGTGT("->>"), - STAR("*"), - SLASH("/"), - AMP("&"), - BAR("|"), + AMPAMP("&&"), + BARBAR("||"), + BARBARSLASH("||/"), + BARSLASH("|/"), + PLUS("+"), + SUB("-"), + SUBGT("->"), + SUBGTGT("->>"), + STAR("*"), + SLASH("/"), + AMP("&"), + BAR("|"), CARET("^"), CARETEQ("^="), - PERCENT("%"), - LTLT("<<"), + PERCENT("%"), + LTLT("<<"), GTGT(">>"), MONKEYS_AT("@"), MONKEYS_AT_AT("@@"),