diff --git a/src/main/java/com/alibaba/druid/sql/SQLTransformUtils.java b/src/main/java/com/alibaba/druid/sql/SQLTransformUtils.java index 27ac4d689c..016f68c803 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLTransformUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLTransformUtils.java @@ -15,8 +15,11 @@ */ package com.alibaba.druid.sql; +import com.alibaba.druid.sql.ast.SQLDataType; +import com.alibaba.druid.sql.ast.SQLDataTypeImpl; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.expr.*; +import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; import java.util.List; @@ -86,6 +89,521 @@ public class SQLTransformUtils { caseExpr.setElseExpr(defaultExpr); } + caseExpr.setParent(x.getParent()); + return caseExpr; } + + public static SQLDataType transformOracleToMySql(SQLDataType x) { + final String name = x.getName(); + + if (name == null) { + return x; + } + List argumentns = x.getArguments(); + + String name_lower = name.toLowerCase(); + + SQLDataType dataType; + + if ("urowid".equalsIgnoreCase(name_lower)) { + int len = 4000; + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLIntegerExpr) { + len = ((SQLIntegerExpr) arg0).getNumber().intValue(); + } + } + dataType = new SQLDataTypeImpl("varchar", len); + } else if ("rowid".equals(name_lower)) { + dataType = new SQLDataTypeImpl("char", 10); + + } else if ("boolean".equals(name_lower)) { + dataType = new SQLDataTypeImpl("tinyint"); + + } else if ("integer".equals(name_lower)) { + dataType = new SQLDataTypeImpl("int"); + + } else if ("float".equals(name_lower) || "binary_float".equals(name_lower)) { + dataType = new SQLDataTypeImpl("float"); + + } else if ("real".equals(name_lower) + || "double precision".equals(name_lower) + || "binary_double".equals(name_lower)) { + dataType = new SQLDataTypeImpl("double"); + + } else if ("number".equals(name_lower)) { + if (argumentns.size() == 0) { + dataType = new SQLDataTypeImpl("decimal", 38); + } else { + SQLExpr arg0 = argumentns.get(0); + + int precision, scale = 0; + if (arg0 instanceof SQLAllColumnExpr) { + precision = 9; + scale = 1; + } else { + precision = ((SQLIntegerExpr) arg0).getNumber().intValue(); + } + + if (argumentns.size() > 1) { + scale = ((SQLIntegerExpr) argumentns.get(1)).getNumber().intValue(); + } + + if (scale > precision) { + if (arg0 instanceof SQLAllColumnExpr) { + precision = 19; + if (scale > precision) { + precision = scale; + } + } else { + precision = scale; + } + } + + if (scale == 0) { + if (precision < 3) { + dataType = new SQLDataTypeImpl("tinyint"); + } else if (precision < 5) { + dataType = new SQLDataTypeImpl("smallint"); + } else if (precision < 9) { + dataType = new SQLDataTypeImpl("int"); + } else if (precision < 19) { + dataType = new SQLDataTypeImpl("bigint"); + } else { + dataType = new SQLDataTypeImpl("decimal", precision); + } + } else { + dataType = new SQLDataTypeImpl("decimal", precision, scale); + } + } + + } else if ("dec".equals(name_lower) || "decimal".equals(name_lower)) { + dataType = x.clone(); + dataType.setName("decimal"); + + int precision = 0; + if (argumentns.size() > 0) { + precision = ((SQLIntegerExpr) argumentns.get(0)).getNumber().intValue(); + } + + int scale = 0; + if (argumentns.size() > 1) { + scale = ((SQLIntegerExpr) argumentns.get(1)).getNumber().intValue(); + if (precision < scale) { + ((SQLIntegerExpr) dataType.getArguments().get(1)).setNumber(precision); + } + } + +// if (precision == 38 && scale == 0 && x.getParent() instanceof SQLCastExpr) { +// dataType.getArguments().clear(); +// dataType.setName("int"); +// } + ///////////////////////////////// + + } else if ("raw".equals(name_lower)) { + int len; + + if (argumentns.size() == 0) { + len = -1; + } else if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + if (len == -1) { + dataType = new SQLDataTypeImpl("binary"); + } else if (len <= 255) { + dataType = new SQLDataTypeImpl("binary", len); + } else { + dataType = new SQLDataTypeImpl("varbinary", len); + } + } else if ("char".equals(name_lower) + || "character".equals(name_lower)) { + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + + int len; + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + if (len <= 255) { + dataType = new SQLCharacterDataType("char", len); + } else { + dataType = new SQLCharacterDataType("varchar", len); + } + } else if (argumentns.size() == 0) { + dataType = new SQLCharacterDataType("char"); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + } else if ("nchar".equals(name_lower)) { + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + + int len; + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + if (len <= 255) { + dataType = new SQLCharacterDataType("nchar", len); + } else { + dataType = new SQLCharacterDataType("nvarchar", len); + } + } else if (argumentns.size() == 0) { + dataType = new SQLCharacterDataType("nchar"); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + } else if ("varchar2".equals(name_lower)) { + if (argumentns.size() > 0) { + int len; + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + dataType = new SQLCharacterDataType("varchar", len); + } else { + dataType = new SQLCharacterDataType("varchar"); + } + + } else if ("nvarchar2".equals(name_lower)) { + if (argumentns.size() > 0) { + int len; + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + dataType = new SQLCharacterDataType("nvarchar", len); + } else { + dataType = new SQLCharacterDataType("nvarchar"); + } + + } else if ("bfile".equals(name_lower)) { + dataType = new SQLCharacterDataType("varchar", 255); + + } else if ("date".equals(name_lower) + || "timestamp".equals(name_lower)) { + int len = -1; + if (argumentns.size() > 0) { + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + } + + if (len >= 0) { + if (len > 6) { + len = 6; + } + dataType = new SQLDataTypeImpl("datetime", len); + } else { + dataType = new SQLDataTypeImpl("datetime"); + } + } else if ("blob".equals(name_lower) || "long raw".equals(name_lower)) { + argumentns.clear(); + dataType = new SQLDataTypeImpl("LONGBLOB"); + + } else if ("clob".equals(name_lower) + || "nclob".equals(name_lower) + || "long".equals(name_lower) + || "xmltype".equals(name_lower)) { + argumentns.clear(); + dataType = new SQLCharacterDataType("LONGTEXT"); + + } else { + dataType = x; + } + + if (dataType != x) { + dataType.setParent(x.getParent()); + } + + return dataType; + } + + public static SQLDataType transformOracleToAliyunAds(SQLDataType x) { + final String dataTypeName = x.getName().toLowerCase(); + SQLDataType dataType; + + if (dataTypeName.equals("varchar2") + || dataTypeName.equals("varchar") + || dataTypeName.equals("char") + || dataTypeName.equals("nchar") + || dataTypeName.equals("nvarchar") + || dataTypeName.equals("nvarchar2") + || dataTypeName.equals("clob") + || dataTypeName.equals("nclob") + || dataTypeName.equals("blob") + || dataTypeName.equals("long") + || dataTypeName.equals("long raw") + || dataTypeName.equals("raw") + ) { + dataType = new SQLCharacterDataType("varchar"); + } else if (dataTypeName.equals("number") + || dataTypeName.equals("decimal") + || dataTypeName.equals("dec") + || dataTypeName.equals("numeric")) { + int scale = 0; + if (x.getArguments().size() > 1) { + scale = ((SQLIntegerExpr) x.getArguments().get(1)).getNumber().intValue(); + } + if (scale == 0) { + dataType = new SQLDataTypeImpl("bigint"); + } else { + dataType = new SQLDataTypeImpl("double"); + } + } else if (dataTypeName.equals("date") + || dataTypeName.equals("datetime") + || dataTypeName.equals("timestamp")) { + dataType = new SQLDataTypeImpl("timestamp"); + } else if (dataTypeName.equals("float") + || dataTypeName.equals("binary_float")) { + dataType = new SQLDataTypeImpl("float"); + } else if (dataTypeName.equals("double") + || dataTypeName.equals("binary_double")) { + dataType = new SQLDataTypeImpl("double"); + } else { + dataType = x; + } + + if (dataType != x) { + dataType.setParent(x.getParent()); + } + + return dataType; + } + + public static SQLDataType transformOracleToPostgresql(SQLDataType x) { + final String name = x.getName(); + + if (name == null) { + return x; + } + List argumentns = x.getArguments(); + + String name_lower = name.toLowerCase(); + + SQLDataType dataType; + + if ("urowid".equalsIgnoreCase(name_lower)) { + int len = 4000; + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLIntegerExpr) { + len = ((SQLIntegerExpr) arg0).getNumber().intValue(); + } + } + dataType = new SQLDataTypeImpl("varchar", len); + } else if ("rowid".equals(name_lower)) { + dataType = new SQLDataTypeImpl("char", 10); + + } else if ("boolean".equals(name_lower)) { + dataType = new SQLDataTypeImpl("tinyint"); + + } else if ("integer".equals(name_lower) || "int".equals(name_lower)) { + dataType = new SQLDataTypeImpl("decimal", 38); + + } else if ("binary_float".equals(name_lower)) { + dataType = new SQLDataTypeImpl("real"); + + } else if ("binary_double".equals(name_lower) + || "float".equals(name_lower) + || "real".equals(name_lower)) { + dataType = new SQLDataTypeImpl("double precision"); + + } else if ("number".equals(name_lower)) { + if (argumentns.size() == 0) { + dataType = new SQLDataTypeImpl("decimal", 38); + } else { + SQLExpr arg0 = argumentns.get(0); + + int precision, scale = 0; + if (arg0 instanceof SQLAllColumnExpr) { + precision = 9; + scale = 1; + } else { + precision = ((SQLIntegerExpr) arg0).getNumber().intValue(); + } + + if (argumentns.size() > 1) { + scale = ((SQLIntegerExpr) argumentns.get(1)).getNumber().intValue(); + } + + if (scale > precision) { + if (arg0 instanceof SQLAllColumnExpr) { + precision = 19; + if (scale > precision) { + precision = scale; + } + } else { + precision = scale; + } + } + + if (scale == 0) { + if (precision < 3) { + dataType = new SQLDataTypeImpl("tinyint"); + } else if (precision < 5) { + dataType = new SQLDataTypeImpl("smallint"); + } else if (precision < 9) { + dataType = new SQLDataTypeImpl("int"); + } else if (precision < 19) { + dataType = new SQLDataTypeImpl("bigint"); + } else { + dataType = new SQLDataTypeImpl("decimal", precision); + } + } else { + dataType = new SQLDataTypeImpl("decimal", precision, scale); + } + } + + } else if ("dec".equals(name_lower) || "decimal".equals(name_lower)) { + dataType = x.clone(); + dataType.setName("decimal"); + + int precision = 0; + if (argumentns.size() > 0) { + precision = ((SQLIntegerExpr) argumentns.get(0)).getNumber().intValue(); + } + + int scale = 0; + if (argumentns.size() > 1) { + scale = ((SQLIntegerExpr) argumentns.get(1)).getNumber().intValue(); + if (precision < scale) { + ((SQLIntegerExpr) dataType.getArguments().get(1)).setNumber(precision); + } + } + + } else if ("char".equals(name_lower) + || "character".equals(name_lower)) { + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + + int len; + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + if (len <= 255) { + dataType = new SQLCharacterDataType("char", len); + } else { + dataType = new SQLCharacterDataType("varchar", len); + } + } else if (argumentns.size() == 0) { + dataType = new SQLCharacterDataType("char"); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + } else if ("nchar".equals(name_lower)) { + if (argumentns.size() == 1) { + SQLExpr arg0 = argumentns.get(0); + + int len; + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + if (len <= 255) { + dataType = new SQLCharacterDataType("char", len); + } else { + dataType = new SQLCharacterDataType("varchar", len); + } + } else if (argumentns.size() == 0) { + dataType = new SQLCharacterDataType("char"); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + + } else if ("varchar2".equals(name_lower)) { + if (argumentns.size() > 0) { + int len; + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + dataType = new SQLCharacterDataType("varchar", len); + } else { + dataType = new SQLCharacterDataType("varchar"); + } + + } else if ("nvarchar2".equals(name_lower) || "nchar varying".equals(name_lower)) { + if (argumentns.size() > 0) { + int len; + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + dataType = new SQLCharacterDataType("varchar", len); + } else { + dataType = new SQLCharacterDataType("varchar"); + } + + } else if ("bfile".equals(name_lower)) { + dataType = new SQLCharacterDataType("varchar", 255); + + } else if ("date".equals(name_lower) + || "timestamp".equals(name_lower)) { + int len = -1; + if (argumentns.size() > 0) { + SQLExpr arg0 = argumentns.get(0); + if (arg0 instanceof SQLNumericLiteralExpr) { + len = ((SQLNumericLiteralExpr) arg0).getNumber().intValue(); + } else { + throw new UnsupportedOperationException(SQLUtils.toOracleString(x)); + } + } + + dataType = new SQLDataTypeImpl("timestamp", len); + } else if ("blob".equals(name_lower) || "long raw".equals(name_lower) || "raw".equals(name_lower)) { + argumentns.clear(); + dataType = new SQLDataTypeImpl("bytea"); + + } else if ("clob".equals(name_lower) + || "nclob".equals(name_lower) + || "long".equals(name_lower)) { + argumentns.clear(); + dataType = new SQLCharacterDataType("TEXT"); + + } else if ("xmltype".equals(name_lower)) { + dataType = new SQLDataTypeImpl("xml"); + } else { + dataType = x; + } + + if (dataType != x) { + dataType.setParent(x.getParent()); + } + + return dataType; + } } 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 3326c964b3..3a1562e768 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLDataTypeImpl.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLDataTypeImpl.java @@ -15,6 +15,7 @@ */ package com.alibaba.druid.sql.ast; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.visitor.SQLASTVisitor; import java.util.ArrayList; @@ -37,6 +38,17 @@ public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType { this.name = name; } + public SQLDataTypeImpl(String name, int precision) { + this(name); + addArgument(new SQLIntegerExpr(precision)); + } + + public SQLDataTypeImpl(String name, int precision, int scale) { + this(name); + addArgument(new SQLIntegerExpr(precision)); + addArgument(new SQLIntegerExpr(scale)); + } + @Override protected void accept0(SQLASTVisitor visitor) { if (visitor.visit(this)) { diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLDeclareItem.java b/src/main/java/com/alibaba/druid/sql/ast/SQLDeclareItem.java index 323da37701..7f53890876 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLDeclareItem.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLDeclareItem.java @@ -21,7 +21,7 @@ import java.util.List; import com.alibaba.druid.sql.ast.statement.SQLTableElement; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLDeclareItem extends SQLObjectImpl { +public class SQLDeclareItem extends SQLObjectImpl implements SQLObjectWithDataType { protected Type type; diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLObjectWithDataType.java b/src/main/java/com/alibaba/druid/sql/ast/SQLObjectWithDataType.java new file mode 100644 index 0000000000..f3a731447e --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLObjectWithDataType.java @@ -0,0 +1,21 @@ +/* + * 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.ast; + +public interface SQLObjectWithDataType extends SQLObject { + SQLDataType getDataType(); + void setDataType(SQLDataType dataType); +} 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 d649c427c3..9ba71eb29f 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 { +public class SQLParameter extends SQLObjectImpl implements SQLObjectWithDataType { private SQLExpr name; private SQLDataType dataType; @@ -59,6 +59,9 @@ public class SQLParameter extends SQLObjectImpl { } public void setDataType(SQLDataType dataType) { + if (dataType != null) { + dataType.setParent(this); + } this.dataType = dataType; } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java index 2bfd1726bd..44d1998233 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java @@ -18,9 +18,10 @@ package com.alibaba.druid.sql.ast.expr; import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; +import com.alibaba.druid.sql.ast.SQLObjectWithDataType; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLCastExpr extends SQLExprImpl { +public class SQLCastExpr extends SQLExprImpl implements SQLObjectWithDataType { protected SQLExpr expr; protected SQLDataType dataType; @@ -45,6 +46,9 @@ public class SQLCastExpr extends SQLExprImpl { } public void setDataType(SQLDataType dataType) { + if (dataType != null) { + dataType.setParent(this); + } this.dataType = dataType; } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharacterDataType.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharacterDataType.java index 0c102c114d..2ecdd5808d 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharacterDataType.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCharacterDataType.java @@ -41,6 +41,10 @@ public class SQLCharacterDataType extends SQLDataTypeImpl { super(name); } + public SQLCharacterDataType(String name, int precision){ + super(name, precision); + } + public String getCharSetName() { return charSetName; } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java index 3825dcacf5..85bb7a532c 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java @@ -19,16 +19,13 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.druid.sql.SQLUtils; -import com.alibaba.druid.sql.ast.SQLDataType; -import com.alibaba.druid.sql.ast.SQLExpr; -import com.alibaba.druid.sql.ast.SQLName; -import com.alibaba.druid.sql.ast.SQLObjectImpl; +import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.visitor.SQLASTVisitor; import com.alibaba.druid.util.JdbcConstants; -public class SQLColumnDefinition extends SQLObjectImpl implements SQLTableElement { +public class SQLColumnDefinition extends SQLObjectImpl implements SQLTableElement, SQLObjectWithDataType { protected String dbType; protected SQLName name; diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateFunctionStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateFunctionStatement.java index 4c2cd3b828..a96f0c7113 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateFunctionStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateFunctionStatement.java @@ -25,7 +25,7 @@ import java.util.List; /** * Created by wenshao on 23/05/2017. */ -public class SQLCreateFunctionStatement extends SQLStatementImpl implements SQLCreateStatement { +public class SQLCreateFunctionStatement extends SQLStatementImpl implements SQLCreateStatement, SQLObjectWithDataType { private SQLName definer; private boolean create = true; @@ -85,6 +85,7 @@ public class SQLCreateFunctionStatement extends SQLStatementImpl implements SQLC acceptChild(visitor, definer); acceptChild(visitor, name); acceptChild(visitor, parameters); + acceptChild(visitor, returnDataType); acceptChild(visitor, block); } visitor.endVisit(this); @@ -199,4 +200,14 @@ public class SQLCreateFunctionStatement extends SQLStatementImpl implements SQLC return null; } + + @Override + public SQLDataType getDataType() { + return returnDataType; + } + + @Override + public void setDataType(SQLDataType dataType) { + this.setReturnDataType(dataType); + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java index fa56b25731..45e6bad152 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java @@ -80,14 +80,14 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { accept(Token.CREATE); } - if (identifierEquals("TEMPORARY")) { + if (lexer.identifierEquals("TEMPORARY")) { lexer.nextToken(); stmt.setType(SQLCreateTableStatement.Type.GLOBAL_TEMPORARY); } accept(Token.TABLE); - if (lexer.token() == Token.IF || identifierEquals("IF")) { + if (lexer.token() == Token.IF || lexer.identifierEquals("IF")) { lexer.nextToken(); accept(Token.NOT); accept(Token.EXISTS); @@ -132,7 +132,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } } - if (identifierEquals("USING")) { + if (lexer.identifierEquals("USING")) { lexer.nextToken(); idx.setIndexType(lexer.stringVal()); lexer.nextToken(); @@ -149,7 +149,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } accept(Token.RPAREN); - if (identifierEquals("USING")) { + if (lexer.identifierEquals("USING")) { lexer.nextToken(); idx.setIndexType(lexer.stringVal()); lexer.nextToken(); @@ -190,7 +190,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { lexer.nextToken(); } - if (identifierEquals("ENGINE")) { + if (lexer.identifierEquals("ENGINE")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -199,7 +199,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("AUTO_INCREMENT")) { + if (lexer.identifierEquals("AUTO_INCREMENT")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -208,7 +208,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("AVG_ROW_LENGTH")) { + if (lexer.identifierEquals("AVG_ROW_LENGTH")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -227,7 +227,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("CHECKSUM")) { + if (lexer.identifierEquals("CHECKSUM")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -245,7 +245,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("CONNECTION")) { + if (lexer.identifierEquals("CONNECTION")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -254,7 +254,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("DATA")) { + if (lexer.identifierEquals("DATA")) { lexer.nextToken(); acceptIdentifier("DIRECTORY"); if (lexer.token() == Token.EQ) { @@ -264,7 +264,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("DELAY_KEY_WRITE")) { + if (lexer.identifierEquals("DELAY_KEY_WRITE")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -273,7 +273,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("INDEX")) { + if (lexer.identifierEquals("INDEX")) { lexer.nextToken(); acceptIdentifier("DIRECTORY"); if (lexer.token() == Token.EQ) { @@ -283,7 +283,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("INSERT_METHOD")) { + if (lexer.identifierEquals("INSERT_METHOD")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -292,7 +292,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("KEY_BLOCK_SIZE")) { + if (lexer.identifierEquals("KEY_BLOCK_SIZE")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -301,7 +301,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("MAX_ROWS")) { + if (lexer.identifierEquals("MAX_ROWS")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -310,7 +310,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("MIN_ROWS")) { + if (lexer.identifierEquals("MIN_ROWS")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -319,7 +319,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("PACK_KEYS")) { + if (lexer.identifierEquals("PACK_KEYS")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -328,7 +328,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("PASSWORD")) { + if (lexer.identifierEquals("PASSWORD")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -337,7 +337,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("ROW_FORMAT")) { + if (lexer.identifierEquals("ROW_FORMAT")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -346,7 +346,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("STATS_AUTO_RECALC")) { + if (lexer.identifierEquals("STATS_AUTO_RECALC")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -356,7 +356,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("STATS_PERSISTENT")) { + if (lexer.identifierEquals("STATS_PERSISTENT")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -366,7 +366,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("STATS_SAMPLE_PAGES")) { + if (lexer.identifierEquals("STATS_SAMPLE_PAGES")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -395,7 +395,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { TableSpaceOption option = new TableSpaceOption(); option.setName(this.exprParser.name()); - if (identifierEquals("STORAGE")) { + if (lexer.identifierEquals("STORAGE")) { lexer.nextToken(); option.setStorage(this.exprParser.name()); } @@ -404,7 +404,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("TABLEGROUP")) { + if (lexer.identifierEquals("TABLEGROUP")) { lexer.nextToken(); SQLName tableGroup = this.exprParser.name(); @@ -412,7 +412,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { continue; } - if (identifierEquals("TYPE")) { + if (lexer.identifierEquals("TYPE")) { lexer.nextToken(); accept(Token.EQ); stmt.getTableOptions().put("TYPE", this.exprParser.expr()); @@ -427,7 +427,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { SQLPartitionBy partitionClause; boolean linera = false; - if (identifierEquals("LINEAR")) { + if (lexer.identifierEquals("LINEAR")) { lexer.nextToken(); linera = true; } @@ -456,7 +456,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { partitionClause = clause; partitionClauseRest(clause); - } else if (identifierEquals("HASH")) { + } else if (lexer.identifierEquals("HASH")) { lexer.nextToken(); SQLPartitionByHash clause = new SQLPartitionByHash(); @@ -476,13 +476,13 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { partitionClauseRest(clause); - } else if (identifierEquals("RANGE")) { + } else if (lexer.identifierEquals("RANGE")) { SQLPartitionByRange clause = partitionByRange(); partitionClause = clause; partitionClauseRest(clause); - } else if (identifierEquals("LIST")) { + } else if (lexer.identifierEquals("LIST")) { lexer.nextToken(); SQLPartitionByList clause = new SQLPartitionByList(); @@ -582,7 +582,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } protected void partitionClauseRest(SQLPartitionBy clause) { - if (identifierEquals("PARTITIONS")) { + if (lexer.identifierEquals("PARTITIONS")) { lexer.nextToken(); SQLIntegerExpr countExpr = this.exprParser.integerExpr(); @@ -592,7 +592,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { if (lexer.token() == Token.PARTITION) { lexer.nextToken(); - if (identifierEquals("NUM")) { + if (lexer.identifierEquals("NUM")) { lexer.nextToken(); } @@ -601,14 +601,14 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { clause.putAttribute("ads.partition", Boolean.TRUE); } - if (identifierEquals("SUBPARTITION")) { + if (lexer.identifierEquals("SUBPARTITION")) { lexer.nextToken(); accept(Token.BY); SQLSubPartitionBy subPartitionByClause = null; boolean linear = false; - if (identifierEquals("LINEAR")) { + if (lexer.identifierEquals("LINEAR")) { lexer.nextToken(); linear = true; } @@ -634,7 +634,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { subPartitionByClause = subPartitionKey; - } else if (identifierEquals("HASH")) { + } else if (lexer.identifierEquals("HASH")) { lexer.nextToken(); SQLSubPartitionByHash subPartitionHash = new SQLSubPartitionByHash(); @@ -652,7 +652,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { accept(Token.RPAREN); subPartitionByClause = subPartitionHash; - } else if (identifierEquals("LIST")) { + } else if (lexer.identifierEquals("LIST")) { lexer.nextToken(); MySqlSubPartitionByList subPartitionList = new MySqlSubPartitionByList(); @@ -660,7 +660,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { lexer.nextToken(); SQLExpr expr = this.exprParser.expr(); - if (expr instanceof SQLIdentifierExpr && (identifierEquals("bigint") || identifierEquals("long"))) { + if (expr instanceof SQLIdentifierExpr && (lexer.identifierEquals("bigint") || lexer.identifierEquals("long"))) { String dataType = lexer.stringVal(); lexer.nextToken(); @@ -690,7 +690,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { subPartitionByClause = subPartitionList; } - if (identifierEquals("SUBPARTITION")) { + if (lexer.identifierEquals("SUBPARTITION")) { lexer.nextToken(); acceptIdentifier("OPTIONS"); accept(Token.LPAREN); @@ -703,7 +703,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { subPartitionByClause.getOptions().add(option); } - if (identifierEquals("SUBPARTITIONS")) { + if (lexer.identifierEquals("SUBPARTITIONS")) { lexer.nextToken(); Number intValue = lexer.integerValue(); SQLNumberExpr numExpr = new SQLNumberExpr(intValue); @@ -720,7 +720,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } private boolean parseTableOptionCharsetOrCollate(MySqlCreateTableStatement stmt) { - if (identifierEquals("CHARACTER")) { + if (lexer.identifierEquals("CHARACTER")) { lexer.nextToken(); accept(Token.SET); if (lexer.token() == Token.EQ) { @@ -730,7 +730,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { return true; } - if (identifierEquals("CHARSET")) { + if (lexer.identifierEquals("CHARSET")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -739,7 +739,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { return true; } - if (identifierEquals("COLLATE")) { + if (lexer.identifierEquals("COLLATE")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); @@ -783,7 +783,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { } // 5.5语法 USING BTREE 放在index 名字后 - if (identifierEquals("USING")) { + if (lexer.identifierEquals("USING")) { lexer.nextToken(); key.setIndexType(lexer.stringVal()); lexer.nextToken(); @@ -813,7 +813,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { key.setName(name); } - if (identifierEquals("USING")) { + if (lexer.identifierEquals("USING")) { lexer.nextToken(); key.setIndexType(lexer.stringVal()); lexer.nextToken(); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java index df6f5792df..b60bbd0589 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java @@ -57,6 +57,7 @@ import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.Token; +import com.alibaba.druid.util.FNVUtils; import com.alibaba.druid.util.JdbcConstants; public class MySqlExprParser extends SQLExprParser { @@ -85,7 +86,7 @@ public class MySqlExprParser extends SQLExprParser { } public SQLExpr relationalRest(SQLExpr expr) { - if (identifierEquals("REGEXP")) { + if (lexer.identifierEquals(FNVUtils.REGEXP)) { lexer.nextToken(); SQLExpr rightExp = equality(); @@ -117,7 +118,7 @@ public class MySqlExprParser extends SQLExprParser { } public SQLExpr notRationalRest(SQLExpr expr) { - if (identifierEquals("REGEXP")) { + if (lexer.identifierEquals("REGEXP")) { lexer.nextToken(); SQLExpr rightExp = primary(); @@ -132,7 +133,7 @@ public class MySqlExprParser extends SQLExprParser { public SQLExpr primary() { final Token tok = lexer.token(); - if (identifierEquals("outfile")) { + if (lexer.identifierEquals(FNVUtils.OUTFILE)) { lexer.nextToken(); SQLExpr file = primary(); SQLExpr expr = new MySqlOutFileExpr(file); @@ -214,7 +215,7 @@ public class MySqlExprParser extends SQLExprParser { MySqlCharExpr mysqlCharExpr = new MySqlCharExpr(charValue); mysqlCharExpr.setCharset(identExpr.getName()); - if (identifierEquals("COLLATE")) { + if (lexer.identifierEquals("COLLATE")) { lexer.nextToken(); String collate = lexer.stringVal(); @@ -398,7 +399,7 @@ public class MySqlExprParser extends SQLExprParser { if (lexer.token() == Token.IN) { lexer.nextToken(); - if (identifierEquals("NATURAL")) { + if (lexer.identifierEquals("NATURAL")) { lexer.nextToken(); acceptIdentifier("LANGUAGE"); acceptIdentifier("MODE"); @@ -410,7 +411,7 @@ public class MySqlExprParser extends SQLExprParser { } else { matchAgainstExpr.setSearchModifier(SearchModifier.IN_NATURAL_LANGUAGE_MODE); } - } else if (identifierEquals("BOOLEAN")) { + } else if (lexer.identifierEquals("BOOLEAN")) { lexer.nextToken(); acceptIdentifier("MODE"); matchAgainstExpr.setSearchModifier(SearchModifier.IN_BOOLEAN_MODE); @@ -434,7 +435,7 @@ public class MySqlExprParser extends SQLExprParser { exprList(methodInvokeExpr.getParameters(), methodInvokeExpr); } - if (identifierEquals("USING")) { + if (lexer.identifierEquals(FNVUtils.USING)) { lexer.nextToken(); if (lexer.token() != Token.IDENTIFIER) { throw new ParserException("syntax error. " + lexer.info()); @@ -556,12 +557,12 @@ public class MySqlExprParser extends SQLExprParser { SQLExpr expr = this.expr(); column.setOnUpdate(expr); } - if (identifierEquals("CHARSET")) { + if (lexer.identifierEquals("CHARSET")) { lexer.nextToken(); MySqlCharExpr charSetCollateExpr=new MySqlCharExpr(); charSetCollateExpr.setCharset(lexer.stringVal()); lexer.nextToken(); - if (identifierEquals("COLLATE")) { + if (lexer.identifierEquals("COLLATE")) { lexer.nextToken(); charSetCollateExpr.setCollate(lexer.stringVal()); lexer.nextToken(); @@ -569,13 +570,13 @@ public class MySqlExprParser extends SQLExprParser { column.setCharsetExpr(charSetCollateExpr); return parseColumnRest(column); } - if (identifierEquals("AUTO_INCREMENT")) { + if (lexer.identifierEquals("AUTO_INCREMENT")) { lexer.nextToken(); column.setAutoIncrement(true); return parseColumnRest(column); } - if (identifierEquals("precision") && column.getDataType().getName().equalsIgnoreCase("double")) { + if (lexer.identifierEquals("precision") && column.getDataType().getName().equalsIgnoreCase("double")) { lexer.nextToken(); } @@ -583,7 +584,7 @@ public class MySqlExprParser extends SQLExprParser { throw new ParserException("syntax error " + lexer.info()); } - if (identifierEquals("STORAGE")) { + if (lexer.identifierEquals("STORAGE")) { lexer.nextToken(); SQLExpr expr = expr(); column.setStorage(expr); @@ -597,12 +598,12 @@ public class MySqlExprParser extends SQLExprParser { accept(Token.RPAREN); } - if (identifierEquals("STORED")) { + if (lexer.identifierEquals("STORED")) { lexer.nextToken(); column.setSorted(true); } - if (identifierEquals("VIRTUAL")) { + if (lexer.identifierEquals("VIRTUAL")) { lexer.nextToken(); column.setVirtual(true); } @@ -615,12 +616,12 @@ public class MySqlExprParser extends SQLExprParser { protected SQLDataType parseDataTypeRest(SQLDataType dataType) { super.parseDataTypeRest(dataType); - if (identifierEquals("UNSIGNED")) { + if (lexer.identifierEquals("UNSIGNED")) { lexer.nextToken(); dataType.getAttributes().put("UNSIGNED", true); } - if (identifierEquals("ZEROFILL")) { + if (lexer.identifierEquals("ZEROFILL")) { lexer.nextToken(); dataType.getAttributes().put("ZEROFILL", true); } @@ -708,7 +709,7 @@ public class MySqlExprParser extends SQLExprParser { accept(Token.LITERAL_CHARS); } - if (identifierEquals("COLLATE")) { + if (lexer.identifierEquals("COLLATE")) { MySqlCharExpr charsetExpr = new MySqlCharExpr(charset); lexer.nextToken(); @@ -779,7 +780,7 @@ public class MySqlExprParser extends SQLExprParser { MySqlPrimaryKey primaryKey = new MySqlPrimaryKey(); - if (identifierEquals("USING")) { + if (lexer.identifierEquals("USING")) { lexer.nextToken(); primaryKey.setIndexType(lexer.stringVal()); lexer.nextToken(); @@ -823,7 +824,7 @@ public class MySqlExprParser extends SQLExprParser { } //5.5语法 USING BTREE 放在index 名字后 - if (identifierEquals("USING")) { + if (lexer.identifierEquals("USING")) { lexer.nextToken(); unique.setIndexType(lexer.stringVal()); lexer.nextToken(); @@ -848,7 +849,7 @@ public class MySqlExprParser extends SQLExprParser { } accept(Token.RPAREN); - if (identifierEquals("USING")) { + if (lexer.identifierEquals("USING")) { lexer.nextToken(); unique.setIndexType(lexer.stringVal()); lexer.nextToken(); @@ -880,12 +881,12 @@ public class MySqlExprParser extends SQLExprParser { this.names(fk.getReferencedColumns()); accept(Token.RPAREN); - if (identifierEquals("MATCH")) { - if (identifierEquals("FULL")) { + if (lexer.identifierEquals("MATCH")) { + if (lexer.identifierEquals("FULL")) { fk.setReferenceMatch(Match.FULL); - } else if (identifierEquals("PARTIAL")) { + } else if (lexer.identifierEquals("PARTIAL")) { fk.setReferenceMatch(Match.PARTIAL); - } else if (identifierEquals("SIMPLE")) { + } else if (lexer.identifierEquals("SIMPLE")) { fk.setReferenceMatch(Match.SIMPLE); } } @@ -913,19 +914,19 @@ public class MySqlExprParser extends SQLExprParser { protected Option parseReferenceOption() { Option option; - if (lexer.token() == Token.RESTRICT || identifierEquals("RESTRICT")) { + if (lexer.token() == Token.RESTRICT || lexer.identifierEquals("RESTRICT")) { option = Option.RESTRICT; lexer.nextToken(); - } else if (identifierEquals("CASCADE")) { + } else if (lexer.identifierEquals("CASCADE")) { option = Option.CASCADE; lexer.nextToken(); } else if (lexer.token() == Token.SET) { lexer.nextToken(); accept(Token.NULL); option = Option.SET_NULL; - } else if (identifierEquals("ON")) { + } else if (lexer.identifierEquals("ON")) { lexer.nextToken(); - if (identifierEquals("ACTION")) { + if (lexer.identifierEquals("ACTION")) { option = Option.NO_ACTION; lexer.nextToken(); } else { @@ -945,7 +946,7 @@ public class MySqlExprParser extends SQLExprParser { SQLOrderBy orderBy = this.parseOrderBy(); aggregateExpr.putAttribute("ORDER BY", orderBy); } - if (identifierEquals("SEPARATOR")) { + if (lexer.identifierEquals("SEPARATOR")) { lexer.nextToken(); SQLExpr seperator = this.primary(); @@ -986,7 +987,7 @@ public class MySqlExprParser extends SQLExprParser { for (;;) { boolean storage = false; - if (identifierEquals("DATA")) { + if (lexer.identifierEquals("DATA")) { lexer.nextToken(); acceptIdentifier("DIRECTORY"); if (lexer.token() == Token.EQ) { @@ -1007,22 +1008,22 @@ public class MySqlExprParser extends SQLExprParser { lexer.nextToken(); } partitionDef.setIndexDirectory(this.expr()); - } else if (identifierEquals("MAX_ROWS")) { + } else if (lexer.identifierEquals("MAX_ROWS")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); } SQLExpr maxRows = this.primary(); partitionDef.setMaxRows(maxRows); - } else if (identifierEquals("MIN_ROWS")) { + } else if (lexer.identifierEquals("MIN_ROWS")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); } SQLExpr minRows = this.primary(); partitionDef.setMaxRows(minRows); - } else if (identifierEquals("ENGINE") || // - (storage = (lexer.token() == Token.STORAGE || identifierEquals("STORAGE")))) { + } else if (lexer.identifierEquals("ENGINE") || // + (storage = (lexer.token() == Token.STORAGE || lexer.identifierEquals("STORAGE")))) { if (storage) { lexer.nextToken(); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java index e20a639f5f..22b1507e59 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java @@ -21,11 +21,7 @@ import static com.alibaba.druid.sql.parser.LayoutCharacters.EOI; import java.util.HashMap; import java.util.Map; -import com.alibaba.druid.sql.parser.Keywords; -import com.alibaba.druid.sql.parser.Lexer; -import com.alibaba.druid.sql.parser.NotAllowCommentException; -import com.alibaba.druid.sql.parser.ParserException; -import com.alibaba.druid.sql.parser.Token; +import com.alibaba.druid.sql.parser.*; public class MySqlLexer extends Lexer { @@ -216,6 +212,9 @@ public class MySqlLexer extends Lexer { } public void scanIdentifier() { + hash_lower = 0; + hash = 0; + final char first = ch; if (ch == 'b' && charAt(pos + 1) == '\'') { @@ -274,9 +273,14 @@ public class MySqlLexer extends Lexer { throw new ParserException("illegal identifier. " + info()); } - long hashCode = 0xcbf29ce484222325L; - hashCode ^= ((ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch); - hashCode *= 0x100000001b3L; + hash_lower = 0xcbf29ce484222325L; + hash = 0xcbf29ce484222325L; + + hash_lower ^= ((ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch); + hash_lower *= 0x100000001b3L; + + hash ^= ch; + hash *= 0x100000001b3L; mark = pos; bufPos = 1; @@ -290,25 +294,28 @@ public class MySqlLexer extends Lexer { bufPos++; - hashCode ^= ((ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch); - hashCode *= 0x100000001b3L; + hash_lower ^= ((ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch); + hash_lower *= 0x100000001b3L; + + hash ^= ch; + hash *= 0x100000001b3L; continue; } this.ch = charAt(pos); - Token tok = keywods.getKeyword(hashCode); + Token tok = keywods.getKeyword(hash_lower); if (tok != null) { token = tok; + if (token == Token.IDENTIFIER) { + stringVal = SymbolTable.global.addSymbol(text, mark, bufPos, hash); + } else { + stringVal = null; + } } else { token = Token.IDENTIFIER; - } - - if (token == Token.IDENTIFIER) { - stringVal = addSymbol(); - } else { - stringVal = null; + stringVal = SymbolTable.global.addSymbol(text, mark, bufPos, hash); } } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectIntoParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectIntoParser.java index d93a0ecc2f..fc35681c3e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectIntoParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectIntoParser.java @@ -93,7 +93,7 @@ public class MySqlSelectIntoParser extends SQLSelectParser { if (lexer.token() == (Token.DISTINCT)) { queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT); lexer.nextToken(); - } else if (identifierEquals("DISTINCTROW")) { + } else if (lexer.identifierEquals("DISTINCTROW")) { queryBlock.setDistionOption(SQLSetQuantifier.DISTINCTROW); lexer.nextToken(); } else if (lexer.token() == (Token.ALL)) { @@ -101,42 +101,42 @@ public class MySqlSelectIntoParser extends SQLSelectParser { lexer.nextToken(); } - if (identifierEquals("HIGH_PRIORITY")) { + if (lexer.identifierEquals("HIGH_PRIORITY")) { queryBlock.setHignPriority(true); lexer.nextToken(); } - if (identifierEquals("STRAIGHT_JOIN")) { + if (lexer.identifierEquals("STRAIGHT_JOIN")) { queryBlock.setStraightJoin(true); lexer.nextToken(); } - if (identifierEquals("SQL_SMALL_RESULT")) { + if (lexer.identifierEquals("SQL_SMALL_RESULT")) { queryBlock.setSmallResult(true); lexer.nextToken(); } - if (identifierEquals("SQL_BIG_RESULT")) { + if (lexer.identifierEquals("SQL_BIG_RESULT")) { queryBlock.setBigResult(true); lexer.nextToken(); } - if (identifierEquals("SQL_BUFFER_RESULT")) { + if (lexer.identifierEquals("SQL_BUFFER_RESULT")) { queryBlock.setBufferResult(true); lexer.nextToken(); } - if (identifierEquals("SQL_CACHE")) { + if (lexer.identifierEquals("SQL_CACHE")) { queryBlock.setCache(true); lexer.nextToken(); } - if (identifierEquals("SQL_NO_CACHE")) { + if (lexer.identifierEquals("SQL_NO_CACHE")) { queryBlock.setCache(false); lexer.nextToken(); } - if (identifierEquals("SQL_CALC_FOUND_ROWS")) { + if (lexer.identifierEquals("SQL_CALC_FOUND_ROWS")) { queryBlock.setCalcFoundRows(true); lexer.nextToken(); } @@ -217,7 +217,7 @@ public class MySqlSelectIntoParser extends SQLSelectParser { if (lexer.token() == (Token.INTO)) { lexer.nextToken(); - if (identifierEquals("OUTFILE")) { + if (lexer.identifierEquals("OUTFILE")) { lexer.nextToken(); MySqlOutFileExpr outFile = new MySqlOutFileExpr(); @@ -225,42 +225,42 @@ public class MySqlSelectIntoParser extends SQLSelectParser { queryBlock.setInto(outFile); - if (identifierEquals("FIELDS") || identifierEquals("COLUMNS")) { + if (lexer.identifierEquals("FIELDS") || lexer.identifierEquals("COLUMNS")) { lexer.nextToken(); - if (identifierEquals("TERMINATED")) { + if (lexer.identifierEquals("TERMINATED")) { lexer.nextToken(); accept(Token.BY); } outFile.setColumnsTerminatedBy((SQLLiteralExpr) expr()); - if (identifierEquals("OPTIONALLY")) { + if (lexer.identifierEquals("OPTIONALLY")) { lexer.nextToken(); outFile.setColumnsEnclosedOptionally(true); } - if (identifierEquals("ENCLOSED")) { + if (lexer.identifierEquals("ENCLOSED")) { lexer.nextToken(); accept(Token.BY); outFile.setColumnsEnclosedBy((SQLLiteralExpr) expr()); } - if (identifierEquals("ESCAPED")) { + if (lexer.identifierEquals("ESCAPED")) { lexer.nextToken(); accept(Token.BY); outFile.setColumnsEscaped((SQLLiteralExpr) expr()); } } - if (identifierEquals("LINES")) { + if (lexer.identifierEquals("LINES")) { lexer.nextToken(); - if (identifierEquals("STARTING")) { + if (lexer.identifierEquals("STARTING")) { lexer.nextToken(); accept(Token.BY); outFile.setLinesStartingBy((SQLLiteralExpr) expr()); } else { - identifierEquals("TERMINATED"); + lexer.identifierEquals("TERMINATED"); lexer.nextToken(); accept(Token.BY); outFile.setLinesTerminatedBy((SQLLiteralExpr) expr()); @@ -273,7 +273,7 @@ public class MySqlSelectIntoParser extends SQLSelectParser { } protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) { - if (identifierEquals("USING")) { + if (lexer.identifierEquals("USING")) { return tableSource; } @@ -284,14 +284,14 @@ public class MySqlSelectIntoParser extends SQLSelectParser { tableSource.getHints().add(hint); } - if (identifierEquals("IGNORE")) { + if (lexer.identifierEquals("IGNORE")) { lexer.nextToken(); MySqlIgnoreIndexHint hint = new MySqlIgnoreIndexHint(); parseIndexHint(hint); tableSource.getHints().add(hint); } - if (identifierEquals("FORCE")) { + if (lexer.identifierEquals("FORCE")) { lexer.nextToken(); MySqlForceIndexHint hint = new MySqlForceIndexHint(); parseIndexHint(hint); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java index 3e68c30ce4..688eb36468 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java @@ -35,6 +35,7 @@ import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.Token; +import com.alibaba.druid.util.FNVUtils; import java.util.List; @@ -99,53 +100,54 @@ public class MySqlSelectParser extends SQLSelectParser { this.exprParser.parseHints(queryBlock.getHints()); } - if (lexer.token() == (Token.DISTINCT)) { + Token token = lexer.token(); + if (token == (Token.DISTINCT)) { queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT); lexer.nextToken(); - } else if (identifierEquals("DISTINCTROW")) { + } else if (lexer.identifierEquals(FNVUtils.DISTINCTROW)) { queryBlock.setDistionOption(SQLSetQuantifier.DISTINCTROW); lexer.nextToken(); - } else if (lexer.token() == (Token.ALL)) { + } else if (token == (Token.ALL)) { queryBlock.setDistionOption(SQLSetQuantifier.ALL); lexer.nextToken(); } - if (identifierEquals("HIGH_PRIORITY")) { + if (lexer.identifierEquals(FNVUtils.HIGH_PRIORITY)) { queryBlock.setHignPriority(true); lexer.nextToken(); } - if (identifierEquals("STRAIGHT_JOIN")) { + if (lexer.identifierEquals(FNVUtils.STRAIGHT_JOIN)) { queryBlock.setStraightJoin(true); lexer.nextToken(); } - if (identifierEquals("SQL_SMALL_RESULT")) { + if (lexer.identifierEquals(FNVUtils.SQL_SMALL_RESULT)) { queryBlock.setSmallResult(true); lexer.nextToken(); } - if (identifierEquals("SQL_BIG_RESULT")) { + if (lexer.identifierEquals(FNVUtils.SQL_BIG_RESULT)) { queryBlock.setBigResult(true); lexer.nextToken(); } - if (identifierEquals("SQL_BUFFER_RESULT")) { + if (lexer.identifierEquals(FNVUtils.SQL_BUFFER_RESULT)) { queryBlock.setBufferResult(true); lexer.nextToken(); } - if (identifierEquals("SQL_CACHE")) { + if (lexer.identifierEquals(FNVUtils.SQL_CACHE)) { queryBlock.setCache(true); lexer.nextToken(); } - if (identifierEquals("SQL_NO_CACHE")) { + if (lexer.identifierEquals(FNVUtils.SQL_NO_CACHE)) { queryBlock.setCache(false); lexer.nextToken(); } - if (identifierEquals("SQL_CALC_FOUND_ROWS")) { + if (lexer.identifierEquals(FNVUtils.SQL_CALC_FOUND_ROWS)) { queryBlock.setCalcFoundRows(true); lexer.nextToken(); } @@ -182,10 +184,10 @@ public class MySqlSelectParser extends SQLSelectParser { queryBlock.setForUpdate(true); - if (identifierEquals("NO_WAIT") || identifierEquals("NOWAIT")) { + if (lexer.identifierEquals("NO_WAIT") || lexer.identifierEquals("NOWAIT")) { lexer.nextToken(); queryBlock.setNoWait(true); - } else if (identifierEquals("WAIT")) { + } else if (lexer.identifierEquals("WAIT")) { lexer.nextToken(); SQLExpr waitTime = this.exprParser.primary(); queryBlock.setWaitTime(waitTime); @@ -257,32 +259,32 @@ public class MySqlSelectParser extends SQLSelectParser { lexer.nextToken(); - if (identifierEquals("LOW_PRIORITY")) { + if (lexer.identifierEquals("LOW_PRIORITY")) { lexer.nextToken(); update.setLowPriority(true); } - if (identifierEquals("IGNORE")) { + if (lexer.identifierEquals("IGNORE")) { lexer.nextToken(); update.setIgnore(true); } - if (identifierEquals("COMMIT_ON_SUCCESS")) { + if (lexer.identifierEquals("COMMIT_ON_SUCCESS")) { lexer.nextToken(); update.setCommitOnSuccess(true); } - if (identifierEquals("ROLLBACK_ON_FAIL")) { + if (lexer.identifierEquals("ROLLBACK_ON_FAIL")) { lexer.nextToken(); update.setRollBackOnFail(true); } - if (identifierEquals("QUEUE_ON_PK")) { + if (lexer.identifierEquals("QUEUE_ON_PK")) { lexer.nextToken(); update.setQueryOnPk(true); } - if (identifierEquals("TARGET_AFFECT_ROW")) { + if (lexer.identifierEquals("TARGET_AFFECT_ROW")) { lexer.nextToken(); SQLExpr targetAffectRow = this.exprParser.expr(); update.setTargetAffectRow(targetAffectRow); @@ -319,7 +321,7 @@ public class MySqlSelectParser extends SQLSelectParser { if (lexer.token() == (Token.INTO)) { lexer.nextToken(); - if (identifierEquals("OUTFILE")) { + if (lexer.identifierEquals("OUTFILE")) { lexer.nextToken(); MySqlOutFileExpr outFile = new MySqlOutFileExpr(); @@ -327,42 +329,42 @@ public class MySqlSelectParser extends SQLSelectParser { queryBlock.setInto(outFile); - if (identifierEquals("FIELDS") || identifierEquals("COLUMNS")) { + if (lexer.identifierEquals("FIELDS") || lexer.identifierEquals("COLUMNS")) { lexer.nextToken(); - if (identifierEquals("TERMINATED")) { + if (lexer.identifierEquals("TERMINATED")) { lexer.nextToken(); accept(Token.BY); } outFile.setColumnsTerminatedBy(expr()); - if (identifierEquals("OPTIONALLY")) { + if (lexer.identifierEquals("OPTIONALLY")) { lexer.nextToken(); outFile.setColumnsEnclosedOptionally(true); } - if (identifierEquals("ENCLOSED")) { + if (lexer.identifierEquals("ENCLOSED")) { lexer.nextToken(); accept(Token.BY); outFile.setColumnsEnclosedBy((SQLLiteralExpr) expr()); } - if (identifierEquals("ESCAPED")) { + if (lexer.identifierEquals("ESCAPED")) { lexer.nextToken(); accept(Token.BY); outFile.setColumnsEscaped((SQLLiteralExpr) expr()); } } - if (identifierEquals("LINES")) { + if (lexer.identifierEquals("LINES")) { lexer.nextToken(); - if (identifierEquals("STARTING")) { + if (lexer.identifierEquals("STARTING")) { lexer.nextToken(); accept(Token.BY); outFile.setLinesStartingBy((SQLLiteralExpr) expr()); } else { - identifierEquals("TERMINATED"); + lexer.identifierEquals("TERMINATED"); lexer.nextToken(); accept(Token.BY); outFile.setLinesTerminatedBy((SQLLiteralExpr) expr()); @@ -395,14 +397,14 @@ public class MySqlSelectParser extends SQLSelectParser { tableSource.getHints().add(hint); } - if (identifierEquals("IGNORE")) { + if (lexer.identifierEquals("IGNORE")) { lexer.nextToken(); MySqlIgnoreIndexHint hint = new MySqlIgnoreIndexHint(); parseIndexHint(hint); tableSource.getHints().add(hint); } - if (identifierEquals("FORCE")) { + if (lexer.identifierEquals("FORCE")) { lexer.nextToken(); MySqlForceIndexHint hint = new MySqlForceIndexHint(); parseIndexHint(hint); @@ -420,7 +422,7 @@ public class MySqlSelectParser extends SQLSelectParser { } protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) { - if (identifierEquals("USING")) { + if (lexer.identifierEquals(FNVUtils.USING)) { return tableSource; } @@ -431,14 +433,14 @@ public class MySqlSelectParser extends SQLSelectParser { tableSource.getHints().add(hint); } - if (identifierEquals("IGNORE")) { + if (lexer.identifierEquals(FNVUtils.IGNORE)) { lexer.nextToken(); MySqlIgnoreIndexHint hint = new MySqlIgnoreIndexHint(); parseIndexHint(hint); tableSource.getHints().add(hint); } - if (identifierEquals("FORCE")) { + if (lexer.identifierEquals(FNVUtils.FORCE)) { lexer.nextToken(); MySqlForceIndexHint hint = new MySqlForceIndexHint(); parseIndexHint(hint); 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 dd8859c9f6..4e2f37f59e 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 @@ -149,12 +149,12 @@ public class MySqlStatementParser extends SQLStatementParser { this.getExprParser().parseHints(deleteStatement.getHints()); } - if (identifierEquals(LOW_PRIORITY)) { + if (lexer.identifierEquals(LOW_PRIORITY)) { deleteStatement.setLowPriority(true); lexer.nextToken(); } - if (identifierEquals("QUICK")) { + if (lexer.identifierEquals("QUICK")) { deleteStatement.setQuick(true); lexer.nextToken(); } 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 24c91fe855..6d774d6153 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 @@ -124,11 +124,12 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV print(' '); } - if (SQLSetQuantifier.ALL == x.getDistionOption()) { + final int distionOption = x.getDistionOption(); + if (SQLSetQuantifier.ALL == distionOption) { print0(ucase ? "ALL " : "all "); - } else if (SQLSetQuantifier.DISTINCT == x.getDistionOption()) { + } else if (SQLSetQuantifier.DISTINCT == distionOption) { print0(ucase ? "DISTINCT " : "distinct "); - } else if (SQLSetQuantifier.DISTINCTROW == x.getDistionOption()) { + } else if (SQLSetQuantifier.DISTINCTROW == distionOption) { print0(ucase ? "DISTINCTROW " : "distinctrow "); } diff --git a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java index 884d975af9..3448d8b446 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -40,6 +40,7 @@ import java.util.Arrays; import java.util.List; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; +import com.alibaba.druid.util.FNVUtils; import com.alibaba.druid.util.JdbcConstants; import com.alibaba.druid.util.StringUtils; @@ -62,6 +63,8 @@ public class Lexer { protected Keywords keywods = Keywords.DEFAULT_KEYWORDS; protected String stringVal; + protected long hash_lower; // fnv1a_64 + protected long hash; protected int commentCount = 0; @@ -1422,6 +1425,31 @@ public class Lexer { } return stringVal; } + + public final boolean identifierEquals(String text) { + if (token != Token.IDENTIFIER) { + return false; + } + + if (stringVal == null) { + stringVal = subString(mark, bufPos); + } + return text.equalsIgnoreCase(stringVal); + } + + public final boolean identifierEquals(long hash_lower) { + if (token != Token.IDENTIFIER) { + return false; + } + + if (this.hash_lower == 0) { + if (stringVal == null) { + stringVal = subString(mark, bufPos); + } + this.hash_lower = FNVUtils.fnv_64_lower(stringVal); + } + return this.hash_lower == hash_lower; + } public final List readAndResetComments() { List comments = this.comments; diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLCreateTableParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLCreateTableParser.java index a15e900ef7..11db2ed1d5 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLCreateTableParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLCreateTableParser.java @@ -60,10 +60,10 @@ public class SQLCreateTableParser extends SQLDDLParser { accept(Token.CREATE); } - if (identifierEquals("GLOBAL")) { + if (lexer.identifierEquals("GLOBAL")) { lexer.nextToken(); - if (identifierEquals("TEMPORARY")) { + if (lexer.identifierEquals("TEMPORARY")) { lexer.nextToken(); createTable.setType(SQLCreateTableStatement.Type.GLOBAL_TEMPORARY); } else { @@ -134,7 +134,7 @@ public class SQLCreateTableParser extends SQLDDLParser { accept(Token.RPAREN); - if (identifierEquals("INHERITS")) { + if (lexer.identifierEquals("INHERITS")) { lexer.nextToken(); accept(Token.LPAREN); SQLName inherits = this.exprParser.name(); 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 ef35e572d9..3c6d967981 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -44,6 +44,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.ast.statement.SQLUnique; import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr; +import com.alibaba.druid.util.FNVUtils; import com.alibaba.druid.util.JdbcConstants; public class SQLExprParser extends SQLParser { @@ -791,7 +792,7 @@ public class SQLExprParser extends SQLParser { expr = dotRest(expr); return primaryRest(expr); - } else if (identifierEquals("SETS") // + } else if (lexer.identifierEquals("SETS") // && expr.getClass() == SQLIdentifierExpr.class // && "GROUPING".equalsIgnoreCase(((SQLIdentifierExpr) expr).getName())) { SQLGroupingSetExpr groupingSets = new SQLGroupingSetExpr(); @@ -1661,7 +1662,7 @@ public class SQLExprParser extends SQLParser { rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Escape, rightExp, getDbType()); } - } else if (identifierEquals("RLIKE")) { + } else if (lexer.identifierEquals(FNVUtils.RLIKE)) { lexer.nextToken(); rightExp = equality(); diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java index 748406b56d..211850aa6c 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java @@ -50,11 +50,11 @@ public class SQLParser { } protected boolean identifierEquals(String text) { - return lexer.token() == Token.IDENTIFIER && lexer.stringVal().equalsIgnoreCase(text); + return lexer.identifierEquals(text); } protected void acceptIdentifier(String text) { - if (identifierEquals(text)) { + if (lexer.identifierEquals(text)) { lexer.nextToken(); } else { setErrorEndPos(lexer.pos()); diff --git a/src/main/java/com/alibaba/druid/sql/parser/SymbolTable.java b/src/main/java/com/alibaba/druid/sql/parser/SymbolTable.java new file mode 100644 index 0000000000..123b0d5bb5 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/parser/SymbolTable.java @@ -0,0 +1,59 @@ +package com.alibaba.druid.sql.parser; + +/** + * @author wenshao[szujobs@hotmail.com] + */ +public class SymbolTable { + public static SymbolTable global = new SymbolTable(8192); + + private final Entry[] entries; + private final int indexMask; + + public SymbolTable(int tableSize){ + this.indexMask = tableSize - 1; + this.entries = new Entry[tableSize]; + +// this.addSymbol("id", 0, 2, "id".hashCode()); + } + + + + public String addSymbol(String buffer, int offset, int len, long hash) { + final int bucket = ((int) hash) & indexMask; + + Entry entry = entries[bucket]; + if (entry != null) { + if (hash == entry.hash // + && len == entry.len) { + return entry.value; + } + + String str = subString(buffer, offset, len); + + return str; + } + + String str = subString(buffer, offset, len); + entry = new Entry(hash, len, str); + entries[bucket] = entry; + return str; + } + + private static String subString(String src, int offset, int len) { + char[] chars = new char[len]; + src.getChars(offset, offset + len, chars, 0); + return new String(chars); + } + + private static class Entry { + public final long hash; + public final int len; + public final String value; + + public Entry(long hash, int len, String value) { + this.hash = hash; + this.len = len; + this.value = value; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/alibaba/druid/sql/transform/SQLDataTypeTransform.java b/src/main/java/com/alibaba/druid/sql/transform/SQLDataTypeTransform.java new file mode 100644 index 0000000000..6f86a1c4e0 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/transform/SQLDataTypeTransform.java @@ -0,0 +1,20 @@ +/* + * 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.transform; + +public class SQLDataTypeTransform extends SQLTranformImpl { + +} diff --git a/src/main/java/com/alibaba/druid/sql/transform/SQLTranform.java b/src/main/java/com/alibaba/druid/sql/transform/SQLTranform.java new file mode 100644 index 0000000000..ab6b52b9c5 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/transform/SQLTranform.java @@ -0,0 +1,21 @@ +/* + * 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.transform; + +public interface SQLTranform { + String getSourceDbType(); + String getTargetDbType(); +} diff --git a/src/main/java/com/alibaba/druid/sql/transform/SQLTranformImpl.java b/src/main/java/com/alibaba/druid/sql/transform/SQLTranformImpl.java new file mode 100644 index 0000000000..81bd3ed611 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/transform/SQLTranformImpl.java @@ -0,0 +1,31 @@ +/* + * 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.transform; + +public abstract class SQLTranformImpl implements SQLTranform { + protected String sourceDbType; + protected String targetDbType; + + @Override + public String getSourceDbType() { + return sourceDbType; + } + + @Override + public String getTargetDbType() { + return targetDbType; + } +} 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 d1603c01c6..18b0c70d91 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -1523,7 +1523,15 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet if (x.isConnectByRoot()) { print0(ucase ? "CONNECT_BY_ROOT " : "connect_by_root "); } - x.getExpr().accept(this); + + SQLExpr expr = x.getExpr(); + + if (expr.getClass() == SQLIdentifierExpr.class) { + String ident = ((SQLIdentifierExpr) expr).getName(); + print0(ident); + } else { + expr.accept(this); + } String alias = x.getAlias(); if (alias != null && alias.length() > 0) { diff --git a/src/main/java/com/alibaba/druid/util/FNVUtils.java b/src/main/java/com/alibaba/druid/util/FNVUtils.java new file mode 100644 index 0000000000..d255d84a25 --- /dev/null +++ b/src/main/java/com/alibaba/druid/util/FNVUtils.java @@ -0,0 +1,90 @@ +/* + * 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.util; + +public class FNVUtils { + public final static long HIGH_PRIORITY = fnv_64_lower("HIGH_PRIORITY"); + public final static long DISTINCTROW = fnv_64_lower("DISTINCTROW"); + public final static long STRAIGHT_JOIN = fnv_64_lower("STRAIGHT_JOIN"); + public final static long SQL_SMALL_RESULT = fnv_64_lower("SQL_SMALL_RESULT"); + public final static long SQL_BIG_RESULT = fnv_64_lower("SQL_BIG_RESULT"); + public final static long SQL_BUFFER_RESULT = fnv_64_lower("SQL_BUFFER_RESULT"); + public final static long SQL_CACHE = fnv_64_lower("SQL_CACHE"); + public final static long SQL_NO_CACHE = fnv_64_lower("SQL_NO_CACHE"); + public final static long SQL_CALC_FOUND_ROWS = fnv_64_lower("SQL_CALC_FOUND_ROWS"); + public final static long OUTFILE = fnv_64_lower("OUTFILE"); + public final static long SETS = fnv_64_lower("SETS"); + public final static long REGEXP = fnv_64_lower("REGEXP"); + public final static long RLIKE = fnv_64_lower("RLIKE"); + public final static long USING = fnv_64_lower("USING"); + public final static long IGNORE = fnv_64_lower("IGNORE"); + public final static long FORCE = fnv_64_lower("FORCE"); + public final static long CROSS = fnv_64_lower("CROSS"); + public final static long NATURAL = fnv_64_lower("NATURAL"); + public final static long APPLY = fnv_64_lower("APPLY"); + public final static long CONNECT = fnv_64_lower("CONNECT"); + public final static long START = fnv_64_lower("START"); + + public static long fnv_64(String input) { + if (input == null) { + return 0; + } + + long hash = 0xcbf29ce484222325L; + for (int i = 0; i < input.length(); ++i) { + char c = input.charAt(i); + hash ^= c; + hash *= 0x100000001b3L; + } + + return hash; + } + + public static long fnv_64_lower(String key) { + long hashCode = 0xcbf29ce484222325L; + for (int i = 0; i < key.length(); ++i) { + char ch = key.charAt(i); + + if (ch >= 'A' && ch <= 'Z') { + ch = (char) (ch + 32); + } + + hashCode ^= ch; + hashCode *= 0x100000001b3L; + } + + return hashCode; + } + + public static long fnv_32_lower(String key) { + long hashCode = 0x811c9dc5; + for (int i = 0; i < key.length(); ++i) { + char ch = key.charAt(i); + if (ch == '_' || ch == '-') { + continue; + } + + if (ch >= 'A' && ch <= 'Z') { + ch = (char) (ch + 32); + } + + hashCode ^= ch; + hashCode *= 0x01000193; + } + + return hashCode; + } +} diff --git a/src/main/java/com/alibaba/druid/util/MySqlUtils.java b/src/main/java/com/alibaba/druid/util/MySqlUtils.java index edd8735652..1ee13964c6 100644 --- a/src/main/java/com/alibaba/druid/util/MySqlUtils.java +++ b/src/main/java/com/alibaba/druid/util/MySqlUtils.java @@ -128,6 +128,26 @@ public class MySqlUtils { return words.contains(name_lower); } + private static Set builtinDataTypes; + + public static boolean isBuiltinDataType(String dataType) { + if (dataType == null) { + return false; + } + + String table_lower = dataType.toLowerCase(); + + Set dataTypes = builtinDataTypes; + + if (dataTypes == null) { + dataTypes = new HashSet(); + Utils.loadFromFile("META-INF/druid/parser/mysql/builtin_datatypes", dataTypes); + builtinDataTypes = dataTypes; + } + + return dataTypes.contains(table_lower); + } + public static List showTables(Connection conn) throws SQLException { List tables = new ArrayList(); diff --git a/src/main/java/com/alibaba/druid/util/Utils.java b/src/main/java/com/alibaba/druid/util/Utils.java index 8e12e162d6..f8e3ba2c3a 100644 --- a/src/main/java/com/alibaba/druid/util/Utils.java +++ b/src/main/java/com/alibaba/druid/util/Utils.java @@ -409,53 +409,15 @@ public class Utils { } public static long fnv_64(String input) { - if (input == null) { - return 0; - } - - long hash = 0xcbf29ce484222325L; - for (int i = 0; i < input.length(); ++i) { - char c = input.charAt(i); - hash ^= c; - hash *= 0x100000001b3L; - } - - return hash; + return FNVUtils.fnv_64(input); } public static long fnv_64_lower(String key) { - long hashCode = 0xcbf29ce484222325L; - for (int i = 0; i < key.length(); ++i) { - char ch = key.charAt(i); - - if (ch >= 'A' && ch <= 'Z') { - ch = (char) (ch + 32); - } - - hashCode ^= ch; - hashCode *= 0x100000001b3L; - } - - return hashCode; + return FNVUtils.fnv_64_lower(key); } public static long fnv_32_lower(String key) { - long hashCode = 0x811c9dc5; - for (int i = 0; i < key.length(); ++i) { - char ch = key.charAt(i); - if (ch == '_' || ch == '-') { - continue; - } - - if (ch >= 'A' && ch <= 'Z') { - ch = (char) (ch + 32); - } - - hashCode ^= ch; - hashCode *= 0x01000193; - } - - return hashCode; + return FNVUtils.fnv_32_lower(key); } public static void loadFromFile(String path, Set set) { diff --git a/src/main/resources/META-INF/druid/parser/mysql/builtin_datatypes b/src/main/resources/META-INF/druid/parser/mysql/builtin_datatypes new file mode 100644 index 0000000000..e04b202db8 --- /dev/null +++ b/src/main/resources/META-INF/druid/parser/mysql/builtin_datatypes @@ -0,0 +1,32 @@ +INTEGER +TINYINT +SMALLINT +MEDIUMINT +INT +BIGINT +DECIMAL +NUMERIC +FLOAT +DOUBLE +BIT +DATE +DATETIME +TIMESTAMP +TIME +YEAR +CHAR +VARCHAR +NCHAR +NVARCHAR +BINARY +VARBINARY +MEDIUMBLOB +BLOB +BLOB +LONGBLOB +TINYTEXT +MEDIUMTEXT +TEXT +LONGTEXT +ENUM +SET \ No newline at end of file diff --git a/src/test/java/com/alibaba/druid/benckmark/sql/MySqlParameterizedBenchmark.java b/src/test/java/com/alibaba/druid/benckmark/sql/MySqlParameterizedBenchmark.java new file mode 100644 index 0000000000..b588af5146 --- /dev/null +++ b/src/test/java/com/alibaba/druid/benckmark/sql/MySqlParameterizedBenchmark.java @@ -0,0 +1,48 @@ +package com.alibaba.druid.benckmark.sql; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor; +import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; +import com.alibaba.druid.util.JdbcConstants; +import junit.framework.TestCase; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class MySqlParameterizedBenchmark extends TestCase { + + public void test_perf() throws Exception { + String sql = "select id as id, gmt_create as gmtCreate, gmt_modified as gmtModified, name as name, owner as owner, type as type, statement as statement, datasource as datasource, meta as meta, param_file as paramFile, sharable as sharable, data_type as dataType, status as status, config as config, project_id as projectId, plugins as plugins, field_compare as fieldCompare, field_ext as fieldExt, open as open from quark_s_dataset where id = 12569434"; + + for (int i = 0; i < 5; ++i) { +// perf(sql); // 6740 6201 + perf_parse(sql); // 4643 4377 + } + } + public void perf(String sql) { + long startMillis = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + + + String psql = SqlHolder.of(sql).parameterize(); +// stmt.toString(); + } + long millis = System.currentTimeMillis() - startMillis; + System.out.println("millis : " + millis); + } + + public void perf_parse(String sql) { + long startMillis = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + + + SqlHolder.of(sql).ensureParsed(); +// stmt.toString(); + } + long millis = System.currentTimeMillis() - startMillis; + System.out.println("millis : " + millis); + } +} diff --git a/src/test/java/com/alibaba/druid/benckmark/sql/SqlHolder.java b/src/test/java/com/alibaba/druid/benckmark/sql/SqlHolder.java new file mode 100644 index 0000000000..f715f314f6 --- /dev/null +++ b/src/test/java/com/alibaba/druid/benckmark/sql/SqlHolder.java @@ -0,0 +1,115 @@ +package com.alibaba.druid.benckmark.sql; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; +import com.alibaba.druid.sql.parser.ParserException; +import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; +import com.alibaba.druid.util.JdbcConstants; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.serializer.SerializerFeature; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; + +/** + * Created by kaiwang.ckw on 15/05/2017. + */ +public class SqlHolder { + private String text; + private String dialect; + + private boolean parsed; + private SQLStatement ast; + + public static SqlHolder of(String sql) { + return new SqlHolder(sql); + } + + SqlHolder(String text) { + this(text, JdbcConstants.MYSQL); + } + + SqlHolder(String text, String dialect) { + if (!"mysql".equalsIgnoreCase(dialect)) { + throw new IllegalArgumentException("only mysql is"); + } + + this.text = text; + this.dialect = dialect; + } + + public String format() { + try { + return SQLUtils.format(text, dialect); + } catch (ParserException e) { + throw new UnsupportedOperationException(e); + } + } + + public void ensureParsed() { + if (parsed) { + return; + } + // ast = SQLUtils.parseStatements(text, dialect).get(0); + try { + ast = new MySqlStatementParser(text).parseStatement(); + } catch (ParserException e) { + throw new UnsupportedOperationException(e); + } + parsed = true; + } + + // returns rewritten sql, or original string object if not rewritten + public String select() { + ensureParsed(); + + SQLStatement stmt = ast; + if (stmt instanceof SQLSelectStatement) { + boolean rewritten = StatementConverter.rewriteSelect((SQLSelectStatement) stmt); + if (rewritten) { + return SQLUtils.toMySqlString(stmt); + } else { + return text; + } + } else { + SQLSelectStatement selectStatement = StatementConverter.rewrite(stmt); + if (stmt == selectStatement) { + return text; + } else { + return SQLUtils.toMySqlString(selectStatement); + } + } + } + + public String parameterize() { + return parameterize(null, null); + } + + public String parameterize(Set physicalNames) { + ensureParsed(); + return Templates.parameterize(ast, physicalNames, null); + } + + public String parameterize(Set physicalNames, List params) { + ensureParsed(); + return Templates.parameterize(ast, physicalNames, params); + } + + + public String getParams() { + ensureParsed(); + StringBuilder out = new StringBuilder(); + SQLASTOutputVisitor visitor = SQLUtils.createOutputVisitor(out, JdbcConstants.MYSQL); + List parameters = new ArrayList(); + visitor.setParameterized(true); + visitor.setParameterizedMergeInList(true); + visitor.setParameters(parameters); + ast.accept(visitor); + String params = JSONArray.toJSONString(parameters, SerializerFeature.WriteClassName); + params = StringUtils.replace(params, "\"", "\\\""); + return params; + } +} diff --git a/src/test/java/com/alibaba/druid/benckmark/sql/StatementConverter.java b/src/test/java/com/alibaba/druid/benckmark/sql/StatementConverter.java new file mode 100644 index 0000000000..0a20485613 --- /dev/null +++ b/src/test/java/com/alibaba/druid/benckmark/sql/StatementConverter.java @@ -0,0 +1,84 @@ +package com.alibaba.druid.benckmark.sql; + +import com.alibaba.druid.sql.ast.SQLExpr; +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; + +/** + * Created by kaiwang.ckw on 15/05/2017. + */ +public class StatementConverter { + + // remove 'for update' from 'select ... for update' + public static boolean rewriteSelect(SQLSelectStatement stmt) { + SQLSelectQuery q = stmt.getSelect().getQuery(); + if (q instanceof MySqlSelectQueryBlock) { + MySqlSelectQueryBlock qb = (MySqlSelectQueryBlock) q; + if (qb.isForUpdate()) { + qb.setForUpdate(false); + return true; + } + } + return false; + } + + // construct a 'select' from other types of dml + public static SQLSelectStatement rewrite(SQLStatement stmt) { + SQLSelectStatement selectStmt; + if (stmt instanceof SQLSelectStatement) { + throw new RuntimeException("please use rewriteSelect which does ast modification instead of construction"); + } else if (stmt instanceof SQLUpdateStatement) { + SQLTableSource tableSource = ((SQLUpdateStatement) stmt).getTableSource(); + SQLExpr where = ((SQLUpdateStatement) stmt).getWhere(); + String dbType = ((SQLUpdateStatement) stmt).getDbType(); + selectStmt = buildSelect(tableSource, where, dbType); + } else if (stmt instanceof SQLDeleteStatement) { + SQLTableSource tableSource = ((SQLDeleteStatement) stmt).getTableSource(); + SQLExpr where = ((SQLDeleteStatement) stmt).getWhere(); + String dbType = ((SQLDeleteStatement) stmt).getDbType(); + selectStmt = buildSelect(tableSource, where, dbType); + } else if (stmt instanceof SQLInsertStatement) { + SQLSelect sqlSelect = ((SQLInsertStatement) stmt).getQuery(); + if (sqlSelect != null) { + selectStmt = new SQLSelectStatement(); + selectStmt.setSelect(sqlSelect); + } else { + throw new UnsupportedOperationException("only insert..select.. is supported"); + } + } else if (stmt instanceof MySqlReplaceStatement) { + SQLQueryExpr sqlQueryExpr = ((MySqlReplaceStatement) stmt).getQuery(); + if (sqlQueryExpr != null) { + SQLSelect sqlSelect = ((MySqlReplaceStatement) stmt).getQuery().getSubQuery(); + selectStmt = new SQLSelectStatement(); + selectStmt.setSelect(sqlSelect); + } else { + throw new UnsupportedOperationException("only replace..select.. is supported"); + } + } else { + throw new UnsupportedOperationException("only select/update/delete/insert/replace are supported"); + } + return selectStmt; + } + + // build 'select * from ...' + static SQLSelectStatement buildSelect(SQLTableSource tableSource, SQLExpr where, String dbType) { + SQLSelectQueryBlock sqlSelectQuery = new SQLSelectQueryBlock(); + sqlSelectQuery.addSelectItem(new SQLSelectItem(new SQLAllColumnExpr())); + sqlSelectQuery.setWhere(where); + sqlSelectQuery.setFrom(tableSource); + tableSource.setParent(sqlSelectQuery); + + SQLSelect sqlSelect = new SQLSelect(); + sqlSelect.setQuery(sqlSelectQuery); + + SQLSelectStatement selectStmt = new SQLSelectStatement(); + selectStmt.setSelect(sqlSelect); + selectStmt.setDbType(dbType); + + return selectStmt; + } +} diff --git a/src/test/java/com/alibaba/druid/benckmark/sql/Templates.java b/src/test/java/com/alibaba/druid/benckmark/sql/Templates.java new file mode 100644 index 0000000000..0dfba9b8e0 --- /dev/null +++ b/src/test/java/com/alibaba/druid/benckmark/sql/Templates.java @@ -0,0 +1,51 @@ +package com.alibaba.druid.benckmark.sql; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor; +import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Created by kaiwang.ckw on 15/05/2017. + */ +public class Templates { + + public static final String UNKNOWN = "UNKNOWN"; + + public static String parameterize(SQLStatement ast, Set physicalNames, List params) { + + List parameters = null; + StringBuilder out = new StringBuilder(); + SQLASTOutputVisitor visitor = new MySqlOutputVisitor(out); + visitor.setParameterized(true); + visitor.setParameterizedMergeInList(true); + if (physicalNames != null) { + visitor.setExportTables(true); + } + if (params != null) { + parameters = new ArrayList(); + visitor.setParameters(parameters); + } + visitor.setPrettyFormat(false); + ast.accept(visitor); + + if (physicalNames != null) { + Set tableSet = visitor.getTables(); + if (tableSet != null) { + physicalNames.addAll(tableSet); + } + } + if (params != null) { + if (!parameters.isEmpty()) { + params.addAll(parameters); + } + } + + String sqlTemplate = out.toString(); + return sqlTemplate; + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest75_comment.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest75_comment.java new file mode 100644 index 0000000000..d1c5077695 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest75_comment.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.oracle.select; + +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 org.junit.Assert; + +import java.util.List; + +public class OracleSelectTest75_comment extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "--CMS???'?o??\n" + + "SELECT *\n" + + "FROM CDM.CDM_CON_ISSUE_DATE_CONTROL@ERPCMS idc\n" + + "WHERE idc.ecc_contract_header_id = ?"; // + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + stmt.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("relationships : " + visitor.getRelationships()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + assertEquals(1, visitor.getTables().size()); + + assertEquals(2, visitor.getColumns().size()); + + { + String text = SQLUtils.toOracleString(stmt); + + assertEquals("-- CMS???'?o??\n" + + "SELECT *\n" + + "FROM CDM.CDM_CON_ISSUE_DATE_CONTROL@ERPCMS idc\n" + + "WHERE idc.ecc_contract_header_id = ?", text); + } + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("acduser.vw_acd_info", "xzqh"))); + + // Assert.assertTrue(visitor.getOrderByColumns().contains(new TableStat.Column("employees", "last_name"))); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/utils/MySqlUtils_1_builtin_dataTypes.java b/src/test/java/com/alibaba/druid/bvt/utils/MySqlUtils_1_builtin_dataTypes.java new file mode 100644 index 0000000000..9adac0d889 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/utils/MySqlUtils_1_builtin_dataTypes.java @@ -0,0 +1,12 @@ +package com.alibaba.druid.bvt.utils; + +import com.alibaba.druid.util.MySqlUtils; +import junit.framework.TestCase; + +public class MySqlUtils_1_builtin_dataTypes extends TestCase { + public void test_builtin_dataTypes() throws Exception { + assertTrue(MySqlUtils.isBuiltinDataType("decimal")); + assertTrue(MySqlUtils.isBuiltinDataType("INT")); + assertFalse(MySqlUtils.isBuiltinDataType("decimalx")); + } +}