diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerOutput.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerOutput.java new file mode 100644 index 0000000000..8ba1e25491 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerOutput.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 Alibaba.com All right reserved. This software is the + * confidential and proprietary information of Alibaba.com ("Confidential + * Information"). You shall not disclose such Confidential Information and shall + * use it only in accordance with the terms of the license agreement you entered + * into with Alibaba.com. + */ +package com.alibaba.druid.sql.dialect.sqlserver.ast; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor; + +public class SQLServerOutput extends SQLServerObjectImpl { + + protected SQLExprTableSource into; + + protected final List columns = new ArrayList(); + + protected final List selectList = new ArrayList(); + + @Override + public void accept0(SQLServerASTVisitor visitor) { + if (visitor.visit(this)) { + this.acceptChild(visitor, selectList); + this.acceptChild(visitor, into); + this.acceptChild(visitor, columns); + } + + visitor.endVisit(this); + } + + public SQLExprTableSource getInto() { + return into; + } + + public void setInto(SQLExprTableSource into) { + this.into = into; + } + + public List getColumns() { + return columns; + } + + public List getSelectList() { + return selectList; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerInsertStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerInsertStatement.java index 2c76853129..6d51faa438 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerInsertStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerInsertStatement.java @@ -20,6 +20,8 @@ import java.util.List; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerObject; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop; import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -29,6 +31,10 @@ public class SQLServerInsertStatement extends SQLInsertStatement implements SQLS private boolean defaultValues; + private SQLServerTop top; + + private SQLServerOutput output; + public ValuesClause getValues() { if (valuesList.size() == 0) { return null; @@ -56,8 +62,10 @@ public class SQLServerInsertStatement extends SQLInsertStatement implements SQLS @Override public void accept0(SQLServerASTVisitor visitor) { if (visitor.visit(this)) { + this.acceptChild(visitor, getTop()); this.acceptChild(visitor, getTableSource()); this.acceptChild(visitor, getColumns()); + this.acceptChild(visitor, getOutput()); this.acceptChild(visitor, getValuesList()); this.acceptChild(visitor, getQuery()); } @@ -73,4 +81,20 @@ public class SQLServerInsertStatement extends SQLInsertStatement implements SQLS this.defaultValues = defaultValues; } + public SQLServerOutput getOutput() { + return output; + } + + public void setOutput(SQLServerOutput output) { + this.output = output; + } + + public SQLServerTop getTop() { + return top; + } + + public void setTop(SQLServerTop top) { + this.top = top; + } + } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerUpdateStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerUpdateStatement.java index 512c84daff..4619536a87 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerUpdateStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerUpdateStatement.java @@ -17,6 +17,7 @@ package com.alibaba.druid.sql.dialect.sqlserver.ast.stmt; import com.alibaba.druid.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop; import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor; @@ -24,8 +25,9 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLServerUpdateStatement extends SQLUpdateStatement implements SQLServerStatement { - private SQLServerTop top; - private SQLTableSource from; + private SQLServerTop top; + private SQLTableSource from; + private SQLServerOutput output; public SQLServerTop getTop() { return top; @@ -43,6 +45,14 @@ public class SQLServerUpdateStatement extends SQLUpdateStatement implements SQLS this.from = from; } + public SQLServerOutput getOutput() { + return output; + } + + public void setOutput(SQLServerOutput output) { + this.output = output; + } + @Override protected void accept0(SQLASTVisitor visitor) { this.accept0((SQLServerASTVisitor) visitor); @@ -54,6 +64,7 @@ public class SQLServerUpdateStatement extends SQLUpdateStatement implements SQLS acceptChild(visitor, top); acceptChild(visitor, tableSource); acceptChild(visitor, items); + acceptChild(visitor, output); acceptChild(visitor, from); acceptChild(visitor, where); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerExprParser.java index 794768fc2a..08bd2b9ebd 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerExprParser.java @@ -15,13 +15,19 @@ */ package com.alibaba.druid.sql.dialect.sqlserver.parser; +import java.util.List; + import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerColumnDefinition; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop; import com.alibaba.druid.sql.dialect.sqlserver.ast.expr.SQLServerObjectReferenceExpr; import com.alibaba.druid.sql.parser.Lexer; @@ -133,6 +139,54 @@ public class SQLServerExprParser extends SQLExprParser { return null; } + + protected SQLServerOutput parserOutput() { + if (identifierEquals("OUTPUT")) { + lexer.nextToken(); + SQLServerOutput output = new SQLServerOutput(); + + final List selectList = output.getSelectList(); + for (;;) { + final SQLSelectItem selectItem = parseSelectItem(); + selectList.add(selectItem); + + if (lexer.token() != Token.COMMA) { + break; + } + + lexer.nextToken(); + } + + if (lexer.token() == Token.INTO) { + lexer.nextToken(); + output.setInto(new SQLExprTableSource(this.name())); + if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + this.exprList(output.getColumns(), output); + accept(Token.RPAREN); + } + } + return output; + } + return null; + } + + protected SQLSelectItem parseSelectItem() { + SQLExpr expr; + if (lexer.token() == Token.IDENTIFIER) { + expr = new SQLIdentifierExpr(lexer.stringVal()); + lexer.nextTokenComma(); + + if (lexer.token() != Token.COMMA) { + expr = this.primaryRest(expr); + expr = this.exprRest(expr); + } + } else { + expr = this.expr(); + } + final String alias = as(); + return new SQLSelectItem(expr, alias); + } protected SQLColumnDefinition createColumnDefinition() { SQLColumnDefinition column = new SQLServerColumnDefinition(); 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 8693d06188..da434554dd 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 @@ -26,6 +26,7 @@ import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; import com.alibaba.druid.sql.ast.statement.SQLSetStatement; import com.alibaba.druid.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerExecStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; @@ -93,6 +94,11 @@ public class SQLServerStatementParser extends SQLStatementParser { protected void parseInsert0(SQLInsertInto insert, boolean acceptSubQuery) { SQLServerInsertStatement insertStatement = (SQLServerInsertStatement) insert; + + SQLServerTop top = this.getExprParser().parseTop(); + if (top != null) { + insertStatement.setTop(top); + } if (lexer.token() == Token.INTO) { lexer.nextToken(); @@ -107,7 +113,7 @@ public class SQLServerStatementParser extends SQLStatementParser { parseInsert0_hinits(insertStatement); - if (lexer.token() == Token.IDENTIFIER) { + if (lexer.token() == Token.IDENTIFIER && !lexer.stringVal().equalsIgnoreCase("OUTPUT")) { insertStatement.setAlias(lexer.stringVal()); lexer.nextToken(); } @@ -117,6 +123,11 @@ public class SQLServerStatementParser extends SQLStatementParser { this.exprParser.exprList(insertStatement.getColumns(), insertStatement); accept(Token.RPAREN); } + + SQLServerOutput output = this.getExprParser().parserOutput(); + if (output != null) { + insertStatement.setOutput(output); + } if (lexer.token() == Token.VALUES) { lexer.nextToken(); @@ -168,6 +179,11 @@ public class SQLServerStatementParser extends SQLStatementParser { udpateStatement.setTableSource(tableSource); parseUpdateSet(udpateStatement); + + SQLServerOutput output = this.getExprParser().parserOutput(); + if (output != null) { + udpateStatement.setOutput(output); + } if (lexer.token() == Token.FROM) { lexer.nextToken(); @@ -182,7 +198,7 @@ public class SQLServerStatementParser extends SQLStatementParser { return udpateStatement; } - + public SQLServerExprParser getExprParser() { return (SQLServerExprParser) exprParser; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerASTVisitor.java index c4a9b7a04a..b7db1ce651 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerASTVisitor.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.dialect.sqlserver.visitor; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerColumnDefinition; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop; import com.alibaba.druid.sql.dialect.sqlserver.ast.expr.SQLServerObjectReferenceExpr; @@ -67,4 +68,8 @@ public interface SQLServerASTVisitor extends SQLASTVisitor { boolean visit(SQLServerSetStatement x); void endVisit(SQLServerSetStatement x); + + boolean visit(SQLServerOutput x); + + void endVisit(SQLServerOutput x); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerASTVisitorAdapter.java index 6f610afe12..abeeb4eac7 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerASTVisitorAdapter.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.dialect.sqlserver.visitor; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerColumnDefinition; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop; import com.alibaba.druid.sql.dialect.sqlserver.ast.expr.SQLServerObjectReferenceExpr; @@ -128,4 +129,14 @@ public class SQLServerASTVisitorAdapter extends SQLASTVisitorAdapter implements } + @Override + public boolean visit(SQLServerOutput x) { + return true; + } + + @Override + public void endVisit(SQLServerOutput x) { + + } + } 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 5f31ac1df4..0c2979dd25 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 @@ -23,6 +23,7 @@ import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerColumnDefinition; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerColumnDefinition.Identity; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop; import com.alibaba.druid.sql.dialect.sqlserver.ast.expr.SQLServerObjectReferenceExpr; @@ -95,7 +96,7 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe boolean paren = false; - if (x.getParent() instanceof SQLServerUpdateStatement) { + if (x.getParent() instanceof SQLServerUpdateStatement || x.getParent() instanceof SQLServerInsertStatement) { paren = true; print("("); } @@ -131,8 +132,16 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe @Override public boolean visit(SQLServerInsertStatement x) { - print("INSERT INTO "); + print("INSERT "); + if (x.getTop() != null) { + x.getTop().setParent(x); + x.getTop().accept(this); + print(' '); + } + + print("INTO "); + x.getTableSource().accept(this); if (x.getColumns().size() > 0) { @@ -152,6 +161,12 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe print(")"); decrementIndent(); } + + if (x.getOutput() != null) { + println(); + x.getOutput().setParent(x); + x.getOutput().accept(this); + } if (x.getValuesList().size() != 0) { println(); @@ -170,7 +185,7 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe println(); x.getQuery().accept(this); } - + if (x.isDefaultValues()) { print(" DEFAULT VALUES"); } @@ -202,6 +217,12 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe } x.getItems().get(i).accept(this); } + + if (x.getOutput() != null) { + println(); + x.getOutput().setParent(x); + x.getOutput().accept(this); + } if (x.getFrom() != null) { println(); @@ -333,7 +354,7 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe @Override public void endVisit(SQLServerSetTransactionIsolationLevelStatement x) { - + } @Override @@ -348,6 +369,44 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe @Override public void endVisit(SQLServerSetStatement x) { - + + } + + @Override + public boolean visit(SQLServerOutput x) { + print("OUTPUT "); + printSelectList(x.getSelectList()); + + if (x.getInto() != null) { + incrementIndent(); + println(); + print("INTO "); + x.getInto().accept(this); + + if (x.getColumns().size() > 0) { + incrementIndent(); + println(); + print("("); + for (int i = 0, size = x.getColumns().size(); i < size; ++i) { + if (i != 0) { + if (i % 5 == 0) { + println(); + } + print(", "); + } + + x.getColumns().get(i).accept(this); + } + print(")"); + decrementIndent(); + } + } + decrementIndent(); + return false; + } + + @Override + public void endVisit(SQLServerOutput x) { + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerSchemaStatVisitor.java index a086de6e5f..275c5d1206 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/visitor/SQLServerSchemaStatVisitor.java @@ -22,6 +22,7 @@ import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerColumnDefinition; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerColumnDefinition.Identity; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop; import com.alibaba.druid.sql.dialect.sqlserver.ast.expr.SQLServerObjectReferenceExpr; @@ -157,4 +158,14 @@ public class SQLServerSchemaStatVisitor extends SchemaStatVisitor implements SQL } + @Override + public boolean visit(SQLServerOutput x) { + return false; + } + + @Override + public void endVisit(SQLServerOutput x) { + + } + } 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 new file mode 100644 index 0000000000..d61b4b41e2 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest7.java @@ -0,0 +1,87 @@ +/* + * 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 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;"; + + 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)); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerUpdateTest5.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerUpdateTest5.java new file mode 100644 index 0000000000..c23e15db6f --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerUpdateTest5.java @@ -0,0 +1,46 @@ +/* + * 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 junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; +import com.alibaba.druid.sql.test.TestUtils; + +public class SQLServerUpdateTest5 extends TestCase { + + public void test_update() throws Exception { + String sql = "UPDATE TOP (10) HumanResources.Employee SET VacationHours = VacationHours * 1.25, ModifiedDate = GETDATE() OUTPUT inserted.BusinessEntityID, deleted.VacationHours, inserted.VacationHours, inserted.ModifiedDate INTO @MyTableVar;"; + + String expect = "UPDATE TOP (10) HumanResources.Employee" + + "\nSET VacationHours = VacationHours * 1.25, ModifiedDate = GETDATE()" + + "\nOUTPUT inserted.BusinessEntityID, deleted.VacationHours, inserted.VacationHours, inserted.ModifiedDate" + + "\n\tINTO @MyTableVar"; + + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + + String text = TestUtils.outputSqlServer(stmt); + + Assert.assertEquals(expect, text); + + System.out.println(text); + } +}