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 133361d011..9ce5e9be31 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 @@ -118,6 +118,13 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable, this.parameters.add(param); } + public void addArgument(SQLExpr arg) { + if (arg != null) { + arg.setParent(this); + } + this.parameters.add(arg); + } + public void output(StringBuffer buf) { if (this.owner != null) { this.owner.output(buf); 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 46ec6ae785..f177434143 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 @@ -235,6 +235,13 @@ public class MySqlExprParser extends SQLExprParser { lexer.nextToken(); } while (lexer.token() == Token.LITERAL_CHARS || lexer.token() == Token.LITERAL_ALIAS); expr = new SQLCharExpr(text2); + } else if (expr instanceof SQLVariantRefExpr) { + SQLMethodInvokeExpr concat = new SQLMethodInvokeExpr("CONCAT"); + concat.addArgument(expr); + concat.addArgument(this.primary()); + expr = concat; + + return primaryRest(expr); } } else if (lexer.token() == Token.IDENTIFIER) { if (expr instanceof SQLHexExpr) { 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 4ffc427fcc..725182c519 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -696,7 +696,11 @@ public class SQLExprParser extends SQLParser { sqlExpr = unary; break; case QUES: - lexer.nextToken(); + if (JdbcConstants.MYSQL.equals(dbType)) { + lexer.nextTokenValue(); + } else { + lexer.nextToken(); + } SQLVariantRefExpr quesVarRefExpr = new SQLVariantRefExpr("?"); quesVarRefExpr.setIndex(lexer.nextVarIndex()); sqlExpr = quesVarRefExpr; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_186.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_186.java new file mode 100644 index 0000000000..2263405115 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_186.java @@ -0,0 +1,66 @@ +/* + * 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.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; + +import java.util.List; + +public class MySqlSelectTest_186 extends MysqlTest { + + public void test_0() throws Exception { + String sql = "select count(0) from (SELECT * FROM auth_tenant WHERE type = 'tenant' AND name LIKE ?\"%\") tmp_count"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + +// print(statementList); + + assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + 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(3, visitor.getColumns().size()); + assertEquals(2, visitor.getConditions().size()); + assertEquals(0, visitor.getOrderByColumns().size()); + + assertTrue(visitor.containsTable("auth_tenant")); + assertTrue(visitor.containsColumn("auth_tenant", "name")); + + String output = SQLUtils.toMySqlString(stmt); + assertEquals("SELECT COUNT(0)\n" + + "FROM (\n" + + "\tSELECT *\n" + + "\tFROM auth_tenant\n" + + "\tWHERE type = 'tenant'\n" + + "\t\tAND name LIKE CONCAT(?, '%')\n" + + ") tmp_count", // + output); + } + +}