diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerSetStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerSetStatement.java new file mode 100644 index 0000000000..3bf15a6957 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerSetStatement.java @@ -0,0 +1,56 @@ +/* + * 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 com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.statement.SQLAssignItem; +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 SQLServerSetStatement extends SQLServerObjectImpl implements SQLServerStatement { + + private SQLAssignItem item = new SQLAssignItem(); + + + public SQLServerSetStatement(){ + } + + public SQLServerSetStatement(SQLExpr target, SQLExpr value){ + this.item = new SQLAssignItem(target, value); + } + + public SQLAssignItem getItem() { + return item; + } + + public void setItem(SQLAssignItem item) { + this.item = item; + } + + public void output(StringBuffer buf) { + buf.append("SET "); + item.output(buf); + } + + @Override + public void accept0(SQLServerASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, this.item); + } + visitor.endVisit(this); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerSetTransactionIsolationLevelStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerSetTransactionIsolationLevelStatement.java new file mode 100644 index 0000000000..558467357e --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/ast/stmt/SQLServerSetTransactionIsolationLevelStatement.java @@ -0,0 +1,40 @@ +/* + * 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 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 SQLServerSetTransactionIsolationLevelStatement extends SQLServerObjectImpl implements SQLServerStatement { + + private String level; + + @Override + public void accept0(SQLServerASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + +} 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 ab0fc58e10..f279bf2da5 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 @@ -19,16 +19,21 @@ import java.util.List; 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.SQLInsertInto; 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.SQLServerTop; 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; +import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetTransactionIsolationLevelStatement; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement; import com.alibaba.druid.sql.parser.Lexer; +import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.Token; @@ -181,4 +186,89 @@ public class SQLServerStatementParser extends SQLStatementParser { public SQLServerExprParser getExprParser() { return (SQLServerExprParser) exprParser; } + + public SQLStatement parseSet() { + accept(Token.SET); + + if (identifierEquals("TRANSACTION")) { + lexer.nextToken(); + acceptIdentifier("ISOLATION"); + acceptIdentifier("LEVEL"); + + SQLServerSetTransactionIsolationLevelStatement stmt = new SQLServerSetTransactionIsolationLevelStatement(); + + if (identifierEquals("READ")) { + lexer.nextToken(); + + if (identifierEquals("UNCOMMITTED")) { + stmt.setLevel("READ UNCOMMITTED"); + lexer.nextToken(); + } else if (identifierEquals("COMMITTED")) { + stmt.setLevel("READ COMMITTED"); + lexer.nextToken(); + } else { + throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); + } + } else if (identifierEquals("SERIALIZABLE")) { + stmt.setLevel("SERIALIZABLE"); + lexer.nextToken(); + } else if (identifierEquals("SNAPSHOT")) { + stmt.setLevel("SNAPSHOT"); + lexer.nextToken(); + } else if (identifierEquals("REPEATABLE")) { + lexer.nextToken(); + if (identifierEquals("READ")) { + stmt.setLevel("REPEATABLE READ"); + lexer.nextToken(); + } else { + throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); + } + } else { + throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); + } + + return stmt; + } + + if (identifierEquals("STATISTICS")) { + lexer.nextToken(); + + SQLServerSetStatement stmt = new SQLServerSetStatement(); + + if (identifierEquals("IO") || identifierEquals("XML") || identifierEquals("PROFILE") + || identifierEquals("TIME")) { + stmt.getItem().setTarget(new SQLIdentifierExpr("STATISTICS " + lexer.stringVal().toUpperCase())); + + lexer.nextToken(); + if (lexer.token() == Token.ON) { + stmt.getItem().setValue(new SQLIdentifierExpr("ON")); + lexer.nextToken(); + } else if (identifierEquals("OFF")) { + stmt.getItem().setValue(new SQLIdentifierExpr("OFF")); + lexer.nextToken(); + } + } + return stmt; + } + + if (lexer.token() == Token.VARIANT) { + SQLSetStatement stmt = new SQLSetStatement(); + parseAssignItems(stmt.getItems(), stmt); + return stmt; + } else { + SQLServerSetStatement stmt = new SQLServerSetStatement(); + stmt.getItem().setTarget(this.exprParser.expr()); + + if (lexer.token() == Token.ON) { + stmt.getItem().setValue(new SQLIdentifierExpr("ON")); + lexer.nextToken(); + } else if (identifierEquals("OFF")) { + stmt.getItem().setValue(new SQLIdentifierExpr("OFF")); + lexer.nextToken(); + } else { + stmt.getItem().setValue(this.exprParser.expr()); + } + return stmt; + } + } } 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 e328581ae6..c4a9b7a04a 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,6 +21,8 @@ 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.SQLServerExecStatement; 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; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -58,4 +60,11 @@ public interface SQLServerASTVisitor extends SQLASTVisitor { void endVisit(SQLServerExecStatement x); + boolean visit(SQLServerSetTransactionIsolationLevelStatement x); + + void endVisit(SQLServerSetTransactionIsolationLevelStatement x); + + boolean visit(SQLServerSetStatement x); + + void endVisit(SQLServerSetStatement 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 6f8a5997b9..6f610afe12 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,6 +21,8 @@ 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.SQLServerExecStatement; 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; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement; import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter; @@ -106,4 +108,24 @@ public class SQLServerASTVisitorAdapter extends SQLASTVisitorAdapter implements } + @Override + public boolean visit(SQLServerSetTransactionIsolationLevelStatement x) { + return true; + } + + @Override + public void endVisit(SQLServerSetTransactionIsolationLevelStatement x) { + + } + + @Override + public boolean visit(SQLServerSetStatement x) { + return true; + } + + @Override + public void endVisit(SQLServerSetStatement 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 6bb20d8fbb..5f31ac1df4 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.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLColumnConstraint; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; @@ -27,6 +28,8 @@ 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.SQLServerExecStatement; 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; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement; import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; @@ -320,4 +323,31 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe public void endVisit(SQLServerExecStatement x) { } + + @Override + public boolean visit(SQLServerSetTransactionIsolationLevelStatement x) { + print("SET TRANSACTION ISOLATION LEVEL "); + print(x.getLevel()); + return false; + } + + @Override + public void endVisit(SQLServerSetTransactionIsolationLevelStatement x) { + + } + + @Override + public boolean visit(SQLServerSetStatement x) { + print("SET "); + SQLAssignItem item = x.getItem(); + item.getTarget().accept(this); + print(" "); + item.getValue().accept(this); + return false; + } + + @Override + public void endVisit(SQLServerSetStatement 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 d4e1236280..a086de6e5f 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 @@ -27,6 +27,8 @@ 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.SQLServerExecStatement; 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; import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement; import com.alibaba.druid.sql.visitor.SchemaStatVisitor; import com.alibaba.druid.stat.TableStat; @@ -135,4 +137,24 @@ public class SQLServerSchemaStatVisitor extends SchemaStatVisitor implements SQL } + @Override + public boolean visit(SQLServerSetTransactionIsolationLevelStatement x) { + return false; + } + + @Override + public void endVisit(SQLServerSetTransactionIsolationLevelStatement x) { + + } + + @Override + public boolean visit(SQLServerSetStatement x) { + return false; + } + + @Override + public void endVisit(SQLServerSetStatement x) { + + } + } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSetTest.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSetTest.java new file mode 100644 index 0000000000..6ba7934302 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSetTest.java @@ -0,0 +1,120 @@ +/* + * 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.parser.SQLServerStatementParser; +import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor; +import com.alibaba.druid.util.JdbcUtils; + +public class SQLServerSetTest extends TestCase { + + public void test_0() { + String sql = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List stmtList = parser.parseStatementList(); + SQLStatement stmt = stmtList.get(0); + + Assert.assertEquals(1, stmtList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + Assert.assertEquals(0, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + String text = SQLUtils.toSQLString(stmtList, JdbcUtils.SQL_SERVER); + + Assert.assertEquals("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED", text); + } + + public void test_1() { + String sql = "SET FMTONLY ON"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List stmtList = parser.parseStatementList(); + SQLStatement stmt = stmtList.get(0); + + Assert.assertEquals(1, stmtList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + Assert.assertEquals(0, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + String text = SQLUtils.toSQLString(stmtList, JdbcUtils.SQL_SERVER); + + Assert.assertEquals("SET FMTONLY ON", text); + } + + public void test_2() { + String sql = "SET STATISTICS XML OFF"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List stmtList = parser.parseStatementList(); + SQLStatement stmt = stmtList.get(0); + + Assert.assertEquals(1, stmtList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + Assert.assertEquals(0, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + String text = SQLUtils.toSQLString(stmtList, JdbcUtils.SQL_SERVER); + + Assert.assertEquals("SET STATISTICS XML OFF", text); + } + + public void test_3() { + String sql = "SET @state = N'Oregon'"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + List stmtList = parser.parseStatementList(); + SQLStatement stmt = stmtList.get(0); + + Assert.assertEquals(1, stmtList.size()); + + SQLServerSchemaStatVisitor visitor = new SQLServerSchemaStatVisitor(); + stmt.accept(visitor); + + Assert.assertEquals(0, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + String text = SQLUtils.toSQLString(stmtList, JdbcUtils.SQL_SERVER); + + Assert.assertEquals("SET @state = N'Oregon'", text); + } +}