From d9776a15309250a7b2d286ad47af53222f6fa014 Mon Sep 17 00:00:00 2001 From: wenshao Date: Thu, 19 May 2011 06:52:32 +0000 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=BC=BAParser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://code.alibabatech.com/svn/druid/trunk@132 b9813039-fb51-4c41-a8b9-e21c2acb5095 --- .../ast/visitor/OracleOutputVisitor.java | 7 +- .../oracle/parser/OracleExprParser.java | 20 +++++ .../oracle/parser/OracleInsertParser.java | 4 +- .../oracle/parser/OracleSelectParser.java | 5 ++ .../oracle/parser/OracleStatementParser.java | 5 ++ .../alibaba/druid/sql/parser/CharTypes.java | 1 + .../druid/sql/parser/SQLStatementParser.java | 4 +- .../com/alibaba/druid/sql/parser/Token.java | 3 +- .../bvt/OracleSQLParserResourceTest.java | 76 +++++++++++++++++++ .../sql/oracle/bvt/OracleSQLParserTest.java | 56 ++++++-------- .../druid/sql/parser/SQLLexerTest2.java | 2 + src/test/resources/bvt/parser/oracle-0.txt | 14 ++++ src/test/resources/bvt/parser/oracle-1.txt | 59 ++++++++++++++ 13 files changed, 215 insertions(+), 41 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserResourceTest.java create mode 100644 src/test/resources/bvt/parser/oracle-0.txt create mode 100644 src/test/resources/bvt/parser/oracle-1.txt diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleOutputVisitor.java index 6f154ada3b..b0c6d318a4 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleOutputVisitor.java @@ -560,6 +560,10 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } public boolean visit(OracleSelectHierachicalQueryClause x) { + print("START WITH "); + x.getStartWith().accept(this); + + println(); print("CONNECT BY "); if (x.isPrior()) { @@ -571,8 +575,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } x.getConnectBy().accept(this); - print(" START WITH "); - x.getStartWith().accept(this); + return false; } 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 1553362d65..3f1b88a156 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 @@ -15,8 +15,10 @@ */ package com.alibaba.druid.sql.dialect.oracle.parser; +import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLOrderingSpecification; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalytic; @@ -55,6 +57,24 @@ public class OracleExprParser extends SQLExprParser { return false; } + public SQLExpr primary() throws ParserException { + final Token tok = lexer.token(); + + switch (tok) { + case COLON: + lexer.nextToken(); + if (lexer.token() == Token.LITERAL_INT) { + String name = ":" + lexer.numberString(); + lexer.nextToken(); + return new SQLVariantRefExpr(name); + } else{ + throw new ParserException("syntax error : " + lexer.token()); + } + default: + return super.primary(); + } + } + @Override public OracleOrderBy parseOrderBy() { if (lexer.token() == (Token.ORDER)) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleInsertParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleInsertParser.java index 9284236ef1..c3c7db3125 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleInsertParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleInsertParser.java @@ -15,7 +15,7 @@ */ package com.alibaba.druid.sql.dialect.oracle.parser; -import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleInsertStatement; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; @@ -32,7 +32,7 @@ public class OracleInsertParser extends SQLStatementParser { super(lexer); } - public SQLInsertStatement parseInsert() throws ParserException { + public SQLStatement parseInsert() throws ParserException { throw new ParserException("TODO"); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java index 72983c111e..399a8ab6e5 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java @@ -36,6 +36,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableSource; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectUnPivot; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; +import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.Token; @@ -48,6 +49,10 @@ public class OracleSelectParser extends SQLSelectParser { public OracleSelectParser(Lexer lexer){ super(lexer); } + + protected SQLExprParser createExprParser() { + return new OracleExprParser(lexer); + } public OracleSelect select() { OracleSelect select = new OracleSelect(); 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 1c251028a7..6e67dc84d4 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 @@ -24,6 +24,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateViewStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OraclePLSQLCommitStatement; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; +import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.Token; @@ -37,6 +38,10 @@ public class OracleStatementParser extends SQLStatementParser { public OracleStatementParser(Lexer lexer){ super(lexer); } + + protected SQLExprParser createExprParser() { + return new OracleExprParser(lexer); + } @Override public void parseStatementList(List statementList) throws ParserException { diff --git a/src/main/java/com/alibaba/druid/sql/parser/CharTypes.java b/src/main/java/com/alibaba/druid/sql/parser/CharTypes.java index 7b13a42360..8c84b24b7c 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/CharTypes.java +++ b/src/main/java/com/alibaba/druid/sql/parser/CharTypes.java @@ -84,6 +84,7 @@ public class CharTypes { whitespaceFlags['\t'] = true; whitespaceFlags['\f'] = true; whitespaceFlags['\b'] = true; + whitespaceFlags[160] = true; // 特别处理 } /** diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java index 17336e0397..98fa3bccdc 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -85,7 +85,7 @@ public class SQLStatementParser extends SQLParser { } if (lexer.token() == (Token.INSERT)) { - SQLInsertStatement insertStatement = parseInsert(); + SQLStatement insertStatement = parseInsert(); statementList.add(insertStatement); continue; @@ -130,7 +130,7 @@ public class SQLStatementParser extends SQLParser { } } - public SQLInsertStatement parseInsert() { + public SQLStatement parseInsert() { accept(Token.INSERT); accept(Token.INTO); 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 08e4749190..9c7cdf3622 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -102,7 +102,8 @@ public enum Token { PRIOR("PRIOR"), CONNECT("CONNECT"), - EOF, ERROR, + EOF, + ERROR, IDENTIFIER, HINT, VARIANT, diff --git a/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserResourceTest.java b/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserResourceTest.java new file mode 100644 index 0000000000..449243dd61 --- /dev/null +++ b/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserResourceTest.java @@ -0,0 +1,76 @@ +package com.alibaba.druid.sql.oracle.bvt; + +import java.util.List; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetListClause; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetListSingleColumnItem; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleOutputVisitor; +import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; + +public class OracleSQLParserResourceTest extends TestCase { + + public void test_0() throws Exception { + String sql = "UPDATE employees SET salary = salary * 1.1 WHERE employee_id IN (SELECT employee_id FROM job_history);"; + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + + Assert.assertEquals(1, statementList.size()); + + OracleUpdateStatement statement = (OracleUpdateStatement) statementList.get(0); + Assert.assertEquals(0, statement.getHints().size()); + OracleUpdateSetListClause setList = (OracleUpdateSetListClause) statement.getSetClause(); + Assert.assertEquals(1, setList.getItems().size()); + OracleUpdateSetListSingleColumnItem item = (OracleUpdateSetListSingleColumnItem) setList.getItems().get(0); + SQLIdentifierExpr column = (SQLIdentifierExpr) item.getColumn(); + Assert.assertEquals("salary", column.getName()); + + SQLBinaryOpExpr value = (SQLBinaryOpExpr) item.getValue(); + Assert.assertEquals(SQLBinaryOperator.Multiply, value.getOperator()); + + String text = output(statementList); + System.out.println(text); + } + + public void test_1() throws Exception { + String sql = "SELECT employees_seq.nextval FROM DUAL;"; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + + Assert.assertEquals(1, statementList.size()); + + String text = output(statementList); + System.out.println(text); + } + + public void test_2() throws Exception { + String sql = "SELECT LPAD(' ',2*(LEVEL-1)) || last_name org_chart, employee_id, manager_id, job_id FROM employees WHERE job_id != 'FI_MGR' START WITH job_id = 'AD_VP' CONNECT BY PRIOR employee_id = manager_id; "; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + + Assert.assertEquals(1, statementList.size()); + + String text = output(statementList); + System.out.println(text); + } + + private String output(List stmtList) { + StringBuilder out = new StringBuilder(); + OracleOutputVisitor visitor = new OracleOutputVisitor(out); + + for (SQLStatement stmt : stmtList) { + stmt.accept(visitor); + } + + return out.toString(); + } +} diff --git a/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserTest.java b/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserTest.java index a32a1f4aac..53efa101d9 100644 --- a/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserTest.java +++ b/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserTest.java @@ -1,64 +1,52 @@ package com.alibaba.druid.sql.oracle.bvt; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; import java.util.List; import junit.framework.Assert; import junit.framework.TestCase; import com.alibaba.druid.sql.ast.SQLStatement; -import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; -import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; -import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; -import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetListClause; -import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetListSingleColumnItem; -import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateStatement; import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleOutputVisitor; import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; +import com.alibaba.druid.sql.parser.Lexer; +import com.alibaba.druid.sql.parser.Token; +import com.alibaba.druid.util.JdbcUtils; public class OracleSQLParserTest extends TestCase { - public void test_0() throws Exception { - String sql = "UPDATE employees SET salary = salary * 1.1 WHERE employee_id IN (SELECT employee_id FROM job_history);"; - OracleStatementParser parser = new OracleStatementParser(sql); - List statementList = parser.parseStatementList(); - - Assert.assertEquals(1, statementList.size()); - - OracleUpdateStatement statement = (OracleUpdateStatement) statementList.get(0); - Assert.assertEquals(0, statement.getHints().size()); - OracleUpdateSetListClause setList = (OracleUpdateSetListClause) statement.getSetClause(); - Assert.assertEquals(1, setList.getItems().size()); - OracleUpdateSetListSingleColumnItem item = (OracleUpdateSetListSingleColumnItem) setList.getItems().get(0); - SQLIdentifierExpr column = (SQLIdentifierExpr) item.getColumn(); - Assert.assertEquals("salary", column.getName()); - - SQLBinaryOpExpr value = (SQLBinaryOpExpr) item.getValue(); - Assert.assertEquals(SQLBinaryOperator.Multiply, value.getOperator()); - - String text = output(statementList); - System.out.println(text); - } - public void test_1() throws Exception { - String sql = "SELECT employees_seq.nextval FROM DUAL;"; + InputStream is = null; + + is = Thread.currentThread().getContextClassLoader().getResourceAsStream("bvt/parser/oracle-0.txt"); + Reader reader = new InputStreamReader(is); + String sql = JdbcUtils.read(reader); + JdbcUtils.close(reader); OracleStatementParser parser = new OracleStatementParser(sql); List statementList = parser.parseStatementList(); - + Assert.assertEquals(1, statementList.size()); - + String text = output(statementList); System.out.println(text); } public void test_2() throws Exception { - String sql = "SELECT LPAD(' ',2*(LEVEL-1)) || last_name org_chart, employee_id, manager_id, job_id FROM employees WHERE job_id != 'FI_MGR' START WITH job_id = 'AD_VP' CONNECT BY PRIOR employee_id = manager_id; "; + InputStream is = null; + + is = Thread.currentThread().getContextClassLoader().getResourceAsStream("bvt/parser/oracle-1.txt"); + Reader reader = new InputStreamReader(is); + String sql = JdbcUtils.read(reader); + JdbcUtils.close(reader); OracleStatementParser parser = new OracleStatementParser(sql); List statementList = parser.parseStatementList(); - + Assert.assertEquals(1, statementList.size()); - + String text = output(statementList); System.out.println(text); } diff --git a/src/test/java/com/alibaba/druid/sql/parser/SQLLexerTest2.java b/src/test/java/com/alibaba/druid/sql/parser/SQLLexerTest2.java index 28e54e3b8d..e6dfb05531 100644 --- a/src/test/java/com/alibaba/druid/sql/parser/SQLLexerTest2.java +++ b/src/test/java/com/alibaba/druid/sql/parser/SQLLexerTest2.java @@ -13,6 +13,8 @@ public class SQLLexerTest2 extends TestCase { if (tok == Token.IDENTIFIER) { System.out.println(tok.name() + "\t\t" + lexer.stringVal()); + } else if (tok == Token.LITERAL_INT) { + System.out.println(tok.name() + "\t\t" + lexer.numberString()); } else { System.out.println(tok.name() + "\t\t\t" + tok.name); } diff --git a/src/test/resources/bvt/parser/oracle-0.txt b/src/test/resources/bvt/parser/oracle-0.txt new file mode 100644 index 0000000000..1bd26cc324 --- /dev/null +++ b/src/test/resources/bvt/parser/oracle-0.txt @@ -0,0 +1,14 @@ +SELECT                 +ID as id,                 +to_char(GMT_MODIFIED,'yyyymmdd hh24:mi:ss') as gmtModified,                                +COL5 as col5             +FROM BPM_ACTINST             +WHERE IS_DELETED='n'                   +AND end_time is null   +AND deadline_time < sysdate   +AND approval_time is null +AND             id > :1         +AND col2 in     +(:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16,:17,:18,:19,:20,:21,:22,:23,:24,:25,:26,:27,:28,:29,:30,:31,:32,:33)       +AND rownum<:34   +ORDER BY id   ; \ No newline at end of file diff --git a/src/test/resources/bvt/parser/oracle-1.txt b/src/test/resources/bvt/parser/oracle-1.txt new file mode 100644 index 0000000000..a6ecec891e --- /dev/null +++ b/src/test/resources/bvt/parser/oracle-1.txt @@ -0,0 +1,59 @@ +INSERT INTO GLOBAL_ACCOUNT_SMD + (ID, + GMT_MODIFIED, + MODIFIER, + GMT_CREATE, + CREATOR, + DOMAIN, + EMPLOYEE_NUMBER, + COMPANY_NAME, + HOMEPAGE_URL, + BACKGROUND, + CATEGORY_ID, + REMARK, + MEMBER_ID, + SALES_OWNER_ID, + ACCOUNT_ID, + IS_DELETED, + CUST_GRADE) + SELECT ID, + GMT_MODIFIED, + MODIFIER, + GMT_CREATE, + CREATOR, + DOMAIN, + EMPLOYEE_NUMBER, + COMPANY_NAME, + HOMEPAGE_URL, + BACKGROUND, + CATEGORY_ID, + REMARK, + MEMBER_ID, + SALES_OWNER_ID, + ACCOUNT_ID, + IS_DELETED, + CUST_GRADE + FROM APOLLO_ZEUS.GLOBAL_ACCOUNT + WHERE ACCOUNT_ID = :B2 + AND DOMAIN = :B1 + UNION ALL + SELECT ID, + GMT_MODIFIED, + MODIFIER, + GMT_CREATE, + CREATOR, + DOMAIN, + EMPLOYEE_NUMBER, + COMPANY_NAME, + HOMEPAGE_URL, + BACKGROUND, + CATEGORY_ID, + REMARK, + MEMBER_ID, + SALES_OWNER_ID, + ACCOUNT_ID, + IS_DELETED, + CUST_GRADE + FROM APOLLO_NIR.GLOBAL_ACCOUNT + WHERE ACCOUNT_ID = :B2 + AND DOMAIN = :B1 \ No newline at end of file