Skip to content

Commit

Permalink
refactor: RETURNING clause
Browse files Browse the repository at this point in the history
- supports Oracle's `RETURN ... INTO ...`
- fixes JSQLParser#1780
- fixes JSQLParser#686
- Special Oracle tests `insert11.sql` and `insert12.sql`
  • Loading branch information
manticore-projects committed May 16, 2023
1 parent daa56ed commit 4fb1cfb
Show file tree
Hide file tree
Showing 23 changed files with 277 additions and 132 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*-
* #%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.expression;

import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.parser.SimpleNode;

import java.io.Serializable;
Expand Down Expand Up @@ -65,7 +64,7 @@ public ExpressionList addExpressions(T... expressions) {
return this;
}

public ExpressionList addExpressions(Collection<T> expressions) {
public ExpressionList<?> addExpressions(Collection<T> expressions) {
addAll(expressions);
return this;
}
Expand All @@ -80,9 +79,19 @@ public ExpressionList withExpressions(Collection<T> expressions) {
return addExpressions(expressions);
}

public StringBuilder appendTo(StringBuilder builder) {
for (int i = 0; i < size(); i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(get(i));
}
return builder;
}

@Override
public String toString() {
return PlainSelect.getStringList(this, true, false);
return appendTo(new StringBuilder()).toString();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*-
* #%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.expression.operators.relational;

import net.sf.jsqlparser.expression.Expression;
Expand Down
97 changes: 97 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/ReturningClause.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*-
* #%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;

import net.sf.jsqlparser.statement.select.SelectItem;

import java.util.ArrayList;
import java.util.List;

/**
* RETURNING clause according to
* {@see https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/DELETE.html#GUID-156845A5-B626-412B-9F95-8869B988ABD7
* } Part of UPDATE, INSERT, DELETE statements
*/

public class ReturningClause extends ArrayList<SelectItem<?>> {
enum Keyword {
RETURN, RETURNING;

public static Keyword from(String keyword) {
return Enum.valueOf(Keyword.class, keyword.toUpperCase());
}
}

private Keyword keyword;

/**
* List of output targets like Table or UserVariable
*/
private final List<Object> dataItems;

public ReturningClause(Keyword keyword, List<SelectItem<?>> selectItems,
List<Object> dataItems) {
this.keyword = keyword;
this.addAll(selectItems);
this.dataItems = dataItems;
}

public ReturningClause(String keyword, List<SelectItem<?>> selectItems,
List<Object> dataItems) {
this(Keyword.from(keyword), selectItems, dataItems);
}

public ReturningClause(Keyword keyword, List<SelectItem<?>> selectItems) {
this(keyword, selectItems, null);
}

public ReturningClause(String keyword, List<SelectItem<?>> selectItems) {
this(Keyword.valueOf(keyword), selectItems, null);
}

public Keyword getKeyword() {
return keyword;
}

public ReturningClause setKeyword(Keyword keyword) {
this.keyword = keyword;
return this;
}

public List<?> getDataItems() {
return dataItems;
}

public StringBuilder appendTo(StringBuilder builder) {
builder.append(" ").append(keyword).append(" ");
for (int i = 0; i < size(); i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(get(i));
}

if (dataItems != null && dataItems.size() > 0) {
builder.append(" INTO ");
for (int i = 0; i < dataItems.size(); i++) {
if (i > 0) {
builder.append(" ,");
}
builder.append(dataItems.get(i));
}
}
return builder;
}

@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
}
}
22 changes: 9 additions & 13 deletions src/main/java/net/sf/jsqlparser/statement/delete/Delete.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
import net.sf.jsqlparser.expression.OracleHint;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.OutputClause;
import net.sf.jsqlparser.statement.ReturningClause;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.Limit;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.WithItem;

import java.util.ArrayList;
Expand All @@ -46,7 +46,8 @@ public class Delete implements Statement {
private DeleteModifierPriority modifierPriority;
private boolean modifierIgnore;
private boolean modifierQuick;
private List<SelectItem<?>> returningExpressionList = null;

private ReturningClause returningClause;
private OutputClause outputClause;

public OutputClause getOutputClause() {
Expand All @@ -57,16 +58,12 @@ public void setOutputClause(OutputClause outputClause) {
this.outputClause = outputClause;
}

public List<SelectItem<?>> getReturningExpressionList() {
return returningExpressionList;
}

public void setReturningExpressionList(List<SelectItem<?>> returningExpressionList) {
this.returningExpressionList = returningExpressionList;
public ReturningClause getReturningClause() {
return returningClause;
}

public Delete withReturningExpressionList(List<SelectItem<?>> returningExpressionList) {
this.returningExpressionList = returningExpressionList;
public Delete setReturningClause(ReturningClause returningClause) {
this.returningClause = returningClause;
return this;
}

Expand Down Expand Up @@ -248,9 +245,8 @@ public String toString() {
b.append(limit);
}

if (getReturningExpressionList() != null) {
b.append(" RETURNING ")
.append(PlainSelect.getStringList(getReturningExpressionList(), true, false));
if (returningClause != null) {
returningClause.appendTo(b);
}

return b.toString();
Expand Down
36 changes: 9 additions & 27 deletions src/main/java/net/sf/jsqlparser/statement/insert/Insert.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.OutputClause;
import net.sf.jsqlparser.statement.ReturningClause;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.select.Values;
import net.sf.jsqlparser.statement.select.WithItem;
import net.sf.jsqlparser.statement.update.UpdateSet;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
Expand All @@ -41,7 +40,7 @@ public class Insert implements Statement {
private List<UpdateSet> duplicateUpdateSets = null;
private InsertModifierPriority modifierPriority = null;
private boolean modifierIgnore = false;
private List<SelectItem<?>> returningExpressionList = null;
private ReturningClause returningClause;
private List<UpdateSet> setUpdateSets = null;
private List<WithItem> withItemsList;
private OutputClause outputClause;
Expand Down Expand Up @@ -108,12 +107,13 @@ public boolean isUseValues() {
return select != null && select instanceof Values;
}

public List<SelectItem<?>> getReturningExpressionList() {
return returningExpressionList;
public ReturningClause getReturningClause() {
return returningClause;
}

public void setReturningExpressionList(List<SelectItem<?>> returningExpressionList) {
this.returningExpressionList = returningExpressionList;
public Insert setReturningClause(ReturningClause returningClause) {
this.returningClause = returningClause;
return this;
}

public Select getSelect() {
Expand Down Expand Up @@ -257,9 +257,8 @@ public String toString() {
conflictAction.appendTo(sql);
}

if (getReturningExpressionList() != null) {
sql.append(" RETURNING ")
.append(PlainSelect.getStringList(getReturningExpressionList(), true, false));
if (returningClause != null) {
returningClause.appendTo(sql);
}

return sql.toString();
Expand All @@ -285,11 +284,6 @@ public Insert withModifierIgnore(boolean modifierIgnore) {
return this;
}

public Insert withReturningExpressionList(List<SelectItem<?>> returningExpressionList) {
this.setReturningExpressionList(returningExpressionList);
return this;
}

public Insert withTable(Table table) {
this.setTable(table);
return this;
Expand All @@ -310,16 +304,4 @@ public Insert addColumns(Collection<Column> columns) {
collection.addAll(columns);
return this.withColumns(collection);
}

public Insert addReturningExpressionList(SelectItem<?>... returningExpressions) {
return this.addReturningExpressionList(Arrays.asList(returningExpressions));
}

public Insert addReturningExpressionList(
Collection<? extends SelectItem<?>> returningExpressions) {
List<SelectItem<?>> collection =
Optional.ofNullable(getReturningExpressionList()).orElseGet(ArrayList::new);
collection.addAll(returningExpressions);
return this.withReturningExpressionList(collection);
}
}
38 changes: 9 additions & 29 deletions src/main/java/net/sf/jsqlparser/statement/update/Update.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.OutputClause;
import net.sf.jsqlparser.statement.ReturningClause;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
import net.sf.jsqlparser.statement.select.FromItem;
Expand All @@ -22,7 +23,6 @@
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.WithItem;

import java.util.ArrayList;
Expand All @@ -46,7 +46,7 @@ public class Update implements Statement {
private OracleHint oracleHint = null;
private List<OrderByElement> orderByElements;
private Limit limit;
private List<SelectItem<?>> returningExpressionList = null;
private ReturningClause returningClause;
private UpdateModifierPriority modifierPriority;
private boolean modifierIgnore;

Expand Down Expand Up @@ -245,12 +245,13 @@ public Limit getLimit() {
return limit;
}

public List<SelectItem<?>> getReturningExpressionList() {
return returningExpressionList;
public ReturningClause getReturningClause() {
return returningClause;
}

public void setReturningExpressionList(List<SelectItem<?>> returningExpressionList) {
this.returningExpressionList = returningExpressionList;
public Update setReturningClause(ReturningClause returningClause) {
this.returningClause = returningClause;
return this;
}

public UpdateModifierPriority getModifierPriority() {
Expand Down Expand Up @@ -335,9 +336,8 @@ public String toString() {
b.append(limit);
}

if (getReturningExpressionList() != null) {
b.append(" RETURNING ")
.append(PlainSelect.getStringList(getReturningExpressionList(), true, false));
if (returningClause != null) {
returningClause.appendTo(b);
}

return b.toString();
Expand Down Expand Up @@ -388,11 +388,6 @@ public Update withLimit(Limit limit) {
return this;
}

public Update withReturningExpressionList(List<SelectItem<?>> returningExpressionList) {
this.setReturningExpressionList(returningExpressionList);
return this;
}

public Update withWhere(Expression where) {
this.setWhere(where);
return this;
Expand Down Expand Up @@ -478,21 +473,6 @@ public Update addOrderByElements(Collection<? extends OrderByElement> orderByEle
return this.withOrderByElements(collection);
}

public Update addReturningExpressionList(SelectItem<?>... returningExpressionList) {
List<SelectItem<?>> collection =
Optional.ofNullable(getReturningExpressionList()).orElseGet(ArrayList::new);
Collections.addAll(collection, returningExpressionList);
return this.withReturningExpressionList(collection);
}

public Update addReturningExpressionList(
Collection<? extends SelectItem<?>> returningExpressionList) {
List<SelectItem<?>> collection =
Optional.ofNullable(getReturningExpressionList()).orElseGet(ArrayList::new);
collection.addAll(returningExpressionList);
return this.withReturningExpressionList(collection);
}

public <E extends Expression> E getWhere(Class<E> type) {
return type.cast(getWhere());
}
Expand Down
Loading

0 comments on commit 4fb1cfb

Please sign in to comment.