Skip to content

Commit 4d81521

Browse files
#1527 DELETE ... RETURNING ... (#1528)
* #1527 DELETE ... RETURNING ... Fixes #1527 Add DELETE... RETURNING ... expression Simplify INSERT ... RETURNING ... expression Simply UPDATE ... RETURNING ... expression * TSQL Output Clause According to https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-ver15 Implement Output Clause for INSERT, UPDATE and DELETE Add Tests according the Microsoft Documentation * Appease Codacy/PMD
1 parent f7f9d27 commit 4d81521

File tree

15 files changed

+388
-120
lines changed

15 files changed

+388
-120
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package net.sf.jsqlparser.statement;
2+
3+
import net.sf.jsqlparser.expression.UserVariable;
4+
import net.sf.jsqlparser.schema.Table;
5+
import net.sf.jsqlparser.statement.select.PlainSelect;
6+
import net.sf.jsqlparser.statement.select.SelectItem;
7+
8+
import java.util.List;
9+
import java.util.Objects;
10+
11+
/**
12+
* T-SQL Output Clause
13+
*
14+
* @see <a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-ver15">OUTPUT Clause (Transact-SQL)</a>
15+
*
16+
* <pre>
17+
* &lt;OUTPUT_CLAUSE&gt; ::=
18+
* {
19+
* [ OUTPUT &lt;dml_select_list&gt; INTO { @table_variable | output_table } [ ( column_list ) ] ]
20+
* [ OUTPUT &lt;dml_select_list&gt; ]
21+
* }
22+
* &lt;dml_select_list&gt; ::=
23+
* { &lt;column_name&gt; | scalar_expression } [ [AS] column_alias_identifier ]
24+
* [ ,...n ]
25+
*
26+
* &lt;column_name&gt; ::=
27+
* { DELETED | INSERTED | from_table_name } . { * | column_name }
28+
* | $action
29+
* </pre>
30+
*/
31+
public class OutputClause {
32+
List<SelectItem> selectItemList;
33+
UserVariable tableVariable;
34+
Table outputTable;
35+
List<String> columnList;
36+
37+
public OutputClause(List<SelectItem> selectItemList, UserVariable tableVariable, Table outputTable, List<String> columnList) {
38+
this.selectItemList = Objects.requireNonNull(selectItemList, "The Select List of the Output Clause must not be null.");
39+
this.tableVariable = tableVariable;
40+
this.outputTable = outputTable;
41+
this.columnList = columnList;
42+
}
43+
44+
public List<SelectItem> getSelectItemList() {
45+
return selectItemList;
46+
}
47+
48+
public void setSelectItemList(List<SelectItem> selectItemList) {
49+
this.selectItemList = selectItemList;
50+
}
51+
52+
public UserVariable getTableVariable() {
53+
return tableVariable;
54+
}
55+
56+
public void setTableVariable(UserVariable tableVariable) {
57+
this.tableVariable = tableVariable;
58+
}
59+
60+
public Table getOutputTable() {
61+
return outputTable;
62+
}
63+
64+
public void setOutputTable(Table outputTable) {
65+
this.outputTable = outputTable;
66+
}
67+
68+
public List<String> getColumnList() {
69+
return columnList;
70+
}
71+
72+
public void setColumnList(List<String> columnList) {
73+
this.columnList = columnList;
74+
}
75+
76+
public StringBuilder appendTo(StringBuilder builder) {
77+
builder.append(" OUTPUT ");
78+
PlainSelect.appendStringListTo(builder, selectItemList, true, false);
79+
80+
if (tableVariable != null) {
81+
builder.append(" INTO ").append(tableVariable);
82+
} else if (outputTable != null) {
83+
builder.append(" INTO ").append(outputTable);
84+
}
85+
86+
PlainSelect.appendStringListTo(builder, columnList, true, false);
87+
88+
return builder.append(" ");
89+
}
90+
91+
@Override
92+
public String toString() {
93+
return appendTo(new StringBuilder()).toString();
94+
}
95+
}

src/main/java/net/sf/jsqlparser/statement/delete/Delete.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020
import net.sf.jsqlparser.expression.Expression;
2121
import net.sf.jsqlparser.expression.OracleHint;
2222
import net.sf.jsqlparser.schema.Table;
23+
import net.sf.jsqlparser.statement.OutputClause;
2324
import net.sf.jsqlparser.statement.Statement;
2425
import net.sf.jsqlparser.statement.StatementVisitor;
2526
import net.sf.jsqlparser.statement.select.Join;
2627
import net.sf.jsqlparser.statement.select.Limit;
2728
import net.sf.jsqlparser.statement.select.OrderByElement;
2829
import net.sf.jsqlparser.statement.select.PlainSelect;
30+
import net.sf.jsqlparser.statement.select.SelectItem;
2931
import net.sf.jsqlparser.statement.select.WithItem;
3032

