Add basic implementation for Teradata Select

This commit is contained in:
Louis Xu
2016-03-28 19:34:01 +08:00
parent 81ebc6c49c
commit 8d8451bdff
6 changed files with 419 additions and 0 deletions
@@ -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;
}
}
@@ -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 {
}
@@ -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;
}
}
@@ -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;
}
}