Skip to content

Commit 3822466

Browse files
authored
Render DML RETURNING expressions through shared visitor handling (#2624)
1 parent c314df2 commit 3822466

5 files changed

Lines changed: 69 additions & 9 deletions

File tree

src/main/java/net/sf/jsqlparser/util/deparser/AbstractDeParser.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
package net.sf.jsqlparser.util.deparser;
1111

12+
import net.sf.jsqlparser.statement.ReturningClause;
1213
import net.sf.jsqlparser.expression.ExpressionVisitor;
1314
import net.sf.jsqlparser.statement.update.UpdateSet;
1415
import net.sf.jsqlparser.statement.ForPortionClause;
@@ -27,6 +28,14 @@ protected AbstractDeParser(StringBuilder builder) {
2728
this.builder = builder;
2829
}
2930

31+
protected void deparseReturningClause(ReturningClause clause,
32+
ExpressionVisitor<StringBuilder> visitor) {
33+
if (clause != null) {
34+
SelectDeParser selectItems = new SelectDeParser(visitor, builder);
35+
clause.appendTo(builder, item -> item.accept(selectItems, null));
36+
}
37+
}
38+
3039
public static void deparseUpdateSets(List<UpdateSet> updateSets, StringBuilder buffer,
3140
ExpressionVisitor<StringBuilder> visitor) {
3241
ExpressionListDeParser<?> expressionListDeParser =

src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,7 @@ public void deParse(Delete delete) {
110110
builder.append(delete.getOption());
111111
}
112112

113-
if (delete.getReturningClause() != null) {
114-
delete.getReturningClause().appendTo(builder);
115-
}
113+
deparseReturningClause(delete.getReturningClause(), expressionVisitor);
116114

117115
}
118116

src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,7 @@ public void deParse(Insert insert) {
153153
insert.getConflictAction().appendTo(builder);
154154
}
155155

156-
if (insert.getReturningClause() != null) {
157-
insert.getReturningClause().appendTo(builder);
158-
}
156+
deparseReturningClause(insert.getReturningClause(), expressionVisitor);
159157
}
160158

161159
public ExpressionVisitor<StringBuilder> getExpressionVisitor() {

src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,7 @@ public void deParse(Update update) {
102102
builder.append(update.getOption());
103103
}
104104

105-
if (update.getReturningClause() != null) {
106-
update.getReturningClause().appendTo(builder);
107-
}
105+
deparseReturningClause(update.getReturningClause(), expressionVisitor);
108106
}
109107

110108
protected void deparseWhereClause(Update update) {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2019 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.util.deparser;
11+
12+
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
import net.sf.jsqlparser.expression.LongValue;
16+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
17+
import org.junit.jupiter.params.ParameterizedTest;
18+
import org.junit.jupiter.params.provider.ValueSource;
19+
20+
class DmlReturningExpressionTest {
21+
@ParameterizedTest
22+
@ValueSource(strings = {"UPDATE t SET a = 7 RETURNING a + 8 AS result",
23+
"DELETE FROM t WHERE a = 7 RETURNING a + 8 AS result",
24+
"INSERT INTO t(a) VALUES (7) RETURNING a + 8 AS result",
25+
"UPDATE t SET a = 7 RETURNING (SELECT b + 8 FROM source) AS result"})
26+
void visitsReturnedExpressionsExactlyOnce(String sql) throws Exception {
27+
var statement = CCJSqlParserUtil.parse(sql);
28+
String original = statement.toString();
29+
List<Long> seen = new ArrayList<>();
30+
ExpressionDeParser expressions = new ExpressionDeParser() {
31+
@Override
32+
public <S> StringBuilder visit(LongValue value, S context) {
33+
seen.add(value.getValue());
34+
return getBuilder().append(value.getValue() + 100);
35+
}
36+
};
37+
StringBuilder output = new StringBuilder();
38+
statement.accept(new StatementDeParser(expressions, new SelectDeParser(), output), null);
39+
assertEquals(List.of(7L, 8L), seen);
40+
assertEquals(original.replace("7", "107").replace("8", "108"), output.toString());
41+
assertEquals(original, statement.toString());
42+
assertEquals(output.toString(), CCJSqlParserUtil.parse(output.toString()).toString());
43+
}
44+
45+
@ParameterizedTest
46+
@ValueSource(strings = {"INSERT INTO t(a) VALUES (1) RETURNING *",
47+
"DELETE FROM t RETURNING t.*, a AS result",
48+
"UPDATE t SET a = 1 RETURNING a, b INTO x, y",
49+
"DELETE FROM t RETURNING WITH (OLD AS o, NEW AS n) o.*, n.id"})
50+
void preservesWildcardsAliasesAndOutputTargets(String sql) throws Exception {
51+
var statement = CCJSqlParserUtil.parse(sql);
52+
StringBuilder output = new StringBuilder();
53+
statement.accept(new StatementDeParser(output), null);
54+
assertEquals(statement.toString(), output.toString());
55+
assertEquals(statement.toString(), CCJSqlParserUtil.parse(output.toString()).toString());
56+
}
57+
}

0 commit comments

Comments
 (0)