mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improved sql parser
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package com.alibaba.druid.sql.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
public class SQLPartitionSpec extends SQLObjectImpl implements Cloneable {
|
||||
private List<Item> items = new ArrayList<Item>();
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor v) {
|
||||
if (v.visit(this)) {
|
||||
acceptChild(v, items);
|
||||
}
|
||||
v.endVisit(this);
|
||||
}
|
||||
|
||||
public void addItem(Item item) {
|
||||
item.setParent(this);
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
public List<Item> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public SQLPartitionSpec clone() {
|
||||
SQLPartitionSpec x = new SQLPartitionSpec();
|
||||
|
||||
for (Item item : items) {
|
||||
x.addItem(item.clone());
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
public static class Item extends SQLObjectImpl implements Cloneable {
|
||||
private SQLName column;
|
||||
private SQLExpr value;
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor v) {
|
||||
if (v.visit(this)) {
|
||||
acceptChild(v, column);
|
||||
acceptChild(v, value);
|
||||
}
|
||||
v.endVisit(this);
|
||||
}
|
||||
|
||||
public Item clone() {
|
||||
Item x = new Item();
|
||||
|
||||
if (column != null) {
|
||||
x.setColumn(column.clone());
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
x.setValue(value.clone());
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
public SQLName getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
public void setColumn(SQLName column) {
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public SQLExpr getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(SQLExpr value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,14 +33,14 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable,
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected String methodName;
|
||||
protected long methodNameHashCode64;
|
||||
protected SQLExpr owner;
|
||||
protected final List<SQLExpr> arguments = new ArrayList<SQLExpr>();
|
||||
private SQLExpr from;
|
||||
private SQLExpr using;
|
||||
private SQLExpr _for;
|
||||
private String trimOption;
|
||||
protected final List<SQLExpr> arguments = new ArrayList<SQLExpr>();
|
||||
protected String methodName;
|
||||
protected long methodNameHashCode64;
|
||||
protected SQLExpr owner;
|
||||
protected SQLExpr from;
|
||||
protected SQLExpr using;
|
||||
protected SQLExpr _for;
|
||||
protected String trimOption;
|
||||
protected transient SQLDataType resolvedReturnDataType;
|
||||
|
||||
public SQLMethodInvokeExpr(){
|
||||
@@ -273,7 +273,11 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable,
|
||||
|
||||
public SQLMethodInvokeExpr clone() {
|
||||
SQLMethodInvokeExpr x = new SQLMethodInvokeExpr();
|
||||
cloneTo(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
public void cloneTo(SQLMethodInvokeExpr x) {
|
||||
x.methodName = methodName;
|
||||
|
||||
if (owner != null) {
|
||||
@@ -306,8 +310,6 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable,
|
||||
x.putAttribute(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 1999-2017 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.druid.sql.ast.statement;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLObjectImpl;
|
||||
import com.alibaba.druid.sql.ast.SQLPartitionSpec;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SQLAlterTableMergePartition extends SQLObjectImpl implements SQLAlterTableItem {
|
||||
|
||||
private final List<SQLPartitionSpec> partitions = new ArrayList<SQLPartitionSpec>(4);
|
||||
private boolean ifExists = false;
|
||||
private SQLPartitionSpec overwritePartition;
|
||||
|
||||
public List<SQLPartitionSpec> getPartitions() {
|
||||
return partitions;
|
||||
}
|
||||
|
||||
public void addPartition(SQLPartitionSpec x) {
|
||||
if (x != null) {
|
||||
x.setParent(this);
|
||||
}
|
||||
this.partitions.add(x);
|
||||
}
|
||||
|
||||
public boolean isIfExists() {
|
||||
return ifExists;
|
||||
}
|
||||
|
||||
public void setIfExists(boolean ifExists) {
|
||||
this.ifExists = ifExists;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
acceptChild(visitor, partitions);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public SQLPartitionSpec getOverwritePartition() {
|
||||
return overwritePartition;
|
||||
}
|
||||
|
||||
public void setOverwritePartition(SQLPartitionSpec x) {
|
||||
if (x != null) {
|
||||
x.setParent(this);
|
||||
}
|
||||
this.overwritePartition = x;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,9 @@ public enum SQLUnionOperator {
|
||||
MINUS("MINUS"),
|
||||
EXCEPT("EXCEPT"),
|
||||
EXCEPT_ALL("EXCEPT ALL"),
|
||||
EXCEPT_DISTINCT("EXCEPT DISTINCT"),
|
||||
INTERSECT("INTERSECT"),
|
||||
INTERSECT_ALL("INTERSECT ALL"),
|
||||
INTERSECT_DISTINCT("INTERSECT DISTINCT"),
|
||||
DISTINCT("UNION DISTINCT");
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
public class HiveMsckRepairStatement extends SQLStatementImpl implements SQLAlterStatement {
|
||||
private SQLExprTableSource table;
|
||||
private SQLName database;
|
||||
private boolean addPartitions;
|
||||
|
||||
public HiveMsckRepairStatement() {
|
||||
super(DbType.hive);
|
||||
@@ -34,6 +35,13 @@ public class HiveMsckRepairStatement extends SQLStatementImpl implements SQLAlte
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public boolean isAddPartitions() {
|
||||
return addPartitions;
|
||||
}
|
||||
|
||||
public void setAddPartitions(boolean addPartitions) {
|
||||
this.addPartitions = addPartitions;
|
||||
}
|
||||
|
||||
public SQLExprTableSource getTable() {
|
||||
return table;
|
||||
|
||||
@@ -328,6 +328,10 @@ public class HiveOutputVisitor extends SQLASTOutputVisitor implements HiveASTVis
|
||||
print0(ucase ? " TABLE " : " table ");
|
||||
table.accept(this);
|
||||
}
|
||||
|
||||
if (x.isAddPartitions()) {
|
||||
print0(ucase ? " ADD PARTITIONS" : " add partitions");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.alibaba.druid.sql.dialect.odps.ast;
|
||||
|
||||
import com.alibaba.druid.FastsqlException;
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.dialect.odps.visitor.OdpsASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class OdpsNewExpr extends SQLMethodInvokeExpr implements OdpsObject {
|
||||
@Override
|
||||
public OdpsNewExpr clone() {
|
||||
OdpsNewExpr x = new OdpsNewExpr();
|
||||
cloneTo(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept0(SQLASTVisitor v) {
|
||||
accept0((OdpsASTVisitor) v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept0(OdpsASTVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
if (this.owner != null) {
|
||||
this.owner.accept(visitor);
|
||||
}
|
||||
|
||||
for (SQLExpr arg : this.arguments) {
|
||||
if (arg != null) {
|
||||
arg.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.from != null) {
|
||||
this.from.accept(visitor);
|
||||
}
|
||||
|
||||
if (this.using != null) {
|
||||
this.using.accept(visitor);
|
||||
}
|
||||
|
||||
if (this._for != null) {
|
||||
this._for.accept(visitor);
|
||||
}
|
||||
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
|
||||
public void output(Appendable buf) {
|
||||
try {
|
||||
buf.append("new ");
|
||||
} catch (IOException ex) {
|
||||
throw new FastsqlException("output error", ex);
|
||||
}
|
||||
super.output(buf);
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,14 @@ public class OdpsCreateTableParser extends SQLCreateTableParser {
|
||||
case CLOSE:
|
||||
case IN:
|
||||
case OUT:
|
||||
column = this.exprParser.parseColumn();
|
||||
case LIMIT:
|
||||
case FULL:
|
||||
case MINUS:
|
||||
case VALUES:
|
||||
case TRIGGER:
|
||||
case USE:
|
||||
case LIKE:
|
||||
column = this.exprParser.parseColumn(stmt);
|
||||
break;
|
||||
default:
|
||||
throw new ParserException("expect identifier. " + lexer.info());
|
||||
@@ -182,6 +189,8 @@ public class OdpsCreateTableParser extends SQLCreateTableParser {
|
||||
switch (lexer.token()) {
|
||||
case KEY:
|
||||
case IDENTIFIER:
|
||||
case GROUP:
|
||||
case INTERVAL:
|
||||
break;
|
||||
default:
|
||||
throw new ParserException("expect identifier. " + lexer.info());
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.alibaba.druid.sql.ast.*;
|
||||
import com.alibaba.druid.sql.ast.expr.*;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLExternalRecordFormat;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
|
||||
import com.alibaba.druid.sql.dialect.odps.ast.OdpsNewExpr;
|
||||
import com.alibaba.druid.sql.dialect.odps.ast.OdpsTransformExpr;
|
||||
import com.alibaba.druid.sql.dialect.odps.ast.OdpsUDTFSQLSelectItem;
|
||||
import com.alibaba.druid.sql.parser.*;
|
||||
@@ -75,16 +76,31 @@ public class OdpsExprParser extends SQLExprParser {
|
||||
return new SQLCharExpr(chars);
|
||||
}
|
||||
|
||||
final static long GSONBUILDER = FnvHash.fnv1a_64_lower("GSONBUILDER");
|
||||
|
||||
@Override
|
||||
public SQLSelectItem parseSelectItem() {
|
||||
SQLExpr expr;
|
||||
if (lexer.token() == Token.IDENTIFIER) {
|
||||
expr = new SQLIdentifierExpr(lexer.stringVal());
|
||||
String stringVal = lexer.stringVal();
|
||||
long hash_lower = lexer.hash_lower();
|
||||
|
||||
lexer.nextTokenComma();
|
||||
|
||||
if (lexer.token() != Token.COMMA) {
|
||||
expr = this.primaryRest(expr);
|
||||
expr = this.exprRest(expr);
|
||||
if (FnvHash.Constants.DATETIME == hash_lower
|
||||
&& lexer.stringVal().charAt(0) != '`'
|
||||
&& lexer.token() == Token.LITERAL_CHARS) {
|
||||
String literal = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
|
||||
SQLDateTimeExpr ts = new SQLDateTimeExpr(literal);
|
||||
expr = ts;
|
||||
} else {
|
||||
expr = new SQLIdentifierExpr(stringVal);
|
||||
if (lexer.token() != Token.COMMA) {
|
||||
expr = this.primaryRest(expr);
|
||||
expr = this.exprRest(expr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
expr = expr();
|
||||
@@ -123,23 +139,23 @@ public class OdpsExprParser extends SQLExprParser {
|
||||
} else {
|
||||
alias = as();
|
||||
}
|
||||
|
||||
|
||||
SQLSelectItem item = new SQLSelectItem(expr, alias);
|
||||
|
||||
|
||||
if (lexer.hasComment() && lexer.isKeepComments()) {
|
||||
item.addAfterComment(lexer.readAndResetComments());
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
public SQLExpr primaryRest(SQLExpr expr) {
|
||||
if(lexer.token() == Token.COLON) {
|
||||
lexer.nextToken();
|
||||
expr = dotRest(expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
if (lexer.token() == Token.LBRACKET) {
|
||||
SQLArrayExpr array = new SQLArrayExpr();
|
||||
array.setExpr(expr);
|
||||
@@ -197,13 +213,20 @@ public class OdpsExprParser extends SQLExprParser {
|
||||
return transformExpr;
|
||||
}
|
||||
|
||||
if (expr instanceof SQLIdentifierExpr && ((SQLIdentifierExpr) expr).nameHashCode64() == FnvHash.Constants.NEW) {
|
||||
if (expr instanceof SQLIdentifierExpr
|
||||
&& ((SQLIdentifierExpr) expr).nameHashCode64() == FnvHash.Constants.NEW) {
|
||||
SQLIdentifierExpr ident = (SQLIdentifierExpr) expr;
|
||||
|
||||
if (lexer.identifierEquals(FnvHash.Constants.GSON)) {
|
||||
ident.setName(ident.getName() + ' ' + lexer.stringVal());
|
||||
OdpsNewExpr newExpr = new OdpsNewExpr();
|
||||
if (lexer.identifierEquals(FnvHash.Constants.GSON)
|
||||
|| lexer.identifierEquals(GSONBUILDER)) {
|
||||
lexer.nextToken();
|
||||
} else if (lexer.identifierEquals("java")) {
|
||||
newExpr.setMethodName(lexer.stringVal());
|
||||
accept(Token.LPAREN);
|
||||
this.exprList(newExpr.getArguments(), newExpr);
|
||||
accept(Token.RPAREN);
|
||||
expr = newExpr;
|
||||
} else if (lexer.identifierEquals("java") || lexer.identifierEquals("com")) {
|
||||
SQLName name = this.name();
|
||||
String strName = ident.getName() + ' ' + name.toString();
|
||||
if (lexer.token() == Token.LT) {
|
||||
@@ -221,7 +244,7 @@ public class OdpsExprParser extends SQLExprParser {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return super.primaryRest(expr);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ public class OdpsSelectParser extends SQLSelectParser {
|
||||
if (lexer.token() == Token.FROM) {
|
||||
parseFrom(queryBlock);
|
||||
parseWhere(queryBlock);
|
||||
parseGroupBy(queryBlock);
|
||||
|
||||
if (lexer.token() == Token.SELECT) {
|
||||
lexer.nextToken();
|
||||
@@ -84,6 +85,10 @@ public class OdpsSelectParser extends SQLSelectParser {
|
||||
|
||||
parseSelectList(queryBlock);
|
||||
}
|
||||
|
||||
if (queryBlock.getWhere() == null && lexer.token() == Token.WHERE) {
|
||||
parseWhere(queryBlock);
|
||||
}
|
||||
} else {
|
||||
accept(Token.SELECT);
|
||||
|
||||
@@ -92,22 +97,29 @@ public class OdpsSelectParser extends SQLSelectParser {
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.COMMENT) {
|
||||
String tokenStr = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.COMMA) {
|
||||
queryBlock.addSelectItem(new SQLIdentifierExpr(tokenStr));
|
||||
lexer.nextToken();
|
||||
}
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.DISTINCT) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == Token.UNIQUE) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.UNIQUE);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == Token.ALL) {
|
||||
Lexer.SavePoint mark = lexer.mark();
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.DOT) {
|
||||
lexer.reset(mark);
|
||||
} else {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.ALL);
|
||||
if (queryBlock.getSelectList().isEmpty()) {
|
||||
if (lexer.token() == Token.DISTINCT) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == Token.UNIQUE) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.UNIQUE);
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token() == Token.ALL) {
|
||||
Lexer.SavePoint mark = lexer.mark();
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.DOT) {
|
||||
lexer.reset(mark);
|
||||
} else {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +133,7 @@ public class OdpsSelectParser extends SQLSelectParser {
|
||||
}
|
||||
|
||||
parseWhere(queryBlock);
|
||||
parseGroupBy(queryBlock);
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals(FnvHash.Constants.WINDOW)) {
|
||||
@@ -193,6 +206,30 @@ public class OdpsSelectParser extends SQLSelectParser {
|
||||
lexer.nextToken();
|
||||
return new SQLExprTableSource(new SQLIdentifierExpr(str));
|
||||
}
|
||||
return super.parseTableSource();
|
||||
SQLTableSource tableSource = super.parseTableSource();
|
||||
|
||||
if (lexer.token() == Token.TABLE && tableSource.getAlias() == null) {
|
||||
tableSource.setAlias(
|
||||
lexer.stringVal()
|
||||
);
|
||||
lexer.nextToken();
|
||||
|
||||
tableSource = parseTableSourceRest(tableSource);
|
||||
}
|
||||
|
||||
return tableSource;
|
||||
}
|
||||
|
||||
protected SQLTableSource primaryTableSourceRest(SQLTableSource tableSource) {
|
||||
if (lexer.identifierEquals(FnvHash.Constants.LATERAL) || lexer.token() == Token.LATERAL) {
|
||||
Lexer.SavePoint mark = lexer.mark();
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.VIEW) {
|
||||
tableSource = parseLateralView(tableSource);
|
||||
} else {
|
||||
lexer.reset(mark);
|
||||
}
|
||||
}
|
||||
return tableSource;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,12 +49,12 @@ public class OdpsStatementParser extends SQLStatementParser {
|
||||
SQLSelect select = new OdpsSelectParser(this.exprParser)
|
||||
.select();
|
||||
|
||||
if (select.getWithSubQuery() == null && select.getQuery() instanceof SQLSelectQueryBlock) {
|
||||
SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) select.getQuery();
|
||||
if (queryBlock.getFrom() == null && queryBlock.getWhere() != null) {
|
||||
throw new ParserException("none from query not support where clause.");
|
||||
}
|
||||
}
|
||||
// if (select.getWithSubQuery() == null && select.getQuery() instanceof SQLSelectQueryBlock) {
|
||||
// SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) select.getQuery();
|
||||
// if (queryBlock.getFrom() == null && queryBlock.getWhere() != null) {
|
||||
// throw new ParserException("none from query not support where clause.");
|
||||
// }
|
||||
// }
|
||||
|
||||
return new SQLSelectStatement(select, DbType.odps);
|
||||
}
|
||||
|
||||
@@ -232,4 +232,12 @@ public interface OdpsASTVisitor extends HiveASTVisitor {
|
||||
|
||||
}
|
||||
|
||||
default boolean visit(OdpsNewExpr x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void endVisit(OdpsNewExpr x) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.alibaba.druid.sql.dialect.odps.visitor;
|
||||
import com.alibaba.druid.DbType;
|
||||
import com.alibaba.druid.sql.ast.*;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
|
||||
import com.alibaba.druid.sql.ast.statement.*;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType;
|
||||
import com.alibaba.druid.sql.dialect.hive.stmt.HiveCreateTableStatement;
|
||||
@@ -593,7 +594,11 @@ public class OdpsOutputVisitor extends HiveOutputVisitor implements OdpsASTVisit
|
||||
|
||||
protected void printMethodOwner(SQLExpr owner) {
|
||||
owner.accept(this);
|
||||
print(':');
|
||||
if (owner instanceof SQLMethodInvokeExpr) {
|
||||
print('.');
|
||||
} else {
|
||||
print(':');
|
||||
}
|
||||
}
|
||||
|
||||
protected void printJoinType(JoinType joinType) {
|
||||
@@ -956,4 +961,11 @@ public class OdpsOutputVisitor extends HiveOutputVisitor implements OdpsASTVisit
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(OdpsNewExpr x) {
|
||||
print0("new ");
|
||||
super.visit((SQLMethodInvokeExpr) x);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,6 +779,7 @@ public class SQLExprParser extends SQLParser {
|
||||
parseQueryPlanHint(sqlExpr);
|
||||
}
|
||||
break;
|
||||
case FROM:
|
||||
case SELECT:
|
||||
SQLQueryExpr queryExpr = new SQLQueryExpr(
|
||||
createSelectParser()
|
||||
@@ -866,6 +867,7 @@ public class SQLExprParser extends SQLParser {
|
||||
case NULL:
|
||||
case INTERVAL:
|
||||
case LBRACE:
|
||||
case IF:
|
||||
sqlExpr = primary();
|
||||
|
||||
while (lexer.token == Token.HINT) {
|
||||
@@ -1079,6 +1081,10 @@ public class SQLExprParser extends SQLParser {
|
||||
case DELETE:
|
||||
case BY:
|
||||
case UPDATE:
|
||||
case LOOP:
|
||||
case LIKE:
|
||||
case UNION:
|
||||
case CREATE:
|
||||
if (dbType == DbType.odps) {
|
||||
sqlExpr = new SQLIdentifierExpr(lexer.stringVal());
|
||||
lexer.nextToken();
|
||||
@@ -1135,6 +1141,15 @@ public class SQLExprParser extends SQLParser {
|
||||
}
|
||||
}
|
||||
throw new ParserException("ERROR. " + lexer.info());
|
||||
case COLONCOLON:
|
||||
if (dbType == DbType.odps) {
|
||||
lexer.nextToken();
|
||||
SQLMethodInvokeExpr method = (SQLMethodInvokeExpr) this.primary();
|
||||
method.setOwner(new SQLIdentifierExpr(""));
|
||||
sqlExpr = method;
|
||||
break;
|
||||
}
|
||||
throw new ParserException("ERROR. " + lexer.info());
|
||||
default:
|
||||
throw new ParserException("ERROR. " + lexer.info());
|
||||
}
|
||||
@@ -1152,7 +1167,7 @@ public class SQLExprParser extends SQLParser {
|
||||
SQLExpr sqlExpr;
|
||||
String str = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
if (lexer.token == Token.DOT) {
|
||||
if (lexer.token == Token.DOT || lexer.token == Token.SLASH) {
|
||||
return primaryRest(new SQLIdentifierExpr(str));
|
||||
} else if (lexer.token == Token.COMMA) {
|
||||
return new SQLIdentifierExpr(str);
|
||||
@@ -1244,6 +1259,9 @@ public class SQLExprParser extends SQLParser {
|
||||
case SLASH:
|
||||
case DOT:
|
||||
case FROM:
|
||||
case ORDER:
|
||||
case THEN:
|
||||
case END:
|
||||
return new SQLIdentifierExpr(str);
|
||||
default:
|
||||
break;
|
||||
@@ -1357,7 +1375,7 @@ public class SQLExprParser extends SQLParser {
|
||||
if (lexer.token == Token.LPAREN &&
|
||||
!(expr instanceof SQLIntegerExpr) && !(expr instanceof SQLHexExpr)) {
|
||||
SQLExpr method = methodRest(expr, true);
|
||||
if (lexer.token == Token.LBRACKET) {
|
||||
if (lexer.token == Token.LBRACKET || lexer.token == Token.DOT) {
|
||||
method = primaryRest(method);
|
||||
}
|
||||
return method;
|
||||
@@ -2023,6 +2041,10 @@ public class SQLExprParser extends SQLParser {
|
||||
case VALUES:
|
||||
case IN:
|
||||
case OUT:
|
||||
case LIMIT:
|
||||
case TRIGGER:
|
||||
case USE:
|
||||
case LIKE:
|
||||
if (dbType == DbType.odps) {
|
||||
identName = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
@@ -2227,7 +2249,7 @@ public class SQLExprParser extends SQLParser {
|
||||
|| lexer.token == Token.LITERAL_FLOAT
|
||||
|| lexer.token == Token.LITERAL_CHARS
|
||||
) {
|
||||
SQLExpr betweenBegin = this.primary();
|
||||
SQLExpr betweenBegin = this.additive();
|
||||
over.setWindowingBetweenBegin(betweenBegin);
|
||||
} else if (lexer.token == Token.IDENTIFIER) {
|
||||
long hash = lexer.hash_lower();
|
||||
@@ -2252,7 +2274,7 @@ public class SQLExprParser extends SQLParser {
|
||||
|| lexer.token == Token.LITERAL_FLOAT
|
||||
|| lexer.token == Token.LITERAL_CHARS
|
||||
) {
|
||||
SQLExpr betweenEnd = this.primary();
|
||||
SQLExpr betweenEnd = this.additive();
|
||||
over.setWindowingBetweenEnd(betweenEnd);
|
||||
} else if (lexer.token == Token.IDENTIFIER) {
|
||||
long hash = lexer.hash_lower();
|
||||
@@ -2261,7 +2283,7 @@ public class SQLExprParser extends SQLParser {
|
||||
&& hash != FnvHash.Constants.FOLLOWING
|
||||
&& hash != FnvHash.Constants.CURRENT
|
||||
&& hash != FnvHash.Constants.UNBOUNDED) {
|
||||
SQLExpr betweenBegin = this.primary();
|
||||
SQLExpr betweenBegin = this.additive();
|
||||
over.setWindowingBetweenEnd(betweenBegin);
|
||||
}
|
||||
}
|
||||
@@ -2275,7 +2297,7 @@ public class SQLExprParser extends SQLParser {
|
||||
|| lexer.token == Token.LITERAL_FLOAT
|
||||
|| lexer.token == Token.LITERAL_CHARS
|
||||
) {
|
||||
SQLExpr betweenBegin = this.primary();
|
||||
SQLExpr betweenBegin = this.additive();
|
||||
over.setWindowingBetweenBegin(betweenBegin);
|
||||
} else if (lexer.token == Token.IDENTIFIER) {
|
||||
long hash = lexer.hash_lower();
|
||||
@@ -2284,7 +2306,7 @@ public class SQLExprParser extends SQLParser {
|
||||
&& hash != FnvHash.Constants.FOLLOWING
|
||||
&& hash != FnvHash.Constants.CURRENT
|
||||
&& hash != FnvHash.Constants.UNBOUNDED) {
|
||||
SQLExpr betweenBegin = this.primary();
|
||||
SQLExpr betweenBegin = this.additive();
|
||||
over.setWindowingBetweenBegin(betweenBegin);
|
||||
}
|
||||
}
|
||||
@@ -4261,17 +4283,21 @@ public class SQLExprParser extends SQLParser {
|
||||
lexer.nextToken();
|
||||
|
||||
if (dbType == DbType.odps) {
|
||||
if (lexer.token == Token.LITERAL_ALIAS) {
|
||||
String tmp = lexer.stringVal();
|
||||
if (tmp.length() > 2 && tmp.charAt(0) == '"' && tmp.charAt(tmp.length() - 1) == '"') {
|
||||
tmp = tmp.substring(1, tmp.length() - 1);
|
||||
}
|
||||
for (;;) {
|
||||
if (lexer.token == Token.LITERAL_ALIAS) {
|
||||
String tmp = lexer.stringVal();
|
||||
if (tmp.length() > 2 && tmp.charAt(0) == '"' && tmp.charAt(tmp.length() - 1) == '"') {
|
||||
tmp = tmp.substring(1, tmp.length() - 1);
|
||||
}
|
||||
|
||||
stringVal += tmp;
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token == Token.LITERAL_CHARS) {
|
||||
stringVal += lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
stringVal += tmp;
|
||||
lexer.nextToken();
|
||||
} else if (lexer.token == Token.LITERAL_CHARS) {
|
||||
stringVal += lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5612,6 +5638,35 @@ public class SQLExprParser extends SQLParser {
|
||||
throw new ParserException("TODO");
|
||||
}
|
||||
|
||||
public SQLPartitionSpec parsePartitionSpec() {
|
||||
SQLPartitionSpec spec = new SQLPartitionSpec();
|
||||
accept(Token.PARTITION);
|
||||
accept(Token.LPAREN);
|
||||
|
||||
for (;;) {
|
||||
SQLPartitionSpec.Item item = new SQLPartitionSpec.Item();
|
||||
item.setColumn(
|
||||
this.name());
|
||||
|
||||
accept(Token.EQ);
|
||||
|
||||
item.setValue(
|
||||
this.expr());
|
||||
|
||||
spec.addItem(item);
|
||||
|
||||
if (lexer.token() == Token.COMMA) {
|
||||
lexer.nextToken();
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
accept(Token.RPAREN);
|
||||
return spec;
|
||||
}
|
||||
|
||||
protected SQLPartitionBy parsePartitionBy() {
|
||||
lexer.nextToken();
|
||||
accept(Token.BY);
|
||||
|
||||
@@ -297,6 +297,7 @@ public class SQLParser {
|
||||
case DEFERRED:
|
||||
case OUTER:
|
||||
case DO:
|
||||
case LOOP:
|
||||
case STORE:
|
||||
case MOD:
|
||||
case ANY:
|
||||
@@ -337,6 +338,9 @@ public class SQLParser {
|
||||
case INNER:
|
||||
case CLOSE:
|
||||
case VALUES:
|
||||
case SHOW:
|
||||
case SEQUENCE:
|
||||
case TO:
|
||||
if (dbType == DbType.odps) {
|
||||
alias = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
@@ -345,6 +349,7 @@ public class SQLParser {
|
||||
break;
|
||||
case GROUP:
|
||||
case ORDER:
|
||||
case DEFAULT:
|
||||
if (dbType == DbType.odps) {
|
||||
Lexer.SavePoint mark = lexer.mark();
|
||||
alias = lexer.stringVal();
|
||||
@@ -486,6 +491,7 @@ public class SQLParser {
|
||||
case PARTITION:
|
||||
case UPDATE:
|
||||
case DO:
|
||||
case LOOP:
|
||||
case REPEAT:
|
||||
case DEFAULT:
|
||||
case LIKE:
|
||||
@@ -499,6 +505,7 @@ public class SQLParser {
|
||||
case IN:
|
||||
case OUT:
|
||||
case BY:
|
||||
case EXCEPT:
|
||||
alias = lexer.stringVal();
|
||||
lexer.nextToken();
|
||||
return alias;
|
||||
|
||||
@@ -232,6 +232,9 @@ public class SQLSelectParser extends SQLParser {
|
||||
if (lexer.token == Token.ALL) {
|
||||
lexer.nextToken();
|
||||
union.setOperator(SQLUnionOperator.EXCEPT_ALL);
|
||||
} else if (lexer.token == Token.DISTINCT) {
|
||||
lexer.nextToken();
|
||||
union.setOperator(SQLUnionOperator.EXCEPT_DISTINCT);
|
||||
} else {
|
||||
union.setOperator(SQLUnionOperator.EXCEPT);
|
||||
}
|
||||
@@ -283,6 +286,9 @@ public class SQLSelectParser extends SQLParser {
|
||||
if (lexer.token() == Token.DISTINCT) {
|
||||
lexer.nextToken();
|
||||
union.setOperator(SQLUnionOperator.INTERSECT_DISTINCT);
|
||||
} else if (lexer.token == Token.ALL) {
|
||||
lexer.nextToken();
|
||||
union.setOperator(SQLUnionOperator.INTERSECT_ALL);
|
||||
} else {
|
||||
union.setOperator(SQLUnionOperator.INTERSECT);
|
||||
}
|
||||
@@ -596,111 +602,114 @@ public class SQLSelectParser extends SQLParser {
|
||||
}
|
||||
|
||||
public void parseWhere(SQLSelectQueryBlock queryBlock) {
|
||||
if (lexer.token == Token.WHERE) {
|
||||
lexer.nextTokenIdent();
|
||||
if (lexer.token != Token.WHERE) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> beforeComments = null;
|
||||
if (lexer.hasComment() && lexer.isKeepComments()) {
|
||||
beforeComments = lexer.readAndResetComments();
|
||||
}
|
||||
lexer.nextTokenIdent();
|
||||
|
||||
SQLExpr where;
|
||||
List<String> beforeComments = null;
|
||||
if (lexer.hasComment() && lexer.isKeepComments()) {
|
||||
beforeComments = lexer.readAndResetComments();
|
||||
}
|
||||
|
||||
if (lexer.token == Token.IDENTIFIER) {
|
||||
String ident = lexer.stringVal();
|
||||
long hash_lower = lexer.hash_lower();
|
||||
lexer.nextTokenEq();
|
||||
SQLExpr where;
|
||||
|
||||
SQLExpr identExpr;
|
||||
if (lexer.token == Token.LITERAL_CHARS) {
|
||||
String literal = lexer.stringVal;
|
||||
if (hash_lower == FnvHash.Constants.TIMESTAMP) {
|
||||
identExpr = new SQLTimestampExpr(literal);
|
||||
lexer.nextToken();
|
||||
} else if (hash_lower == FnvHash.Constants.DATE) {
|
||||
identExpr = new SQLDateExpr(literal);
|
||||
lexer.nextToken();
|
||||
} else if (hash_lower == FnvHash.Constants.REAL) {
|
||||
identExpr = new SQLRealExpr(Float.parseFloat(literal));
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
identExpr = new SQLIdentifierExpr(ident, hash_lower);
|
||||
}
|
||||
if (lexer.token == Token.IDENTIFIER) {
|
||||
String ident = lexer.stringVal();
|
||||
long hash_lower = lexer.hash_lower();
|
||||
lexer.nextTokenEq();
|
||||
|
||||
SQLExpr identExpr;
|
||||
if (lexer.token == Token.LITERAL_CHARS) {
|
||||
String literal = lexer.stringVal;
|
||||
if (hash_lower == FnvHash.Constants.TIMESTAMP) {
|
||||
identExpr = new SQLTimestampExpr(literal);
|
||||
lexer.nextToken();
|
||||
} else if (hash_lower == FnvHash.Constants.DATE) {
|
||||
identExpr = new SQLDateExpr(literal);
|
||||
lexer.nextToken();
|
||||
} else if (hash_lower == FnvHash.Constants.REAL) {
|
||||
identExpr = new SQLRealExpr(Float.parseFloat(literal));
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
identExpr = new SQLIdentifierExpr(ident, hash_lower);
|
||||
}
|
||||
|
||||
if (lexer.token == Token.DOT) {
|
||||
identExpr = this.exprParser.primaryRest(identExpr);
|
||||
}
|
||||
|
||||
if (lexer.token == Token.EQ) {
|
||||
SQLExpr rightExp;
|
||||
|
||||
lexer.nextToken();
|
||||
|
||||
try {
|
||||
rightExp = this.exprParser.bitOr();
|
||||
} catch (EOFParserException e) {
|
||||
throw new ParserException("EOF, " + ident + "=", e);
|
||||
}
|
||||
|
||||
where = new SQLBinaryOpExpr(identExpr, SQLBinaryOperator.Equality, rightExp, dbType);
|
||||
switch (lexer.token) {
|
||||
case BETWEEN:
|
||||
case IS:
|
||||
case EQ:
|
||||
case IN:
|
||||
case CONTAINS:
|
||||
case BANG_TILDE_STAR:
|
||||
case TILDE_EQ:
|
||||
case LT:
|
||||
case LTEQ:
|
||||
case LTEQGT:
|
||||
case GT:
|
||||
case GTEQ:
|
||||
case LTGT:
|
||||
case BANGEQ:
|
||||
case LIKE:
|
||||
case NOT:
|
||||
where = this.exprParser.relationalRest(where);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
where = this.exprParser.andRest(where);
|
||||
where = this.exprParser.xorRest(where);
|
||||
where = this.exprParser.orRest(where);
|
||||
} else {
|
||||
identExpr = this.exprParser.primaryRest(identExpr);
|
||||
where = this.exprParser.exprRest(identExpr);
|
||||
}
|
||||
} else {
|
||||
while (lexer.token == Token.HINT) {
|
||||
lexer.nextToken();
|
||||
identExpr = new SQLIdentifierExpr(ident, hash_lower);
|
||||
}
|
||||
|
||||
if (lexer.token == Token.DOT) {
|
||||
identExpr = this.exprParser.primaryRest(identExpr);
|
||||
}
|
||||
|
||||
if (lexer.token == Token.EQ) {
|
||||
SQLExpr rightExp;
|
||||
|
||||
lexer.nextToken();
|
||||
|
||||
try {
|
||||
rightExp = this.exprParser.bitOr();
|
||||
} catch (EOFParserException e) {
|
||||
throw new ParserException("EOF, " + ident + "=", e);
|
||||
}
|
||||
|
||||
where = this.exprParser.expr();
|
||||
|
||||
while (lexer.token == Token.HINT) {
|
||||
lexer.nextToken();
|
||||
where = new SQLBinaryOpExpr(identExpr, SQLBinaryOperator.Equality, rightExp, dbType);
|
||||
switch (lexer.token) {
|
||||
case BETWEEN:
|
||||
case IS:
|
||||
case EQ:
|
||||
case IN:
|
||||
case CONTAINS:
|
||||
case BANG_TILDE_STAR:
|
||||
case TILDE_EQ:
|
||||
case LT:
|
||||
case LTEQ:
|
||||
case LTEQGT:
|
||||
case GT:
|
||||
case GTEQ:
|
||||
case LTGT:
|
||||
case BANGEQ:
|
||||
case LIKE:
|
||||
case NOT:
|
||||
where = this.exprParser.relationalRest(where);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
where = this.exprParser.andRest(where);
|
||||
where = this.exprParser.xorRest(where);
|
||||
where = this.exprParser.orRest(where);
|
||||
} else {
|
||||
identExpr = this.exprParser.primaryRest(identExpr);
|
||||
where = this.exprParser.exprRest(identExpr);
|
||||
}
|
||||
// where = this.exprParser.expr();
|
||||
|
||||
if (beforeComments != null) {
|
||||
where.addBeforeComment(beforeComments);
|
||||
} else {
|
||||
while (lexer.token == Token.HINT) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
if (lexer.hasComment() && lexer.isKeepComments() //
|
||||
&& lexer.token != Token.INSERT // odps multi-insert
|
||||
) {
|
||||
where.addAfterComment(lexer.readAndResetComments());
|
||||
|
||||
where = this.exprParser.expr();
|
||||
|
||||
while (lexer.token == Token.HINT) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
queryBlock.setWhere(where);
|
||||
}
|
||||
// where = this.exprParser.expr();
|
||||
|
||||
if (beforeComments != null) {
|
||||
where.addBeforeComment(beforeComments);
|
||||
}
|
||||
|
||||
if (lexer.hasComment() && lexer.isKeepComments() //
|
||||
&& lexer.token != Token.INSERT // odps multi-insert
|
||||
) {
|
||||
where.addAfterComment(lexer.readAndResetComments());
|
||||
}
|
||||
|
||||
queryBlock.setWhere(where);
|
||||
|
||||
}
|
||||
|
||||
protected void parseSortBy(SQLSelectQueryBlock queryBlock) {
|
||||
@@ -1391,7 +1400,7 @@ public class SQLSelectParser extends SQLParser {
|
||||
|
||||
rightTableSource = exprTableSource;
|
||||
}
|
||||
primaryTableSourceRest(rightTableSource);
|
||||
rightTableSource = primaryTableSourceRest(rightTableSource);
|
||||
}
|
||||
|
||||
if (lexer.token == Token.USING
|
||||
@@ -1438,7 +1447,7 @@ public class SQLSelectParser extends SQLParser {
|
||||
}
|
||||
}
|
||||
|
||||
primaryTableSourceRest(rightTableSource);
|
||||
rightTableSource = primaryTableSourceRest(rightTableSource);
|
||||
}
|
||||
|
||||
if (lexer.token == Token.WITH) {
|
||||
|
||||
@@ -2183,8 +2183,41 @@ public class SQLStatementParser extends SQLParser {
|
||||
stmt.addItem(item);
|
||||
} else if (DbType.odps == dbType && lexer.identifierEquals("MERGE")) {
|
||||
lexer.nextToken();
|
||||
acceptIdentifier("SMALLFILES");
|
||||
stmt.setMergeSmallFiles(true);
|
||||
|
||||
boolean ifExists = false;
|
||||
if (lexer.token == Token.IF) {
|
||||
lexer.nextToken();
|
||||
accept(Token.EXISTS);
|
||||
ifExists = true;
|
||||
}
|
||||
|
||||
if (lexer.token == PARTITION) {
|
||||
SQLAlterTableMergePartition item = new SQLAlterTableMergePartition();
|
||||
for (;;) {
|
||||
item.addPartition(
|
||||
this.getExprParser().parsePartitionSpec()
|
||||
);
|
||||
if (lexer.token == COMMA) {
|
||||
lexer.nextToken();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
accept(OVERWRITE);
|
||||
item.setOverwritePartition(
|
||||
this.getExprParser().parsePartitionSpec()
|
||||
);
|
||||
|
||||
if (ifExists) {
|
||||
item.setIfExists(true);
|
||||
}
|
||||
|
||||
stmt.addItem(item);
|
||||
} else {
|
||||
acceptIdentifier("SMALLFILES");
|
||||
stmt.setMergeSmallFiles(true);
|
||||
}
|
||||
} else if (DbType.odps == dbType && lexer.identifierEquals(FnvHash.Constants.CLUSTERED)) {
|
||||
lexer.nextToken();
|
||||
accept(Token.BY);
|
||||
@@ -6627,6 +6660,13 @@ public class SQLStatementParser extends SQLParser {
|
||||
SQLExpr tableExpr = this.exprParser.expr();
|
||||
stmt.setTable(tableExpr);
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals(FnvHash.Constants.ADD)) {
|
||||
lexer.nextToken();
|
||||
acceptIdentifier("PARTITIONS");
|
||||
stmt.setAddPartitions(true);
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.alibaba.druid.sql.dialect.hive.stmt.HiveCreateTableStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.*;
|
||||
import com.alibaba.druid.sql.dialect.odps.ast.OdpsNewExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleSegmentAttributes;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleCursorExpr;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleDatetimeExpr;
|
||||
@@ -9038,6 +9039,34 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLAlterTableMergePartition x) {
|
||||
print0(ucase ? "MERGE " : "merge ");
|
||||
if (x.isIfExists()) {
|
||||
print0(ucase ? "IF EXISTS " : "if exists ");
|
||||
}
|
||||
println();
|
||||
printlnAndAccept(x.getPartitions(), ", ");
|
||||
println();
|
||||
print0(ucase ? "OVERWRITE" : "overwrite");
|
||||
println();
|
||||
x.getOverwritePartition().accept(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLPartitionSpec x) {
|
||||
print0(ucase ? "PARTITION (" : "partition (");
|
||||
printAndAccept(x.getItems(), ", ");
|
||||
print(')');
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLPartitionSpec.Item x) {
|
||||
x.getColumn().accept(this);
|
||||
print0(" = ");
|
||||
x.getValue().accept(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLAlterTableSubpartitionAvailablePartitionNum x) {
|
||||
print0(ucase ? "SUBPARTITION_AVAILABLE_PARTITION_NUM = " : "subpartition_available_partition_num = ");
|
||||
x.getNumber().accept(this);
|
||||
@@ -10960,6 +10989,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(OdpsNewExpr x) {
|
||||
print0(ucase ? "NEW " : "new ");
|
||||
return super.visit((SQLMethodInvokeExpr) x);
|
||||
}
|
||||
|
||||
public char getNameQuote() {
|
||||
return quote;
|
||||
}
|
||||
|
||||
@@ -2595,4 +2595,29 @@ public interface SQLASTVisitor {
|
||||
default boolean visit(SQLListResourceGroupStatement x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void endVisit(SQLAlterTableMergePartition x) {
|
||||
|
||||
}
|
||||
|
||||
default boolean visit(SQLAlterTableMergePartition x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void endVisit(SQLPartitionSpec x) {
|
||||
|
||||
}
|
||||
|
||||
default boolean visit(SQLPartitionSpec x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void endVisit(SQLPartitionSpec.Item x) {
|
||||
|
||||
}
|
||||
|
||||
default boolean visit(SQLPartitionSpec.Item x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.alibaba.druid.bvt.sql.schemaStat;
|
||||
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
|
||||
import com.alibaba.druid.sql.parser.SQLParserUtils;
|
||||
import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
import com.alibaba.druid.sql.repository.SchemaRepository;
|
||||
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
|
||||
import com.alibaba.druid.util.JdbcConstants;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class SchemaStatTest21_issue3980 extends TestCase {
|
||||
|
||||
public void test_schemaStat() throws Exception {
|
||||
SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);
|
||||
|
||||
String sql = "select n.user_name,\n" +
|
||||
"n.user_passwd,\n" +
|
||||
"n.user_project,\n" +
|
||||
"n.start_date,\n" +
|
||||
"n.end_date\n" +
|
||||
"from (\n" +
|
||||
"select t.name as user_name,\n" +
|
||||
"t.passwd as user_passwd,\n" +
|
||||
"cast(from_unixtime(t.from_time, \"yyyyMMdd\") as int) as start_date,\n" +
|
||||
"cast(from_unixtime(t.to_time, \"yyyyMMdd\") as int) as end_date\n" +
|
||||
"from tableA as t\n" +
|
||||
"where t.user_id = 1\n" +
|
||||
"union all\n" +
|
||||
"select p.project as user_project\n" +
|
||||
"from tableB as p\n" +
|
||||
"where p.project_id = 10\n" +
|
||||
") as n;";
|
||||
|
||||
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, JdbcConstants.MYSQL);
|
||||
SQLStatement stmt = parser.parseStatementList().get(0);
|
||||
|
||||
SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(repository);
|
||||
stmt.accept(statVisitor);
|
||||
|
||||
System.out.println("Tables : " + statVisitor.getTables());
|
||||
System.out.println("columns : " + statVisitor.getColumns());
|
||||
System.out.println(statVisitor.getGroupByColumns()); // group by
|
||||
System.out.println("relationships : " + statVisitor.getRelationships()); // group by
|
||||
System.out.println("conditions : " + statVisitor.getConditions());
|
||||
System.out.println("functions : " + statVisitor.getFunctions());
|
||||
|
||||
assertEquals(7, statVisitor.getColumns().size());
|
||||
assertEquals(2, statVisitor.getConditions().size());
|
||||
assertEquals(2, statVisitor.getFunctions().size());
|
||||
|
||||
SQLPropertyExpr expr = (SQLPropertyExpr) statVisitor.getFunctions().get(0).getArguments().get(0);
|
||||
SQLIdentifierExpr tableAlias = (SQLIdentifierExpr) expr.getOwner();
|
||||
tableAlias.getResolvedTableSource();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.alibaba.druid.bvt.sql.schemaStat;
|
||||
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.parser.SQLParserUtils;
|
||||
import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
import com.alibaba.druid.sql.repository.SchemaRepository;
|
||||
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
|
||||
import com.alibaba.druid.util.JdbcConstants;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class SchemaStatTest22_yiran extends TestCase {
|
||||
|
||||
public void test_schemaStat() throws Exception {
|
||||
SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL);
|
||||
repository.console("CREATE TABLE DEPT (depno INT4, dname ENC_TEXT)");
|
||||
|
||||
String sql = "SELECT * FROM ( SELECT dname FROM DEPT) X WHERE X.dname='cs';";
|
||||
// sql = "SELECT * FROM ( SELECT * FROM DEPT) X WHERE X.dname='cs'";
|
||||
|
||||
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, JdbcConstants.MYSQL);
|
||||
SQLStatement stmt = parser.parseStatementList().get(0);
|
||||
|
||||
SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(repository);
|
||||
stmt.accept(statVisitor);
|
||||
|
||||
SQLSelectQueryBlock q = ((SQLSelectStatement) stmt).getSelect().getFirstQueryBlock();
|
||||
SQLPropertyExpr whereLeft = (SQLPropertyExpr) ((SQLBinaryOpExpr) q.getWhere()).getLeft();
|
||||
SQLColumnDefinition resolvedColumn = whereLeft.getResolvedColumn();
|
||||
assertNotNull(resolvedColumn);
|
||||
|
||||
System.out.println("Tables : " + statVisitor.getTables());
|
||||
System.out.println("columns : " + statVisitor.getColumns());
|
||||
// System.out.println(statVisitor.getGroupByColumns()); // group by
|
||||
System.out.println("relationships : " + statVisitor.getRelationships()); // group by
|
||||
System.out.println("conditions : " + statVisitor.getConditions());
|
||||
|
||||
assertEquals(1, statVisitor.getColumns().size());
|
||||
assertEquals(1, statVisitor.getConditions().size());
|
||||
assertEquals(0, statVisitor.getFunctions().size());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user