improved sql parser.

This commit is contained in:
wenshao
2017-06-05 09:59:34 +08:00
parent 21ae9b5722
commit bea1d70af2
28 changed files with 419 additions and 233 deletions
@@ -810,5 +810,54 @@ public class SQLUtils {
return false;
}
public static SQLCaseExpr decodeToCase(SQLMethodInvokeExpr x) {
if (x == null) {
return null;
}
if (!"decode".equalsIgnoreCase(x.getMethodName())) {
throw new IllegalArgumentException(x.getMethodName());
}
List<SQLExpr> parameters = x.getParameters();
SQLCaseExpr caseExpr = new SQLCaseExpr();
caseExpr.setValueExpr(parameters.get(0));
for (int i = 1; i + 1 < parameters.size(); i += 2) {
SQLCaseExpr.Item item = new SQLCaseExpr.Item();
SQLExpr conditionExpr = parameters.get(i);
item.setConditionExpr(conditionExpr);
SQLExpr valueExpr = parameters.get(i + 1);
if (valueExpr instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) valueExpr;
if ("decode".equalsIgnoreCase(methodInvokeExpr.getMethodName())) {
valueExpr = decodeToCase(methodInvokeExpr);
}
}
item.setValueExpr(valueExpr);
caseExpr.addItem(item);
}
if (parameters.size() % 2 == 0) {
SQLExpr defaultExpr = parameters.get(parameters.size() - 1);
if (defaultExpr instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) defaultExpr;
if ("decode".equalsIgnoreCase(methodInvokeExpr.getMethodName())) {
defaultExpr = decodeToCase(methodInvokeExpr);
}
}
caseExpr.setElseExpr(defaultExpr);
}
return caseExpr;
}
}
@@ -289,4 +289,12 @@ public class SQLBinaryOpExpr extends SQLExprImpl implements Serializable {
return new SQLBinaryOpExpr(a, SQLBinaryOperator.BooleanAnd, b);
}
public static SQLBinaryOpExpr isNotNull(SQLExpr expr) {
return new SQLBinaryOpExpr(expr, SQLBinaryOperator.IsNot, new SQLNullExpr());
}
public static SQLBinaryOpExpr isNull(SQLExpr expr) {
return new SQLBinaryOpExpr(expr, SQLBinaryOperator.Is, new SQLNullExpr());
}
}
@@ -18,5 +18,7 @@ package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.ast.SQLObject;
public interface SQLSelectQuery extends SQLObject {
boolean isBracket();
void setBracket(boolean bracket);
}
@@ -25,7 +25,7 @@ import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery {
private boolean bracket = false;
protected int distionOption;
protected final List<SQLSelectItem> selectList = new ArrayList<SQLSelectItem>();
@@ -376,4 +376,14 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery
x.setLimit(limit.clone());
}
}
@Override
public boolean isBracket() {
return bracket;
}
@Override
public void setBracket(boolean bracket) {
this.bracket = bracket;
}
}
@@ -22,6 +22,8 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLUnionQuery extends SQLObjectImpl implements SQLSelectQuery {
private boolean bracket = false;
private SQLSelectQuery left;
private SQLSelectQuery right;
private SQLUnionOperator operator = SQLUnionOperator.UNION;
@@ -96,4 +98,12 @@ public class SQLUnionQuery extends SQLObjectImpl implements SQLSelectQuery {
}
this.limit = limit;
}
public boolean isBracket() {
return bracket;
}
public void setBracket(boolean bracket) {
this.bracket = bracket;
}
}
@@ -78,6 +78,7 @@ public class MySqlSelectParser extends SQLSelectParser {
lexer.nextToken();
SQLSelectQuery select = query();
select.setBracket(true);
accept(Token.RPAREN);
return queryRest(select);
@@ -210,9 +211,12 @@ public class MySqlSelectParser extends SQLSelectParser {
SQLTableSource tableSource;
if (lexer.token() == Token.SELECT || lexer.token() == Token.WITH) {
SQLSelect select = select();
accept(Token.RPAREN);
SQLSelectQuery query = queryRest(select.getQuery());
if (query instanceof SQLUnionQuery) {
select.getQuery().setBracket(true);
tableSource = new SQLUnionQueryTableSource((SQLUnionQuery) query);
} else {
tableSource = new SQLSubqueryTableSource(select);
@@ -193,6 +193,11 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
public boolean visit(MySqlSelectQueryBlock x) {
final boolean bracket = x.isBracket();
if (bracket) {
print('(');
}
if ((!isParameterized()) && isPrettyFormat() && x.hasBeforeComment()) {
printComment(x.getBeforeCommentsDirect(), "\n");
}
@@ -309,6 +314,10 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
print0(ucase ? "LOCK IN SHARE MODE" : "lock in share mode");
}
if (bracket) {
print(')');
}
return false;
}
@@ -716,10 +725,10 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
public boolean visit(SQLMethodInvokeExpr x) {
SQLExpr owner = x.getOwner();
if ("SUBSTRING".equalsIgnoreCase(x.getMethodName())) {
if (x.getOwner() != null) {
x.getOwner().accept(this);
print('.');
if (owner != null) {
printMethodOwner(owner);
}
print0(x.getMethodName());
print('(');
@@ -741,9 +750,8 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
if ("TRIM".equalsIgnoreCase(x.getMethodName())) {
if (x.getOwner() != null) {
x.getOwner().accept(this);
print('.');
if (owner != null) {
printMethodOwner(owner);
}
print0(x.getMethodName());
print('(');
@@ -768,9 +776,8 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
if (("CONVERT".equalsIgnoreCase(x.getMethodName())) || "CHAR".equalsIgnoreCase(x.getMethodName())) {
if (x.getOwner() != null) {
x.getOwner().accept(this);
print('.');
if (owner != null) {
printMethodOwner(owner);
}
print0(x.getMethodName());
print('(');
@@ -2569,37 +2576,37 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
public boolean visit(SQLUnionQuery x) {
print('(');
x.getLeft().accept(this);
print(')');
println();
print0(ucase ? x.getOperator().name : x.getOperator().name_lcase);
println();
SQLSelectQuery right = x.getRight();
boolean needParen = ! (right instanceof SQLUnionQuery);
if (needParen) {
print('(');
right.accept(this);
print(')');
} else {
right.accept(this);
}
if (x.getOrderBy() != null) {
println();
x.getOrderBy().accept(this);
}
if (x.getLimit() != null) {
println();
x.getLimit().accept(this);
}
return false;
}
// public boolean visit(SQLUnionQuery x) {
// print('(');
// x.getLeft().accept(this);
// print(')');
// println();
// print0(ucase ? x.getOperator().name : x.getOperator().name_lcase);
// println();
//
// SQLSelectQuery right = x.getRight();
// boolean needParen = ! (right instanceof SQLUnionQuery);
//
// if (needParen) {
// print('(');
// right.accept(this);
// print(')');
// } else {
// right.accept(this);
// }
//
// if (x.getOrderBy() != null) {
// println();
// x.getOrderBy().accept(this);
// }
//
// if (x.getLimit() != null) {
// println();
// x.getLimit().accept(this);
// }
//
// return false;
// }
@Override
public boolean visit(MySqlUseIndexHint x) {
@@ -19,11 +19,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.alibaba.druid.sql.ast.SQLDataType;
import com.alibaba.druid.sql.ast.SQLHint;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.SQLCaseExpr;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
@@ -242,32 +238,6 @@ public class OdpsOutputVisitor extends SQLASTOutputVisitor implements OdpsASTVis
return false;
}
public boolean visit(SQLCaseExpr x) {
incrementIndent();
print0(ucase ? "CASE " : "case ");
if (x.getValueExpr() != null) {
x.getValueExpr().accept(this);
println();
}
for (int i = 0, size = x.getItems().size(); i < size; ++i) {
println();
x.getItems().get(i).accept(this);
}
if (x.getElseExpr() != null) {
println();
print0(ucase ? "ELSE " : "else ");
x.getElseExpr().accept(this);
}
decrementIndent();
println();
print0(ucase ? "END" : "end");
return false;
}
protected void printSelectList(List<SQLSelectItem> selectList) {
incrementIndent();
for (int i = 0, size = selectList.size(); i < size; ++i) {
@@ -685,16 +655,9 @@ public class OdpsOutputVisitor extends SQLASTOutputVisitor implements OdpsASTVis
return false;
}
public boolean visit(SQLMethodInvokeExpr x) {
if (x.getOwner() != null) {
x.getOwner().accept(this);
print(':');
}
printFunctionName(x.getMethodName());
print('(');
printAndAccept(x.getParameters(), ", ");
print(')');
return false;
protected void printMethodOwner(SQLExpr owner) {
owner.accept(this);
print(':');
}
protected void printJoinType(JoinType joinType) {
@@ -24,6 +24,7 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGSQLObjectImpl;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
public class PGValuesQuery extends PGSQLObjectImpl implements SQLSelectQuery {
private boolean bracket = false;
private List<SQLExpr> values = new ArrayList<SQLExpr>();
@@ -39,4 +40,13 @@ public class PGValuesQuery extends PGSQLObjectImpl implements SQLSelectQuery {
visitor.endVisit(this);
}
@Override
public boolean isBracket() {
return bracket;
}
@Override
public void setBracket(boolean bracket) {
this.bracket = bracket;
}
}
@@ -256,8 +256,17 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
SQLSelectItem selectItem = selectList.get(i);
SQLExpr selectItemExpr = selectItem.getExpr();
if (i != 0) {
if (lineItemCount == selectListNumberOfLine
|| selectItemExpr instanceof SQLQueryExpr) {
if (selectItemExpr instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) selectItemExpr;
int paramCount = methodInvokeExpr.getParameters().size();
lineItemCount += paramCount;
if (lineItemCount >= selectListNumberOfLine) {
lineItemCount = paramCount;
println();
}
} else if (lineItemCount >= selectListNumberOfLine
|| selectItemExpr instanceof SQLQueryExpr
|| selectItemExpr instanceof SQLCaseExpr) {
lineItemCount = 0;
println();
}
@@ -498,28 +507,53 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
}
public boolean visit(SQLCaseExpr x) {
incrementIndent();
print0(ucase ? "CASE " : "case ");
if (x.getValueExpr() != null) {
x.getValueExpr().accept(this);
print0(" ");
}
printAndAccept(x.getItems(), " ");
if (x.getElseExpr() != null) {
print0(ucase ? " ELSE " : " else ");
x.getElseExpr().accept(this);
for (int i = 0, size = x.getItems().size(); i < size; ++i) {
println();
x.getItems().get(i).accept(this);
}
print0(ucase ? " END" : " end");
SQLExpr elExpr = x.getElseExpr();
if (elExpr != null) {
println();
print0(ucase ? "ELSE " : "else ");
if (elExpr instanceof SQLCaseExpr) {
incrementIndent();
println();
elExpr.accept(this);
decrementIndent();
} else {
elExpr.accept(this);
}
}
decrementIndent();
println();
print0(ucase ? "END" : "end");
return false;
}
public boolean visit(SQLCaseExpr.Item x) {
print0(ucase ? "WHEN " : "when ");
x.getConditionExpr().accept(this);
SQLExpr expr = x.getConditionExpr();
expr.accept(this);
print0(ucase ? " THEN " : " then ");
x.getValueExpr().accept(this);
SQLExpr valueExpr = x.getValueExpr();
if (valueExpr instanceof SQLCaseExpr) {
incrementIndent();
println();
valueExpr.accept(this);
decrementIndent();
} else {
valueExpr.accept(this);
}
return false;
}
@@ -861,13 +895,22 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
}
public boolean visit(SQLMethodInvokeExpr x) {
if (x.getOwner() != null) {
x.getOwner().accept(this);
print('.');
SQLExpr owner = x.getOwner();
if (owner != null) {
printMethodOwner(owner);
}
printFunctionName(x.getMethodName());
print('(');
printAndAccept(x.getParameters(), ", ");
List<SQLExpr> parameters = x.getParameters();
for (int i = 0, size = parameters.size(); i < size; ++i) {
if (i != 0) {
print0(", ");
}
SQLExpr param = x.getParameters().get(i);
param.accept(this);
}
SQLExpr from = x.getFrom();
if (from != null) {
@@ -879,6 +922,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
return false;
}
protected void printMethodOwner(SQLExpr owner) {
owner.accept(this);
print('.');
}
protected void printFunctionName(String name) {
print0(name);
}
@@ -1859,28 +1907,26 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
public boolean visit(SQLUnionQuery x) {
SQLUnionOperator operator = x.getOperator();
boolean mysqlUnion = (JdbcConstants.MYSQL.equals(dbType) //
&& (operator == SQLUnionOperator.UNION || operator == SQLUnionOperator.UNION_ALL));
boolean bracket = x.isBracket();
if (mysqlUnion) {
if (bracket) {
print('(');
}
x.getLeft().accept(this);
if (mysqlUnion) {
print(')');
}
println();
print0(ucase ? operator.name : operator.name_lcase);
println();
boolean needParen = x.getOrderBy() != null || mysqlUnion;
SQLSelectQuery right = x.getRight();
boolean needParen = x.getOrderBy() != null && !right.isBracket();
if (needParen) {
print('(');
x.getRight().accept(this);
right.accept(this);
print(')');
} else {
x.getRight().accept(this);
right.accept(this);
}
if (x.getOrderBy() != null) {
@@ -1888,6 +1934,10 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
x.getOrderBy().accept(this);
}
if (bracket) {
print(')');
}
return false;
}