mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
Merge pull request #1177 from usakey/master
Enhancement for Teradata select and insert clauses
This commit is contained in:
@@ -28,6 +28,7 @@ public enum SQLBinaryOperator {
|
||||
Multiply("*", 60),
|
||||
Divide("/", 60),
|
||||
Modulus("%", 60),
|
||||
Mod("MOD", 60),
|
||||
|
||||
Add("+", 70),
|
||||
Subtract("-", 70),
|
||||
|
||||
+14
@@ -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);
|
||||
}
|
||||
|
||||
+40
-1
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -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);
|
||||
}
|
||||
|
||||
+78
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user