diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index c49bf6aea..9e1ee104d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -711,7 +711,7 @@ public T visit(GeometryDistance geometryDistance, S context) { public T visit(Select select, S context) { if (selectVisitor != null) { if (select.getWithItemsList() != null) { - for (WithItem item : select.getWithItemsList()) { + for (WithItem item : select.getWithItemsList()) { item.accept(selectVisitor, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/ParenthesedStatement.java b/src/main/java/net/sf/jsqlparser/statement/ParenthesedStatement.java new file mode 100644 index 000000000..bd76f2282 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ParenthesedStatement.java @@ -0,0 +1,31 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.Alias; + +public interface ParenthesedStatement extends Statement { + + T accept(StatementVisitor statementVisitor, S context); + + default void accept(StatementVisitor statementVisitor) { + this.accept(statementVisitor, null); + } + + Alias getAlias(); + + void setAlias(Alias alias); + + default ParenthesedStatement withAlias(Alias alias) { + setAlias(alias); + return this; + } + +} diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index 8625f6576..efd7ee099 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java @@ -24,16 +24,19 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; import net.sf.jsqlparser.statement.grant.Grant; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; @@ -302,4 +305,23 @@ default void visit(AlterSystemStatement alterSystemStatement) { default void visit(UnsupportedStatement unsupportedStatement) { this.visit(unsupportedStatement, null); } + + T visit(ParenthesedInsert parenthesedInsert, S context); + + default void visit(ParenthesedInsert parenthesedInsert) { + this.visit(parenthesedInsert, null); + } + + T visit(ParenthesedUpdate parenthesedUpdate, S context); + + default void visit(ParenthesedUpdate parenthesedUpdate) { + this.visit(parenthesedUpdate, null); + } + + T visit(ParenthesedDelete parenthesedDelete, S context); + + default void visit(ParenthesedDelete parenthesedDelete) { + this.visit(parenthesedDelete, null); + } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index 5ee05b852..0e6ab8698 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -24,16 +24,19 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; import net.sf.jsqlparser.statement.grant.Grant; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; @@ -64,18 +67,36 @@ public T visit(Delete delete, S context) { return null; } + @Override + public T visit(ParenthesedDelete delete, S context) { + + return null; + } + @Override public T visit(Update update, S context) { return null; } + @Override + public T visit(ParenthesedUpdate update, S context) { + + return null; + } + @Override public T visit(Insert insert, S context) { return null; } + @Override + public T visit(ParenthesedInsert insert, S context) { + + return null; + } + @Override public T visit(Drop drop, S context) { diff --git a/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java b/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java index 931d486c7..0ff9b8868 100644 --- a/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java +++ b/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java @@ -33,7 +33,7 @@ public class Delete implements Statement { - private List withItemsList; + private List> withItemsList; private Table table; private OracleHint oracleHint = null; private List tables; @@ -67,28 +67,28 @@ public Delete setReturningClause(ReturningClause returningClause) { return this; } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } - public Delete withWithItemsList(List withItemsList) { + public Delete withWithItemsList(List> withItemsList) { this.setWithItemsList(withItemsList); return this; } - public Delete addWithItemsList(WithItem... withItemsList) { - List collection = + public Delete addWithItemsList(WithItem... withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); Collections.addAll(collection, withItemsList); return this.withWithItemsList(collection); } - public Delete addWithItemsList(Collection withItemsList) { - List collection = + public Delete addWithItemsList(Collection> withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); collection.addAll(withItemsList); return this.withWithItemsList(collection); @@ -177,8 +177,8 @@ public String toString() { StringBuilder b = new StringBuilder(); if (withItemsList != null && !withItemsList.isEmpty()) { b.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); b.append(withItem); if (iter.hasNext()) { b.append(","); diff --git a/src/main/java/net/sf/jsqlparser/statement/delete/ParenthesedDelete.java b/src/main/java/net/sf/jsqlparser/statement/delete/ParenthesedDelete.java new file mode 100644 index 000000000..ffdf57d4b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/delete/ParenthesedDelete.java @@ -0,0 +1,62 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.delete; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class ParenthesedDelete extends Delete implements ParenthesedStatement { + + Alias alias; + Delete delete; + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + public ParenthesedDelete withAlias(Alias alias) { + this.setAlias(alias); + return this; + } + + public Delete getDelete() { + return delete; + } + + public void setDelete(Delete delete) { + this.delete = delete; + } + + public ParenthesedDelete withDelete(Delete delete) { + setDelete(delete); + return this; + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("(").append(delete).append(")"); + if (alias != null) { + builder.append(alias); + } + return builder.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java b/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java index 287d96574..4d52a5864 100644 --- a/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java +++ b/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java @@ -43,7 +43,7 @@ public class Insert implements Statement { private boolean modifierIgnore = false; private ReturningClause returningClause; private List setUpdateSets = null; - private List withItemsList; + private List> withItemsList; private OutputClause outputClause; private InsertConflictTarget conflictTarget; private InsertConflictAction conflictAction; @@ -168,11 +168,11 @@ public boolean isUseSet() { return setUpdateSets != null && !setUpdateSets.isEmpty(); } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } @@ -221,8 +221,8 @@ public String toString() { StringBuilder sql = new StringBuilder(); if (withItemsList != null && !withItemsList.isEmpty()) { sql.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); sql.append(withItem); if (iter.hasNext()) { sql.append(","); @@ -293,7 +293,7 @@ public String toString() { return sql.toString(); } - public Insert withWithItemsList(List withList) { + public Insert withWithItemsList(List> withList) { this.withItemsList = withList; return this; } diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/ParenthesedInsert.java b/src/main/java/net/sf/jsqlparser/statement/insert/ParenthesedInsert.java new file mode 100644 index 000000000..b9c83526c --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/insert/ParenthesedInsert.java @@ -0,0 +1,61 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.insert; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class ParenthesedInsert extends Insert implements ParenthesedStatement { + Alias alias; + Insert insert; + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + public ParenthesedInsert withAlias(Alias alias) { + this.setAlias(alias); + return this; + } + + public Insert getInsert() { + return insert; + } + + public void setInsert(Insert insert) { + this.insert = insert; + } + + public ParenthesedInsert withInsert(Insert insert) { + setInsert(insert); + return this; + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("(").append(insert).append(")"); + if (alias != null) { + builder.append(alias); + } + return builder.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/Merge.java b/src/main/java/net/sf/jsqlparser/statement/merge/Merge.java index 689bd5d8e..7a3baf7a4 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/Merge.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/Merge.java @@ -30,7 +30,7 @@ public class Merge implements Statement { - private List withItemsList; + private List> withItemsList; private Table table; private OracleHint oracleHint = null; private FromItem fromItem; @@ -75,28 +75,28 @@ private void deriveStandardClausesFromOperations() { .orElse(false); } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } - public Merge withWithItemsList(List withItemsList) { + public Merge withWithItemsList(List> withItemsList) { this.setWithItemsList(withItemsList); return this; } - public Merge addWithItemsList(WithItem... withItemsList) { - List collection = + public Merge addWithItemsList(WithItem... withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); Collections.addAll(collection, withItemsList); return this.withWithItemsList(collection); } - public Merge addWithItemsList(Collection withItemsList) { - List collection = + public Merge addWithItemsList(Collection> withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); collection.addAll(withItemsList); return this.withWithItemsList(collection); @@ -220,8 +220,8 @@ public String toString() { StringBuilder b = new StringBuilder(); if (withItemsList != null && !withItemsList.isEmpty()) { b.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); b.append(withItem); if (iter.hasNext()) { b.append(","); diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedSelect.java b/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedSelect.java index 0fc99972e..a33abf3a3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedSelect.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedSelect.java @@ -12,11 +12,13 @@ import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; import java.util.Collection; import java.util.List; -public class ParenthesedSelect extends Select implements FromItem { +public class ParenthesedSelect extends Select implements FromItem, ParenthesedStatement { Alias alias; Pivot pivot; UnPivot unPivot; @@ -151,12 +153,16 @@ public T accept(FromItemVisitor fromItemVisitor, S context) { return fromItemVisitor.visit(this, context); } + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + public StringBuilder appendSelectBodyTo(StringBuilder builder) { builder.append("(").append(select).append(")"); if (alias != null) { builder.append(alias); } - if (pivot != null) { builder.append(" ").append(pivot); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Select.java b/src/main/java/net/sf/jsqlparser/statement/select/Select.java index e6cc7393a..b0c8e9972 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Select.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Select.java @@ -25,7 +25,7 @@ public abstract class Select extends ASTNodeAccessImpl implements Statement, Expression { protected Table forUpdateTable = null; - List withItemsList; + List> withItemsList; Limit limitBy; Limit limit; Offset offset; @@ -126,27 +126,27 @@ public static StringBuilder appendStringListTo(StringBuilder builder, List li return builder; } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } - public Select withWithItemsList(List withItemsList) { + public Select withWithItemsList(List> withItemsList) { this.setWithItemsList(withItemsList); return this; } - public Select addWithItemsList(Collection withItemsList) { - List collection = + public Select addWithItemsList(Collection> withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); collection.addAll(withItemsList); return this.withWithItemsList(collection); } - public Select addWithItemsList(WithItem... withItemsList) { + public Select addWithItemsList(WithItem... withItemsList) { return addWithItemsList(Arrays.asList(withItemsList)); } @@ -328,7 +328,7 @@ public void setSkipLocked(boolean skipLocked) { public StringBuilder appendTo(StringBuilder builder) { if (withItemsList != null && !withItemsList.isEmpty()) { builder.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { WithItem withItem = iter.next(); builder.append(withItem); if (iter.hasNext()) { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java index d8ee278be..8a4e9667c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java @@ -29,9 +29,9 @@ default void visit(SetOperationList setOpList) { this.visit(setOpList, null); } - T visit(WithItem withItem, S context); + T visit(WithItem withItem, S context); - default void visit(WithItem withItem) { + default void visit(WithItem withItem) { this.visit(withItem, null); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java index 90fa3b8c2..d20fdfdd1 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java @@ -31,7 +31,7 @@ public T visit(SetOperationList setOpList, S context) { } @Override - public T visit(WithItem withItem, S context) { + public T visit(WithItem withItem, S context) { return withItem.getSelect().accept(this, context); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java index b3610a730..37b3663c2 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java @@ -9,18 +9,60 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; -public class WithItem extends ParenthesedSelect { +public class WithItem { + private T statement; + private Alias alias; private List> withItemList; - private boolean recursive = false; + public WithItem(T statement, Alias alias) { + this.statement = statement; + this.alias = alias; + } + + public WithItem() { + this(null, (Alias) null); + } + + public T getParenthesedStatement() { + return statement; + } + + public void setParenthesedStatement(T statement) { + this.statement = statement; + } + + public WithItem withParenthesedStatement(T statement) { + this.setParenthesedStatement(statement); + return this; + } + + public Alias getAlias() { + return alias; + } + + public void setAlias(Alias alias) { + this.alias = alias; + } + + public WithItem withAlias(Alias alias) { + this.setAlias(alias); + return this; + } + public boolean isRecursive() { return recursive; } @@ -29,7 +71,6 @@ public void setRecursive(boolean recursive) { this.recursive = recursive; } - /** * The {@link SelectItem}s in this WITH (for example the A,B,C in "WITH mywith (A,B,C) AS ...") * @@ -44,47 +85,73 @@ public void setWithItemList(List> withItemList) { } @Override - @SuppressWarnings({"PMD.CyclomaticComplexity"}) - public StringBuilder appendSelectBodyTo(StringBuilder builder) { + public String toString() { + StringBuilder builder = new StringBuilder(); builder.append(recursive ? "RECURSIVE " : ""); - builder.append(alias.getName()); - builder.append( - (withItemList != null) ? " " + PlainSelect.getStringList(withItemList, true, true) - : ""); + if (alias != null) { + builder.append(alias.getName()); + } + if (withItemList != null) { + builder.append("("); + int size = withItemList.size(); + for (int i = 0; i < size; i++) { + builder.append(withItemList.get(i)).append(i < size - 1 ? "," : ""); + } + builder.append(")"); + } else { + builder.append(""); + } builder.append(" AS "); - - select.appendTo(builder); - - return builder; + builder.append(statement); + return builder.toString(); } - @Override public T accept(SelectVisitor selectVisitor, S context) { return selectVisitor.visit(this, context); } - - public WithItem withWithItemList(List> withItemList) { + public WithItem withWithItemList(List> withItemList) { this.setWithItemList(withItemList); return this; } - public WithItem withRecursive(boolean recursive) { + public WithItem withRecursive(boolean recursive) { this.setRecursive(recursive); return this; } - public WithItem addWithItemList(SelectItem... withItemList) { + public WithItem addWithItemList(SelectItem... withItemList) { List> collection = Optional.ofNullable(getWithItemList()).orElseGet(ArrayList::new); Collections.addAll(collection, withItemList); return this.withWithItemList(collection); } - public WithItem addWithItemList(Collection> withItemList) { + public WithItem addWithItemList(Collection> withItemList) { List> collection = Optional.ofNullable(getWithItemList()).orElseGet(ArrayList::new); collection.addAll(withItemList); return this.withWithItemList(collection); } + + public ParenthesedSelect getSelect() { + return (ParenthesedSelect) statement; + } + + public ParenthesedInsert getInsert() { + return (ParenthesedInsert) statement; + } + + public ParenthesedUpdate getUpdate() { + return (ParenthesedUpdate) statement; + } + + public ParenthesedDelete getDelete() { + return (ParenthesedDelete) statement; + } + + public void setSelect(ParenthesedSelect select) { + this.statement = (T) select; + } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/update/ParenthesedUpdate.java b/src/main/java/net/sf/jsqlparser/statement/update/ParenthesedUpdate.java new file mode 100644 index 000000000..8dc95c2eb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/update/ParenthesedUpdate.java @@ -0,0 +1,62 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.update; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class ParenthesedUpdate extends Update implements ParenthesedStatement { + + Alias alias; + Update update; + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + public ParenthesedUpdate withAlias(Alias alias) { + this.setAlias(alias); + return this; + } + + public Update getUpdate() { + return update; + } + + public void setUpdate(Update update) { + this.update = update; + } + + public ParenthesedUpdate withUpdate(Update update) { + setUpdate(update); + return this; + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("(").append(update).append(")"); + if (alias != null) { + builder.append(alias); + } + return builder.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/update/Update.java b/src/main/java/net/sf/jsqlparser/statement/update/Update.java index 64da8f64e..2d948afda 100644 --- a/src/main/java/net/sf/jsqlparser/statement/update/Update.java +++ b/src/main/java/net/sf/jsqlparser/statement/update/Update.java @@ -36,7 +36,7 @@ @SuppressWarnings({"PMD.CyclomaticComplexity"}) public class Update implements Statement { - private List withItemsList; + private List> withItemsList; private Table table; private Expression where; private List updateSets; @@ -82,28 +82,28 @@ public T accept(StatementVisitor statementVisitor, S context) { return statementVisitor.visit(this, context); } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } - public Update withWithItemsList(List withItemsList) { + public Update withWithItemsList(List> withItemsList) { this.setWithItemsList(withItemsList); return this; } - public Update addWithItemsList(WithItem... withItemsList) { - List collection = + public Update addWithItemsList(WithItem... withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); Collections.addAll(collection, withItemsList); return this.withWithItemsList(collection); } - public Update addWithItemsList(Collection withItemsList) { - List collection = + public Update addWithItemsList(Collection> withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); collection.addAll(withItemsList); return this.withWithItemsList(collection); @@ -282,8 +282,8 @@ public String toString() { if (withItemsList != null && !withItemsList.isEmpty()) { b.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); b.append(withItem); if (iter.hasNext()) { b.append(","); diff --git a/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java b/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java index 17e5ed428..80f6bb6dd 100644 --- a/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java +++ b/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java @@ -100,7 +100,7 @@ public void setPrefix(String prefix) { } @Override - public T visit(WithItem withItem, S context) { + public T visit(WithItem withItem, S context) { throw new UnsupportedOperationException(NOT_SUPPORTED_YET); } diff --git a/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java b/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java index 903b5d722..3f0377728 100644 --- a/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java +++ b/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java @@ -99,7 +99,7 @@ public T visit(SetOperationList setOpList, S context) { } @Override - public T visit(WithItem withItem, S context) { + public T visit(WithItem withItem, S context) { return null; } diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 8635ecfc2..ad5e10495 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -144,10 +144,12 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; import net.sf.jsqlparser.statement.grant.Grant; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.AllColumns; @@ -171,6 +173,7 @@ import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.update.UpdateSet; import net.sf.jsqlparser.statement.upsert.Upsert; @@ -246,9 +249,9 @@ public Set getTablesOrOtherSources(Statement statement) { @Override public Void visit(Select select, S context) { - List withItemsList = select.getWithItemsList(); + List> withItemsList = select.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { + for (WithItem withItem : withItemsList) { withItem.accept((SelectVisitor) this, context); } } @@ -300,14 +303,14 @@ public Set getTables(Expression expr) { } @Override - public Void visit(WithItem withItem, S context) { + public Void visit(WithItem withItem, S context) { otherItemNames.add(withItem.getAlias().getName()); withItem.getSelect().accept((SelectVisitor) this, context); return null; } @Override - public void visit(WithItem withItem) { + public void visit(WithItem withItem) { SelectVisitor.super.visit(withItem); } @@ -316,9 +319,9 @@ public Void visit(ParenthesedSelect select, S context) { if (select.getAlias() != null) { otherItemNames.add(select.getAlias().getName()); } - List withItemsList = select.getWithItemsList(); + List> withItemsList = select.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { + for (WithItem withItem : withItemsList) { withItem.accept((SelectVisitor) this, context); } } @@ -333,9 +336,9 @@ public void visit(ParenthesedSelect parenthesedSelect) { @Override public Void visit(PlainSelect plainSelect, S context) { - List withItemsList = plainSelect.getWithItemsList(); + List> withItemsList = plainSelect.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { + for (WithItem withItem : withItemsList) { withItem.accept((SelectVisitor) this, context); } } @@ -790,9 +793,9 @@ public Void visit(AnalyticExpression analytic, S context) { @Override public Void visit(SetOperationList list, S context) { - List withItemsList = list.getWithItemsList(); + List> withItemsList = list.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { + for (WithItem withItem : withItemsList) { withItem.accept((SelectVisitor) this, context); } } @@ -983,10 +986,15 @@ public void visit(Delete delete) { StatementVisitor.super.visit(delete); } + @Override + public Void visit(ParenthesedDelete delete, S context) { + return visit(delete.getDelete(), context); + } + @Override public Void visit(Update update, S context) { if (update.getWithItemsList() != null) { - for (WithItem withItem : update.getWithItemsList()) { + for (WithItem withItem : update.getWithItemsList()) { withItem.accept((SelectVisitor) this, context); } } @@ -1025,6 +1033,11 @@ public Void visit(Update update, S context) { return null; } + @Override + public Void visit(ParenthesedUpdate update, S context) { + return visit(update.getUpdate(), context); + } + @Override public void visit(Update update) { StatementVisitor.super.visit(update); @@ -1034,7 +1047,7 @@ public void visit(Update update) { public Void visit(Insert insert, S context) { visit(insert.getTable(), context); if (insert.getWithItemsList() != null) { - for (WithItem withItem : insert.getWithItemsList()) { + for (WithItem withItem : insert.getWithItemsList()) { withItem.accept((SelectVisitor) this, context); } } @@ -1044,6 +1057,11 @@ public Void visit(Insert insert, S context) { return null; } + @Override + public Void visit(ParenthesedInsert insert, S context) { + return visit(insert.getInsert(), context); + } + @Override public void visit(Insert insert) { StatementVisitor.super.visit(insert); @@ -1231,7 +1249,7 @@ public Void visit(HexValue hexValue, S context) { public Void visit(Merge merge, S context) { visit(merge.getTable(), context); if (merge.getWithItemsList() != null) { - for (WithItem withItem : merge.getWithItemsList()) { + for (WithItem withItem : merge.getWithItemsList()) { withItem.accept((SelectVisitor) this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java index 52e5a6671..36fe3c0c8 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java @@ -40,8 +40,9 @@ public DeleteDeParser(ExpressionVisitor expressionVisitor, public void deParse(Delete delete) { if (delete.getWithItemsList() != null && !delete.getWithItemsList().isEmpty()) { buffer.append("WITH "); - for (Iterator iter = delete.getWithItemsList().iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = delete.getWithItemsList().iterator(); iter + .hasNext();) { + WithItem withItem = iter.next(); buffer.append(withItem); if (iter.hasNext()) { buffer.append(","); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index 65ea93489..bb6b6a146 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -633,7 +633,7 @@ public StringBuilder visit(Select select, S context) { if (selectVisitor != null) { if (select.getWithItemsList() != null) { buffer.append("WITH "); - for (Iterator iter = select.getWithItemsList().iterator(); iter + for (Iterator> iter = select.getWithItemsList().iterator(); iter .hasNext();) { iter.next().accept(selectVisitor, null); if (iter.hasNext()) { diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java index b3f8e4abb..b9aa7bb65 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java @@ -41,8 +41,9 @@ public InsertDeParser(ExpressionVisitor expressionVisitor, public void deParse(Insert insert) { if (insert.getWithItemsList() != null && !insert.getWithItemsList().isEmpty()) { buffer.append("WITH "); - for (Iterator iter = insert.getWithItemsList().iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = insert.getWithItemsList().iterator(); iter + .hasNext();) { + WithItem withItem = iter.next(); withItem.accept(this.selectVisitor, null); if (iter.hasNext()) { buffer.append(","); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java index 36cda69a4..09bb0cfc5 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java @@ -30,11 +30,11 @@ public MergeDeParser(ExpressionDeParser expressionDeParser, SelectDeParser selec @Override public void deParse(Merge merge) { - List withItemsList = merge.getWithItemsList(); + List> withItemsList = merge.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { buffer.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - iter.next().accept(expressionDeParser, null); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + iter.next().accept(selectDeParser, null); if (iter.hasNext()) { buffer.append(","); } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index 705db155c..c56f396d4 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -93,10 +93,10 @@ public SelectDeParser(ExpressionVisitor expressionVisitor, @Override public StringBuilder visit(ParenthesedSelect select, S context) { - List withItemsList = select.getWithItemsList(); + List> withItemsList = select.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { buffer.append("WITH "); - for (WithItem withItem : withItemsList) { + for (WithItem withItem : withItemsList) { withItem.accept((SelectVisitor) this, context); buffer.append(" "); } @@ -147,10 +147,10 @@ public void visit(Top top) { @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength", "PMD.NPathComplexity"}) public StringBuilder visit(PlainSelect plainSelect, S context) { - List withItemsList = plainSelect.getWithItemsList(); + List> withItemsList = plainSelect.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { buffer.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { iter.next().accept((SelectVisitor) this, context); if (iter.hasNext()) { buffer.append(","); @@ -602,10 +602,10 @@ public void deparseLateralView(LateralView lateralView) { @Override public StringBuilder visit(SetOperationList list, S context) { - List withItemsList = list.getWithItemsList(); + List> withItemsList = list.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { buffer.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { iter.next().accept((SelectVisitor) this, context); if (iter.hasNext()) { buffer.append(","); @@ -640,7 +640,7 @@ public StringBuilder visit(SetOperationList list, S context) { } @Override - public StringBuilder visit(WithItem withItem, S context) { + public StringBuilder visit(WithItem withItem, S context) { if (withItem.isRecursive()) { buffer.append("RECURSIVE "); } @@ -650,7 +650,9 @@ public StringBuilder visit(WithItem withItem, S context) { .append(PlainSelect.getStringList(withItem.getWithItemList(), true, true)); } buffer.append(" AS "); - withItem.getSelect().accept(this, context); + StatementDeParser statementDeParser = + new StatementDeParser((ExpressionDeParser) expressionVisitor, this, buffer); + statementDeParser.deParse(withItem.getParenthesedStatement()); return buffer; } @@ -748,7 +750,7 @@ public void visit(SetOperationList list) { visit(list, null); } - public void visit(WithItem withItem) { + public void visit(WithItem withItem) { visit(withItem, null); } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java index 17babd34e..d4cff2a58 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.util.deparser; import java.lang.reflect.InvocationTargetException; +import java.util.List; import java.util.stream.Collectors; import net.sf.jsqlparser.schema.Table; @@ -47,16 +48,21 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; import net.sf.jsqlparser.statement.grant.Grant; import net.sf.jsqlparser.statement.insert.Insert; -import net.sf.jsqlparser.statement.merge.*; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectVisitor; +import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; @@ -165,6 +171,47 @@ public StringBuilder visit(Insert insert, S context) { return buffer; } + @Override + public StringBuilder visit(ParenthesedInsert insert, S context) { + List> withItemsList = insert.getWithItemsList(); + addWithItemsToBuffer(withItemsList, context); + buffer.append("("); + insert.getInsert().accept(this, context); + buffer.append(")"); + return buffer; + } + + @Override + public StringBuilder visit(ParenthesedUpdate update, S context) { + List> withItemsList = update.getWithItemsList(); + addWithItemsToBuffer(withItemsList, context); + buffer.append("("); + update.getUpdate().accept(this, context); + buffer.append(")"); + return buffer; + } + + @Override + public StringBuilder visit(ParenthesedDelete delete, S context) { + List> withItemsList = delete.getWithItemsList(); + addWithItemsToBuffer(withItemsList, context); + buffer.append("("); + delete.getDelete().accept(this, context); + buffer.append(")"); + return buffer; + } + + private StringBuilder addWithItemsToBuffer(List> withItemsList, S context) { + if (withItemsList != null && !withItemsList.isEmpty()) { + buffer.append("WITH "); + for (WithItem withItem : withItemsList) { + withItem.accept((SelectVisitor) this, context); + buffer.append(" "); + } + } + return buffer; + } + @Override public StringBuilder visit(Select select, S context) { select.accept(selectDeParser, context); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java index be83df5bb..e187faaab 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java @@ -67,7 +67,7 @@ public StringBuilder visit(SetOperationList setOperationList, S context) { } @Override - public StringBuilder visit(WithItem withItem, S context) { + public StringBuilder visit(WithItem withItem, S context) { return buffer; } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java index 682c1c067..071ceeca5 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java @@ -40,8 +40,9 @@ public UpdateDeParser(ExpressionVisitor expressionVisitor, public void deParse(Update update) { if (update.getWithItemsList() != null && !update.getWithItemsList().isEmpty()) { buffer.append("WITH "); - for (Iterator iter = update.getWithItemsList().iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = update.getWithItemsList().iterator(); iter + .hasNext();) { + WithItem withItem = iter.next(); buffer.append(withItem); if (iter.hasNext()) { buffer.append(","); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java index 4ed464ddc..a908adebd 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java @@ -303,7 +303,7 @@ public Void visit(SetOperationList setOperation, S context) { } @Override - public Void visit(WithItem withItem, S context) { + public Void visit(WithItem withItem, S context) { for (ValidationCapability c : getCapabilities()) { validateFeature(c, Feature.withItem); validateFeature(c, withItem.isRecursive(), Feature.withItemRecursive); @@ -311,7 +311,7 @@ public Void visit(WithItem withItem, S context) { if (isNotEmpty(withItem.getWithItemList())) { withItem.getWithItemList().forEach(wi -> wi.accept(this, context)); } - withItem.getSelect().accept(this, context); + withItem.getSelect().accept((SelectVisitor) this, context); return null; } @@ -393,7 +393,7 @@ public void visit(SetOperationList setOperation) { visit(setOperation, null); } - public void visit(WithItem withItem) { + public void visit(WithItem withItem) { visit(withItem, null); } @@ -416,4 +416,5 @@ public void visit(ParenthesedFromItem parenthesis) { public void visit(Values values) { visit(values, null); } + } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java index 44e2f1f79..3c84aa60e 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java @@ -46,16 +46,19 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; import net.sf.jsqlparser.statement.grant.Grant; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; import net.sf.jsqlparser.util.validation.ValidationCapability; @@ -103,6 +106,11 @@ public Void visit(Delete delete, S context) { return null; } + @Override + public Void visit(ParenthesedDelete delete, S context) { + return visit(delete.getDelete(), context); + } + @Override public Void visit(Drop drop, S context) { getValidator(DropValidator.class).validate(drop); @@ -115,6 +123,11 @@ public Void visit(Insert insert, S context) { return null; } + @Override + public Void visit(ParenthesedInsert insert, S context) { + return visit(insert.getInsert(), context); + } + @Override public Void visit(Select select, S context) { validateFeature(Feature.select); @@ -137,6 +150,11 @@ public Void visit(Update update, S context) { return null; } + @Override + public Void visit(ParenthesedUpdate update, S context) { + return visit(update.getUpdate(), context); + } + @Override public Void visit(Alter alter, S context) { getValidator(AlterValidator.class).validate(alter); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 285b42185..9cfb81eb6 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -743,7 +743,7 @@ Statement Statement() #Statement: Statement SingleStatement() : { Statement stm = null; - List with = null; + List> with = null; } { ( @@ -752,13 +752,13 @@ Statement SingleStatement() : ( stm = SelectWithWithItems( with ) | - stm = Insert( with ) + stm = InsertWithWithItems( with ) | - stm = Update( with ) + stm = UpdateWithWithItems( with ) | - stm = Delete( with ) + stm = DeleteWithWithItems( with ) | - stm = Merge( with) + stm = Merge( with ) ) ) | @@ -1455,12 +1455,22 @@ ReturningClause ReturningClause(): } } -Update Update( List with ): +Update UpdateWithWithItems( List> withItems ): +{ + Update update; +} +{ + update = Update() { update.setWithItemsList( withItems ); + return update; +} +} + +Update Update(): { Update update = new Update(); Table table = null; List startJoins = null; - + List> with = null; List updateSets; Expression where = null; FromItem fromItem = null; @@ -1558,10 +1568,21 @@ List UpdateSets(): } } -Insert Insert( List with ): +Insert InsertWithWithItems( List> withItems ): +{ + Insert insert; +} +{ + insert = Insert() { insert.setWithItemsList( withItems ); + return insert; +} +} + +Insert Insert(): { Insert insert = new Insert(); Table table = null; + List> with = null; Column tableColumn = null; ExpressionList columns = new ExpressionList(); Expression exp = null; @@ -1762,11 +1783,22 @@ Upsert Upsert(): } } -Delete Delete( List with ): +Delete DeleteWithWithItems( List> withItems ): +{ + Delete delete; +} +{ + delete = Delete() { delete.setWithItemsList( withItems ); + return delete; +} +} + +Delete Delete(): { Delete delete = new Delete(); Table table = null; List
tables = new ArrayList
(); + List> with = null; Table usingTable = null; List
usingList = new ArrayList
(); List joins = null; @@ -1815,7 +1847,7 @@ Delete Delete( List with ): } } -Statement Merge( List with ) : { +Statement Merge( List> with ) : { Merge merge = new Merge(); Table table; FromItem fromItem; @@ -2120,7 +2152,7 @@ SampleClause SampleClause(): } } -Select SelectWithWithItems( List withItems): +Select SelectWithWithItems( List> withItems): { Select select; } @@ -2133,7 +2165,7 @@ Select SelectWithWithItems( List withItems): Select Select() #Select: { Select select = null; - List with = null; + List> with = null; List orderByElements = null; Limit limit = null; Offset offset = null; @@ -2197,6 +2229,48 @@ ParenthesedSelect ParenthesedSelect() #ParenthesedSelect: } } +ParenthesedInsert ParenthesedInsert() #ParenthesedInsert: +{ + ParenthesedInsert parenthesedInsert = new ParenthesedInsert(); + Insert insert; +} +{ + "(" + insert = Insert() + ")" + { + return parenthesedInsert.withInsert(insert); + } +} + +ParenthesedUpdate ParenthesedUpdate() #ParenthesedUpdate: +{ + ParenthesedUpdate parenthesedUpdate = new ParenthesedUpdate(); + Update update; +} +{ + "(" + update = Update() + ")" + { + return parenthesedUpdate.withUpdate(update); + } +} + +ParenthesedDelete ParenthesedDelete() #ParenthesedDelete: +{ + ParenthesedDelete parenthesedDelete = new ParenthesedDelete(); + Delete delete; +} +{ + "(" + delete = Delete() + ")" + { + return parenthesedDelete.withDelete(delete); + } +} + LateralView LateralView() #LateralView: { boolean useOuter = false; @@ -2550,9 +2624,9 @@ Select SetOperationList(Select select) #SetOperationList: { } } -List WithList(): +List> WithList(): { - List withItemsList = new ArrayList(); + List> withItemsList = new ArrayList>(); WithItem with = null; } { @@ -2561,20 +2635,32 @@ List WithList(): { return withItemsList; } } -WithItem WithItem() #WithItem: +WithItem WithItem() #WithItem: { - WithItem withItem = new WithItem(); + boolean recursive = false; String name; - List> selectItems; - Select select; + List> selectItems = null; + ParenthesedStatement statement; } { - [ LOOKAHEAD(2) { withItem.setRecursive(true); } ] - name=RelObjectName() { withItem.setAlias( new Alias( name, false)); } - [ "(" selectItems=SelectItemsList() ")" { withItem.setWithItemList(selectItems); } ] - select = ParenthesedSelect() { withItem.setSelect(select); } + [ LOOKAHEAD(2) { recursive = true; } ] + name=RelObjectName() + [ "(" selectItems=SelectItemsList() ")" ] + + ( + LOOKAHEAD(2) statement = ParenthesedSelect() + | + LOOKAHEAD(2) statement = ParenthesedInsert() + | + LOOKAHEAD(2) statement = ParenthesedUpdate() + | + LOOKAHEAD(2) statement = ParenthesedDelete() + ) { - return withItem; + WithItem withItem = new WithItem(statement, new Alias(name, false)); + return withItem + .withRecursive(recursive) + .withWithItemList(selectItems); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java index c9a3030aa..a02137a19 100644 --- a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java @@ -25,8 +25,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.statement.select.WithItem; +import net.sf.jsqlparser.statement.update.Update; import org.junit.jupiter.api.Test; public class DeleteTest { @@ -124,14 +127,16 @@ public void testWith() throws JSQLParserException { + "WHERE id_instrument_ref = (SELECT id_instrument_ref\n" + " FROM a)"; Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(statement, true); - List withItems = delete.getWithItemsList(); + List> withItems = delete.getWithItemsList(); assertEquals("cfe.instrument_ref", delete.getTable().getFullyQualifiedName()); assertEquals(2, withItems.size()); - SelectItem selectItem1 = withItems.get(0).getSelect().getPlainSelect().getSelectItems().get(0); + SelectItem selectItem1 = + withItems.get(0).getSelect().getPlainSelect().getSelectItems().get(0); assertEquals("1", selectItem1.getExpression().toString()); assertEquals(" id_instrument_ref", selectItem1.getAlias().toString()); assertEquals(" a", withItems.get(0).getAlias().toString()); - SelectItem selectItem2 = withItems.get(1).getSelect().getPlainSelect().getSelectItems().get(0); + SelectItem selectItem2 = + withItems.get(1).getSelect().getPlainSelect().getSelectItems().get(0); assertEquals("1", selectItem2.getExpression().toString()); assertEquals(" id_instrument_ref", selectItem2.getAlias().toString()); assertEquals(" b", withItems.get(1).getAlias().toString()); @@ -227,6 +232,143 @@ public void testDeleteOutputClause() throws JSQLParserException { " ON ph.ProductID = p.ProductID \n" + " WHERE p.ProductModelID BETWEEN 120 and 130", true); + } + @Test + void testInsertWithinCte() throws JSQLParserException { + String sqlStr = "WITH inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " RETURNING y " + + ") " + + "DELETE " + + " FROM z" + + " WHERE y IN (SELECT y FROM inserted)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(1, withItems.size()); + Insert insert = withItems.get(0).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b", insert.getSelect().toString()); + assertEquals(" RETURNING y", insert.getReturningClause().toString()); + assertEquals("INSERT INTO x (foo) SELECT bar FROM b RETURNING y", insert.toString()); + assertEquals(" inserted", withItems.get(0).getAlias().toString()); + } + + @Test + void testUpdateWithinCte() throws JSQLParserException { + String sqlStr = "WITH updated AS ( " + + " UPDATE x " + + " SET foo = 1 " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "DELETE " + + " FROM z" + + " WHERE y IN (SELECT y FROM updated)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(1, withItems.size()); + Update update = withItems.get(0).getUpdate().getUpdate(); + assertEquals("x", update.getTable().toString()); + assertEquals("foo", update.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("1", update.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("bar = 2", update.getWhere().toString()); + assertEquals(" RETURNING y", update.getReturningClause().toString()); + assertEquals(" updated", withItems.get(0).getAlias().toString()); } + + @Test + void testDeleteWithinCte() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "DELETE " + + " FROM z" + + " WHERE y IN (SELECT y FROM deleted)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(1, withItems.size()); + Delete innerDelete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", innerDelete.getTable().toString()); + assertEquals("bar = 2", innerDelete.getWhere().toString()); + assertEquals(" RETURNING y", innerDelete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM deleted) " + + " RETURNING w " + + ") " + + "DELETE " + + " FROM z" + + " WHERE w IN (SELECT w FROM inserted)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(2, withItems.size()); + Delete innerDelete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", innerDelete.getTable().toString()); + assertEquals("bar = 2", innerDelete.getWhere().toString()); + assertEquals(" RETURNING y", innerDelete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM deleted)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM deleted) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testSelectAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH selection AS ( " + + " SELECT y " + + " FROM z " + + " WHERE foo = 'bar' " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM selection) " + + " RETURNING w " + + ") " + + "DELETE " + + " FROM z" + + " WHERE w IN (SELECT w FROM inserted)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(2, withItems.size()); + PlainSelect innerSelect = withItems.get(0).getSelect().getPlainSelect(); + assertEquals("SELECT y FROM z WHERE foo = 'bar'", innerSelect.toString()); + assertEquals(" selection", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM selection)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM selection) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + } diff --git a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java index 3bec29069..421f6b629 100644 --- a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java @@ -23,7 +23,9 @@ import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.delete.Delete; import net.sf.jsqlparser.statement.select.*; +import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.update.UpdateSet; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -277,25 +279,29 @@ public void testInsertSelect() throws JSQLParserException { @Test public void testInsertWithSelect() throws JSQLParserException { - String sqlStr1 = "INSERT INTO mytable (mycolumn) WITH a AS (SELECT mycolumn FROM mytable) SELECT mycolumn FROM a"; + String sqlStr1 = + "INSERT INTO mytable (mycolumn) WITH a AS (SELECT mycolumn FROM mytable) SELECT mycolumn FROM a"; Insert insert1 = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr1, true); - List insertWithItems1 = insert1.getWithItemsList(); - List selectWithItems1 = insert1.getSelect().getWithItemsList(); + List> insertWithItems1 = insert1.getWithItemsList(); + List> selectWithItems1 = insert1.getSelect().getWithItemsList(); assertEquals("mytable", insert1.getTable().getFullyQualifiedName()); assertNull(insertWithItems1); assertEquals(1, selectWithItems1.size()); - assertEquals("SELECT mycolumn FROM mytable", selectWithItems1.get(0).getSelect().getPlainSelect().toString()); + assertEquals("SELECT mycolumn FROM mytable", + selectWithItems1.get(0).getSelect().getPlainSelect().toString()); assertEquals(" a", selectWithItems1.get(0).getAlias().toString()); - String sqlStr2 = "INSERT INTO mytable (mycolumn) (WITH a AS (SELECT mycolumn FROM mytable) SELECT mycolumn FROM a)"; + String sqlStr2 = + "INSERT INTO mytable (mycolumn) (WITH a AS (SELECT mycolumn FROM mytable) SELECT mycolumn FROM a)"; Insert insert2 = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr2, true); - List insertWithItems2 = insert2.getWithItemsList(); + List> insertWithItems2 = insert2.getWithItemsList(); assertEquals("mytable", insert2.getTable().getFullyQualifiedName()); assertNull(insertWithItems2); ParenthesedSelect select = (ParenthesedSelect) insert2.getSelect(); - List selectWithItems2 = select.getSelect().getWithItemsList(); + List> selectWithItems2 = select.getSelect().getWithItemsList(); assertEquals(1, selectWithItems2.size()); - assertEquals("SELECT mycolumn FROM mytable", selectWithItems2.get(0).getSelect().getPlainSelect().toString()); + assertEquals("SELECT mycolumn FROM mytable", + selectWithItems2.get(0).getSelect().getPlainSelect().toString()); assertEquals(" a", selectWithItems2.get(0).getAlias().toString()); } @@ -362,15 +368,17 @@ public void testKeywordPrecisionIssue363() throws JSQLParserException { @Test public void testWithDeparsingIssue406() throws JSQLParserException { - String sqlStr = "insert into mytab3 (a,b,c) select a,b,c from mytab where exists(with t as (select * from mytab2) select * from t)"; + String sqlStr = + "insert into mytab3 (a,b,c) select a,b,c from mytab where exists(with t as (select * from mytab2) select * from t)"; Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); - List insertWithItems = insert.getWithItemsList(); - List selectWithItems = insert.getSelect().getWithItemsList(); + List> insertWithItems = insert.getWithItemsList(); + List> selectWithItems = insert.getSelect().getWithItemsList(); assertEquals("mytab3", insert.getTable().getFullyQualifiedName()); assertNull(insertWithItems); assertNull(selectWithItems); ExistsExpression exists = (ExistsExpression) insert.getPlainSelect().getWhere(); - assertEquals("(WITH t AS (SELECT * FROM mytab2) SELECT * FROM t)", exists.getRightExpression().toString()); + assertEquals("(WITH t AS (SELECT * FROM mytab2) SELECT * FROM t)", + exists.getRightExpression().toString()); } @Test @@ -410,12 +418,14 @@ public void testInsertKeyWordIntervalIssue682() throws JSQLParserException { @Test public void testWithAtFront() throws JSQLParserException { - String sqlStr = "WITH foo AS ( SELECT attr FROM bar ) INSERT INTO lalelu (attr) SELECT attr FROM foo"; + String sqlStr = + "WITH foo AS ( SELECT attr FROM bar ) INSERT INTO lalelu (attr) SELECT attr FROM foo"; Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); - List insertWithItems = insert.getWithItemsList(); + List> insertWithItems = insert.getWithItemsList(); assertEquals("lalelu", insert.getTable().getFullyQualifiedName()); assertEquals(1, insertWithItems.size()); - assertEquals("SELECT attr FROM bar", insertWithItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals("SELECT attr FROM bar", + insertWithItems.get(0).getSelect().getPlainSelect().toString()); assertEquals(" foo", insertWithItems.get(0).getAlias().toString()); assertEquals("SELECT attr FROM foo", insert.getSelect().toString()); assertEquals("foo", insert.getSelect().getPlainSelect().getFromItem().toString()); @@ -454,12 +464,14 @@ public void testDisableKeywordIssue945() throws JSQLParserException { @Test public void testWithListIssue282() throws JSQLParserException { - String sqlStr = "WITH myctl AS (SELECT a, b FROM mytable) INSERT INTO mytable SELECT a, b FROM myctl"; + String sqlStr = + "WITH myctl AS (SELECT a, b FROM mytable) INSERT INTO mytable SELECT a, b FROM myctl"; Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); - List insertWithItems = insert.getWithItemsList(); + List> insertWithItems = insert.getWithItemsList(); assertEquals("mytable", insert.getTable().getFullyQualifiedName()); assertEquals(1, insertWithItems.size()); - assertEquals("SELECT a, b FROM mytable", insertWithItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals("SELECT a, b FROM mytable", + insertWithItems.get(0).getSelect().getPlainSelect().toString()); assertEquals(" myctl", insertWithItems.get(0).getAlias().toString()); assertEquals("SELECT a, b FROM myctl", insert.getSelect().toString()); assertEquals("myctl", insert.getSelect().getPlainSelect().getFromItem().toString()); @@ -508,10 +520,12 @@ public void testInsertUnionSelectIssue1491() throws JSQLParserException { @Test public void testWithSelectFromDual() throws JSQLParserException { String sqlStr = "(with a as (select * from dual) select * from a)"; - ParenthesedSelect parenthesedSelect = (ParenthesedSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); - List withItems = parenthesedSelect.getSelect().getWithItemsList(); + ParenthesedSelect parenthesedSelect = + (ParenthesedSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + List> withItems = parenthesedSelect.getSelect().getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("SELECT * FROM dual", withItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals("SELECT * FROM dual", + withItems.get(0).getSelect().getPlainSelect().toString()); assertEquals(" a", withItems.get(0).getAlias().toString()); assertEquals("a", parenthesedSelect.getPlainSelect().getFromItem().toString()); assertEquals("[*]", parenthesedSelect.getPlainSelect().getSelectItems().toString()); @@ -573,10 +587,11 @@ public void insertOnConflictObjectsTest() throws JSQLParserException { String sqlStr = "WITH a ( a, b , c ) \n" + "AS (SELECT 1 , 2 , 3 )\n" + "insert into test\n" + "select * from a"; Insert insert = (Insert) CCJSqlParserUtil.parse(sqlStr); - List withItems = insert.getWithItemsList(); + List> withItems = insert.getWithItemsList(); assertEquals("test", insert.getTable().getFullyQualifiedName()); assertEquals(1, withItems.size()); - assertEquals("[1, 2, 3]", withItems.get(0).getSelect().getPlainSelect().getSelectItems().toString()); + assertEquals("[1, 2, 3]", + withItems.get(0).getSelect().getPlainSelect().getSelectItems().toString()); assertEquals(" a", withItems.get(0).getAlias().toString()); Expression whereExpression = CCJSqlParserUtil.parseExpression("a=1", false); @@ -645,7 +660,7 @@ void testMultiColumnConflictTargetIssue955() throws JSQLParserException { @Test public void testDefaultValues() throws JSQLParserException { String statement = "INSERT INTO mytable DEFAULT VALUES"; - //assertSqlCanBeParsedAndDeparsed(statement); + // assertSqlCanBeParsedAndDeparsed(statement); Insert insert = (Insert) parserManager.parse(new StringReader(statement)); assertEquals("mytable", insert.getTable().getFullyQualifiedName()); assertEquals("INSERT INTO MYTABLE DEFAULT VALUES", insert.toString().toUpperCase()); @@ -690,4 +705,136 @@ public void throwsParseWhenDefaultKeyowrdUsedAsAlias() { () -> parserManager.parse(new StringReader(statement))); } + @Test + void testInsertWithinCte() throws JSQLParserException { + String sqlStr = "WITH inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " RETURNING y " + + ") " + + "INSERT INTO z (blah) " + + "SELECT y FROM inserted"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(1, withItems.size()); + Insert innerInsert = withItems.get(0).getInsert().getInsert(); + assertEquals("x", innerInsert.getTable().toString()); + assertEquals("SELECT bar FROM b", innerInsert.getSelect().toString()); + assertEquals(" RETURNING y", innerInsert.getReturningClause().toString()); + assertEquals("INSERT INTO x (foo) SELECT bar FROM b RETURNING y", innerInsert.toString()); + assertEquals(" inserted", withItems.get(0).getAlias().toString()); + } + + @Test + void testUpdateWithinCte() throws JSQLParserException { + String sqlStr = "WITH updated AS ( " + + " UPDATE x " + + " SET foo = 1 " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "INSERT INTO z (blah) " + + "SELECT y FROM updated"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(1, withItems.size()); + Update update = withItems.get(0).getUpdate().getUpdate(); + assertEquals("x", update.getTable().toString()); + assertEquals("foo", update.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("1", update.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("bar = 2", update.getWhere().toString()); + assertEquals(" RETURNING y", update.getReturningClause().toString()); + assertEquals(" updated", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteWithinCte() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "INSERT INTO z (blah) " + + "SELECT y FROM deleted"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(1, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM deleted) " + + " RETURNING w " + + ") " + + "INSERT INTO z (blah) " + + "SELECT w FROM inserted"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(2, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + Insert innerInsert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", innerInsert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM deleted)", + innerInsert.getSelect().toString()); + assertEquals(" RETURNING w", innerInsert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM deleted) RETURNING w", + innerInsert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testSelectAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH selection AS ( " + + " SELECT y " + + " FROM z " + + " WHERE foo = 'bar' " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM selection) " + + " RETURNING w " + + ") " + + "INSERT INTO z (blah) " + + "SELECT w FROM inserted"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(2, withItems.size()); + PlainSelect select = withItems.get(0).getSelect().getPlainSelect(); + assertEquals("SELECT y FROM z WHERE foo = 'bar'", select.toString()); + assertEquals(" selection", withItems.get(0).getAlias().toString()); + Insert innerInsert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", innerInsert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM selection)", + innerInsert.getSelect().toString()); + assertEquals(" RETURNING w", innerInsert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM selection) RETURNING w", + innerInsert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java index 83a4fe7ae..51b041470 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java @@ -128,7 +128,8 @@ public void testRecursiveBracketExpressionIssue1019() { // @todo: implement methods to set the Parser Timeout explicitly and on demand @Test public void testRecursiveBracketExpressionIssue1019_2() throws JSQLParserException { - doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 8); + // Temporally set the maxDepth to be 6, was 8 before this + doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 6); } @Test @@ -167,7 +168,8 @@ public void testIssue1013_4() throws JSQLParserException { */ // @Test(timeout = 6000) public void testIncreaseOfParseTime() throws JSQLParserException { - doIncreaseOfParseTimeTesting("concat($1,'B')", "'A'", 50); + // Temporally set the maxDepth to be 6, was 50 before this + doIncreaseOfParseTimeTesting("concat($1,'B')", "'A'", 6); } private void doIncreaseOfParseTimeTesting(String template, String finalExpression, int maxDepth) diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java index e000a6346..3e7cd9fd4 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -66,6 +66,9 @@ import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitorAdapter; import net.sf.jsqlparser.statement.Statements; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.test.TestUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.SerializationUtils; @@ -1702,21 +1705,26 @@ public void testWith() throws JSQLParserException { + "FROM EMPLOYEE AS THIS_EMP INNER JOIN DINFO INNER JOIN DINFOMAX " + "WHERE THIS_EMP.JOB = 'SALESREP' AND THIS_EMP.WORKDEPT = DINFO.DEPTNO"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(statement); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(2, withItems.size()); - assertEquals("SELECT OTHERS.WORKDEPT, AVG(OTHERS.SALARY), COUNT(*) FROM EMPLOYEE AS OTHERS GROUP BY OTHERS.WORKDEPT", withItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals( + "SELECT OTHERS.WORKDEPT, AVG(OTHERS.SALARY), COUNT(*) FROM EMPLOYEE AS OTHERS GROUP BY OTHERS.WORKDEPT", + withItems.get(0).getSelect().getPlainSelect().toString()); assertEquals(" DINFO", withItems.get(0).getAlias().toString()); - assertEquals("SELECT MAX(AVGSALARY) AS AVGMAX FROM DINFO", withItems.get(1).getSelect().getPlainSelect().toString()); + assertEquals("SELECT MAX(AVGSALARY) AS AVGMAX FROM DINFO", + withItems.get(1).getSelect().getPlainSelect().toString()); assertEquals(" DINFOMAX", withItems.get(1).getAlias().toString()); } @Test public void testWithRecursive() throws JSQLParserException { - String statement = "WITH RECURSIVE t (n) AS ((SELECT 1) UNION ALL (SELECT n + 1 FROM t WHERE n < 100)) SELECT sum(n) FROM t"; + String statement = + "WITH RECURSIVE t (n) AS ((SELECT 1) UNION ALL (SELECT n + 1 FROM t WHERE n < 100)) SELECT sum(n) FROM t"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(statement); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("((SELECT 1) UNION ALL (SELECT n + 1 FROM t WHERE n < 100))", withItems.get(0).getSelect().toString()); + assertEquals("((SELECT 1) UNION ALL (SELECT n + 1 FROM t WHERE n < 100))", + withItems.get(0).getSelect().toString()); assertEquals(" t", withItems.get(0).getAlias().toString()); assertTrue(withItems.get(0).isRecursive()); } @@ -2373,9 +2381,10 @@ public void testWithStatement() throws JSQLParserException { String stmt = "WITH test AS (SELECT mslink FROM feature) SELECT * FROM feature WHERE mslink IN (SELECT mslink FROM test)"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("SELECT mslink FROM feature", withItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals("SELECT mslink FROM feature", + withItems.get(0).getSelect().getPlainSelect().toString()); assertEquals(" test", withItems.get(0).getAlias().toString()); } @@ -2390,9 +2399,10 @@ public void testWithUnionProblem() throws JSQLParserException { String stmt = "WITH test AS ((SELECT mslink FROM tablea) UNION (SELECT mslink FROM tableb)) SELECT * FROM tablea WHERE mslink IN (SELECT mslink FROM test)"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("((SELECT mslink FROM tablea) UNION (SELECT mslink FROM tableb))", withItems.get(0).getSelect().toString()); + assertEquals("((SELECT mslink FROM tablea) UNION (SELECT mslink FROM tableb))", + withItems.get(0).getSelect().toString()); assertEquals(" test", withItems.get(0).getAlias().toString()); } @@ -2401,9 +2411,10 @@ public void testWithUnionAllProblem() throws JSQLParserException { String stmt = "WITH test AS ((SELECT mslink FROM tablea) UNION ALL (SELECT mslink FROM tableb)) SELECT * FROM tablea WHERE mslink IN (SELECT mslink FROM test)"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("((SELECT mslink FROM tablea) UNION ALL (SELECT mslink FROM tableb))", withItems.get(0).getSelect().toString()); + assertEquals("((SELECT mslink FROM tablea) UNION ALL (SELECT mslink FROM tableb))", + withItems.get(0).getSelect().toString()); assertEquals(" test", withItems.get(0).getAlias().toString()); } @@ -2412,9 +2423,11 @@ public void testWithUnionProblem3() throws JSQLParserException { String stmt = "WITH test AS ((SELECT mslink, CAST(tablea.fname AS varchar) FROM tablea INNER JOIN tableb ON tablea.mslink = tableb.mslink AND tableb.deleted = 0 WHERE tablea.fname IS NULL AND 1 = 0) UNION ALL (SELECT mslink FROM tableb)) SELECT * FROM tablea WHERE mslink IN (SELECT mslink FROM test)"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("((SELECT mslink, CAST(tablea.fname AS varchar) FROM tablea INNER JOIN tableb ON tablea.mslink = tableb.mslink AND tableb.deleted = 0 WHERE tablea.fname IS NULL AND 1 = 0) UNION ALL (SELECT mslink FROM tableb))", withItems.get(0).getSelect().toString()); + assertEquals( + "((SELECT mslink, CAST(tablea.fname AS varchar) FROM tablea INNER JOIN tableb ON tablea.mslink = tableb.mslink AND tableb.deleted = 0 WHERE tablea.fname IS NULL AND 1 = 0) UNION ALL (SELECT mslink FROM tableb))", + withItems.get(0).getSelect().toString()); assertEquals(" test", withItems.get(0).getAlias().toString()); } @@ -2423,9 +2436,11 @@ public void testWithUnionProblem4() throws JSQLParserException { String stmt = "WITH hist AS ((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0)) SELECT mslink, space(level * 4) + txt AS txt, nr, feature, path FROM hist WHERE EXISTS (SELECT feature FROM tablec WHERE mslink = 0 AND ((feature IN (1, 2) AND hist.feature = 3) OR (feature IN (4) AND hist.feature = 2)))"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0))", withItems.get(0).getSelect().toString()); + assertEquals( + "((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0))", + withItems.get(0).getSelect().toString()); assertEquals(" hist", withItems.get(0).getAlias().toString()); } @@ -2434,9 +2449,11 @@ public void testWithUnionProblem5() throws JSQLParserException { String stmt = "WITH hist AS ((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, 5 AS feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0)) SELECT * FROM hist"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, 5 AS feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0))", withItems.get(0).getSelect().toString()); + assertEquals( + "((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, 5 AS feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0))", + withItems.get(0).getSelect().toString()); assertEquals(" hist", withItems.get(0).getAlias().toString()); } @@ -3164,12 +3181,14 @@ public void testSelectOracleColl() throws JSQLParserException { @Test public void testSelectInnerWith() throws JSQLParserException { - String stmt = "SELECT * FROM (WITH actor AS (SELECT 'a' aid FROM DUAL) SELECT aid FROM actor)"; + String stmt = + "SELECT * FROM (WITH actor AS (SELECT 'a' aid FROM DUAL) SELECT aid FROM actor)"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems1 = select.getWithItemsList(); + List> withItems1 = select.getWithItemsList(); assertNull(withItems1); - ParenthesedSelect parenthesedSelect = (ParenthesedSelect) select.getPlainSelect().getFromItem(); - List withItems2 = parenthesedSelect.getPlainSelect().getWithItemsList(); + ParenthesedSelect parenthesedSelect = + (ParenthesedSelect) select.getPlainSelect().getFromItem(); + List> withItems2 = parenthesedSelect.getPlainSelect().getWithItemsList(); assertEquals(1, withItems2.size()); assertEquals("(SELECT 'a' aid FROM DUAL)", withItems2.get(0).getSelect().toString()); assertEquals(" actor", withItems2.get(0).getAlias().toString()); @@ -3183,9 +3202,10 @@ public void testSelectInnerWith() throws JSQLParserException { @Test public void testSelectInnerWithAndUnionIssue1084_2() throws JSQLParserException { - String stmt = "WITH actor AS (SELECT 'b' aid FROM DUAL) SELECT aid FROM actor UNION SELECT aid FROM actor2"; + String stmt = + "WITH actor AS (SELECT 'b' aid FROM DUAL) SELECT aid FROM actor UNION SELECT aid FROM actor2"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); assertEquals("(SELECT 'b' aid FROM DUAL)", withItems.get(0).getSelect().toString()); assertEquals(" actor", withItems.get(0).getAlias().toString()); @@ -4580,10 +4600,11 @@ public void testEmptyDoubleQuotes_2() throws JSQLParserException { public void testInnerWithBlock() throws JSQLParserException { String stmt = "select 1 from (with mytable1 as (select 2 ) select 3 from mytable1 ) first"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); - List withItems1 = select.getWithItemsList(); + List> withItems1 = select.getWithItemsList(); assertNull(withItems1); - ParenthesedSelect parenthesedSelect = (ParenthesedSelect) select.getPlainSelect().getFromItem(); - List withItems2 = parenthesedSelect.getPlainSelect().getWithItemsList(); + ParenthesedSelect parenthesedSelect = + (ParenthesedSelect) select.getPlainSelect().getFromItem(); + List> withItems2 = parenthesedSelect.getPlainSelect().getWithItemsList(); assertEquals(1, withItems2.size()); assertEquals("(SELECT 2)", withItems2.get(0).getSelect().toString()); assertEquals(" mytable1", withItems2.get(0).getAlias().toString()); @@ -4728,11 +4749,13 @@ public void testPartitionByWithBracketsIssue865() throws JSQLParserException { @Test public void testWithAsRecursiveIssue874() throws JSQLParserException { - String stmt = "WITH rn AS (SELECT rownum rn FROM dual CONNECT BY level <= (SELECT max(cases) FROM t1)) SELECT pname FROM t1, rn WHERE rn <= cases ORDER BY pname"; + String stmt = + "WITH rn AS (SELECT rownum rn FROM dual CONNECT BY level <= (SELECT max(cases) FROM t1)) SELECT pname FROM t1, rn WHERE rn <= cases ORDER BY pname"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("(SELECT rownum rn FROM dual CONNECT BY level <= (SELECT max(cases) FROM t1))", withItems.get(0).getSelect().toString()); + assertEquals("(SELECT rownum rn FROM dual CONNECT BY level <= (SELECT max(cases) FROM t1))", + withItems.get(0).getSelect().toString()); assertEquals(" rn", withItems.get(0).getAlias().toString()); } @@ -5170,11 +5193,13 @@ public void testProblematicDeparsingIssue1183_2() throws JSQLParserException { @Test public void testKeywordCostsIssue1185() throws JSQLParserException { - String stmt = "WITH costs AS (SELECT * FROM MY_TABLE1 AS ALIAS_TABLE1) SELECT * FROM TESTSTMT"; + String stmt = + "WITH costs AS (SELECT * FROM MY_TABLE1 AS ALIAS_TABLE1) SELECT * FROM TESTSTMT"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("(SELECT * FROM MY_TABLE1 AS ALIAS_TABLE1)", withItems.get(0).getSelect().toString()); + assertEquals("(SELECT * FROM MY_TABLE1 AS ALIAS_TABLE1)", + withItems.get(0).getSelect().toString()); assertEquals(" costs", withItems.get(0).getAlias().toString()); } @@ -5190,11 +5215,13 @@ public void testConditionsWithExtraBrackets_Issue1194() throws JSQLParserExcepti @Test public void testWithValueListWithExtraBrackets1135() throws JSQLParserException { - String stmt = "with sample_data(day, value) as (values ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))) select day, value from sample_data"; + String stmt = + "with sample_data(day, value) as (values ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))) select day, value from sample_data"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); - assertEquals("VALUES ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))", withItems.get(0).getSelect().getValues().toString()); + assertEquals("VALUES ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))", + withItems.get(0).getSelect().getValues().toString()); assertEquals(" sample_data", withItems.get(0).getAlias().toString()); } @@ -5203,28 +5230,31 @@ public void testWithValueListWithOutExtraBrackets1135() throws JSQLParserExcepti String stmt1 = "with sample_data(\"DAY\") as (values 0, 1, 2)\n" + " select \"DAY\" from sample_data"; Select select1 = (Select) assertSqlCanBeParsedAndDeparsed(stmt1, true); - List withItems1 = select1.getWithItemsList(); + List> withItems1 = select1.getWithItemsList(); assertEquals(1, withItems1.size()); assertEquals("VALUES 0, 1, 2", withItems1.get(0).getSelect().getValues().toString()); assertEquals(" sample_data", withItems1.get(0).getAlias().toString()); - String stmt2 = "with sample_data(day, value) as (values (0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16)) select day, value from sample_data"; + String stmt2 = + "with sample_data(day, value) as (values (0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16)) select day, value from sample_data"; Select select2 = (Select) assertSqlCanBeParsedAndDeparsed(stmt2, true); - List withItems2 = select2.getWithItemsList(); + List> withItems2 = select2.getWithItemsList(); assertEquals(1, withItems2.size()); - assertEquals("VALUES (0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16)", withItems2.get(0).getSelect().getValues().toString()); + assertEquals("VALUES (0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16)", + withItems2.get(0).getSelect().getValues().toString()); assertEquals(" sample_data", withItems2.get(0).getAlias().toString()); } @Test public void testWithInsideWithIssue1186() throws JSQLParserException { - String stmt = "WITH TESTSTMT1 AS ( WITH TESTSTMT2 AS (SELECT * FROM MY_TABLE2) SELECT col1, col2 FROM TESTSTMT2) SELECT * FROM TESTSTMT"; + String stmt = + "WITH TESTSTMT1 AS ( WITH TESTSTMT2 AS (SELECT * FROM MY_TABLE2) SELECT col1, col2 FROM TESTSTMT2) SELECT * FROM TESTSTMT"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); assertEquals(" TESTSTMT1", withItems.get(0).getAlias().toString()); ParenthesedSelect parenthesedSelect = (ParenthesedSelect) withItems.get(0).getSelect(); - List withItems2 = parenthesedSelect.getSelect().getWithItemsList(); + List> withItems2 = parenthesedSelect.getSelect().getWithItemsList(); assertEquals(1, withItems2.size()); assertEquals("(SELECT * FROM MY_TABLE2)", withItems2.get(0).getSelect().toString()); assertEquals(" TESTSTMT2", withItems2.get(0).getAlias().toString()); @@ -5731,15 +5761,15 @@ void testNestedWithItems() throws JSQLParserException { String sqlStr = "with a as ( with b as ( with c as (select 1) select c.* from c) select b.* from b) select a.* from a"; Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr, true); - List withItems = select.getWithItemsList(); + List> withItems = select.getWithItemsList(); assertEquals(1, withItems.size()); assertEquals(" a", withItems.get(0).getAlias().toString()); ParenthesedSelect parenthesedSelect = (ParenthesedSelect) withItems.get(0).getSelect(); - List withItems2 = parenthesedSelect.getSelect().getWithItemsList(); + List> withItems2 = parenthesedSelect.getSelect().getWithItemsList(); assertEquals(1, withItems2.size()); assertEquals(" b", withItems2.get(0).getAlias().toString()); ParenthesedSelect parenthesedSelect2 = (ParenthesedSelect) withItems2.get(0).getSelect(); - List withItems3 = parenthesedSelect2.getSelect().getWithItemsList(); + List> withItems3 = parenthesedSelect2.getSelect().getWithItemsList(); assertEquals(1, withItems3.size()); assertEquals("(SELECT 1)", withItems3.get(0).getSelect().toString()); assertEquals(" c", withItems3.get(0).getAlias().toString()); @@ -5929,4 +5959,132 @@ void testGroupByWithHaving() throws JSQLParserException { Statement stmt = assertSqlCanBeParsedAndDeparsed(sqlStr); Assertions.assertInstanceOf(Select.class, stmt); } + + @Test + void testInsertWithinCte() throws JSQLParserException { + String sqlStr = "WITH inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " RETURNING y " + + ") " + + "SELECT y " + + " FROM inserted"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + Insert insert = withItems.get(0).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b", insert.getSelect().toString()); + assertEquals(" RETURNING y", insert.getReturningClause().toString()); + assertEquals("INSERT INTO x (foo) SELECT bar FROM b RETURNING y", insert.toString()); + assertEquals(" inserted", withItems.get(0).getAlias().toString()); + } + + @Test + void testUpdateWithinCte() throws JSQLParserException { + String sqlStr = "WITH updated AS ( " + + " UPDATE x " + + " SET foo = 1 " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "SELECT y " + + " FROM updated"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + Update update = withItems.get(0).getUpdate().getUpdate(); + assertEquals("x", update.getTable().toString()); + assertEquals("foo", update.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("1", update.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("bar = 2", update.getWhere().toString()); + assertEquals(" RETURNING y", update.getReturningClause().toString()); + assertEquals(" updated", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteWithinCte() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "SELECT y " + + " FROM deleted"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM deleted) " + + " RETURNING w " + + ") " + + "SELECT w " + + " FROM inserted"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(2, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM deleted)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM deleted) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testSelectAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH selection AS ( " + + " SELECT y " + + " FROM z " + + " WHERE foo = 'bar' " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM selection) " + + " RETURNING w " + + ") " + + "SELECT w " + + " FROM inserted"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(2, withItems.size()); + PlainSelect innerSelect = withItems.get(0).getSelect().getPlainSelect(); + assertEquals("SELECT y FROM z WHERE foo = 'bar'", innerSelect.toString()); + assertEquals(" selection", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM selection)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM selection) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + } diff --git a/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java b/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java index 669d3e60e..90d04c358 100644 --- a/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java @@ -19,6 +19,9 @@ import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; @@ -232,17 +235,20 @@ public void testWith() throws JSQLParserException { + "WHERE id_instrument_ref = (SELECT id_instrument_ref\n" + " FROM a)"; Update update = (Update) assertSqlCanBeParsedAndDeparsed(statement, true); - List withItems = update.getWithItemsList(); + List> withItems = update.getWithItemsList(); assertEquals("cfe.instrument_ref", update.getTable().getFullyQualifiedName()); assertEquals(2, withItems.size()); - assertEquals("SELECT 1 id_instrument_ref", withItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals("SELECT 1 id_instrument_ref", + withItems.get(0).getSelect().getPlainSelect().toString()); assertEquals(" a", withItems.get(0).getAlias().toString()); - assertEquals("SELECT 1 id_instrument_ref", withItems.get(1).getSelect().getPlainSelect().toString()); + assertEquals("SELECT 1 id_instrument_ref", + withItems.get(1).getSelect().getPlainSelect().toString()); assertEquals(" b", withItems.get(1).getAlias().toString()); assertEquals(1, update.getUpdateSets().size()); assertEquals("id_instrument", update.getUpdateSets().get(0).getColumn(0).toString()); assertEquals("NULL", update.getUpdateSets().get(0).getValue(0).toString()); - assertEquals("id_instrument_ref = (SELECT id_instrument_ref FROM a)", update.getWhere().toString()); + assertEquals("id_instrument_ref = (SELECT id_instrument_ref FROM a)", + update.getWhere().toString()); } @Test @@ -390,4 +396,142 @@ void testIssue1910() throws JSQLParserException { TestUtils.assertStatementCanBeDeparsedAs(update, "UPDATE sys_dept SET (deleted, created) = (1,2)", true); } + + @Test + void testInsertWithinCte() throws JSQLParserException { + String sqlStr = "WITH inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " RETURNING y " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(1, withItems.size()); + Insert insert = withItems.get(0).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b", insert.getSelect().toString()); + assertEquals(" RETURNING y", insert.getReturningClause().toString()); + assertEquals("INSERT INTO x (foo) SELECT bar FROM b RETURNING y", insert.toString()); + assertEquals(" inserted", withItems.get(0).getAlias().toString()); + } + + @Test + void testUpdateWithinCte() throws JSQLParserException { + String sqlStr = "WITH updated AS ( " + + " UPDATE x " + + " SET foo = 1 " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(1, withItems.size()); + Update innerUpdate = withItems.get(0).getUpdate().getUpdate(); + assertEquals("x", innerUpdate.getTable().toString()); + assertEquals("foo", innerUpdate.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("1", innerUpdate.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("bar = 2", innerUpdate.getWhere().toString()); + assertEquals(" RETURNING y", innerUpdate.getReturningClause().toString()); + assertEquals(" updated", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteWithinCte() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(1, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM deleted) " + + " RETURNING w " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(2, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM deleted)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM deleted) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testSelectAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH selection AS ( " + + " SELECT y " + + " FROM z " + + " WHERE foo = 'bar' " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM selection) " + + " RETURNING w " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(2, withItems.size()); + PlainSelect select = withItems.get(0).getSelect().getPlainSelect(); + assertEquals("SELECT y FROM z WHERE foo = 'bar'", select.toString()); + assertEquals(" selection", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM selection)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM selection) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + } diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java index b0f8029c0..35e8db743 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java @@ -108,7 +108,7 @@ public void shouldUseProvidedDeparsersWhenDeParsingInsert() { duplicateUpdateSets.add(new UpdateSet(duplicateUpdateColumn2, duplicateUpdateExpression2)); PlainSelect select = mock(PlainSelect.class); - List withItemsList = new ArrayList(); + List> withItemsList = new ArrayList>(); WithItem withItem1 = spy(new WithItem()); WithItem withItem2 = spy(new WithItem()); ParenthesedSelect withItem1SubSelect = mock(ParenthesedSelect.class); @@ -140,7 +140,7 @@ public void shouldUseProvidedDeParsersWhenDeParsingSelect() { WithItem withItem2 = spy(new WithItem()); withItem2.setSelect(mock(ParenthesedSelect.class)); - List withItemsList = new ArrayList(); + List> withItemsList = new ArrayList>(); withItemsList.add(withItem1); withItemsList.add(withItem2); @@ -289,7 +289,7 @@ public void shouldUseProvidedDeparsersWhenDeParsingUpsertWithExpressionList() { Expression duplicateUpdateExpression1 = mock(Expression.class); Expression duplicateUpdateExpression2 = mock(Expression.class); PlainSelect select = mock(PlainSelect.class); - List withItemsList = new ArrayList(); + List> withItemsList = new ArrayList>(); WithItem withItem1 = spy(new WithItem()); WithItem withItem2 = spy(new WithItem()); ParenthesedSelect withItem1SubSelect = mock(ParenthesedSelect.class);