diff --git a/src/main/java/com/alibaba/druid/mock/handler/MySqlMockExecuteHandlerImpl.java b/src/main/java/com/alibaba/druid/mock/handler/MySqlMockExecuteHandlerImpl.java index 9edbd00ca1..0146edbfcd 100644 --- a/src/main/java/com/alibaba/druid/mock/handler/MySqlMockExecuteHandlerImpl.java +++ b/src/main/java/com/alibaba/druid/mock/handler/MySqlMockExecuteHandlerImpl.java @@ -143,7 +143,7 @@ public class MySqlMockExecuteHandlerImpl implements MockExecuteHandler { row[i] = ((SQLNCharExpr) expr).getText(); column.setColumnType(Types.NVARCHAR); } else if (expr instanceof SQLBooleanExpr) { - row[i] = ((SQLBooleanExpr) expr).getValue(); + row[i] = ((SQLBooleanExpr) expr).getBooleanValue(); column.setColumnType(Types.NVARCHAR); } else if (expr instanceof SQLNullExpr) { row[i] = null; diff --git a/src/main/java/com/alibaba/druid/sql/SQLTransformUtils.java b/src/main/java/com/alibaba/druid/sql/SQLTransformUtils.java new file mode 100644 index 0000000000..27ac4d689c --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/SQLTransformUtils.java @@ -0,0 +1,91 @@ +/* + * 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; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.expr.*; + +import java.util.List; + +public class SQLTransformUtils { + public static SQLExpr transformDecode(SQLMethodInvokeExpr x) { + if (x == null) { + return null; + } + + if (!"decode".equalsIgnoreCase(x.getMethodName())) { + throw new IllegalArgumentException(x.getMethodName()); + } + + List parameters = x.getParameters(); + SQLCaseExpr caseExpr = new SQLCaseExpr(); + caseExpr.setParent(x.getParent()); + caseExpr.setValueExpr(parameters.get(0)); + + if (parameters.size() == 4) { + SQLExpr param1 = parameters.get(1); + + x.setMethodName("if"); + + SQLBinaryOpExpr condition; + if (param1 instanceof SQLNullExpr) { + condition = new SQLBinaryOpExpr(parameters.get(0), SQLBinaryOperator.Is, param1); + } else { + condition = new SQLBinaryOpExpr(parameters.get(0), SQLBinaryOperator.Equality, param1); + } + condition.setParent(x); + parameters.set(0, condition); + parameters.set(1, parameters.get(2)); + parameters.set(2, parameters.get(3)); + parameters.remove(3); + return x; + } + + for (int i = 1; i + 1 < parameters.size(); i += 2) { + SQLCaseExpr.Item item = new SQLCaseExpr.Item(); + SQLExpr conditionExpr = parameters.get(i); + + item.setConditionExpr(conditionExpr); + + SQLExpr valueExpr = parameters.get(i + 1); + + if (valueExpr instanceof SQLMethodInvokeExpr) { + SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) valueExpr; + if ("decode".equalsIgnoreCase(methodInvokeExpr.getMethodName())) { + valueExpr = transformDecode(methodInvokeExpr); + } + } + + item.setValueExpr(valueExpr); + caseExpr.addItem(item); + } + + if (parameters.size() % 2 == 0) { + SQLExpr defaultExpr = parameters.get(parameters.size() - 1); + + if (defaultExpr instanceof SQLMethodInvokeExpr) { + SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) defaultExpr; + if ("decode".equalsIgnoreCase(methodInvokeExpr.getMethodName())) { + defaultExpr = transformDecode(methodInvokeExpr); + } + } + + caseExpr.setElseExpr(defaultExpr); + } + + return caseExpr; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index 1cde04911c..ee1b990d25 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -863,53 +863,8 @@ public class SQLUtils { return false; } - public static SQLCaseExpr decodeToCase(SQLMethodInvokeExpr x) { - if (x == null) { - return null; - } - - if (!"decode".equalsIgnoreCase(x.getMethodName())) { - throw new IllegalArgumentException(x.getMethodName()); - } - - List parameters = x.getParameters(); - SQLCaseExpr caseExpr = new SQLCaseExpr(); - caseExpr.setParent(x.getParent()); - caseExpr.setValueExpr(parameters.get(0)); - - for (int i = 1; i + 1 < parameters.size(); i += 2) { - SQLCaseExpr.Item item = new SQLCaseExpr.Item(); - SQLExpr conditionExpr = parameters.get(i); - - item.setConditionExpr(conditionExpr); - - SQLExpr valueExpr = parameters.get(i + 1); - - if (valueExpr instanceof SQLMethodInvokeExpr) { - SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) valueExpr; - if ("decode".equalsIgnoreCase(methodInvokeExpr.getMethodName())) { - valueExpr = decodeToCase(methodInvokeExpr); - } - } - - item.setValueExpr(valueExpr); - caseExpr.addItem(item); - } - - if (parameters.size() % 2 == 0) { - SQLExpr defaultExpr = parameters.get(parameters.size() - 1); - - if (defaultExpr instanceof SQLMethodInvokeExpr) { - SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) defaultExpr; - if ("decode".equalsIgnoreCase(methodInvokeExpr.getMethodName())) { - defaultExpr = decodeToCase(methodInvokeExpr); - } - } - - caseExpr.setElseExpr(defaultExpr); - } - - return caseExpr; + public static SQLExpr decodeToCase(SQLMethodInvokeExpr x) { + return SQLTransformUtils.transformDecode(x); } public static boolean replaceInParent(SQLExpr expr, SQLExpr target) { diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java index 737d8d9293..f35d115a15 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java @@ -23,7 +23,7 @@ import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLAggregateExpr extends SQLExprImpl implements Serializable { +public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLReplaceable { private static final long serialVersionUID = 1L; protected String methodName; @@ -223,4 +223,18 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable { return null; } + + public boolean replace(SQLExpr expr, SQLExpr target) { + if (target == null) { + return false; + } + for (int i = 0; i < arguments.size(); ++i) { + if (arguments.get(i) == expr) { + arguments.set(i, target); + target.setParent(this); + return true; + } + } + return false; + } } 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 f434954b1d..473faa28b0 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 @@ -16,9 +16,11 @@ package com.alibaba.druid.sql.ast.expr; 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 { + private transient SQLTableSource resolvedTableSource; public SQLAllColumnExpr(){ @@ -42,6 +44,17 @@ public class SQLAllColumnExpr extends SQLExprImpl { } public SQLAllColumnExpr clone() { - return new SQLAllColumnExpr(); + SQLAllColumnExpr x = new SQLAllColumnExpr(); + + x.resolvedTableSource = resolvedTableSource; + return x; + } + + public SQLTableSource getResolvedTableSource() { + return resolvedTableSource; + } + + public void setResolvedTableSource(SQLTableSource resolvedTableSource) { + this.resolvedTableSource = resolvedTableSource; } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryExpr.java index 8aa6fecab0..12cbd0b664 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryExpr.java @@ -18,7 +18,7 @@ package com.alibaba.druid.sql.ast.expr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLBinaryExpr extends SQLExprImpl implements SQLLiteralExpr { +public class SQLBinaryExpr extends SQLExprImpl implements SQLLiteralExpr, SQLValuableExpr { private String value; 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 09b95b9f9c..cd1e32f4f5 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 { +public class SQLBooleanExpr extends SQLExprImpl implements SQLExpr, SQLLiteralExpr, SQLValuableExpr { public static final SQLDataType DEFAULT_DATA_TYPE = new SQLCharacterDataType("boolean"); private boolean value; @@ -34,7 +34,11 @@ public class SQLBooleanExpr extends SQLExprImpl implements SQLExpr, SQLLiteralEx this.value = value; } - public boolean getValue() { + public boolean getBooleanValue() { + return value; + } + + public Boolean getValue() { return value; } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java index 774ba6cb68..9b18daa02b 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java @@ -19,6 +19,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -270,4 +271,8 @@ public class SQLCaseExpr extends SQLExprImpl implements SQLReplaceable, Serializ return null; } + + public String toString() { + return SQLUtils.toSQLString(this, null); + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLDateExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLDateExpr.java index fe73df2db7..f3cad98ba3 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLDateExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLDateExpr.java @@ -22,7 +22,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleExpr; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class SQLDateExpr extends SQLExprImpl implements SQLLiteralExpr { +public class SQLDateExpr extends SQLExprImpl implements SQLLiteralExpr, SQLValuableExpr { public static final SQLDataType DEFAULT_DATA_TYPE = new SQLCharacterDataType("date"); private String literal; @@ -43,6 +43,10 @@ public class SQLDateExpr extends SQLExprImpl implements SQLLiteralExpr { this.literal = literal; } + public String getValue() { + return literal; + } + @Override protected void accept0(SQLASTVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLHexExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLHexExpr.java index 2e839f259c..63e8c03134 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLHexExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLHexExpr.java @@ -19,7 +19,7 @@ import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; import com.alibaba.druid.util.HexBin; -public class SQLHexExpr extends SQLExprImpl implements SQLLiteralExpr { +public class SQLHexExpr extends SQLExprImpl implements SQLLiteralExpr, SQLValuableExpr { private final String hex; @@ -84,4 +84,8 @@ public class SQLHexExpr extends SQLExprImpl implements SQLLiteralExpr { public SQLHexExpr clone () { return new SQLHexExpr(hex); } + + public byte[] getValue() { + return toBytes(); + } } 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 e8028f8abf..b706b6012e 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 @@ -135,7 +135,10 @@ public class SQLIdentifierExpr extends SQLExprImpl implements SQLName { } public SQLIdentifierExpr clone() { - return new SQLIdentifierExpr(this.name); + SQLIdentifierExpr x = new SQLIdentifierExpr(this.name); + x.resolvedColumn = resolvedColumn; + x.resolvedTableSource = resolvedTableSource; + return x; } public String normalizedName() { diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLMethodInvokeExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLMethodInvokeExpr.java index 3d9678df7e..4d4837e4c8 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLMethodInvokeExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLMethodInvokeExpr.java @@ -35,6 +35,7 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable, private final List parameters = new ArrayList(); private SQLExpr from; + private SQLExpr using; public SQLMethodInvokeExpr(){ @@ -173,6 +174,10 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable, x.setFrom(from.clone()); } + if (using != null) { + x.setUsing(using.clone()); + } + return x; } @@ -216,6 +221,11 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable, } public SQLDataType computeDataType() { + if (SQLUtils.nameEquals("to_date", methodName) + || SQLUtils.nameEquals("add_months", methodName)) { + return SQLDateExpr.DEFAULT_DATA_TYPE; + } + if (parameters.size() == 1) { if (SQLUtils.nameEquals("trunc", methodName)) { return parameters.get(0).computeDataType(); @@ -234,4 +244,15 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable, } return null; } + + public SQLExpr getUsing() { + return using; + } + + public void setUsing(SQLExpr using) { + if (using != null) { + using.setParent(this); + } + this.using = using; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNumberExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNumberExpr.java index 22c97d1926..5d6b874964 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNumberExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNumberExpr.java @@ -22,7 +22,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; import java.io.IOException; import java.math.BigDecimal; -public class SQLNumberExpr extends SQLNumericLiteralExpr { +public class SQLNumberExpr extends SQLNumericLiteralExpr implements SQLValuableExpr { private static SQLDataType defaultDataType = new SQLDataTypeImpl("number"); private Number number; @@ -48,6 +48,10 @@ public class SQLNumberExpr extends SQLNumericLiteralExpr { return this.number; } + public Number getValue() { + return getNumber(); + } + public void setNumber(Number number) { this.number = number; this.chars = null; 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 9d04a6b016..c04a2386f4 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 @@ -133,12 +133,16 @@ public class SQLPropertyExpr extends SQLExprImpl implements SQLName { } public SQLPropertyExpr clone() { - SQLPropertyExpr propertyExpr = new SQLPropertyExpr(); - propertyExpr.name = this.name; + SQLPropertyExpr x = new SQLPropertyExpr(); + x.name = this.name; if (owner != null) { - propertyExpr.setOwner(owner.clone()); + x.setOwner(owner.clone()); } - return propertyExpr; + + x.resolvedColumn = resolvedColumn; + x.resolvedTableSource = resolvedTableSource; + + return x; } public boolean matchOwner(String alias) { diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLTimestampExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLTimestampExpr.java index d045ca8caf..a63d5afefb 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLTimestampExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLTimestampExpr.java @@ -21,7 +21,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; * See the License for the specific language governing permissions and * limitations under the License. */ -public class SQLTimestampExpr extends SQLExprImpl { +public class SQLTimestampExpr extends SQLExprImpl implements SQLValuableExpr { public static final SQLDataType DEFAULT_DATA_TYPE = new SQLCharacterDataType("datetime"); protected String literal; @@ -40,6 +40,10 @@ public class SQLTimestampExpr extends SQLExprImpl { return x; } + public String getValue() { + return literal; + } + public String getLiteral() { return literal; } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java index 24db15bb76..62d89d5982 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java @@ -16,10 +16,7 @@ package com.alibaba.druid.sql.ast.statement; 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.SQLObjectImpl; -import com.alibaba.druid.sql.ast.SQLReplaceable; +import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; @@ -180,7 +177,12 @@ public class SQLSelectItem extends SQLObjectImpl implements SQLReplaceable { } if (expr instanceof SQLAllColumnExpr) { - return true; + SQLTableSource resolvedTableSource = ((SQLAllColumnExpr) expr).getResolvedTableSource(); + if (resolvedTableSource != null + && resolvedTableSource.findColumn(alias) != null) { + return true; + } + return false; } if (expr instanceof SQLIdentifierExpr) { @@ -191,7 +193,12 @@ public class SQLSelectItem extends SQLObjectImpl implements SQLReplaceable { if (expr instanceof SQLPropertyExpr) { String ident = ((SQLPropertyExpr) expr).getName(); if ("*".equals(ident)) { - return true; + SQLTableSource resolvedTableSource = ((SQLPropertyExpr) expr).getResolvedTableSource(); + if (resolvedTableSource != null + && resolvedTableSource.findColumn(alias) != null) { + return true; + } + return false; } return alias_normalized.equalsIgnoreCase(SQLUtils.normalize(ident)); 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 5679643ead..df6f5792df 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 @@ -177,8 +177,9 @@ public class MySqlExprParser extends SQLExprParser { } case CACHE: case GROUP: + String strVal = lexer.stringVal(); lexer.nextToken(); - return primaryRest(new SQLIdentifierExpr(lexer.stringVal())); + return primaryRest(new SQLIdentifierExpr(strVal)); default: return super.primary(); } 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 c70e52d005..e20a639f5f 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 @@ -269,52 +269,47 @@ public class MySqlLexer extends Lexer { token = Token.IDENTIFIER; } } else { - final boolean firstFlag = isFirstIdentifierChar(first); if (!firstFlag) { throw new ParserException("illegal identifier. " + info()); } + long hashCode = 0xcbf29ce484222325L; + hashCode ^= ((ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch); + hashCode *= 0x100000001b3L; + mark = pos; bufPos = 1; - char ch = '\0', last_ch; + char ch = '\0'; for (;;) { - last_ch = ch; ch = charAt(++pos); if (!isIdentifierChar(ch)) { -// if (ch == '-' && pos < text.length() - 1) { -// if (mark > 0 && text.charAt(mark - 1) == '.') { -// break; -// } -// -// char next_char = text.charAt(pos + 1); -// if (isIdentifierChar(next_char)) { -// bufPos++; -// continue; -// } -// } -// if (last_ch == '-' && charAt(pos-2) != '-') { -// ch = last_ch; -// bufPos--; -// pos--; -// } break; } bufPos++; + + hashCode ^= ((ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch); + hashCode *= 0x100000001b3L; + continue; } this.ch = charAt(pos); - stringVal = addSymbol(); - Token tok = keywods.getKeyword(stringVal); + Token tok = keywods.getKeyword(hashCode); if (tok != null) { token = tok; } else { token = Token.IDENTIFIER; } + + if (token == Token.IDENTIFIER) { + stringVal = addSymbol(); + } else { + stringVal = null; + } } } 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 4bc84e0050..3e68c30ce4 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 @@ -99,10 +99,6 @@ public class MySqlSelectParser extends SQLSelectParser { this.exprParser.parseHints(queryBlock.getHints()); } - if (lexer.token() == Token.COMMENT) { - lexer.nextToken(); - } - if (lexer.token() == (Token.DISTINCT)) { queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT); lexer.nextToken(); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlEvalVisitorImpl.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlEvalVisitorImpl.java index 9d3b2b73dd..efc6db3613 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlEvalVisitorImpl.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlEvalVisitorImpl.java @@ -165,7 +165,7 @@ public class MySqlEvalVisitorImpl extends MySqlASTVisitorAdapter implements SQLE @Override public boolean visit(SQLBooleanExpr x) { - x.getAttributes().put(EVAL_VALUE, x.getValue()); + x.getAttributes().put(EVAL_VALUE, x.getBooleanValue()); return false; } } 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 b6e2d7e9a5..24c91fe855 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 @@ -889,7 +889,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); incrementIndent(); print0(ucase ? "WHERE " : "where "); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -1252,7 +1251,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV if (x.getWhere() != null) { print0(ucase ? " WHERE " : " where "); - x.getWhere().setParent(x); x.getWhere().accept(this); } @@ -1279,7 +1277,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV if (x.getWhere() != null) { print0(ucase ? " WHERE " : " where "); - x.getWhere().setParent(x); x.getWhere().accept(this); } @@ -1302,7 +1299,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV if (x.getWhere() != null) { print0(ucase ? " WHERE " : " where "); - x.getWhere().setParent(x); x.getWhere().accept(this); } @@ -1355,7 +1351,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV if (x.getWhere() != null) { print0(ucase ? " WHERE " : " where "); - x.getWhere().setParent(x); x.getWhere().accept(this); } @@ -1688,7 +1683,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); incrementIndent(); print0(ucase ? "WHERE " : "where "); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -2377,7 +2371,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV if (x.getWhere() != null) { print0(ucase ? " WHERE " : " where "); - x.getWhere().setParent(x); x.getWhere().accept(this); } @@ -2410,7 +2403,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV if (x.getWhere() != null) { print0(ucase ? " WHERE " : " where "); - x.getWhere().setParent(x); x.getWhere().accept(this); } @@ -3124,7 +3116,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); for (int i = 0, size = x.getStatements().size(); i < size; ++i) { SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); if (i != size - 1) { println(); @@ -3151,7 +3142,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); for (int i = 0, size = x.getStatements().size(); i < size; ++i) { SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); if (i != size - 1) { println(); @@ -3169,7 +3159,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); for (int i = 0, size = x.getStatements().size(); i < size; ++i) { SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); if (i != size - 1) { println(); @@ -3259,7 +3248,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); for (int i = 0, size = x.getStatements().size(); i < size; ++i) { SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); if (i != size - 1) { println(); @@ -3583,7 +3571,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } println(); - x.getBlock().setParent(x); x.getBlock().accept(this); 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 52e61db688..801febce31 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 @@ -1179,8 +1179,6 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS @Override public boolean visit(MySqlDeclareStatement x) { for (SQLDeclareItem item : x.getVarList()) { - item.setParent(x); - SQLName var = (SQLName) item.getName(); this.variants.put(var.toString(), var); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/NameResolveVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/NameResolveVisitor.java index c228e6bfdc..260a90dcb0 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/NameResolveVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/NameResolveVisitor.java @@ -30,7 +30,8 @@ public class NameResolveVisitor extends OracleASTVisitorAdapter { public boolean visit(SQLIdentifierExpr x) { SQLObject parent = x.getParent(); - if (parent instanceof SQLBinaryOpExpr) { + if (parent instanceof SQLBinaryOpExpr + && x.getResolvedColumn() == null) { SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) parent; boolean isJoinCondition = binaryOpExpr.getLeft() instanceof SQLName && binaryOpExpr.getRight() instanceof SQLName; 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 03acfa1684..e063bfeeda 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 @@ -163,7 +163,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS println(); incrementIndent(); print0(ucase ? "WHERE " : "where "); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -401,14 +400,12 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS if (x.getFrom() == null) { print0(ucase ? "DUAL" : "dual"); } else { - x.getFrom().setParent(x); x.getFrom().accept(this); } if (x.getWhere() != null) { println(); print0(ucase ? "WHERE " : "where "); - x.getWhere().setParent(x); x.getWhere().accept(this); } @@ -611,7 +608,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS println(); print0(ucase ? "WHERE " : "where "); incrementIndent(); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -1155,7 +1151,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } else { if (x.getQuery() != null) { println(); - x.getQuery().setParent(x); x.getQuery().accept(this); } } @@ -1208,7 +1203,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } else { if (x.getQuery() != null) { println(); - x.getQuery().setParent(x); x.getQuery().accept(this); } } @@ -1943,7 +1937,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS println(); } SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); } @@ -3214,7 +3207,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS for (int i = 0, size = x.getStatements().size(); i < size; ++i) { println(); SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java index 10839501bb..306142a38c 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java @@ -213,10 +213,6 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle } public boolean visit(OracleSelectQueryBlock x) { - if (x.getWhere() != null) { - x.getWhere().setParent(x); - } - if (x.getInto() instanceof SQLName) { String tableName = x.getInto().toString(); TableStat stat = getTableStat(tableName); @@ -742,11 +738,6 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle setAliasMap(); accept(x.getSubQuery()); - - for (OracleMultiInsertStatement.Entry entry : x.getEntries()) { - entry.setParent(x); - } - accept(x.getEntries()); return false; @@ -759,12 +750,6 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle @Override public boolean visit(ConditionalInsertClause x) { - for (ConditionalInsertClauseItem item : x.getItems()) { - item.setParent(x); - } - if (x.getElseItem() != null) { - x.getElseItem().setParent(x); - } return true; } @@ -1031,8 +1016,6 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle @Override public boolean visit(OracleForStatement x) { - x.getRange().setParent(x); - SQLName index = x.getIndex(); this.getVariants().put(index.toString(), x); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java index a364519d3b..e560a9e936 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java @@ -208,7 +208,6 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor if (x.getWhere() != null) { println(); print0(ucase ? "WHERE " : "where "); - x.getWhere().setParent(x); x.getWhere().accept(this); } @@ -307,7 +306,6 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor println(); print0(ucase ? "WHERE " : "where "); incrementIndent(); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -412,7 +410,6 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor println(); print0(ucase ? "WHERE " : "where "); incrementIndent(); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } diff --git a/src/main/java/com/alibaba/druid/sql/parser/Keywords.java b/src/main/java/com/alibaba/druid/sql/parser/Keywords.java index 853a65468d..d83f847596 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Keywords.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Keywords.java @@ -15,6 +15,11 @@ */ package com.alibaba.druid.sql.parser; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.util.JdbcUtils; +import com.alibaba.druid.util.Utils; + +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -25,6 +30,9 @@ public class Keywords { private final Map keywords; + private long[] hashArray; + private Token[] tokens; + public final static Keywords DEFAULT_KEYWORDS; public final static Keywords SQLITE_KEYWORDS; @@ -169,11 +177,38 @@ public class Keywords { public Keywords(Map keywords){ this.keywords = keywords; + + this.hashArray = new long[keywords.size()]; + this.tokens = new Token[keywords.size()]; + + int index = 0; + for (String k : keywords.keySet()) { + hashArray[index++] = Utils.fnv_64_lower(k); + } + Arrays.sort(hashArray); + for (Map.Entry entry : keywords.entrySet()) { + long k = Utils.fnv_64_lower(entry.getKey()); + index = Arrays.binarySearch(hashArray, k); + tokens[index] = entry.getValue(); + } + } + + public Token getKeyword(long hash) { + int index = Arrays.binarySearch(hashArray, hash); + if (index < 0) { + return null; + } + return tokens[index]; } public Token getKeyword(String key) { - key = key.toUpperCase(); - return keywords.get(key); + long k = Utils.fnv_64_lower(key); + int index = Arrays.binarySearch(hashArray, k); + if (index < 0) { + return null; + } + return tokens[index]; +// return keywords.get(key); } public Map getKeywords() { 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 ee6606caee..884d975af9 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -1417,6 +1417,9 @@ public class Lexer { * The value of a literal token, recorded as a string. For integers, leading 0x and 'l' suffixes are suppressed. */ public final String stringVal() { + if (stringVal == null) { + stringVal = subString(mark, bufPos); + } return stringVal; } 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 21c9703181..ef35e572d9 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -659,7 +659,7 @@ public class SQLExprParser extends SQLParser { break; } default: - throw new ParserException("ERROR" + lexer.info()); + throw new ParserException("ERROR. " + lexer.info()); } SQLExpr expr = primaryRest(sqlExpr); @@ -882,6 +882,12 @@ public class SQLExprParser extends SQLParser { methodInvokeExpr.setFrom(from); } + if (lexer.token == Token.USING) { + lexer.nextToken(); + SQLExpr using = this.primary(); + methodInvokeExpr.setUsing(using); + } + accept(Token.RPAREN); if (lexer.token() == Token.OVER) { diff --git a/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java b/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java index c6a7800eb7..98856718a1 100644 --- a/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java +++ b/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java @@ -422,6 +422,11 @@ public class SchemaRepository { return true; } + public boolean visit(SQLAllColumnExpr x) { + resolve(this, x); + return false; + } + @Override public boolean isEnabled(Option option) { return (options & option.mask) != 0; @@ -464,12 +469,41 @@ public class SchemaRepository { return true; } + public boolean visit(SQLAllColumnExpr x) { + resolve(this, x); + return false; + } + @Override public boolean isEnabled(Option option) { return (options & option.mask) != 0; } } + private void resolve(SchemaResolveVisitor visitor, SQLAllColumnExpr x) { + SQLSelectQueryBlock queryBlock = null; + for (SQLObject parent = x.getParent(); parent != null; parent = parent.getParent()) { + if (parent instanceof SQLTableSource) { + return; + } + if (parent instanceof SQLSelectQueryBlock) { + queryBlock = (SQLSelectQueryBlock) parent; + break; + } + } + + if (queryBlock == null) { + return; + } + + SQLTableSource from = queryBlock.getFrom(); + if (from == null || from instanceof SQLJoinTableSource) { + return; + } + + x.setResolvedTableSource(from); + } + private void resolve(SchemaResolveVisitor visitor, SQLPropertyExpr x) { String owner = x.getOwnernName(); if (owner == null) { diff --git a/src/main/java/com/alibaba/druid/sql/visitor/ExportParameterVisitorUtils.java b/src/main/java/com/alibaba/druid/sql/visitor/ExportParameterVisitorUtils.java index d427a1aad0..d2ee2abc00 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/ExportParameterVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/ExportParameterVisitorUtils.java @@ -91,7 +91,7 @@ public final class ExportParameterVisitorUtils { } if (param instanceof SQLBooleanExpr) { - value = ((SQLBooleanExpr) param).getValue(); + value = ((SQLBooleanExpr) param).getBooleanValue(); replace = true; } 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 3a46f8de99..d1603c01c6 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -39,7 +39,6 @@ import com.alibaba.druid.sql.dialect.oracle.ast.OracleSegmentAttributes; import com.alibaba.druid.sql.ast.statement.SQLDeclareStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreatePackageStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForStatement; -import com.alibaba.druid.sql.visitor.functions.Ucase; import com.alibaba.druid.util.JdbcConstants; import com.alibaba.druid.util.JdbcUtils; @@ -605,8 +604,10 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet public boolean visit(SQLCaseExpr x) { incrementIndent(); print0(ucase ? "CASE " : "case "); - if (x.getValueExpr() != null) { - x.getValueExpr().accept(this); + + SQLExpr valueExpr = x.getValueExpr(); + if (valueExpr != null) { + valueExpr.accept(this); } for (int i = 0, size = x.getItems().size(); i < size; ++i) { @@ -1073,6 +1074,12 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet from.accept(this); } + SQLExpr using = x.getUsing(); + if (using != null) { + print0(ucase ? " USING " : " using "); + using.accept(this); + } + print(')'); return false; } @@ -1367,8 +1374,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLSelect x) { - x.getQuery().setParent(x); - if (x.getWithSubQuery() != null) { x.getWithSubQuery().accept(this); println(); @@ -1425,7 +1430,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet if (where != null) { println(); print0(ucase ? "WHERE " : "where "); - where.setParent(x); where.accept(this); } @@ -1938,7 +1942,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet println(); print0(ucase ? "WHERE " : "where "); incrementIndent(); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -1970,7 +1973,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } else { if (x.getQuery() != null) { println(); - x.getQuery().setParent(x); x.getQuery().accept(this); } } @@ -2037,7 +2039,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet println(); incrementIndent(); print0(ucase ? "WHERE " : "where "); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -2282,7 +2283,17 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet @Override public boolean visit(SQLJoinTableSource x) { - x.getLeft().accept(this); + SQLTableSource left = x.getLeft(); + + if (left instanceof SQLJoinTableSource + && ((SQLJoinTableSource) left).getJoinType() == JoinType.COMMA + && x.getJoinType() != JoinType.COMMA) { + print('('); + left.accept(this); + print(')'); + } else { + left.accept(this); + } incrementIndent(); if (x.getJoinType() == JoinType.COMMA) { @@ -3436,7 +3447,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLBooleanExpr x) { - print0(x.getValue() ? "true" : "false"); + print0(x.getBooleanValue() ? "true" : "false"); return false; } @@ -3727,7 +3738,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet println(); for (int i = 0, size = x.getStatements().size(); i < size; ++i) { SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); if (i != size - 1) { println(); @@ -3758,7 +3768,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet println(); } SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); } @@ -3779,7 +3788,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet println(); } SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); } @@ -3796,7 +3804,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet for (int i = 0, size = x.getStatements().size(); i < size; ++i) { SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); if (i != size - 1) { @@ -4403,7 +4410,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet incrementIndent(); println(); print0(ucase ? "WHERE " : "where "); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -4412,7 +4418,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet incrementIndent(); println(); print0(ucase ? "DELETE WHERE " : "delete where "); - x.getDeleteWhere().setParent(x); x.getDeleteWhere().accept(this); decrementIndent(); } @@ -4434,7 +4439,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet incrementIndent(); println(); print0(ucase ? "WHERE " : "where "); - x.getWhere().setParent(x); x.getWhere().accept(this); decrementIndent(); } @@ -4665,7 +4669,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet println(); for (int i = 0, size = x.getStatements().size(); i < size; ++i) { SQLStatement item = x.getStatements().get(i); - item.setParent(x); item.accept(this); if (i != size - 1) { println(); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java index 688ab7c9fa..1beb5c7b60 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java @@ -148,7 +148,7 @@ public class SQLEvalVisitorImpl extends SQLASTVisitorAdapter implements SQLEvalV @Override public boolean visit(SQLBooleanExpr x) { - x.getAttributes().put(EVAL_VALUE, x.getValue()); + x.getAttributes().put(EVAL_VALUE, x.getBooleanValue()); return false; } diff --git a/src/main/java/com/alibaba/druid/util/Utils.java b/src/main/java/com/alibaba/druid/util/Utils.java index ed72592d30..8e12e162d6 100644 --- a/src/main/java/com/alibaba/druid/util/Utils.java +++ b/src/main/java/com/alibaba/druid/util/Utils.java @@ -427,9 +427,6 @@ public class Utils { long hashCode = 0xcbf29ce484222325L; 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); 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 6038ea3a54..3f9ca781ef 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -15,7 +15,6 @@ */ package com.alibaba.druid.wall.spi; -import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLCommentHint; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLLimit; @@ -63,7 +62,6 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowGrantsStatemen import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; -import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterIndexStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExecuteImmediateStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGShowStatement; @@ -232,11 +230,6 @@ public class WallVisitorUtils { } public static void checkSelelct(WallVisitor visitor, SQLSelectQueryBlock x) { - - for (SQLSelectItem item : x.getSelectList()) { - item.setParent(x); - } - if (x.getInto() != null) { checkReadOnly(visitor, x.getInto()); } @@ -246,13 +239,8 @@ public class WallVisitorUtils { return; } - if (x.getFrom() != null) { - x.getFrom().setParent(x); - } - SQLExpr where = x.getWhere(); if (where != null) { - where.setParent(x); checkCondition(visitor, x.getWhere()); Object whereValue = getConditionValue(visitor, where, visitor.getConfig().isSelectWhereAlwayTrueCheck()); @@ -334,7 +322,7 @@ public class WallVisitorUtils { Object evalValue = part.getAttribute(EVAL_VALUE); if (evalValue == null) { if (part instanceof SQLBooleanExpr) { - evalValue = ((SQLBooleanExpr) part).getValue(); + evalValue = ((SQLBooleanExpr) part).getBooleanValue(); } else if (part instanceof SQLNumericLiteralExpr) { evalValue = ((SQLNumericLiteralExpr) part).getNumber(); } else if (part instanceof SQLCharExpr) { @@ -1475,7 +1463,7 @@ public class WallVisitorUtils { } if (x instanceof SQLBooleanExpr) { - return ((SQLBooleanExpr) x).getValue(); + return ((SQLBooleanExpr) x).getBooleanValue(); } if (x instanceof SQLNumericLiteralExpr) { diff --git a/src/test/java/com/alibaba/druid/benckmark/sql/MySqlPerfMain_select.java b/src/test/java/com/alibaba/druid/benckmark/sql/MySqlPerfMain_select.java index 60dfb1690b..ca1eb39711 100644 --- a/src/test/java/com/alibaba/druid/benckmark/sql/MySqlPerfMain_select.java +++ b/src/test/java/com/alibaba/druid/benckmark/sql/MySqlPerfMain_select.java @@ -31,9 +31,14 @@ public class MySqlPerfMain_select { System.out.println(arguments); String sql = "SELECT ID, NAME, AGE FROM USER WHERE ID = ?"; +// String sql = "SELECT student_name, " // +// + "GROUP_CONCAT(DISTINCT test_score " // +// + " ORDER BY test_score DESC SEPARATOR ' ') " // +// + "FROM student " // +// + "GROUP BY student_name"; for (int i = 0; i < 10; ++i) { - perfMySql(sql); + perfMySql(sql); // 831 810 } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/DeleteSyntaxTest.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/DeleteSyntaxTest.java index 88567ee47f..3397ffb929 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/DeleteSyntaxTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/DeleteSyntaxTest.java @@ -72,9 +72,10 @@ public class DeleteSyntaxTest extends TestCase { SQLStatement stmt = stmtList.get(0); - Assert.assertEquals("DELETE FROM a1, a2 USING (t1) AS a1" + // - "\n\tINNER JOIN t2 a2\nWHERE a1.id = a2.id", SQLUtils.toMySqlString(stmt)); - Assert.assertEquals("delete from a1, a2 using (t1) as a1" + // + Assert.assertEquals("DELETE FROM (a1, a2 USING (t1) AS a1)\n" + + "\tINNER JOIN t2 a2\n" + + "WHERE a1.id = a2.id", SQLUtils.toMySqlString(stmt)); + Assert.assertEquals("delete from (a1, a2 using (t1) as a1)" + // "\n\tinner join t2 a2\nwhere a1.id = a2.id", SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlDeleteTest_1.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlDeleteTest_1.java index 86f8b3c2ff..2f066741c0 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlDeleteTest_1.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlDeleteTest_1.java @@ -36,10 +36,10 @@ public class MySqlDeleteTest_1 extends MysqlTest { List statementList = parser.parseStatementList(); SQLStatement stmt = statementList.get(0); - Assert.assertEquals("DELETE FROM a1, a2 USING (t1) AS a1" + Assert.assertEquals("DELETE FROM (a1, a2 USING (t1) AS a1)" + "\n\tINNER JOIN t2 a2" + "\nWHERE a1.id = a2.id;", SQLUtils.toMySqlString(stmt)); - Assert.assertEquals("delete from a1, a2 using (t1) as a1" + Assert.assertEquals("delete from (a1, a2 using (t1) as a1)" + "\n\tinner join t2 a2" + "\nwhere a1.id = a2.id;", SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_52_comment.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_52_comment.java new file mode 100644 index 0000000000..b80533a4b9 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_52_comment.java @@ -0,0 +1,131 @@ +/* + * 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.mysql.select; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class MySqlSelectTest_52_comment extends MysqlTest { + + public void test_0() throws Exception { + String sql = "SELECT comment.id,user.id AS user_id,user.username,user.avatar,comment.created_at,\n" + + " getDistance('31.860968', '117.252579', user.latitude, user.longitude) AS distance,\n" + + " 1 AS type\n" + + " FROM user,comment\n" + + " WHERE user.id=comment.user_id\n" + + " AND getDistance('31.860968', '117.252579', user.latitude, user.longitude)>=0\n" + + " AND getDistance('31.860968', '117.252579', user.latitude, user.longitude)<=10000\n" + + " UNION\n" + + " SELECT user_book_list.id,user.id AS user_id,user.username,user.avatar,user_book_list.created_at,\n" + + " getDistance('31.860968', '117.252579', user.latitude, user.longitude) AS distance,\n" + + " 2 AS type\n" + + " FROM user_book_list,user\n" + + " WHERE user.id=user_book_list.user_id\n" + + " AND getDistance('31.860968', '117.252579', user.latitude, user.longitude)>=0\n" + + " AND getDistance('31.860968', '117.252579', user.latitude, user.longitude)<=10000\n" + + " ORDER BY created_at DESC\n" + + " LIMIT 10, 10"; + + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL, true); + SQLStatement stmt = statementList.get(0); + + assertEquals(1, statementList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.MYSQL); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); +// System.out.println("orderBy : " + visitor.getOrderByColumns()); + +// assertEquals(1, visitor.getTables().size()); +// assertEquals(1, visitor.getColumns().size()); +// assertEquals(0, visitor.getConditions().size()); +// assertEquals(0, visitor.getOrderByColumns().size()); + + { + String output = SQLUtils.toMySqlString(stmt); + assertEquals("SELECT comment.id, user.id AS user_id, user.username, user.avatar, comment.created_at\n" + + "\t, getDistance('31.860968', '117.252579', user.latitude, user.longitude) AS distance\n" + + "\t, 1 AS type\n" + + "FROM user, comment\n" + + "WHERE user.id = comment.user_id\n" + + "\tAND getDistance('31.860968', '117.252579', user.latitude, user.longitude) >= 0\n" + + "\tAND getDistance('31.860968', '117.252579', user.latitude, user.longitude) <= 10000\n" + + "UNION\n" + + "SELECT user_book_list.id, user.id AS user_id, user.username, user.avatar, user_book_list.created_at\n" + + "\t, getDistance('31.860968', '117.252579', user.latitude, user.longitude) AS distance\n" + + "\t, 2 AS type\n" + + "FROM user_book_list, user\n" + + "WHERE user.id = user_book_list.user_id\n" + + "\tAND getDistance('31.860968', '117.252579', user.latitude, user.longitude) >= 0\n" + + "\tAND getDistance('31.860968', '117.252579', user.latitude, user.longitude) <= 10000\n" + + "ORDER BY created_at DESC\n" + + "LIMIT 10, 10", // + output); + } + { + String output = SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION); + assertEquals("select comment.id, user.id as user_id, user.username, user.avatar, comment.created_at\n" + + "\t, getDistance('31.860968', '117.252579', user.latitude, user.longitude) as distance\n" + + "\t, 1 as type\n" + + "from user, comment\n" + + "where user.id = comment.user_id\n" + + "\tand getDistance('31.860968', '117.252579', user.latitude, user.longitude) >= 0\n" + + "\tand getDistance('31.860968', '117.252579', user.latitude, user.longitude) <= 10000\n" + + "union\n" + + "select user_book_list.id, user.id as user_id, user.username, user.avatar, user_book_list.created_at\n" + + "\t, getDistance('31.860968', '117.252579', user.latitude, user.longitude) as distance\n" + + "\t, 2 as type\n" + + "from user_book_list, user\n" + + "where user.id = user_book_list.user_id\n" + + "\tand getDistance('31.860968', '117.252579', user.latitude, user.longitude) >= 0\n" + + "\tand getDistance('31.860968', '117.252579', user.latitude, user.longitude) <= 10000\n" + + "order by created_at desc\n" + + "limit 10, 10", // + output); + } + + { + String output = SQLUtils.toMySqlString(stmt, new SQLUtils.FormatOption(true, true, true)); + assertEquals("SELECT comment.id, user.id AS user_id, user.username, user.avatar, comment.created_at\n" + + "\t, getDistance(?, ?, user.latitude, user.longitude) AS distance\n" + + "\t, ? AS type\n" + + "FROM user, comment\n" + + "WHERE user.id = comment.user_id\n" + + "\tAND getDistance(?, ?, user.latitude, user.longitude) >= ?\n" + + "\tAND getDistance(?, ?, user.latitude, user.longitude) <= ?\n" + + "UNION\n" + + "SELECT user_book_list.id, user.id AS user_id, user.username, user.avatar, user_book_list.created_at\n" + + "\t, getDistance(?, ?, user.latitude, user.longitude) AS distance\n" + + "\t, ? AS type\n" + + "FROM user_book_list, user\n" + + "WHERE user.id = user_book_list.user_id\n" + + "\tAND getDistance(?, ?, user.latitude, user.longitude) >= ?\n" + + "\tAND getDistance(?, ?, user.latitude, user.longitude) <= ?\n" + + "ORDER BY created_at DESC\n" + + "LIMIT ?, ?", // + output); + } + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/transform/DecodeTest_0.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/transform/DecodeTest_0.java new file mode 100644 index 0000000000..359c45143b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/transform/DecodeTest_0.java @@ -0,0 +1,25 @@ +package com.alibaba.druid.bvt.sql.mysql.transform; + +import com.alibaba.druid.sql.SQLTransformUtils; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; +import com.alibaba.druid.sql.parser.SQLParserUtils; +import com.alibaba.druid.util.JdbcConstants; +import junit.framework.TestCase; + +public class DecodeTest_0 extends TestCase { + public void test_transform() throws Exception { + SQLMethodInvokeExpr decodeExpr = (SQLMethodInvokeExpr) SQLUtils.toSQLExpr("decode(a, b, c, d)", JdbcConstants.ORACLE); + SQLExpr expr = SQLTransformUtils.transformDecode(decodeExpr); + String targetSql = SQLUtils.toSQLString(expr, JdbcConstants.MYSQL); + assertEquals("if(a = b, c, d)", targetSql); + } + + public void test_transform_null() throws Exception { + SQLMethodInvokeExpr decodeExpr = (SQLMethodInvokeExpr) SQLUtils.toSQLExpr("decode(a, null, c, d)", JdbcConstants.ORACLE); + SQLExpr expr = SQLTransformUtils.transformDecode(decodeExpr); + String targetSql = SQLUtils.toSQLString(expr, JdbcConstants.MYSQL); + assertEquals("if(a IS NULL, c, d)", targetSql); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest74_translate.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest74_translate.java new file mode 100644 index 0000000000..beb7ff8f81 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest74_translate.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 OracleSelectTest74_translate extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "SELECT TRANSLATE(SUBSTR(TRIM(E.BZ)||\n" + + " TRIM(I.BZ)||\n" + + " TRIM(H.MC)||\n" + + " TRIM(A.MLPH)||\n" + + " TRIM(A.MLXZ),1,35)\n" + + " USING CHAR_CS) FROM T"; // + + 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(5, visitor.getColumns().size()); + + { + String text = SQLUtils.toOracleString(stmt); + + assertEquals("SELECT TRANSLATE(SUBSTR(TRIM(E.BZ) || TRIM(I.BZ) || TRIM(H.MC) || TRIM(A.MLPH) || TRIM(A.MLXZ), 1, 35) USING CHAR_CS)\n" + + "FROM T", 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"))); + } +}