diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSequenceExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSequenceExpr.java new file mode 100644 index 0000000000..6d182af364 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSequenceExpr.java @@ -0,0 +1,79 @@ +package com.alibaba.druid.sql.ast.expr; + +import com.alibaba.druid.sql.ast.SQLExprImpl; +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class SQLSequenceExpr extends SQLExprImpl { + + private SQLName sequence; + private Function function; + + public SQLSequenceExpr(){ + + } + + public SQLSequenceExpr(SQLName sequence, Function function){ + this.sequence = sequence; + this.function = function; + } + + @Override + protected void accept0(SQLASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, sequence); + } + visitor.endVisit(this); + } + + public static enum Function { + NextVal("NEXTVAL"), CurrVal("CURRVAL"), PrevVal("PREVVAL"); + + public final String name; + public final String name_lcase; + + private Function(String name){ + this.name = name; + this.name_lcase = name.toLowerCase(); + } + } + + public SQLName getSequence() { + return sequence; + } + + public void setSequence(SQLName sequence) { + this.sequence = sequence; + } + + public Function getFunction() { + return function; + } + + public void setFunction(Function function) { + this.function = function; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((function == null) ? 0 : function.hashCode()); + result = prime * result + ((sequence == null) ? 0 : sequence.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + SQLSequenceExpr other = (SQLSequenceExpr) obj; + if (function != other.function) return false; + if (sequence == null) { + if (other.sequence != null) return false; + } else if (!sequence.equals(other.sequence)) return false; + return true; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index daffa6e1a7..0060ca49b4 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -59,6 +59,7 @@ import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr; import com.alibaba.druid.sql.ast.expr.SQLSomeExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryOperator; @@ -688,7 +689,8 @@ public class SQLExprParser extends SQLParser { throw new IllegalArgumentException("expr"); } - if (lexer.token() == Token.OF) { + Token token = lexer.token; + if (token == Token.OF) { if (expr instanceof SQLIdentifierExpr) { String name = ((SQLIdentifierExpr) expr).getName(); if ("CURRENT".equalsIgnoreCase(name)) { @@ -697,9 +699,30 @@ public class SQLExprParser extends SQLParser { return new SQLCurrentOfCursorExpr(cursorName); } } + } else if (token == Token.FOR) { + if (expr instanceof SQLIdentifierExpr) { + SQLIdentifierExpr idenExpr = (SQLIdentifierExpr) expr; + String name = idenExpr.getName(); + if ("NEXTVAL".equalsIgnoreCase(name)) { + lexer.nextToken(); + SQLName seqName = this.name(); + SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.NextVal); + return seqExpr; + } else if ("CURRVAL".equalsIgnoreCase(name)) { + lexer.nextToken(); + SQLName seqName = this.name(); + SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.CurrVal); + return seqExpr; + } else if ("PREVVAL".equalsIgnoreCase(name)) { + lexer.nextToken(); + SQLName seqName = this.name(); + SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.PrevVal); + return seqExpr; + } + } } - if (lexer.token() == Token.DOT) { + if (token == Token.DOT) { lexer.nextToken(); if (expr instanceof SQLCharExpr) { diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index c7cfb02591..d1e47786a4 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -78,6 +78,7 @@ import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr; import com.alibaba.druid.sql.ast.expr.SQLSomeExpr; import com.alibaba.druid.sql.ast.expr.SQLTimestampExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr; @@ -3073,4 +3074,12 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Printab printPartitions(x.getPartitions()); return false; } + + @Override + public boolean visit(SQLSequenceExpr x) { + x.getSequence().accept(this); + print('.'); + print0(ucase ? x.getFunction().name : x.getFunction().name_lcase); + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java index 95e6820425..d0dfc85bff 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java @@ -60,6 +60,7 @@ import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr; import com.alibaba.druid.sql.ast.expr.SQLSomeExpr; import com.alibaba.druid.sql.ast.expr.SQLTimestampExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr; @@ -696,4 +697,8 @@ public interface SQLASTVisitor { void endVisit(SQLAlterTableRepairPartition x); + boolean visit(SQLSequenceExpr x); + + void endVisit(SQLSequenceExpr x); + } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java index 4d8d7caca1..a4d18eabd6 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java @@ -61,6 +61,7 @@ import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr; import com.alibaba.druid.sql.ast.expr.SQLSomeExpr; import com.alibaba.druid.sql.ast.expr.SQLTimestampExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr; @@ -1513,4 +1514,14 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor { } + @Override + public boolean visit(SQLSequenceExpr x) { + return true; + } + + @Override + public void endVisit(SQLSequenceExpr x) { + + } + } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java index 92a3d31978..ae96478e1a 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -50,6 +50,7 @@ import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr; import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; +import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr; import com.alibaba.druid.sql.ast.statement.SQLAlterDatabaseStatement; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddIndex; @@ -1684,4 +1685,8 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { public boolean visit(SQLAlterTableRepairPartition x) { return false; } + + public boolean visit(SQLSequenceExpr x) { + return false; + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_14.java b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_14.java new file mode 100644 index 0000000000..2124ec8cfc --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_14.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2101 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.db2; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.DB2Test; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.db2.parser.DB2StatementParser; +import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Column; +import com.alibaba.druid.util.JdbcConstants; + +public class DB2SelectTest_14 extends DB2Test { + + public void test_0() throws Exception { + String sql = "SELECT (NEXTVAL FOR TEST_SEQ) FROM SYSIBM.SYSDUMMY1"; + + DB2StatementParser parser = new DB2StatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + DB2SchemaStatVisitor visitor = new DB2SchemaStatVisitor(); + 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(1, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("SYSIBM.SYSDUMMY1"))); + +// Assert.assertTrue(visitor.getColumns().contains(new Column("DSN8B10.EMP", "WORKDEPT"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "first_name"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "full_name"))); + + Assert.assertEquals("SELECT TEST_SEQ.NEXTVAL" + + "\nFROM SYSIBM.SYSDUMMY1", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2)); + + Assert.assertEquals("select TEST_SEQ.nextval" + + "\nfrom SYSIBM.SYSDUMMY1", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_15.java b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_15.java new file mode 100644 index 0000000000..7a0e75cc3d --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_15.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2101 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.db2; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.DB2Test; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.db2.parser.DB2StatementParser; +import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Column; +import com.alibaba.druid.util.JdbcConstants; + +public class DB2SelectTest_15 extends DB2Test { + + public void test_0() throws Exception { + String sql = "SELECT (PREVVAL FOR TEST_SEQ) FROM SYSIBM.SYSDUMMY1"; + + DB2StatementParser parser = new DB2StatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + DB2SchemaStatVisitor visitor = new DB2SchemaStatVisitor(); + 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(1, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("SYSIBM.SYSDUMMY1"))); + +// Assert.assertTrue(visitor.getColumns().contains(new Column("DSN8B10.EMP", "WORKDEPT"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "first_name"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "full_name"))); + + Assert.assertEquals("SELECT TEST_SEQ.PREVVAL" + + "\nFROM SYSIBM.SYSDUMMY1", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2)); + + Assert.assertEquals("select TEST_SEQ.prevval" + + "\nfrom SYSIBM.SYSDUMMY1", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_16.java b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_16.java new file mode 100644 index 0000000000..d9ade74450 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2SelectTest_16.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2101 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.db2; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.DB2Test; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.db2.parser.DB2StatementParser; +import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Column; +import com.alibaba.druid.util.JdbcConstants; + +public class DB2SelectTest_16 extends DB2Test { + + public void test_0() throws Exception { + String sql = "SELECT (CURRVAL FOR TEST_SEQ) FROM SYSIBM.SYSDUMMY1"; + + DB2StatementParser parser = new DB2StatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + DB2SchemaStatVisitor visitor = new DB2SchemaStatVisitor(); + 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(1, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("SYSIBM.SYSDUMMY1"))); + +// Assert.assertTrue(visitor.getColumns().contains(new Column("DSN8B10.EMP", "WORKDEPT"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "first_name"))); + // Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "full_name"))); + + Assert.assertEquals("SELECT TEST_SEQ.CURRVAL" + + "\nFROM SYSIBM.SYSDUMMY1", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2)); + + Assert.assertEquals("select TEST_SEQ.currval" + + "\nfrom SYSIBM.SYSDUMMY1", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + } +}