From 2cdd16c2e732fe5ff7fe326b9bfa539d4fc9e024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=93=81?= Date: Thu, 5 May 2016 14:42:27 +0800 Subject: [PATCH] improved sql server sql parser support xml path. --- .../sqlserver/ast/SQLServerSelect.java | 12 +++ .../parser/SQLServerSelectParser.java | 3 + .../visitor/SQLServerOutputVisitor.java | 6 ++ .../sql/sqlserver/SQLServerInsertTest7.java | 61 ++++++------- .../sql/sqlserver/SQLServerInsertTest8.java | 87 +++++++++++++++++++ 5 files changed, 133 insertions(+), 36 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest8.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerSelect.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerSelect.java index 49547eca2e..5acd31a6d0 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerSelect.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerSelect.java @@ -27,6 +27,7 @@ public class SQLServerSelect extends SQLSelect implements SQLServerObject { private boolean forBrowse; private List forXmlOptions = new ArrayList(4); + private SQLExpr xmlPath; private SQLExpr rowCount; private SQLExpr offset; @@ -69,6 +70,17 @@ public class SQLServerSelect extends SQLSelect implements SQLServerObject { } this.offset = offset; } + + public SQLExpr getXmlPath() { + return xmlPath; + } + + public void setXmlPath(SQLExpr xmlPath) { + if (xmlPath != null) { + xmlPath.setParent(this); + } + this.xmlPath = xmlPath; + } @Override protected void accept0(SQLASTVisitor visitor) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerSelectParser.java index d41d8215c8..cc6834ce29 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerSelectParser.java @@ -76,6 +76,9 @@ public class SQLServerSelectParser extends SQLSelectParser { } else { select.getForXmlOptions().add("ELEMENTS"); } + } else if (identifierEquals("PATH")) { + SQLExpr xmlPath = this.exprParser.expr(); + select.setXmlPath(xmlPath); } else { break; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerOutputVisitor.java index 449f19dae3..1994aa3fc1 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerOutputVisitor.java @@ -469,6 +469,12 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe } } + if (x.getXmlPath() != null) { + println(); + print0(ucase ? "FOR XML " : "for xml "); + x.getXmlPath().accept(this); + } + if (x.getOffset() != null) { println(); print0(ucase ? "OFFSET " : "offset "); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest7.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest7.java index 723f2392b3..5850d3b9ae 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest7.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest7.java @@ -30,34 +30,16 @@ import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisito public class SQLServerInsertTest7 extends TestCase { public void test_0() throws Exception { - String sql = "INSERT Production.ScrapReason OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate INTO @MyTableVar VALUES (N'Operator error', GETDATE());"; - - 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(2, insertStmt.getValues().getValues().size()); - Assert.assertEquals(0, insertStmt.getColumns().size()); - Assert.assertEquals(1, statementList.size()); - - SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); - stmt.accept(visitor); - - String formatSql = "INSERT INTO Production.ScrapReason"// - + "\nOUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate"// - + "\n\tINTO @MyTableVar"// - + "\nVALUES"// - + "\n(N'Operator error', GETDATE())"; - Assert.assertEquals(formatSql, SQLUtils.toSQLServerString(insertStmt)); - } - - public void test_1() throws Exception { - String sql = "INSERT TOP(5)INTO dbo.EmployeeSales OUTPUT inserted.EmployeeID, inserted.FirstName, inserted.LastName, inserted.YearlySales SELECT sp.BusinessEntityID, c.LastName, c.FirstName, sp.SalesYTD FROM Sales.SalesPerson AS sp INNER JOIN Person.Person AS c ON sp.BusinessEntityID = c.BusinessEntityID WHERE sp.SalesYTD > 250000.00 ORDER BY sp.SalesYTD DESC;"; + String sql = "INSERT INTO MMS_SETTLEMENT_COM(handler,handleTime,MID,MERCHANTNAME,TOTALAMT,ACTUALAMT," + + " paymentMoney,STATUS,SERIAL_NUM,REMARKS)" + + "SELECT 'admin',getdate(),MID,MERCHANTNAME,SUM(CONVERT(DECIMAL(18,2),isnull(TOTALAMT,0))) " + + " TOTALAMT,SUM(CONVERT(DECIMAL(18,2),isnull(ACTUALAMT,0))) ACTUALAMT,SUM(CONVERT(DECIMAL(18,2)," + + " isnull(paymentMoney,0))) paymentMoney,2,126,(" + + " SELECT REMARKS+'' " + + " FROM MMS_SETTLEMENT_COM " + + " WHERE MID=A.MID " + + " FOR XML PATH('')" + + ") AS REMARKS FROM MMS_SETTLEMENT_COM A WHERE ID IN (304,305,306,297,108,184) GROUP BY MID ,MERCHANTNAME"; SQLServerStatementParser parser = new SQLServerStatementParser(sql); parser.setParseCompleteValues(false); @@ -68,20 +50,27 @@ public class SQLServerInsertTest7 extends TestCase { SQLServerInsertStatement insertStmt = (SQLServerInsertStatement) stmt; Assert.assertEquals(0, insertStmt.getValuesList().size()); - Assert.assertEquals(0, insertStmt.getColumns().size()); + Assert.assertEquals(10, insertStmt.getColumns().size()); Assert.assertEquals(1, statementList.size()); SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); stmt.accept(visitor); - String formatSql = "INSERT TOP (5) INTO dbo.EmployeeSales"// - + "\nOUTPUT inserted.EmployeeID, inserted.FirstName, inserted.LastName, inserted.YearlySales"// - + "\nSELECT sp.BusinessEntityID, c.LastName, c.FirstName, sp.SalesYTD"// - + "\nFROM Sales.SalesPerson sp"// - + "\nINNER JOIN Person.Person c ON sp.BusinessEntityID = c.BusinessEntityID"// - + "\nWHERE sp.SalesYTD > 250000.00"// - + "\nORDER BY sp.SalesYTD DESC"; + String formatSql = "INSERT INTO MMS_SETTLEMENT_COM" + + "\n\t(handler, handleTime, MID, MERCHANTNAME, TOTALAMT" + + "\n\t, ACTUALAMT, paymentMoney, STATUS, SERIAL_NUM, REMARKS)" + + "\nSELECT 'admin', getdate(), MID, MERCHANTNAME, SUM(CONVERT(DECIMAL(18, 2), isnull(TOTALAMT, 0))) AS TOTALAMT" + + "\n\t, SUM(CONVERT(DECIMAL(18, 2), isnull(ACTUALAMT, 0))) AS ACTUALAMT, SUM(CONVERT(DECIMAL(18, 2), isnull(paymentMoney, 0))) AS paymentMoney, 2, 126, (" + + "\n\t\tSELECT REMARKS + ''" + + "\n\t\tFROM MMS_SETTLEMENT_COM" + + "\n\t\tWHERE MID = A.MID" + + "\n\t\tFOR XML PATH('')" + + "\n\t\t) AS REMARKS" + + "\nFROM MMS_SETTLEMENT_COM A" + + "\nWHERE ID IN (304, 305, 306, 297, 108, 184)" + + "\nGROUP BY MID, MERCHANTNAME"; Assert.assertEquals(formatSql, SQLUtils.toSQLServerString(insertStmt)); } + } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest8.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest8.java new file mode 100644 index 0000000000..3089997831 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest8.java @@ -0,0 +1,87 @@ +/* + * 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.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 SQLServerInsertTest8 extends TestCase { + + public void test_0() throws Exception { + String sql = "INSERT Production.ScrapReason OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate INTO @MyTableVar VALUES (N'Operator error', GETDATE());"; + + 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(2, insertStmt.getValues().getValues().size()); + Assert.assertEquals(0, insertStmt.getColumns().size()); + Assert.assertEquals(1, statementList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + String formatSql = "INSERT INTO Production.ScrapReason"// + + "\nOUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate"// + + "\n\tINTO @MyTableVar"// + + "\nVALUES"// + + "\n(N'Operator error', GETDATE())"; + Assert.assertEquals(formatSql, SQLUtils.toSQLServerString(insertStmt)); + } + + public void test_1() throws Exception { + String sql = "INSERT TOP(5)INTO dbo.EmployeeSales OUTPUT inserted.EmployeeID, inserted.FirstName, inserted.LastName, inserted.YearlySales SELECT sp.BusinessEntityID, c.LastName, c.FirstName, sp.SalesYTD FROM Sales.SalesPerson AS sp INNER JOIN Person.Person AS c ON sp.BusinessEntityID = c.BusinessEntityID WHERE sp.SalesYTD > 250000.00 ORDER BY sp.SalesYTD DESC;"; + + 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(0, insertStmt.getValuesList().size()); + Assert.assertEquals(0, insertStmt.getColumns().size()); + Assert.assertEquals(1, statementList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + String formatSql = "INSERT TOP (5) INTO dbo.EmployeeSales"// + + "\nOUTPUT inserted.EmployeeID, inserted.FirstName, inserted.LastName, inserted.YearlySales"// + + "\nSELECT sp.BusinessEntityID, c.LastName, c.FirstName, sp.SalesYTD"// + + "\nFROM Sales.SalesPerson sp"// + + "\nINNER JOIN Person.Person c ON sp.BusinessEntityID = c.BusinessEntityID"// + + "\nWHERE sp.SalesYTD > 250000.00"// + + "\nORDER BY sp.SalesYTD DESC"; + Assert.assertEquals(formatSql, SQLUtils.toSQLServerString(insertStmt)); + } + +}