From 19501d678d2e9a09e19d471b4e54b541f91e907e Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 10 Sep 2017 16:11:19 +0800 Subject: [PATCH] imporved sql parser. improved h2 support. for issue #1941 #1942 --- .../java/com/alibaba/druid/sql/SQLUtils.java | 20 +- .../com/alibaba/druid/sql/ast/SQLKeep.java | 2 +- .../com/alibaba/druid/sql/ast/SQLLimit.java | 2 +- .../com/alibaba/druid/sql/ast/SQLOrderBy.java | 2 +- .../alibaba/druid/sql/ast/SQLParameter.java | 2 +- .../druid/sql/ast/expr/SQLAllColumnExpr.java | 2 +- .../druid/sql/ast/expr/SQLAllExpr.java | 2 +- .../druid/sql/ast/expr/SQLBooleanExpr.java | 2 +- .../druid/sql/ast/expr/SQLExistsExpr.java | 2 +- .../druid/sql/ast/expr/SQLIdentifierExpr.java | 2 +- .../druid/sql/ast/expr/SQLInListExpr.java | 2 +- .../druid/sql/ast/expr/SQLNotExpr.java | 2 +- .../druid/sql/ast/expr/SQLNullExpr.java | 2 +- .../druid/sql/ast/expr/SQLPropertyExpr.java | 2 +- .../druid/sql/ast/expr/SQLSomeExpr.java | 2 +- .../statement/SQLCreateTriggerStatement.java | 11 +- .../statement/SQLReplaceStatement.java} | 209 ++++++++---------- .../ast/statement/SQLSelectOrderByItem.java | 2 +- .../sql/dialect/h2/ast/H2MergeStatement.java | 33 +++ .../sql/dialect/h2/parser/H2ExprParser.java | 41 ++++ .../druid/sql/dialect/h2/parser/H2Lexer.java | 42 ++++ .../sql/dialect/h2/parser/H2SelectParser.java | 19 ++ .../dialect/h2/parser/H2StatementParser.java | 61 +++++ .../sql/dialect/h2/visitor/H2ASTVisitor.java | 6 + .../h2/visitor/H2ASTVisitorAdapter.java | 6 + .../sql/dialect/h2/visitor/H2EvalVisitor.java | 120 ++++++++++ .../dialect/h2/visitor/H2OutputVisitor.java | 67 ++++++ .../h2/visitor/H2SchemaStatVisitor.java | 6 + .../mysql/parser/MySqlStatementParser.java | 95 +------- .../mysql/visitor/MySqlASTVisitor.java | 4 - .../mysql/visitor/MySqlASTVisitorAdapter.java | 11 - .../mysql/visitor/MySqlOutputVisitor.java | 69 +++--- .../mysql/visitor/MySqlSchemaStatVisitor.java | 29 --- .../oracle/visitor/OracleOutputVisitor.java | 10 +- .../druid/sql/parser/SQLParserUtils.java | 3 +- .../druid/sql/parser/SQLStatementParser.java | 92 +++++++- .../SchemaResolveVisitorFactory.java | 43 ++-- .../sql/visitor/SQLASTOutputVisitor.java | 46 ++-- .../druid/sql/visitor/SQLASTVisitor.java | 8 +- .../sql/visitor/SQLASTVisitorAdapter.java | 12 +- .../druid/sql/visitor/SchemaStatVisitor.java | 25 +++ .../druid/wall/spi/MySqlWallVisitor.java | 6 - .../druid/wall/spi/WallVisitorUtils.java | 4 +- .../benckmark/sql/StatementConverter.java | 7 +- .../bvt/sql/h2/H2_CreateTriggerTest_0.java | 71 ++++++ .../druid/bvt/sql/h2/H2_MergeTest_0.java | 70 ++++++ .../sql/mysql/MySqlASTVisitorAdapterTest.java | 4 +- .../druid/bvt/sql/mysql/param/ParseUtil.java | 3 +- .../create/OracleCreateTriggerTest.java | 2 +- .../create/OracleCreateTriggerTest2.java | 2 +- .../create/OracleCreateTriggerTest3.java | 2 +- .../OracleSelectTest82_wmsysconcat.java | 3 + 52 files changed, 922 insertions(+), 370 deletions(-) rename src/main/java/com/alibaba/druid/sql/{dialect/mysql/ast/statement/MySqlReplaceStatement.java => ast/statement/SQLReplaceStatement.java} (54%) create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/ast/H2MergeStatement.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2ExprParser.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2Lexer.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2SelectParser.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2StatementParser.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2ASTVisitor.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2ASTVisitorAdapter.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2EvalVisitor.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2OutputVisitor.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2SchemaStatVisitor.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/h2/H2_CreateTriggerTest_0.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/h2/H2_MergeTest_0.java diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index beb1e4e0da..d80f92dddd 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -23,6 +23,7 @@ import com.alibaba.druid.sql.ast.expr.*; import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.dialect.db2.visitor.DB2OutputVisitor; import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor; +import com.alibaba.druid.sql.dialect.h2.visitor.H2OutputVisitor; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; import com.alibaba.druid.sql.dialect.odps.visitor.OdpsOutputVisitor; @@ -43,6 +44,11 @@ import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.*; public class SQLUtils { + private final static SQLParserFeature[] FORMAT_DEFAULT_FEATURES = { + SQLParserFeature.KeepComments, + SQLParserFeature.EnableSQLBinaryOpExprGroup + }; + public static FormatOption DEFAULT_FORMAT_OPTION = new FormatOption(true, true); public static FormatOption DEFAULT_LCASE_FORMAT_OPTION = new FormatOption(false, true); @@ -234,13 +240,8 @@ public class SQLUtils { public static String format(String sql, String dbType, List parameters, FormatOption option) { try { - SQLParserFeature[] features = {SQLParserFeature.KeepComments, SQLParserFeature.EnableSQLBinaryOpExprGroup}; - - SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType, features); - parser.setKeepComments(true); - + SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType, FORMAT_DEFAULT_FEATURES); List statementList = parser.parseStatementList(); - return toSQLString(statementList, dbType, parameters, option); } catch (ParserException ex) { LOG.warn("format error", ex); @@ -363,8 +364,7 @@ public class SQLUtils { } if (JdbcConstants.MYSQL.equals(dbType) // - || JdbcConstants.MARIADB.equals(dbType) // - || JdbcConstants.H2.equals(dbType)) { + || JdbcConstants.MARIADB.equals(dbType)) { return new MySqlOutputVisitor(out); } @@ -384,6 +384,10 @@ public class SQLUtils { return new OdpsOutputVisitor(out); } + if (JdbcConstants.H2.equals(dbType)) { + return new H2OutputVisitor(out); + } + return new SQLASTOutputVisitor(out, dbType); } diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLKeep.java b/src/main/java/com/alibaba/druid/sql/ast/SQLKeep.java index 920b940326..935d4596c8 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLKeep.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLKeep.java @@ -17,7 +17,7 @@ package com.alibaba.druid.sql.ast; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLKeep extends SQLObjectImpl { +public final class SQLKeep extends SQLObjectImpl { protected DenseRank denseRank; diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLLimit.java b/src/main/java/com/alibaba/druid/sql/ast/SQLLimit.java index 5259be4807..975dd77a84 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLLimit.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLLimit.java @@ -23,7 +23,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; /** * Created by wenshao on 16/9/25. */ -public class SQLLimit extends SQLObjectImpl { +public final class SQLLimit extends SQLObjectImpl { public SQLLimit() { diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java b/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java index 071fc10047..be16a3dd8a 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java @@ -21,7 +21,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; import java.util.ArrayList; import java.util.List; -public class SQLOrderBy extends SQLObjectImpl { +public final class SQLOrderBy extends SQLObjectImpl { protected final List items = new ArrayList(); diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLParameter.java b/src/main/java/com/alibaba/druid/sql/ast/SQLParameter.java index 3248043b01..d18be27146 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLParameter.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLParameter.java @@ -20,7 +20,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; import java.util.ArrayList; import java.util.List; -public class SQLParameter extends SQLObjectImpl implements SQLObjectWithDataType { +public final class SQLParameter extends SQLObjectImpl implements SQLObjectWithDataType { private SQLName name; private SQLDataType dataType; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAllColumnExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAllColumnExpr.java index 473faa28b0..7472f02cb4 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAllColumnExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAllColumnExpr.java @@ -19,7 +19,7 @@ import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLAllColumnExpr extends SQLExprImpl { +public final class SQLAllColumnExpr extends SQLExprImpl { private transient SQLTableSource resolvedTableSource; public SQLAllColumnExpr(){ diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAllExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAllExpr.java index 8976974bed..2dad15903e 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAllExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAllExpr.java @@ -19,7 +19,7 @@ import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLAllExpr extends SQLExprImpl { +public final class SQLAllExpr extends SQLExprImpl { public SQLSelect subQuery; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBooleanExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBooleanExpr.java index cd1e32f4f5..349e0d86fe 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBooleanExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBooleanExpr.java @@ -21,7 +21,7 @@ import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLBooleanExpr extends SQLExprImpl implements SQLExpr, SQLLiteralExpr, SQLValuableExpr { +public final class SQLBooleanExpr extends SQLExprImpl implements SQLExpr, SQLLiteralExpr, SQLValuableExpr { public static final SQLDataType DEFAULT_DATA_TYPE = new SQLCharacterDataType("boolean"); private boolean value; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLExistsExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLExistsExpr.java index 26d4d95746..645f65dc6a 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLExistsExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLExistsExpr.java @@ -21,7 +21,7 @@ import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLExistsExpr extends SQLExprImpl implements Serializable { +public final class SQLExistsExpr extends SQLExprImpl implements Serializable { private static final long serialVersionUID = 1L; public boolean not = false; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java index 07ca9a4e95..1910778eb6 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java @@ -21,7 +21,7 @@ import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.visitor.SQLASTVisitor; import com.alibaba.druid.util.FnvHash; -public class SQLIdentifierExpr extends SQLExprImpl implements SQLName { +public final class SQLIdentifierExpr extends SQLExprImpl implements SQLName { protected String name; private long hashCode64; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInListExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInListExpr.java index c59a0a7b57..9816152cc2 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInListExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInListExpr.java @@ -24,7 +24,7 @@ import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLInListExpr extends SQLExprImpl implements Serializable { +public final class SQLInListExpr extends SQLExprImpl implements Serializable { private static final long serialVersionUID = 1L; private boolean not = false; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNotExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNotExpr.java index 11020796cc..97c5c7e6fa 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNotExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNotExpr.java @@ -22,7 +22,7 @@ import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLNotExpr extends SQLExprImpl implements Serializable { +public final class SQLNotExpr extends SQLExprImpl implements Serializable { private static final long serialVersionUID = 1L; public SQLExpr expr; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNullExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNullExpr.java index f6dfeba62a..c196496c3d 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNullExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNullExpr.java @@ -20,7 +20,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; import static com.alibaba.druid.sql.visitor.SQLEvalVisitor.EVAL_VALUE_NULL; -public class SQLNullExpr extends SQLExprImpl implements SQLLiteralExpr, SQLValuableExpr { +public final class SQLNullExpr extends SQLExprImpl implements SQLLiteralExpr, SQLValuableExpr { public SQLNullExpr(){ diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java index 757f249f34..97e54d09c5 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java @@ -21,7 +21,7 @@ import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.visitor.SQLASTVisitor; import com.alibaba.druid.util.FnvHash; -public class SQLPropertyExpr extends SQLExprImpl implements SQLName { +public final class SQLPropertyExpr extends SQLExprImpl implements SQLName { private SQLExpr owner; private String name; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSomeExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSomeExpr.java index ffa00823ec..c00fe8e493 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSomeExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSomeExpr.java @@ -24,7 +24,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; import java.util.List; -public class SQLSomeExpr extends SQLExprImpl { +public final class SQLSomeExpr extends SQLExprImpl { public SQLSelect subQuery; diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTriggerStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTriggerStatement.java index 084403604f..0ba042ea77 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTriggerStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTriggerStatement.java @@ -36,7 +36,7 @@ public class SQLCreateTriggerStatement extends SQLStatementImpl implements SQLCr private boolean delete; private boolean insert; - private SQLName on; + private SQLExprTableSource on; private boolean forEachRow = false; @@ -64,11 +64,18 @@ public class SQLCreateTriggerStatement extends SQLStatementImpl implements SQLCr visitor.endVisit(this); } - public SQLName getOn() { + public SQLExprTableSource getOn() { return on; } public void setOn(SQLName on) { + this.setOn(new SQLExprTableSource(on)); + } + + public void setOn(SQLExprTableSource on) { + if (on != null) { + on.setParent(this); + } this.on = on; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplaceStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLReplaceStatement.java similarity index 54% rename from src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplaceStatement.java rename to src/main/java/com/alibaba/druid/sql/ast/statement/SQLReplaceStatement.java index d7dc2abb77..92b39dbd53 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlReplaceStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLReplaceStatement.java @@ -1,112 +1,97 @@ -/* - * 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.sql.dialect.mysql.ast.statement; - -import java.util.ArrayList; -import java.util.List; - -import com.alibaba.druid.sql.ast.SQLExpr; -import com.alibaba.druid.sql.ast.SQLName; -import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; -import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; -import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; -import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; - -public class MySqlReplaceStatement extends MySqlStatementImpl { - - private boolean lowPriority = false; - private boolean delayed = false; - - private SQLExprTableSource tableSource; - private final List columns = new ArrayList(); - private List valuesList = new ArrayList(); - private SQLQueryExpr query; - - public SQLName getTableName() { - if (tableSource == null) { - return null; - } - - return (SQLName) tableSource.getExpr(); - } - - public void setTableName(SQLName tableName) { - this.setTableSource(new SQLExprTableSource(tableName)); - } - - public SQLExprTableSource getTableSource() { - return tableSource; - } - - public void setTableSource(SQLExprTableSource tableSource) { - if (tableSource != null) { - tableSource.setParent(this); - } - this.tableSource = tableSource; - } - - public List getColumns() { - return columns; - } - - public void addColumn(SQLExpr column) { - if (column != null) { - column.setParent(this); - } - this.columns.add(column); - } - - public boolean isLowPriority() { - return lowPriority; - } - - public void setLowPriority(boolean lowPriority) { - this.lowPriority = lowPriority; - } - - public boolean isDelayed() { - return delayed; - } - - public void setDelayed(boolean delayed) { - this.delayed = delayed; - } - - public SQLQueryExpr getQuery() { - return query; - } - - public void setQuery(SQLQueryExpr query) { - if (query != null) { - query.setParent(this); - } - this.query = query; - } - - public List getValuesList() { - return valuesList; - } - - public void accept0(MySqlASTVisitor visitor) { - if (visitor.visit(this)) { - acceptChild(visitor, tableSource); - acceptChild(visitor, columns); - acceptChild(visitor, valuesList); - acceptChild(visitor, query); - } - visitor.endVisit(this); - } -} +package com.alibaba.druid.sql.ast.statement; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLStatementImpl; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +import java.util.ArrayList; +import java.util.List; + +public class SQLReplaceStatement extends SQLStatementImpl { + protected boolean lowPriority = false; + protected boolean delayed = false; + + protected SQLExprTableSource tableSource; + protected final List columns = new ArrayList(); + protected List valuesList = new ArrayList(); + protected SQLQueryExpr query; + + + public SQLName getTableName() { + if (tableSource == null) { + return null; + } + + return (SQLName) tableSource.getExpr(); + } + + public void setTableName(SQLName tableName) { + this.setTableSource(new SQLExprTableSource(tableName)); + } + + public SQLExprTableSource getTableSource() { + return tableSource; + } + + public void setTableSource(SQLExprTableSource tableSource) { + if (tableSource != null) { + tableSource.setParent(this); + } + this.tableSource = tableSource; + } + + public List getColumns() { + return columns; + } + + public void addColumn(SQLExpr column) { + if (column != null) { + column.setParent(this); + } + this.columns.add(column); + } + + public boolean isLowPriority() { + return lowPriority; + } + + public void setLowPriority(boolean lowPriority) { + this.lowPriority = lowPriority; + } + + public boolean isDelayed() { + return delayed; + } + + public void setDelayed(boolean delayed) { + this.delayed = delayed; + } + + public SQLQueryExpr getQuery() { + return query; + } + + public void setQuery(SQLQueryExpr query) { + if (query != null) { + query.setParent(this); + } + this.query = query; + } + + public List getValuesList() { + return valuesList; + } + + @Override + protected void accept0(SQLASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, tableSource); + acceptChild(visitor, columns); + acceptChild(visitor, valuesList); + acceptChild(visitor, query); + } + visitor.endVisit(this); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java index ac58ffb658..0518f5974f 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java @@ -21,7 +21,7 @@ import com.alibaba.druid.sql.ast.SQLOrderingSpecification; import com.alibaba.druid.sql.ast.SQLReplaceable; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLSelectOrderByItem extends SQLObjectImpl implements SQLReplaceable { +public final class SQLSelectOrderByItem extends SQLObjectImpl implements SQLReplaceable { protected SQLExpr expr; protected String collate; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/ast/H2MergeStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/ast/H2MergeStatement.java new file mode 100644 index 0000000000..1817905004 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/ast/H2MergeStatement.java @@ -0,0 +1,33 @@ +package com.alibaba.druid.sql.dialect.h2.ast; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLStatementImpl; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; + +import java.util.ArrayList; +import java.util.List; + +public class H2MergeStatement extends SQLStatementImpl { + private SQLExprTableSource table; + + private final List keyColumns = new ArrayList(); + + public SQLExprTableSource getTable() { + return table; + } + + public void setTable(SQLName table) { + this.setTable(new SQLExprTableSource(table)); + } + + public void setTable(SQLExprTableSource table) { + if (table != null) { + table.setParent(this); + } + this.table = table; + } + + public List getKeyColumns() { + return keyColumns; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2ExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2ExprParser.java new file mode 100644 index 0000000000..d1c0ae3a84 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2ExprParser.java @@ -0,0 +1,41 @@ +package com.alibaba.druid.sql.dialect.h2.parser; + +import com.alibaba.druid.sql.parser.Lexer; +import com.alibaba.druid.sql.parser.SQLExprParser; +import com.alibaba.druid.sql.parser.SQLParserFeature; +import com.alibaba.druid.util.FnvHash; + +import java.util.Arrays; + +public class H2ExprParser extends SQLExprParser { + private final static String[] AGGREGATE_FUNCTIONS; + private final static long[] AGGREGATE_FUNCTIONS_CODES; + + static { + String[] strings = { "AVG", "COUNT", "MAX", "MIN", "STDDEV", "SUM", "ROW_NUMBER", + "ROWNUMBER" }; + AGGREGATE_FUNCTIONS_CODES = FnvHash.fnv1a_64_lower(strings, true); + AGGREGATE_FUNCTIONS = new String[AGGREGATE_FUNCTIONS_CODES.length]; + for (String str : strings) { + long hash = FnvHash.fnv1a_64_lower(str); + int index = Arrays.binarySearch(AGGREGATE_FUNCTIONS_CODES, hash); + AGGREGATE_FUNCTIONS[index] = str; + } + } + + public H2ExprParser(String sql){ + this(new H2Lexer(sql)); + this.lexer.nextToken(); + } + + public H2ExprParser(String sql, SQLParserFeature... features){ + this(new H2Lexer(sql, features)); + this.lexer.nextToken(); + } + + public H2ExprParser(Lexer lexer){ + super(lexer); + this.aggregateFunctions = AGGREGATE_FUNCTIONS; + this.aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2Lexer.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2Lexer.java new file mode 100644 index 0000000000..4605f6a5c5 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2Lexer.java @@ -0,0 +1,42 @@ +package com.alibaba.druid.sql.dialect.h2.parser; + +import com.alibaba.druid.sql.parser.Keywords; +import com.alibaba.druid.sql.parser.Lexer; +import com.alibaba.druid.sql.parser.SQLParserFeature; +import com.alibaba.druid.sql.parser.Token; + +import java.util.HashMap; +import java.util.Map; + +public class H2Lexer extends Lexer { + public final static Keywords DEFAULT_H2_KEYWORDS; + + static { + Map map = new HashMap(); + + map.putAll(Keywords.DEFAULT_KEYWORDS.getKeywords()); + + map.put("OF", Token.OF); + map.put("CONCAT", Token.CONCAT); + map.put("CONTINUE", Token.CONTINUE); + map.put("MERGE", Token.MERGE); + map.put("USING", Token.USING); + + map.put("ROW", Token.ROW); + + DEFAULT_H2_KEYWORDS = new Keywords(map); + } + + public H2Lexer(String input){ + super(input); + super.keywods = DEFAULT_H2_KEYWORDS; + } + + public H2Lexer(String input, SQLParserFeature... features){ + super(input); + super.keywods = DEFAULT_H2_KEYWORDS; + for (SQLParserFeature feature : features) { + config(feature, true); + } + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2SelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2SelectParser.java new file mode 100644 index 0000000000..762661a4e3 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2SelectParser.java @@ -0,0 +1,19 @@ +package com.alibaba.druid.sql.dialect.h2.parser; + +import com.alibaba.druid.sql.parser.SQLExprParser; +import com.alibaba.druid.sql.parser.SQLSelectParser; + +public class H2SelectParser extends SQLSelectParser { + + public H2SelectParser(SQLExprParser exprParser){ + super(exprParser); + } + + public H2SelectParser(String sql){ + this(new H2ExprParser(sql)); + } + + protected SQLExprParser createExprParser() { + return new H2ExprParser(lexer); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2StatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2StatementParser.java new file mode 100644 index 0000000000..9130ba7b25 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/parser/H2StatementParser.java @@ -0,0 +1,61 @@ +package com.alibaba.druid.sql.dialect.h2.parser; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLReplaceStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.dialect.h2.ast.H2MergeStatement; +import com.alibaba.druid.sql.parser.*; +import com.alibaba.druid.util.FnvHash; + +public class H2StatementParser extends SQLStatementParser { + public H2StatementParser(String sql) { + super (new H2ExprParser(sql)); + } + + public H2StatementParser(String sql, SQLParserFeature... features) { + super (new H2ExprParser(sql, features)); + } + + public H2StatementParser(Lexer lexer){ + super(new H2ExprParser(lexer)); + } + + public H2SelectParser createSQLSelectParser() { + return new H2SelectParser(this.exprParser); + } + + public SQLStatement parseMerge() { + accept(Token.MERGE); + accept(Token.INTO); + + SQLReplaceStatement stmt = new SQLReplaceStatement(); + + SQLName tableName = exprParser.name(); + stmt.setTableName(tableName); + + if (lexer.token() == Token.KEY) { + lexer.nextToken(); + accept(Token.LPAREN); + this.exprParser.exprList(stmt.getColumns(), stmt); + accept(Token.RPAREN); + } + + if (lexer.token() == Token.VALUES || lexer.identifierEquals("VALUE")) { + lexer.nextToken(); + + parseValueClause(stmt.getValuesList(), 0, stmt); + } else if (lexer.token() == Token.SELECT) { + SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); + stmt.setQuery(queryExpr); + } else if (lexer.token() == Token.LPAREN) { + SQLSelect select = this.createSQLSelectParser().select(); + SQLQueryExpr queryExpr = new SQLQueryExpr(select); + stmt.setQuery(queryExpr); + } + + return stmt; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2ASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2ASTVisitor.java new file mode 100644 index 0000000000..8bcde2ef58 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2ASTVisitor.java @@ -0,0 +1,6 @@ +package com.alibaba.druid.sql.dialect.h2.visitor; + +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public interface H2ASTVisitor extends SQLASTVisitor { +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2ASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2ASTVisitorAdapter.java new file mode 100644 index 0000000000..f47e5d9817 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2ASTVisitorAdapter.java @@ -0,0 +1,6 @@ +package com.alibaba.druid.sql.dialect.h2.visitor; + +import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter; + +public class H2ASTVisitorAdapter extends SQLASTVisitorAdapter implements H2ASTVisitor { +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2EvalVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2EvalVisitor.java new file mode 100644 index 0000000000..3da27b6c5d --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2EvalVisitor.java @@ -0,0 +1,120 @@ +package com.alibaba.druid.sql.dialect.h2.visitor; + +import com.alibaba.druid.sql.ast.expr.*; +import com.alibaba.druid.sql.visitor.SQLEvalVisitor; +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.sql.visitor.functions.Function; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class H2EvalVisitor extends H2ASTVisitorAdapter implements SQLEvalVisitor { + private Map functions = new HashMap(); + private List parameters = new ArrayList(); + + private int variantIndex = -1; + + private boolean markVariantIndex = true; + + public H2EvalVisitor(){ + this(new ArrayList(1)); + } + + public H2EvalVisitor(List parameters){ + this.parameters = parameters; + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public boolean visit(SQLCharExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public int incrementAndGetVariantIndex() { + return ++variantIndex; + } + + public int getVariantIndex() { + return variantIndex; + } + + public boolean visit(SQLVariantRefExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLBinaryOpExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLUnaryExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLIntegerExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLNumberExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLCaseExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLInListExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLNullExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLMethodInvokeExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLQueryExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean isMarkVariantIndex() { + return markVariantIndex; + } + + public void setMarkVariantIndex(boolean markVariantIndex) { + this.markVariantIndex = markVariantIndex; + } + + @Override + public Function getFunction(String funcName) { + return functions.get(funcName); + } + + @Override + public void registerFunction(String funcName, Function function) { + functions.put(funcName, function); + } + + @Override + public void unregisterFunction(String funcName) { + functions.remove(funcName); + } + + public boolean visit(SQLIdentifierExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2OutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2OutputVisitor.java new file mode 100644 index 0000000000..8b6e020720 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2OutputVisitor.java @@ -0,0 +1,67 @@ +package com.alibaba.druid.sql.dialect.h2.visitor; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLReplaceStatement; +import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; + +import java.util.List; + +public class H2OutputVisitor extends SQLASTOutputVisitor implements H2ASTVisitor { + public H2OutputVisitor(Appendable appender) { + super(appender); + } + + public H2OutputVisitor(Appendable appender, String dbType) { + super(appender, dbType); + } + + public H2OutputVisitor(Appendable appender, boolean parameterized) { + super(appender, parameterized); + } + + public boolean visit(SQLReplaceStatement x) { + print0(ucase ? "MERGE INTO " : "merge into "); + + printTableSourceExpr(x.getTableName()); + + List columns = x.getColumns(); + if (columns.size() > 0) { + print0(ucase ? " KEY (" : " key ("); + for (int i = 0, size = columns.size(); i < size; ++i) { + if (i != 0) { + print0(", "); + } + + SQLExpr columnn = columns.get(i); + printExpr(columnn); + } + print(')'); + } + + List valuesClauseList = x.getValuesList(); + if (valuesClauseList.size() != 0) { + println(); + print0(ucase ? "VALUES " : "values "); + int size = valuesClauseList.size(); + if (size == 0) { + print0("()"); + } else { + for (int i = 0; i < size; ++i) { + if (i != 0) { + print0(", "); + } + visit(valuesClauseList.get(i)); + } + } + } + + SQLQueryExpr query = x.getQuery(); + if (query != null) { + visit(query); + } + + return false; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2SchemaStatVisitor.java new file mode 100644 index 0000000000..83aeb4960d --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/h2/visitor/H2SchemaStatVisitor.java @@ -0,0 +1,6 @@ +package com.alibaba.druid.sql.dialect.h2.visitor; + +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; + +public class H2SchemaStatVisitor extends SchemaStatVisitor implements H2ASTVisitor { +} 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 61091fcd68..5b1b046179 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 @@ -504,7 +504,7 @@ public class MySqlStatementParser extends SQLStatementParser { } if (lexer.token() == Token.REPLACE) { - MySqlReplaceStatement stmt = parseReplicate(); + SQLReplaceStatement stmt = parseReplace(); statementList.add(stmt); return true; } @@ -1773,8 +1773,8 @@ public class MySqlStatementParser extends SQLStatementParser { return stmt; } - public MySqlReplaceStatement parseReplicate() { - MySqlReplaceStatement stmt = new MySqlReplaceStatement(); + public SQLReplaceStatement parseReplace() { + SQLReplaceStatement stmt = new SQLReplaceStatement(); accept(Token.REPLACE); @@ -2262,95 +2262,6 @@ public class MySqlStatementParser extends SQLStatementParser { return insertStatement; } - private void parseValueClause(List valueClauseList, int columnSize, SQLObject parent) { - for (int i = 0; ; ++i) { - int startPos = lexer.pos() - 1; - - if (lexer.token() != Token.LPAREN) { - throw new ParserException("syntax error, expect ')', " + lexer.info()); - } - lexer.nextTokenValue(); - - if (lexer.token() != Token.RPAREN) { - List valueExprList; - if (columnSize > 0) { - valueExprList = new ArrayList(columnSize); - } else { - valueExprList = new ArrayList(); - } - - for (; ; ) { - SQLExpr expr; - if (lexer.token() == Token.LITERAL_INT) { - expr = new SQLIntegerExpr(lexer.integerValue()); - lexer.nextTokenComma(); - } else if (lexer.token() == Token.LITERAL_CHARS) { - expr = new SQLCharExpr(lexer.stringVal()); - lexer.nextTokenComma(); - } else if (lexer.token() == Token.LITERAL_NCHARS) { - expr = new SQLNCharExpr(lexer.stringVal()); - lexer.nextTokenComma(); - } else { - expr = exprParser.expr(); - } - - if (lexer.token() == Token.COMMA) { - valueExprList.add(expr); - lexer.nextTokenValue(); - continue; - } else if (lexer.token() == Token.RPAREN) { - valueExprList.add(expr); - break; - } else { - expr = this.exprParser.primaryRest(expr); - if (lexer.token() != Token.COMMA && lexer.token() != Token.RPAREN) { - expr = this.exprParser.exprRest(expr); - } - - valueExprList.add(expr); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } else { - break; - } - } - } - - SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(valueExprList); - values.setParent(parent); - - if (lexer.isEnabled(SQLParserFeature.KeepInsertValueClauseOriginalString)) { - int endPos = lexer.pos(); - String orginalString = lexer.subString(startPos, endPos - startPos); - values.setOriginalString(orginalString); - } - - valueClauseList.add(values); - } else { - SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList(0)); - valueClauseList.add(values); - } - - if (lexer.token() != Token.RPAREN) { - throw new ParserException("syntax error. " + lexer.info()); - } - - if (!parseCompleteValues && valueClauseList.size() >= parseValuesSize) { - lexer.skipToEOF(); - break; - } - - lexer.nextTokenComma(); - if (lexer.token() == Token.COMMA) { - lexer.nextTokenLParen(); - continue; - } else { - break; - } - } - } - public SQLSelectParser createSQLSelectParser() { return new MySqlSelectParser(this.exprParser); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java index e8e07338f8..f36124939e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java @@ -103,10 +103,6 @@ public interface MySqlASTVisitor extends SQLASTVisitor { boolean visit(MySqlLoadXmlStatement x); - void endVisit(MySqlReplaceStatement x); - - boolean visit(MySqlReplaceStatement x); - void endVisit(MySqlShowColumnsStatement x); boolean visit(MySqlShowColumnsStatement x); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java index 5c3222582f..83393bb11b 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java @@ -186,17 +186,6 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements MySq return true; } - @Override - public void endVisit(MySqlReplaceStatement x) { - - } - - @Override - public boolean visit(MySqlReplaceStatement x) { - - return true; - } - @Override public void endVisit(MySqlShowColumnsStatement x) { 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 b78ec59701..764b6657e1 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 @@ -803,20 +803,22 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV print0(ucase ? "IGNORE " : "ignore "); } - if (x.getFrom() == null) { + SQLTableSource from = x.getFrom(); + if (from == null) { print0(ucase ? "FROM " : "from "); x.getTableSource().accept(this); } else { x.getTableSource().accept(this); println(); print0(ucase ? "FROM " : "from "); - x.getFrom().accept(this); + from.accept(this); } - if (x.getUsing() != null) { + SQLTableSource using = x.getUsing(); + if (using != null) { println(); print0(ucase ? "USING " : "using "); - x.getUsing().accept(this); + using.accept(this); } SQLExpr where = x.getWhere(); @@ -894,7 +896,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV SQLExpr column = columns.get(i); if (column instanceof SQLIdentifierExpr) { - visit((SQLIdentifierExpr) column); + print0(((SQLIdentifierExpr) column).getName()); } else { printExpr(column); } @@ -1053,13 +1055,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV return false; } - @Override - public void endVisit(MySqlReplaceStatement x) { - - } - - @Override - public boolean visit(MySqlReplaceStatement x) { + public boolean visit(SQLReplaceStatement x) { print0(ucase ? "REPLACE " : "replace "); if (x.isLowPriority()) { @@ -1574,9 +1570,10 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlUpdateStatement x) { - if (x.getReturning() != null && x.getReturning().size() > 0) { + List returning = x.getReturning(); + if (returning != null && returning.size() > 0) { print0(ucase ? "SELECT " : "select "); - printAndAccept(x.getReturning(), ", "); + printAndAccept(returning, ", "); println(); print0(ucase ? "FROM " : "from "); } @@ -1614,11 +1611,12 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); print0(ucase ? "SET " : "set "); - for (int i = 0, size = x.getItems().size(); i < size; ++i) { + List items = x.getItems(); + for (int i = 0, size = items.size(); i < size; ++i) { if (i != 0) { print0(", "); } - SQLUpdateSetItem item = x.getItems().get(i); + SQLUpdateSetItem item = items.get(i); visit(item); } @@ -3007,26 +3005,31 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(SQLBlockStatement x) { - if (x.getLabelName() != null && !x.getLabelName().equals("")) { - print0(x.getLabelName()); + SQLObject parent = x.getParent(); + String labelName = x.getLabelName(); + + if (labelName != null && !labelName.equals("")) { + print0(labelName); print0(": "); } - if (x.getParameters().size() != 0) { + + List parameters = x.getParameters(); + if (parameters.size() != 0) { this.indentCount++; - if (x.getParent() instanceof SQLCreateProcedureStatement) { + if (parent instanceof SQLCreateProcedureStatement) { printIndent(); } - if (!(x.getParent() instanceof SQLCreateProcedureStatement)) { + if (!(parent instanceof SQLCreateProcedureStatement)) { print0(ucase ? "DECLARE" : "declare"); println(); } - for (int i = 0, size = x.getParameters().size(); i < size; ++i) { + for (int i = 0, size = parameters.size(); i < size; ++i) { if (i != 0) { println(); } - SQLParameter param = x.getParameters().get(i); - param.accept(this); + SQLParameter param = parameters.get(i); + visit(param); print(';'); } @@ -3036,19 +3039,20 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV print0(ucase ? "BEGIN" : "begin"); this.indentCount++; println(); - for (int i = 0, size = x.getStatementList().size(); i < size; ++i) { + List statementList = x.getStatementList(); + for (int i = 0, size = statementList.size(); i < size; ++i) { if (i != 0) { println(); } - SQLStatement stmt = x.getStatementList().get(i); + SQLStatement stmt = statementList.get(i); stmt.accept(this); } this.indentCount--; println(); print0(ucase ? "END" : "end"); - if (x.getLabelName() != null && !x.getLabelName().equals("")) { + if (labelName != null && !labelName.equals("")) { print(' '); - print0(x.getLabelName()); + print0(labelName); } return false; } @@ -3060,8 +3064,9 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV print0(ucase ? " THEN" : " then"); this.indentCount++; println(); - for (int i = 0, size = x.getStatements().size(); i < size; ++i) { - SQLStatement item = x.getStatements().get(i); + List statements = x.getStatements(); + for (int i = 0, size = statements.size(); i < size; ++i) { + SQLStatement item = statements.get(i); item.accept(this); if (i != size - 1) { println(); @@ -3073,7 +3078,9 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV iterable_element.accept(this); } - if (x.getElseItem() != null) x.getElseItem().accept(this); + if (x.getElseItem() != null) { + x.getElseItem().accept(this); + } print0(ucase ? "END IF" : "end if"); return false; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java index 548e527d1e..5a23493ac8 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java @@ -259,35 +259,6 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS return true; } - @Override - public void endVisit(MySqlReplaceStatement x) { - - } - - @Override - public boolean visit(MySqlReplaceStatement x) { - if (repository != null - && x.getParent() == null) { - repository.resolve(x); - } - - setMode(x, Mode.Replace); - - SQLName tableName = x.getTableName(); - - TableStat stat = getTableStat(tableName); - - if (stat != null) { - stat.incrementInsertCount(); - } - - accept(x.getColumns()); - accept(x.getValuesList()); - accept(x.getQuery()); - - return false; - } - @Override public void endVisit(SQLStartTransactionStatement 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 9196bd0cd4..92b70d0d4b 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 @@ -97,19 +97,21 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS space = true; } - if (x.getOrderBy() != null) { + SQLOrderBy orderBy = x.getOrderBy(); + if (orderBy != null) { if (space) { print(' '); } - x.getOrderBy().accept(this); + visit(orderBy); space = true; } - if (x.getWindowing() != null) { + OracleAnalyticWindowing windowing = x.getWindowing(); + if (windowing != null) { if (space) { print(' '); } - x.getWindowing().accept(this); + visit(windowing); } print(')'); diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java b/src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java index 68015f91a2..135d99bf15 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLParserUtils.java @@ -18,6 +18,7 @@ package com.alibaba.druid.sql.parser; import com.alibaba.druid.sql.dialect.db2.parser.DB2ExprParser; import com.alibaba.druid.sql.dialect.db2.parser.DB2Lexer; import com.alibaba.druid.sql.dialect.db2.parser.DB2StatementParser; +import com.alibaba.druid.sql.dialect.h2.parser.H2StatementParser; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlExprParser; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlLexer; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; @@ -85,7 +86,7 @@ public class SQLParserUtils { } if (JdbcUtils.H2.equals(dbType)) { - return new MySqlStatementParser(sql); + return new H2StatementParser(sql); } if (JdbcUtils.DB2.equals(dbType)) { 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 f170f3b2c4..658a729888 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -22,7 +22,6 @@ import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.expr.*; import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.ast.statement.SQLCreateTriggerStatement.TriggerType; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.druid.sql.dialect.oracle.parser.OracleExprParser; import com.alibaba.druid.util.FnvHash; import com.alibaba.druid.util.JdbcConstants; @@ -2600,7 +2599,7 @@ public class SQLStatementParser extends SQLParser { this.parseValuesSize = parseValuesSize; } - public SQLMergeStatement parseMerge() { + public SQLStatement parseMerge() { accept(Token.MERGE); SQLMergeStatement stmt = new SQLMergeStatement(); @@ -2870,4 +2869,93 @@ public class SQLStatementParser extends SQLParser { throw new ParserException("TODO. " + lexer.info()); } + + protected void parseValueClause(List valueClauseList, int columnSize, SQLObject parent) { + for (int i = 0; ; ++i) { + int startPos = lexer.pos() - 1; + + if (lexer.token() != Token.LPAREN) { + throw new ParserException("syntax error, expect ')', " + lexer.info()); + } + lexer.nextTokenValue(); + + if (lexer.token() != Token.RPAREN) { + List valueExprList; + if (columnSize > 0) { + valueExprList = new ArrayList(columnSize); + } else { + valueExprList = new ArrayList(); + } + + for (; ; ) { + SQLExpr expr; + if (lexer.token() == Token.LITERAL_INT) { + expr = new SQLIntegerExpr(lexer.integerValue()); + lexer.nextTokenComma(); + } else if (lexer.token() == Token.LITERAL_CHARS) { + expr = new SQLCharExpr(lexer.stringVal()); + lexer.nextTokenComma(); + } else if (lexer.token() == Token.LITERAL_NCHARS) { + expr = new SQLNCharExpr(lexer.stringVal()); + lexer.nextTokenComma(); + } else { + expr = exprParser.expr(); + } + + if (lexer.token() == Token.COMMA) { + valueExprList.add(expr); + lexer.nextTokenValue(); + continue; + } else if (lexer.token() == Token.RPAREN) { + valueExprList.add(expr); + break; + } else { + expr = this.exprParser.primaryRest(expr); + if (lexer.token() != Token.COMMA && lexer.token() != Token.RPAREN) { + expr = this.exprParser.exprRest(expr); + } + + valueExprList.add(expr); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } else { + break; + } + } + } + + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(valueExprList); + values.setParent(parent); + + if (lexer.isEnabled(SQLParserFeature.KeepInsertValueClauseOriginalString)) { + int endPos = lexer.pos(); + String orginalString = lexer.subString(startPos, endPos - startPos); + values.setOriginalString(orginalString); + } + + valueClauseList.add(values); + } else { + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList(0)); + valueClauseList.add(values); + } + + if (lexer.token() != Token.RPAREN) { + throw new ParserException("syntax error. " + lexer.info()); + } + + if (!parseCompleteValues && valueClauseList.size() >= parseValuesSize) { + lexer.skipToEOF(); + break; + } + + lexer.nextTokenComma(); + if (lexer.token() == Token.COMMA) { + lexer.nextTokenLParen(); + continue; + } else { + break; + } + } + } } diff --git a/src/main/java/com/alibaba/druid/sql/repository/SchemaResolveVisitorFactory.java b/src/main/java/com/alibaba/druid/sql/repository/SchemaResolveVisitorFactory.java index c2dbccceee..84cbf5f140 100644 --- a/src/main/java/com/alibaba/druid/sql/repository/SchemaResolveVisitorFactory.java +++ b/src/main/java/com/alibaba/druid/sql/repository/SchemaResolveVisitorFactory.java @@ -169,23 +169,8 @@ class SchemaResolveVisitorFactory { return false; } - public boolean visit(MySqlReplaceStatement x) { - Context ctx = createContext(x); - - SQLExprTableSource tableSource = x.getTableSource(); - ctx.setTableSource(tableSource); - visit(tableSource); - - for (SQLExpr column : x.getColumns()) { - column.accept(this); - } - - SQLQueryExpr queryExpr = x.getQuery(); - if (queryExpr != null) { - visit(queryExpr.getSubQuery()); - } - - popContext(); + public boolean visit(SQLReplaceStatement x) { + resolve(this, x); return false; } @@ -1339,6 +1324,11 @@ class SchemaResolveVisitorFactory { return false; } + public boolean visit(SQLReplaceStatement x) { + resolve(this, x); + return false; + } + @Override public boolean isEnabled(Option option) { return (options & option.mask) != 0; @@ -2444,6 +2434,25 @@ class SchemaResolveVisitorFactory { return false; } + static void resolve(SchemaResolveVisitor visitor, SQLReplaceStatement x) { + SchemaResolveVisitor.Context ctx = visitor.createContext(x); + + SQLExprTableSource tableSource = x.getTableSource(); + ctx.setTableSource(tableSource); + visitor.visit(tableSource); + + for (SQLExpr column : x.getColumns()) { + column.accept(visitor); + } + + SQLQueryExpr queryExpr = x.getQuery(); + if (queryExpr != null) { + visitor.visit(queryExpr.getSubQuery()); + } + + visitor.popContext(); + } + static void resolve(SchemaResolveVisitor visitor, SQLForeignKeyConstraint x) { SchemaRepository repository = visitor.getRepository(); SQLObject parent = x.getParent(); 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 0d55242fbd..9df690b869 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -426,7 +426,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet // //////////////////// public boolean visit(SQLBetweenExpr x) { - x.getTestExpr().accept(this); + printExpr(x.getTestExpr()); if (x.isNot()) { print0(ucase ? " NOT BETWEEN " : " not between "); @@ -1154,9 +1154,9 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet printExpr(x.getExpr()); if (x.isNot()) { - print(isUppCase() ? " NOT IN (?)" : " not in (?)"); + print(ucase ? " NOT IN (?)" : " not in (?)"); } else { - print(isUppCase() ? " IN (?)" : " in (?)"); + print(ucase ? " IN (?)" : " in (?)"); } if (changed) { @@ -1296,7 +1296,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet if (i != 0) { print0(", "); } - SQLExpr param = x.getParameters().get(i); + SQLExpr param = parameters.get(i); if (this.parameterized) { if (size == 2 && i == 1 && param instanceof SQLCharExpr) { @@ -1365,11 +1365,13 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet boolean parameterized = this.parameterized; this.parameterized = false; - print0(ucase ? x.getMethodName() : x.getMethodName().toLowerCase()); + String methodName = x.getMethodName(); + print0(ucase ? methodName : methodName.toLowerCase()); print('('); - if (x.getOption() != null) { - print0(x.getOption().toString()); + SQLAggregateOption option = x.getOption(); + if (option != null) { + print0(option.toString()); print(' '); } @@ -1388,19 +1390,20 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet SQLOrderBy withGroup = x.getWithinGroup(); if (withGroup != null) { print0(ucase ? " WITHIN GROUP (" : " within group ("); - withGroup.accept(this); + visit(withGroup); print(')'); } SQLKeep keep = x.getKeep(); if (keep != null) { print(' '); - keep.accept(this); + visit(keep); } - if (x.getOver() != null) { + SQLOver over = x.getOver(); + if (over != null) { print(' '); - x.getOver().accept(this); + over.accept(this); } this.parameterized = parameterized; @@ -2449,9 +2452,10 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet printTableElements(x.getTableElementList()); - if (x.getInherits() != null) { + SQLExprTableSource inherits = x.getInherits(); + if (inherits != null) { print0(ucase ? " INHERITS (" : " inherits ("); - x.getInherits().accept(this); + inherits.accept(this); print(')'); } @@ -2473,26 +2477,27 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } print0(ucase ? "UNIQUE (" : "unique ("); - for (int i = 0, size = x.getColumns().size(); i < size; ++i) { + List columns = x.getColumns(); + for (int i = 0, size = columns.size(); i < size; ++i) { if (i != 0) { print0(", "); } - x.getColumns().get(i).accept(this); + visit(columns.get(i)); } print(')'); return false; } public boolean visit(SQLNotNullConstraint x) { - if (x.getName() != null) { + SQLName name = x.getName(); + if (name != null) { print0(ucase ? "CONSTRAINT " : "constraint "); - x.getName().accept(this); + name.accept(this); print(' '); } print0(ucase ? "NOT NULL" : "not null"); List hints = x.hints; - if (hints != null) { print(' '); for (SQLCommentHint hint : hints) { @@ -2504,9 +2509,10 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLNullConstraint x) { - if (x.getName() != null) { + SQLName name = x.getName(); + if (name != null) { print0(ucase ? "CONSTRAINT " : "constraint "); - x.getName().accept(this); + name.accept(this); print(' '); } print0(ucase ? "NULL" : "null"); 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 f9a52ea38d..2be41a8729 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java @@ -739,7 +739,11 @@ public interface SQLASTVisitor { void endVisit(SQLBinaryOpExprGroup x); - boolean visit(SQLScriptCommitStatement astNode); + boolean visit(SQLScriptCommitStatement x); - void endVisit(SQLScriptCommitStatement astNode); + void endVisit(SQLScriptCommitStatement x); + + boolean visit(SQLReplaceStatement x); + + void endVisit(SQLReplaceStatement 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 2de60ec512..536142d610 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java @@ -1695,7 +1695,17 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor { } @Override - public void endVisit(SQLScriptCommitStatement astNode) { + public void endVisit(SQLScriptCommitStatement x) { + + } + + @Override + public boolean visit(SQLReplaceStatement x) { + return true; + } + + @Override + public void endVisit(SQLReplaceStatement x) { } 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 4632391fc3..80b2b70c6f 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -1983,6 +1983,8 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { } public boolean visit(SQLCreateTriggerStatement x) { + SQLExprTableSource on = x.getOn(); + on.accept(this); return false; } @@ -2306,6 +2308,29 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { return true; } + public boolean visit(SQLReplaceStatement x) { + if (repository != null + && x.getParent() == null) { + repository.resolve(x); + } + + setMode(x, Mode.Replace); + + SQLName tableName = x.getTableName(); + + TableStat stat = getTableStat(tableName); + + if (stat != null) { + stat.incrementInsertCount(); + } + + accept(x.getColumns()); + accept(x.getValuesList()); + accept(x.getQuery()); + + return false; + } + protected final void statExpr(SQLExpr x) { Class clazz = x.getClass(); if (clazz == SQLIdentifierExpr.class) { diff --git a/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java b/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java index ee8ccf1b23..ccac50c3ee 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java +++ b/src/main/java/com/alibaba/druid/wall/spi/MySqlWallVisitor.java @@ -34,7 +34,6 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.druid.sql.ast.SQLLimit; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateTableStatement; @@ -402,11 +401,6 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi return false; } - @Override - public boolean visit(MySqlReplaceStatement x) { - return true; - } - @Override public boolean visit(SQLCallStatement x) { return false; diff --git a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java index 09e574009b..c85993fc9b 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -2181,7 +2181,7 @@ public class WallVisitorUtils { tableStat.incrementDeleteCount(); } else if (parent instanceof SQLUpdateStatement) { tableStat.incrementUpdateCount(); - } else if (parent instanceof MySqlReplaceStatement) { + } else if (parent instanceof SQLReplaceStatement) { tableStat.incrementReplaceCount(); } } @@ -2512,7 +2512,7 @@ public class WallVisitorUtils { allow = config.isSetAllow(); denyMessage = "set not allow"; errorCode = ErrorCode.SET_NOT_ALLOW; - } else if (x instanceof MySqlReplaceStatement) { + } else if (x instanceof SQLReplaceStatement) { allow = config.isReplaceAllow(); denyMessage = "replace not allow"; errorCode = ErrorCode.REPLACE_NOT_ALLOW; diff --git a/src/test/java/com/alibaba/druid/benckmark/sql/StatementConverter.java b/src/test/java/com/alibaba/druid/benckmark/sql/StatementConverter.java index 0a20485613..e828dced75 100644 --- a/src/test/java/com/alibaba/druid/benckmark/sql/StatementConverter.java +++ b/src/test/java/com/alibaba/druid/benckmark/sql/StatementConverter.java @@ -5,7 +5,6 @@ import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.statement.*; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; /** @@ -49,10 +48,10 @@ public class StatementConverter { } else { throw new UnsupportedOperationException("only insert..select.. is supported"); } - } else if (stmt instanceof MySqlReplaceStatement) { - SQLQueryExpr sqlQueryExpr = ((MySqlReplaceStatement) stmt).getQuery(); + } else if (stmt instanceof SQLReplaceStatement) { + SQLQueryExpr sqlQueryExpr = ((SQLReplaceStatement) stmt).getQuery(); if (sqlQueryExpr != null) { - SQLSelect sqlSelect = ((MySqlReplaceStatement) stmt).getQuery().getSubQuery(); + SQLSelect sqlSelect = ((SQLReplaceStatement) stmt).getQuery().getSubQuery(); selectStmt = new SQLSelectStatement(); selectStmt.setSelect(sqlSelect); } else { diff --git a/src/test/java/com/alibaba/druid/bvt/sql/h2/H2_CreateTriggerTest_0.java b/src/test/java/com/alibaba/druid/bvt/sql/h2/H2_CreateTriggerTest_0.java new file mode 100644 index 0000000000..f0f766693a --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/h2/H2_CreateTriggerTest_0.java @@ -0,0 +1,71 @@ +/* + * 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.h2; + +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.sql.parser.SQLStatementParser; +import com.alibaba.druid.util.JdbcConstants; +import org.junit.Assert; + +import java.util.List; + +public class H2_CreateTriggerTest_0 extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "create trigger employee_trigger after insert,update,delete on employee for each row call \"test.redisson.h2cluster.trigger.ClusterTrigger\"\n"; // + + List statementList = SQLUtils.toStatementList(sql, JdbcConstants.H2); + SQLStatement stmt = statementList.get(0); + print(statementList); + + + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + stmt.accept(visitor); + + { + String text = SQLUtils.toSQLString(stmt, JdbcConstants.H2); + + assertEquals("CREATE TRIGGER employee_trigger\n" + + "\tAFTER INSERT OR DELETE OR UPDATE\n" + + "\tON employee\n" + + "\tFOR EACH ROW\n" + + "CALL \"test.redisson.h2cluster.trigger.ClusterTrigger\"()", text); + } + + 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()); + + assertEquals(1, visitor.getTables().size()); + assertEquals(0, visitor.getColumns().size()); + assertEquals(0, visitor.getConditions().size()); + assertEquals(0, visitor.getRelationships().size()); + assertEquals(0, visitor.getOrderByColumns().size()); + + Assert.assertTrue(visitor.containsTable("employee")); + + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/h2/H2_MergeTest_0.java b/src/test/java/com/alibaba/druid/bvt/sql/h2/H2_MergeTest_0.java new file mode 100644 index 0000000000..ba323933cb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/h2/H2_MergeTest_0.java @@ -0,0 +1,70 @@ +/* + * 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.h2; + +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.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; +import org.junit.Assert; + +import java.util.List; + +public class H2_MergeTest_0 extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "merge into person key(id) select * from person_test"; // + + System.out.println(sql); + + List statementList = SQLUtils.toStatementList(sql, JdbcConstants.H2); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.H2); + stmt.accept(visitor); + + { + String text = SQLUtils.toSQLString(stmt, JdbcConstants.H2); + + assertEquals("MERGE INTO person KEY (id)\n" + + "\tSELECT *\n" + + "\tFROM person_test", text); + } + + 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()); + + assertEquals(2, visitor.getTables().size()); + assertEquals(2, visitor.getColumns().size()); + assertEquals(0, visitor.getConditions().size()); + assertEquals(0, visitor.getRelationships().size()); + assertEquals(0, visitor.getOrderByColumns().size()); + + Assert.assertTrue(visitor.containsTable("person")); + Assert.assertTrue(visitor.containsTable("person_test")); + + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlASTVisitorAdapterTest.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlASTVisitorAdapterTest.java index 5e0f30e91d..b28eda42c3 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlASTVisitorAdapterTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlASTVisitorAdapterTest.java @@ -2,6 +2,7 @@ package com.alibaba.druid.bvt.sql.mysql; import com.alibaba.druid.sql.ast.expr.SQLBinaryExpr; import com.alibaba.druid.sql.ast.expr.SQLBooleanExpr; +import com.alibaba.druid.sql.ast.statement.SQLReplaceStatement; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; @@ -32,7 +33,6 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement; import com.alibaba.druid.sql.ast.SQLLimit; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetTransactionStatement; @@ -102,7 +102,7 @@ public class MySqlASTVisitorAdapterTest extends TestCase { new MySqlDeleteStatement().accept(adapter); new MySqlInsertStatement().accept(adapter); new MySqlLoadXmlStatement().accept(adapter); - new MySqlReplaceStatement().accept(adapter); + new SQLReplaceStatement().accept(adapter); new SQLStartTransactionStatement().accept(adapter); new MySqlShowColumnsStatement().accept(adapter); new MySqlShowDatabasesStatement().accept(adapter); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/param/ParseUtil.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/param/ParseUtil.java index 6f25485577..7215d0781f 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/param/ParseUtil.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/param/ParseUtil.java @@ -4,7 +4,6 @@ package com.alibaba.druid.bvt.sql.mysql.param; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.statement.*; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; import com.alibaba.druid.sql.visitor.ParameterizedOutputVisitorUtils; @@ -43,7 +42,7 @@ public class ParseUtil { // return DML_1_PATTERN.matcher(querySql).find() || DML_2_PATTERN.matcher(querySql).find(); return statement instanceof SQLSelectStatement || statement instanceof SQLInsertStatement || - statement instanceof MySqlReplaceStatement || + statement instanceof SQLReplaceStatement || statement instanceof SQLUpdateStatement || statement instanceof SQLDeleteStatement; } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest.java index 019dfc7867..587a124921 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest.java @@ -64,7 +64,7 @@ public class OracleCreateTriggerTest extends OracleTest { System.out.println("relationships : " + visitor.getRelationships()); System.out.println("orderBy : " + visitor.getOrderByColumns()); - Assert.assertEquals(0, visitor.getTables().size()); + Assert.assertEquals(1, visitor.getTables().size()); // Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("cdc.en_complaint_ipr_stat_fdt0"))); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest2.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest2.java index f3fcc207e6..7990539482 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest2.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest2.java @@ -67,7 +67,7 @@ public class OracleCreateTriggerTest2 extends OracleTest { System.out.println("relationships : " + visitor.getRelationships()); System.out.println("orderBy : " + visitor.getOrderByColumns()); - Assert.assertEquals(0, visitor.getTables().size()); + Assert.assertEquals(1, visitor.getTables().size()); // Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("cdc.en_complaint_ipr_stat_fdt0"))); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest3.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest3.java index 6fd116b746..1a12b34f6d 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest3.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/create/OracleCreateTriggerTest3.java @@ -59,7 +59,7 @@ public class OracleCreateTriggerTest3 extends OracleTest { System.out.println("relationships : " + visitor.getRelationships()); System.out.println("orderBy : " + visitor.getOrderByColumns()); - Assert.assertEquals(0, visitor.getTables().size()); + Assert.assertEquals(1, visitor.getTables().size()); // Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("cdc.en_complaint_ipr_stat_fdt0"))); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest82_wmsysconcat.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest82_wmsysconcat.java index 4799b64603..a4d5d76854 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest82_wmsysconcat.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest82_wmsysconcat.java @@ -83,6 +83,9 @@ public class OracleSelectTest82_wmsysconcat extends OracleTest { assertEquals(1, visitor.getRelationships().size()); assertEquals(0, visitor.getOrderByColumns().size()); + Assert.assertTrue(visitor.containsTable("sup_registration")); + Assert.assertTrue(visitor.containsTable("sup_task")); + Assert.assertTrue(visitor.containsTable("sys_org")); Assert.assertTrue(visitor.containsColumn("sup_task", "orgid")); Assert.assertTrue(visitor.containsColumn("sup_task", "orgid"));