From a60fe4054237f8e6da45a57e3b58d23e2f96ec17 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 29 Dec 2012 16:08:29 +0800 Subject: [PATCH] improve SQL Parser --- .../druid/sql/ast/SQLDataTypeImpl.java | 8 -- .../ast/statement/SQLCharactorDataType.java | 9 ++ .../mysql/visitor/MySqlOutputVisitor.java | 26 ++++- .../oracle/visitor/OracleOutputVisitor.java | 21 ++-- .../druid/sql/parser/SQLExprParser.java | 9 +- .../sql/visitor/SQLASTOutputVisitor.java | 10 +- .../druid/sql/visitor/SQLASTVisitor.java | 5 + .../sql/visitor/SQLASTVisitorAdapter.java | 11 +++ .../sql/oracle/OracleCreateTableTest14.java | 97 +++++++++++++++++++ .../bvt/sql/postgresql/PGFormatTest.java | 10 +- 10 files changed, 174 insertions(+), 32 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleCreateTableTest14.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLDataTypeImpl.java b/src/main/java/com/alibaba/druid/sql/ast/SQLDataTypeImpl.java index 0714ca9f0f..a9232ee75f 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLDataTypeImpl.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLDataTypeImpl.java @@ -46,14 +46,6 @@ public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType { visitor.endVisit(this); } - protected void accept0(OracleASTVisitor visitor) { - if (visitor.visit(this)) { - acceptChild(visitor, this.arguments); - } - - visitor.endVisit(this); - } - public String getName() { return this.name; } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharactorDataType.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharactorDataType.java index b14b1bb3a7..539a1aed3d 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharactorDataType.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharactorDataType.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.ast.statement; import com.alibaba.druid.sql.ast.SQLDataTypeImpl; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; @SuppressWarnings("serial") public class SQLCharactorDataType extends SQLDataTypeImpl { @@ -56,4 +57,12 @@ public class SQLCharactorDataType extends SQLDataTypeImpl { this.charType = charType; } + @Override + protected void accept0(SQLASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, this.arguments); + } + + visitor.endVisit(this); + } } 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 1f5b130752..d62fc7b3f1 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 @@ -335,6 +335,26 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV return false; } + public boolean visit(SQLCharactorDataType x) { + print(x.getName()); + if (x.getArguments().size() > 0) { + print("("); + printAndAccept(x.getArguments(), ", "); + print(")"); + } + + if (x.getCharSetName() != null) { + print(" CHARACTER SET "); + print(x.getCharSetName()); + + if (x.getCollate() != null) { + print(" COLLATE "); + print(x.getCollate()); + } + } + return false; + } + @Override public void endVisit(Limit x) { @@ -489,13 +509,13 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV public boolean visit(SQLCharExpr x) { print('\''); - + String text = x.getText(); text = text.replaceAll("'", "''"); text = text.replaceAll("\\\\", "\\\\"); - + print(text); - + print('\''); return false; } 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 8411d2cbf7..07a611c768 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 @@ -17,7 +17,6 @@ package com.alibaba.druid.sql.dialect.oracle.visitor; import java.util.List; -import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLHint; import com.alibaba.druid.sql.ast.SQLName; @@ -31,6 +30,7 @@ import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLObjectCreateExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; +import com.alibaba.druid.sql.ast.statement.SQLCharactorDataType; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; @@ -887,11 +887,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } - @Override - public void endVisit(SQLDataType x) { - - } - @Override public void endVisit(OracleDateExpr x) { @@ -3098,4 +3093,18 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS public void endVisit(OracleDropDatabaseLinkStatement x) { } + + public boolean visit(SQLCharactorDataType x) { + print(x.getName()); + if (x.getArguments().size() > 0) { + print("("); + x.getArguments().get(0).accept(this); + if (x.getCharType() != null) { + print(' '); + print(x.getCharType()); + } + print(")"); + } + return false; + } } 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 6fbb3196c7..87cfc8a251 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1175,14 +1175,7 @@ public class SQLExprParser extends SQLParser { ; } - protected SQLDataType parseCharTypeRest(SQLDataType dataType) { - if (!isCharType(dataType.getName())) { - return dataType; - } - - SQLCharactorDataType charType = new SQLCharactorDataType(dataType.getName()); - charType.getArguments().addAll(dataType.getArguments()); - + protected SQLDataType parseCharTypeRest(SQLCharactorDataType charType) { if (identifierEquals("CHARACTER")) { lexer.nextToken(); 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 74551b2cd4..fce978eb6b 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -71,6 +71,7 @@ import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropIndex; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLCallStatement; +import com.alibaba.druid.sql.ast.statement.SQLCharactorDataType; import com.alibaba.druid.sql.ast.statement.SQLColumnConstraint; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLColumnPrimaryKey; @@ -422,7 +423,12 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { printAndAccept(x.getArguments(), ", "); print(")"); } - + + return false; + } + + public boolean visit(SQLCharactorDataType x) { + visit((SQLDataType) x); return false; } @@ -904,7 +910,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { println(); for (int i = 0; i < size; ++i) { if (i != 0) { - print(", "); + print(","); println(); } x.getTableElementList().get(i).accept(this); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java index 1cbbf09cab..2f00b9d368 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java @@ -59,6 +59,7 @@ import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropIndex; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLCallStatement; +import com.alibaba.druid.sql.ast.statement.SQLCharactorDataType; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLColumnPrimaryKey; import com.alibaba.druid.sql.ast.statement.SQLColumnUniqueIndex; @@ -250,6 +251,10 @@ public interface SQLASTVisitor { boolean visit(SQLDataType x); void endVisit(SQLDataType x); + + boolean visit(SQLCharactorDataType x); + + void endVisit(SQLCharactorDataType x); boolean visit(SQLDeleteStatement x); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java index fd3b363f7d..dcdfe83975 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java @@ -59,6 +59,7 @@ import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropIndex; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLCallStatement; +import com.alibaba.druid.sql.ast.statement.SQLCharactorDataType; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLColumnPrimaryKey; import com.alibaba.druid.sql.ast.statement.SQLColumnUniqueIndex; @@ -754,4 +755,14 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor { public boolean visit(SQLWithSubqueryClause.Entry x) { return true; } + + @Override + public boolean visit(SQLCharactorDataType x) { + return true; + } + + @Override + public void endVisit(SQLCharactorDataType x) { + + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleCreateTableTest14.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleCreateTableTest14.java new file mode 100644 index 0000000000..5cefb5daeb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleCreateTableTest14.java @@ -0,0 +1,97 @@ +/* + * Copyright 1999-2011 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; + +import java.util.List; + +import junit.framework.Assert; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.SQLUtils; +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; +import com.alibaba.druid.util.JdbcConstants; + +public class OracleCreateTableTest14 extends OracleTest { + + public void test_charTypes() throws Exception { + String sql = // + "create table T (" + // + "F1 CHAR(1)," + // + "F2 CHAR(1 BYTE)," + // + "F3 CHAR(1 CHAR)," + // + "F4 VARCHAR2(2)," + // + "F5 VARCHAR2(2 BYTE)," + // + "F6 VARCHAR2(2 CHAR)," + // + "F7 NCHAR(3 BYTE), " + // + "F8 NCHAR(3 CHAR), " + // + "F9 NCHAR(3), " + // + "F10 NVARCHAR2(4), " + // + "F11 NVARCHAR2(4 BYTE), " + // + "F12 NVARCHAR2(4 CHAR) " + // + ") "; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statement = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + Assert.assertEquals( "CREATE TABLE T (" + // + "\n\tF1 CHAR(1)," + // + "\n\tF2 CHAR(1 BYTE)," + // + "\n\tF3 CHAR(1 CHAR)," + // + "\n\tF4 VARCHAR2(2)," + // + "\n\tF5 VARCHAR2(2 BYTE)," + // + "\n\tF6 VARCHAR2(2 CHAR)," + // + "\n\tF7 NCHAR(3 BYTE)," + // + "\n\tF8 NCHAR(3 CHAR)," + // + "\n\tF9 NCHAR(3)," + // + "\n\tF10 NVARCHAR2(4)," + // + "\n\tF11 NVARCHAR2(4 BYTE)," + // + "\n\tF12 NVARCHAR2(4 CHAR)" + // + "\n)", SQLUtils.toSQLString(statement, JdbcConstants.ORACLE)); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + statement.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("relationships : " + visitor.getRelationships()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + Assert.assertEquals(1, visitor.getTables().size()); + + Assert.assertEquals(12, visitor.getColumns().size()); + + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F1"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F2"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F3"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F4"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F5"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F6"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F7"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F8"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F9"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F10"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F11"))); + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("T", "F12"))); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGFormatTest.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGFormatTest.java index 927353ace3..a129c2d58c 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGFormatTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGFormatTest.java @@ -26,10 +26,10 @@ public class PGFormatTest extends TestCase { public void test_0() throws Exception { String sql = "CREATE TABLE foo (fooid int, foosubid int, fooname text);"; String formatedSql = SQLUtils.format(sql, JdbcUtils.POSTGRESQL); - Assert.assertEquals("CREATE TABLE foo (\n" + // - "\tfooid int, \n" + // - "\tfoosubid int, \n" + // - "\tfooname text\n" + // - ")", formatedSql); + Assert.assertEquals("CREATE TABLE foo (" + // + "\n\tfooid int," + // + "\n\tfoosubid int," + // + "\n\tfooname text" + // + "\n)", formatedSql); } }