From 75526cb351ec9b7a473a912c2bdf522b2bd824b3 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 19 Aug 2017 21:20:32 +0800 Subject: [PATCH] improved sql parser. for issue #1919 --- .../alibaba/druid/filter/FilterManager.java | 3 + .../dialect/mysql/parser/MySqlExprParser.java | 6 ++ .../mysql/parser/MySqlStatementParser.java | 4 ++ .../visitor/OracleToMySqlOutputVisitor.java | 10 +++ .../stmt/OracleCreateSynonymStatement.java | 57 +++++++++++++++++ .../oracle/parser/OracleExprParser.java | 13 +++- .../oracle/parser/OracleStatementParser.java | 25 ++++++++ .../oracle/visitor/OracleASTVisitor.java | 4 ++ .../visitor/OracleASTVisitorAdapter.java | 10 +++ .../oracle/visitor/OracleOutputVisitor.java | 28 +++++++++ .../visitor/OracleSchemaStatVisitor.java | 10 +++ .../druid/sql/parser/SQLStatementParser.java | 18 +++++- .../com/alibaba/druid/util/JdbcConstants.java | 2 +- .../create/OracleCreateSynonymTest.java | 61 +++++++++++++++++++ .../create/OracleCreateSynonymTest1.java | 60 ++++++++++++++++++ .../create/OracleCreateSynonymTest2.java | 61 +++++++++++++++++++ 16 files changed, 369 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleCreateSynonymStatement.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest1.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest2.java diff --git a/src/main/java/com/alibaba/druid/filter/FilterManager.java b/src/main/java/com/alibaba/druid/filter/FilterManager.java index f1f835f214..d6c6a01610 100644 --- a/src/main/java/com/alibaba/druid/filter/FilterManager.java +++ b/src/main/java/com/alibaba/druid/filter/FilterManager.java @@ -112,6 +112,9 @@ public class FilterManager { try { filter = (Filter) filterClass.newInstance(); + } catch (ClassCastException e) { + LOG.error("load filter error.", e); + continue; } catch (InstantiationException e) { throw new SQLException("load managed jdbc driver event listener error. " + filterName, e); } catch (IllegalAccessException e) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java index 008ee56a47..5679643ead 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java @@ -78,6 +78,12 @@ public class MySqlExprParser extends SQLExprParser { this.lexer.nextToken(); } + + public MySqlExprParser(String sql, boolean skipComment,boolean keepComments){ + this(new MySqlLexer(sql, skipComment, keepComments)); + this.lexer.nextToken(); + } + public SQLExpr relationalRest(SQLExpr expr) { if (identifierEquals("REGEXP")) { lexer.nextToken(); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index 879746f83f..a11c499016 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -98,6 +98,10 @@ public class MySqlStatementParser extends SQLStatementParser { super(new MySqlExprParser(sql, keepComments)); } + public MySqlStatementParser(String sql, boolean skipComment, boolean keepComments) { + super(new MySqlExprParser(sql, skipComment, keepComments)); + } + public MySqlStatementParser(Lexer lexer) { super(new MySqlExprParser(lexer)); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/OracleToMySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/OracleToMySqlOutputVisitor.java index 3a43d2e875..a364803ec5 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/OracleToMySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/OracleToMySqlOutputVisitor.java @@ -1003,4 +1003,14 @@ public class OracleToMySqlOutputVisitor extends MySqlOutputVisitor implements Or public void endVisit(OracleTreatExpr x) { } + + @Override + public boolean visit(OracleCreateSynonymStatement x) { + return false; + } + + @Override + public void endVisit(OracleCreateSynonymStatement x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleCreateSynonymStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleCreateSynonymStatement.java new file mode 100644 index 0000000000..51b06d2132 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleCreateSynonymStatement.java @@ -0,0 +1,57 @@ +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 OracleCreateSynonymStatement extends OracleStatementImpl { + private boolean orReplace; + private SQLName name; + private boolean isPublic; + private SQLName object; + + @Override + public void accept0(OracleASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, name); + acceptChild(visitor, object); + } + } + + public boolean isPublic() { + return isPublic; + } + + public void setPublic(boolean value) { + isPublic = value; + } + + public SQLName getName() { + return name; + } + + public void setName(SQLName name) { + if (name != null) { + name.setParent(this); + } + this.name = name; + } + + public SQLName getObject() { + return object; + } + + public void setObject(SQLName object) { + if (object != null) { + object.setParent(this); + } + this.object = object; + } + + public boolean isOrReplace() { + return orReplace; + } + + public void setOrReplace(boolean orReplace) { + this.orReplace = orReplace; + } +} 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 490d449df3..be94b7b3c5 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 @@ -968,8 +968,19 @@ public class OracleExprParser extends SQLExprParser { } OracleDbLinkExpr dbLink = new OracleDbLinkExpr(); dbLink.setExpr(name); - dbLink.setDbLink(lexer.stringVal()); + + + String link = lexer.stringVal(); lexer.nextToken(); + while (lexer.token() == Token.DOT) { + lexer.nextToken(); + + String stringVal = lexer.stringVal(); + accept(Token.IDENTIFIER); + link += "." + stringVal; + } + + dbLink.setDbLink(link); return dbLink; } 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 ecbc23465a..f9dac1bc06 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 @@ -2293,4 +2293,29 @@ public class OracleStatementParser extends SQLStatementParser { accept(Token.SEMI); return stmt; } + + public SQLStatement parseCreateSynonym() { + OracleCreateSynonymStatement stmt = new OracleCreateSynonymStatement(); + accept(Token.CREATE); + + if (lexer.token() == Token.OR) { + lexer.nextToken(); + accept(Token.REPLACE); + stmt.setOrReplace(true); + } + + if (identifierEquals("PUBLIC")) { + lexer.nextToken(); + stmt.setPublic(true); + } + + acceptIdentifier("SYNONYM"); + + stmt.setName(this.exprParser.name()); + + accept(Token.FOR); + + stmt.setObject(this.exprParser.name()); + return stmt; + } } 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 37974009cb..c870f74092 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 @@ -427,4 +427,8 @@ public interface OracleASTVisitor extends SQLASTVisitor { boolean visit(OracleTreatExpr x); void endVisit(OracleTreatExpr x); + + boolean visit(OracleCreateSynonymStatement x); + + void endVisit(OracleCreateSynonymStatement 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 7683ad0f30..fa968b026f 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 @@ -1052,4 +1052,14 @@ public class OracleASTVisitorAdapter extends SQLASTVisitorAdapter implements Ora public void endVisit(OracleTreatExpr x) { } + + @Override + public boolean visit(OracleCreateSynonymStatement x) { + return true; + } + + @Override + public void endVisit(OracleCreateSynonymStatement 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 f7796b0313..bf352e5ede 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 @@ -3268,4 +3268,32 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS public void endVisit(OracleTreatExpr x) { } + + @Override + public boolean visit(OracleCreateSynonymStatement x) { + + if (x.isOrReplace()) { + print0(ucase ? "CREATE OR REPLACE " : "create or replace "); + } else { + print0(ucase ? "CREATE " : "create "); + } + + if (x.isPublic()) { + print0(ucase ? "PUBLIC " : "public "); + } + + print0(ucase ? "SYNONYM " : "synonym "); + + x.getName().accept(this); + + print0(ucase ? " FOR " : " for "); + x.getObject().accept(this); + + return false; + } + + @Override + public void endVisit(OracleCreateSynonymStatement 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 4f913977ae..10839501bb 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 @@ -1445,4 +1445,14 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle public void endVisit(OracleTreatExpr x) { } + + @Override + public boolean visit(OracleCreateSynonymStatement x) { + return false; + } + + @Override + public void endVisit(OracleCreateSynonymStatement x) { + + } } 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 f63b5a12eb..2fe1dfa67f 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -1853,9 +1853,21 @@ public class SQLStatementParser extends SQLParser { lexer.reset(markBp, markChar, Token.CREATE); return parseCreateDatabase(); - } else if (identifierEquals("PUBLIC") || identifierEquals("SHARE")) { + } else if (identifierEquals("PUBLIC")) { + lexer.nextToken(); + if (identifierEquals("SYNONYM")) { + lexer.reset(markBp, markChar, Token.CREATE); + return parseCreateSynonym(); + } else { + lexer.reset(markBp, markChar, Token.CREATE); + return parseCreateDbLink(); + } + } else if (identifierEquals("SHARE")) { lexer.reset(markBp, markChar, Token.CREATE); return parseCreateDbLink(); + } else if (identifierEquals("SYNONYM")) { + lexer.reset(markBp, markChar, Token.CREATE); + return parseCreateSynonym(); } else if (token == Token.VIEW) { return parseCreateView(); } else if (token == Token.TRIGGER) { @@ -1963,6 +1975,10 @@ public class SQLStatementParser extends SQLParser { throw new ParserException("TODO " + lexer.token()); } + public SQLStatement parseCreateSynonym() { + throw new ParserException("TODO " + lexer.token()); + } + public SQLStatement parseCreateTrigger() { accept(Token.CREATE); diff --git a/src/main/java/com/alibaba/druid/util/JdbcConstants.java b/src/main/java/com/alibaba/druid/util/JdbcConstants.java index 072fd09035..d69183847f 100644 --- a/src/main/java/com/alibaba/druid/util/JdbcConstants.java +++ b/src/main/java/com/alibaba/druid/util/JdbcConstants.java @@ -47,7 +47,7 @@ public interface JdbcConstants { public static final String MYSQL = "mysql"; public static final String MYSQL_DRIVER = "com.mysql.jdbc.Driver"; public static final String MYSQL_DRIVER_6 = "com.mysql.cj.jdbc.Driver"; - public static final String MYSQL_DRIVER_REPLICATE = "com.mysql.jdbc.ReplicationDriver"; + public static final String MYSQL_DRIVER_REPLICATE = "com.mysql.jdbc."; public static final String MARIADB = "mariadb"; public static final String MARIADB_DRIVER = "org.mariadb.jdbc.Driver"; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest.java new file mode 100644 index 0000000000..ea9a3fc3d7 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest.java @@ -0,0 +1,61 @@ +/* + * 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.create; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor; +import org.junit.Assert; + +import java.util.List; + +public class OracleCreateSynonymTest extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "CREATE SYNONYM offices \n" + + " FOR hr.locations;"; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + stmt.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()); + + Assert.assertEquals(0, visitor.getTables().size()); + + // Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("cdc.en_complaint_ipr_stat_fdt0"))); + + Assert.assertEquals(0, visitor.getColumns().size()); + + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "*"))); + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "YEAR"))); + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "order_mode"))); + + assertEquals("CREATE SYNONYM offices FOR hr.locations;", stmt.toString()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest1.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest1.java new file mode 100644 index 0000000000..401910dbad --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest1.java @@ -0,0 +1,60 @@ +/* + * 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.create; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor; +import org.junit.Assert; + +import java.util.List; + +public class OracleCreateSynonymTest1 extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "CREATE PUBLIC SYNONYM customers FOR oe.customers;"; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + stmt.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()); + + Assert.assertEquals(0, visitor.getTables().size()); + + // Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("cdc.en_complaint_ipr_stat_fdt0"))); + + Assert.assertEquals(0, visitor.getColumns().size()); + + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "*"))); + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "YEAR"))); + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "order_mode"))); + + assertEquals("CREATE PUBLIC SYNONYM customers FOR oe.customers;", stmt.toString()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest2.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest2.java new file mode 100644 index 0000000000..59200a82d6 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateSynonymTest2.java @@ -0,0 +1,61 @@ +/* + * 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.create; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor; +import org.junit.Assert; + +import java.util.List; + +public class OracleCreateSynonymTest2 extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "CREATE PUBLIC SYNONYM emp_table \n" + + " FOR hr.employees@remote.us.oracle.com;"; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + stmt.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()); + + Assert.assertEquals(0, visitor.getTables().size()); + + // Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("cdc.en_complaint_ipr_stat_fdt0"))); + + Assert.assertEquals(0, visitor.getColumns().size()); + + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "*"))); + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "YEAR"))); + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("pivot_table", "order_mode"))); + + assertEquals("CREATE PUBLIC SYNONYM emp_table FOR hr.employees@remote.us.oracle.com;", stmt.toString()); + } +}