diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index d7ac1c80e7..66a583f6d0 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -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 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; diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLReplaceable.java b/src/main/java/com/alibaba/druid/sql/ast/SQLReplaceable.java new file mode 100644 index 0000000000..1b9b236963 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLReplaceable.java @@ -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); +} diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java index ecc0a2fdea..947daf2785 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java @@ -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 groupListA = new ArrayList(); + List groupListB = new ArrayList(); + 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; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java index 11cc17da80..24d5434c59 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java @@ -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 items = new ArrayList(); @@ -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 diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLMethodInvokeExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLMethodInvokeExpr.java index 3ab91ff154..d85cc54dd9 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLMethodInvokeExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLMethodInvokeExpr.java @@ -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; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAssignItem.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAssignItem.java index 93f908da51..95d632acc9 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAssignItem.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAssignItem.java @@ -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; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java index c551cd119a..1cd6f4b081 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java @@ -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 keyColumns = null; if (element instanceof SQLUniqueConstraint) { diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java index 7686dde547..e53445c923 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java @@ -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; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java index c1960de721..cfa9b4460a 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java @@ -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"), // diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java index 576596457d..7db00d3c22 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java @@ -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; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java index dacf07538a..448d644195 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java @@ -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; diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java index d306e0bca0..851fa06fd8 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java @@ -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 selectList = new ArrayList(); @@ -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; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUpdateStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUpdateStatement.java index ad6d8eb236..96bf774ef8 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUpdateStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUpdateStatement.java @@ -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 items = new ArrayList(); 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; + } } diff --git a/src/main/java/com/alibaba/druid/sql/repository/SchemaObject.java b/src/main/java/com/alibaba/druid/sql/repository/SchemaObject.java new file mode 100644 index 0000000000..0ac0cff183 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/repository/SchemaObject.java @@ -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; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java b/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java new file mode 100644 index 0000000000..1df1b468fa --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java @@ -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 objects = new ConcurrentSkipListMap(); + + 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 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; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index 625b61df99..a6f7e7b3a2 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -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); }