From a5e4bdd645f871a3ebba0c5da9f80755e73298b5 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 13 May 2017 14:38:32 +0800 Subject: [PATCH] improved oracle pl/sql parser. --- .../ast/stmt/OracleConntinueStatement.java | 58 +++++++++ .../ast/stmt/OracleExceptionStatement.java | 15 ++- .../oracle/ast/stmt/OracleExitStatement.java | 3 + .../oracle/ast/stmt/OracleForStatement.java | 17 ++- .../dialect/oracle/parser/OracleLexer.java | 1 + .../oracle/parser/OracleStatementParser.java | 43 ++++++- .../oracle/visitor/OracleASTVisitor.java | 4 + .../visitor/OracleASTVisitorAdapter.java | 10 ++ .../oracle/visitor/OracleOutputVisitor.java | 40 +++++- .../visitor/OracleSchemaStatVisitor.java | 10 ++ .../sql/visitor/SQLASTOutputVisitor.java | 29 ++++- .../sql/oracle/block/OracleBlockTest5.java | 11 +- .../bvt/sql/oracle/pl/Oracle_pl_case_1.java | 6 +- .../bvt/sql/oracle/pl/Oracle_pl_for_3.java | 106 ++++++++++++++++ .../bvt/sql/oracle/pl/Oracle_pl_for_4.java | 120 ++++++++++++++++++ .../sql/oracle/pl/Oracle_pl_open_for_0.java | 8 +- 16 files changed, 440 insertions(+), 41 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleConntinueStatement.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_for_3.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_for_4.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleConntinueStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleConntinueStatement.java new file mode 100644 index 0000000000..f37a92b2a0 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleConntinueStatement.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed 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 com.alibaba.druid.sql.dialect.oracle.ast.stmt; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; + +public class OracleConntinueStatement extends OracleStatementImpl { + + private SQLExpr when; + private SQLName label; + + public SQLExpr getWhen() { + return when; + } + + public void setWhen(SQLExpr when) { + if (when != null) { + when.setParent(this); + } + this.when = when; + } + + public SQLName getLabel() { + return label; + } + + public void setLabel(SQLName label) { + if (label != null) { + label.setParent(this); + } + this.label = label; + } + + @Override + public void accept0(OracleASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, label); + acceptChild(visitor, when); + } + visitor.endVisit(this); + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExceptionStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExceptionStatement.java index 031ed164e0..c70eac70eb 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExceptionStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExceptionStatement.java @@ -42,7 +42,7 @@ public class OracleExceptionStatement extends OracleStatementImpl implements Ora public static class Item extends OracleSQLObjectImpl { private SQLExpr when; - private List statements = new ArrayList(); + private SQLStatement statement; public SQLExpr getWhen() { return when; @@ -52,19 +52,22 @@ public class OracleExceptionStatement extends OracleStatementImpl implements Ora this.when = when; } - public List getStatements() { - return statements; + public SQLStatement getStatement() { + return statement; } - public void setStatements(List statements) { - this.statements = statements; + public void setStatement(SQLStatement statement) { + if (statement != null) { + statement.setParent(this); + } + this.statement = statement; } @Override public void accept0(OracleASTVisitor visitor) { if (visitor.visit(this)) { acceptChild(visitor, when); - acceptChild(visitor, statements); + acceptChild(visitor, statement); } visitor.endVisit(this); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExitStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExitStatement.java index 7de5ebc1bb..683b1cc46d 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExitStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleExitStatement.java @@ -27,6 +27,9 @@ public class OracleExitStatement extends OracleStatementImpl { } public void setWhen(SQLExpr when) { + if (when != null) { + when.setParent(this); + } this.when = when; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleForStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleForStatement.java index 6858060fb4..dede6337fc 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleForStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleForStatement.java @@ -33,6 +33,8 @@ public class OracleForStatement extends OracleStatementImpl { private boolean all; + private SQLName endLabel; + @Override public void accept0(OracleASTVisitor visitor) { if (visitor.visit(this)) { @@ -63,10 +65,6 @@ public class OracleForStatement extends OracleStatementImpl { return statements; } - public void setStatements(List statements) { - this.statements = statements; - } - public boolean isAll() { return all; } @@ -74,4 +72,15 @@ public class OracleForStatement extends OracleStatementImpl { public void setAll(boolean all) { this.all = all; } + + public SQLName getEndLabel() { + return endLabel; + } + + public void setEndLabel(SQLName endLabel) { + if (endLabel != null) { + endLabel.setParent(this); + } + this.endLabel = endLabel; + } } 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 f426034917..14f3879ed0 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 @@ -40,6 +40,7 @@ public class OracleLexer extends Lexer { map.put("COMMENT", Token.COMMENT); map.put("COMMIT", Token.COMMIT); map.put("CONNECT", Token.CONNECT); + map.put("CONTINUE", Token.CONTINUE); map.put("CROSS", Token.CROSS); map.put("CURSOR", Token.CURSOR); 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 de6e6e343f..d3ffe551e6 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 @@ -191,6 +191,22 @@ public class OracleStatementParser extends SQLStatementParser { continue; } + if (lexer.token() == Token.CONTINUE) { + lexer.nextToken(); + OracleConntinueStatement stmt = new OracleConntinueStatement(); + + if (lexer.token() == Token.IDENTIFIER) { + SQLName label = this.exprParser.name(); + stmt.setLabel(label); + } + if (lexer.token() == Token.WHEN) { + lexer.nextToken(); + stmt.setWhen(this.exprParser.expr()); + } + statementList.add(stmt); + continue; + } + if (lexer.token() == Token.FETCH || identifierEquals("FETCH")) { SQLStatement stmt = parseFetch(); statementList.add(stmt); @@ -262,7 +278,21 @@ public class OracleStatementParser extends SQLStatementParser { continue; } if (lexer.token() == Token.FOR) { - statementList.add(this.parseFor()); + OracleForStatement forStatement = this.parseFor(); + if (lexer.token() == Token.IDENTIFIER) { + String strVal = lexer.stringVal(); + int stmtListSize = statementList.size(); + if (stmtListSize > 0) { + SQLStatement lastStmt = statementList.get(stmtListSize - 1); + if (lastStmt instanceof OracleLabelStatement) { + if (((OracleLabelStatement) lastStmt).getLabel().getSimpleName().equalsIgnoreCase(strVal)) { + SQLName endLabbel = this.exprParser.name(); + forStatement.setEndLabel(endLabbel); + } + } + } + } + statementList.add(forStatement); continue; } if (lexer.token() == Token.LOOP) { @@ -458,7 +488,9 @@ public class OracleStatementParser extends SQLStatementParser { public SQLStatement parseRaise() { lexer.nextToken(); OracleRaiseStatement stmt = new OracleRaiseStatement(); - stmt.setException(this.exprParser.expr()); + if (lexer.token() != Token.SEMI) { + stmt.setException(this.exprParser.expr()); + } return stmt; } @@ -574,7 +606,7 @@ public class OracleStatementParser extends SQLStatementParser { } else { accept(Token.LOOP); - this.parseStatementList(stmt.getStatements()); + this.parseStatementList(stmt.getStatements(), -1, stmt); accept(Token.END); accept(Token.LOOP); } @@ -586,7 +618,7 @@ public class OracleStatementParser extends SQLStatementParser { SQLLoopStatement stmt = new SQLLoopStatement(); - this.parseStatementList(stmt.getStatements()); + this.parseStatementList(stmt.getStatements(), -1, stmt); accept(Token.END); accept(Token.LOOP); return stmt; @@ -1308,7 +1340,8 @@ public class OracleStatementParser extends SQLStatementParser { OracleExceptionStatement.Item item = new OracleExceptionStatement.Item(); item.setWhen(this.exprParser.expr()); accept(Token.THEN); - parseStatementList(item.getStatements()); + SQLStatement thenStmt = this.parseStatement(); + item.setStatement(thenStmt); stmt.addItem(item); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java index 90a7a32d6a..baf6d0b414 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java @@ -393,6 +393,10 @@ public interface OracleASTVisitor extends SQLASTVisitor { void endVisit(OracleExitStatement x); + boolean visit(OracleConntinueStatement x); + + void endVisit(OracleConntinueStatement x); + boolean visit(OracleRaiseStatement x); void endVisit(OracleRaiseStatement x); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitorAdapter.java index 48aa766493..27aff053dc 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitorAdapter.java @@ -948,6 +948,16 @@ public class OracleASTVisitorAdapter extends SQLASTVisitorAdapter implements Ora } + @Override + public boolean visit(OracleConntinueStatement x) { + return true; + } + + @Override + public void endVisit(OracleConntinueStatement x) { + + } + @Override public boolean visit(OracleRaiseStatement x) { return true; 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 8f069a0f53..667d1da8de 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 @@ -109,7 +109,9 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS return; } - if (x instanceof OraclePLSQLCommitStatement) { + if (x instanceof OraclePLSQLCommitStatement + || x instanceof OracleLabelStatement + || x instanceof OracleExceptionStatement.Item) { return; } @@ -1495,14 +1497,10 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS public boolean visit(com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExceptionStatement.Item x) { print0(ucase ? "WHEN " : "when "); x.getWhen().accept(this); + print0(ucase ? " THEN " : " then "); incrementIndent(); + x.getStatement().accept(this); - for (int i = 0, size = x.getStatements().size(); i < size; ++i) { - println(); - SQLStatement stmt = x.getStatements().get(i); - stmt.setParent(x); - stmt.accept(this); - } decrementIndent(); return false; } @@ -1898,6 +1896,11 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS if (!all) { println(); print0(ucase ? "END LOOP" : "end loop"); + SQLName endLabel = x.getEndLabel(); + if (endLabel != null) { + print(' '); + endLabel.accept(this); + } } return false; } @@ -2496,6 +2499,29 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } + + @Override + public boolean visit(OracleConntinueStatement x) { + print0(ucase ? "CONTINUE" : "continue"); + + SQLName label = x.getLabel(); + if (label != null) { + print(' '); + label.accept(this); + } + + if (x.getWhen() != null) { + print0(ucase ? " WHEN " : " when "); + x.getWhen().accept(this); + } + return false; + } + + @Override + public void endVisit(OracleConntinueStatement x) { + + } + @Override public boolean visit(OracleRaiseStatement x) { print0(ucase ? "RAISE" : "raise"); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java index f147596eee..13633630fa 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java @@ -1281,6 +1281,16 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle } + @Override + public boolean visit(OracleConntinueStatement x) { + return false; + } + + @Override + public void endVisit(OracleConntinueStatement x) { + + } + @Override public boolean visit(OracleRaiseStatement x) { return false; diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index 1737f1f89e..62e2a6cb5e 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -322,6 +322,8 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet x = ParameterizedOutputVisitorUtils.merge(this, x); } + SQLBinaryOperator operator = x.getOperator(); + if (parameters != null && parameters.size() > 0 && x.getOperator() == SQLBinaryOperator.Equality @@ -343,8 +345,8 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet SQLObject parent = x.getParent(); boolean isRoot = parent instanceof SQLSelectQueryBlock; - boolean relational = x.getOperator() == SQLBinaryOperator.BooleanAnd - || x.getOperator() == SQLBinaryOperator.BooleanOr; + boolean relational = operator == SQLBinaryOperator.BooleanAnd + || operator == SQLBinaryOperator.BooleanOr; if (isRoot && relational) { incrementIndent(); @@ -352,8 +354,9 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet List groupList = new ArrayList(); SQLExpr left = x.getLeft(); + SQLExpr right = x.getRight(); for (;;) { - if (left instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr) left).getOperator() == x.getOperator()) { + if (left instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr) left).getOperator() == operator) { SQLBinaryOpExpr binaryLeft = (SQLBinaryOpExpr) left; groupList.add(binaryLeft.getRight()); left = binaryLeft.getLeft(); @@ -376,7 +379,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet printlnComments(item.getBeforeCommentsDirect()); } - visitBinaryLeft(item, x.getOperator()); + visitBinaryLeft(item, operator); if (isPrettyFormat() && item.hasAfterComment()) { print(' '); @@ -388,13 +391,25 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet printComment(item.getParent().getAfterCommentsDirect(), "\n"); } + boolean printOpSpace = true; if (relational) { println(); } else { - print0(" "); + if (operator == SQLBinaryOperator.Modulus + && JdbcConstants.ORACLE.equals(dbType) + && left instanceof SQLIdentifierExpr + && right instanceof SQLIdentifierExpr + && ((SQLIdentifierExpr) right).getName().equalsIgnoreCase("NOTFOUND")) { + printOpSpace = false; + } + if (printOpSpace) { + print(' '); + } + } + printOperator(operator); + if (printOpSpace) { + print(' '); } - printOperator(x.getOperator()); - print0(" "); } visitorBinaryRight(x); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/block/OracleBlockTest5.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/block/OracleBlockTest5.java index f81b5a9989..387d2c9c10 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/block/OracleBlockTest5.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/block/OracleBlockTest5.java @@ -17,6 +17,8 @@ package com.alibaba.druid.bvt.sql.oracle.block; import java.util.List; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.util.JdbcConstants; import org.junit.Assert; import com.alibaba.druid.sql.OracleTest; @@ -46,13 +48,14 @@ public class OracleBlockTest5 extends OracleTest { OracleStatementParser parser = new OracleStatementParser(sql); List statementList = parser.parseStatementList(); - SQLStatement statemen = statementList.get(0); - print(statementList); + SQLStatement stmt = statementList.get(0); + String output = SQLUtils.toSQLString(stmt, JdbcConstants.ORACLE); + System.out.println(output); - Assert.assertEquals(1, statementList.size()); + assertEquals(1, statementList.size()); OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); - statemen.accept(visitor); + stmt.accept(visitor); System.out.println("Tables : " + visitor.getTables()); System.out.println("fields : " + visitor.getColumns()); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_case_1.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_case_1.java index 2f48bc599c..803d226b10 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_case_1.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_case_1.java @@ -85,8 +85,7 @@ public class Oracle_pl_case_1 extends OracleTest { "\t\tELSE ;\n" + "\tEND CASE;\n" + "\tEXCEPTION\n" + - "\t\tWHEN CASE_NOT_FOUND\n" + - "\t\t\tDBMS_OUTPUT.PUT_LINE('No such grade');\n" + + "\t\tWHEN CASE_NOT_FOUND THEN DBMS_OUTPUT.PUT_LINE('No such grade');\n" + "END", // output); } @@ -105,8 +104,7 @@ public class Oracle_pl_case_1 extends OracleTest { "\t\telse ;\n" + "\tend case;\n" + "\texception\n" + - "\t\twhen CASE_NOT_FOUND\n" + - "\t\t\tDBMS_OUTPUT.PUT_LINE('No such grade');\n" + + "\t\twhen CASE_NOT_FOUND then DBMS_OUTPUT.PUT_LINE('No such grade');\n" + "end", // output); } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_for_3.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_for_3.java new file mode 100644 index 0000000000..5a1360a196 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_for_3.java @@ -0,0 +1,106 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed 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 com.alibaba.druid.bvt.sql.oracle.pl; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class Oracle_pl_for_3 extends OracleTest { + + public void test_0() throws Exception { + String sql = "DECLARE\n" + + " v_employees employees%ROWTYPE;\n" + + " CURSOR c1 is SELECT * FROM employees;\n" + + "BEGIN\n" + + " OPEN c1;\n" + + " -- Fetch entire row into v_employees record:\n" + + " FOR i IN 1..10 LOOP\n" + + " FETCH c1 INTO v_employees;\n" + + " EXIT WHEN c1%NOTFOUND;\n" + + " -- Process data here\n" + + " END LOOP;\n" + + " CLOSE c1;\n" + + "END;"; // + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.ORACLE); + assertEquals(1, statementList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.ORACLE); + for (SQLStatement statement : statementList) { + statement.accept(visitor); + } + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); +// System.out.println("relationships : " + visitor.getRelationships()); +// System.out.println("orderBy : " + visitor.getOrderByColumns()); + + assertEquals(1, visitor.getTables().size()); + +// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("employees"))); +// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("emp_name"))); + +// Assert.assertEquals(7, visitor.getColumns().size()); +// Assert.assertEquals(3, visitor.getConditions().size()); +// Assert.assertEquals(1, visitor.getRelationships().size()); + + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("employees", "salary"))); + + { + String output = SQLUtils.toSQLString(statementList, JdbcConstants.ORACLE); + System.out.println(output); + assertEquals("DECLARE\n" + + "\tv_employees employees%ROWTYPE;\n" + + "\tCURSOR c1 IS\n" + + "\t\tSELECT *\n" + + "\t\tFROM employees;\n" + + "BEGIN\n" + + "\tOPEN c1;\n" + + "\tFOR i IN 1..10\n" + + "\tLOOP\n" + + "\t\tFETCH c1 INTO v_employees;\n" + + "\t\tEXIT WHEN c1%NOTFOUND;\n" + + "\tEND LOOP;\n" + + "\tCLOSE c1;\n" + + "END", // + output); + } + { + String output = SQLUtils.toSQLString(statementList, JdbcConstants.ORACLE, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION); + assertEquals("declare\n" + + "\tv_employees employees%ROWTYPE;\n" + + "\tcursor c1 is\n" + + "\t\tselect *\n" + + "\t\tfrom employees;\n" + + "begin\n" + + "\topen c1;\n" + + "\tfor i in 1..10\n" + + "\tloop\n" + + "\t\tfetch c1 into v_employees;\n" + + "\t\texit when c1%NOTFOUND;\n" + + "\tend loop;\n" + + "\tclose c1;\n" + + "end", // + output); + } + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_for_4.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_for_4.java new file mode 100644 index 0000000000..15ed2d69db --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_for_4.java @@ -0,0 +1,120 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed 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 com.alibaba.druid.bvt.sql.oracle.pl; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class Oracle_pl_for_4 extends OracleTest { + + public void test_0() throws Exception { + String sql = "DECLARE\n" + + " v_employees employees%ROWTYPE;\n" + + " CURSOR c1 is SELECT * FROM employees;\n" + + "BEGIN\n" + + " OPEN c1;\n" + + " \n" + + " -- Fetch entire row into v_employees record:\n" + + " <>\n" + + " FOR i IN 1..10 LOOP\n" + + " -- Process data here\n" + + " FOR j IN 1..10 LOOP\n" + + " FETCH c1 INTO v_employees;\n" + + " CONTINUE outer_loop WHEN c1%NOTFOUND;\n" + + " -- Process data here\n" + + " END LOOP;\n" + + " END LOOP outer_loop;\n" + + " \n" + + " CLOSE c1;\n" + + "END;"; // + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.ORACLE); + assertEquals(1, statementList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.ORACLE); + for (SQLStatement statement : statementList) { + statement.accept(visitor); + } + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); +// System.out.println("relationships : " + visitor.getRelationships()); +// System.out.println("orderBy : " + visitor.getOrderByColumns()); + + assertEquals(1, visitor.getTables().size()); + +// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("employees"))); +// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("emp_name"))); + +// Assert.assertEquals(7, visitor.getColumns().size()); +// Assert.assertEquals(3, visitor.getConditions().size()); +// Assert.assertEquals(1, visitor.getRelationships().size()); + + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("employees", "salary"))); + + { + String output = SQLUtils.toSQLString(statementList, JdbcConstants.ORACLE); + System.out.println(output); + assertEquals("DECLARE\n" + + "\tv_employees employees%ROWTYPE;\n" + + "\tCURSOR c1 IS\n" + + "\t\tSELECT *\n" + + "\t\tFROM employees;\n" + + "BEGIN\n" + + "\tOPEN c1;\n" + + "\t<>\n" + + "\tFOR i IN 1..10\n" + + "\tLOOP\n" + + "\t\tFOR j IN 1..10\n" + + "\t\tLOOP\n" + + "\t\t\tFETCH c1 INTO v_employees;\n" + + "\t\t\tCONTINUE outer_loop WHEN c1%NOTFOUND;\n" + + "\t\tEND LOOP;\n" + + "\tEND LOOP outer_loop;\n" + + "\tCLOSE c1;\n" + + "END", // + output); + } + { + String output = SQLUtils.toSQLString(statementList, JdbcConstants.ORACLE, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION); + assertEquals("declare\n" + + "\tv_employees employees%ROWTYPE;\n" + + "\tcursor c1 is\n" + + "\t\tselect *\n" + + "\t\tfrom employees;\n" + + "begin\n" + + "\topen c1;\n" + + "\t<>\n" + + "\tfor i in 1..10\n" + + "\tloop\n" + + "\t\tfor j in 1..10\n" + + "\t\tloop\n" + + "\t\t\tfetch c1 into v_employees;\n" + + "\t\t\tcontinue outer_loop when c1%NOTFOUND;\n" + + "\t\tend loop;\n" + + "\tend loop outer_loop;\n" + + "\tclose c1;\n" + + "end", // + output); + } + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_open_for_0.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_open_for_0.java index 21cd820e93..5f794e9280 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_open_for_0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_open_for_0.java @@ -109,7 +109,7 @@ public class Oracle_pl_open_for_0 extends OracleTest { "\t\tWHERE job_id LIKE 'AD_%';\n" + "\tLOOP\n" + "\t\tFETCH cv INTO sal, sal_multiple;\n" + - "\t\tEXIT WHEN cv % NOTFOUND;\n" + + "\t\tEXIT WHEN cv%NOTFOUND;\n" + "\t\tDBMS_OUTPUT.PUT_LINE('sal = ' || sal);\n" + "\t\tDBMS_OUTPUT.PUT_LINE('sal_multiple = ' || sal_multiple);\n" + "\tEND LOOP;\n" + @@ -121,7 +121,7 @@ public class Oracle_pl_open_for_0 extends OracleTest { "\t\tWHERE job_id LIKE 'AD_%';\n" + "\tLOOP\n" + "\t\tFETCH cv INTO sal, sal_multiple;\n" + - "\t\tEXIT WHEN cv % NOTFOUND;\n" + + "\t\tEXIT WHEN cv%NOTFOUND;\n" + "\t\tDBMS_OUTPUT.PUT_LINE('sal = ' || sal);\n" + "\t\tDBMS_OUTPUT.PUT_LINE('sal_multiple = ' || sal_multiple);\n" + "\tEND LOOP;\n" + @@ -144,7 +144,7 @@ public class Oracle_pl_open_for_0 extends OracleTest { "\t\twhere job_id like 'AD_%';\n" + "\tloop\n" + "\t\tfetch cv into sal, sal_multiple;\n" + - "\t\texit when cv % NOTFOUND;\n" + + "\t\texit when cv%NOTFOUND;\n" + "\t\tDBMS_OUTPUT.PUT_LINE('sal = ' || sal);\n" + "\t\tDBMS_OUTPUT.PUT_LINE('sal_multiple = ' || sal_multiple);\n" + "\tend loop;\n" + @@ -156,7 +156,7 @@ public class Oracle_pl_open_for_0 extends OracleTest { "\t\twhere job_id like 'AD_%';\n" + "\tloop\n" + "\t\tfetch cv into sal, sal_multiple;\n" + - "\t\texit when cv % NOTFOUND;\n" + + "\t\texit when cv%NOTFOUND;\n" + "\t\tDBMS_OUTPUT.PUT_LINE('sal = ' || sal);\n" + "\t\tDBMS_OUTPUT.PUT_LINE('sal_multiple = ' || sal_multiple);\n" + "\tend loop;\n" +