mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
Add basic implementation for Teradata Select
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.ast.expr;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLOver;
|
||||
import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class TeradataAnalytic extends SQLOver implements TeradataExpr {
|
||||
|
||||
private TeradataAnalyticWindowing windowing;
|
||||
|
||||
public TeradataAnalytic(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
this.accept0((TeradataASTVisitor) visitor);
|
||||
}
|
||||
|
||||
public void accept0(TeradataASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, this.partitionBy);
|
||||
acceptChild(visitor, this.orderBy);
|
||||
acceptChild(visitor, this.windowing);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public TeradataAnalyticWindowing getWindowing() {
|
||||
return this.windowing;
|
||||
}
|
||||
|
||||
public void setWindowing(TeradataAnalyticWindowing windowing) {
|
||||
this.windowing = windowing;
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.ast.expr;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLObjectImpl;
|
||||
import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class TeradataAnalyticWindowing extends SQLObjectImpl implements TeradataExpr {
|
||||
|
||||
private Type type;
|
||||
private SQLExpr expr;
|
||||
|
||||
public TeradataAnalyticWindowing(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
this.accept0((TeradataASTVisitor) visitor);
|
||||
}
|
||||
|
||||
public void accept0(TeradataASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, this.expr);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public SQLExpr getExpr() {
|
||||
return this.expr;
|
||||
}
|
||||
|
||||
public void setExpr(SQLExpr expr) {
|
||||
this.expr = expr;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static enum Type {
|
||||
ROWS, RANGE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.ast.expr;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.dialect.teradata.ast.TeradataObject;
|
||||
|
||||
public interface TeradataExpr extends SQLExpr, TeradataObject {
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.ast.stmt;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLOrderBy;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class TeradataSelectQueryBlock extends SQLSelectQueryBlock {
|
||||
private SQLOrderBy orderBy;
|
||||
|
||||
public TeradataSelectQueryBlock() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
if (visitor instanceof TeradataASTVisitor) {
|
||||
accept0((TeradataASTVisitor) visitor);
|
||||
return;
|
||||
}
|
||||
|
||||
super.accept0(visitor);
|
||||
}
|
||||
|
||||
protected void accept0(TeradataASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, this.selectList);
|
||||
acceptChild(visitor, this.into);
|
||||
acceptChild(visitor, this.from);
|
||||
acceptChild(visitor, this.where);
|
||||
acceptChild(visitor, this.groupBy);
|
||||
acceptChild(visitor, this.orderBy);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public SQLOrderBy getOrderBy() {
|
||||
return orderBy;
|
||||
}
|
||||
|
||||
public void setOrderBy(SQLOrderBy orderBy) {
|
||||
this.orderBy = orderBy;
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,24 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.parser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLKeep;
|
||||
import com.alibaba.druid.sql.ast.SQLOrderBy;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.SQLKeep.DenseRank;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLAggregateOption;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLCastExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
|
||||
import com.alibaba.druid.sql.dialect.teradata.ast.expr.TeradataAnalytic;
|
||||
import com.alibaba.druid.sql.dialect.teradata.ast.expr.TeradataAnalyticWindowing;
|
||||
import com.alibaba.druid.sql.parser.Lexer;
|
||||
import com.alibaba.druid.sql.parser.ParserException;
|
||||
import com.alibaba.druid.sql.parser.SQLExprParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
import com.alibaba.druid.util.JdbcConstants;
|
||||
|
||||
public class TeradataExprParser extends SQLExprParser {
|
||||
@@ -35,5 +51,211 @@ public class TeradataExprParser extends SQLExprParser {
|
||||
this.dbType = JdbcConstants.TERADATA;
|
||||
}
|
||||
|
||||
public SQLExpr primary() {
|
||||
SQLExpr sqlExpr = null;
|
||||
|
||||
final Token tok = lexer.token();
|
||||
|
||||
switch (tok){
|
||||
case SEL:
|
||||
SQLQueryExpr queryExpr = new SQLQueryExpr(createSelectParser().select());
|
||||
sqlExpr = queryExpr;
|
||||
return primaryRest(sqlExpr);
|
||||
case CAST:
|
||||
System.out.println("cast test!");
|
||||
lexer.nextToken();
|
||||
accept(Token.LPAREN);
|
||||
SQLCastExpr cast = new SQLCastExpr();
|
||||
cast.setExpr(expr());
|
||||
accept(Token.AS);
|
||||
cast.setDataType(parseDataType());
|
||||
// TODO: deal with FORMAT
|
||||
// currently ignore FORMAT keywords
|
||||
if(lexer.token() == Token.FORMAT) {
|
||||
lexer.nextToken();
|
||||
lexer.nextToken();
|
||||
}
|
||||
accept(Token.RPAREN);
|
||||
return primaryRest(cast);
|
||||
default:
|
||||
return super.primary();
|
||||
}
|
||||
}
|
||||
|
||||
protected SQLAggregateExpr parseAggregateExpr(String methodName) {
|
||||
methodName = methodName.toUpperCase();
|
||||
|
||||
SQLAggregateExpr aggregateExpr;
|
||||
if (lexer.token() == Token.UNIQUE) {
|
||||
aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.UNIQUE);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == (Token.ALL)) {
|
||||
aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.ALL);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == (Token.DISTINCT)) {
|
||||
aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.DISTINCT);
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
aggregateExpr = new SQLAggregateExpr(methodName);
|
||||
}
|
||||
exprList(aggregateExpr.getArguments(), aggregateExpr);
|
||||
|
||||
accept(Token.RPAREN);
|
||||
|
||||
if (lexer.token() == Token.KEEP) {
|
||||
lexer.nextToken();
|
||||
|
||||
SQLKeep keep = new SQLKeep();
|
||||
accept(Token.LPAREN);
|
||||
acceptIdentifier("DENSE_RANK");
|
||||
if (identifierEquals("FIRST")) {
|
||||
lexer.nextToken();
|
||||
keep.setDenseRank(DenseRank.FIRST);
|
||||
} else {
|
||||
acceptIdentifier("LAST");
|
||||
keep.setDenseRank(DenseRank.LAST);
|
||||
}
|
||||
|
||||
SQLOrderBy orderBy = this.parseOrderBy();
|
||||
keep.setOrderBy(orderBy);
|
||||
|
||||
aggregateExpr.setKeep(keep);
|
||||
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.OVER) {
|
||||
TeradataAnalytic over = new TeradataAnalytic();
|
||||
|
||||
lexer.nextToken();
|
||||
accept(Token.LPAREN);
|
||||
|
||||
if (identifierEquals("PARTITION")) {
|
||||
lexer.nextToken();
|
||||
accept(Token.BY);
|
||||
|
||||
if (lexer.token() == (Token.LPAREN)) {
|
||||
lexer.nextToken();
|
||||
exprList(over.getPartitionBy(), over);
|
||||
accept(Token.RPAREN);
|
||||
} else {
|
||||
exprList(over.getPartitionBy(), over);
|
||||
}
|
||||
}
|
||||
|
||||
over.setOrderBy(parseOrderBy());
|
||||
if (over.getOrderBy() != null) {
|
||||
TeradataAnalyticWindowing windowing = null;
|
||||
if (lexer.stringVal().equalsIgnoreCase("ROWS")) {
|
||||
lexer.nextToken();
|
||||
windowing = new TeradataAnalyticWindowing();
|
||||
windowing.setType(TeradataAnalyticWindowing.Type.ROWS);
|
||||
} else if (lexer.stringVal().equalsIgnoreCase("RANGE")) {
|
||||
lexer.nextToken();
|
||||
windowing = new TeradataAnalyticWindowing();
|
||||
windowing.setType(TeradataAnalyticWindowing.Type.RANGE);
|
||||
}
|
||||
|
||||
if (windowing != null) {
|
||||
if (lexer.stringVal().equalsIgnoreCase("BETWEEN")) {
|
||||
String between = null;
|
||||
String and = null;
|
||||
lexer.nextToken();
|
||||
if(lexer.token() == Token.LITERAL_INT) {
|
||||
int val_1 = lexer.integerValue().intValue();
|
||||
lexer.nextToken();
|
||||
if (lexer.stringVal().equalsIgnoreCase("PRECEDING")) {
|
||||
lexer.nextToken();
|
||||
between = "BETWEEN " + String.valueOf(val_1) + " PRECEDING";
|
||||
} else if (lexer.stringVal().equalsIgnoreCase("FOLLOWING")) {
|
||||
lexer.nextToken();
|
||||
between = "BETWEEN " + String.valueOf(val_1) + " FOLLOWING";
|
||||
} else {
|
||||
throw new ParserException("syntax error");
|
||||
}
|
||||
} else if (lexer.stringVal().equalsIgnoreCase("CURRENT")) {
|
||||
lexer.nextToken();
|
||||
if (lexer.stringVal().equalsIgnoreCase("ROW")) {
|
||||
lexer.nextToken();
|
||||
between = "BETWEEN CURRENT ROW";
|
||||
}
|
||||
} else if (lexer.stringVal().equalsIgnoreCase("UNBOUNDED")) {
|
||||
lexer.nextToken();
|
||||
if (lexer.stringVal().equalsIgnoreCase("PRECEDING")) {
|
||||
lexer.nextToken();
|
||||
between = "BETWEEN UNBOUNDED PRECEDING";
|
||||
}
|
||||
} else {
|
||||
throw new ParserException("syntax error");
|
||||
}
|
||||
if (lexer.stringVal().equalsIgnoreCase("AND")) {
|
||||
lexer.nextToken();
|
||||
if(lexer.token() == Token.LITERAL_INT) {
|
||||
System.out.println("yes, inside and");
|
||||
int val_2 = lexer.integerValue().intValue();
|
||||
lexer.nextToken();
|
||||
if (lexer.stringVal().equalsIgnoreCase("PRECEDING")) {
|
||||
lexer.nextToken();
|
||||
and = " AND " + String.valueOf(val_2) + " PRECEDING";
|
||||
windowing.setExpr(new SQLIdentifierExpr(between + and));
|
||||
} else if (lexer.stringVal().equalsIgnoreCase("FOLLOWING")) {
|
||||
lexer.nextToken();
|
||||
and = " AND " + String.valueOf(val_2) + " FOLLOWING";
|
||||
windowing.setExpr(new SQLIdentifierExpr(between + and));
|
||||
} else {
|
||||
throw new ParserException("syntax error");
|
||||
}
|
||||
} else if (lexer.stringVal().equalsIgnoreCase("CURRENT")) {
|
||||
lexer.nextToken();
|
||||
if (lexer.stringVal().equalsIgnoreCase("ROW")) {
|
||||
lexer.nextToken();
|
||||
and = " AND CURRENT ROW";
|
||||
windowing.setExpr(new SQLIdentifierExpr(between + and));
|
||||
}
|
||||
} else if (lexer.stringVal().equalsIgnoreCase("UNBOUNDED")) {
|
||||
lexer.nextToken();
|
||||
if (lexer.stringVal().equalsIgnoreCase("FOLLOWING")) {
|
||||
lexer.nextToken();
|
||||
and = " AND UNBOUNDED FOLLOWING";
|
||||
windowing.setExpr(new SQLIdentifierExpr(between + and));
|
||||
}
|
||||
} else {
|
||||
throw new ParserException("syntax error");
|
||||
}
|
||||
} else {
|
||||
throw new ParserException("syntax error");
|
||||
}
|
||||
} else {
|
||||
if (lexer.stringVal().equalsIgnoreCase("CURRENT")) {
|
||||
lexer.nextToken();
|
||||
if (lexer.stringVal().equalsIgnoreCase("ROW")) {
|
||||
lexer.nextToken();
|
||||
windowing.setExpr(new SQLIdentifierExpr("CURRENT ROW"));
|
||||
over.setWindowing(windowing);
|
||||
} else {
|
||||
throw new ParserException("syntax error");
|
||||
}
|
||||
}
|
||||
if (lexer.stringVal().equalsIgnoreCase("UNBOUNDED")) {
|
||||
lexer.nextToken();
|
||||
if (lexer.stringVal().equalsIgnoreCase("PRECEDING")) {
|
||||
lexer.nextToken();
|
||||
System.out.println("yes, inside!!");
|
||||
windowing.setExpr(new SQLIdentifierExpr("UNBOUNDED PRECEDING"));
|
||||
} else {
|
||||
throw new ParserException("syntax error");
|
||||
}
|
||||
}
|
||||
}
|
||||
over.setWindowing(windowing);
|
||||
}
|
||||
}
|
||||
|
||||
accept(Token.RPAREN);
|
||||
|
||||
aggregateExpr.setOver(over);
|
||||
}
|
||||
return aggregateExpr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+60
@@ -15,8 +15,15 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.parser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.dialect.oracle.parser.OracleSelectParser;
|
||||
import com.alibaba.druid.sql.parser.Lexer;
|
||||
import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
import com.alibaba.druid.util.JdbcConstants;
|
||||
|
||||
public class TeradataStatementParser extends SQLStatementParser {
|
||||
|
||||
@@ -27,5 +34,58 @@ public class TeradataStatementParser extends SQLStatementParser {
|
||||
public TeradataStatementParser(Lexer lexer){
|
||||
super(new TeradataExprParser(lexer));
|
||||
}
|
||||
|
||||
public TeradataExprParser getExprParser() {
|
||||
return (TeradataExprParser) exprParser;
|
||||
}
|
||||
|
||||
public TeradataSelectParser createSQLSelectParser() {
|
||||
return new TeradataSelectParser(this.exprParser);
|
||||
}
|
||||
|
||||
public SQLSelectStatement parseSelect() {
|
||||
TeradataSelectParser selectParser = new TeradataSelectParser(this.exprParser);
|
||||
return new SQLSelectStatement(selectParser.select(), JdbcConstants.TERADATA);
|
||||
}
|
||||
|
||||
public void parseStatementList(List<SQLStatement> statementList, int max) {
|
||||
for (;;) {
|
||||
if (max != -1) {
|
||||
if (statementList.size() >= max) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.EOF) {
|
||||
return;
|
||||
}
|
||||
if (lexer.token() == Token.END) {
|
||||
return;
|
||||
}
|
||||
if (lexer.token() == Token.ELSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lexer.token() == (Token.SEMI)) {
|
||||
lexer.nextToken();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lexer.token() == (Token.SELECT)) {
|
||||
statementList.add(parseSelect());
|
||||
continue;
|
||||
} else {
|
||||
super.parseStatementList(statementList, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean parseStatementListDialect(List<SQLStatement> statementList) {
|
||||
if (lexer.token() == Token.SEL) {
|
||||
statementList.add(parseSelect());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user