mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improved db2 sql parser, support db2 interval expr. for issue #2037
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user