From 720a8579133251f9fe5e76aa3678affb195e2b9e Mon Sep 17 00:00:00 2001 From: wenshao Date: Thu, 22 Mar 2018 16:41:51 +0800 Subject: [PATCH] bug fixed for pg sql parser. for issue #1950 --- .../postgresql/parser/PGExprParser.java | 38 ++++++++++-- .../bvt/sql/PagerUtilsTest_Count_MySql_0.java | 10 ++++ .../insert/MySqlInsertTest_26_special.java | 27 +++++++++ .../select/MySqlSelectTest_147_huizhi.java | 55 +++++++++++++++++ .../sql/postgresql/select/PGSelectTest64.java | 59 +++++++++++++++++++ 5 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_147_huizhi.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest64.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java index a4f822b77f..7a371e05de 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java @@ -183,16 +183,17 @@ public class PGExprParser extends SQLExprParser { if (lexer.token() == Token.COMMA) { return super.primaryRest(expr); } - + if ("TIMESTAMP".equalsIgnoreCase(ident)) { if (lexer.token() != Token.LITERAL_ALIAS // && lexer.token() != Token.LITERAL_CHARS // && lexer.token() != Token.WITH) { - return new SQLIdentifierExpr("TIMESTAMP"); + return super.primaryRest( + new SQLIdentifierExpr(ident)); } SQLTimestampExpr timestamp = new SQLTimestampExpr(); - + if (lexer.token() == Token.WITH) { lexer.nextToken(); acceptIdentifier("TIME"); @@ -214,8 +215,35 @@ public class PGExprParser extends SQLExprParser { accept(Token.LITERAL_CHARS); } - - return primaryRest(timestamp); + + return primaryRest(timestamp); + } else if ("TIMESTAMPTZ".equalsIgnoreCase(ident)) { + if (lexer.token() != Token.LITERAL_ALIAS // + && lexer.token() != Token.LITERAL_CHARS // + && lexer.token() != Token.WITH) { + return super.primaryRest( + new SQLIdentifierExpr(ident)); + } + + SQLTimestampExpr timestamp = new SQLTimestampExpr(); + timestamp.setWithTimeZone(true); + + String literal = lexer.stringVal(); + timestamp.setLiteral(literal); + accept(Token.LITERAL_CHARS); + + if (lexer.identifierEquals("AT")) { + lexer.nextToken(); + acceptIdentifier("TIME"); + acceptIdentifier("ZONE"); + + String timezone = lexer.stringVal(); + timestamp.setTimeZone(timezone); + accept(Token.LITERAL_CHARS); + } + + + return primaryRest(timestamp); } else if ("EXTRACT".equalsIgnoreCase(ident)) { accept(Token.LPAREN); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java index 74acf37b69..f0b35eb3b7 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java @@ -1,5 +1,7 @@ package com.alibaba.druid.bvt.sql; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import junit.framework.TestCase; import org.junit.Assert; @@ -67,4 +69,12 @@ public class PagerUtilsTest_Count_MySql_0 extends TestCase { "\tFROM t2\n" + ") ALIAS_COUNT", result); } + + public void test_mysql_select() throws Exception { + SQLSelectStatement stmt = (SQLSelectStatement) SQLUtils.parseStatements("select * from t", JdbcConstants.MYSQL).get(0); + PagerUtils.limit(stmt.getSelect(), stmt.getDbType(), 10, 10); + assertEquals("SELECT *\n" + + "FROM t\n" + + "LIMIT 10, 10", stmt.toString()); + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/insert/MySqlInsertTest_26_special.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/insert/MySqlInsertTest_26_special.java index b5f4cbeac4..f1ad178b29 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/insert/MySqlInsertTest_26_special.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/insert/MySqlInsertTest_26_special.java @@ -56,4 +56,31 @@ public class MySqlInsertTest_26_special extends MysqlTest { } + public void test_insert_special_1() throws Exception { + String sql = "INSERT INTO SUNTEST(ID,NAME) VALUES(1, \"Y\\\"'\")"; + + { + List outParameters = new ArrayList(); + String psql = ParameterizedOutputVisitorUtils.parameterize(sql, JdbcConstants.MYSQL, outParameters); + assertEquals("INSERT INTO SUNTEST(ID, NAME)\n" + + "VALUES (?, ?)", psql); + + assertEquals(2, outParameters.size()); + + String rsql = ParameterizedOutputVisitorUtils.restore(psql, JdbcConstants.MYSQL, outParameters); + assertEquals("INSERT INTO SUNTEST (ID, NAME)\n" + + "VALUES (1, 'Y\"''')", rsql); + } + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt; + + assertEquals("INSERT INTO SUNTEST (ID, NAME)\n" + + "VALUES (1, 'Y\"''')", SQLUtils.toMySqlString(insertStmt)); + + + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_147_huizhi.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_147_huizhi.java new file mode 100644 index 0000000000..721d45f959 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_147_huizhi.java @@ -0,0 +1,55 @@ +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.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.visitor.ParameterizedOutputVisitorUtils; +import com.alibaba.druid.sql.visitor.VisitorFeature; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class MySqlSelectTest_147_huizhi extends MysqlTest { + + public void test_0() throws Exception { + String sql = "INSERT INTO hz_dev_hb.tb_tmp_cda_opera_281c (target, appeartimes, source_id) SELECT\n" + + " VARCHAR20,\n" + + " count(1) AS appeartimes,\n" + + " 'resource_count1' as source_id\n" + + " FROM hz_dev_hb.tb_fxzx_large t1\n" + + " WHERE 1 = 1 AND VARCHAR20 IS NOT NULL AND\n" + + " MISSIONID =\n" + + " 'd2051b6549d9a028e83a8a9ab2c2'\n" + + " GROUP BY VARCHAR20"; + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL); + SQLInsertStatement stmt = (SQLInsertStatement)statementList.get(0); + + assertEquals(1, statementList.size()); + + assertEquals("INSERT INTO hz_dev_hb.tb_tmp_cda_opera_281c (target, appeartimes, source_id)\n" + + "SELECT VARCHAR20, COUNT(1) AS appeartimes, 'resource_count1' AS source_id\n" + + "FROM hz_dev_hb.tb_fxzx_large t1\n" + + "WHERE 1 = 1\n" + + "\tAND VARCHAR20 IS NOT NULL\n" + + "\tAND MISSIONID = 'd2051b6549d9a028e83a8a9ab2c2'\n" + + "GROUP BY VARCHAR20", stmt.toString()); + + assertEquals("INSERT INTO hz_dev_hb.tb_tmp_cda_opera_281c(target, appeartimes, source_id)\n" + + "SELECT VARCHAR20, COUNT(1) AS appeartimes, ? AS source_id\n" + + "FROM hz_dev_hb.tb_fxzx_large t1\n" + + "WHERE 1 = 1\n" + + "\tAND VARCHAR20 IS NOT NULL\n" + + "\tAND MISSIONID = ?\n" + + "GROUP BY VARCHAR20" + , ParameterizedOutputVisitorUtils.parameterize(sql, JdbcConstants.MYSQL)); + + SQLSelectQueryBlock queryBlock = stmt.getQuery().getQueryBlock(); + assertEquals(3, queryBlock.getSelectList().size()); + assertEquals(SQLCharExpr.class, queryBlock.getSelectList().get(2).getExpr().getClass()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest64.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest64.java new file mode 100644 index 0000000000..e7f97db215 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest64.java @@ -0,0 +1,59 @@ +/* + * 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.postgresql.select; + +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 junit.framework.TestCase; + +import java.util.List; + +public class PGSelectTest64 extends TestCase { + + public void test_0() throws Exception { + String sql = "select * from public.newtable \n" + + "where EXTRACT(EPOCH FROM timestamptz (column1)) >= EXTRACT(EPOCH FROM timestamptz '2017-09-10 00:00:00') \n" + + "limit 10 offset 0"; + System.out.println(sql); + + List stmtList = SQLUtils.parseStatements(sql, JdbcConstants.POSTGRESQL); + SQLStatement stmt = stmtList.get(0); + + assertEquals("SELECT *\n" + + "FROM public.newtable\n" + + "WHERE EXTRACT (EPOCH FROM timestamptz(column1)) >= EXTRACT (EPOCH FROM TIMESTAMP WITH TIME ZONE '2017-09-10 00:00:00')\n" + + "LIMIT 10 OFFSET 0", SQLUtils.toPGString(stmt)); + + assertEquals("select *\n" + + "from public.newtable\n" + + "where extract (EPOCH from timestamptz(column1)) >= extract (EPOCH from timestamp with time zone '2017-09-10 00:00:00')\n" + + "limit 10 offset 0", SQLUtils.toPGString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + assertEquals(1, stmtList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.POSTGRESQL); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); + + assertEquals(2, visitor.getColumns().size()); + assertEquals(1, visitor.getTables().size()); + } +}