Merge pull request #1177 from usakey/master

Enhancement for Teradata select and insert clauses
This commit is contained in:
wenshao
2016-04-22 18:18:24 +08:00
11 changed files with 200 additions and 5 deletions
@@ -28,6 +28,7 @@ public enum SQLBinaryOperator {
Multiply("*", 60),
Divide("/", 60),
Modulus("%", 60),
Mod("MOD", 60),
Add("+", 70),
Subtract("-", 70),
@@ -1,6 +1,7 @@
package com.alibaba.druid.sql.dialect.teradata.ast.stmt;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataASTVisitor;
@@ -8,6 +9,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class TeradataSelectQueryBlock extends SQLSelectQueryBlock {
private SQLOrderBy orderBy;
private SQLExpr qualifyClause;
public TeradataSelectQueryBlock() {
@@ -30,6 +32,7 @@ public class TeradataSelectQueryBlock extends SQLSelectQueryBlock {
acceptChild(visitor, this.from);
acceptChild(visitor, this.where);
acceptChild(visitor, this.groupBy);
acceptChild(visitor, this.qualifyClause);
acceptChild(visitor, this.orderBy);
}
visitor.endVisit(this);
@@ -43,6 +46,17 @@ public class TeradataSelectQueryBlock extends SQLSelectQueryBlock {
this.orderBy = orderBy;
}
public SQLExpr getQualifyClause() {
return qualifyClause;
}
public void setQualifyClause(SQLExpr qualify) {
if (qualify != null) {
qualify.setParent(this);
}
this.qualifyClause = qualify;
}
public String toString() {
return SQLUtils.toTeradataString(this);
}
@@ -21,6 +21,10 @@ 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.SQLBetweenExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLCaseExpr;
import com.alibaba.druid.sql.ast.expr.SQLCastExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
@@ -63,7 +67,6 @@ public class TeradataExprParser extends SQLExprParser {
sqlExpr = queryExpr;
return primaryRest(sqlExpr);
case CAST:
System.out.println("cast test!");
lexer.nextToken();
accept(Token.LPAREN);
SQLCastExpr cast = new SQLCastExpr();
@@ -87,6 +90,27 @@ public class TeradataExprParser extends SQLExprParser {
return new TeradataSelectParser(this);
}
// for cases like: between DATE '2010-01-01' and DATE '2011-01-01'
public SQLExpr relationalRest(SQLExpr expr) {
if (lexer.token() == Token.BETWEEN) {
lexer.nextToken();
SQLExpr beginExpr = bitOr();
SQLExpr endExpr;
if (lexer.token() != Token.AND) {
lexer.nextToken();
accept(Token.AND);
endExpr = bitOr();
lexer.nextToken();
} else {
accept(Token.AND);
endExpr = bitOr();
}
expr = new SQLBetweenExpr(expr, beginExpr, endExpr);
return expr;
}
return super.relationalRest(expr);
}
protected SQLExpr methodRest(SQLExpr expr, boolean acceptLPAREN) {
if (acceptLPAREN) {
accept(Token.LPAREN);
@@ -121,10 +145,25 @@ public class TeradataExprParser extends SQLExprParser {
accept(Token.RPAREN);
return primaryRest(methodExpr);
}
} else if (expr instanceof SQLCaseExpr) {
lexer.nextToken();
accept(Token.RPAREN);
return primaryRest(expr);
}
return super.methodRest(expr, false);
}
public SQLExpr multiplicativeRest(SQLExpr expr) {
if (lexer.token() == Token.MOD) {
lexer.nextToken();
SQLExpr rightExp = bitXor();
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Mod, rightExp, getDbType());
expr = multiplicativeRest(expr);
return expr;
}
return super.multiplicativeRest(expr);
}
protected SQLAggregateExpr parseAggregateExpr(String methodName) {
methodName = methodName.toUpperCase();
@@ -45,6 +45,10 @@ public class TeradataLexer extends Lexer {
map.put("FORMAT", Token.FORMAT);
map.put("QUALIFY", Token.QUALIFY);
map.put("MOD", Token.MOD);
DEFAULT_TD_KEYWORDS = new Keywords(map);
}
@@ -1,9 +1,17 @@
package com.alibaba.druid.sql.dialect.teradata.parser;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
import com.alibaba.druid.sql.ast.expr.SQLDefaultExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
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.ParserException;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLSelectParser;
import com.alibaba.druid.sql.parser.Token;
@@ -54,9 +62,49 @@ public class TeradataSelectParser extends SQLSelectParser{
parseGroupBy(queryBlock);
parserQualify(queryBlock);
queryBlock.setOrderBy(this.exprParser.parseOrderBy());
return queryRest(queryBlock);
}
private void parserQualify(TeradataSelectQueryBlock queryBlock) {
if (lexer.token() != Token.QUALIFY) {
return;
}
lexer.nextToken();
if (lexer.token() == Token.LITERAL_INT) {
lexer.nextToken();
// possibly =, >=, <=
// ignore this for now
lexer.nextToken();
if (lexer.token() == Token.IDENTIFIER) {
SQLExpr expr = new SQLIdentifierExpr(lexer.stringVal());
lexer.nextToken();
if (lexer.token() != Token.COMMA) {
expr = this.exprParser.primaryRest(expr);
}
// TODO: add qualify clause into queryBlock
queryBlock.setQualifyClause(expr);
} else {
throw new ParserException("not support token:" + lexer.token());
}
} else if (lexer.token() == Token.IDENTIFIER) {
SQLExpr expr = new SQLIdentifierExpr(lexer.stringVal());
lexer.nextToken();
if (lexer.token() != Token.COMMA) {
expr = this.exprParser.primaryRest(expr);
}
lexer.nextToken();
lexer.nextToken();
// TODO: add qualify clause into queryBlock
queryBlock.setQualifyClause(expr);
} else {
throw new ParserException("not support token:" + lexer.token());
}
}
}
@@ -118,7 +118,8 @@ public class TeradataStatementParser extends SQLStatementParser {
break;
}
} else if (lexer.token() == (Token.SELECT)) {
} else if (lexer.token() == (Token.SELECT)
|| lexer.token() == (Token.SEL)) {
SQLSelect select = this.exprParser.createSelectParser().select();
select.setParent(insertStatement);
insertStatement.setQuery(select);
@@ -17,6 +17,7 @@ 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.ast.statement.SQLSubqueryTableSource;
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;
@@ -37,4 +38,8 @@ public interface TeradataASTVisitor extends SQLASTVisitor {
boolean visit(TeradataIntervalExpr x);
void endVisit(TeradataIntervalExpr x);
boolean visit(SQLSubqueryTableSource x);
void endVisit(SQLSubqueryTableSource x);
}
@@ -15,14 +15,28 @@
*/
package com.alibaba.druid.sql.dialect.teradata.visitor;
import java.util.LinkedHashMap;
import java.util.Map;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
import com.alibaba.druid.sql.ast.expr.SQLCaseExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
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.stat.TableStat.Column;
import com.alibaba.druid.util.JdbcUtils;
public class TeradataSchemaStatVisitor extends SchemaStatVisitor implements TeradataASTVisitor {
protected final Map<String, SQLObject> aliasQueryMap = new LinkedHashMap<String, SQLObject>();
@Override
public String getDbType() {
return JdbcUtils.TERADATA;
@@ -54,5 +68,69 @@ public class TeradataSchemaStatVisitor extends SchemaStatVisitor implements Tera
public void endVisit(TeradataIntervalExpr x) {
}
@Override
public boolean visit(SQLSubqueryTableSource x) {
accept(x.getSelect());
String table = (String) x.getSelect().getAttribute(ATTR_TABLE);
if (aliasMap != null && x.getAlias() != null) {
if (table != null) {
this.aliasMap.put(x.getAlias(), table);
}
addSubQuery(x.getAlias(), x.getSelect());
this.setCurrentTable(x.getAlias());
}
if (table != null) {
x.putAttribute(ATTR_TABLE, table);
}
return false;
}
@Override
public void endVisit(SQLSubqueryTableSource x) {
}
public boolean visit(SQLSelectItem x) {
x.getExpr().accept(this);
String alias = x.getAlias();
Map<String, String> aliasMap = this.getAliasMap();
if (alias != null && (!alias.isEmpty()) && aliasMap != null) {
if (x.getExpr() instanceof SQLName) {
putAliasMap(aliasMap, alias, x.getExpr().toString());
} else {
TeradataSchemaStatVisitor visitor = new TeradataSchemaStatVisitor();
x.getExpr().accept(visitor);
putAliasMap(aliasMap, alias, null);
// Add expression alias into aliasQuery map
// in order to retrieve column info from aliasQueryMap
// if aliasMap value is null
String uniqueAliasName = this.getCurrentTable() == null ?
alias : this.getCurrentTable() + "." + alias;
addAliasQuery(uniqueAliasName, x.getExpr());
}
}
return false;
}
protected void addAliasQuery(String alias, SQLObject query) {
String alias_lcase = alias.toLowerCase();
aliasQueryMap.put(alias_lcase, query);
}
public SQLObject getAliasQuery(String alias) {
String alias_lcase = alias.toLowerCase();
return aliasQueryMap.get(alias_lcase);
}
public Map<String, SQLObject> getAliasQueryMap() {
return aliasQueryMap;
}
}
@@ -382,7 +382,8 @@ public class SQLSelectParser extends SQLParser {
if (lexer.token() == Token.LPAREN) {
lexer.nextToken();
SQLTableSource tableSource;
if (lexer.token() == Token.SELECT || lexer.token() == Token.WITH) {
if (lexer.token() == Token.SELECT || lexer.token() == Token.WITH
|| lexer.token == Token.SEL) {
SQLSelect select = select();
accept(Token.RPAREN);
SQLSelectQuery query = queryRest(select.getQuery());
@@ -279,6 +279,8 @@ public enum Token {
POSITION("POSITION"),
RANGE_N("RANGE_N"),
FORMAT("FORMAT"),
QUALIFY("QUALIFY"),
MOD("MOD"),
LPAREN("("),
RPAREN(")"),
@@ -760,12 +760,14 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
Map<String, String> aliasMap = getAliasMap();
if (aliasMap != null) {
if (aliasMap.containsKey(name)) {
if (aliasMap.containsKey(name)
&& aliasMap.get(name) != null) {
return aliasMap.get(name);
}
String name_lcase = name.toLowerCase();
if (name_lcase != name && aliasMap.containsKey(name_lcase)) {
if (name_lcase != name && aliasMap.containsKey(name_lcase)
&& aliasMap.get(name_lcase) != null) {
return aliasMap.get(name_lcase);
}