diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java b/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java index 1467ebc243..a59bdb9ad8 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java @@ -19,7 +19,7 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; -import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectOrderByItem; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @SuppressWarnings("serial") @@ -52,7 +52,7 @@ public class SQLOrderBy extends SQLObjectImpl { if (i != 0) { buf.append(", "); } - ((OracleSelectOrderByItem) this.items.get(i)).output(buf); + ((OracleOrderByItem) this.items.get(i)).output(buf); } } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleOrderBy.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleOrderBy.java index f0c01b8f9e..8cf53ebc3a 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleOrderBy.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleOrderBy.java @@ -16,7 +16,7 @@ package com.alibaba.druid.sql.dialect.oracle.ast; import com.alibaba.druid.sql.ast.SQLOrderBy; -import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectOrderByItem; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem; import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleASTVisitor; public class OracleOrderBy extends SQLOrderBy { @@ -57,7 +57,7 @@ public class OracleOrderBy extends SQLOrderBy { if (i != 0) { buf.append(", "); } - ((OracleSelectOrderByItem) this.items.get(i)).output(buf); + ((OracleOrderByItem) this.items.get(i)).output(buf); } } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/CycleClause.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/CycleClause.java new file mode 100644 index 0000000000..ac5ed6cbbb --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/CycleClause.java @@ -0,0 +1,58 @@ +package com.alibaba.druid.sql.dialect.oracle.ast.clause; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObject; +import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleASTVisitor; + +public class CycleClause extends OracleSQLObject { + + private static final long serialVersionUID = 1L; + + private final List aliases = new ArrayList(); + private SQLExpr mark; + private SQLExpr value; + private SQLExpr defaultValue; + + public SQLExpr getMark() { + return mark; + } + + public void setMark(SQLExpr mark) { + this.mark = mark; + } + + public SQLExpr getValue() { + return value; + } + + public void setValue(SQLExpr value) { + this.value = value; + } + + public SQLExpr getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(SQLExpr defaultValue) { + this.defaultValue = defaultValue; + } + + public List getAliases() { + return aliases; + } + + @Override + protected void accept0(OracleASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, aliases); + acceptChild(visitor, mark); + acceptChild(visitor, value); + acceptChild(visitor, defaultValue); + } + visitor.endVisit(this); + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/SearchClause.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/SearchClause.java new file mode 100644 index 0000000000..6141af47ab --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/SearchClause.java @@ -0,0 +1,54 @@ +package com.alibaba.druid.sql.dialect.oracle.ast.clause; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObject; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem; +import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleASTVisitor; + +public class SearchClause extends OracleSQLObject { + + private static final long serialVersionUID = 1L; + + public static enum Type { + DEPTH, BREADTH + } + + private Type type; + + private final List items = new ArrayList(); + + private SQLIdentifierExpr orderingColumn; + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getItems() { + return items; + } + + public SQLIdentifierExpr getOrderingColumn() { + return orderingColumn; + } + + public void setOrderingColumn(SQLIdentifierExpr orderingColumn) { + this.orderingColumn = orderingColumn; + } + + @Override + protected void accept0(OracleASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, items); + acceptChild(visitor, orderingColumn); + } + visitor.endVisit(this); + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/SubqueryFactoringClause.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/SubqueryFactoringClause.java new file mode 100644 index 0000000000..e4f27a484d --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/clause/SubqueryFactoringClause.java @@ -0,0 +1,87 @@ +package com.alibaba.druid.sql.dialect.oracle.ast.clause; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; +import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObject; +import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleASTVisitor; + +public class SubqueryFactoringClause extends OracleSQLObject { + + private static final long serialVersionUID = 1L; + + private final List entries = new ArrayList(); + + public List getEntries() { + return entries; + } + + public static class Entry extends OracleSQLObject { + + private static final long serialVersionUID = 1L; + + private SQLIdentifierExpr name; + private final List columns = new ArrayList(); + private SQLSelectQuery subQuery; + private SearchClause searchClause; + private CycleClause cycleClause; + + public CycleClause getCycleClause() { + return cycleClause; + } + + public void setCycleClause(CycleClause cycleClause) { + this.cycleClause = cycleClause; + } + + public SearchClause getSearchClause() { + return searchClause; + } + + public void setSearchClause(SearchClause searchClause) { + this.searchClause = searchClause; + } + + public SQLIdentifierExpr getName() { + return name; + } + + public void setName(SQLIdentifierExpr name) { + this.name = name; + } + + public SQLSelectQuery getSubQuery() { + return subQuery; + } + + public void setSubQuery(SQLSelectQuery subQuery) { + this.subQuery = subQuery; + } + + public List getColumns() { + return columns; + } + + @Override + protected void accept0(OracleASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, name); + acceptChild(visitor, columns); + acceptChild(visitor, subQuery); + } + visitor.endVisit(this); + } + + } + + @Override + protected void accept0(OracleASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, entries); + } + visitor.endVisit(this); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleSelectOrderByItem.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleOrderByItem.java similarity index 95% rename from src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleSelectOrderByItem.java rename to src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleOrderByItem.java index d64f9fa155..a231341f92 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleSelectOrderByItem.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleOrderByItem.java @@ -20,13 +20,13 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -public class OracleSelectOrderByItem extends SQLSelectOrderByItem { +public class OracleOrderByItem extends SQLSelectOrderByItem { private static final long serialVersionUID = 1L; private NullsOrderType nullsOrderType; - public OracleSelectOrderByItem(){ + public OracleOrderByItem(){ } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleSelect.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleSelect.java index 496e1a5651..8444df561f 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleSelect.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/stmt/OracleSelect.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.dialect.oracle.ast.stmt; import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.dialect.oracle.ast.clause.SubqueryFactoringClause; import com.alibaba.druid.sql.dialect.oracle.ast.visitor.OracleASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -23,6 +24,7 @@ public class OracleSelect extends SQLSelect { private static final long serialVersionUID = 1L; + private SubqueryFactoringClause factoring; private OracleSelectForUpdate forUpdate; private OracleSelectRestriction restriction; @@ -30,6 +32,14 @@ public class OracleSelect extends SQLSelect { } + public SubqueryFactoringClause getFactoring() { + return factoring; + } + + public void setFactoring(SubqueryFactoringClause factoring) { + this.factoring = factoring; + } + public OracleSelectRestriction getRestriction() { return this.restriction; } @@ -52,25 +62,14 @@ public class OracleSelect extends SQLSelect { if (this.orderBy != null) this.orderBy.output(buf); } - - protected void accept0(SQLASTVisitor visitor) { - if (visitor instanceof OracleASTVisitor) { - accept0((OracleASTVisitor) visitor); - return; - } - - if (visitor.visit(this)) { - acceptChild(visitor, this.query); - acceptChild(visitor, this.restriction); - acceptChild(visitor, this.orderBy); - acceptChild(visitor, this.forUpdate); - } - visitor.endVisit(this); + protected void accept0(SQLASTVisitor visitor) { + accept0((OracleASTVisitor) visitor); } protected void accept0(OracleASTVisitor visitor) { if (visitor.visit(this)) { + acceptChild(visitor, this.factoring); acceptChild(visitor, this.query); acceptChild(visitor, this.restriction); acceptChild(visitor, this.orderBy); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleASTVisitor.java index 53a54a6224..ce274ae150 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleASTVisitor.java @@ -19,11 +19,14 @@ import com.alibaba.druid.sql.ast.expr.SQLObjectCreateExpr; import com.alibaba.druid.sql.dialect.oracle.ast.OracleDataTypeInterval; 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.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.expr.OracleAggregateExpr; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalytic; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalyticWindowing; @@ -46,6 +49,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateViewStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleDeleteStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForeignKey; +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.OraclePrimaryKey; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleRefDataType; @@ -53,7 +57,6 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleReferencesConstaint; 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.OracleSelectOrderByItem; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectPivot; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectRestriction; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectSubqueryTableSource; @@ -157,7 +160,7 @@ public interface OracleASTVisitor extends SQLASTVisitor { void endVisit(OracleSelectJoin x); - void endVisit(OracleSelectOrderByItem x); + void endVisit(OracleOrderByItem x); void endVisit(OracleSelectPivot x); @@ -277,7 +280,7 @@ public interface OracleASTVisitor extends SQLASTVisitor { boolean visit(OracleSelectJoin x); - boolean visit(OracleSelectOrderByItem x); + boolean visit(OracleOrderByItem x); boolean visit(OracleSelectPivot x); @@ -314,28 +317,44 @@ public interface OracleASTVisitor extends SQLASTVisitor { boolean visit(SampleClause x); void endVisit(SampleClause x); - + boolean visit(OracleSelectTableReference x); - + void endVisit(OracleSelectTableReference x); - + boolean visit(PartitionExtensionClause x); - + void endVisit(PartitionExtensionClause x); - + boolean visit(VersionsFlashbackQueryClause x); - + void endVisit(VersionsFlashbackQueryClause x); - + boolean visit(AsOfFlashbackQueryClause x); - + void endVisit(AsOfFlashbackQueryClause x); - + boolean visit(GroupingSetExpr x); - + void endVisit(GroupingSetExpr x); - + boolean visit(OraclePriorExpr x); - + void endVisit(OraclePriorExpr x); + + boolean visit(SubqueryFactoringClause x); + + void endVisit(SubqueryFactoringClause x); + + boolean visit(SubqueryFactoringClause.Entry x); + + void endVisit(SubqueryFactoringClause.Entry x); + + boolean visit(SearchClause x); + + void endVisit(SearchClause x); + + boolean visit(CycleClause x); + + void endVisit(CycleClause x); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleOutputVisitor.java index 9eeaa3644f..a00181826a 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/visitor/OracleOutputVisitor.java @@ -31,11 +31,14 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.oracle.ast.OracleDataTypeInterval; 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.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.expr.OracleAggregateExpr; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalytic; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalyticWindowing; @@ -72,6 +75,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateViewStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleDeleteStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForeignKey; +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.OraclePrimaryKey; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleRefDataType; @@ -80,7 +84,6 @@ 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.OracleSelectOrderByItem; 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; @@ -496,6 +499,11 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } public boolean visit(OracleSelect x) { + if (x.getFactoring() != null) { + x.getFactoring().accept(this); + println(); + } + x.getQuery().accept(this); if (x.getRestriction() != null) { @@ -567,7 +575,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS return false; } - public boolean visit(OracleSelectOrderByItem x) { + public boolean visit(OracleOrderByItem x) { x.getExpr().accept(this); if (x.getType() != null) { print(" "); @@ -717,22 +725,22 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS if (x.isOnly()) { print("ONLY ("); x.getExpr().accept(this); - + if (x.getPartition() != null) { print(" "); x.getPartition().accept(this); } - + print(")"); } else { x.getExpr().accept(this); - + if (x.getPartition() != null) { print(" "); x.getPartition().accept(this); } } - + if (x.getSampleClause() != null) { print(" "); x.getSampleClause().accept(this); @@ -746,7 +754,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS decrementIndent(); } - + if (x.getFlashback() != null) { println(); x.getFlashback().accept(this); @@ -1392,7 +1400,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } @Override - public void endVisit(OracleSelectOrderByItem x) { + public void endVisit(OracleOrderByItem x) { } @@ -1479,32 +1487,32 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS @Override public boolean visit(SampleClause x) { print("SAMPLE "); - + if (x.isBlock()) { print("BLOCK "); } - + print("("); print(x.getPercent()); print(")"); - + if (x.getSeedValue() != null) { print(" SEED ("); x.getSeedValue().accept(this); print(")"); } - + return false; } @Override public void endVisit(SampleClause x) { - + } @Override public void endVisit(OracleSelectTableReference x) { - + } @Override @@ -1514,7 +1522,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } else { print("PARTITION "); } - + if (x.getPartition() != null) { print("("); x.getPartition().accept(this); @@ -1529,7 +1537,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS @Override public void endVisit(PartitionExtensionClause x) { - + } @Override @@ -1545,7 +1553,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS @Override public void endVisit(VersionsFlashbackQueryClause x) { - + } @Override @@ -1560,9 +1568,9 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS @Override public void endVisit(AsOfFlashbackQueryClause x) { - + } - + @Override public boolean visit(GroupingSetExpr x) { print("GROUPING SETS"); @@ -1571,10 +1579,10 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS print(")"); return false; } - + @Override public void endVisit(GroupingSetExpr x) { - + } @Override @@ -1586,7 +1594,95 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS @Override public void endVisit(OraclePriorExpr x) { + + } + + @Override + public boolean visit(SubqueryFactoringClause.Entry 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(")"); + + if (x.getSearchClause() != null) { + println(); + x.getSearchClause().accept(this); + } + if (x.getCycleClause() != null) { + println(); + x.getCycleClause().accept(this); + } + return false; + } + + @Override + public void endVisit(SubqueryFactoringClause.Entry x) { + + } + + @Override + public boolean visit(SubqueryFactoringClause x) { + print("WITH"); + incrementIndent(); + println(); + printlnAndAccept(x.getEntries(), ", "); + decrementIndent(); + return false; + } + + @Override + public void endVisit(SubqueryFactoringClause x) { + + } + + @Override + public boolean visit(SearchClause x) { + print("SEARCH "); + print(x.getType().name()); + print(" FIRST BY "); + printAndAccept(x.getItems(), ", "); + print(" SET "); + x.getOrderingColumn().accept(this); + + return false; + } + + @Override + public void endVisit(SearchClause x) { + + } + + @Override + public boolean visit(CycleClause x) { + print("CYCLE "); + printAndAccept(x.getAliases(), ", "); + print(" SET "); + x.getMark().accept(this); + print(" TO "); + x.getValue().accept(this); + print(" DEFAULT "); + x.getDefaultValue().accept(this); + + return false; + } + + @Override + public void endVisit(CycleClause x) { + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java index 670a7694d1..2a0ea0b695 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java @@ -26,7 +26,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAnalyticWindowing; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleIntervalExpr; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleIntervalType; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OraclePriorExpr; -import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectOrderByItem; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLExprParser; @@ -234,8 +234,8 @@ public class OracleExprParser extends SQLExprParser { } @Override - protected OracleSelectOrderByItem parseSelectOrderByItem() { - OracleSelectOrderByItem item = new OracleSelectOrderByItem(); + public OracleOrderByItem parseSelectOrderByItem() { + OracleOrderByItem item = new OracleOrderByItem(); item.setExpr(expr()); @@ -251,10 +251,10 @@ public class OracleExprParser extends SQLExprParser { lexer.nextToken(); if (identifierEquals("FIRST")) { lexer.nextToken(); - item.setNullsOrderType(OracleSelectOrderByItem.NullsOrderType.NullsFirst); + item.setNullsOrderType(OracleOrderByItem.NullsOrderType.NullsFirst); } else if (identifierEquals("LAST")) { lexer.nextToken(); - item.setNullsOrderType(OracleSelectOrderByItem.NullsOrderType.NullsLast); + item.setNullsOrderType(OracleOrderByItem.NullsOrderType.NullsLast); } else { throw new ParserException("TODO " + lexer.token()); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java index 7793cd1233..3a0fd18bd7 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java @@ -85,6 +85,7 @@ public class OracleLexer extends Lexer { map.put("START", Token.START); map.put("CONNECT", Token.CONNECT); map.put("PRIOR", Token.PRIOR); + map.put("WITH", Token.WITH); DEFAULT_ORACLE_KEYWORDS = new Keywords(map); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java index 2cd23590f2..d4965b5527 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java @@ -25,12 +25,16 @@ 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; import com.alibaba.druid.sql.dialect.oracle.ast.clause.GroupingSetExpr; 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.expr.OracleAggregateExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem; 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; @@ -44,7 +48,6 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableSource; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectUnPivot; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; -import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.SQLParseException; import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.Token; @@ -59,13 +62,86 @@ public class OracleSelectParser extends SQLSelectParser { super(lexer); } - protected SQLExprParser createExprParser() { + protected OracleExprParser createExprParser() { return new OracleExprParser(lexer); } public OracleSelect select() { OracleSelect select = new OracleSelect(); + if (lexer.token() == Token.WITH) { + lexer.nextToken(); + + SubqueryFactoringClause subqueryFactoringClause = new SubqueryFactoringClause(); + for (;;) { + SubqueryFactoringClause.Entry entry = new SubqueryFactoringClause.Entry(); + entry.setName((SQLIdentifierExpr) createExprParser().name()); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + createExprParser().names(entry.getColumns()); + accept(Token.RPAREN); + } + + accept(Token.AS); + accept(Token.LPAREN); + entry.setSubQuery(query()); + accept(Token.RPAREN); + + if (identifierEquals("SEARCH")) { + lexer.nextToken(); + SearchClause searchClause = new SearchClause(); + + if (lexer.token() != Token.IDENTIFIER) { + throw new SQLParseException("syntax erorr : " + lexer.token()); + } + + searchClause.setType(SearchClause.Type.valueOf(lexer.stringVal())); + lexer.nextToken(); + + acceptIdentifier("FIRST"); + accept(Token.BY); + + searchClause.getItems().add((OracleOrderByItem) createExprParser().parseSelectOrderByItem()); + + while (lexer.token() == (Token.COMMA)) { + lexer.nextToken(); + searchClause.getItems().add((OracleOrderByItem) createExprParser().parseSelectOrderByItem()); + } + + accept(Token.SET); + + searchClause.setOrderingColumn((SQLIdentifierExpr) createExprParser().name()); + + entry.setSearchClause(searchClause); + } + + if (identifierEquals("CYCLE")) { + lexer.nextToken(); + CycleClause cycleClause = new CycleClause(); + createExprParser().exprList(cycleClause.getAliases()); + accept(Token.SET); + cycleClause.setMark(createExprParser().expr()); + acceptIdentifier("TO"); + cycleClause.setValue(createExprParser().expr()); + accept(Token.DEFAULT); + cycleClause.setDefaultValue(createExprParser().expr()); + entry.setCycleClause(cycleClause); + } + + subqueryFactoringClause.getEntries().add(entry); + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + + break; + } + + select.setFactoring(subqueryFactoringClause); + } + select.setQuery(query()); select.setOrderBy(this.parseOrderBy()); @@ -93,7 +169,7 @@ public class OracleSelectParser extends SQLSelectParser { select.setOrderBy(this.createExprParser().parseOrderBy()); } - if (identifierEquals("WITH")) { + if (lexer.token() == Token.WITH) { lexer.nextToken(); if (identifierEquals("READ")) { @@ -278,7 +354,7 @@ public class OracleSelectParser extends SQLSelectParser { if (hierachical == null) { hierachical = new OracleSelectHierachicalQueryClause(); } - acceptIdentifier("WITH"); + accept(Token.WITH); hierachical.setStartWith(this.createExprParser().expr()); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java index 6e67dc84d4..3f22ffeb43 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java @@ -102,6 +102,11 @@ public class OracleStatementParser extends SQLStatementParser { if (lexer.token() == Token.ALTER) { throw new ParserException("TODO"); } + + if (lexer.token() == Token.WITH) { + statementList.add(new SQLSelectStatement(new OracleSelectParser(this.lexer).select())); + continue; + } throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal()); } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index e38370ef93..ccb3398bf3 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -618,7 +618,7 @@ public class SQLExprParser extends SQLParser { return null; } - protected SQLSelectOrderByItem parseSelectOrderByItem() throws ParserException { + public SQLSelectOrderByItem parseSelectOrderByItem() throws ParserException { SQLSelectOrderByItem item = new SQLSelectOrderByItem(); item.setExpr(expr()); diff --git a/src/main/java/com/alibaba/druid/sql/parser/Token.java b/src/main/java/com/alibaba/druid/sql/parser/Token.java index 88d201de4c..bf93a0e172 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -102,6 +102,7 @@ public enum Token { START("START"), PRIOR("PRIOR"), CONNECT("CONNECT"), + WITH("WITH"), EOF, ERROR, diff --git a/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserResourceTest.java b/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserResourceTest.java index c1d4317a3c..8164d06255 100644 --- a/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserResourceTest.java +++ b/src/test/java/com/alibaba/druid/sql/oracle/bvt/OracleSQLParserResourceTest.java @@ -45,6 +45,8 @@ public class OracleSQLParserResourceTest extends TestCase { exec_test("bvt/parser/oracle-26.txt"); exec_test("bvt/parser/oracle-27.txt"); exec_test("bvt/parser/oracle-28.txt"); + exec_test("bvt/parser/oracle-29.txt"); + exec_test("bvt/parser/oracle-30.txt"); } diff --git a/src/test/resources/bvt/parser/oracle-29.txt b/src/test/resources/bvt/parser/oracle-29.txt index 69c07428f5..a079a9ccf9 100644 --- a/src/test/resources/bvt/parser/oracle-29.txt +++ b/src/test/resources/bvt/parser/oracle-29.txt @@ -1,18 +1,38 @@ -select count(*) -from CREDIT_CMT_APPLY ,CREDIT_CMT_SHEET -where 1=2 -OR operator = ? - and CREDIT_CMT_APPLY.GMT_CREATE >= ? - and CREDIT_CMT_APPLY.GMT_CREATE <= ? - and CREDIT_CMT_APPLY.ID = CREDIT_CMT_SHEET.cmt_apply_id - and Type = 'denounce' - and (SHEET_STATUS = 'assigned_unresolved') +WITH + org_chart (eid, emp_last, mgr_id, reportLevel, salary, job_id) AS + ( + SELECT employee_id, last_name, manager_id, 0 reportLevel, salary, job_id + FROM employees + WHERE manager_id is null + UNION ALL + SELECT e.employee_id, e.last_name, e.manager_id, + r.reportLevel+1 reportLevel, e.salary, e.job_id + FROM org_chart r, employees e + WHERE r.eid = e.manager_id + ) + SEARCH DEPTH FIRST BY emp_last SET order1 +SELECT lpad(' ',2*reportLevel)||emp_last emp_name, eid, mgr_id, salary, job_id +FROM org_chart +ORDER BY order1; --------------------------- -SELECT bk.attr_id AS attrId, group_concat(DISTINCT(bk.value_id)) AS attrValueStr, group_concat(DISTINCT(pt.name)) AS themeNameStr -FROM price_theme pt LEFT JOIN tl_spu_attr_value_rel_bk bk ON pt.spu_id = bk.spu_id -WHERE pt.status = 'action' AND pt.category_id = ? -GROUP BY bk.attr_id; - +WITH + org_chart (eid, emp_last, mgr_id, reportLevel, salary, job_id) + AS + ( + SELECT employee_id, last_name, manager_id, 0 AS reportLevel, salary + , job_id + FROM employees + WHERE manager_id IS NULL + UNION ALL + SELECT e.employee_id, e.last_name, e.manager_id, r.reportLevel + 1 AS reportLevel, e.salary + , e.job_id + FROM org_chart r , employees e + WHERE r.eid = e.manager_id + ) + SEARCH DEPTH FIRST BY emp_last SET order1 +SELECT lpad(' ', 2 * reportLevel) || emp_last AS emp_name, eid, mgr_id, salary, job_id +FROM org_chart +ORDER BY order1; diff --git a/src/test/resources/bvt/parser/oracle-30.txt b/src/test/resources/bvt/parser/oracle-30.txt new file mode 100644 index 0000000000..53e58b7a32 --- /dev/null +++ b/src/test/resources/bvt/parser/oracle-30.txt @@ -0,0 +1,41 @@ +WITH + dup_hiredate (eid, emp_last, mgr_id, reportLevel, hire_date, job_id) AS + ( + SELECT employee_id, last_name, manager_id, 0 reportLevel, hire_date, job_id + FROM employees + WHERE manager_id is null + UNION ALL + SELECT e.employee_id, e.last_name, e.manager_id, + r.reportLevel+1 reportLevel, e.hire_date, e.job_id + FROM dup_hiredate r, employees e + WHERE r.eid = e.manager_id + ) + SEARCH DEPTH FIRST BY hire_date SET order1 + CYCLE hire_date SET is_cycle TO 'Y' DEFAULT 'N' +SELECT lpad(' ',2*reportLevel)||emp_last emp_name, eid, mgr_id, + hire_date, job_id, is_cycle +FROM dup_hiredate +ORDER BY order1; + + +--------------------------- +WITH + dup_hiredate (eid, emp_last, mgr_id, reportLevel, hire_date, job_id) + AS + ( + SELECT employee_id, last_name, manager_id, 0 AS reportLevel, hire_date + , job_id + FROM employees + WHERE manager_id IS NULL + UNION ALL + SELECT e.employee_id, e.last_name, e.manager_id, r.reportLevel + 1 AS reportLevel, e.hire_date + , e.job_id + FROM dup_hiredate r , employees e + WHERE r.eid = e.manager_id + ) + SEARCH DEPTH FIRST BY hire_date SET order1 + CYCLE hire_date SET is_cycle TO 'Y' DEFAULT 'N' +SELECT lpad(' ', 2 * reportLevel) || emp_last AS emp_name, eid, mgr_id, hire_date, job_id + , is_cycle +FROM dup_hiredate +ORDER BY order1; diff --git a/src/test/resources/bvt/parser/oracle-31.txt b/src/test/resources/bvt/parser/oracle-31.txt new file mode 100644 index 0000000000..bf36866271 --- /dev/null +++ b/src/test/resources/bvt/parser/oracle-31.txt @@ -0,0 +1,25 @@ +WITH + org_chart (eid, emp_last, mgr_id, reportLevel, salary, job_id) AS + ( + SELECT employee_id, last_name, manager_id, 0 reportLevel, salary, job_id + FROM employees + WHERE manager_id is null + UNION ALL + SELECT e.employee_id, e.last_name, e.manager_id, + r.reportLevel+1 reportLevel, e.salary, e.job_id + FROM org_chart r, employees e + WHERE r.eid = e.manager_id + ) + SEARCH DEPTH FIRST BY emp_last SET order1 +SELECT lpad(' ',2*reportLevel)||emp_last emp_name, eid, mgr_id, salary, job_id +FROM org_chart +ORDER BY order1; + + + +--------------------------- +SELECT bk.attr_id AS attrId, group_concat(DISTINCT(bk.value_id)) AS attrValueStr, group_concat(DISTINCT(pt.name)) AS themeNameStr +FROM price_theme pt LEFT JOIN tl_spu_attr_value_rel_bk bk ON pt.spu_id = bk.spu_id +WHERE pt.status = 'action' AND pt.category_id = ? +GROUP BY bk.attr_id; +