From 2fb9763c776891fbe65ebb6a704813f2923b06cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=93=81?= Date: Fri, 6 May 2016 16:50:05 +0800 Subject: [PATCH] db2 sql parser support concat binary operator --- .../sql/dialect/db2/parser/DB2Lexer.java | 1 + .../dialect/db2/visitor/DB2OutputVisitor.java | 9 ++ .../druid/sql/parser/SQLExprParser.java | 2 +- .../com/alibaba/druid/sql/parser/Token.java | 2 + .../sql/visitor/SQLASTOutputVisitor.java | 6 +- .../druid/bvt/sql/db2/DB2SelectTest_11.java | 100 ++++++++++++++++++ 6 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_11.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2Lexer.java b/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2Lexer.java index 1f0d909c6e..9a461843e3 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2Lexer.java @@ -37,6 +37,7 @@ public class DB2Lexer extends Lexer { map.put("ONLY", Token.ONLY); map.put("OPTIMIZE", Token.OPTIMIZE); map.put("OF", Token.OF); + map.put("CONCAT", Token.CONCAT); DEFAULT_DB2_KEYWORDS = new Keywords(map); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java index 297e06da63..2adf1c7e09 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java @@ -17,6 +17,7 @@ package com.alibaba.druid.sql.dialect.db2.visitor; import com.alibaba.druid.sql.ast.SQLObject; import com.alibaba.druid.sql.ast.SQLOrderBy; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock; @@ -91,4 +92,12 @@ public class DB2OutputVisitor extends SQLASTOutputVisitor implements DB2ASTVisit public void endVisit(DB2ValuesStatement x) { } + + protected void printOperator(SQLBinaryOperator operator) { + if (operator == SQLBinaryOperator.Concat) { + print0(ucase ? "CONCAT" : "concat"); + } else { + print0(ucase ? operator.name : operator.name_lcase); + } + } } 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 5286aa9dc7..6330f86dfb 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1223,7 +1223,7 @@ public class SQLExprParser extends SQLParser { expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Add, rightExp, getDbType()); expr = additiveRest(expr); - } else if (lexer.token() == Token.BARBAR) { + } else if (lexer.token() == Token.BARBAR || lexer.token() == Token.CONCAT) { lexer.nextToken(); SQLExpr rightExp = multiplicative(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Concat, rightExp, getDbType()); diff --git a/src/main/java/com/alibaba/druid/sql/parser/Token.java b/src/main/java/com/alibaba/druid/sql/parser/Token.java index 6231e18633..71157df09a 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -277,6 +277,8 @@ public enum Token { FORMAT("FORMAT"), QUALIFY("QUALIFY"), MOD("MOD"), + + CONCAT("CONCAT"), // DB2 LPAREN("("), RPAREN(")"), 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 20a2e529ad..7a229d56f1 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -329,7 +329,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Printab } else { print0(" "); } - print0(ucase ? x.getOperator().name : x.getOperator().name_lcase); + printOperator(x.getOperator()); print0(" "); } @@ -342,6 +342,10 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Printab return false; } + protected void printOperator(SQLBinaryOperator operator) { + print0(ucase ? operator.name : operator.name_lcase); + } + private void visitorBinaryRight(SQLBinaryOpExpr x) { if (isPrettyFormat() && x.getRight().hasBeforeComment()) { printlnComments(x.getRight().getBeforeCommentsDirect()); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_11.java b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_11.java new file mode 100644 index 0000000000..75d3f70daa --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_11.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2101 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.db2; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.DB2Test; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.db2.parser.DB2StatementParser; +import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Column; +import com.alibaba.druid.util.JdbcConstants; + +public class DB2SelectTest_11 extends DB2Test { + + public void test_0() throws Exception { + String sql = "SELECT A.F_0201, A.F_0301, A.F_0802, A.F_2100" + + "\nFROM A, B" + + "\nWHERE B.F_2211 = '5'" + + "\n AND A.F_0301 = B.F_0301" + + " AND Substr(B.F_0815, 1, 4) concat Substr ( B.F_0815,5,2 ) > A.F_0802" + + " AND A.F_2100 > 0" + + "\nUNION" + + "\nSELECT A.F_0201, A.F_0301, A.F_0802, A.F_2100" + + "\nFROM A" + + "\nWHERE A.F_0301 NOT IN (SELECT F_0301" + + "\n FROM B)" + + "\n AND A.F_2100 > 0"; + + DB2StatementParser parser = new DB2StatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + DB2SchemaStatVisitor visitor = new DB2SchemaStatVisitor(); + 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()); + + Assert.assertEquals(2, visitor.getTables().size()); + Assert.assertEquals(7, visitor.getColumns().size()); + Assert.assertEquals(6, visitor.getConditions().size()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("A"))); + + Assert.assertTrue(visitor.getColumns().contains(new Column("A", "F_0201"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "first_name"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "full_name"))); + + Assert.assertEquals("SELECT A.F_0201, A.F_0301, A.F_0802, A.F_2100" + + "\nFROM A, B" + + "\nWHERE B.F_2211 = '5'" + + "\n\tAND A.F_0301 = B.F_0301" + + "\n\tAND (Substr(B.F_0815, 1, 4) CONCAT Substr(B.F_0815, 5, 2)) > A.F_0802" + + "\n\tAND A.F_2100 > 0" + + "\nUNION" + + "\nSELECT A.F_0201, A.F_0301, A.F_0802, A.F_2100" + + "\nFROM A" + + "\nWHERE A.F_0301 NOT IN (SELECT F_0301" + + "\n\t\tFROM B)" + + "\n\tAND A.F_2100 > 0", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2)); + + Assert.assertEquals("select A.F_0201, A.F_0301, A.F_0802, A.F_2100" + + "\nfrom A, B" + + "\nwhere B.F_2211 = '5'" + + "\n\tand A.F_0301 = B.F_0301" + + "\n\tand (Substr(B.F_0815, 1, 4) concat Substr(B.F_0815, 5, 2)) > A.F_0802" + + "\n\tand A.F_2100 > 0" + + "\nunion" + + "\nselect A.F_0201, A.F_0301, A.F_0802, A.F_2100" + + "\nfrom A" + + "\nwhere A.F_0301 not in (select F_0301" + + "\n\t\tfrom B)" + + "\n\tand A.F_2100 > 0", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + } +}