mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
Merge pull request #1149 from usakey/master
Add implementation for Teradata SQL parser SELECT
This commit is contained in:
@@ -172,6 +172,14 @@ public class SQLUtils {
|
||||
public static String toSQLServerString(SQLObject sqlObject, FormatOption option) {
|
||||
return toSQLString(sqlObject, JdbcConstants.SQL_SERVER, option);
|
||||
}
|
||||
|
||||
public static String toTeradataString(SQLObject sqlObject) {
|
||||
return toTeradataString(sqlObject, null);
|
||||
}
|
||||
|
||||
public static String toTeradataString(SQLObject sqlObject, FormatOption option) {
|
||||
return toSQLString(sqlObject, JdbcConstants.TERADATA, option);
|
||||
}
|
||||
|
||||
public static String formatPGSql(String sql, FormatOption option) {
|
||||
return format(sql, JdbcConstants.POSTGRESQL, option);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.ast.expr;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLExprImpl;
|
||||
import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class TeradataIntervalExpr extends SQLExprImpl implements TeradataExpr {
|
||||
|
||||
private SQLExpr value;
|
||||
private TeradataIntervalUnit unit;
|
||||
|
||||
public TeradataIntervalExpr() {
|
||||
|
||||
}
|
||||
|
||||
public SQLExpr getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setValue(SQLExpr value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public TeradataIntervalUnit getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public void setUnit(TeradataIntervalUnit unit) {
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TeradataIntervalExpr other = (TeradataIntervalExpr) obj;
|
||||
if (unit != other.unit) {
|
||||
return false;
|
||||
}
|
||||
if (value == null) {
|
||||
if (other.value != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!value.equals(other.value)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((unit == null)? 0 : unit.hashCode());
|
||||
result = prime * result + ((value == null)? 0 : value.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
TeradataASTVisitor tdVisitor = (TeradataASTVisitor) visitor;
|
||||
if (tdVisitor.visit(this)) {
|
||||
acceptChild(visitor, this.value);
|
||||
}
|
||||
tdVisitor.endVisit(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.ast.expr;
|
||||
|
||||
public enum TeradataIntervalUnit {
|
||||
|
||||
YEAR, MONTH, DAY,
|
||||
|
||||
HOUR, MINUTE, SECOND;
|
||||
|
||||
public final String name_lcase;
|
||||
|
||||
private TeradataIntervalUnit() {
|
||||
this.name_lcase = name().toLowerCase();
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.ast.stmt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
|
||||
import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class TeradataInsertStatement extends SQLInsertStatement {
|
||||
private List<ValuesClause> valuesList = new ArrayList<ValuesClause>();
|
||||
|
||||
public ValuesClause getValues() {
|
||||
if (valuesList.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
return valuesList.get(0);
|
||||
}
|
||||
|
||||
public void setValues(ValuesClause values) {
|
||||
if (valuesList.size() == 0) {
|
||||
valuesList.add(values);
|
||||
} else {
|
||||
valuesList.set(0, values);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ValuesClause> getValuesList() {
|
||||
return valuesList;
|
||||
}
|
||||
|
||||
public void addValueCause(ValuesClause valueClause) {
|
||||
valueClause.setParent(this);
|
||||
valuesList.add(valueClause);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
if (visitor instanceof TeradataASTVisitor) {
|
||||
accept0((TeradataASTVisitor) visitor);
|
||||
} else {
|
||||
throw new IllegalArgumentException("not support visitor type : " + visitor.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected void accept0(TeradataASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
this.acceptChild(visitor, getTableSource());
|
||||
this.acceptChild(visitor, getColumns());
|
||||
this.acceptChild(visitor, getValuesList());
|
||||
this.acceptChild(visitor, getQuery());
|
||||
}
|
||||
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.ast.stmt;
|
||||
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
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;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return SQLUtils.toTeradataString(this);
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,25 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.parser;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLKeep;
|
||||
import com.alibaba.druid.sql.ast.SQLKeep.DenseRank;
|
||||
import com.alibaba.druid.sql.ast.SQLOrderBy;
|
||||
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.SQLMethodInvokeExpr;
|
||||
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.dialect.teradata.ast.expr.TeradataIntervalExpr;
|
||||
import com.alibaba.druid.sql.dialect.teradata.ast.expr.TeradataIntervalUnit;
|
||||
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.SQLSelectParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
import com.alibaba.druid.util.JdbcConstants;
|
||||
|
||||
public class TeradataExprParser extends SQLExprParser {
|
||||
@@ -35,5 +52,276 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
public SQLSelectParser createSelectParser() {
|
||||
return new TeradataSelectParser(this);
|
||||
}
|
||||
|
||||
protected SQLExpr methodRest(SQLExpr expr, boolean acceptLPAREN) {
|
||||
if (acceptLPAREN) {
|
||||
accept(Token.LPAREN);
|
||||
}
|
||||
|
||||
if (expr instanceof SQLIdentifierExpr) {
|
||||
String methodName = ((SQLIdentifierExpr) expr).getName();
|
||||
SQLMethodInvokeExpr methodExpr = new SQLMethodInvokeExpr(methodName);
|
||||
if ("trim".equalsIgnoreCase(methodName)) {
|
||||
if (identifierEquals("LEADING")
|
||||
|| identifierEquals("TRAILING")
|
||||
|| identifierEquals("BOTH")) {
|
||||
methodExpr.putAttribute("trim_option", lexer.stringVal());
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.LITERAL_CHARS) {
|
||||
SQLExpr trim_character = this.primary();
|
||||
trim_character.setParent(methodExpr);
|
||||
methodExpr.putAttribute("trim_character", trim_character);
|
||||
}
|
||||
} else {
|
||||
SQLExpr trim_character = this.primary();
|
||||
trim_character.setParent(methodExpr);
|
||||
methodExpr.putAttribute("trim_character", trim_character);
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.FROM) {
|
||||
lexer.nextToken();
|
||||
SQLExpr trim_source = this.expr();
|
||||
methodExpr.addParameter(trim_source);
|
||||
}
|
||||
|
||||
accept(Token.RPAREN);
|
||||
return primaryRest(methodExpr);
|
||||
}
|
||||
}
|
||||
return super.methodRest(expr, false);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
protected SQLExpr parseInterval() {
|
||||
accept(Token.INTERVAL);
|
||||
|
||||
if (lexer.token() == Token.LITERAL_CHARS) {
|
||||
SQLExpr value = expr();
|
||||
|
||||
if (lexer.token() != Token.IDENTIFIER) {
|
||||
throw new ParserException("Syntax error");
|
||||
}
|
||||
|
||||
String unit = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
|
||||
TeradataIntervalExpr intervalExpr = new TeradataIntervalExpr();
|
||||
intervalExpr.setValue(value);
|
||||
intervalExpr.setUnit(TeradataIntervalUnit.valueOf(unit.toUpperCase()));
|
||||
|
||||
return intervalExpr;
|
||||
} else {
|
||||
throw new ParserException("TODO with other interval");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,26 +15,140 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.parser;
|
||||
|
||||
import static com.alibaba.druid.sql.parser.LayoutCharacters.EOI;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.druid.sql.parser.Keywords;
|
||||
import com.alibaba.druid.sql.parser.Lexer;
|
||||
import com.alibaba.druid.sql.parser.NotAllowCommentException;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
|
||||
public class TeradataLexer extends Lexer {
|
||||
public final static Keywords DEFAULT_PG_KEYWORDS;
|
||||
public final static Keywords DEFAULT_TD_KEYWORDS;
|
||||
|
||||
static {
|
||||
Map<String, Token> map = new HashMap<String, Token>();
|
||||
map.putAll(Keywords.DEFAULT_KEYWORDS.getKeywords());
|
||||
|
||||
DEFAULT_PG_KEYWORDS = new Keywords(map);
|
||||
map.put("SEL", Token.SEL);
|
||||
map.put("LOCKING", Token.LOCKING);
|
||||
map.put("ACCESS", Token.ACCESS);
|
||||
|
||||
// map.put("PARTITION", Token.PARTITION);
|
||||
// map.put("PARTITIONED", Token.PARTITIONED);
|
||||
map.put("RANGE_N", Token.RANGE_N);
|
||||
|
||||
map.put("VOLATILE", Token.VOLATILE);
|
||||
map.put("MULTISET", Token.MULTISET);
|
||||
|
||||
map.put("FORMAT", Token.FORMAT);
|
||||
|
||||
DEFAULT_TD_KEYWORDS = new Keywords(map);
|
||||
}
|
||||
|
||||
public TeradataLexer(String input){
|
||||
super(input);
|
||||
super.keywods = DEFAULT_PG_KEYWORDS;
|
||||
super.keywods = DEFAULT_TD_KEYWORDS;
|
||||
}
|
||||
|
||||
public void scanComment() {
|
||||
if (ch != '/' && ch != '-') {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
mark = pos;
|
||||
bufPos = 0;
|
||||
scanChar();
|
||||
|
||||
// /*+ */
|
||||
if (ch == '*') {
|
||||
scanChar();
|
||||
bufPos++;
|
||||
|
||||
while (ch == ' ') {
|
||||
scanChar();
|
||||
bufPos++;
|
||||
}
|
||||
|
||||
boolean isHint = false;
|
||||
int startHintSp = bufPos + 1;
|
||||
if (ch == '+') {
|
||||
isHint = true;
|
||||
scanChar();
|
||||
bufPos++;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (ch == '*' && charAt(pos + 1) == '/') {
|
||||
bufPos += 2;
|
||||
scanChar();
|
||||
scanChar();
|
||||
break;
|
||||
}
|
||||
|
||||
scanChar();
|
||||
bufPos++;
|
||||
}
|
||||
|
||||
if (isHint) {
|
||||
stringVal = subString(mark + startHintSp, (bufPos - startHintSp) - 1);
|
||||
token = Token.HINT;
|
||||
} else {
|
||||
stringVal = subString(mark, bufPos);
|
||||
token = Token.MULTI_LINE_COMMENT;
|
||||
if (keepComments) {
|
||||
addComment(stringVal);
|
||||
}
|
||||
}
|
||||
|
||||
if (token != Token.HINT && !isAllowComment()) {
|
||||
throw new NotAllowCommentException();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAllowComment()) {
|
||||
throw new NotAllowCommentException();
|
||||
}
|
||||
|
||||
if (ch == '/' || ch == '-') {
|
||||
scanChar();
|
||||
bufPos++;
|
||||
|
||||
for (;;) {
|
||||
if (ch == '\r') {
|
||||
if (charAt(pos + 1) == '\n') {
|
||||
bufPos += 2;
|
||||
scanChar();
|
||||
break;
|
||||
}
|
||||
bufPos++;
|
||||
break;
|
||||
} else if (ch == EOI) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == '\n') {
|
||||
scanChar();
|
||||
bufPos++;
|
||||
break;
|
||||
}
|
||||
|
||||
scanChar();
|
||||
bufPos++;
|
||||
}
|
||||
|
||||
stringVal = subString(mark + 1, bufPos);
|
||||
token = Token.LINE_COMMENT;
|
||||
if (keepComments) {
|
||||
addComment(stringVal);
|
||||
}
|
||||
endOfComment = isEOF();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.parser;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.dialect.teradata.ast.stmt.TeradataSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.parser.SQLExprParser;
|
||||
import com.alibaba.druid.sql.parser.SQLSelectParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
|
||||
public class TeradataSelectParser extends SQLSelectParser{
|
||||
|
||||
public TeradataSelectParser(SQLExprParser exprParser) {
|
||||
super(exprParser);
|
||||
}
|
||||
|
||||
public TeradataSelectParser(String sql) {
|
||||
this(new TeradataExprParser(sql));
|
||||
}
|
||||
|
||||
public SQLSelectQuery query() {
|
||||
if (lexer.token() == Token.LPAREN) {
|
||||
lexer.nextToken();
|
||||
|
||||
SQLSelectQuery select = query();
|
||||
accept(Token.RPAREN);
|
||||
|
||||
return queryRest(select);
|
||||
}
|
||||
|
||||
TeradataSelectQueryBlock queryBlock = new TeradataSelectQueryBlock();
|
||||
|
||||
if (lexer.token() == Token.SEL
|
||||
|| lexer.token() == Token.SELECT) {
|
||||
|
||||
lexer.nextToken();
|
||||
|
||||
if (lexer.token() == Token.COMMENT) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
if (lexer.token() == (Token.DISTINCT)) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == (Token.ALL)) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.ALL);
|
||||
lexer.nextToken();
|
||||
}
|
||||
parseSelectList(queryBlock);
|
||||
}
|
||||
parseFrom(queryBlock);
|
||||
|
||||
parseWhere(queryBlock);
|
||||
|
||||
parseGroupBy(queryBlock);
|
||||
|
||||
queryBlock.setOrderBy(this.exprParser.parseOrderBy());
|
||||
|
||||
return queryRest(queryBlock);
|
||||
}
|
||||
|
||||
}
|
||||
+224
@@ -15,8 +15,25 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLName;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLNCharExpr;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelect;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause;
|
||||
import com.alibaba.druid.sql.dialect.teradata.ast.stmt.TeradataInsertStatement;
|
||||
import com.alibaba.druid.sql.parser.Lexer;
|
||||
import com.alibaba.druid.sql.parser.ParserException;
|
||||
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 +44,212 @@ 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 SQLInsertStatement parseInsert() {
|
||||
TeradataInsertStatement insertStatement = new TeradataInsertStatement();
|
||||
|
||||
if (lexer.token() == Token.INSERT) {
|
||||
lexer.nextToken();
|
||||
|
||||
if (lexer.token() == Token.INTO) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
SQLName tableName = this.exprParser.name();
|
||||
insertStatement.setTableName(tableName);
|
||||
|
||||
if (lexer.token() == Token.IDENTIFIER && !identifierEquals("VALUE")) {
|
||||
insertStatement.setAlias(lexer.stringVal());
|
||||
lexer.nextToken();
|
||||
}
|
||||
}
|
||||
|
||||
int columnSize = 0;
|
||||
if (lexer.token() == (Token.LPAREN)) {
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == (Token.SELECT)) {
|
||||
SQLSelect select = this.exprParser.createSelectParser().select();
|
||||
select.setParent(insertStatement);
|
||||
insertStatement.setQuery(select);
|
||||
} else {
|
||||
this.exprParser.exprList(insertStatement.getColumns(), insertStatement);
|
||||
columnSize = insertStatement.getColumns().size();
|
||||
}
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.VALUES || identifierEquals("VALUE")) {
|
||||
lexer.nextTokenLParen();
|
||||
parseValueClause(insertStatement.getValuesList(), columnSize);
|
||||
} else if (lexer.token() == Token.SET) {
|
||||
lexer.nextToken();
|
||||
|
||||
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
|
||||
insertStatement.getValuesList().add(values);
|
||||
|
||||
for (;;) {
|
||||
SQLName name = this.exprParser.name();
|
||||
insertStatement.addColumn(name);
|
||||
if (lexer.token() == Token.EQ) {
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
accept(Token.COLONEQ);
|
||||
}
|
||||
values.addValue(this.exprParser.expr());
|
||||
|
||||
if (lexer.token() == Token.COMMA) {
|
||||
lexer.nextToken();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (lexer.token() == (Token.SELECT)) {
|
||||
SQLSelect select = this.exprParser.createSelectParser().select();
|
||||
select.setParent(insertStatement);
|
||||
insertStatement.setQuery(select);
|
||||
} else if (lexer.token() == (Token.LPAREN)) {
|
||||
lexer.nextToken();
|
||||
SQLSelect select = this.exprParser.createSelectParser().select();
|
||||
select.setParent(insertStatement);
|
||||
insertStatement.setQuery(select);
|
||||
accept(Token.RPAREN);
|
||||
}
|
||||
|
||||
return insertStatement;
|
||||
}
|
||||
|
||||
private void parseValueClause(List<ValuesClause> valueClauseList, int columnSize) {
|
||||
for (;;) {
|
||||
if (lexer.token() != Token.LPAREN) {
|
||||
throw new ParserException("syntax error, expect ')'");
|
||||
}
|
||||
lexer.nextTokenValue();
|
||||
|
||||
if (lexer.token() != Token.RPAREN) {
|
||||
List<SQLExpr> valueExprList;
|
||||
if (columnSize > 0) {
|
||||
valueExprList = new ArrayList<SQLExpr>(columnSize);
|
||||
} else {
|
||||
valueExprList = new ArrayList<SQLExpr>();
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
SQLExpr expr;
|
||||
if (lexer.token() == Token.LITERAL_INT) {
|
||||
expr = new SQLIntegerExpr(lexer.integerValue());
|
||||
lexer.nextTokenComma();
|
||||
} else if (lexer.token() == Token.LITERAL_CHARS) {
|
||||
expr = new SQLCharExpr(lexer.stringVal());
|
||||
lexer.nextTokenComma();
|
||||
} else if (lexer.token() == Token.LITERAL_NCHARS) {
|
||||
expr = new SQLNCharExpr(lexer.stringVal());
|
||||
lexer.nextTokenComma();
|
||||
} else {
|
||||
expr = exprParser.expr();
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.COMMA) {
|
||||
valueExprList.add(expr);
|
||||
lexer.nextTokenValue();
|
||||
continue;
|
||||
} else if (lexer.token() == Token.RPAREN) {
|
||||
valueExprList.add(expr);
|
||||
break;
|
||||
} else {
|
||||
expr = this.exprParser.primaryRest(expr);
|
||||
if (lexer.token() != Token.COMMA && lexer.token() != Token.RPAREN) {
|
||||
expr = this.exprParser.exprRest(expr);
|
||||
}
|
||||
|
||||
valueExprList.add(expr);
|
||||
if (lexer.token() == Token.COMMA) {
|
||||
lexer.nextToken();
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(valueExprList);
|
||||
valueClauseList.add(values);
|
||||
} else {
|
||||
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList<SQLExpr>(0));
|
||||
valueClauseList.add(values);
|
||||
}
|
||||
|
||||
if (lexer.token() != Token.RPAREN) {
|
||||
throw new ParserException("syntax error");
|
||||
}
|
||||
|
||||
if (!parseCompleteValues && valueClauseList.size() >= parseValuesSize) {
|
||||
lexer.skipToEOF();
|
||||
break;
|
||||
}
|
||||
|
||||
lexer.nextTokenComma();
|
||||
if (lexer.token() == Token.COMMA) {
|
||||
lexer.nextTokenLParen();
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,26 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.visitor;
|
||||
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelect;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
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.dialect.teradata.ast.expr.TeradataIntervalExpr;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public interface TeradataASTVisitor extends SQLASTVisitor {
|
||||
|
||||
boolean visit(TeradataAnalyticWindowing x);
|
||||
|
||||
void endVisit(TeradataAnalyticWindowing x);
|
||||
|
||||
boolean visit(TeradataAnalytic x);
|
||||
|
||||
boolean visit(SQLSelectQueryBlock x);
|
||||
|
||||
boolean visit(SQLSelect x);
|
||||
|
||||
boolean visit(TeradataIntervalExpr x);
|
||||
|
||||
void endVisit(TeradataIntervalExpr x);
|
||||
}
|
||||
|
||||
+33
@@ -15,8 +15,41 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.visitor;
|
||||
|
||||
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.dialect.teradata.ast.expr.TeradataIntervalExpr;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
|
||||
|
||||
public class TeradataASTVisitorAdapter extends SQLASTVisitorAdapter implements TeradataASTVisitor {
|
||||
|
||||
@Override
|
||||
public boolean visit(TeradataAnalyticWindowing x) {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(TeradataAnalyticWindowing x) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TeradataAnalytic x) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TeradataIntervalExpr x) {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(TeradataIntervalExpr x) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.alibaba.druid.sql.dialect.teradata.visitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
|
||||
import com.alibaba.druid.sql.visitor.SQLEvalVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils;
|
||||
import com.alibaba.druid.sql.visitor.functions.Function;
|
||||
|
||||
public class TeradataEvalVisitor extends TeradataASTVisitorAdapter implements SQLEvalVisitor {
|
||||
private Map<String, Function> functions = new HashMap<String, Function>();
|
||||
private List<Object> parameters = new ArrayList<Object>();
|
||||
|
||||
private int variantIndex = -1;
|
||||
|
||||
private boolean markVariantIndex = true;
|
||||
|
||||
public TeradataEvalVisitor() {
|
||||
this(new ArrayList<Object>(1));
|
||||
}
|
||||
|
||||
public TeradataEvalVisitor(List<Object> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function getFunction(String funcName) {
|
||||
return functions.get(funcName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerFunction(String funcName, Function function) {
|
||||
functions.put(funcName, function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterFunction(String funcName) {
|
||||
functions.remove(funcName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameters(List<Object> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int incrementAndGetVariantIndex() {
|
||||
return ++variantIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkVariantIndex() {
|
||||
return markVariantIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkVariantIndex(boolean markVariantIndex) {
|
||||
this.markVariantIndex = markVariantIndex;
|
||||
}
|
||||
|
||||
public boolean visit(SQLBinaryOpExpr x) {
|
||||
return SQLEvalVisitorUtils.visit(this, x);
|
||||
}
|
||||
|
||||
}
|
||||
+180
@@ -15,6 +15,18 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.visitor;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLObject;
|
||||
import com.alibaba.druid.sql.ast.SQLOrderBy;
|
||||
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelect;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
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.dialect.teradata.ast.expr.TeradataIntervalExpr;
|
||||
import com.alibaba.druid.sql.dialect.teradata.ast.stmt.TeradataSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
|
||||
|
||||
public class TeradataOutputVisitor extends SQLASTOutputVisitor implements TeradataASTVisitor {
|
||||
@@ -22,5 +34,173 @@ public class TeradataOutputVisitor extends SQLASTOutputVisitor implements Terada
|
||||
public TeradataOutputVisitor(Appendable appender){
|
||||
super(appender);
|
||||
}
|
||||
|
||||
public boolean visit(TeradataAnalytic x) {
|
||||
print0(ucase ? "OVER (" : "over (");
|
||||
|
||||
boolean space = false;
|
||||
if (x.getPartitionBy().size() > 0) {
|
||||
print0(ucase ? "PARTITION BY " : "partition by ");
|
||||
printAndAccept(x.getPartitionBy(), ", ");
|
||||
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (x.getOrderBy() != null) {
|
||||
if (space) {
|
||||
print(' ');
|
||||
}
|
||||
x.getOrderBy().accept(this);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (x.getWindowing() != null) {
|
||||
if (space) {
|
||||
print(' ');
|
||||
}
|
||||
x.getWindowing().accept(this);
|
||||
}
|
||||
|
||||
print(')');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TeradataAnalyticWindowing x) {
|
||||
print0(x.getType().name().toUpperCase());
|
||||
print(' ');
|
||||
x.getExpr().accept(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(TeradataAnalyticWindowing x) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelectQueryBlock select) {
|
||||
if(select instanceof TeradataSelectQueryBlock) {
|
||||
return visit((TeradataSelectQueryBlock) select);
|
||||
}
|
||||
|
||||
return super.visit(select);
|
||||
}
|
||||
|
||||
public boolean visit(TeradataSelectQueryBlock x) {
|
||||
if (x.getOrderBy() != null) {
|
||||
x.getOrderBy().setParent(x);
|
||||
}
|
||||
|
||||
print0(ucase ? "SELECT " : "select ");
|
||||
|
||||
if (SQLSetQuantifier.ALL == x.getDistionOption()) {
|
||||
print0(ucase ? "ALL " : "all ");
|
||||
} else if (SQLSetQuantifier.DISTINCT == x.getDistionOption()) {
|
||||
print0(ucase ? "DISTINCT " : "distinct ");
|
||||
} else if (SQLSetQuantifier.UNIQUE == x.getDistionOption()) {
|
||||
print0(ucase ? "UNIQUE " : "unique ");
|
||||
}
|
||||
|
||||
printSelectList(x.getSelectList());
|
||||
|
||||
if (x.getInto() != null) {
|
||||
println();
|
||||
print0(ucase ? "INTO " : "into ");
|
||||
x.getInto().accept(this);
|
||||
}
|
||||
|
||||
println();
|
||||
print0(ucase ? "FROM " : "from ");
|
||||
if (x.getFrom() == null) {
|
||||
print0(ucase ? "DUAL" : "dual");
|
||||
} else {
|
||||
x.getFrom().setParent(x);
|
||||
x.getFrom().accept(this);
|
||||
}
|
||||
|
||||
if (x.getWhere() != null) {
|
||||
println();
|
||||
print0(ucase ? "WHERE " : "where ");
|
||||
x.getWhere().setParent(x);
|
||||
x.getWhere().accept(this);
|
||||
}
|
||||
|
||||
if (x.getGroupBy() != null) {
|
||||
println();
|
||||
x.getGroupBy().accept(this);
|
||||
}
|
||||
|
||||
if (x.getOrderBy() != null) {
|
||||
println();
|
||||
x.getOrderBy().accept(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelect x) {
|
||||
return super.visit(x);
|
||||
}
|
||||
|
||||
protected void visitAggreateRest(SQLAggregateExpr aggregateExpr) {
|
||||
{
|
||||
SQLOrderBy value = (SQLOrderBy) aggregateExpr.getAttribute("ORDER BY");
|
||||
if (value != null) {
|
||||
print(' ');
|
||||
((SQLObject) value).accept(this);
|
||||
}
|
||||
}
|
||||
{
|
||||
Object value = aggregateExpr.getAttribute("SEPARATOR");
|
||||
if (value != null) {
|
||||
print0(ucase ? " SEPARATOR " : " separator ");
|
||||
((SQLObject) value).accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TeradataIntervalExpr x) {
|
||||
print0(ucase ? "INTERVAL " : "interval ");
|
||||
x.getValue().accept(this);
|
||||
print(' ');
|
||||
print0(ucase ? x.getUnit().name() : x.getUnit().name_lcase);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(TeradataIntervalExpr x) {
|
||||
|
||||
}
|
||||
|
||||
public void endVisit(SQLMethodInvokeExpr x) {
|
||||
|
||||
}
|
||||
|
||||
public boolean visit(SQLMethodInvokeExpr x) {
|
||||
if ("trim".equalsIgnoreCase(x.getMethodName())) {
|
||||
SQLExpr trim_character = (SQLExpr) x.getAttribute("trim_character");
|
||||
|
||||
print0(x.getMethodName());
|
||||
print('(');
|
||||
String trim_option = (String) x.getAttribute("trim_option");
|
||||
if (trim_option != null && trim_option.length() != 0) {
|
||||
print0(trim_option);
|
||||
print(' ');
|
||||
}
|
||||
if (trim_character != null) {
|
||||
trim_character.accept(this);
|
||||
}
|
||||
if (x.getParameters().size() > 0) {
|
||||
print0(ucase ? " FROM " : " from ");
|
||||
x.getParameters().get(0).accept(this);
|
||||
}
|
||||
print(')');
|
||||
return false;
|
||||
}
|
||||
return super.visit(x);
|
||||
}
|
||||
}
|
||||
|
||||
+31
-1
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.teradata.visitor;
|
||||
|
||||
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.dialect.teradata.ast.expr.TeradataIntervalExpr;
|
||||
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
|
||||
@@ -22,7 +25,34 @@ public class TeradataSchemaStatVisitor extends SchemaStatVisitor implements Tera
|
||||
|
||||
@Override
|
||||
public String getDbType() {
|
||||
return JdbcUtils.POSTGRESQL;
|
||||
return JdbcUtils.TERADATA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TeradataAnalyticWindowing x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(TeradataAnalyticWindowing x) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TeradataAnalytic x) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TeradataIntervalExpr x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(TeradataIntervalExpr x) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -261,6 +261,16 @@ public enum Token {
|
||||
PARTITION,
|
||||
PARTITIONED,
|
||||
OVERWRITE,
|
||||
|
||||
// Teradata
|
||||
SEL("SEL"),
|
||||
LOCKING("LOCKING"),
|
||||
ACCESS("ACCESS"),
|
||||
VOLATILE("VOLATILE"),
|
||||
MULTISET("MULTISET"),
|
||||
POSITION("POSITION"),
|
||||
RANGE_N("RANGE_N"),
|
||||
FORMAT("FORMAT"),
|
||||
|
||||
LPAREN("("),
|
||||
RPAREN(")"),
|
||||
|
||||
@@ -44,6 +44,7 @@ import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlEvalVisitorImpl;
|
||||
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleEvalVisitor;
|
||||
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGEvalVisitor;
|
||||
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerEvalVisitor;
|
||||
import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataEvalVisitor;
|
||||
import com.alibaba.druid.sql.visitor.functions.Ascii;
|
||||
import com.alibaba.druid.sql.visitor.functions.Bin;
|
||||
import com.alibaba.druid.sql.visitor.functions.BitLength;
|
||||
@@ -178,6 +179,10 @@ public class SQLEvalVisitorUtils {
|
||||
if (JdbcUtils.DB2.equals(dbType)) {
|
||||
return new DB2EvalVisitor();
|
||||
}
|
||||
|
||||
if (JdbcUtils.TERADATA.equals(dbType)) {
|
||||
return new TeradataEvalVisitor();
|
||||
}
|
||||
|
||||
return new SQLEvalVisitorImpl();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user