From 793658499e429b1a67076734859dc50c87deedbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=93=81?= Date: Fri, 18 Mar 2016 16:33:02 +0800 Subject: [PATCH 1/3] add license info --- .../sql/dialect/teradata/ast/TeradataObject.java | 15 +++++++++++++++ .../teradata/parser/TeradataExprParser.java | 15 +++++++++++++++ .../dialect/teradata/parser/TeradataLexer.java | 15 +++++++++++++++ .../teradata/parser/TeradataStatementParser.java | 15 +++++++++++++++ .../teradata/visitor/TeradataASTVisitor.java | 15 +++++++++++++++ .../visitor/TeradataASTVisitorAdapter.java | 15 +++++++++++++++ .../teradata/visitor/TeradataOutputVisitor.java | 15 +++++++++++++++ .../visitor/TeradataSchemaStatVisitor.java | 15 +++++++++++++++ 8 files changed, 120 insertions(+) diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/TeradataObject.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/TeradataObject.java index 22a0f6ce4e..abb16ee0a8 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/TeradataObject.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/TeradataObject.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2101 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.teradata.ast; import com.alibaba.druid.sql.ast.SQLObject; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataExprParser.java index d4c9d86f94..94eaeeb6fa 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataExprParser.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2101 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.teradata.parser; import com.alibaba.druid.sql.parser.Lexer; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataLexer.java index ea117ac69e..ebd7d2e530 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataLexer.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2101 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.teradata.parser; import java.util.HashMap; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataStatementParser.java index a847102eee..2fe2c5917e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataStatementParser.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2101 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.teradata.parser; import com.alibaba.druid.sql.parser.Lexer; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataASTVisitor.java index a0bee2499b..c4a3c8e48c 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataASTVisitor.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2101 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.teradata.visitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataASTVisitorAdapter.java index d6bc6a50b0..3dcdb0e84b 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataASTVisitorAdapter.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2101 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.teradata.visitor; import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataOutputVisitor.java index dfc81f1f5c..bbedbacee2 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataOutputVisitor.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2101 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.teradata.visitor; import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataSchemaStatVisitor.java index efa2e33378..43472f728c 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataSchemaStatVisitor.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2101 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.teradata.visitor; import com.alibaba.druid.sql.visitor.SchemaStatVisitor; From bf1ad5da0c7705ea3bb3cf02a69254caaddb9d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=93=81?= Date: Fri, 18 Mar 2016 16:34:02 +0800 Subject: [PATCH 2/3] sql parser improved db2 support --- .../com/alibaba/druid/sql/ast/SQLOver.java | 15 +++ .../sql/dialect/db2/parser/DB2Lexer.java | 1 + .../druid/sql/parser/SQLExprParser.java | 6 ++ .../sql/visitor/SQLASTOutputVisitor.java | 7 ++ .../druid/bvt/sql/db2/DB2SelectTest_10.java | 93 +++++++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_10.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLOver.java b/src/main/java/com/alibaba/druid/sql/ast/SQLOver.java index 9396c541e2..8aa9ef0e77 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLOver.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLOver.java @@ -25,6 +25,9 @@ public class SQLOver extends SQLObjectImpl { protected final List partitionBy = new ArrayList(); protected SQLOrderBy orderBy; + // for db2 + protected SQLExpr of; + public SQLOver(){ } @@ -38,6 +41,7 @@ public class SQLOver extends SQLObjectImpl { if (visitor.visit(this)) { acceptChild(visitor, this.partitionBy); acceptChild(visitor, this.orderBy); + acceptChild(visitor, this.of); } visitor.endVisit(this); } @@ -53,6 +57,17 @@ public class SQLOver extends SQLObjectImpl { this.orderBy = orderBy; } + public SQLExpr getOf() { + return of; + } + + public void setOf(SQLExpr of) { + if (of != null) { + of.setParent(this); + } + this.of = of; + } + public List getPartitionBy() { return partitionBy; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2Lexer.java b/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2Lexer.java index 9fee7ff66d..1f0d909c6e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2Lexer.java @@ -36,6 +36,7 @@ public class DB2Lexer extends Lexer { map.put("FIRST", Token.FIRST); map.put("ONLY", Token.ONLY); map.put("OPTIMIZE", Token.OPTIMIZE); + map.put("OF", Token.OF); DEFAULT_DB2_KEYWORDS = new Keywords(map); } 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 f13df09738..60ce7d8832 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1036,6 +1036,12 @@ public class SQLExprParser extends SQLParser { } over.setOrderBy(parseOrderBy()); + + if (lexer.token() == Token.OF) { + lexer.nextToken(); + SQLExpr of = this.expr(); + over.setOf(of); + } accept(Token.RPAREN); aggregateExpr.setOver(over); 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 5dd21fa600..20a2e529ad 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -1632,9 +1632,16 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Printab printAndAccept(x.getPartitionBy(), ", "); print(' '); } + if (x.getOrderBy() != null) { x.getOrderBy().accept(this); } + + if (x.getOf() != null) { + print0(ucase ? " OF " : " of "); + x.getOf().accept(this); + } + print(')'); return false; } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_10.java b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_10.java new file mode 100644 index 0000000000..6c7e5ca26d --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_10.java @@ -0,0 +1,93 @@ +/* + * Copyright 1999-2101 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.db2; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.DB2Test; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.db2.parser.DB2StatementParser; +import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.util.JdbcConstants; + +public class DB2SelectTest_10 extends DB2Test { + + public void test_0() throws Exception { + String sql = "select * from ( select inner2_.*, rownumber() over(order by order of inner2_) as rownumber_ from (" + + " select tsuserstb0_.USERID as USERID1_1_, tsuserstb0_.CREASTAF as CREASTAF2_1_, tsuserstb0_.CREATIME as CREATIME3_1_" + + " , tsuserstb0_.LOCORGNO as LOCORGNO4_1_, tsuserstb0_.PWDMODIFYTIME as PWDMODIF5_1_, tsuserstb0_.REMARK01 as REMARK6_1_" + + " , tsuserstb0_.REMARK02 as REMARK7_1_, tsuserstb0_.STAORGNO as STAORGNO8_1_, tsuserstb0_.UPDASTAF as UPDASTAF9_1_" + + " , tsuserstb0_.UPDATIME as UPDATIM10_1_, tsuserstb0_.USERNAME as USERNAM11_1_, tsuserstb0_.USERPWD as USERPWD12_1_" + + " , tsuserstb0_.USERSTATE as USERSTA13_1_ from TS_USERSTB tsuserstb0_ fetch first 20 rows only ) as inner2_ " + + ") as inner1_" + + " where rownumber_ > 10 order by rownumber_"; + + DB2StatementParser parser = new DB2StatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + DB2SchemaStatVisitor visitor = new DB2SchemaStatVisitor(); + stmt.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + Assert.assertEquals(1, visitor.getTables().size()); + Assert.assertEquals(14, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("TS_USERSTB"))); + + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "last_name"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "first_name"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "full_name"))); + + Assert.assertEquals("SELECT *" + + "\nFROM (SELECT inner2_.*, ROWNUMBER() OVER (ORDER BY order OF inner2_) AS rownumber_" + + "\n\tFROM (SELECT tsuserstb0_.USERID AS USERID1_1_, tsuserstb0_.CREASTAF AS CREASTAF2_1_, tsuserstb0_.CREATIME AS CREATIME3_1_, tsuserstb0_.LOCORGNO AS LOCORGNO4_1_, tsuserstb0_.PWDMODIFYTIME AS PWDMODIF5_1_" + + "\n\t\t\t, tsuserstb0_.REMARK01 AS REMARK6_1_, tsuserstb0_.REMARK02 AS REMARK7_1_, tsuserstb0_.STAORGNO AS STAORGNO8_1_, tsuserstb0_.UPDASTAF AS UPDASTAF9_1_, tsuserstb0_.UPDATIME AS UPDATIM10_1_" + + "\n\t\t\t, tsuserstb0_.USERNAME AS USERNAM11_1_, tsuserstb0_.USERPWD AS USERPWD12_1_, tsuserstb0_.USERSTATE AS USERSTA13_1_" + + "\n\t\tFROM TS_USERSTB tsuserstb0_" + + "\n\t\tFETCH FIRST 20 ROWS ONLY" + + "\n\t\t) inner2_" + + "\n\t) inner1_" + + "\nWHERE rownumber_ > 10" + + "\nORDER BY rownumber_", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2)); + + Assert.assertEquals("select *" + + "\nfrom (select inner2_.*, rownumber() over (order by order of inner2_) as rownumber_" + + "\n\tfrom (select tsuserstb0_.USERID as USERID1_1_, tsuserstb0_.CREASTAF as CREASTAF2_1_, tsuserstb0_.CREATIME as CREATIME3_1_, tsuserstb0_.LOCORGNO as LOCORGNO4_1_, tsuserstb0_.PWDMODIFYTIME as PWDMODIF5_1_" + + "\n\t\t\t, tsuserstb0_.REMARK01 as REMARK6_1_, tsuserstb0_.REMARK02 as REMARK7_1_, tsuserstb0_.STAORGNO as STAORGNO8_1_, tsuserstb0_.UPDASTAF as UPDASTAF9_1_, tsuserstb0_.UPDATIME as UPDATIM10_1_" + + "\n\t\t\t, tsuserstb0_.USERNAME as USERNAM11_1_, tsuserstb0_.USERPWD as USERPWD12_1_, tsuserstb0_.USERSTATE as USERSTA13_1_" + + "\n\t\tfrom TS_USERSTB tsuserstb0_" + + "\n\t\tfetch first 20 rows only" + + "\n\t\t) inner2_" + + "\n\t) inner1_" + + "\nwhere rownumber_ > 10" + + "\norder by rownumber_", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + } +} From 824360e0eaca8d351d866f8a8f84f3ea31e7b2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=93=81?= Date: Sat, 19 Mar 2016 14:36:55 +0800 Subject: [PATCH 3/3] improved sql parser --- .../dialect/mysql/ast/MysqlForeignKey.java | 49 +++++---- .../mysql/parser/MySqlCreateTableParser.java | 9 +- .../dialect/mysql/parser/MySqlExprParser.java | 62 +++++++----- .../mysql/visitor/MySqlOutputVisitor.java | 18 ++-- .../visitor/OracleSchemaStatVisitor.java | 6 +- .../visitor/PGSchemaStatVisitor.java | 2 +- .../druid/sql/visitor/SchemaStatVisitor.java | 99 ++++++++++++++++--- .../com/alibaba/druid/stat/TableStat.java | 32 +++--- .../bvt/sql/mysql/MySqlCreateTableTest54.java | 4 +- .../bvt/sql/mysql/MySqlCreateTableTest70.java | 93 +++++++++++++++++ .../visitor/OracleSchemaStatVisitorTest1.java | 4 + .../visitor/OracleSchemaStatVisitorTest5.java | 84 ++++++++++++++++ .../visitor/OracleSchemaStatVisitorTest6.java | 69 +++++++++++++ .../visitor/OracleSchemaStatVisitorTest7.java | 60 +++++++++++ 14 files changed, 495 insertions(+), 96 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest70.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest5.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest6.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest7.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MysqlForeignKey.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MysqlForeignKey.java index 14eb943d2a..fd55b61ea1 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MysqlForeignKey.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MysqlForeignKey.java @@ -25,15 +25,14 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; */ public class MysqlForeignKey extends SQLForeignKeyImpl { - private SQLName indexName; + private SQLName indexName; - private boolean hasConstraint; + private boolean hasConstraint; - private Match referenceMatch; + private Match referenceMatch; - private On referenceOn; - - private Option referenceOption; + protected Option onUpdate; + protected Option onDelete; public SQLName getIndexName() { return indexName; @@ -78,25 +77,25 @@ public class MysqlForeignKey extends SQLForeignKeyImpl { this.referenceMatch = referenceMatch; } - public On getReferenceOn() { - return referenceOn; + public Option getOnUpdate() { + return onUpdate; } - public void setReferenceOn(On referenceOn) { - this.referenceOn = referenceOn; + public void setOnUpdate(Option onUpdate) { + this.onUpdate = onUpdate; } - public Option getReferenceOption() { - return referenceOption; + public Option getOnDelete() { + return onDelete; } - public void setReferenceOption(Option referenceOption) { - this.referenceOption = referenceOption; + public void setOnDelete(Option onDelete) { + this.onDelete = onDelete; } public static enum Option { - RESTRICT("RESTRICT"), CASCADE("CASCADE"), SET_NULL("SET NULL"), NO_ACTION("NO ACTION"); + RESTRICT("RESTRICT"), CASCADE("CASCADE"), SET_NULL("SET NULL"), NO_ACTION("NO ACTION"); public final String name; public final String name_lcase; @@ -113,27 +112,25 @@ public class MysqlForeignKey extends SQLForeignKeyImpl { } public static enum Match { - FULL("FULL"), - PARTIAL("PARTIAL"), - SIMPLE("SIMPLE"); - + FULL("FULL"), PARTIAL("PARTIAL"), SIMPLE("SIMPLE"); + public final String name; public final String name_lcase; - - Match(String name) { + + Match(String name){ this.name = name; this.name_lcase = name.toLowerCase(); } } public static enum On { - DELETE("DELETE"), // - UPDATE("UPDATE"); - + DELETE("DELETE"), // + UPDATE("UPDATE"); + public final String name; public final String name_lcase; - - On(String name) { + + On(String name){ this.name = name; this.name_lcase = name.toLowerCase(); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java index ba6619466e..1954ecc1fb 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java @@ -116,7 +116,8 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } else if (lexer.token() == Token.CONSTRAINT // || lexer.token() == Token.PRIMARY // || lexer.token() == Token.UNIQUE) { - stmt.getTableElementList().add(parseConstraint()); + SQLTableConstraint constraint = this.parseConstraint(); + stmt.getTableElementList().add(constraint); } else if (lexer.token() == (Token.INDEX)) { lexer.nextToken(); @@ -144,6 +145,12 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } } accept(Token.RPAREN); + + if (identifierEquals("USING")) { + lexer.nextToken(); + idx.setIndexType(lexer.stringVal()); + lexer.nextToken(); + } stmt.getTableElementList().add(idx); } else if (lexer.token() == (Token.KEY)) { 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 ed0851f80c..fde479f91c 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 @@ -41,7 +41,6 @@ import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique; import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey; import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey.Match; -import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey.On; import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey.Option; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlCharExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExtractExpr; @@ -834,39 +833,56 @@ public class MySqlExprParser extends SQLExprParser { } } - if (lexer.token() == Token.ON) { + while (lexer.token() == Token.ON) { lexer.nextToken(); + if (lexer.token() == Token.DELETE) { - fk.setReferenceOn(On.DELETE); + lexer.nextToken(); + + Option option = parseReferenceOption(); + fk.setOnDelete(option); } else if (lexer.token() == Token.UPDATE) { - fk.setReferenceOn(On.UPDATE); + lexer.nextToken(); + + Option option = parseReferenceOption(); + fk.setOnUpdate(option); } else { throw new ParserException("syntax error, expect DELETE or UPDATE, actual " + lexer.token() + " " + lexer.stringVal()); } - lexer.nextToken(); - - if (lexer.token() == Token.RESTRICT) { - fk.setReferenceOption(Option.RESTRICT); - } else if (identifierEquals("CASCADE")) { - fk.setReferenceOption(Option.CASCADE); - } else if (lexer.token() == Token.SET) { - accept(Token.NULL); - fk.setReferenceOption(Option.SET_NULL); - } else if (identifierEquals("ON")) { - lexer.nextToken(); - if (identifierEquals("ACTION")) { - fk.setReferenceOption(Option.NO_ACTION); - } else { - throw new ParserException("syntax error, expect ACTION, actual " + lexer.token() + " " - + lexer.stringVal()); - } - } - lexer.nextToken(); } return fk; } + protected Option parseReferenceOption() { + Option option; + if (lexer.token() == Token.RESTRICT || identifierEquals("RESTRICT")) { + option = Option.RESTRICT; + lexer.nextToken(); + } else if (identifierEquals("CASCADE")) { + option = Option.CASCADE; + lexer.nextToken(); + } else if (lexer.token() == Token.SET) { + lexer.nextToken(); + accept(Token.NULL); + option = Option.SET_NULL; + } else if (identifierEquals("ON")) { + lexer.nextToken(); + if (identifierEquals("ACTION")) { + option = Option.NO_ACTION; + lexer.nextToken(); + } else { + throw new ParserException("syntax error, expect ACTION, actual " + lexer.token() + " " + + lexer.stringVal()); + } + } else { + throw new ParserException("syntax error, expect ACTION, actual " + lexer.token() + " " + + lexer.stringVal()); + } + + return option; + } + protected SQLAggregateExpr parseAggregateExprRest(SQLAggregateExpr aggregateExpr) { if (lexer.token() == Token.ORDER) { SQLOrderBy orderBy = this.parseOrderBy(); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index 905213a014..accd4e391e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -54,7 +54,6 @@ import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUseIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey; -import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey.Option; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement.MySqlWhenStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement; @@ -2816,15 +2815,14 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV print0(ucase ? match.name : match.name_lcase); } - MysqlForeignKey.On on = x.getReferenceOn(); - if (on != null) { - print0(ucase ? " ON " : " on "); - print0(ucase ? on.name : on.name_lcase); - print(' '); - Option option = x.getReferenceOption(); - if (option != null) { - print0(ucase ? option.name : option.name_lcase); - } + if (x.getOnDelete() != null) { + print0(ucase ? " ON DELETE " : " on delete "); + print0(ucase ? x.getOnDelete().name : x.getOnDelete().name_lcase); + } + + if (x.getOnDelete() != null) { + print0(ucase ? " ON UPDATE " : " on update "); + print0(ucase ? x.getOnDelete().name : x.getOnDelete().name_lcase); } return false; } 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 51f77ce647..14ea4cc7e8 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 @@ -196,7 +196,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle ident = expr.toString(); } - if (subQueryMap.containsKey(ident)) { + if (containsSubQuery(ident)) { return false; } @@ -575,7 +575,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle if (table != null) { this.aliasMap.put(x.getAlias(), table); } - this.subQueryMap.put(x.getAlias(), x.getSelect()); + addSubQuery(x.getAlias(), x.getSelect()); this.setCurrentTable(x.getAlias()); } @@ -650,7 +650,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle if (alias != null) { putAliasMap(aliasMap, alias, null); - subQueryMap.put(alias, x.getSubQuery()); + addSubQuery(alias, x.getSubQuery()); } } x.getSubQuery().accept(this); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java index 31231ea9c9..db265b434e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java @@ -107,7 +107,7 @@ public class PGSchemaStatVisitor extends SchemaStatVisitor implements PGASTVisit if (alias != null) { aliasMap.put(alias, null); - subQueryMap.put(alias, x.getQuery()); + addSubQuery(alias, x.getQuery()); } } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java index a6df65ee9a..9839bf9bc7 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -113,6 +113,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLShowTablesStatement; import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; import com.alibaba.druid.sql.ast.statement.SQLTableElement; +import com.alibaba.druid.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.ast.statement.SQLTruncateStatement; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.sql.ast.statement.SQLUseStatement; @@ -310,7 +311,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { } public boolean visit(SQLIdentifierExpr x) { - if (subQueryMap.containsKey(currentTable)) { + if (containsSubQuery(currentTable)) { return false; } @@ -331,7 +332,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { if (x.getOwner() instanceof SQLIdentifierExpr) { String owner = ((SQLIdentifierExpr) x.getOwner()).getName(); - if (subQueryMap.containsKey(owner)) { + if (containsSubQuery(owner)) { return false; } @@ -499,8 +500,14 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { if (owner instanceof SQLIdentifierExpr) { String tableName = ((SQLIdentifierExpr) owner).getName(); String table = tableName; - if (aliasMap.containsKey(table)) { - table = aliasMap.get(table); + String tableNameLower = tableName.toLowerCase(); + + if (aliasMap.containsKey(tableNameLower)) { + table = aliasMap.get(tableNameLower); + } + + if (containsSubQuery(tableNameLower)) { + table = null; } if (variants.containsKey(table)) { @@ -726,7 +733,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { if (x.getOwner() instanceof SQLIdentifierExpr) { String owner = ((SQLIdentifierExpr) x.getOwner()).getName(); - if (subQueryMap.containsKey(owner)) { + if (containsSubQuery(owner)) { return false; } @@ -736,6 +743,10 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { Column column = addColumn(owner, x.getName()); x.putAttribute(ATTR_COLUMN, column); if (column != null) { + if (isParentGroupBy(x)) { + this.groupByColumns.add(column); + } + if (column != null) { setColumn(x, column); } @@ -772,15 +783,25 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { } protected Column handleSubQueryColumn(String owner, String alias) { - SQLObject query = subQueryMap.get(owner); + SQLObject query = getSubQuery(owner); if (query == null) { return null; } + + return handleSubQueryColumn(alias, query); + } + protected Column handleSubQueryColumn(String alias, SQLObject query) { + if (query instanceof SQLSelect) { + query = ((SQLSelect) query).getQuery(); + } + + SQLSelectQueryBlock queryBlock = null; List selectList = null; if (query instanceof SQLSelectQueryBlock) { - selectList = ((SQLSelectQueryBlock) query).getSelectList(); + queryBlock = (SQLSelectQueryBlock) query; + selectList = queryBlock.getSelectList(); } if (selectList != null) { @@ -791,19 +812,30 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { String itemAlias = item.getAlias(); SQLExpr itemExpr = item.getExpr(); + + String ident = itemAlias; if (itemAlias == null) { if (itemExpr instanceof SQLIdentifierExpr) { - itemAlias = itemExpr.toString(); + ident = itemAlias = itemExpr.toString(); } else if (itemExpr instanceof SQLPropertyExpr) { itemAlias = ((SQLPropertyExpr) itemExpr).getName(); + ident = itemExpr.toString(); } } if (alias.equalsIgnoreCase(itemAlias)) { Column column = (Column) itemExpr.getAttribute(ATTR_COLUMN); - return column; + if (column != null) { + return column; + } else { + SQLTableSource from = queryBlock.getFrom(); + if (from instanceof SQLSubqueryTableSource) { + SQLSelect select = ((SQLSubqueryTableSource) from).getSelect(); + Column subQueryColumn = handleSubQueryColumn(ident, select); + return subQueryColumn; + } + } } - } } @@ -813,7 +845,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { public boolean visit(SQLIdentifierExpr x) { String currentTable = getCurrentTable(); - if (subQueryMap.containsKey(currentTable)) { + if (containsSubQuery(currentTable)) { return false; } @@ -826,6 +858,10 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { Column column; if (currentTable != null) { column = addColumn(currentTable, ident); + + if (column != null && isParentGroupBy(x)) { + this.groupByColumns.add(column); + } x.putAttribute(ATTR_COLUMN, column); } else { column = handleUnkownColumn(ident); @@ -854,6 +890,18 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { return isParentSelectItem(parent.getParent()); } + + private boolean isParentGroupBy(SQLObject parent) { + if (parent == null) { + return false; + } + + if (parent instanceof SQLSelectGroupByClause) { + return true; + } + + return isParentGroupBy(parent.getParent()); + } private void setColumn(SQLExpr x, Column column) { SQLObject current = x; @@ -906,7 +954,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { public boolean visit(SQLAllColumnExpr x) { String currentTable = getCurrentTable(); - if (subQueryMap.containsKey(currentTable)) { + if (containsSubQuery(currentTable)) { return false; } @@ -966,7 +1014,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { if (aliasMap != null && alias != null) { putAliasMap(aliasMap, alias, null); - subQueryMap.put(alias, x.getSubQuery().getQuery()); + addSubQuery(alias, x.getSubQuery().getQuery()); } x.getSubQuery().accept(this); @@ -975,7 +1023,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { if (aliasMap != null && alias != null) { putAliasMap(aliasMap, alias, null); - subQueryMap.put(alias, x.getSubQuery().getQuery()); + addSubQuery(alias, x.getSubQuery().getQuery()); } } @@ -990,10 +1038,29 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { Map aliasMap = getAliasMap(); if (aliasMap != null && x.getAlias() != null) { putAliasMap(aliasMap, x.getAlias(), null); - subQueryMap.put(x.getAlias(), query); + addSubQuery(x.getAlias(), query); } return false; } + + protected void addSubQuery(String alias, SQLObject query) { + String alias_lcase = alias.toLowerCase(); + subQueryMap.put(alias_lcase, query); + } + + protected SQLObject getSubQuery(String alias) { + String alias_lcase = alias.toLowerCase(); + return subQueryMap.get(alias_lcase); + } + + protected boolean containsSubQuery(String alias) { + if (alias == null) { + return false; + } + + String alias_lcase = alias.toLowerCase(); + return subQueryMap.containsKey(alias_lcase); + } protected boolean isSimpleExprTableSource(SQLExprTableSource x) { return x.getExpr() instanceof SQLName; @@ -1007,7 +1074,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { return false; } - if (subQueryMap.containsKey(ident)) { + if (containsSubQuery(ident)) { return false; } diff --git a/src/main/java/com/alibaba/druid/stat/TableStat.java b/src/main/java/com/alibaba/druid/stat/TableStat.java index a05f4f78d4..e911cf5763 100644 --- a/src/main/java/com/alibaba/druid/stat/TableStat.java +++ b/src/main/java/com/alibaba/druid/stat/TableStat.java @@ -217,6 +217,10 @@ public class TableStat { private Column right; private String operator; + public Relationship(){ + + } + public Column getLeft() { return left; } @@ -394,7 +398,7 @@ public class TableStat { private boolean join; private Map attributes = new HashMap(); - + private transient String fullName; public Column(){ @@ -414,7 +418,7 @@ public class TableStat { this.table = table; this.fullName = null; } - + public String getFullName() { if (fullName == null) { if (table != null) { @@ -423,7 +427,7 @@ public class TableStat { fullName = table + '.' + name; } } - + return fullName; } @@ -501,7 +505,7 @@ public class TableStat { public boolean equals(Object obj) { - if (!(obj instanceof Column)) { + if (!(obj instanceof Column)) { return false; } @@ -532,16 +536,16 @@ public class TableStat { } public static enum Mode { - Insert(1), // - Update(2), // - Delete(4), // - Select(8), // - Merge(16), // - Truncate(32), // - Alter(64), // - Drop(128), // - DropIndex(256), // - CreateIndex(512)// + Insert(1), // + Update(2), // + Delete(4), // + Select(8), // + Merge(16), // + Truncate(32), // + Alter(64), // + Drop(128), // + DropIndex(256), // + CreateIndex(512)// ; // public final int mark; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest54.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest54.java index 15a39e5cff..23b9b3fa42 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest54.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest54.java @@ -125,7 +125,7 @@ public class MySqlCreateTableTest54 extends MysqlTest { + "\n\tPRIMARY KEY (`id`), " + "\n\tKEY `canvas_id` (`canvas_id`), " + "\n\tKEY `sid_ty_time` (`sellerId`, `node_type`, `start_time`), " - + "\n\tCONSTRAINT `t_activity_node_ibfk_1` FOREIGN KEY (`canvas_id`) REFERENCES `t_activity_canvas` (`id`) ON DELETE CASCADE" + + "\n\tCONSTRAINT `t_activity_node_ibfk_1` FOREIGN KEY (`canvas_id`) REFERENCES `t_activity_canvas` (`id`) ON DELETE CASCADE ON UPDATE CASCADE" + "\n) ENGINE = InnoDB CHARSET = utf8", output); } { @@ -157,7 +157,7 @@ public class MySqlCreateTableTest54 extends MysqlTest { + "\n\tprimary key (`id`), " + "\n\tkey `canvas_id` (`canvas_id`), " + "\n\tkey `sid_ty_time` (`sellerId`, `node_type`, `start_time`), " - + "\n\tconstraint `t_activity_node_ibfk_1` foreign key (`canvas_id`) references `t_activity_canvas` (`id`) on delete cascade" + + "\n\tconstraint `t_activity_node_ibfk_1` foreign key (`canvas_id`) references `t_activity_canvas` (`id`) on delete cascade on update cascade" + "\n) engine = InnoDB charset = utf8", output); } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest70.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest70.java new file mode 100644 index 0000000000..fbccad5a31 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateTableTest70.java @@ -0,0 +1,93 @@ +/* + * Copyright 1999-2101 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.mysql; + +import org.junit.Assert; +import org.junit.Test; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; + +public class MySqlCreateTableTest70 extends MysqlTest { + + @Test + public void test_one() throws Exception { + String sql = "CREATE TABLE `app_customer_license` (" + + " `id` bigint(20) NOT NULL AUTO_INCREMENT ," + + " `created_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ," + + " `created_date` datetime NOT NULL ," + + " `last_modified_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ," + + " `last_modified_date` datetime NULL DEFAULT NULL ," + + " `version` bigint(20) NOT NULL ," + + " `device_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ," + + " `customer_info` bigint(20) NULL DEFAULT NULL ," + + " PRIMARY KEY (`id`)," + + " FOREIGN KEY (`customer_info`) REFERENCES `app_customer_info` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT," + + " INDEX `fk_app_customer_info_id` (`customer_info`) USING BTREE," + + " UNIQUE `idx_app_customer_license_deviceId` (`device_id`) USING BTREE" + + ")" + + "ENGINE=InnoDB " + + "DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci " + + "AUTO_INCREMENT=1 " + + "ROW_FORMAT=DYNAMIC " + + ";;"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseCreateTable(); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + { + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("CREATE TABLE `app_customer_license` (" + + "\n\t`id` bigint(20) NOT NULL AUTO_INCREMENT, " + + "\n\t`created_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, " + + "\n\t`created_date` datetime NOT NULL, " + + "\n\t`last_modified_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL, " + + "\n\t`last_modified_date` datetime NULL, " + + "\n\t`version` bigint(20) NOT NULL, " + + "\n\t`device_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, " + + "\n\t`customer_info` bigint(20) NULL, " + + "\n\tPRIMARY KEY (`id`), " + + "\n\tFOREIGN KEY (`customer_info`) REFERENCES `app_customer_info` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, " + + "\n\tINDEX `fk_app_customer_info_id` USING BTREE(`customer_info`), " + + "\n\tUNIQUE `idx_app_customer_license_deviceId` USING BTREE (`device_id`)" + + "\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE utf8_general_ci AUTO_INCREMENT = 1 ROW_FORMAT = DYNAMIC", output); + } + + { + String output = SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION); + Assert.assertEquals("create table `app_customer_license` (" + + "\n\t`id` bigint(20) not null auto_increment, " + + "\n\t`created_by` varchar(50) character set utf8 collate utf8_general_ci not null, " + + "\n\t`created_date` datetime not null, " + + "\n\t`last_modified_by` varchar(50) character set utf8 collate utf8_general_ci null, " + + "\n\t`last_modified_date` datetime null, " + + "\n\t`version` bigint(20) not null, " + + "\n\t`device_id` varchar(20) character set utf8 collate utf8_general_ci not null, " + + "\n\t`customer_info` bigint(20) null, " + + "\n\tprimary key (`id`), " + + "\n\tforeign key (`customer_info`) references `app_customer_info` (`id`) on delete restrict on update restrict, " + + "\n\tindex `fk_app_customer_info_id` using BTREE(`customer_info`), " + + "\n\tunique `idx_app_customer_license_deviceId` using BTREE (`device_id`)" + + "\n) engine = InnoDB character set = utf8 collate utf8_general_ci auto_increment = 1 row_format = DYNAMIC", output); + } + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest1.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest1.java index be14dcde02..08b7fbd50c 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest1.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest1.java @@ -42,6 +42,7 @@ public class OracleSchemaStatVisitorTest1 extends TestCase { System.out.println(sql); System.out.println("Tables : " + visitor.getTables()); System.out.println("fields : " + visitor.getColumns()); + System.out.println("relationShip : " + visitor.getRelationships()); Assert.assertEquals(2, visitor.getTables().size()); Assert.assertEquals(true, visitor.containsTable("users")); @@ -53,6 +54,9 @@ public class OracleSchemaStatVisitorTest1 extends TestCase { Assert.assertEquals(true, visitor.getColumns().contains(new Column("usergroups", "id"))); Assert.assertEquals(true, visitor.getColumns().contains(new Column("usergroups", "name"))); + Assert.assertEquals(1, visitor.getRelationships().size()); + Assert.assertEquals("users.groupId = usergroups.id", visitor.getRelationships().iterator().next().toString()); + } public void test_1() throws Exception { diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest5.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest5.java new file mode 100644 index 0000000000..0fc2a7cd3c --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest5.java @@ -0,0 +1,84 @@ +/* + * Copyright 1999-2101 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.visitor; + +import java.util.List; + +import org.junit.Assert; + +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 com.alibaba.druid.stat.TableStat.Condition; + +import junit.framework.TestCase; + +public class OracleSchemaStatVisitorTest5 extends TestCase { + + public void test_0() throws Exception { + String sql = "SELECT B.OBJ_ID AS BDZID,B.BDZMC,count(A.*) " + + "FROM (" + + " SELECT BDZ " + + " FROM (" + + " SELECT JLZB.OBJ_ID,JLZB.BDZ, JLB.BHSBID, JLB.CLZ " + + " FROM SCYW.T_YJ_DWYJ_YXRZ_CDBHCLJL JLB " + + " INNER JOIN SCYW.T_YJ_DWYJ_YXRZ_YXJLZB JLZB ON JLB.YXJLID = JLZB.OBJ_ID) T " + + " WHERE T.OBJ_ID IN('SYS_B_02','SYS_B_03','SYS_B_04') " + + " AND 'SYS_B_05'='SYS_B_06'" + + ") A, SCYW.T_SB_ZNYC_DZ B " + + "WHERE A.BDZ=B.OBJ_ID " + + " AND B.OBJ_ID IN (" + + " SELECT DZ.OBJ_ID " + + " FROM T_SB_ZNYC_DZ DZ " + + " WHERE DZ.WHBZ = 'SYS_B_07' " + + " OR DZ.OBJ_ID IN (" + + " SELECT ZFBZ.ZFID " + + " FROM T_SB_ZNYC_ZFBZ ZFBZ " + + " WHERE ZFBZ.BZID = 'SYS_B_08' AND ZFBZ.BZLB = 'SYS_B_09'" + + " ) " + + " AND DZ.FBZT = 'SYS_B_10'" + + " ) " + + "GROUP BY B.OBJ_ID,B.BDZMC"; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println(sql); + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("relationShip : " + visitor.getRelationships()); + System.out.println("where : " + visitor.getConditions()); + System.out.println("groupBy : " + visitor.getGroupByColumns()); + + for (Condition condition : visitor.getConditions()) { + String table = condition.getColumn().getTable(); + Assert.assertTrue("table not exists : " + table, visitor.containsTable(table)); + } + + Assert.assertEquals(5, visitor.getTables().size()); + Assert.assertEquals(true, visitor.containsTable("T_SB_ZNYC_ZFBZ")); + + Assert.assertEquals(13, visitor.getColumns().size()); + + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest6.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest6.java new file mode 100644 index 0000000000..4ebcfe99a8 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest6.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2101 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.visitor; + +import java.util.List; + +import org.junit.Assert; +import junit.framework.TestCase; + +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 com.alibaba.druid.stat.TableStat.Column; + +public class OracleSchemaStatVisitorTest6 extends TestCase { + + public void test_0() throws Exception { + String sql = "SELECT 'SYS_B_0',COUNT('$SYS_B_1') AS DEVICECOUNT " + + "FROM (" + + " SELECT OID,SSJG,OID " + + " FROM (" + + " SELECT A.OID,A.SSJG,A.OID " + + " FROM T_TX_ZLSB_ZLDYHGQ A " // + + " WHERE (A.VERSIONID IS NULL OR A.VERSIONID='$SYS_B_2')" + + " ) T1 JOIN (" + + " SELECT B.OID,B.SSJG,B.OID " + + " FROM T_TX_ZLSB_ZLDYHGQ_VER B WHERE B.ADDFLAG<'SYS_B_3'" + + " ) T2 ON T1.OID=T2.OID" + + ") WHERE SSJG='$SYS_B_4'"; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println(sql); + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("relationShip : " + visitor.getRelationships()); + System.out.println("where : " + visitor.getConditions()); + System.out.println("groupBy : " + visitor.getGroupByColumns()); + +// Assert.assertEquals(2, visitor.getTables().size()); +// Assert.assertEquals(true, visitor.containsTable("users")); +// +// Assert.assertEquals(2, visitor.getColumns().size()); +// Assert.assertEquals(true, visitor.getColumns().contains(new Column("users", "id"))); +// Assert.assertEquals(true, visitor.getColumns().contains(new Column("users", "name"))); + + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest7.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest7.java new file mode 100644 index 0000000000..09ebbb4d69 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/visitor/OracleSchemaStatVisitorTest7.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2101 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.visitor; + +import java.util.List; + +import org.junit.Assert; +import junit.framework.TestCase; + +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 com.alibaba.druid.stat.TableStat.Column; + +public class OracleSchemaStatVisitorTest7 extends TestCase { + + public void test_0() throws Exception { + String sql = "SELECT 'SYS_B_0',COUNT('$SYS_B_1') AS DEVICECOUNT " + + "FROM (SELECT A.OID,A.SSJG,A.OID FROM T_TX_ZLSB_ZLDYHGQ A WHERE (A.VERSIONID IS NULL OR A.VERSIONID='$SYS_B_2') UNION ALL SELECT B.OID,B.SSJG,B.OID " + + "FROM T_TX_ZLSB_ZLDYHGQ_VER B WHERE B.ADDFLAG<'SYS_B_3') WHERE SSJG='$SYS_B_4'"; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println(sql); + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("relationShip : " + visitor.getRelationships()); + System.out.println("where : " + visitor.getConditions()); + System.out.println("groupBy : " + visitor.getGroupByColumns()); + +// Assert.assertEquals(2, visitor.getTables().size()); +// Assert.assertEquals(true, visitor.containsTable("users")); +// +// Assert.assertEquals(2, visitor.getColumns().size()); +// Assert.assertEquals(true, visitor.getColumns().contains(new Column("users", "id"))); +// Assert.assertEquals(true, visitor.getColumns().contains(new Column("users", "name"))); + + } + +}