From 85a988355da366592af8a7d77fbb2628c32cc5c8 Mon Sep 17 00:00:00 2001 From: Yako Date: Mon, 22 Sep 2014 16:24:09 +0800 Subject: [PATCH] improve sqlserver parser: insert and select_apply --- .../sql/ast/statement/SQLJoinTableSource.java | 8 +- .../parser/SQLServerStatementParser.java | 22 +++--- .../druid/sql/parser/SQLSelectParser.java | 17 ++++- .../sql/sqlserver/SQLServerInsertTest6.java | 58 ++++++++++++++ .../SQLServerSelectTest_cross_apply.java | 75 +++++++++++++++++++ .../SQLServerSelectTest_outer_apply.java | 75 +++++++++++++++++++ 6 files changed, 239 insertions(+), 16 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest6.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest_cross_apply.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest_outer_apply.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java index 19581e46f9..018870a88b 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java @@ -113,8 +113,12 @@ public class SQLJoinTableSource extends SQLTableSourceImpl { CROSS_JOIN("CROSS JOIN"), // NATURAL_JOIN("NATURAL JOIN"), // NATURAL_INNER_JOIN("NATURAL INNER JOIN"), // - LEFT_OUTER_JOIN("LEFT JOIN"), RIGHT_OUTER_JOIN("RIGHT JOIN"), FULL_OUTER_JOIN("FULL JOIN"), - STRAIGHT_JOIN("STRAIGHT_JOIN"); + LEFT_OUTER_JOIN("LEFT JOIN"), // + RIGHT_OUTER_JOIN("RIGHT JOIN"), // + FULL_OUTER_JOIN("FULL JOIN"),// + STRAIGHT_JOIN("STRAIGHT_JOIN"), // + OUTER_APPLY("OUTER APPLY"),// + CROSS_APPLY("CROSS APPLY"); public final String name; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerStatementParser.java index f279bf2da5..8693d06188 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerStatementParser.java @@ -96,20 +96,20 @@ public class SQLServerStatementParser extends SQLStatementParser { if (lexer.token() == Token.INTO) { lexer.nextToken(); + } + + SQLName tableName = this.exprParser.name(); + insertStatement.setTableName(tableName); - SQLName tableName = this.exprParser.name(); - insertStatement.setTableName(tableName); + if (lexer.token() == Token.LITERAL_ALIAS) { + insertStatement.setAlias(as()); + } - if (lexer.token() == Token.LITERAL_ALIAS) { - insertStatement.setAlias(as()); - } + parseInsert0_hinits(insertStatement); - parseInsert0_hinits(insertStatement); - - if (lexer.token() == Token.IDENTIFIER) { - insertStatement.setAlias(lexer.stringVal()); - lexer.nextToken(); - } + if (lexer.token() == Token.IDENTIFIER) { + insertStatement.setAlias(lexer.stringVal()); + lexer.nextToken(); } if (lexer.token() == (Token.LPAREN)) { diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java index ae80bb140c..ecb0894012 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java @@ -363,7 +363,7 @@ public class SQLSelectParser extends SQLParser { protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) { if ((tableSource.getAlias() == null) || (tableSource.getAlias().length() == 0)) { if (lexer.token() != Token.LEFT && lexer.token() != Token.RIGHT && lexer.token() != Token.FULL - && !identifierEquals("STRAIGHT_JOIN") && !identifierEquals("CROSS")) { + && !identifierEquals("STRAIGHT_JOIN") && !identifierEquals("CROSS") && lexer.token != Token.OUTER) { String alias = as(); if (alias != null) { tableSource.setAlias(alias); @@ -411,8 +411,19 @@ public class SQLSelectParser extends SQLParser { joinType = SQLJoinTableSource.JoinType.STRAIGHT_JOIN; } else if (identifierEquals("CROSS")) { lexer.nextToken(); - accept(Token.JOIN); - joinType = SQLJoinTableSource.JoinType.CROSS_JOIN; + if (lexer.token() == Token.JOIN) { + lexer.nextToken(); + joinType = SQLJoinTableSource.JoinType.CROSS_JOIN; + } else if (identifierEquals("APPLY")) { + lexer.nextToken(); + joinType = SQLJoinTableSource.JoinType.CROSS_APPLY; + } + } else if (lexer.token() == Token.OUTER) { + lexer.nextToken(); + if (identifierEquals("APPLY")) { + lexer.nextToken(); + joinType = SQLJoinTableSource.JoinType.OUTER_APPLY; + } } if (joinType != null) { diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest6.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest6.java new file mode 100644 index 0000000000..db3533a7fb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest6.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2011 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.sqlserver; + +import java.util.List; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; +import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; +import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor; + +public class SQLServerInsertTest6 extends TestCase { + + public void test() throws Exception { + String sql = "INSERT [dbo].[SurveyAnswer]([CustomerId], [QuestionId], [OptionId], [CreateTime], [LastUpdateTime]) VALUES (@0, @1, @2, @3, @4)"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + parser.setParseCompleteValues(false); + parser.setParseValuesSize(3); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + SQLServerInsertStatement insertStmt = (SQLServerInsertStatement) stmt; + + Assert.assertEquals(1, insertStmt.getValuesList().size()); + Assert.assertEquals(5, insertStmt.getValues().getValues().size()); + Assert.assertEquals(5, insertStmt.getColumns().size()); + Assert.assertEquals(1, statementList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + String formatSql = "INSERT INTO [dbo].[SurveyAnswer]"// + + "\n\t([CustomerId], [QuestionId], [OptionId], [CreateTime], [LastUpdateTime])"// + + "\nVALUES" // + + "\n(@0, @1, @2, @3, @4)"; + Assert.assertEquals(formatSql, SQLUtils.toSQLServerString(insertStmt)); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest_cross_apply.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest_cross_apply.java new file mode 100644 index 0000000000..ef2090ac61 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest_cross_apply.java @@ -0,0 +1,75 @@ +/* + * Copyright 1999-2011 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.sqlserver; + +import java.util.List; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; +import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; +import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor; +import com.alibaba.druid.util.JdbcUtils; + +public class SQLServerSelectTest_cross_apply extends TestCase { + + public void test_0() throws Exception { + String sql = "SELECT DeptID, DeptName, DeptMgrID, EmpID, EmpLastName, EmpSalary FROM Departments d CROSS APPLY dbo.GetReports(d.DeptMgrID)"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; + + SQLSelect select = selectStmt.getSelect(); + Assert.assertNotNull(select.getQuery()); + SQLServerSelectQueryBlock queryBlock = (SQLServerSelectQueryBlock) select.getQuery(); + Assert.assertNull(queryBlock.getGroupBy()); + + String fomatSQL = SQLUtils.toSQLString(statementList, JdbcUtils.SQL_SERVER); + + System.out.println(fomatSQL); + + Assert.assertEquals(1, statementList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + 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(1, visitor.getTables().size()); + Assert.assertEquals(7, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + Assert.assertEquals(0, visitor.getOrderByColumns().size()); + + String expected = "SELECT DeptID, DeptName, DeptMgrID, EmpID, EmpLastName"// + + "\n\t, EmpSalary"// + + "\nFROM Departments d" // + + "\n\tCROSS APPLY dbo.GetReports(d.DeptMgrID)"; + + Assert.assertEquals(expected, fomatSQL); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest_outer_apply.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest_outer_apply.java new file mode 100644 index 0000000000..176f9c8a93 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest_outer_apply.java @@ -0,0 +1,75 @@ +/* + * Copyright 1999-2011 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.sqlserver; + +import java.util.List; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; +import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; +import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor; +import com.alibaba.druid.util.JdbcUtils; + +public class SQLServerSelectTest_outer_apply extends TestCase { + + public void test_0() throws Exception { + String sql = "SELECT DeptID, DeptName, DeptMgrID, EmpID, EmpLastName, EmpSalary FROM Departments d OUTER APPLY dbo.GetReports(d.DeptMgrID)"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; + + SQLSelect select = selectStmt.getSelect(); + Assert.assertNotNull(select.getQuery()); + SQLServerSelectQueryBlock queryBlock = (SQLServerSelectQueryBlock) select.getQuery(); + Assert.assertNull(queryBlock.getGroupBy()); + + String fomatSQL = SQLUtils.toSQLString(statementList, JdbcUtils.SQL_SERVER); + + System.out.println(fomatSQL); + + Assert.assertEquals(1, statementList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + 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(1, visitor.getTables().size()); + Assert.assertEquals(7, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + Assert.assertEquals(0, visitor.getOrderByColumns().size()); + + String expected = "SELECT DeptID, DeptName, DeptMgrID, EmpID, EmpLastName"// + + "\n\t, EmpSalary"// + + "\nFROM Departments d" // + + "\n\tOUTER APPLY dbo.GetReports(d.DeptMgrID)"; + + Assert.assertEquals(expected, fomatSQL); + } +}