From 0acd0c76df1c0acd9146004f605dd48b8d9ec4e4 Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 16 Apr 2018 00:03:21 +0800 Subject: [PATCH] improved db2 parser support. for issue #2489 --- .../com/alibaba/druid/sql/ast/SQLWindow.java | 44 +++++++++ .../druid/sql/ast/expr/SQLAggregateExpr.java | 94 ++++++++++--------- .../ast/statement/SQLColumnDefinition.java | 20 +++- .../ast/statement/SQLSelectQueryBlock.java | 15 +++ .../db2/parser/DB2CreateTableParser.java | 6 +- .../sql/dialect/db2/parser/DB2ExprParser.java | 66 ++++++++++++- .../dialect/db2/visitor/DB2OutputVisitor.java | 18 ++++ .../postgresql/parser/PGSelectParser.java | 17 +--- .../druid/sql/parser/SQLExprParser.java | 38 ++++++-- .../druid/sql/parser/SQLSelectParser.java | 23 +++++ .../sql/visitor/SQLASTOutputVisitor.java | 20 ++++ .../druid/sql/visitor/SQLASTVisitor.java | 4 + .../sql/visitor/SQLASTVisitorAdapter.java | 11 +++ .../java/com/alibaba/druid/util/FnvHash.java | 4 + .../bvt/sql/db2/DB2CreateTableTest_06.java | 67 +++++++++++++ .../select/PGSelectTest71_window.java | 72 ++++++++++++++ 16 files changed, 440 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/ast/SQLWindow.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/db2/DB2CreateTableTest_06.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest71_window.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLWindow.java b/src/main/java/com/alibaba/druid/sql/ast/SQLWindow.java new file mode 100644 index 0000000000..19c07d7548 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLWindow.java @@ -0,0 +1,44 @@ +package com.alibaba.druid.sql.ast; + +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class SQLWindow extends SQLObjectImpl { + private SQLName name; + private SQLOver over; + + public SQLWindow(SQLName name, SQLOver over) { + this.setName(name); + this.setOver(over); + } + + public SQLName getName() { + return name; + } + + public void setName(SQLName x) { + if (x != null) { + x.setParent(this); + } + this.name = x; + } + + public SQLOver getOver() { + return over; + } + + public void setOver(SQLOver x) { + if (x != null) { + x.setParent(this); + } + this.over = x; + } + + @Override + protected void accept0(SQLASTVisitor v) { + if (v.visit(this)) { + acceptChild(v, name); + acceptChild(v, over); + } + v.endVisit(this); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java index aa9a292458..8fa9e7f99d 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java @@ -36,6 +36,7 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLRe protected final List arguments = new ArrayList(); protected SQLKeep keep; protected SQLOver over; + protected SQLName overRef; protected SQLOrderBy withinGroup; protected Boolean ignoreNulls = false; @@ -104,6 +105,17 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLRe } this.over = over; } + + public SQLName getOverRef() { + return overRef; + } + + public void setOverRef(SQLName x) { + if (x != null) { + x.setParent(this); + } + this.overRef = x; + } public SQLKeep getKeep() { return keep; @@ -139,6 +151,7 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLRe acceptChild(visitor, this.arguments); acceptChild(visitor, this.keep); acceptChild(visitor, this.over); + acceptChild(visitor, this.overRef); acceptChild(visitor, this.withinGroup); } @@ -162,53 +175,35 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLRe } @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((arguments == null) ? 0 : arguments.hashCode()); - result = prime * result + ((methodName == null) ? 0 : methodName.hashCode()); - result = prime * result + ((option == null) ? 0 : option.hashCode()); - result = prime * result + ((over == null) ? 0 : over.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SQLAggregateExpr that = (SQLAggregateExpr) o; + + if (methodNameHashCod64 != that.methodNameHashCod64) return false; + if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) return false; + if (option != that.option) return false; + if (arguments != null ? !arguments.equals(that.arguments) : that.arguments != null) return false; + if (keep != null ? !keep.equals(that.keep) : that.keep != null) return false; + if (over != null ? !over.equals(that.over) : that.over != null) return false; + if (overRef != null ? !overRef.equals(that.overRef) : that.overRef != null) return false; + if (withinGroup != null ? !withinGroup.equals(that.withinGroup) : that.withinGroup != null) return false; + return ignoreNulls != null ? ignoreNulls.equals(that.ignoreNulls) : that.ignoreNulls == null; } @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - SQLAggregateExpr other = (SQLAggregateExpr) obj; - if (arguments == null) { - if (other.arguments != null) { - return false; - } - } else if (!arguments.equals(other.arguments)) { - return false; - } - if (methodName == null) { - if (other.methodName != null) { - return false; - } - } else if (!methodName.equals(other.methodName)) { - return false; - } - if (over == null) { - if (other.over != null) { - return false; - } - } else if (!over.equals(other.over)) { - return false; - } - if (option != other.option) { - return false; - } - return true; + public int hashCode() { + int result = methodName != null ? methodName.hashCode() : 0; + result = 31 * result + (int) (methodNameHashCod64 ^ (methodNameHashCod64 >>> 32)); + result = 31 * result + (option != null ? option.hashCode() : 0); + result = 31 * result + (arguments != null ? arguments.hashCode() : 0); + result = 31 * result + (keep != null ? keep.hashCode() : 0); + result = 31 * result + (over != null ? over.hashCode() : 0); + result = 31 * result + (overRef != null ? overRef.hashCode() : 0); + result = 31 * result + (withinGroup != null ? withinGroup.hashCode() : 0); + result = 31 * result + (ignoreNulls != null ? ignoreNulls.hashCode() : 0); + return result; } public SQLAggregateExpr clone() { @@ -228,6 +223,10 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLRe x.setOver(over.clone()); } + if (overRef != null) { + x.setOverRef(overRef.clone()); + } + if (withinGroup != null) { x.setWithinGroup(withinGroup.clone()); } @@ -264,6 +263,7 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLRe if (target == null) { return false; } + for (int i = 0; i < arguments.size(); ++i) { if (arguments.get(i) == expr) { arguments.set(i, target); @@ -271,6 +271,12 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLRe return true; } } + + if (overRef == expr) { + setOverRef((SQLName) target); + return true; + } + return false; } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java index 7018023d86..8cd4d02ddb 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java @@ -49,6 +49,7 @@ public class SQLColumnDefinition extends SQLObjectImpl implements SQLTableElemen protected boolean virtual = false; protected Identity identity; + protected SQLExpr generatedAlawsAs; public SQLColumnDefinition(){ @@ -59,11 +60,22 @@ public class SQLColumnDefinition extends SQLObjectImpl implements SQLTableElemen } // for sqlserver - public void setIdentity(Identity identity) { - if (identity != null) { - identity.setParent(this); + public void setIdentity(Identity x) { + if (x != null) { + x.setParent(this); } - this.identity = identity; + this.identity = x; + } + + public SQLExpr getGeneratedAlawsAs() { + return generatedAlawsAs; + } + + public void setGeneratedAlawsAs(SQLExpr x) { + if (x != null) { + x.setParent(this); + } + this.generatedAlawsAs = x; } public Boolean getEnable() { diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java index fd82f41bb7..a009cac403 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java @@ -41,6 +41,7 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery protected SQLOrderBy orderBySiblings; protected SQLSelectGroupByClause groupBy; + protected List windows; protected SQLOrderBy orderBy; protected boolean parenthesized = false; protected boolean forUpdate = false; @@ -719,4 +720,18 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery public void setDbType(String dbType) { this.dbType = dbType; } + + public List getWindows() { + return windows; + } + + public void addWindow(SQLWindow x) { + if (x != null) { + x.setParent(this); + } + if (windows == null) { + windows = new ArrayList(4); + } + this.windows.add(x); + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2CreateTableParser.java b/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2CreateTableParser.java index 3e4de067ee..a455f63d10 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2CreateTableParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2CreateTableParser.java @@ -75,11 +75,7 @@ public class DB2CreateTableParser extends SQLCreateTableParser { for (; ; ) { Token token = lexer.token(); - if (token == Token.IDENTIFIER - && lexer.stringVal().equalsIgnoreCase("SUPPLEMENTAL") - && JdbcConstants.ORACLE.equals(dbType)) { - this.parseCreateTableSupplementalLogingProps(createTable); - } else if (token == Token.IDENTIFIER // + if (token == Token.IDENTIFIER // || token == Token.LITERAL_ALIAS) { SQLColumnDefinition column = this.exprParser.parseColumn(); createTable.getTableElementList().add(column); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2ExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2ExprParser.java index 091d4cdebc..8917d2b3c3 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2ExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/db2/parser/DB2ExprParser.java @@ -18,10 +18,8 @@ package com.alibaba.druid.sql.dialect.db2.parser; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.expr.*; -import com.alibaba.druid.sql.parser.Lexer; -import com.alibaba.druid.sql.parser.SQLExprParser; -import com.alibaba.druid.sql.parser.SQLParserFeature; -import com.alibaba.druid.sql.parser.Token; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; +import com.alibaba.druid.sql.parser.*; import com.alibaba.druid.util.FnvHash; import com.alibaba.druid.util.JdbcConstants; @@ -184,4 +182,64 @@ public class DB2ExprParser extends SQLExprParser { return super.dotRest(expr); } + public SQLColumnDefinition parseColumnRest(SQLColumnDefinition column) { + column = super.parseColumnRest(column); + + if (lexer.identifierEquals(FnvHash.Constants.GENERATED)) { + lexer.nextToken(); + if (lexer.identifierEquals(FnvHash.Constants.ALWAYS)) { + lexer.nextToken(); + } else { + throw new ParserException("TODO " + lexer.info()); + } + + accept(Token.AS); + + if (lexer.token() == Token.IDENTITY) { + SQLColumnDefinition.Identity identity = parseIdentity(); + column.setIdentity(identity); + } else { + SQLExpr expr = this.expr(); + + column.setGeneratedAlawsAs(expr); + } + } + + return column; + } + + private SQLColumnDefinition.Identity parseIdentity() { + SQLColumnDefinition.Identity identity = new SQLColumnDefinition.Identity(); + + accept(Token.IDENTITY); + accept(Token.LPAREN); + + if (lexer.identifierEquals(FnvHash.Constants.START)) { + lexer.nextToken(); + accept(Token.WITH); + if (lexer.token() == Token.LITERAL_INT) { + identity.setSeed((Integer) lexer.integerValue()); + lexer.nextToken(); + } else { + throw new ParserException("TODO " + lexer.info()); + } + + accept(Token.COMMA); + } + + if (lexer.identifierEquals(FnvHash.Constants.INCREMENT)) { + lexer.nextToken(); + accept(Token.BY); + if (lexer.token() == Token.LITERAL_INT) { + identity.setIncrement((Integer) lexer.integerValue()); + lexer.nextToken(); + } else { + throw new ParserException("TODO " + lexer.info()); + } + } + + accept(Token.RPAREN); + + return identity; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java index 06553ad813..e8f76375d5 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/db2/visitor/DB2OutputVisitor.java @@ -21,6 +21,7 @@ import com.alibaba.druid.sql.ast.SQLPartitionBy; import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; import com.alibaba.druid.sql.ast.expr.SQLIntervalExpr; import com.alibaba.druid.sql.ast.expr.SQLIntervalUnit; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2CreateTableStatement; @@ -167,4 +168,21 @@ public class DB2OutputVisitor extends SQLASTOutputVisitor implements DB2ASTVisit } return false; } + + public boolean visit(SQLColumnDefinition.Identity x) { + print0(ucase ? "GENERATED ALWAYS AS IDENTITY (" : "generated always as identity ("); + + final Integer seed = x.getSeed(); + if (seed != null) { + print0(ucase ? "START WITH " : "start with "); + print(seed); + print0(", "); + } + + print0(ucase ? "INCREMENT BY " : "increment by "); + print(x.getIncrement()); + print(')'); + + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java index 454eda7177..4fb8fd39a8 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java @@ -138,22 +138,7 @@ public class PGSelectParser extends SQLSelectParser { parseGroupBy(queryBlock); if (lexer.token() == Token.WINDOW) { - lexer.nextToken(); - PGSelectQueryBlock.WindowClause window = new PGSelectQueryBlock.WindowClause(); - window.setName(this.expr()); - accept(Token.AS); - - for (;;) { - SQLExpr expr = this.createExprParser().expr(); - window.getDefinition().add(expr); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } else { - break; - } - } - queryBlock.setWindow(window); + this.parseWindow(queryBlock); } queryBlock.setOrderBy(this.createExprParser().parseOrderBy()); 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 033ab09529..ffde718bd6 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1446,8 +1446,20 @@ public class SQLExprParser extends SQLParser { protected void over(SQLAggregateExpr aggregateExpr) { lexer.nextToken(); + + if (lexer.token != Token.LPAREN) { + SQLName overRef = this.name(); + aggregateExpr.setOverRef(overRef); + return; + } + SQLOver over = new SQLOver(); - accept(Token.LPAREN); + over(over); + aggregateExpr.setOver(over); + } + + protected void over(SQLOver over) { + lexer.nextToken(); if (lexer.token == Token.PARTITION || lexer.identifierEquals("PARTITION")) { lexer.nextToken(); @@ -1463,7 +1475,7 @@ public class SQLExprParser extends SQLParser { } over.setOrderBy(parseOrderBy()); - + if (lexer.token == Token.OF) { lexer.nextToken(); SQLName of = this.name(); @@ -1484,7 +1496,7 @@ public class SQLExprParser extends SQLParser { if (lexer.token == Token.BETWEEN) { lexer.nextToken(); - SQLIntegerExpr rowsBegin = (SQLIntegerExpr) this.primary(); + SQLExpr rowsBegin = this.primary(); over.setWindowingBetweenBegin(rowsBegin); if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) { @@ -1497,7 +1509,18 @@ public class SQLExprParser extends SQLParser { accept(Token.AND); - SQLIntegerExpr betweenEnd = (SQLIntegerExpr) this.primary(); + SQLExpr betweenEnd; + if (lexer.identifierEquals(FnvHash.Constants.CURRENT)) { + lexer.nextToken(); + if (lexer.identifierEquals(FnvHash.Constants.ROW)) { + lexer.nextToken(); + } else { + accept(Token.ROW); + } + betweenEnd = new SQLIdentifierExpr("CURRENT ROW"); + } else { + betweenEnd = this.primary(); + } over.setWindowingBetweenEnd(betweenEnd); if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) { @@ -1512,7 +1535,11 @@ public class SQLExprParser extends SQLParser { if (lexer.identifierEquals(FnvHash.Constants.CURRENT)) { lexer.nextToken(); - acceptIdentifier("ROW"); + if (lexer.identifierEquals(FnvHash.Constants.ROW)) { + lexer.nextToken(); + } else { + accept(Token.ROW); + } over.setWindowing(new SQLIdentifierExpr("CURRENT ROW")); } else if (lexer.identifierEquals(FnvHash.Constants.UNBOUNDED)) { lexer.nextToken(); @@ -1541,7 +1568,6 @@ public class SQLExprParser extends SQLParser { } accept(Token.RPAREN); - aggregateExpr.setOver(over); } protected SQLAggregateExpr parseAggregateExprRest(SQLAggregateExpr aggregateExpr) { diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java index 107a81a1cc..79dc30e3a6 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java @@ -474,6 +474,29 @@ public class SQLSelectParser extends SQLParser { queryBlock.setWhere(where); } } + + protected void parseWindow(SQLSelectQueryBlock queryBlock) { + if (!(lexer.identifierEquals(FnvHash.Constants.WINDOW) || lexer.token == Token.WINDOW)) { + return; + } + + lexer.nextToken(); + + for (;;) { + SQLName name = this.exprParser.name(); + accept(Token.AS); + SQLOver over = new SQLOver(); + this.exprParser.over(over); + queryBlock.addWindow(new SQLWindow(name, over)); + + if (lexer.token == Token.COMMA) { + lexer.nextToken(); + continue; + } + + break; + } + } protected void parseGroupBy(SQLSelectQueryBlock queryBlock) { if (lexer.token == (Token.GROUP)) { 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 adf20669b6..3806840fb5 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -2418,6 +2418,18 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } } + SQLExpr generatedAlawsAs = x.getGeneratedAlawsAs(); + if (generatedAlawsAs != null) { + print0(ucase ? " GENERATED ALWAYS AS " : " generated always as "); + printExpr(generatedAlawsAs); + } + + SQLColumnDefinition.Identity identity = x.getIdentity(); + if (identity != null) { + print(' '); + identity.accept(this); + } + if (x.getEnable() != null) { if (x.getEnable().booleanValue()) { print0(ucase ? " ENABLE" : " enable"); @@ -6525,6 +6537,14 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet return false; } + @Override + public boolean visit(SQLWindow x) { + x.getName().accept(this); + print0(ucase ? " AS " : " as "); + x.getOver().accept(this); + return false; + } + public void print(float value) { if (this.appender == null) { return; 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 5fbae9f89f..17285df6bb 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java @@ -838,4 +838,8 @@ public interface SQLASTVisitor { boolean visit(SQLRealExpr x); void endVisit(SQLRealExpr x); + + boolean visit(SQLWindow x); + void endVisit(SQLWindow 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 2eeae2a510..1900a2dfa7 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java @@ -1990,6 +1990,17 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor { } + + @Override + public boolean visit(SQLWindow x) { + return true; + } + + public void endVisit(SQLWindow x) { + + } + + public final boolean isEnabled(VisitorFeature feature) { return VisitorFeature.isEnabled(this.features, feature); } diff --git a/src/main/java/com/alibaba/druid/util/FnvHash.java b/src/main/java/com/alibaba/druid/util/FnvHash.java index fb39bd7a07..0a65b9e82d 100644 --- a/src/main/java/com/alibaba/druid/util/FnvHash.java +++ b/src/main/java/com/alibaba/druid/util/FnvHash.java @@ -645,5 +645,9 @@ public final class FnvHash { long TBPARTITION = fnv1a_64_lower("TBPARTITION"); long TBPARTITIONS = fnv1a_64_lower("TBPARTITIONS"); long SOUNDS = fnv1a_64_lower("SOUNDS"); + long WINDOW = fnv1a_64_lower("WINDOW"); + long GENERATED = fnv1a_64_lower("GENERATED"); + long ALWAYS = fnv1a_64_lower("ALWAYS"); + long INCREMENT = fnv1a_64_lower("INCREMENT"); } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2CreateTableTest_06.java b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2CreateTableTest_06.java new file mode 100644 index 0000000000..7579bd9f86 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/db2/DB2CreateTableTest_06.java @@ -0,0 +1,67 @@ +/* + * Copyright 1999-2018 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 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.util.JdbcConstants; + +import java.util.List; + +public class DB2CreateTableTest_06 extends DB2Test { + + public void test_0() throws Exception { + String sql = "CREATE TABLE AUDIT.test ( ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1 ))"; + + DB2StatementParser parser = new DB2StatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + System.out.println(SQLUtils.toDB2String(stmt)); + + 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()); + + assertEquals(1, visitor.getTables().size()); + assertEquals(1, visitor.getColumns().size()); + assertEquals(0, visitor.getConditions().size()); + + assertTrue(visitor.containsTable("AUDIT.test")); + +// assertTrue(visitor.getColumns().contains(new Column("DSN8B10.EMP", "WORKDEPT"))); + // assertTrue(visitor.getColumns().contains(new Column("mytable", "first_name"))); + // assertTrue(visitor.getColumns().contains(new Column("mytable", "full_name"))); + + assertEquals("CREATE TABLE AUDIT.test (\n" + + "\tID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1)\n" + + ")", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2)); + + assertEquals("create table AUDIT.test (\n" + + "\tID INTEGER not null generated always as identity (start with 1, increment by 1)\n" + + ")", // + SQLUtils.toSQLString(stmt, JdbcConstants.DB2, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest71_window.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest71_window.java new file mode 100644 index 0000000000..64f04a3ea4 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest71_window.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2017 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.postgresql.select; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; +import junit.framework.TestCase; + +import java.util.List; + +public class PGSelectTest71_window extends TestCase { + private final String dbType = JdbcConstants.POSTGRESQL; + + public void test_0() throws Exception { + String sql = "select a.*, (a.swanav-lead(a.swanav,1,null::numeric) over w)/lead(a.swanav,1,null::numeric) over w as roe_lag\n" + + "from ffund.ffund_eval_prod_nv a\n" + + "where a.prod_id='D20171206191156525S0034R234'\n" + + "and a.stat_date>='0000-00-00'\n" + + "and a.stat_date<='9999-99-99'\n" + + "and a.nav>0 and a.swanav>0\n" + + "window w as (order by a.stat_date desc)"; + System.out.println(sql); + + List stmtList = SQLUtils.parseStatements(sql, dbType); + SQLStatement stmt = stmtList.get(0); + + assertEquals("SELECT a.*\n" + + "\t, (a.swanav - lead(a.swanav, 1, NULL::numeric)) / lead(a.swanav, 1, NULL::numeric) AS roe_lag\n" + + "FROM ffund.ffund_eval_prod_nv a\n" + + "WHERE a.prod_id = 'D20171206191156525S0034R234'\n" + + "\tAND a.stat_date >= '0000-00-00'\n" + + "\tAND a.stat_date <= '9999-99-99'\n" + + "\tAND a.nav > 0\n" + + "\tAND a.swanav > 0", SQLUtils.toPGString(stmt)); + + assertEquals("select a.*\n" + + "\t, (a.swanav - lead(a.swanav, 1, null::numeric)) / lead(a.swanav, 1, null::numeric) as roe_lag\n" + + "from ffund.ffund_eval_prod_nv a\n" + + "where a.prod_id = 'D20171206191156525S0034R234'\n" + + "\tand a.stat_date >= '0000-00-00'\n" + + "\tand a.stat_date <= '9999-99-99'\n" + + "\tand a.nav > 0\n" + + "\tand a.swanav > 0", SQLUtils.toPGString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + assertEquals(1, stmtList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); + + assertEquals(5, visitor.getColumns().size()); + assertEquals(1, visitor.getTables().size()); + } +}