mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
SchemaStatVisitor support relationship
This commit is contained in:
@@ -27,7 +27,6 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUnionOperator;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.CycleClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.AsOfFlashbackQueryClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.clause.FlashbackQueryClause.VersionsFlashbackQueryClause;
|
||||
|
||||
+49
-28
@@ -74,7 +74,6 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetValueClause;
|
||||
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateStatement;
|
||||
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
|
||||
import com.alibaba.druid.stat.TableStat;
|
||||
import com.alibaba.druid.stat.TableStat.Column;
|
||||
import com.alibaba.druid.stat.TableStat.Mode;
|
||||
|
||||
public class OracleSchemaStatVisitor extends SchemaStatVisitor implements OracleASTVisitor {
|
||||
@@ -110,6 +109,9 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
case Select:
|
||||
stat.incrementSelectCount();
|
||||
break;
|
||||
case Merge:
|
||||
stat.incrementMergeCount();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -216,22 +218,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.getOwner() instanceof SQLIdentifierExpr) {
|
||||
String owner = ((SQLIdentifierExpr) x.getOwner()).getName();
|
||||
|
||||
if (owner != null) {
|
||||
Map<String, String> aliasMap = aliasLocal.get();
|
||||
if (aliasMap != null) {
|
||||
String table = aliasMap.get(owner);
|
||||
|
||||
// table == null时是SubQuery
|
||||
if (table != null) {
|
||||
columns.add(new Column(table, x.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return super.visit(x);
|
||||
}
|
||||
|
||||
public boolean visit(SQLIdentifierExpr x) {
|
||||
@@ -247,12 +234,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
return false;
|
||||
}
|
||||
|
||||
String currentTable = currentTableLocal.get();
|
||||
|
||||
if (currentTable != null) {
|
||||
columns.add(new Column(currentTable, x.getName()));
|
||||
}
|
||||
return false;
|
||||
return super.visit(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -826,12 +808,50 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
|
||||
@Override
|
||||
public boolean visit(OracleMergeStatement x) {
|
||||
return true;
|
||||
aliasLocal.set(new HashMap<String, String>());
|
||||
|
||||
x.putAttribute("_original_use_mode", modeLocal.get());
|
||||
modeLocal.set(Mode.Merge);
|
||||
|
||||
String originalTable = currentTableLocal.get();
|
||||
|
||||
x.getUsing().accept(this);
|
||||
|
||||
String ident = x.getInto().toString();
|
||||
currentTableLocal.set(ident);
|
||||
x.putAttribute("_old_local_", originalTable);
|
||||
|
||||
TableStat stat = tableStats.get(ident);
|
||||
if (stat == null) {
|
||||
stat = new TableStat();
|
||||
tableStats.put(new TableStat.Name(ident), stat);
|
||||
}
|
||||
stat.incrementMergeCount();
|
||||
|
||||
Map<String, String> aliasMap = aliasLocal.get();
|
||||
if (aliasMap != null) {
|
||||
if (x.getAlias() != null) {
|
||||
aliasMap.put(x.getAlias(), ident);
|
||||
}
|
||||
aliasMap.put(ident, ident);
|
||||
}
|
||||
|
||||
x.getOn().accept(this);
|
||||
|
||||
if (x.getUpdateClause() != null) {
|
||||
x.getUpdateClause().accept(this);
|
||||
}
|
||||
|
||||
if (x.getInsertClause() != null) {
|
||||
x.getInsertClause().accept(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisit(OracleMergeStatement x) {
|
||||
|
||||
aliasLocal.set(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -841,7 +861,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
|
||||
@Override
|
||||
public void endVisit(MergeUpdateClause x) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -851,7 +871,7 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
|
||||
@Override
|
||||
public void endVisit(MergeInsertClause x) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -861,7 +881,8 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
|
||||
|
||||
@Override
|
||||
public void endVisit(ErrorLoggingClause x) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelect;
|
||||
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.SQLSubqueryTableSource;
|
||||
@@ -37,15 +38,18 @@ import com.alibaba.druid.stat.TableStat;
|
||||
import com.alibaba.druid.stat.TableStat.Column;
|
||||
import com.alibaba.druid.stat.TableStat.Condition;
|
||||
import com.alibaba.druid.stat.TableStat.Mode;
|
||||
import com.alibaba.druid.stat.TableStat.Relationship;
|
||||
|
||||
public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
|
||||
protected final HashMap<TableStat.Name, TableStat> tableStats = new LinkedHashMap<TableStat.Name, TableStat>();
|
||||
protected final Set<Column> columns = new LinkedHashSet<Column>();
|
||||
protected final Set<Condition> conditions = new LinkedHashSet<Condition>();
|
||||
protected final Set<Relationship> relationships = new LinkedHashSet<Relationship>();
|
||||
protected final Set<Column> orderByColumns = new LinkedHashSet<Column>();
|
||||
protected final Set<Column> groupByColumns = new LinkedHashSet<Column>();
|
||||
|
||||
private final Map<String, SQLSelectQuery> subQueryMap = new LinkedHashMap<String, SQLSelectQuery>();
|
||||
protected final static ThreadLocal<Map<String, String>> aliasLocal = new ThreadLocal<Map<String, String>>();
|
||||
protected final static ThreadLocal<String> currentTableLocal = new ThreadLocal<String>();
|
||||
protected final static ThreadLocal<Mode> modeLocal = new ThreadLocal<Mode>();
|
||||
@@ -114,6 +118,10 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Set<Relationship> getRelationships() {
|
||||
return relationships;
|
||||
}
|
||||
|
||||
public Set<Column> getOrderByColumns() {
|
||||
return orderByColumns;
|
||||
}
|
||||
@@ -141,6 +149,8 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
case IsNot:
|
||||
handleCondition(x.getLeft(), x.getOperator().name);
|
||||
handleCondition(x.getRight(), x.getOperator().name);
|
||||
|
||||
handleRelationship(x.getLeft(), x.getOperator().name, x.getRight());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -148,10 +158,41 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void handleRelationship(SQLExpr left, String operator, SQLExpr right) {
|
||||
Column leftColumn = getColumn(left);
|
||||
if (leftColumn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Column rightColumn = getColumn(right);
|
||||
if (rightColumn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Relationship relationship = new Relationship();
|
||||
relationship.setLeft(leftColumn);
|
||||
relationship.setRight(rightColumn);
|
||||
relationship.setOperator(operator);
|
||||
|
||||
this.relationships.add(relationship);
|
||||
}
|
||||
|
||||
protected void handleCondition(SQLExpr expr, String operator) {
|
||||
Column column = getColumn(expr);
|
||||
if (column == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Condition condition = new Condition();
|
||||
condition.setColumn(column);
|
||||
condition.setOperator(operator);
|
||||
this.conditions.add(condition);
|
||||
}
|
||||
|
||||
protected Column getColumn(SQLExpr expr) {
|
||||
Map<String, String> aliasMap = aliasLocal.get();
|
||||
if (aliasMap == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expr instanceof SQLPropertyExpr) {
|
||||
@@ -159,20 +200,20 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
String column = ((SQLPropertyExpr) expr).getName();
|
||||
|
||||
if (owner instanceof SQLIdentifierExpr) {
|
||||
String table = ((SQLIdentifierExpr) owner).getName();
|
||||
String tableName = ((SQLIdentifierExpr) owner).getName();
|
||||
String table = tableName;
|
||||
if (aliasMap.containsKey(table)) {
|
||||
table = aliasMap.get(table);
|
||||
}
|
||||
|
||||
if (table != null) {
|
||||
Condition condition = new Condition();
|
||||
condition.setColumn(new Column(table, column));
|
||||
condition.setOperator(operator);
|
||||
this.conditions.add(condition);
|
||||
return new Column(table, column);
|
||||
}
|
||||
|
||||
return handleSubQueryColumn(tableName, column);
|
||||
}
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expr instanceof SQLIdentifierExpr) {
|
||||
@@ -185,12 +226,11 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
}
|
||||
|
||||
if (table != null) {
|
||||
Condition condition = new Condition();
|
||||
condition.setColumn(new Column(table, column));
|
||||
condition.setOperator(operator);
|
||||
this.conditions.add(condition);
|
||||
return new Column(table, column);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -357,7 +397,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
|
||||
// table == null时是SubQuery
|
||||
if (table != null) {
|
||||
columns.add(new Column(table, x.getName()));
|
||||
Column column = new Column(table, x.getName());
|
||||
columns.add(column);
|
||||
x.putAttribute("_column_", column);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,11 +407,48 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Column handleSubQueryColumn(String owner, String alias) {
|
||||
SQLSelectQuery query = subQueryMap.get(owner);
|
||||
|
||||
if (query == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<SQLSelectItem> selectList = null;
|
||||
if (query instanceof SQLSelectQueryBlock) {
|
||||
selectList = ((SQLSelectQueryBlock) query).getSelectList();
|
||||
}
|
||||
|
||||
if (selectList != null) {
|
||||
for (SQLSelectItem item : selectList) {
|
||||
String itemAlias = item.getAlias();
|
||||
SQLExpr itemExpr = item.getExpr();
|
||||
if (itemAlias == null) {
|
||||
if (itemExpr instanceof SQLIdentifierExpr) {
|
||||
itemAlias = itemExpr.toString();
|
||||
} else if (itemExpr instanceof SQLPropertyExpr) {
|
||||
itemAlias = ((SQLPropertyExpr) itemExpr).getName();
|
||||
}
|
||||
}
|
||||
|
||||
if (alias.equalsIgnoreCase(itemAlias)) {
|
||||
Column column = (Column) itemExpr.getAttribute("_column_");
|
||||
return column;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean visit(SQLIdentifierExpr x) {
|
||||
String currentTable = currentTableLocal.get();
|
||||
|
||||
if (currentTable != null) {
|
||||
columns.add(new Column(currentTable, x.getName()));
|
||||
Column column = new Column(currentTable, x.getName());
|
||||
columns.add(column);
|
||||
x.putAttribute("_column_", column);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -405,13 +484,18 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
}
|
||||
|
||||
public boolean visit(SQLSubqueryTableSource x) {
|
||||
x.getSelect().accept(this);
|
||||
|
||||
SQLSelectQuery query = x.getSelect().getQuery();
|
||||
|
||||
Map<String, String> aliasMap = aliasLocal.get();
|
||||
if (aliasMap != null) {
|
||||
if (x.getAlias() != null) {
|
||||
aliasMap.put(x.getAlias(), null);
|
||||
subQueryMap.put(x.getAlias(), query);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isSimpleExprTableSource(SQLExprTableSource x) {
|
||||
@@ -448,6 +532,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
case Select:
|
||||
stat.incrementSelectCount();
|
||||
break;
|
||||
case Merge:
|
||||
stat.incrementMergeCount();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -465,6 +552,11 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelectItem x) {
|
||||
x.getExpr().setParent(x);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean visit(SQLSelect x) {
|
||||
if (x.getOrderBy() != null) {
|
||||
x.getOrderBy().setParent(x);
|
||||
|
||||
@@ -22,6 +22,15 @@ public class TableStat {
|
||||
int deleteCount = 0;
|
||||
int insertCount = 0;
|
||||
int dropCount = 0;
|
||||
int mergeCount = 0;
|
||||
|
||||
public int getMergeCount() {
|
||||
return mergeCount;
|
||||
}
|
||||
|
||||
public void incrementMergeCount() {
|
||||
this.mergeCount++;
|
||||
}
|
||||
|
||||
public int getDropCount() {
|
||||
return dropCount;
|
||||
@@ -85,6 +94,9 @@ public class TableStat {
|
||||
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(4);
|
||||
if (mergeCount > 0) {
|
||||
buf.append("Merge");
|
||||
}
|
||||
if (insertCount > 0) {
|
||||
buf.append("Insert");
|
||||
}
|
||||
@@ -135,6 +147,89 @@ public class TableStat {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Relationship {
|
||||
|
||||
private Column left;
|
||||
private Column right;
|
||||
private String operator;
|
||||
|
||||
public Column getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public void setLeft(Column left) {
|
||||
this.left = left;
|
||||
}
|
||||
|
||||
public Column getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public void setRight(Column right) {
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((left == null) ? 0 : left.hashCode());
|
||||
result = prime * result + ((operator == null) ? 0 : operator.hashCode());
|
||||
result = prime * result + ((right == null) ? 0 : right.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Relationship other = (Relationship) obj;
|
||||
if (left == null) {
|
||||
if (other.left != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!left.equals(other.left)) {
|
||||
return false;
|
||||
}
|
||||
if (operator == null) {
|
||||
if (other.operator != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!operator.equals(other.operator)) {
|
||||
return false;
|
||||
}
|
||||
if (right == null) {
|
||||
if (other.right != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!right.equals(other.right)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return left + " " + operator + " " + right;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Condition {
|
||||
|
||||
private Column column;
|
||||
@@ -272,7 +367,7 @@ public class TableStat {
|
||||
}
|
||||
|
||||
public static enum Mode {
|
||||
Insert(1), Update(2), Delete(4), Select(8);
|
||||
Insert(1), Update(2), Delete(4), Select(8), Merge(16);
|
||||
|
||||
public final int mark;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user