improved db2 sql parser, support db2 interval expr. for issue #2037

This commit is contained in:
wenshao
2017-10-11 10:09:50 +08:00
parent cef99c1738
commit abad78e4a3
15 changed files with 384 additions and 14 deletions
@@ -248,7 +248,7 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable, SQLRe
}
}
if (hash == FnvHash.Constants.WM_CONAT
if (hash == FnvHash.Constants.WM_CONCAT
|| hash == FnvHash.Constants.GROUP_CONCAT) {
return SQLCharExpr.DEFAULT_DATA_TYPE;
}
@@ -25,11 +25,16 @@ import java.util.List;
public class SQLIntervalExpr extends SQLExprImpl {
private SQLExpr value;
private SQLIntervalUnit unit;
private SQLIntervalUnit unit;
public SQLIntervalExpr(){
}
public SQLIntervalExpr(SQLExpr value, SQLIntervalUnit unit){
setValue(value);
this.unit = unit;
}
public SQLIntervalExpr clone() {
SQLIntervalExpr x = new SQLIntervalExpr();
if (value != null) {
@@ -15,9 +15,11 @@
*/
package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLUnionQuery extends SQLObjectImpl implements SQLSelectQuery {
@@ -29,7 +31,8 @@ public class SQLUnionQuery extends SQLObjectImpl implements SQLSelectQuery {
private SQLUnionOperator operator = SQLUnionOperator.UNION;
private SQLOrderBy orderBy;
private SQLLimit limit;
private SQLLimit limit;
private String dbType;
public SQLUnionOperator getOperator() {
return operator;
@@ -133,6 +136,8 @@ public class SQLUnionQuery extends SQLObjectImpl implements SQLSelectQuery {
x.setLimit(limit.clone());
}
x.dbType = dbType;
return x;
}
@@ -147,4 +152,17 @@ public class SQLUnionQuery extends SQLObjectImpl implements SQLSelectQuery {
return null;
}
public String getDbType() {
return dbType;
}
public void setDbType(String dbType) {
this.dbType = dbType;
}
public void output(StringBuffer buf) {
SQLASTOutputVisitor visitor = SQLUtils.createOutputVisitor(buf, dbType);
this.accept(visitor);
}
}
@@ -17,8 +17,14 @@ package com.alibaba.druid.sql.dialect.db2.ast;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2ASTVisitor;
import com.alibaba.druid.util.FnvHash;
public interface DB2Object extends SQLObject {
void accept0(DB2ASTVisitor visitor);
interface Constants {
long CURRENT_DATE = FnvHash.fnv1a_64_lower("CURRENT DATE");
long CURRENT_TIME = FnvHash.fnv1a_64_lower("CURRENT TIME");
}
}
@@ -18,6 +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.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntervalExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntervalUnit;
import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.SQLExprParser;
@@ -93,9 +95,42 @@ public class DB2ExprParser extends SQLExprParser {
if (identExpr.hashCode64() == FnvHash.Constants.CURRENT) {
lexer.nextToken();
expr = new SQLIdentifierExpr("CURRENT DATE");
expr = new SQLIdentifierExpr("CURRENT TIMESTAMP");
}
}
} else if (lexer.identifierEquals(FnvHash.Constants.TIME)) {
if (expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
if (identExpr.hashCode64() == FnvHash.Constants.CURRENT) {
lexer.nextToken();
expr = new SQLIdentifierExpr("CURRENT TIME");
}
}
} else if (lexer.identifierEquals(FnvHash.Constants.MONTHS)) {
SQLIntervalExpr intervalExpr = new SQLIntervalExpr(expr, SQLIntervalUnit.MONTH);
lexer.nextToken();
expr = intervalExpr;
} else if (lexer.identifierEquals(FnvHash.Constants.YEARS)) {
SQLIntervalExpr intervalExpr = new SQLIntervalExpr(expr, SQLIntervalUnit.YEAR);
lexer.nextToken();
expr = intervalExpr;
} else if (lexer.identifierEquals(FnvHash.Constants.DAYS)) {
SQLIntervalExpr intervalExpr = new SQLIntervalExpr(expr, SQLIntervalUnit.DAY);
lexer.nextToken();
expr = intervalExpr;
} else if (lexer.identifierEquals(FnvHash.Constants.HOURS)) {
SQLIntervalExpr intervalExpr = new SQLIntervalExpr(expr, SQLIntervalUnit.HOUR);
lexer.nextToken();
expr = intervalExpr;
} else if (lexer.identifierEquals(FnvHash.Constants.MINUTES)) {
SQLIntervalExpr intervalExpr = new SQLIntervalExpr(expr, SQLIntervalUnit.MINUTE);
lexer.nextToken();
expr = intervalExpr;
} else if (lexer.identifierEquals(FnvHash.Constants.SECONDS)) {
SQLIntervalExpr intervalExpr = new SQLIntervalExpr(expr, SQLIntervalUnit.SECOND);
lexer.nextToken();
expr = intervalExpr;
}
return super.primaryRest(expr);
@@ -22,15 +22,18 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock.Isolation;
import com.alibaba.druid.sql.parser.*;
import com.alibaba.druid.util.JdbcConstants;
public class DB2SelectParser extends SQLSelectParser {
public DB2SelectParser(SQLExprParser exprParser){
super(exprParser);
dbType = JdbcConstants.DB2;
}
public DB2SelectParser(SQLExprParser exprParser, SQLSelectListCache selectListCache){
super(exprParser, selectListCache);
dbType = JdbcConstants.DB2;
}
public DB2SelectParser(String sql){
@@ -15,9 +15,12 @@
*/
package com.alibaba.druid.sql.dialect.db2.visitor;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
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.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2CreateTableStatement;
@@ -143,4 +146,17 @@ public class DB2OutputVisitor extends SQLASTOutputVisitor implements DB2ASTVisit
print0(ucase ? operator.name : operator.name_lcase);
}
}
public boolean visit(SQLIntervalExpr x) {
SQLExpr value = x.getValue();
value.accept(this);
SQLIntervalUnit unit = x.getUnit();
if (unit != null) {
print(' ');
print0(ucase ? unit.name() : unit.name_lcase);
print(ucase ? 'S' : 's');
}
return false;
}
}
@@ -17,6 +17,7 @@ package com.alibaba.druid.sql.dialect.db2.visitor;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.dialect.db2.ast.DB2Object;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2CreateTableStatement;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2ValuesStatement;
@@ -57,4 +58,8 @@ public class DB2SchemaStatVisitor extends SchemaStatVisitor implements DB2ASTVis
public void endVisit(DB2CreateTableStatement x) {
}
protected boolean isPseudoColumn(long hash64) {
return hash64 == DB2Object.Constants.CURRENT_DATE || hash64 == DB2Object.Constants.CURRENT_TIME;
}
}
@@ -1035,7 +1035,7 @@ public class SQLExprParser extends SQLParser {
}
if (lexer.token == Token.LPAREN) {
expr = methodRest(expr, name);
expr = methodRest(expr, name, false);
} else {
expr = new SQLPropertyExpr(expr, name, hash_lower);
}
@@ -1045,7 +1045,7 @@ public class SQLExprParser extends SQLParser {
return expr;
}
private SQLExpr methodRest(SQLExpr expr, String name) {
private SQLExpr methodRest(SQLExpr expr, String name, boolean aggregate) {
lexer.nextToken();
if (lexer.token == Token.DISTINCT) {
@@ -1066,6 +1066,21 @@ public class SQLExprParser extends SQLParser {
accept(Token.RPAREN);
}
expr = aggregateExpr;
} else if (aggregate) {
SQLAggregateExpr methodInvokeExpr = new SQLAggregateExpr(name);
methodInvokeExpr.setMethodName(expr.toString() + "." + name);
if (lexer.token == Token.RPAREN) {
lexer.nextToken();
} else {
if (lexer.token == Token.PLUS) {
methodInvokeExpr.addArgument(new SQLIdentifierExpr("+"));
lexer.nextToken();
} else {
exprList(methodInvokeExpr.getArguments(), methodInvokeExpr);
}
accept(Token.RPAREN);
}
expr = methodInvokeExpr;
} else {
SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(name);
methodInvokeExpr.setOwner(expr);
@@ -2657,7 +2672,8 @@ public class SQLExprParser extends SQLParser {
token = lexer.token;
if (token == Token.LPAREN) {
expr = methodRest(expr, name);
boolean aggregate = hash_lower == FnvHash.Constants.WMSYS && name_hash_lower == FnvHash.Constants.WM_CONCAT;
expr = methodRest(expr, name, aggregate);
token = lexer.token;
} else {
if (name_hash_lower == FnvHash.Constants.NEXTVAL) {
@@ -84,7 +84,9 @@ public class SQLSelectParser extends SQLParser {
}
protected SQLUnionQuery createSQLUnionQuery() {
return new SQLUnionQuery();
SQLUnionQuery union = new SQLUnionQuery();
union.setDbType(getDbType());
return union;
}
public SQLUnionQuery unionRest(SQLUnionQuery union) {
@@ -19,6 +19,7 @@ import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.db2.ast.DB2Object;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2ASTVisitorAdapter;
import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
@@ -230,8 +231,6 @@ class SchemaResolveVisitorFactory {
}
}
static class DB2ResolveVisitor extends DB2ASTVisitorAdapter implements SchemaResolveVisitor {
private SchemaRepository repository;
private int options;
@@ -283,6 +282,11 @@ class SchemaResolveVisitorFactory {
}
public boolean visit(SQLIdentifierExpr x) {
long hash64 = x.hashCode64();
if (hash64 == DB2Object.Constants.CURRENT_DATE || hash64 == DB2Object.Constants.CURRENT_TIME) {
return false;
}
resolve(this, x);
return true;
}
@@ -1684,7 +1688,7 @@ class SchemaResolveVisitorFactory {
if (ctxTable instanceof SQLJoinTableSource) {
String alias = tableSource.computeAlias();
if (alias == null) {
if (alias == null || tableSource instanceof SQLWithSubqueryClause.Entry) {
return;
}
@@ -350,6 +350,7 @@ public final class FnvHash {
long DATE = fnv1a_64_lower("DATE");
long DATETIME = fnv1a_64_lower("DATETIME");
long TIME = fnv1a_64_lower("TIME");
long TIMESTAMP = fnv1a_64_lower("TIMESTAMP");
long CLOB = fnv1a_64_lower("CLOB");
long NCLOB = fnv1a_64_lower("NCLOB");
@@ -371,7 +372,7 @@ public final class FnvHash {
long CURRENT = fnv1a_64_lower("CURRENT");
long COUNT = fnv1a_64_lower("COUNT");
long ROW_NUMBER = fnv1a_64_lower("ROW_NUMBER");
long WM_CONAT = fnv1a_64_lower("WM_CONAT");
long WM_CONCAT = fnv1a_64_lower("WM_CONCAT");
long AVG = fnv1a_64_lower("AVG");
long MAX = fnv1a_64_lower("MAX");
long MIN = fnv1a_64_lower("MIN");
@@ -472,6 +473,13 @@ public final class FnvHash {
long MINUTE = fnv1a_64_lower("MINUTE");
long SECOND = fnv1a_64_lower("SECOND");
long SECONDS = fnv1a_64_lower("SECONDS");
long MINUTES = fnv1a_64_lower("MINUTES");
long HOURS = fnv1a_64_lower("HOURS");
long DAYS = fnv1a_64_lower("DAYS");
long MONTHS = fnv1a_64_lower("MONTHS");
long YEARS = fnv1a_64_lower("YEARS");
long BEFORE = fnv1a_64_lower("BEFORE");
long AFTER = fnv1a_64_lower("AFTER");
long INSTEAD = fnv1a_64_lower("INSTEAD");
@@ -515,5 +523,6 @@ public final class FnvHash {
long VALIDPROC = fnv1a_64_lower("VALIDPROC");
long COMPRESS = fnv1a_64_lower("COMPRESS");
long YES = fnv1a_64_lower("YES");
long WMSYS = fnv1a_64_lower("WMSYS");
}
}