From a67026f478e03c9c30d3fcf59d061d1978c5013a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A9=E5=B0=91?= Date: Fri, 2 Mar 2012 12:30:44 +0800 Subject: [PATCH] bug fixed for oracle sql parser --- .../oracle/ast/stmt/OracleGotoStatement.java | 35 +++++++++++++++++++ .../oracle/ast/stmt/OracleLabelStatement.java | 35 +++++++++++++++++++ .../oracle/parser/OracleExprParser.java | 14 ++++---- .../dialect/oracle/parser/OracleLexer.java | 5 +++ .../oracle/parser/OracleStatementParser.java | 21 +++++++++++ .../visitor/OracleASTVIsitorAdapter.java | 22 ++++++++++++ .../oracle/visitor/OracleASTVisitor.java | 10 ++++++ .../oracle/visitor/OracleOutputVisitor.java | 26 ++++++++++++++ .../visitor/OracleSchemaStatVisitor.java | 22 ++++++++++++ .../com/alibaba/druid/sql/parser/Lexer.java | 16 ++++++--- .../com/alibaba/druid/sql/parser/Token.java | 2 ++ .../bvt/sql/oracle/OracleBlockTest4.java | 18 +++++----- 12 files changed, 207 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleGotoStatement.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleLabelStatement.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleGotoStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleGotoStatement.java new file mode 100644 index 0000000000..4da2e8569a --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleGotoStatement.java @@ -0,0 +1,35 @@ +package com.alibaba.druid.sql.dialect.oracle.ast.stmt; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; + +public class OracleGotoStatement extends OracleStatementImpl { + + private static final long serialVersionUID = 1L; + + private SQLName label; + + public OracleGotoStatement(){ + } + + public OracleGotoStatement(SQLName label){ + this.label = label; + } + + @Override + public void accept0(OracleASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, label); + } + visitor.endVisit(this); + } + + public SQLName getLabel() { + return label; + } + + public void setLabel(SQLName label) { + this.label = label; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleLabelStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleLabelStatement.java new file mode 100644 index 0000000000..dffdaf54c9 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleLabelStatement.java @@ -0,0 +1,35 @@ +package com.alibaba.druid.sql.dialect.oracle.ast.stmt; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; + +public class OracleLabelStatement extends OracleStatementImpl { + + private static final long serialVersionUID = 1L; + + private SQLName label; + + public OracleLabelStatement(){ + } + + public OracleLabelStatement(SQLName label){ + this.label = label; + } + + @Override + public void accept0(OracleASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, label); + } + visitor.endVisit(this); + } + + public SQLName getLabel() { + return label; + } + + public void setLabel(SQLName label) { + this.label = label; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java index 4d9285b7c5..caed646357 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java @@ -266,6 +266,13 @@ public class OracleExprParser extends SQLExprParser { } public SQLExpr primaryRest(SQLExpr expr) throws ParserException { + if (lexer.token() == Token.DOTDOT) { + lexer.nextToken(); + SQLExpr upBound = expr(); + + return new OracleRangeExpr(expr, upBound); + } + if (lexer.token() == Token.MONKEYS_AT) { lexer.nextToken(); @@ -369,13 +376,6 @@ public class OracleExprParser extends SQLExprParser { } protected SQLExpr dotRest(SQLExpr expr) { - if (lexer.token() == Token.DOT) { - lexer.nextToken(); - SQLExpr upBound = expr(); - - return new OracleRangeExpr(expr, upBound); - } - if (lexer.token() == Token.LITERAL_ALIAS) { String name = '"' + lexer.stringVal() + '"'; lexer.nextToken(); 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 12ee7e87b0..5c39e42cf5 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 @@ -135,6 +135,7 @@ public class OracleLexer extends Lexer { map.put("LOOP", Token.LOOP); map.put("IF", Token.IF); map.put("ELSE", Token.ELSE); + map.put("GOTO", Token.GOTO); DEFAULT_ORACLE_KEYWORDS = new Keywords(map); } @@ -307,6 +308,10 @@ public class OracleLexer extends Lexer { boolean isDouble = false; if (ch == '.') { + if (buf[bp + 1] == '.') { + token = Token.LITERAL_INT; + return; + } sp++; ch = buf[++bp]; isDouble = true; 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 e48f7fc391..81779ac96c 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 @@ -57,9 +57,11 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExceptionStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExplainStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExprStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGotoStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGrantStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleInsertStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLabelStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLockTableStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLockTableStatement.LockMode; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement; @@ -273,6 +275,25 @@ public class OracleStatementParser extends SQLStatementParser { statementList.add(this.parseIf()); continue; } + + if (lexer.token() == Token.GOTO) { + lexer.nextToken(); + SQLName label = this.exprParser.name(); + OracleGotoStatement stmt = new OracleGotoStatement(label); + statementList.add(stmt); + continue; + } + + if (lexer.token() == Token.LTLT) { + lexer.nextToken(); + SQLName label = this.exprParser.name(); + OracleLabelStatement stmt = new OracleLabelStatement(label); + accept(Token.GTGT); + statementList.add(stmt); + continue; + } + + throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal()); } 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 67eefbe02d..f71ab3313a 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 @@ -61,11 +61,13 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExceptionStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExplainStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExprStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGotoStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGrantStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement.Else; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement.ElseIf; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleInsertStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLabelStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLockTableStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeInsertClause; @@ -1149,4 +1151,24 @@ public class OracleASTVIsitorAdapter extends SQLASTVisitorAdapter implements Ora } + @Override + public boolean visit(OracleGotoStatement x) { + return true; + } + + @Override + public void endVisit(OracleGotoStatement x) { + + } + + @Override + public boolean visit(OracleLabelStatement x) { + return true; + } + + @Override + public void endVisit(OracleLabelStatement x) { + + } + } 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 ed82744e2d..e0e6dd4e47 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 @@ -67,11 +67,13 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExceptionStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExplainStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExprStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGotoStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGrantStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement.Else; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement.ElseIf; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleInsertStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLabelStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLockTableStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement; @@ -505,4 +507,12 @@ public interface OracleASTVisitor extends SQLASTVisitor { boolean visit(StorageItem x); void endVisit(StorageItem x); + + boolean visit(OracleGotoStatement x); + + void endVisit(OracleGotoStatement x); + + boolean visit(OracleLabelStatement x); + + void endVisit(OracleLabelStatement x); } 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 8324311d07..12aaa6fedd 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 @@ -101,11 +101,13 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExceptionStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExplainStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExprStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGotoStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGrantStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement.Else; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement.ElseIf; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleInsertStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLabelStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLockTableStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeInsertClause; @@ -2419,4 +2421,28 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS public void endVisit(StorageItem x) { } + + @Override + public boolean visit(OracleGotoStatement x) { + print("GOTO "); + x.getLabel().accept(this); + return false; + } + + @Override + public void endVisit(OracleGotoStatement x) { + + } + @Override + public boolean visit(OracleLabelStatement x) { + print("<<"); + x.getLabel().accept(this); + print(">>"); + return false; + } + + @Override + public void endVisit(OracleLabelStatement x) { + + } } 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 375096e064..7c5d4773e5 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 @@ -79,11 +79,13 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExceptionStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExplainStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExprStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGotoStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleGrantStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement.Else; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleIfStatement.ElseIf; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleInsertStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLabelStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLockTableStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMergeStatement.MergeInsertClause; @@ -1491,4 +1493,24 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle public void endVisit(StorageItem x) { } + + @Override + public boolean visit(OracleGotoStatement x) { + return false; + } + + @Override + public void endVisit(OracleGotoStatement x) { + + } + + @Override + public boolean visit(OracleLabelStatement x) { + return false; + } + + @Override + public void endVisit(OracleLabelStatement x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java index 70e8e36ac1..63fcae2f38 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -270,8 +270,12 @@ public class Lexer { unscan(); scanNumber(); return; + } else if (ch == '.') { + scanChar(); + token = Token.DOTDOT; + } else { + token = Token.DOT; } - token = Token.DOT; return; case '\'': scanString(); @@ -689,6 +693,10 @@ public class Lexer { boolean isDouble = false; if (ch == '.') { + if (buf[bp + 1] == '.') { + token = Token.LITERAL_INT; + return; + } sp++; ch = buf[++bp]; isDouble = true; @@ -869,15 +877,15 @@ public class Lexer { return result; } } - + public int bp() { return this.bp; } - + public char current() { return this.ch; } - + public void reset(int mark, char mark_ch, Token token) { this.bp = mark; this.ch = mark_ch; 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 67f286b2ca..80714f204d 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -170,6 +170,7 @@ public enum Token { EXCEPTION("EXCEPTION"), GRANT("GRANT"), LOOP("LOOP"), + GOTO("GOTO"), // transact-sql TOP("TOP"), @@ -207,6 +208,7 @@ public enum Token { SEMI(";"), COMMA(","), DOT("."), + DOTDOT(".."), EQ("="), GT(">"), LT("<"), diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleBlockTest4.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleBlockTest4.java index 6a55c20c27..6b90941938 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleBlockTest4.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleBlockTest4.java @@ -13,14 +13,16 @@ import com.alibaba.druid.stat.TableStat; public class OracleBlockTest4 extends OracleTest { public void test_0() throws Exception { - String sql = "declare " - + " cursor cspid(vspid dba_hist_snapshot.snap_id%type) is " - + " select end_interval_time , startup_time " // - + " from dba_hist_snapshot " - + // - " where snap_id = vspid and instance_number = :inst_num" - + " and dbid = :dbid; " - + " bsnapt dba_hist_snapshot.end_interval_time%type; bstart dba_hist_snapshot.startup_time%type; esnapt dba_hist_snapshot.end_interval_time%type; estart dba_hist_snapshot.startup_time%type; begin -- Check Begin Snapshot id is valid, get corresponding instance startup time open cspid(:bid); fetch cspid into bsnapt, bstart; if cspid%notfound then raise_application_error(-20200, 'Begin Snapshot Id '||:bid||' does not exist for this database/instance'); end if; close cspid; -- Check End Snapshot id is valid and get corresponding instance startup time open cspid(:eid); fetch cspid into esnapt, estart; if cspid%notfound then raise_application_error(-20200, 'End Snapshot Id '||:eid||' does not exist for this database/instance'); end if; if esnapt <= bsnapt then raise_application_error(-20200, 'End Snapshot Id '||:eid||' must be greater than Begin Snapshot Id '||:bid); end if; close cspid; -- Check startup time is same for begin and end snapshot ids if ( bstart != estart) then raise_application_error(-20200, 'The instance was shutdown between snapshots '||:bid||' and '||:eid); end if; end;"; + String sql = "DECLARE" + // + " done BOOLEAN;" + // + "BEGIN" + // + " FOR i IN 1..50 LOOP" + // + " IF done THEN" + // + " GOTO end_loop;" + // + " END IF;" + // + " <>" + // + " END LOOP;" + // + "END;"; OracleStatementParser parser = new OracleStatementParser(sql); List statementList = parser.parseStatementList();