diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java index 91d3ea5f11..8a3082c4af 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java @@ -1,366 +1,413 @@ package com.alibaba.druid.sql.dialect.mysql.visitor; import java.util.HashMap; -import java.util.HashSet; -import java.util.List; import java.util.Map; -import java.util.Set; import com.alibaba.druid.sql.ast.SQLName; -import com.alibaba.druid.sql.ast.SQLObject; -import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; -import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; -import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; -import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; -import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; -import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; -import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; -import com.alibaba.druid.sql.ast.statement.SQLSelect; -import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; -import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; -import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; -import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlBinaryExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlBooleanExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExtractExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlIntervalExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlExecuteStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadDataInFileStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadXmlStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplicateStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRollbackStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectGroupBy; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowColumnsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowDatabasesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowStatusStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTablesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowWarningsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlStartTransactionStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlTableIndex; +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 MySqlSchemaStatVisitor extends MySqlASTVisitorAdapter { - - private HashMap tableStats = new HashMap(); - private Set fields = new HashSet(); - - private final static ThreadLocal> aliasLocal = new ThreadLocal>(); - private final static ThreadLocal currentTableLocal = new ThreadLocal(); - private final static ThreadLocal modeLocal = new ThreadLocal(); - - public boolean visit(SQLSubqueryTableSource x) { - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - if (x.getAlias() != null) { - aliasMap.put(x.getAlias(), null); - } - } - return true; - } - - public boolean visit(SQLExprTableSource x) { - if (x.getExpr() instanceof SQLIdentifierExpr || x.getExpr() instanceof SQLPropertyExpr) { - String ident = x.getExpr().toString(); - TableStat stat = tableStats.get(ident); - if (stat == null) { - stat = new TableStat(); - tableStats.put(new TableStat.Name(ident), stat); - } - - Mode mode = modeLocal.get(); - switch (mode) { - case Delete: - stat.incrementDeleteCount(); - break; - case Insert: - stat.incrementInsertCount(); - break; - case Update: - stat.incrementUpdateCount(); - break; - case Select: - stat.incrementSelectCount(); - break; - default: - break; - } - - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - if (x.getAlias() != null) { - aliasMap.put(x.getAlias(), ident); - } - aliasMap.put(ident, ident); - } - } else { - accept(x.getExpr()); - } - - return false; - } - - public boolean visit(SQLSelect x) { - accept(x.getQuery()); - - String originalTable = currentTableLocal.get(); - - currentTableLocal.set((String) x.getQuery().getAttribute("table")); - x.putAttribute("_old_local_", originalTable); - - accept(x.getOrderBy()); - - currentTableLocal.set(originalTable); - - return false; - } - - public boolean visit(SQLAggregateExpr x) { - accept(x.getArguments()); - return false; - } - - public boolean visit(SQLMethodInvokeExpr x) { - accept(x.getParameters()); - return false; - } - - public boolean visit(SQLUpdateStatement x) { - aliasLocal.set(new HashMap()); - - String ident = x.getTableName().toString(); - currentTableLocal.set(ident); - - TableStat stat = tableStats.get(ident); - if (stat == null) { - stat = new TableStat(); - tableStats.put(new TableStat.Name(ident), stat); - } - stat.incrementUpdateCount(); - - Map aliasMap = aliasLocal.get(); - aliasMap.put(ident, ident); - - accept(x.getItems()); - accept(x.getWhere()); - - return false; - } - - public void endVisit(SQLUpdateStatement x) { - aliasLocal.set(null); - } - - public boolean visit(MySqlDeleteStatement x) { - aliasLocal.set(new HashMap()); - - x.putAttribute("_original_use_mode", modeLocal.get()); - modeLocal.set(Mode.Delete); - - aliasLocal.set(new HashMap()); - - if (x.getTableNames().size() == 1) { - String ident = ((SQLIdentifierExpr) x.getTableNames().get(0)).getName(); - currentTableLocal.set(ident); - } - - for (SQLName tableName : x.getTableNames()) { - String ident = tableName.toString(); - TableStat stat = tableStats.get(ident); - if (stat == null) { - stat = new TableStat(); - tableStats.put(new TableStat.Name(ident), stat); - } - stat.incrementDeleteCount(); - } - - accept(x.getWhere()); - accept(x.getFrom()); - accept(x.getUsing()); - accept(x.getOrderBy()); - accept(x.getLimit()); - - return false; - } - - public void endVisit(MySqlDeleteStatement x) { - aliasLocal.set(null); - } - - public boolean visit(SQLSelectStatement x) { - aliasLocal.set(new HashMap()); - return true; - } - - public void endVisit(SQLSelectStatement x) { - aliasLocal.set(null); - } - - @Override - public void endVisit(MySqlInsertStatement x) { - Mode originalMode = (Mode) x.getAttribute("_original_use_mode"); - modeLocal.set(originalMode); - } - - @Override - public boolean visit(MySqlInsertStatement x) { - x.putAttribute("_original_use_mode", modeLocal.get()); - modeLocal.set(Mode.Insert); - - aliasLocal.set(new HashMap()); - - String originalTable = currentTableLocal.get(); - - if (x.getTableName() instanceof SQLIdentifierExpr) { - String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); - 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.incrementInsertCount(); - - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - if (x.getAlias() != null) { - aliasMap.put(x.getAlias(), ident); - } - aliasMap.put(ident, ident); - } - } - - accept(x.getColumns()); - accept(x.getValuesList()); - accept(x.getQuery()); - accept(x.getDuplicateKeyUpdate()); - - return false; - } - - @Override - public boolean visit(SQLInsertStatement x) { - x.putAttribute("_original_use_mode", modeLocal.get()); - modeLocal.set(Mode.Insert); - - aliasLocal.set(new HashMap()); - - String originalTable = currentTableLocal.get(); - - if (x.getTableName() instanceof SQLIdentifierExpr) { - String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); - 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.incrementInsertCount(); - - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - if (x.getAlias() != null) { - aliasMap.put(x.getAlias(), ident); - } - aliasMap.put(ident, ident); - } - } - - accept(x.getColumns()); - accept(x.getQuery()); - - return false; - } - - protected void accept(SQLObject x) { - if (x != null) { - x.accept(this); - } - } - - protected void accept(List nodes) { - for (int i = 0, size = nodes.size(); i < size; ++i) { - accept(nodes.get(i)); - } - } - - public boolean visit(SQLSelectQueryBlock x) { - - if (x.getFrom() instanceof SQLSubqueryTableSource) { - x.getFrom().accept(this); - return false; - } - - x.putAttribute("_original_use_mode", modeLocal.get()); - modeLocal.set(Mode.Select); - - String originalTable = currentTableLocal.get(); - - if (x.getFrom() instanceof SQLExprTableSource) { - SQLExprTableSource tableSource = (SQLExprTableSource) x.getFrom(); - if (tableSource.getExpr() instanceof SQLIdentifierExpr) { - String ident = ((SQLIdentifierExpr) tableSource.getExpr()).getName(); - currentTableLocal.set(ident); - x.putAttribute("_old_local_", originalTable); - } - } - - x.getFrom().accept(this); // 提前执行,获得aliasMap - - return true; - } - - public void endVisit(SQLSelectQueryBlock x) { - String originalTable = (String) x.getAttribute("_old_local_"); - x.putAttribute("table", currentTableLocal.get()); - currentTableLocal.set(originalTable); - - Mode originalMode = (Mode) x.getAttribute("_original_use_mode"); - modeLocal.set(originalMode); - } - - public boolean visit(SQLJoinTableSource x) { - return true; - } - - public boolean visit(SQLPropertyExpr x) { - if (x.getOwner() instanceof SQLIdentifierExpr) { - String owner = ((SQLIdentifierExpr) x.getOwner()).getName(); - - if (owner != null) { - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - String table = aliasMap.get(owner); - - // table == null时是SubQuery - if (table != null) { - fields.add(new Column(table, x.getName())); - } - } - } - } - return false; - } - - public boolean visit(SQLIdentifierExpr x) { - String currentTable = currentTableLocal.get(); - - if (currentTable != null) { - fields.add(new Column(currentTable, x.getName())); - } - return false; - } - - public boolean visit(SQLAllColumnExpr x) { - String currentTable = currentTableLocal.get(); - - if (currentTable != null) { - fields.add(new Column(currentTable, "*")); - } - return false; - } - - public Map getTables() { - return tableStats; - } - - public boolean containsTable(String tableName) { - return tableStats.containsKey(new TableStat.Name(tableName)); - } - - public Set getFields() { - return fields; - } +public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements + MySqlASTVisitor { + + public boolean visit(MySqlDeleteStatement x) { + aliasLocal.set(new HashMap()); + + x.putAttribute("_original_use_mode", modeLocal.get()); + modeLocal.set(Mode.Delete); + + aliasLocal.set(new HashMap()); + + if (x.getTableNames().size() == 1) { + String ident = ((SQLIdentifierExpr) x.getTableNames().get(0)) + .getName(); + currentTableLocal.set(ident); + } + + for (SQLName tableName : x.getTableNames()) { + String ident = tableName.toString(); + TableStat stat = tableStats.get(ident); + if (stat == null) { + stat = new TableStat(); + tableStats.put(new TableStat.Name(ident), stat); + } + stat.incrementDeleteCount(); + } + + accept(x.getWhere()); + accept(x.getFrom()); + accept(x.getUsing()); + accept(x.getOrderBy()); + accept(x.getLimit()); + + return false; + } + + public void endVisit(MySqlDeleteStatement x) { + aliasLocal.set(null); + } + + @Override + public void endVisit(MySqlInsertStatement x) { + Mode originalMode = (Mode) x.getAttribute("_original_use_mode"); + modeLocal.set(originalMode); + } + + @Override + public boolean visit(MySqlInsertStatement x) { + x.putAttribute("_original_use_mode", modeLocal.get()); + modeLocal.set(Mode.Insert); + + aliasLocal.set(new HashMap()); + + String originalTable = currentTableLocal.get(); + + if (x.getTableName() instanceof SQLIdentifierExpr) { + String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); + 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.incrementInsertCount(); + + Map aliasMap = aliasLocal.get(); + if (aliasMap != null) { + if (x.getAlias() != null) { + aliasMap.put(x.getAlias(), ident); + } + aliasMap.put(ident, ident); + } + } + + accept(x.getColumns()); + accept(x.getValuesList()); + accept(x.getQuery()); + accept(x.getDuplicateKeyUpdate()); + + return false; + } + + @Override + public boolean visit(MySqlBooleanExpr x) { + + return true; + } + + @Override + public void endVisit(MySqlBooleanExpr x) { + + } + + @Override + public boolean visit(Limit x) { + + return true; + } + + @Override + public void endVisit(Limit x) { + + } + + @Override + public boolean visit(MySqlTableIndex x) { + + return true; + } + + @Override + public void endVisit(MySqlTableIndex x) { + + } + + @Override + public boolean visit(MySqlKey x) { + + return true; + } + + @Override + public void endVisit(MySqlKey x) { + + } + + @Override + public boolean visit(MySqlPrimaryKey x) { + + return true; + } + + @Override + public void endVisit(MySqlPrimaryKey x) { + + } + + @Override + public void endVisit(MySqlIntervalExpr x) { + + } + + @Override + public boolean visit(MySqlIntervalExpr x) { + + return true; + } + + @Override + public void endVisit(MySqlExtractExpr x) { + + } + + @Override + public boolean visit(MySqlExtractExpr x) { + + return true; + } + + @Override + public void endVisit(MySqlMatchAgainstExpr x) { + + } + + @Override + public boolean visit(MySqlMatchAgainstExpr x) { + + return true; + } + + @Override + public void endVisit(MySqlBinaryExpr x) { + + } + + @Override + public boolean visit(MySqlBinaryExpr x) { + + return true; + } + + @Override + public void endVisit(MySqlPrepareStatement x) { + + } + + @Override + public boolean visit(MySqlPrepareStatement x) { + + return true; + } + + @Override + public void endVisit(MySqlExecuteStatement x) { + + } + + @Override + public boolean visit(MySqlExecuteStatement x) { + + return true; + } + + @Override + public void endVisit(MySqlLoadDataInFileStatement x) { + + } + + @Override + public boolean visit(MySqlLoadDataInFileStatement x) { + + return true; + } + + @Override + public void endVisit(MySqlLoadXmlStatement x) { + + } + + @Override + public boolean visit(MySqlLoadXmlStatement x) { + + return true; + } + + @Override + public void endVisit(MySqlReplicateStatement x) { + + } + + @Override + public boolean visit(MySqlReplicateStatement x) { + + return true; + } + + @Override + public void endVisit(MySqlSelectGroupBy x) { + + } + + @Override + public boolean visit(MySqlSelectGroupBy x) { + + return true; + } + + @Override + public void endVisit(MySqlStartTransactionStatement x) { + + } + + @Override + public boolean visit(MySqlStartTransactionStatement x) { + + return true; + } + + @Override + public void endVisit(MySqlCommitStatement x) { + + } + + @Override + public boolean visit(MySqlCommitStatement x) { + + return true; + } + + @Override + public void endVisit(MySqlRollbackStatement x) { + + } + + @Override + public boolean visit(MySqlRollbackStatement x) { + + return true; + } + + @Override + public void endVisit(MySqlShowColumnsStatement x) { + + } + + @Override + public boolean visit(MySqlShowColumnsStatement x) { + return true; + } + + @Override + public void endVisit(MySqlShowTablesStatement x) { + + } + + @Override + public boolean visit(MySqlShowTablesStatement x) { + return true; + } + + @Override + public void endVisit(MySqlShowDatabasesStatement x) { + + } + + @Override + public boolean visit(MySqlShowDatabasesStatement x) { + return true; + } + + @Override + public void endVisit(MySqlShowWarningsStatement x) { + + } + + @Override + public boolean visit(MySqlShowWarningsStatement x) { + return true; + } + + @Override + public void endVisit(MySqlShowStatusStatement x) { + + } + + @Override + public boolean visit(MySqlShowStatusStatement x) { + return true; + } + + @Override + public void endVisit(CobarShowStatus x) { + + } + + @Override + public boolean visit(CobarShowStatus x) { + return true; + } + + @Override + public void endVisit(MySqlKillStatement x) { + + } + + @Override + public boolean visit(MySqlKillStatement x) { + return true; + } + + @Override + public void endVisit(MySqlBinlogStatement x) { + + } + + @Override + public boolean visit(MySqlBinlogStatement x) { + return true; + } + + @Override + public void endVisit(MySqlResetStatement x) { + + } + + @Override + public boolean visit(MySqlResetStatement x) { + return true; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java index 8cbd310b5e..f025427a54 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleSchemaStatVisitor.java @@ -1,458 +1,803 @@ package com.alibaba.druid.sql.dialect.oracle.visitor; import java.util.HashMap; -import java.util.HashSet; -import java.util.List; import java.util.Map; -import java.util.Set; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; -import com.alibaba.druid.sql.ast.SQLObject; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; -import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; -import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; +import com.alibaba.druid.sql.ast.expr.SQLObjectCreateExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; -import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; -import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; -import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; -import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; -import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; -import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.OracleHint; +import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy; +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; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.GroupingSetExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.CellAssignment; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.CellAssignmentItem; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.MainModelClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.ModelColumn; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.ModelColumnClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.ModelRulesClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.QueryPartitionClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.ReturnRowsClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.PartitionExtensionClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.SampleClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.SearchClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.SubqueryFactoringClause; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.SubqueryFactoringClause.Entry; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalytic; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalyticWindowing; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleBinaryDoubleExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleBinaryFloatExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleCursorExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleDateExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleDbLinkExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleExtractExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleIntervalExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleIsSetExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleOuterExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleTimestampExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleDeleteStatement; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OraclePLSQLCommitStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelect; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectForUpdate; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectHierachicalQueryClause; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectJoin; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectPivot; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectPivot.Item; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectRestriction.CheckOption; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectRestriction.ReadOnly; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectSubqueryTableSource; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectUnPivot; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleTableExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetListClause; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetListMultiColumnItem; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateSetListSingleColumnItem; +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; -import com.alibaba.druid.stat.TableStat.Name; - -public class OracleSchemaStatVisitor extends OracleASTVIsitorAdapter { - - private HashMap tableStats = new HashMap(); - private Set fields = new HashSet(); - - private final static ThreadLocal> aliasLocal = new ThreadLocal>(); - private final static ThreadLocal currentTableLocal = new ThreadLocal(); - private final static ThreadLocal modeLocal = new ThreadLocal(); - - public boolean visit(SQLSubqueryTableSource x) { - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - if (x.getAlias() != null) { - aliasMap.put(x.getAlias(), null); - } - } - return true; - } - - public boolean visit(SQLExprTableSource x) { - if (x.getExpr() instanceof SQLIdentifierExpr || x.getExpr() instanceof SQLPropertyExpr) { - String ident = x.getExpr().toString(); - TableStat stat = tableStats.get(ident); - if (stat == null) { - stat = new TableStat(); - tableStats.put(new TableStat.Name(ident), stat); - } - - Mode mode = modeLocal.get(); - switch (mode) { - case Delete: - stat.incrementDeleteCount(); - break; - case Insert: - stat.incrementInsertCount(); - break; - case Update: - stat.incrementUpdateCount(); - break; - case Select: - stat.incrementSelectCount(); - break; - default: - break; - } - - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - if (x.getAlias() != null) { - aliasMap.put(x.getAlias(), ident); - } - aliasMap.put(ident, ident); - } - } else { - accept(x.getExpr()); - } - - return false; - } - - public boolean visit(OracleSelectTableReference x) { - SQLExpr expr = x.getExpr(); - if (expr instanceof SQLName) { - String ident = ((SQLName) expr).toString(); - TableStat stat = tableStats.get(ident); - if (stat == null) { - stat = new TableStat(); - tableStats.put(new TableStat.Name(ident), stat); - } - - Mode mode = modeLocal.get(); - switch (mode) { - case Delete: - stat.incrementDeleteCount(); - break; - case Insert: - stat.incrementInsertCount(); - break; - case Update: - stat.incrementUpdateCount(); - break; - case Select: - stat.incrementSelectCount(); - break; - default: - break; - } - - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - if (x.getAlias() != null) { - aliasMap.put(x.getAlias(), ident); - } - aliasMap.put(ident, ident); - } - return false; - } - - accept(x.getExpr()); - - return false; - } - - public boolean visit(SQLAggregateExpr x) { - accept(x.getArguments()); - return false; - } - - public boolean visit(OracleAggregateExpr x) { - accept(x.getArguments()); - accept(x.getOver()); - return false; - } - - public boolean visit(SQLMethodInvokeExpr x) { - accept(x.getParameters()); - return false; - } - - public boolean visit(SQLSelect x) { - accept(x.getQuery()); - - String originalTable = currentTableLocal.get(); - - currentTableLocal.set((String) x.getQuery().getAttribute("table")); - x.putAttribute("_old_local_", originalTable); - - accept(x.getOrderBy()); - - currentTableLocal.set(originalTable); - - return false; - } - - public void endVisit(OracleSelect x) { - } - - public boolean visit(OracleSelect x) { - accept(x.getFactoring()); - accept(x.getQuery()); - - String originalTable = currentTableLocal.get(); - - currentTableLocal.set((String) x.getQuery().getAttribute("table")); - x.putAttribute("_old_local_", originalTable); - - accept(x.getOrderBy()); - - currentTableLocal.set(originalTable); - - return false; - } - - public void endVisit(SQLSelect x) { - } - public boolean visit(SQLUpdateStatement x) { - aliasLocal.set(new HashMap()); - - String ident = x.getTableName().toString(); - currentTableLocal.set(ident); - - TableStat stat = tableStats.get(ident); - if (stat == null) { - stat = new TableStat(); - tableStats.put(new TableStat.Name(ident), stat); - } - stat.incrementUpdateCount(); +public class OracleSchemaStatVisitor extends SchemaStatVisitor implements + OracleASTVisitor { + + public boolean visit(OracleSelectTableReference x) { + SQLExpr expr = x.getExpr(); + if (expr instanceof SQLName) { + String ident = ((SQLName) expr).toString(); + TableStat stat = tableStats.get(ident); + if (stat == null) { + stat = new TableStat(); + tableStats.put(new TableStat.Name(ident), stat); + } + + Mode mode = modeLocal.get(); + switch (mode) { + case Delete: + stat.incrementDeleteCount(); + break; + case Insert: + stat.incrementInsertCount(); + break; + case Update: + stat.incrementUpdateCount(); + break; + case Select: + stat.incrementSelectCount(); + break; + default: + break; + } + + Map aliasMap = aliasLocal.get(); + if (aliasMap != null) { + if (x.getAlias() != null) { + aliasMap.put(x.getAlias(), ident); + } + aliasMap.put(ident, ident); + } + return false; + } + + accept(x.getExpr()); + + return false; + } + + public boolean visit(SQLAggregateExpr x) { + accept(x.getArguments()); + return false; + } + + public boolean visit(OracleAggregateExpr x) { + accept(x.getArguments()); + accept(x.getOver()); + return false; + } + + public void endVisit(OracleSelect x) { + } + + public boolean visit(OracleSelect x) { + accept(x.getFactoring()); + accept(x.getQuery()); + + String originalTable = currentTableLocal.get(); + + currentTableLocal.set((String) x.getQuery().getAttribute("table")); + x.putAttribute("_old_local_", originalTable); + + accept(x.getOrderBy()); + + currentTableLocal.set(originalTable); + + return false; + } + + public void endVisit(SQLSelect x) { + } + + public boolean visit(OracleUpdateStatement x) { + aliasLocal.set(new HashMap()); + + if (x.getTable() instanceof SQLIdentifierExpr) { + String ident = x.getTable().toString(); + currentTableLocal.set(ident); + + TableStat stat = tableStats.get(ident); + if (stat == null) { + stat = new TableStat(); + tableStats.put(new TableStat.Name(ident), stat); + } + stat.incrementUpdateCount(); + + Map aliasMap = aliasLocal.get(); + aliasMap.put(ident, ident); + } else { + accept(x.getTable()); + } + + accept(x.getSetClause()); + accept(x.getWhere()); + + return false; + } + + public void endVisit(OracleUpdateStatement x) { + aliasLocal.set(null); + } - Map aliasMap = aliasLocal.get(); - aliasMap.put(ident, ident); + public boolean visit(OracleDeleteStatement x) { + return visit((SQLDeleteStatement) x); + } - accept(x.getItems()); - accept(x.getWhere()); + public void endVisit(OracleDeleteStatement x) { + aliasLocal.set(null); + } - return false; - } + public boolean visit(OracleSelectQueryBlock x) { + return visit((SQLSelectQueryBlock) x); + } - public void endVisit(SQLUpdateStatement x) { - aliasLocal.set(null); - } + public void endVisit(OracleSelectQueryBlock x) { + endVisit((SQLSelectQueryBlock) x); + } - public boolean visit(OracleUpdateStatement x) { - aliasLocal.set(new HashMap()); + public boolean visit(SQLPropertyExpr x) { + if ("ROWNUM".equalsIgnoreCase(x.getName())) { + return false; + } - if (x.getTable() instanceof SQLIdentifierExpr) { - String ident = x.getTable().toString(); - currentTableLocal.set(ident); + if (x.getOwner() instanceof SQLIdentifierExpr) { + String owner = ((SQLIdentifierExpr) x.getOwner()).getName(); - TableStat stat = tableStats.get(ident); - if (stat == null) { - stat = new TableStat(); - tableStats.put(new TableStat.Name(ident), stat); - } - stat.incrementUpdateCount(); + if (owner != null) { + Map aliasMap = aliasLocal.get(); + if (aliasMap != null) { + String table = aliasMap.get(owner); - Map aliasMap = aliasLocal.get(); - aliasMap.put(ident, ident); - } else { - accept(x.getTable()); - } + // table == null时是SubQuery + if (table != null) { + fields.add(new Column(table, x.getName())); + } + } + } + } + return false; + } - accept(x.getSetClause()); - accept(x.getWhere()); + public boolean visit(SQLIdentifierExpr x) { + if ("ROWNUM".equalsIgnoreCase(x.getName())) { + return false; + } - return false; - } + if ("SYSDATE".equalsIgnoreCase(x.getName())) { + return false; + } - public void endVisit(OracleUpdateStatement x) { - aliasLocal.set(null); - } + if ("+".equalsIgnoreCase(x.getName())) { + return false; + } - public boolean visit(OracleDeleteStatement x) { - return visit((SQLDeleteStatement) x); - } + String currentTable = currentTableLocal.get(); - public void endVisit(OracleDeleteStatement x) { - aliasLocal.set(null); - } + if (currentTable != null) { + fields.add(new Column(currentTable, x.getName())); + } + return false; + } - public boolean visit(SQLDeleteStatement x) { - aliasLocal.set(new HashMap()); + @Override + public void endVisit(OracleAggregateExpr astNode) { - x.putAttribute("_original_use_mode", modeLocal.get()); - modeLocal.set(Mode.Delete); + } - aliasLocal.set(new HashMap()); + @Override + public void endVisit(OracleConstraintState astNode) { - String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); - currentTableLocal.set(ident); + } - TableStat stat = tableStats.get(ident); - if (stat == null) { - stat = new TableStat(); - tableStats.put(new TableStat.Name(ident), stat); - } - stat.incrementDeleteCount(); + @Override + public void endVisit(OraclePLSQLCommitStatement astNode) { - accept(x.getWhere()); + } - return false; - } + @Override + public void endVisit(OracleAnalytic x) { - public void endVisit(SQLDeleteStatement x) { - aliasLocal.set(null); - } + } - public boolean visit(SQLSelectStatement x) { - aliasLocal.set(new HashMap()); - return true; - } + @Override + public void endVisit(OracleAnalyticWindowing x) { - public void endVisit(SQLSelectStatement x) { - aliasLocal.set(null); - } + } - public void endVisit(SQLInsertStatement x) { - Mode originalMode = (Mode) x.getAttribute("_original_use_mode"); - modeLocal.set(originalMode); - } - - public boolean visit(SQLInsertStatement x) { - x.putAttribute("_original_use_mode", modeLocal.get()); - modeLocal.set(Mode.Insert); - - aliasLocal.set(new HashMap()); - - String originalTable = currentTableLocal.get(); + @Override + public void endVisit(OracleDateExpr x) { - if (x.getTableName() instanceof SQLIdentifierExpr) { - String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); - 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.incrementInsertCount(); - - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - if (x.getAlias() != null) { - aliasMap.put(x.getAlias(), ident); - } - aliasMap.put(ident, ident); - } - } - - accept(x.getColumns()); - accept(x.getValues()); - accept(x.getQuery()); - - return false; - } - - protected void accept(SQLObject x) { - if (x != null) { - x.accept(this); - } - } - - protected void accept(List nodes) { - for (int i = 0, size = nodes.size(); i < size; ++i) { - accept(nodes.get(i)); - } - } - - public boolean visit(SQLSelectQueryBlock x) { - - if (x.getFrom() instanceof SQLSubqueryTableSource) { - x.getFrom().accept(this); - return false; - } - - x.putAttribute("_original_use_mode", modeLocal.get()); - modeLocal.set(Mode.Select); - - String originalTable = currentTableLocal.get(); - - if (x.getFrom() instanceof SQLExprTableSource) { - SQLExprTableSource tableSource = (SQLExprTableSource) x.getFrom(); - if (tableSource.getExpr() instanceof SQLName) { - String ident = ((SQLName) tableSource.getExpr()).toString(); - currentTableLocal.set(ident); - x.putAttribute("_old_local_", originalTable); - } - } - - x.getFrom().accept(this); // 提前执行,获得aliasMap - - return true; - } - - public void endVisit(SQLSelectQueryBlock x) { - String originalTable = (String) x.getAttribute("_old_local_"); - x.putAttribute("table", currentTableLocal.get()); - currentTableLocal.set(originalTable); - - Mode originalMode = (Mode) x.getAttribute("_original_use_mode"); - modeLocal.set(originalMode); - } - - public boolean visit(OracleSelectQueryBlock x) { - return visit((SQLSelectQueryBlock) x); - } - - public void endVisit(OracleSelectQueryBlock x) { - endVisit((SQLSelectQueryBlock) x); - } - - public boolean visit(SQLJoinTableSource x) { - return true; - } - - public boolean visit(SQLPropertyExpr x) { - if ("ROWNUM".equalsIgnoreCase(x.getName())) { - return false; - } - - if (x.getOwner() instanceof SQLIdentifierExpr) { - String owner = ((SQLIdentifierExpr) x.getOwner()).getName(); - - if (owner != null) { - Map aliasMap = aliasLocal.get(); - if (aliasMap != null) { - String table = aliasMap.get(owner); - - // table == null时是SubQuery - if (table != null) { - fields.add(new Column(table, x.getName())); - } - } - } - } - return false; - } - - public boolean visit(SQLIdentifierExpr x) { - if ("ROWNUM".equalsIgnoreCase(x.getName())) { - return false; - } - - if ("SYSDATE".equalsIgnoreCase(x.getName())) { - return false; - } - - if ("+".equalsIgnoreCase(x.getName())) { - return false; - } - - String currentTable = currentTableLocal.get(); - - if (currentTable != null) { - fields.add(new Column(currentTable, x.getName())); - } - return false; - } - - public boolean visit(SQLAllColumnExpr x) { - String currentTable = currentTableLocal.get(); - - if (currentTable != null) { - fields.add(new Column(currentTable, "*")); - } - return false; - } - - public Map getTables() { - return tableStats; - } - - public boolean containsTable(String tableName) { - return tableStats.containsKey(new TableStat.Name(tableName)); - } - - public Set getFields() { - return fields; - } + } + + @Override + public void endVisit(OracleDbLinkExpr x) { + + } + + @Override + public void endVisit(OracleExtractExpr x) { + + } + + @Override + public void endVisit(OracleHint x) { + + } + + @Override + public void endVisit(OracleIntervalExpr x) { + + } + + @Override + public void endVisit(SQLObjectCreateExpr x) { + + } + + @Override + public void endVisit(OracleOrderBy x) { + + } + + @Override + public void endVisit(OracleOuterExpr x) { + + } + + @Override + public void endVisit(OracleSelectForUpdate x) { + + } + + @Override + public void endVisit(OracleSelectHierachicalQueryClause x) { + + } + + @Override + public void endVisit(OracleSelectJoin x) { + + } + + @Override + public void endVisit(OracleOrderByItem x) { + + } + + @Override + public void endVisit(OracleSelectPivot x) { + + } + + @Override + public void endVisit(Item x) { + + } + + @Override + public void endVisit(CheckOption x) { + + } + + @Override + public void endVisit(ReadOnly x) { + + } + + @Override + public void endVisit(OracleSelectSubqueryTableSource x) { + + } + + @Override + public void endVisit(OracleSelectUnPivot x) { + + } + + @Override + public void endVisit(OracleTableExpr x) { + + } + + @Override + public void endVisit(OracleTimestampExpr x) { + + } + + @Override + public void endVisit(OracleUpdateSetListClause x) { + + } + + @Override + public void endVisit(OracleUpdateSetListMultiColumnItem x) { + + } + + @Override + public void endVisit(OracleUpdateSetListSingleColumnItem x) { + + } + + @Override + public void endVisit(OracleUpdateSetValueClause x) { + + } + + @Override + public boolean visit(OracleConstraintState astNode) { + + return true; + } + + @Override + public boolean visit(OraclePLSQLCommitStatement astNode) { + + return true; + } + + @Override + public boolean visit(OracleAnalytic x) { + + return true; + } + + @Override + public boolean visit(OracleAnalyticWindowing x) { + + return true; + } + + @Override + public boolean visit(OracleDateExpr x) { + + return true; + } + + @Override + public boolean visit(OracleDbLinkExpr x) { + + return true; + } + + @Override + public boolean visit(OracleExtractExpr x) { + + return true; + } + + @Override + public boolean visit(OracleHint x) { + + return true; + } + + @Override + public boolean visit(OracleIntervalExpr x) { + + return true; + } + + @Override + public boolean visit(SQLObjectCreateExpr x) { + + return true; + } + + @Override + public boolean visit(OracleOrderBy x) { + + return true; + } + + @Override + public boolean visit(OracleOuterExpr x) { + + return true; + } + + @Override + public boolean visit(OracleSelectForUpdate x) { + + return true; + } + + @Override + public boolean visit(OracleSelectHierachicalQueryClause x) { + + return true; + } + + @Override + public boolean visit(OracleSelectJoin x) { + + return true; + } + + @Override + public boolean visit(OracleOrderByItem x) { + + return true; + } + + @Override + public boolean visit(OracleSelectPivot x) { + + return true; + } + + @Override + public boolean visit(Item x) { + + return true; + } + + @Override + public boolean visit(CheckOption x) { + + return true; + } + + @Override + public boolean visit(ReadOnly x) { + + return true; + } + + @Override + public boolean visit(OracleSelectSubqueryTableSource x) { + + return true; + } + + @Override + public boolean visit(OracleSelectUnPivot x) { + + return true; + } + + @Override + public boolean visit(OracleTableExpr x) { + + return true; + } + + @Override + public boolean visit(OracleTimestampExpr x) { + + return true; + } + + @Override + public boolean visit(OracleUpdateSetListClause x) { + + return true; + } + + @Override + public boolean visit(OracleUpdateSetListMultiColumnItem x) { + + return true; + } + + @Override + public boolean visit(OracleUpdateSetListSingleColumnItem x) { + + return true; + } + + @Override + public boolean visit(OracleUpdateSetValueClause x) { + + return true; + } + + @Override + public boolean visit(SampleClause x) { + + return true; + } + + @Override + public void endVisit(SampleClause x) { + + } + + @Override + public void endVisit(OracleSelectTableReference x) { + + } + + @Override + public boolean visit(PartitionExtensionClause x) { + + return true; + } + + @Override + public void endVisit(PartitionExtensionClause x) { + + } + + @Override + public boolean visit(VersionsFlashbackQueryClause x) { + + return true; + } + + @Override + public void endVisit(VersionsFlashbackQueryClause x) { + + } + + @Override + public boolean visit(AsOfFlashbackQueryClause x) { + + return true; + } + + @Override + public void endVisit(AsOfFlashbackQueryClause x) { + + } + + @Override + public boolean visit(GroupingSetExpr x) { + + return true; + } + + @Override + public void endVisit(GroupingSetExpr x) { + + } + + @Override + public boolean visit(SubqueryFactoringClause x) { + + return true; + } + + @Override + public void endVisit(SubqueryFactoringClause x) { + + } + + @Override + public boolean visit(Entry x) { + + return true; + } + + @Override + public void endVisit(Entry x) { + + } + + @Override + public boolean visit(SearchClause x) { + + return true; + } + + @Override + public void endVisit(SearchClause x) { + + } + + @Override + public boolean visit(CycleClause x) { + + return true; + } + + @Override + public void endVisit(CycleClause x) { + + } + + @Override + public boolean visit(OracleBinaryFloatExpr x) { + + return true; + } + + @Override + public void endVisit(OracleBinaryFloatExpr x) { + + } + + @Override + public boolean visit(OracleBinaryDoubleExpr x) { + + return true; + } + + @Override + public void endVisit(OracleBinaryDoubleExpr x) { + + } + + @Override + public boolean visit(OracleCursorExpr x) { + + return true; + } + + @Override + public void endVisit(OracleCursorExpr x) { + + } + + @Override + public boolean visit(OracleIsSetExpr x) { + + return true; + } + + @Override + public void endVisit(OracleIsSetExpr x) { + + } + + @Override + public boolean visit(ReturnRowsClause x) { + + return true; + } + + @Override + public void endVisit(ReturnRowsClause x) { + + } + + @Override + public boolean visit(MainModelClause x) { + + return true; + } + + @Override + public void endVisit(MainModelClause x) { + + } + + @Override + public boolean visit(ModelColumnClause x) { + + return true; + } + + @Override + public void endVisit(ModelColumnClause x) { + + } + + @Override + public boolean visit(QueryPartitionClause x) { + + return true; + } + + @Override + public void endVisit(QueryPartitionClause x) { + + } + + @Override + public boolean visit(ModelColumn x) { + + return true; + } + + @Override + public void endVisit(ModelColumn x) { + + } + + @Override + public boolean visit(ModelRulesClause x) { + + return true; + } + + @Override + public void endVisit(ModelRulesClause x) { + + } + + @Override + public boolean visit(CellAssignmentItem x) { + + return true; + } + + @Override + public void endVisit(CellAssignmentItem x) { + + } + + @Override + public boolean visit(CellAssignment x) { + + return true; + } + + @Override + public void endVisit(CellAssignment x) { + + } + + @Override + public boolean visit(ModelClause x) { + return true; + } + + @Override + public void endVisit(ModelClause x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGSelectQueryBlock.java index abe32fd974..68617c7eed 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGSelectQueryBlock.java @@ -9,6 +9,8 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + public class PGSelectQueryBlock extends SQLSelectQueryBlock { private static final long serialVersionUID = 1L; @@ -17,8 +19,58 @@ public class PGSelectQueryBlock extends SQLSelectQueryBlock { private List distinctOn = new ArrayList(2); private SQLExpr limit; private SQLExpr offset; + private WindowClause window; private SQLOrderBy orderBy; + private FetchClause fetch; + private ForClause forClause; + + @Override + protected void accept0(SQLASTVisitor visitor) { + accept0((PGASTVisitor) visitor); + } + + protected void accept0(PGASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, this.with); + acceptChild(visitor, this.distinctOn); + acceptChild(visitor, this.selectList); + acceptChild(visitor, this.from); + acceptChild(visitor, this.where); + acceptChild(visitor, this.groupBy); + acceptChild(visitor, this.window); + acceptChild(visitor, this.orderBy); + acceptChild(visitor, this.limit); + acceptChild(visitor, this.offset); + acceptChild(visitor, this.fetch); + acceptChild(visitor, this.forClause); + } + visitor.endVisit(this); + } + + public FetchClause getFetch() { + return fetch; + } + + public void setFetch(FetchClause fetch) { + this.fetch = fetch; + } + + public ForClause getForClause() { + return forClause; + } + + public void setForClause(ForClause forClause) { + this.forClause = forClause; + } + + public WindowClause getWindow() { + return window; + } + + public void setWindow(WindowClause window) { + this.window = window; + } public WithClause getWith() { return with; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java index 1ee9d64803..fbe9b55cd4 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java @@ -95,6 +95,7 @@ public class PGLexer extends Lexer { map.put("SHARE", Token.SHARE); map.put("NOWAIT", Token.NOWAIT); map.put("RECURSIVE", Token.RECURSIVE); + map.put("WITH", Token.WITH); DEFAULT_MYSQL_KEYWORDS = new Keywords(map); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSQLStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSQLStatementParser.java index cbab81f3a0..af27f91ca8 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSQLStatementParser.java @@ -1,8 +1,12 @@ package com.alibaba.druid.sql.dialect.postgresql.parser; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLStatementParser; +import com.alibaba.druid.sql.parser.Token; public class PGSQLStatementParser extends SQLStatementParser { public PGSQLStatementParser(String sql) throws ParserException { @@ -17,4 +21,14 @@ public class PGSQLStatementParser extends SQLStatementParser { public PGSelectParser createSQLSelectParser() { return new PGSelectParser(this.lexer); } + + public boolean parseStatementListDialect(List statementList) { + if (lexer.token() == Token.WITH) { + SQLStatement stmt = parseSelect(); + statementList.add(stmt); + return true; + } + + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java index 9e32091f95..b6a32afa69 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java @@ -74,6 +74,8 @@ public class PGSelectParser extends SQLSelectParser { queryBlock.setDistionOption(SQLSetQuantifier.ALL); lexer.nextToken(); } + + parseSelectList(queryBlock); parseFrom(queryBlock); @@ -97,6 +99,7 @@ public class PGSelectParser extends SQLSelectParser { break; } } + queryBlock.setWindow(window); } queryBlock.setOrderBy(this.createExprParser().parseOrderBy()); @@ -150,6 +153,8 @@ public class PGSelectParser extends SQLSelectParser { } else { throw new ParserException("expect 'ONLY'"); } + + queryBlock.setFetch(fetch); } if (lexer.token() == Token.FOR) { @@ -182,14 +187,17 @@ public class PGSelectParser extends SQLSelectParser { lexer.nextToken(); forClause.setNoWait(true); } + + queryBlock.setForClause(forClause); } - - return queryBlock; + + return queryRest(queryBlock); } private WithQuery withQuery() { WithQuery withQuery = new WithQuery(); withQuery.setName(expr()); + if (lexer.token() == Token.LPAREN) { lexer.nextToken(); @@ -210,6 +218,8 @@ public class PGSelectParser extends SQLSelectParser { accept(Token.AS); if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + SQLSelectQuery subQuery = query(); withQuery.setSubQuery(subQuery); accept(Token.RPAREN); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java new file mode 100644 index 0000000000..a28567f054 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java @@ -0,0 +1,68 @@ +package com.alibaba.druid.sql.dialect.postgresql.visitor; + +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.FetchClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.ForClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WindowClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithQuery; +import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter; + +public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements + PGASTVisitor { + + @Override + public void endVisit(WindowClause x) { + + } + + @Override + public boolean visit(WindowClause x) { + + return true; + } + + @Override + public void endVisit(FetchClause x) { + + } + + @Override + public boolean visit(FetchClause x) { + + return true; + } + + @Override + public void endVisit(ForClause x) { + + } + + @Override + public boolean visit(ForClause x) { + + return true; + } + + @Override + public void endVisit(WithQuery x) { + + } + + @Override + public boolean visit(WithQuery x) { + + return true; + } + + @Override + public void endVisit(WithClause x) { + + } + + @Override + public boolean visit(WithClause x) { + + return true; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java new file mode 100644 index 0000000000..f000609ecb --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java @@ -0,0 +1,213 @@ +package com.alibaba.druid.sql.dialect.postgresql.visitor; + +import com.alibaba.druid.sql.ast.SQLSetQuantifier; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.FetchClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.ForClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WindowClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithQuery; +import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; + +public class PGOutputVisitor extends SQLASTOutputVisitor implements + PGASTVisitor { + + public PGOutputVisitor(Appendable appender) { + super(appender); + } + + @Override + public void endVisit(WindowClause x) { + + } + + @Override + public boolean visit(WindowClause x) { + print("WINDOW "); + x.getName().accept(this); + print(" AS "); + for (int i = 0; i < x.getDefinition().size(); ++i) { + if (i != 0) { + println(", "); + } + print("("); + x.getDefinition().get(i).accept(this); + print(")"); + } + return false; + } + + @Override + public void endVisit(FetchClause x) { + + } + + @Override + public boolean visit(FetchClause x) { + print("FETCH "); + if (FetchClause.Option.FIRST.equals(x.getOption())) { + print("FIRST "); + } else if (FetchClause.Option.NEXT.equals(x.getOption())) { + print("NEXT "); + } + x.getCount().accept(this); + print(" ROWS ONLY"); + return false; + } + + @Override + public void endVisit(ForClause x) { + + } + + @Override + public boolean visit(ForClause x) { + print("FOR "); + if (ForClause.Option.UPDATE.equals(x.getOption())) { + print("UPDATE "); + } else if (ForClause.Option.SHARE.equals(x.getOption())) { + print("SHARE "); + } + + if (x.getOf().size() > 0) { + for (int i = 0; i < x.getOf().size(); ++i) { + if (i != 0) { + println(", "); + } + x.getOf().get(i).accept(this); + } + } + + if (x.isNoWait()) { + print(" NOWAIT"); + } + + return false; + } + + @Override + public void endVisit(WithQuery x) { + + } + + @Override + public boolean visit(WithQuery x) { + x.getName().accept(this); + + if (x.getColumns().size() > 0) { + print(" ("); + printAndAccept(x.getColumns(), ", "); + print(")"); + } + println(); + print("AS"); + println(); + print("("); + incrementIndent(); + println(); + x.getSubQuery().accept(this); + decrementIndent(); + println(); + print(")"); + + return false; + } + + @Override + public void endVisit(WithClause x) { + + } + + @Override + public boolean visit(WithClause x) { + print("WITH"); + incrementIndent(); + println(); + printlnAndAccept(x.getWithQuery(), ", "); + decrementIndent(); + return false; + } + + public boolean visit(SQLSelectQueryBlock x) { + if (x instanceof PGSelectQueryBlock) { + return visit((PGSelectQueryBlock) x); + } + + return super.visit(x); + } + + public boolean visit(PGSelectQueryBlock x) { + if (x.getWith() != null) { + x.getWith().accept(this); + println(); + } + + print("SELECT "); + + if (SQLSetQuantifier.ALL == x.getDistionOption()) { + print("ALL "); + } else if (SQLSetQuantifier.DISTINCT == x.getDistionOption()) { + print("DISTINCT "); + + if (x.getDistinctOn() != null) { + print("ON "); + printAndAccept(x.getDistinctOn(), ", "); + } + } + + printSelectList(x.getSelectList()); + + if (x.getFrom() != null) { + println(); + print("FROM "); + x.getFrom().accept(this); + } + + if (x.getWhere() != null) { + println(); + print("WHERE "); + x.getWhere().accept(this); + } + + if (x.getGroupBy() != null) { + print(" "); + x.getGroupBy().accept(this); + } + + if (x.getWindow() != null) { + println(); + x.getWindow().accept(this); + } + + if (x.getOrderBy() != null) { + println(); + x.getOrderBy().accept(this); + } + + if (x.getLimit() != null) { + println(); + print("LIMIT "); + x.getLimit().accept(this); + } + + if (x.getOffset() != null) { + println(); + print("OFFSET "); + x.getOffset().accept(this); + print(" ROWS"); + } + + if (x.getFetch() != null) { + println(); + x.getFetch().accept(this); + } + + if (x.getForClause() != null) { + println(); + x.getForClause().accept(this); + } + + return false; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java new file mode 100644 index 0000000000..83c6cac432 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java @@ -0,0 +1,66 @@ +package com.alibaba.druid.sql.dialect.postgresql.visitor; + +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.FetchClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.ForClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WindowClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithQuery; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; + +public class PGSchemaStatVisitor extends SchemaStatVisitor implements + PGASTVisitor { + + @Override + public void endVisit(WindowClause x) { + + } + + @Override + public boolean visit(WindowClause x) { + return true; + } + + @Override + public void endVisit(FetchClause x) { + + } + + @Override + public boolean visit(FetchClause x) { + return true; + } + + @Override + public void endVisit(ForClause x) { + + } + + @Override + public boolean visit(ForClause x) { + + return true; + } + + @Override + public void endVisit(WithQuery x) { + + } + + @Override + public boolean visit(WithQuery x) { + + return true; + } + + @Override + public void endVisit(WithClause x) { + + } + + @Override + public boolean visit(WithClause x) { + + return true; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java new file mode 100644 index 0000000000..5ab7ae6317 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -0,0 +1,314 @@ +package com.alibaba.druid.sql.visitor; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLObject; +import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; +import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; +import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; +import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; +import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Column; +import com.alibaba.druid.stat.TableStat.Mode; + +public class SchemaStatVisitor extends SQLASTVisitorAdapter { + protected HashMap tableStats = new HashMap(); + protected Set fields = new HashSet(); + + protected final static ThreadLocal> aliasLocal = new ThreadLocal>(); + protected final static ThreadLocal currentTableLocal = new ThreadLocal(); + protected final static ThreadLocal modeLocal = new ThreadLocal(); + + @Override + public boolean visit(SQLInsertStatement x) { + x.putAttribute("_original_use_mode", modeLocal.get()); + modeLocal.set(Mode.Insert); + + aliasLocal.set(new HashMap()); + + String originalTable = currentTableLocal.get(); + + if (x.getTableName() instanceof SQLIdentifierExpr) { + String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); + 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.incrementInsertCount(); + + Map aliasMap = aliasLocal.get(); + if (aliasMap != null) { + if (x.getAlias() != null) { + aliasMap.put(x.getAlias(), ident); + } + aliasMap.put(ident, ident); + } + } + + accept(x.getColumns()); + accept(x.getQuery()); + + return false; + } + + protected void accept(SQLObject x) { + if (x != null) { + x.accept(this); + } + } + + protected void accept(List nodes) { + for (int i = 0, size = nodes.size(); i < size; ++i) { + accept(nodes.get(i)); + } + } + + public boolean visit(SQLSelectQueryBlock x) { + + if (x.getFrom() instanceof SQLSubqueryTableSource) { + x.getFrom().accept(this); + return false; + } + + x.putAttribute("_original_use_mode", modeLocal.get()); + modeLocal.set(Mode.Select); + + String originalTable = currentTableLocal.get(); + + if (x.getFrom() instanceof SQLExprTableSource) { + SQLExprTableSource tableSource = (SQLExprTableSource) x.getFrom(); + if (tableSource.getExpr() instanceof SQLName) { + String ident = tableSource.getExpr().toString(); + currentTableLocal.set(ident); + x.putAttribute("_old_local_", originalTable); + } + } + + x.getFrom().accept(this); // 提前执行,获得aliasMap + + return true; + } + + public void endVisit(SQLSelectQueryBlock x) { + String originalTable = (String) x.getAttribute("_old_local_"); + x.putAttribute("table", currentTableLocal.get()); + currentTableLocal.set(originalTable); + + Mode originalMode = (Mode) x.getAttribute("_original_use_mode"); + modeLocal.set(originalMode); + } + + public boolean visit(SQLJoinTableSource x) { + return true; + } + + public boolean visit(SQLPropertyExpr x) { + if (x.getOwner() instanceof SQLIdentifierExpr) { + String owner = ((SQLIdentifierExpr) x.getOwner()).getName(); + + if (owner != null) { + Map aliasMap = aliasLocal.get(); + if (aliasMap != null) { + String table = aliasMap.get(owner); + + // table == null时是SubQuery + if (table != null) { + fields.add(new Column(table, x.getName())); + } + } + } + } + return false; + } + + public boolean visit(SQLIdentifierExpr x) { + String currentTable = currentTableLocal.get(); + + if (currentTable != null) { + fields.add(new Column(currentTable, x.getName())); + } + return false; + } + + public boolean visit(SQLAllColumnExpr x) { + String currentTable = currentTableLocal.get(); + + if (currentTable != null) { + fields.add(new Column(currentTable, "*")); + } + return false; + } + + public Map getTables() { + return tableStats; + } + + public boolean containsTable(String tableName) { + return tableStats.containsKey(new TableStat.Name(tableName)); + } + + public Set getFields() { + return fields; + } + + public boolean visit(SQLSelectStatement x) { + aliasLocal.set(new HashMap()); + return true; + } + + public void endVisit(SQLSelectStatement x) { + aliasLocal.set(null); + } + + public boolean visit(SQLSubqueryTableSource x) { + Map aliasMap = aliasLocal.get(); + if (aliasMap != null) { + if (x.getAlias() != null) { + aliasMap.put(x.getAlias(), null); + } + } + return true; + } + + protected boolean isSimpleExprTableSource(SQLExprTableSource x) { + return x.getExpr() instanceof SQLName; + } + + public boolean visit(SQLExprTableSource x) { + if (isSimpleExprTableSource(x)) { + String ident = x.getExpr().toString(); + TableStat stat = tableStats.get(ident); + if (stat == null) { + stat = new TableStat(); + tableStats.put(new TableStat.Name(ident), stat); + } + + Mode mode = modeLocal.get(); + switch (mode) { + case Delete: + stat.incrementDeleteCount(); + break; + case Insert: + stat.incrementInsertCount(); + break; + case Update: + stat.incrementUpdateCount(); + break; + case Select: + stat.incrementSelectCount(); + break; + default: + break; + } + + Map aliasMap = aliasLocal.get(); + if (aliasMap != null) { + if (x.getAlias() != null) { + aliasMap.put(x.getAlias(), ident); + } + aliasMap.put(ident, ident); + } + } else { + accept(x.getExpr()); + } + + return false; + } + + public boolean visit(SQLSelect x) { + accept(x.getQuery()); + + String originalTable = currentTableLocal.get(); + + currentTableLocal.set((String) x.getQuery().getAttribute("table")); + x.putAttribute("_old_local_", originalTable); + + accept(x.getOrderBy()); + + currentTableLocal.set(originalTable); + + return false; + } + + public boolean visit(SQLAggregateExpr x) { + accept(x.getArguments()); + return false; + } + + public boolean visit(SQLMethodInvokeExpr x) { + accept(x.getParameters()); + return false; + } + + public boolean visit(SQLUpdateStatement x) { + aliasLocal.set(new HashMap()); + + String ident = x.getTableName().toString(); + currentTableLocal.set(ident); + + TableStat stat = tableStats.get(ident); + if (stat == null) { + stat = new TableStat(); + tableStats.put(new TableStat.Name(ident), stat); + } + stat.incrementUpdateCount(); + + Map aliasMap = aliasLocal.get(); + aliasMap.put(ident, ident); + + accept(x.getItems()); + accept(x.getWhere()); + + return false; + } + + public boolean visit(SQLDeleteStatement x) { + aliasLocal.set(new HashMap()); + + x.putAttribute("_original_use_mode", modeLocal.get()); + modeLocal.set(Mode.Delete); + + aliasLocal.set(new HashMap()); + + String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); + currentTableLocal.set(ident); + + TableStat stat = tableStats.get(ident); + if (stat == null) { + stat = new TableStat(); + tableStats.put(new TableStat.Name(ident), stat); + } + stat.incrementDeleteCount(); + + accept(x.getWhere()); + + return false; + } + + public void endVisit(SQLDeleteStatement x) { + aliasLocal.set(null); + } + + public void endVisit(SQLUpdateStatement x) { + aliasLocal.set(null); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/visitor/MySqlSchemaStatVisitorTest5.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/visitor/MySqlSchemaStatVisitorTest5.java index 00711a7b4f..36c9a5a94c 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/visitor/MySqlSchemaStatVisitorTest5.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/visitor/MySqlSchemaStatVisitorTest5.java @@ -18,7 +18,7 @@ public class MySqlSchemaStatVisitorTest5 extends TestCase { + " LEFT JOIN (select * from view_portal_panel) c ON a.panel_id = c.panel_id " + " WHERE b.user_id = ? and ((b.is_grid='y' and c.param_name='is_hidden' and c.param_value='false') or b.is_grid != 'y') and b.user_id in (select user_id from table1 where id = 1) ORDER BY a.col ASC, a.position ASC"; - sql = "select columnName from table1 where id in (select id from table3 where name = ?)"; +// sql = "select columnName from table1 where id in (select id from table3 where name = ?)"; MySqlStatementParser parser = new MySqlStatementParser(sql); List statementList = parser.parseStatementList(); SQLStatement statemen = statementList.get(0); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PostgresqlResourceTest.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PostgresqlResourceTest.java new file mode 100644 index 0000000000..44da320ae5 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PostgresqlResourceTest.java @@ -0,0 +1,83 @@ +package com.alibaba.druid.bvt.sql.postgresql; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.List; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor; +import com.alibaba.druid.util.JdbcUtils; + +public class PostgresqlResourceTest extends TestCase { + + public void test_0() throws Exception { + // 13 + exec_test("bvt/parser/postgresql-0.txt"); + // for (int i = 0; i <= 53; ++i) { + // exec_test("bvt/parser/oracle-" + i + ".txt"); + // } + } + + public void exec_test(String resource) throws Exception { + System.out.println(resource); + InputStream is = null; + + is = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource); + Reader reader = new InputStreamReader(is, "UTF-8"); + String input = JdbcUtils.read(reader); + JdbcUtils.close(reader); + String[] items = input.split("---------------------------"); + String sql = items[0].trim(); + String expect = items[1].trim(); + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + System.out.println(output(statementList)); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println(sql); + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getFields()); + + System.out.println(); + System.out.println(); + } + + void mergValidate(String sql, String expect) { + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + + Assert.assertEquals(1, statementList.size()); + + StringBuilder out = new StringBuilder(); + PGOutputVisitor visitor = new PGOutputVisitor(out); + statemen.accept(visitor); + + System.out.println(out.toString()); + + Assert.assertEquals(expect, out.toString()); + } + + private String output(List stmtList) { + StringBuilder out = new StringBuilder(); + PGOutputVisitor visitor = new PGOutputVisitor(out); + + for (SQLStatement stmt : stmtList) { + stmt.accept(visitor); + } + + return out.toString(); + } +} diff --git a/src/test/resources/bvt/parser/postgresql-0.txt b/src/test/resources/bvt/parser/postgresql-0.txt new file mode 100644 index 0000000000..1092cd4161 --- /dev/null +++ b/src/test/resources/bvt/parser/postgresql-0.txt @@ -0,0 +1,19 @@ +WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS ( + SELECT 1, employee_name, manager_name + FROM employee + WHERE manager_name = 'Mary' + UNION ALL + SELECT er.distance + 1, e.employee_name, e.manager_name + FROM employee_recursive er, employee e + WHERE er.employee_name = e.manager_name + ) +SELECT distance, employee_name FROM employee_recursive; +--------------------------- +SELECT e1.last_name +FROM employees e1 +WHERE f(CURSOR(( + SELECT e2.hire_date + FROM employees e2 + WHERE e1.employee_id = e2.manager_id + )), e1.hire_date) = 1 +ORDER BY last_name;