3133
public class Delete implements Statement {
@@ -43,6 +45,29 @@ public class Delete implements Statement {
4345
private DeleteModifierPriority modifierPriority;
4446
private boolean modifierIgnore;
4547
private boolean modifierQuick;
48+
private List<SelectItem> returningExpressionList = null;
49+
private OutputClause outputClause;
50+
51+
public OutputClause getOutputClause() {
52+
return outputClause;
53+
}
54+
55+
public void setOutputClause(OutputClause outputClause) {
56+
this.outputClause = outputClause;
57+
}
58+
59+
public List<SelectItem> getReturningExpressionList() {
60+
return returningExpressionList;
61+
}
62+
63+
public void setReturningExpressionList(List<SelectItem> returningExpressionList) {
64+
this.returningExpressionList = returningExpressionList;
65+
}
66+
67+
public Delete withReturningExpressionList(List<SelectItem> returningExpressionList) {
68+
this.returningExpressionList = returningExpressionList;
69+
return this;
70+
}
4671

4772
public List<WithItem> getWithItemsList() {
4873
return withItemsList;
@@ -181,6 +206,11 @@ public String toString() {
181206
.collect(joining(", ")));
182207
}
183208

209+
if (outputClause!=null) {
210+
outputClause.appendTo(b);
211+
}
212+
213+
184214
if (hasFrom) {
185215
b.append(" FROM");
186216
}
@@ -214,6 +244,12 @@ public String toString() {
214244
if (limit != null) {
215245
b.append(limit);
216246
}
247+
248+
if (getReturningExpressionList() != null) {
249+
b.append(" RETURNING ").append(PlainSelect.
250+
getStringList(getReturningExpressionList(), true, false));
251+
}
252+
217253
return b.toString();
218254
}
219255

src/main/java/net/sf/jsqlparser/statement/insert/Insert.java

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
2121
import net.sf.jsqlparser.schema.Column;
2222
import net.sf.jsqlparser.schema.Table;
23+
import net.sf.jsqlparser.statement.OutputClause;
2324
import net.sf.jsqlparser.statement.Statement;
2425
import net.sf.jsqlparser.statement.StatementVisitor;
2526
import net.sf.jsqlparser.statement.select.PlainSelect;
2627
import net.sf.jsqlparser.statement.select.Select;
27-
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
28+
import net.sf.jsqlparser.statement.select.SelectItem;
2829
import net.sf.jsqlparser.statement.select.WithItem;
2930

3031
@SuppressWarnings({"PMD.CyclomaticComplexity"})
@@ -43,15 +44,23 @@ public class Insert implements Statement {
4344
private InsertModifierPriority modifierPriority = null;
4445
private boolean modifierIgnore = false;
4546

46-
private boolean returningAllColumns = false;
47-
48-
private List<SelectExpressionItem> returningExpressionList = null;
47+
private List<SelectItem> returningExpressionList = null;
4948

5049
private boolean useSet = false;
5150
private List<Column> setColumns;
5251
private List<Expression> setExpressionList;
5352
private List<WithItem> withItemsList;
5453

54+
private OutputClause outputClause;
55+
56+
public OutputClause getOutputClause() {
57+
return outputClause;
58+
}
59+
60+
public void setOutputClause(OutputClause outputClause) {
61+
this.outputClause = outputClause;
62+
}
63+
5564
@Override
5665
public void accept(StatementVisitor statementVisitor) {
5766
statementVisitor.visit(this);
@@ -102,19 +111,11 @@ public void setUseValues(boolean useValues) {
102111
this.useValues = useValues;
103112
}
104113

105-
public boolean isReturningAllColumns() {
106-
return returningAllColumns;
107-
}
108-
109-
public void setReturningAllColumns(boolean returningAllColumns) {
110-
this.returningAllColumns = returningAllColumns;
111-
}
112-
113-
public List<SelectExpressionItem> getReturningExpressionList() {
114+
public List<SelectItem> getReturningExpressionList() {
114115
return returningExpressionList;
115116
}
116117

117-
public void setReturningExpressionList(List<SelectExpressionItem> returningExpressionList) {
118+
public void setReturningExpressionList(List<SelectItem> returningExpressionList) {
118119
this.returningExpressionList = returningExpressionList;
119120
}
120121

@@ -234,6 +235,10 @@ public String toString() {
234235
sql.append(PlainSelect.getStringList(columns, true, true)).append(" ");
235236
}
236237

238+
if (outputClause!=null) {
239+
outputClause.appendTo(sql);
240+
}
241+
237242
if (useValues) {
238243
sql.append("VALUES ");
239244
}
@@ -274,9 +279,7 @@ public String toString() {
274279
}
275280
}
276281

277-
if (isReturningAllColumns()) {
278-
sql.append(" RETURNING *");
279-
} else if (getReturningExpressionList() != null) {
282+
if (getReturningExpressionList() != null) {
280283
sql.append(" RETURNING ").append(PlainSelect.
281284
getStringList(getReturningExpressionList(), true, false));
282285
}
@@ -329,12 +332,7 @@ public Insert withModifierIgnore(boolean modifierIgnore) {
329332
return this;
330333
}
331334

332-
public Insert withReturningAllColumns(boolean returningAllColumns) {
333-
this.setReturningAllColumns(returningAllColumns);
334-
return this;
335-
}
336-
337-
public Insert withReturningExpressionList(List<SelectExpressionItem> returningExpressionList) {
335+
public Insert withReturningExpressionList(List<SelectItem> returningExpressionList) {
338336
this.setReturningExpressionList(returningExpressionList);
339337
return this;
340338
}
@@ -410,14 +408,14 @@ public Insert addDuplicateUpdateExpressionList(Collection<? extends Expression>
410408
return this.withDuplicateUpdateExpressionList(collection);
411409
}
412410

413-
public Insert addReturningExpressionList(SelectExpressionItem... returningExpressionList) {
414-
List<SelectExpressionItem> collection = Optional.ofNullable(getReturningExpressionList()).orElseGet(ArrayList::new);
411+
public Insert addReturningExpressionList(SelectItem... returningExpressionList) {
412+
List<SelectItem> collection = Optional.ofNullable(getReturningExpressionList()).orElseGet(ArrayList::new);
415413
Collections.addAll(collection, returningExpressionList);
416414
return this.withReturningExpressionList(collection);
417415
}
418416

419-
public Insert addReturningExpressionList(Collection<? extends SelectExpressionItem> returningExpressionList) {
420-
List<SelectExpressionItem> collection = Optional.ofNullable(getReturningExpressionList()).orElseGet(ArrayList::new);
417+
public Insert addReturningExpressionList(Collection<? extends SelectItem> returningExpressionList) {
418+
List<SelectItem> collection = Optional.ofNullable(getReturningExpressionList()).orElseGet(ArrayList::new);
421419
collection.addAll(returningExpressionList);
422420
return this.withReturningExpressionList(collection);
423421
}

src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -532,28 +532,38 @@ public static String getStringList(List<?> list) {
532532
* @return comma separated list of the elements in the list
533533
*/
534534
public static String getStringList(List<?> list, boolean useComma, boolean useBrackets) {
535-
StringBuilder ans = new StringBuilder();
536-
String comma = ",";
537-
if (!useComma) {
538-
comma = "";
539-
}
535+
return appendStringListTo(new StringBuilder(), list, useComma, useBrackets).toString();
536+
}
537+
538+
/**
539+
* Append the toString out put of the objects in the List (that can be comma
540+
* separated). If the List is null or empty an empty string is returned.
541+
*
542+
* @param list list of objects with toString methods
543+
* @param useComma true if the list has to be comma separated
544+
* @param useBrackets true if the list has to be enclosed in brackets
545+
* @return comma separated list of the elements in the list
546+
*/
547+
public static StringBuilder appendStringListTo(StringBuilder builder, List<?> list, boolean useComma, boolean useBrackets) {
540548
if (list != null) {
549+
String comma = useComma ? "," : "";
550+
541551
if (useBrackets) {
542-
ans.append("(");
552+
builder.append("(");
543553
}
544554

545-
for (int i = 0; i < list.size(); i++) {
546-
ans.append(list.get(i)).append( i < list.size() - 1
547-
? comma + " "
548-
: "" );
555+
int size = list.size();
556+
for (int i = 0; i < size; i++) {
557+
builder.append(list.get(i)).append( i < size - 1
558+
? comma + " "
559+
: "" );
549560
}
550561

551562
if (useBrackets) {
552-
ans.append(")");
563+
builder.append(")");
553564
}
554565
}
555-
556-
return ans.toString();
566+
return builder;
557567
}
558568

559569
public PlainSelect withMySqlSqlCalcFoundRows(boolean mySqlCalcFoundRows) {

0 commit comments

Comments
 (0)