From 50492859e0e17765b1b8e1291bc1f7b0a6f56b7a Mon Sep 17 00:00:00 2001 From: Yako Date: Wed, 24 Sep 2014 16:35:34 +0800 Subject: [PATCH] improve sqlserver parser --- .../ast/stmt/SQLServerBlockStatement.java | 46 ++++++++++ .../ast/stmt/SQLServerIfStatement.java | 89 +++++++++++++++++++ .../sqlserver/parser/SQLServerLexer.java | 4 + .../parser/SQLServerStatementParser.java | 48 ++++++++++ .../visitor/SQLServerASTVisitor.java | 15 ++++ .../visitor/SQLServerASTVisitorAdapter.java | 33 +++++++ .../visitor/SQLServerOutputVisitor.java | 83 ++++++++++++++++- .../visitor/SQLServerSchemaStatVisitor.java | 43 ++++++++- .../druid/sql/parser/SQLStatementParser.java | 3 + .../bvt/sql/sqlserver/SQLServerIfTest.java | 47 ++++++++++ 10 files changed, 409 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerBlockStatement.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerIfStatement.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerIfTest.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerBlockStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerBlockStatement.java new file mode 100644 index 0000000000..5f6b699599 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerBlockStatement.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.sql.dialect.sqlserver.ast.stmt; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLStatement; +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 SQLServerBlockStatement extends SQLServerObjectImpl implements SQLServerStatement { + + private List statementList = new ArrayList(); + + public List getStatementList() { + return statementList; + } + + public void setStatementList(List statementList) { + this.statementList = statementList; + } + + @Override + public void accept0(SQLServerASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, statementList); + } + visitor.endVisit(this); + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerIfStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerIfStatement.java new file mode 100644 index 0000000000..6f73d4a771 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerIfStatement.java @@ -0,0 +1,89 @@ +/* + * 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.sql.dialect.sqlserver.ast.stmt; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLStatement; +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 SQLServerIfStatement extends SQLServerObjectImpl implements SQLServerStatement { + + private SQLExpr condition; + private List statements = new ArrayList(); + private Else elseItem; + + @Override + public void accept0(SQLServerASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, condition); + acceptChild(visitor, statements); + acceptChild(visitor, elseItem); + } + visitor.endVisit(this); + } + + public SQLExpr getCondition() { + return condition; + } + + public void setCondition(SQLExpr condition) { + this.condition = condition; + } + + public List getStatements() { + return statements; + } + + public void setStatements(List statements) { + this.statements = statements; + } + + public Else getElseItem() { + return elseItem; + } + + public void setElseItem(Else elseItem) { + this.elseItem = elseItem; + } + + public static class Else extends SQLServerObjectImpl { + + private List statements = new ArrayList(); + + @Override + public void accept0(SQLServerASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, statements); + } + visitor.endVisit(this); + } + + public List getStatements() { + return statements; + } + + public void setStatements(List statements) { + this.statements = statements; + } + + } + +} 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 c974625e8f..7d761fd0a0 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 @@ -42,6 +42,10 @@ public class SQLServerLexer extends Lexer { map.put("PERCENT", Token.PERCENT); map.put("IDENTITY", Token.IDENTITY); map.put("DECLARE", Token.DECLARE); + map.put("IF", Token.IF); + map.put("ELSE", Token.ELSE); + map.put("BEGIN", Token.BEGIN); + map.put("END", Token.END); 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 a3abfa583c..d592f6e51e 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 @@ -32,8 +32,10 @@ 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.SQLServerBlockStatement; 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.SQLServerIfStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetTransactionIsolationLevelStatement; @@ -87,6 +89,16 @@ public class SQLServerStatementParser extends SQLStatementParser { statementList.add(this.parseDeclare()); return true; } + + if (lexer.token() == Token.IF) { + statementList.add(this.parseIf()); + return true; + } + + if (lexer.token() == Token.BEGIN) { + statementList.add(this.parseBlock()); + return true; + } return false; } @@ -374,4 +386,40 @@ public class SQLServerStatementParser extends SQLStatementParser { return stmt; } } + + public SQLServerIfStatement parseIf() { + accept(Token.IF); + + SQLServerIfStatement stmt = new SQLServerIfStatement(); + + stmt.setCondition(this.exprParser.expr()); + + this.parseStatementList(stmt.getStatements(), 1); + + if(lexer.token() == Token.SEMI) { + lexer.nextToken(); + } + + if (lexer.token() == Token.ELSE) { + lexer.nextToken(); + + SQLServerIfStatement.Else elseItem = new SQLServerIfStatement.Else(); + this.parseStatementList(elseItem.getStatements(), 1); + stmt.setElseItem(elseItem); + } + + return stmt; + } + + public SQLServerBlockStatement parseBlock() { + SQLServerBlockStatement block = new SQLServerBlockStatement(); + + accept(Token.BEGIN); + + parseStatementList(block.getStatementList()); + + accept(Token.END); + + return block; + } } 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 8aa1dacdcd..4dcc822fa2 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 @@ -21,8 +21,11 @@ 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.SQLServerBlockStatement; 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.SQLServerIfStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerIfStatement.Else; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetTransactionIsolationLevelStatement; @@ -82,5 +85,17 @@ public interface SQLServerASTVisitor extends SQLASTVisitor { boolean visit(SQLServerDeclareStatement x); void endVisit(SQLServerDeclareStatement x); + + boolean visit(Else x); + + void endVisit(Else x); + + boolean visit(SQLServerIfStatement x); + + void endVisit(SQLServerIfStatement x); + + boolean visit(SQLServerBlockStatement x); + + void endVisit(SQLServerBlockStatement 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 e0c7799089..cb9c017a0e 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 @@ -21,8 +21,11 @@ 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.SQLServerBlockStatement; 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.SQLServerIfStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerIfStatement.Else; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetTransactionIsolationLevelStatement; @@ -161,4 +164,34 @@ public class SQLServerASTVisitorAdapter extends SQLASTVisitorAdapter implements } + @Override + public boolean visit(Else x) { + return true; + } + + @Override + public void endVisit(Else x) { + + } + + @Override + public boolean visit(SQLServerIfStatement x) { + return true; + } + + @Override + public void endVisit(SQLServerIfStatement x) { + + } + + @Override + public boolean visit(SQLServerBlockStatement x) { + return true; + } + + @Override + public void endVisit(SQLServerBlockStatement 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 9868f724f5..f19bfee4c6 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 @@ -17,6 +17,7 @@ package com.alibaba.druid.sql.dialect.sqlserver.visitor; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLSetQuantifier; +import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLColumnConstraint; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; @@ -28,8 +29,11 @@ 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.SQLServerBlockStatement; 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.SQLServerIfStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerIfStatement.Else; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetTransactionIsolationLevelStatement; @@ -463,6 +467,83 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe @Override public void endVisit(SQLServerDeclareStatement x) { - + + } + + @Override + public boolean visit(Else x) { + print("ELSE"); + incrementIndent(); + println(); + + for (int i = 0, size = x.getStatements().size(); i < size; ++i) { + if (i != 0) { + println(); + } + SQLStatement item = x.getStatements().get(i); + item.setParent(x); + item.accept(this); + } + + decrementIndent(); + return false; + } + + @Override + public void endVisit(Else x) { + + } + + @Override + public boolean visit(SQLServerIfStatement x) { + print("IF "); + x.getCondition().accept(this); + incrementIndent(); + println(); + for (int i = 0, size = x.getStatements().size(); i < size; ++i) { + SQLStatement item = x.getStatements().get(i); + item.setParent(x); + item.accept(this); + if (i != size - 1) { + println(); + } + } + decrementIndent(); + + if (x.getElseItem() != null) { + println(); + x.getElseItem().accept(this); + } + return false; + } + + @Override + public void endVisit(SQLServerIfStatement x) { + + } + + @Override + public boolean visit(SQLServerBlockStatement x) { + print("BEGIN"); + incrementIndent(); + println(); + for (int i = 0, size = x.getStatementList().size(); i < size; ++i) { + if (i != 0) { + println(); + } + SQLStatement stmt = x.getStatementList().get(i); + stmt.setParent(x); + stmt.accept(this); + print(";"); + } + decrementIndent(); + println(); + print("END"); + return false; + } + + @Override + public void endVisit(SQLServerBlockStatement 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 d6665ff303..cc2116479d 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 @@ -17,9 +17,11 @@ package com.alibaba.druid.sql.dialect.sqlserver.visitor; import java.util.Map; +import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.OracleParameter; 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; @@ -27,8 +29,11 @@ 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.SQLServerBlockStatement; 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.SQLServerIfStatement; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerIfStatement.Else; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetTransactionIsolationLevelStatement; @@ -182,7 +187,13 @@ public class SQLServerSchemaStatVisitor extends SchemaStatVisitor implements SQL @Override public boolean visit(SQLServerDeclareStatement x) { - return false; + for (SQLServerDeclareItem item : x.getItems()) { + item.setParent(x); + + SQLExpr name = item.getName(); + this.variants.put(name.toString(), name); + } + return true; } @Override @@ -190,4 +201,34 @@ public class SQLServerSchemaStatVisitor extends SchemaStatVisitor implements SQL } + @Override + public boolean visit(Else x) { + return true; + } + + @Override + public void endVisit(Else x) { + + } + + @Override + public boolean visit(SQLServerIfStatement x) { + return true; + } + + @Override + public void endVisit(SQLServerIfStatement x) { + + } + + @Override + public boolean visit(SQLServerBlockStatement x) { + return true; + } + + @Override + public void endVisit(SQLServerBlockStatement x) { + + } + } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java index ccf68e08d4..17ea3f836b 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -123,6 +123,9 @@ public class SQLStatementParser extends SQLParser { if (lexer.token() == Token.EOF) { return; } + if (lexer.token() == Token.END) { + return; + } if (lexer.token() == (Token.SEMI)) { lexer.nextToken(); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerIfTest.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerIfTest.java new file mode 100644 index 0000000000..51343f71fb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerIfTest.java @@ -0,0 +1,47 @@ +/* + * 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 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; + +import junit.framework.TestCase; + +public class SQLServerIfTest extends TestCase { + + public void test() { + String sql = "if @is_exists is null begin insert into Inventory_1 (co_id,sku_id,order_lock) values (@0,@1,@2) end else begin insert into Inventory_2 (co_id,sku_id,order_lock) values (@0,@1,@2) end "; + String expect = "IF @is_exists IS NULL"// + + "\n\tBEGIN"// + + "\n\t\tINSERT INTO Inventory_1"// + + "\n\t\t\t(co_id, sku_id, order_lock)"// + + "\n\t\tVALUES"// + + "\n\t\t(@0, @1, @2);"// + + "\n\tEND"// + + "\nELSE"// + + "\n\tBEGIN"// + + "\n\t\tINSERT INTO Inventory_2"// + + "\n\t\t\t(co_id, sku_id, order_lock)"// + + "\n\t\tVALUES"// + + "\n\t\t(@0, @1, @2);"// + + "\n\tEND"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + + String text = TestUtils.outputSqlServer(stmt); + + Assert.assertEquals(expect, text); + + System.out.println(text); + } + +}