improved sql parser.

This commit is contained in:
wenshao
2017-06-06 10:13:48 +08:00
parent d9a0cae840
commit 3165a86e3c
16 changed files with 461 additions and 57 deletions
@@ -22,17 +22,10 @@ import java.util.Map;
import com.alibaba.druid.DruidRuntimeException;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLSetStatement;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2OutputVisitor;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
@@ -871,38 +864,8 @@ public class SQLUtils {
SQLObject parent = expr.getParent();
if (parent instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr binaryParent = (SQLBinaryOpExpr) expr.getParent();
if (binaryParent.getLeft() == expr) {
binaryParent.setLeft(target);
return true;
} else if (binaryParent.getRight() == expr) {
binaryParent.setRight(target);
return true;
} else {
return false;
}
}
if (parent instanceof SQLSelectOrderByItem){
SQLSelectOrderByItem orderByItem = (SQLSelectOrderByItem) parent;
if (orderByItem.getExpr() == expr) {
orderByItem.setExpr(target);
return true;
}
return false;
}
if (parent instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) parent;
List<SQLExpr> parameters = methodInvokeExpr.getParameters();
for (int i = 0; i < parameters.size(); ++i) {
if (parameters.get(i) == expr) {
parameters.set(i, target);
return true;
}
}
return false;
if (parent instanceof SQLReplaceable) {
return ((SQLReplaceable) parent).replace(expr, target);
}
return false;
@@ -0,0 +1,23 @@
/*
* 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;
/**
* Created by wenshao on 06/06/2017.
*/
public interface SQLReplaceable {
boolean replace(SQLExpr expr, SQLExpr target);
}
@@ -22,10 +22,12 @@ import java.util.List;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLExprImpl;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.Utils;
public class SQLBinaryOpExpr extends SQLExprImpl implements Serializable {
public class SQLBinaryOpExpr extends SQLExprImpl implements SQLReplaceable, Serializable {
private static final long serialVersionUID = 1L;
private SQLExpr left;
@@ -310,6 +312,39 @@ public class SQLBinaryOpExpr extends SQLExprImpl implements Serializable {
return new SQLBinaryOpExpr(a, SQLBinaryOperator.BooleanAnd, b);
}
public static SQLExpr andIfNotExists(SQLExpr a, SQLExpr b) {
if (a == null) {
return b;
}
if (b == null) {
return a;
}
List<SQLExpr> groupListA = new ArrayList<SQLExpr>();
List<SQLExpr> groupListB = new ArrayList<SQLExpr>();
split(groupListA, a, SQLBinaryOperator.BooleanAnd);
split(groupListB, a, SQLBinaryOperator.BooleanAnd);
for (SQLExpr itemB : groupListB) {
boolean exist = false;
for (SQLExpr itemA : groupListA) {
if (itemA.equals(itemB)) {
exist = true;
} else if (itemA instanceof SQLBinaryOpExpr
&& itemB instanceof SQLBinaryOpExpr) {
if (((SQLBinaryOpExpr) itemA).equalsIgoreOrder((SQLBinaryOpExpr) itemB)) {
exist = true;
}
}
}
if (!exist) {
groupListA.add(itemB);
}
}
return combine(groupListA, SQLBinaryOperator.BooleanAnd);
}
public static SQLBinaryOpExpr isNotNull(SQLExpr expr) {
return new SQLBinaryOpExpr(expr, SQLBinaryOperator.IsNot, new SQLNullExpr());
}
@@ -317,4 +352,34 @@ public class SQLBinaryOpExpr extends SQLExprImpl implements Serializable {
public static SQLBinaryOpExpr isNull(SQLExpr expr) {
return new SQLBinaryOpExpr(expr, SQLBinaryOperator.Is, new SQLNullExpr());
}
public boolean replace(SQLExpr expr, SQLExpr taget) {
SQLObject parent = getParent();
if (left == expr) {
if (taget == null) {
if (parent instanceof SQLReplaceable) {
return ((SQLReplaceable) parent).replace(this, right);
} else {
return false;
}
}
this.setLeft(taget);
return true;
}
if (right == expr) {
if (taget == null) {
if (parent instanceof SQLReplaceable) {
return ((SQLReplaceable) parent).replace(this, left);
} else {
return false;
}
}
this.setRight(taget);
return true;
}
return false;
}
}
@@ -22,9 +22,10 @@ import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLExprImpl;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLCaseExpr extends SQLExprImpl implements Serializable {
public class SQLCaseExpr extends SQLExprImpl implements SQLReplaceable, Serializable {
private static final long serialVersionUID = 1L;
private final List<Item> items = new ArrayList<Item>();
@@ -77,7 +78,22 @@ public class SQLCaseExpr extends SQLExprImpl implements Serializable {
visitor.endVisit(this);
}
public static class Item extends SQLObjectImpl implements Serializable {
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (valueExpr == expr) {
setValueExpr(target);
return true;
}
if (elseExpr == expr) {
setElseExpr(target);
return true;
}
return false;
}
public static class Item extends SQLObjectImpl implements SQLReplaceable, Serializable {
private static final long serialVersionUID = 1L;
private SQLExpr conditionExpr;
@@ -158,6 +174,21 @@ public class SQLCaseExpr extends SQLExprImpl implements Serializable {
}
return x;
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (valueExpr == expr) {
setValueExpr(target);
return true;
}
if (conditionExpr == expr) {
setConditionExpr(target);
return true;
}
return false;
}
}
@Override
@@ -21,10 +21,11 @@ import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLExprImpl;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLMethodInvokeExpr extends SQLExprImpl implements Serializable {
public class SQLMethodInvokeExpr extends SQLExprImpl implements SQLReplaceable, Serializable {
private static final long serialVersionUID = 1L;
private String methodName;
@@ -164,4 +165,16 @@ public class SQLMethodInvokeExpr extends SQLExprImpl implements Serializable {
return x;
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
for (int i = 0; i < parameters.size(); ++i) {
if (parameters.get(i) == expr) {
parameters.set(i, target);
target.setParent(this);
return true;
}
}
return false;
}
}
@@ -17,9 +17,10 @@ package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLAssignItem extends SQLObjectImpl {
public class SQLAssignItem extends SQLObjectImpl implements SQLReplaceable {
private SQLExpr target;
private SQLExpr value;
@@ -69,4 +70,17 @@ public class SQLAssignItem extends SQLObjectImpl {
visitor.endVisit(this);
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (this.target == expr) {
setTarget(target);
return true;
}
if (this.value == expr) {
setValue(target);
return true;
}
return false;
}
}
@@ -186,7 +186,7 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS
return null;
}
public SQLTableElement findKey(String columnName) {
public SQLTableElement findIndex(String columnName) {
for (SQLTableElement element : tableElementList) {
List<SQLExpr> keyColumns = null;
if (element instanceof SQLUniqueConstraint) {
@@ -17,11 +17,12 @@ package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLDeleteStatement extends SQLStatementImpl {
public class SQLDeleteStatement extends SQLStatementImpl implements SQLReplaceable {
protected SQLTableSource tableSource;
protected SQLExpr where;
@@ -121,4 +122,13 @@ public class SQLDeleteStatement extends SQLStatementImpl {
}
this.from = from;
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (where == expr) {
setWhere(target);
return true;
}
return false;
}
}
@@ -19,9 +19,10 @@ import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLJoinTableSource extends SQLTableSourceImpl {
public class SQLJoinTableSource extends SQLTableSourceImpl implements SQLReplaceable {
protected SQLTableSource left;
protected JoinType joinType;
@@ -139,6 +140,16 @@ public class SQLJoinTableSource extends SQLTableSourceImpl {
return using != null ? using.equals(that.using) : that.using == null;
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (condition == expr) {
setCondition(target);
return true;
}
return false;
}
public static enum JoinType {
COMMA(","), //
JOIN("JOIN"), //
@@ -18,11 +18,12 @@ package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLSelectItem extends SQLObjectImpl {
public class SQLSelectItem extends SQLObjectImpl implements SQLReplaceable {
protected SQLExpr expr;
protected String alias;
@@ -146,4 +147,14 @@ public class SQLSelectItem extends SQLObjectImpl {
x.connectByRoot = connectByRoot;
return x;
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (expr == expr) {
setExpr(target);
return true;
}
return false;
}
}
@@ -18,9 +18,10 @@ package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLSelectOrderByItem extends SQLObjectImpl {
public class SQLSelectOrderByItem extends SQLObjectImpl implements SQLReplaceable {
protected SQLExpr expr;
protected String collate;
@@ -104,6 +105,15 @@ public class SQLSelectOrderByItem extends SQLObjectImpl {
return true;
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (this.expr == expr) {
this.setExpr(target);
return true;
}
return false;
}
public static enum NullsOrderType {
NullsFirst, NullsLast;
@@ -18,13 +18,10 @@ package com.alibaba.druid.sql.ast.statement;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery {
public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery, SQLReplaceable {
private boolean bracket = false;
protected int distionOption;
protected final List<SQLSelectItem> selectList = new ArrayList<SQLSelectItem>();
@@ -415,4 +412,13 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery
return null;
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (where == expr) {
setWhere(target);
return true;
}
return false;
}
}
@@ -20,10 +20,11 @@ import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLUpdateStatement extends SQLStatementImpl {
public class SQLUpdateStatement extends SQLStatementImpl implements SQLReplaceable {
protected final List<SQLUpdateSetItem> items = new ArrayList<SQLUpdateSetItem>();
protected SQLExpr where;
@@ -131,4 +132,13 @@ public class SQLUpdateStatement extends SQLStatementImpl {
}
visitor.endVisit(this);
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (where == expr) {
setWhere(target);
return true;
}
return false;
}
}
@@ -0,0 +1,89 @@
/*
* 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.repository;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableElement;
import com.alibaba.druid.sql.ast.statement.SQLUniqueConstraint;
/**
* Created by wenshao on 03/06/2017.
*/
public class SchemaObject {
public final String name;
public final Type type;
private SQLStatement statement;
public long rowCount = -1;
public SchemaObject(String name, Type type) {
this(name, type, null);
}
public SchemaObject(String name, Type type, SQLStatement statement) {
this.name = name;
this.type = type;
this.statement = statement;
}
public static enum Type {
Sequence, Table, Index
}
public SQLStatement getStatement() {
return statement;
}
public SQLColumnDefinition findColumn(String columName) {
if (statement == null) {
return null;
}
if (statement instanceof SQLCreateTableStatement) {
return ((SQLCreateTableStatement) statement).findColumn(columName);
}
return null;
}
public boolean matchIndex(String columnName) {
if (statement == null) {
return false;
}
if (statement instanceof SQLCreateTableStatement) {
SQLTableElement index = ((SQLCreateTableStatement) statement).findIndex(columnName);
return index != null;
}
return false;
}
public boolean matchKey(String columnName) {
if (statement == null) {
return false;
}
if (statement instanceof SQLCreateTableStatement) {
SQLTableElement index = ((SQLCreateTableStatement) statement).findIndex(columnName);
return index instanceof SQLUniqueConstraint;
}
return false;
}
}
@@ -0,0 +1,137 @@
/*
* 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.repository;
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.statement.*;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
import com.alibaba.druid.util.JdbcUtils;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentSkipListMap;
/**
* Created by wenshao on 03/06/2017.
*/
public class SchemaRepository {
public Map<String, SchemaObject> objects = new ConcurrentSkipListMap<String, SchemaObject>();
public final SchemaVisitor visitor = new SchemaVisitor();
public SchemaObject findTable(String tableName) {
String lowerName = tableName.toLowerCase();
SchemaObject object = objects.get(lowerName);
if (object != null && object.type == SchemaObject.Type.Table) {
return object;
}
return null;
}
public void acceptDDL(String ddl, String dbType) {
List<SQLStatement> stmtList = SQLUtils.parseStatements(ddl, dbType);
for (SQLStatement stmt : stmtList) {
accept(stmt);
}
}
public void accept(SQLStatement stmt) {
stmt.accept(visitor);
}
public boolean isSequence(String name) {
SchemaObject object = objects.get(name);
return object != null
&& object.type == SchemaObject.Type.Sequence;
}
public class SchemaVisitor extends OracleASTVisitorAdapter {
public boolean visit(SQLDropSequenceStatement x) {
String name = x.getName().getSimpleName();
objects.remove(name);
return false;
}
public boolean visit(SQLCreateSequenceStatement x) {
String name = x.getName().getSimpleName();
SchemaObject object = new SchemaObject(name, SchemaObject.Type.Sequence);
objects.put(name.toLowerCase(), object);
return false;
}
public boolean visit(OracleCreateTableStatement x) {
visit((SQLCreateTableStatement) x);
return false;
}
public boolean visit(SQLCreateTableStatement x) {
String name = x.computeName();
SchemaObject object = new SchemaObject(name, SchemaObject.Type.Table, x);
objects.put(name.toLowerCase(), object);
return false;
}
public boolean visit(SQLCreateIndexStatement x) {
String name = x.getName().getSimpleName();
SchemaObject object = new SchemaObject(name, SchemaObject.Type.Index);
objects.put(name.toLowerCase(), object);
return false;
}
}
public SchemaObject findTable(SQLTableSource tableSource, String alias) {
if (tableSource instanceof SQLExprTableSource) {
if (alias.equalsIgnoreCase(tableSource.computeAlias())) {
SQLExpr expr = ((SQLExprTableSource) tableSource).getExpr();
if (expr instanceof SQLIdentifierExpr) {
String tableName = ((SQLIdentifierExpr) expr).getName();
SchemaObject tableObject = findTable(tableName);
return tableObject;
}
}
return null;
}
if (tableSource instanceof SQLJoinTableSource) {
SQLJoinTableSource join = (SQLJoinTableSource) tableSource;
SQLTableSource left = join.getLeft();
SchemaObject tableObject = findTable(left, alias);
if (tableObject != null) {
return tableObject;
}
SQLTableSource right = join.getRight();
tableObject = findTable(right, alias);
return tableObject;
}
return null;
}
}
@@ -924,6 +924,17 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
}
}
if (param instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) param;
SQLBinaryOperator op = binaryOpExpr.getOperator();
if (op == SQLBinaryOperator.BooleanAnd || op == SQLBinaryOperator.BooleanOr) {
incrementIndent();
param.accept(this);
decrementIndent();
continue;
}
}
param.accept(this);
}