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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user