Skip to content

Commit c314df2

Browse files
authored
Validate every UPDATE assignment through shared UpdateSet traversal (#2623)
1 parent 33c4030 commit c314df2

4 files changed

Lines changed: 68 additions & 15 deletions

File tree

src/main/java/net/sf/jsqlparser/util/validation/validator/AbstractValidator.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
import net.sf.jsqlparser.statement.ForPortionClause;
1313
import net.sf.jsqlparser.expression.Expression;
14+
import net.sf.jsqlparser.statement.update.UpdateSet;
15+
import net.sf.jsqlparser.statement.select.Select;
16+
import net.sf.jsqlparser.statement.select.SelectVisitor;
1417
import net.sf.jsqlparser.parser.feature.Feature;
1518
import net.sf.jsqlparser.statement.select.FromItem;
1619
import net.sf.jsqlparser.statement.select.OrderByElement;
@@ -147,6 +150,25 @@ protected void validateOptionalExpression(Expression expression, ExpressionValid
147150
validateOptional(expression, e -> e.accept(v, null));
148151
}
149152

153+
protected void validateOptionalUpdateSets(List<UpdateSet> updateSets) {
154+
if (updateSets != null) {
155+
for (UpdateSet updateSet : updateSets) {
156+
validateOptionalExpressions(updateSet.getColumns());
157+
if (updateSet.getValues() != null) {
158+
for (Expression value : updateSet.getValues()) {
159+
if (value instanceof Select) {
160+
((Select) value).accept(
161+
(SelectVisitor<Void>) getValidator(SelectValidator.class),
162+
null);
163+
} else {
164+
validateOptionalExpression(value);
165+
}
166+
}
167+
}
168+
}
169+
}
170+
}
171+
150172
protected void validateOptionalExpressions(List<? extends Expression> expressions) {
151173
validateOptionalList(expressions, () -> getValidator(ExpressionValidator.class),
152174
(o, v) -> o.accept(v, null));

src/main/java/net/sf/jsqlparser/util/validation/validator/MergeValidator.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import net.sf.jsqlparser.parser.feature.Feature;
1313
import net.sf.jsqlparser.statement.merge.*;
1414
import net.sf.jsqlparser.statement.select.OptionHint;
15-
import net.sf.jsqlparser.statement.update.UpdateSet;
1615
import net.sf.jsqlparser.util.validation.ValidationCapability;
1716

1817
/**
@@ -59,10 +58,7 @@ public void visit(MergeDelete mergeDelete) {
5958
@Override
6059
public <S> Void visit(MergeUpdate mergeUpdate, S context) {
6160
validateOptionalExpression(mergeUpdate.getAndPredicate());
62-
for (UpdateSet updateSet : mergeUpdate.getUpdateSets()) {
63-
validateOptionalExpressions(updateSet.getColumns());
64-
validateOptionalExpressions(updateSet.getValues());
65-
}
61+
validateOptionalUpdateSets(mergeUpdate.getUpdateSets());
6662
validateOptionalExpression(mergeUpdate.getDeleteWhereCondition());
6763
validateOptionalExpression(mergeUpdate.getWhereCondition());
6864
return null;

src/main/java/net/sf/jsqlparser/util/validation/validator/UpdateValidator.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
package net.sf.jsqlparser.util.validation.validator;
1111

1212
import net.sf.jsqlparser.parser.feature.Feature;
13-
import net.sf.jsqlparser.statement.select.SelectVisitor;
1413
import net.sf.jsqlparser.statement.select.OptionHint;
1514
import net.sf.jsqlparser.statement.update.Update;
1615
import net.sf.jsqlparser.util.validation.ValidationCapability;
@@ -27,7 +26,6 @@ public void validate(Update update) {
2726
validateFeature(c, Feature.update);
2827
validateOptionalFeature(c, update.getFromItem(), Feature.updateFrom);
2928
validateOptionalFeature(c, update.getStartJoins(), Feature.updateJoins);
30-
validateFeature(c, update.isUseSelect(), Feature.updateUseSelect);
3129
validateOptionalFeature(c, update.getOrderByElements(), Feature.updateOrderBy);
3230
validateOptionalFeature(c, update.getLimit(), Feature.updateLimit);
3331
validateOptionalFeature(c, update.getReturningClause(),
@@ -41,14 +39,7 @@ public void validate(Update update) {
4139
validateOptional(update.getStartJoins(),
4240
j -> getValidator(SelectValidator.class).validateOptionalJoins(j));
4341

44-
if (update.isUseSelect()) {
45-
validateOptionalExpressions(update.getColumns());
46-
validateOptional(update.getSelect(),
47-
e -> e.accept((SelectVisitor<Void>) getValidator(SelectValidator.class), null));
48-
} else {
49-
validateOptionalExpressions(update.getColumns());
50-
validateOptionalExpressions(update.getExpressions());
51-
}
42+
validateOptionalUpdateSets(update.getUpdateSets());
5243

5344
if (update.getFromItem() != null) {
5445
validateOptionalFromItem(update.getFromItem());
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.util.validation.validator;
11+
12+
import net.sf.jsqlparser.parser.feature.Feature;
13+
import net.sf.jsqlparser.util.validation.ValidationTestAsserts;
14+
import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed;
15+
import org.junit.jupiter.api.Test;
16+
import org.junit.jupiter.params.ParameterizedTest;
17+
import org.junit.jupiter.params.provider.ValueSource;
18+
19+
class UpdateSetValidationTest extends ValidationTestAsserts {
20+
@ParameterizedTest
21+
@ValueSource(strings = {"UPDATE t SET a = ?, b = 1", "UPDATE t SET a = 1, b = ?",
22+
"UPDATE t SET a = 1, b = ?, c = 3", "UPDATE t SET a = 1, b = 2, c = ?",
23+
"UPDATE t SET (b, c) = (2, ?), a = 1",
24+
"UPDATE t SET a = 1, b = (SELECT x FROM s WHERE x = ?)",
25+
"MERGE INTO t USING s ON t.id = s.id WHEN MATCHED THEN UPDATE SET a = 1, b = ?"})
26+
void validatesValuesInEveryAssignment(String sql) {
27+
validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML.copy().remove(Feature.jdbcParameter),
28+
Feature.jdbcParameter);
29+
validateNoErrors(sql, 1, FeaturesAllowed.DML.copy().add(FeaturesAllowed.JDBC));
30+
}
31+
32+
@Test
33+
void reportsIndependentFeaturesAcrossDifferentAssignments() {
34+
validateNotAllowed("UPDATE t SET a = 1, b = COALESCE(c, 0), d = ?", 1, 1,
35+
FeaturesAllowed.UPDATE.copy().remove(Feature.function, Feature.jdbcParameter),
36+
Feature.function, Feature.jdbcParameter);
37+
}
38+
39+
@Test
40+
void keepsTupleAndSubqueryAssignmentsValid() {
41+
validateNoErrors("UPDATE t SET (a, b) = (SELECT c, d FROM s), e = 1", 1,
42+
FeaturesAllowed.UPDATE);
43+
}
44+
}

0 commit comments

Comments
 (0)