From bfa271d0d6955d1e2f17994cac207f5773cb5068 Mon Sep 17 00:00:00 2001 From: Yako Date: Tue, 23 Sep 2014 14:26:16 +0800 Subject: [PATCH 1/2] improve sqlserver parser --- .../sqlserver/ast/SQLServerOutput.java | 53 +++++++++++ .../ast/stmt/SQLServerInsertStatement.java | 24 +++++ .../ast/stmt/SQLServerUpdateStatement.java | 15 +++- .../sqlserver/parser/SQLServerExprParser.java | 54 ++++++++++++ .../parser/SQLServerStatementParser.java | 20 ++++- .../visitor/SQLServerASTVisitor.java | 5 ++ .../visitor/SQLServerASTVisitorAdapter.java | 11 +++ .../visitor/SQLServerOutputVisitor.java | 69 +++++++++++++-- .../visitor/SQLServerSchemaStatVisitor.java | 11 +++ .../sql/sqlserver/SQLServerInsertTest7.java | 87 +++++++++++++++++++ .../sql/sqlserver/SQLServerUpdateTest5.java | 46 ++++++++++ 11 files changed, 386 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerOutput.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerInsertTest7.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerUpdateTest5.java 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); + } +} From e7829a7b805ee81364b80b0c19e55a2d12fe42f7 Mon Sep 17 00:00:00 2001 From: Yako Date: Tue, 23 Sep 2014 19:47:56 +0800 Subject: [PATCH 2/2] improve sqlserver parser --- .../sqlserver/ast/SQLServerDeclareItem.java | 85 ++++++++++++++++++ .../ast/stmt/SQLServerDeclareStatement.java | 38 ++++++++ .../sqlserver/parser/SQLServerLexer.java | 1 + .../parser/SQLServerStatementParser.java | 87 +++++++++++++++++++ .../visitor/SQLServerASTVisitor.java | 11 +++ .../visitor/SQLServerASTVisitorAdapter.java | 24 ++++- .../visitor/SQLServerOutputVisitor.java | 56 ++++++++++++ .../visitor/SQLServerSchemaStatVisitor.java | 22 +++++ .../sql/sqlserver/SQLServerDeclareTest.java | 81 +++++++++++++++++ 9 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerDeclareItem.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerDeclareStatement.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerDeclareTest.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerDeclareItem.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerDeclareItem.java new file mode 100644 index 0000000000..e7ceb4b371 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/SQLServerDeclareItem.java @@ -0,0 +1,85 @@ +/* + * 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.SQLDataType; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.statement.SQLTableElement; +import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor; + +public class SQLServerDeclareItem extends SQLServerObjectImpl { + + protected Type type; + + protected SQLExpr name; + + protected SQLDataType dataType; + + protected SQLExpr value; + + protected List tableElementList = new ArrayList(); + + @Override + public void accept0(SQLServerASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, this.name); + acceptChild(visitor, this.dataType); + acceptChild(visitor, this.value); + acceptChild(visitor, this.tableElementList); + } + visitor.endVisit(this); + } + + public SQLExpr getName() { + return name; + } + + public void setName(SQLExpr name) { + this.name = name; + } + + public SQLDataType getDataType() { + return dataType; + } + + public void setDataType(SQLDataType dataType) { + this.dataType = dataType; + } + + public SQLExpr getValue() { + return value; + } + + public void setValue(SQLExpr value) { + this.value = value; + } + + public List getTableElementList() { + return tableElementList; + } + + public void setTableElementList(List tableElementList) { + this.tableElementList = tableElementList; + } + + public enum Type { + TABLE, LOCAL, CURSOR; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerDeclareStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerDeclareStatement.java new file mode 100644 index 0000000000..50e140516e --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerDeclareStatement.java @@ -0,0 +1,38 @@ +/* + * 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.stmt; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerDeclareItem; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerObjectImpl; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerStatement; +import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor; + +public class SQLServerDeclareStatement extends SQLServerObjectImpl implements SQLServerStatement { + + protected List items = new ArrayList(); + + @Override + public void accept0(SQLServerASTVisitor visitor) { + if (visitor.visit(this)) { + this.acceptChild(visitor, items); + } + visitor.endVisit(this); + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerLexer.java index 84abe762fd..c974625e8f 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerLexer.java @@ -41,6 +41,7 @@ public class SQLServerLexer extends Lexer { map.put("WITH", Token.WITH); map.put("PERCENT", Token.PERCENT); map.put("IDENTITY", Token.IDENTITY); + map.put("DECLARE", Token.DECLARE); DEFAULT_SQL_SERVER_KEYWORDS = new Keywords(map); } 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 da434554dd..a3abfa583c 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 @@ -21,13 +21,18 @@ import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; +import com.alibaba.druid.sql.ast.statement.SQLConstraint; import com.alibaba.druid.sql.ast.statement.SQLInsertInto; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; import com.alibaba.druid.sql.ast.statement.SQLSetStatement; +import com.alibaba.druid.sql.ast.statement.SQLTableElement; import com.alibaba.druid.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerDeclareItem; 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.SQLServerDeclareStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerExecStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; @@ -77,9 +82,91 @@ public class SQLServerStatementParser extends SQLStatementParser { statementList.add(execStmt); return true; } + + if (lexer.token() == Token.DECLARE) { + statementList.add(this.parseDeclare()); + return true; + } return false; } + + public SQLStatement parseDeclare() { + this.accept(Token.DECLARE); + + SQLServerDeclareStatement declareStatement = new SQLServerDeclareStatement(); + + for (;;) { + SQLServerDeclareItem item = new SQLServerDeclareItem(); + declareStatement.getItems().add(item); + + item.setName(this.exprParser.name()); + + if (lexer.token() == Token.AS) { + lexer.nextToken(); + } + + if (lexer.token() == Token.TABLE) { + lexer.nextToken(); + item.setType(SQLServerDeclareItem.Type.TABLE); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + + for (;;) { + if (lexer.token() == Token.IDENTIFIER // + || lexer.token() == Token.LITERAL_ALIAS) { + SQLColumnDefinition column = this.exprParser.parseColumn(); + item.getTableElementList().add(column); + } else if (lexer.token() == Token.PRIMARY // + || lexer.token() == Token.UNIQUE // + || lexer.token() == Token.CHECK // + || lexer.token() == Token.CONSTRAINT) { + SQLConstraint constraint = this.exprParser.parseConstaint(); + constraint.setParent(item); + item.getTableElementList().add((SQLTableElement) constraint); + } else if (lexer.token() == Token.TABLESPACE) { + throw new ParserException("TODO " + lexer.token()); + } else { + SQLColumnDefinition column = this.exprParser.parseColumn(); + item.getTableElementList().add(column); + } + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + + if (lexer.token() == Token.RPAREN) { + break; + } + continue; + } + + break; + } + accept(Token.RPAREN); + } + break; + } else if (lexer.token() == Token.CURSOR) { + item.setType(SQLServerDeclareItem.Type.CURSOR); + lexer.nextToken(); + } else { + item.setType(SQLServerDeclareItem.Type.LOCAL); + item.setDataType(this.exprParser.parseDataType()); + if (lexer.token() == Token.EQ) { + lexer.nextToken(); + item.setValue(this.exprParser.expr()); + } + } + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } else { + break; + } + } + return declareStatement; + } public SQLStatement parseInsert() { SQLServerInsertStatement insertStatement = new SQLServerInsertStatement(); 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 b7db1ce651..8aa1dacdcd 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,10 +16,12 @@ 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.SQLServerDeclareItem; 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; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerDeclareStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerExecStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; @@ -72,4 +74,13 @@ public interface SQLServerASTVisitor extends SQLASTVisitor { boolean visit(SQLServerOutput x); void endVisit(SQLServerOutput x); + + boolean visit(SQLServerDeclareItem x); + + void endVisit(SQLServerDeclareItem x); + + boolean visit(SQLServerDeclareStatement x); + + void endVisit(SQLServerDeclareStatement 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 abeeb4eac7..e0c7799089 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,10 +16,12 @@ 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.SQLServerDeclareItem; 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; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerDeclareStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerExecStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; @@ -136,7 +138,27 @@ public class SQLServerASTVisitorAdapter extends SQLASTVisitorAdapter implements @Override public void endVisit(SQLServerOutput x) { - + + } + + @Override + public boolean visit(SQLServerDeclareItem x) { + return true; + } + + @Override + public void endVisit(SQLServerDeclareItem x) { + + } + + @Override + public boolean visit(SQLServerDeclareStatement x) { + return true; + } + + @Override + public void endVisit(SQLServerDeclareStatement 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 0c2979dd25..9868f724f5 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,10 +23,12 @@ 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.SQLServerDeclareItem; 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; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerDeclareStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerExecStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; @@ -409,4 +411,58 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe public void endVisit(SQLServerOutput x) { } + + @Override + public boolean visit(SQLServerDeclareItem x) { + x.getName().accept(this); + + if(x.getType() == SQLServerDeclareItem.Type.TABLE) { + print(" TABLE"); + int size = x.getTableElementList().size(); + + if (size > 0) { + print(" ("); + incrementIndent(); + println(); + for (int i = 0; i < size; ++i) { + if (i != 0) { + print(","); + println(); + } + x.getTableElementList().get(i).accept(this); + } + decrementIndent(); + println(); + print(")"); + } + } else if (x.getType() == SQLServerDeclareItem.Type.CURSOR) { + print(" CURSOR"); + } else { + print(" "); + x.getDataType().accept(this); + if (x.getValue() != null) { + print(" = "); + x.getValue().accept(this); + } + } + + return false; + } + + @Override + public void endVisit(SQLServerDeclareItem x) { + + } + + @Override + public boolean visit(SQLServerDeclareStatement x) { + print("DECLARE "); + this.printAndAccept(x.getItems(), ", "); + return false; + } + + @Override + public void endVisit(SQLServerDeclareStatement 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 275c5d1206..d6665ff303 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,10 +22,12 @@ 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.SQLServerDeclareItem; 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; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerDeclareStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerExecStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; @@ -168,4 +170,24 @@ public class SQLServerSchemaStatVisitor extends SchemaStatVisitor implements SQL } + @Override + public boolean visit(SQLServerDeclareItem x) { + return false; + } + + @Override + public void endVisit(SQLServerDeclareItem x) { + + } + + @Override + public boolean visit(SQLServerDeclareStatement x) { + return false; + } + + @Override + public void endVisit(SQLServerDeclareStatement x) { + + } + } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerDeclareTest.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerDeclareTest.java new file mode 100644 index 0000000000..29eb22219a --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerDeclareTest.java @@ -0,0 +1,81 @@ +/* + * 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.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.parser.SQLServerStatementParser; +import com.alibaba.druid.util.JdbcUtils; + +public class SQLServerDeclareTest extends TestCase { + + public void test_0() { + String sql = "declare @is_updated bit"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List stmtList = parser.parseStatementList(); + + Assert.assertEquals(1, stmtList.size()); + + String text = SQLUtils.toSQLString(stmtList, JdbcUtils.SQL_SERVER); + + Assert.assertEquals("DECLARE @is_updated bit", text); + } + + public void test_1() { + String sql = "DECLARE @Group nvarchar(50), @Sales money=1;"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List stmtList = parser.parseStatementList(); + + Assert.assertEquals(1, stmtList.size()); + + String text = SQLUtils.toSQLString(stmtList, JdbcUtils.SQL_SERVER); + + Assert.assertEquals("DECLARE @Group nvarchar(50), @Sales money = 1", text); + } + + public void test_2() { + String sql = "DECLARE @cursor CURSOR"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List stmtList = parser.parseStatementList(); + + Assert.assertEquals(1, stmtList.size()); + + String text = SQLUtils.toSQLString(stmtList, JdbcUtils.SQL_SERVER); + + Assert.assertEquals("DECLARE @cursor CURSOR", text); + } + + public void test_3() { + String sql = "DECLARE @MyTableVar table( EmpID int NOT NULL, OldVacationHours int, NewVacationHours int, ModifiedDate datetime);"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List stmtList = parser.parseStatementList(); + + Assert.assertEquals(1, stmtList.size()); + + String text = SQLUtils.toSQLString(stmtList, JdbcUtils.SQL_SERVER); + + String expected = "DECLARE @MyTableVar TABLE ("// + + "\n\tEmpID int NOT NULL,"// + + "\n\tOldVacationHours int,"// + + "\n\tNewVacationHours int,"// + + "\n\tModifiedDate datetime"// + + "\n)"; + Assert.assertEquals(expected, text); + } + +}