Skip to content

Commit e7cf62d

Browse files
schaudermp911de
authored andcommitted
DATAJDBC-335 - Address review comments.
1 parent 949955c commit e7cf62d

File tree

11 files changed

+168
-46
lines changed

11 files changed

+168
-46
lines changed

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.util.HashSet;
1919
import java.util.Set;
2020

21+
import org.springframework.lang.Nullable;
22+
2123
/**
2224
* Validator for statements to import columns.
2325
*
@@ -42,13 +44,7 @@ public void enter(Visitable segment) {
4244
}
4345

4446
if (segment instanceof Where) {
45-
46-
segment.visit(item -> {
47-
48-
if (item instanceof Table) {
49-
requiredByWhere.add((Table) item);
50-
}
51-
});
47+
segment.visit(new SubselectFilteringWhereVisitor());
5248
}
5349

5450
if (segment instanceof Join || segment instanceof OrderByField || segment instanceof From
@@ -63,4 +59,45 @@ public void enter(Visitable segment) {
6359
*/
6460
@Override
6561
public void leave(Visitable segment) {}
62+
63+
/**
64+
* {@link Visitor} that skips sub-{@link Select} and collects columns within a {@link Where} clause.
65+
*/
66+
class SubselectFilteringWhereVisitor implements Visitor {
67+
68+
private @Nullable Select selectFilter;
69+
70+
/*
71+
* (non-Javadoc)
72+
* @see org.springframework.data.relational.core.sql.Visitor#enter(org.springframework.data.relational.core.sql.Visitable)
73+
*/
74+
@Override
75+
public void enter(Visitable segment) {
76+
77+
if (selectFilter != null) {
78+
return;
79+
}
80+
81+
if (segment instanceof Select) {
82+
this.selectFilter = (Select) segment;
83+
return;
84+
}
85+
86+
if (segment instanceof Table) {
87+
requiredByWhere.add((Table) segment);
88+
}
89+
}
90+
91+
/*
92+
* (non-Javadoc)
93+
* @see org.springframework.data.relational.core.sql.Visitor#leave(org.springframework.data.relational.core.sql.Visitable)
94+
*/
95+
@Override
96+
public void leave(Visitable segment) {
97+
98+
if (this.selectFilter == segment) {
99+
this.selectFilter = null;
100+
}
101+
}
102+
}
66103
}

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@ public Expression getValue() {
6565
return value;
6666
}
6767

68-
/*
68+
/*
6969
* (non-Javadoc)
7070
* @see java.lang.Object#toString()
7171
*/
7272
@Override
7373
public String toString() {
7474

75-
StringBuilder builder = new StringBuilder(32);
75+
StringBuilder builder = new StringBuilder();
7676
return builder.append(this.column).append(" = ").append(this.value).toString();
7777
}
7878
}

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class DefaultUpdate implements Update {
4040
this.where = where != null ? new Where(where) : null;
4141
}
4242

43-
/*
43+
/*
4444
* (non-Javadoc)
4545
* @see org.springframework.data.relational.core.sql.Visitable#visit(org.springframework.data.relational.core.sql.Visitor)
4646
*/
@@ -61,22 +61,22 @@ public void visit(Visitor visitor) {
6161
visitor.leave(this);
6262
}
6363

64-
/*
64+
/*
6565
* (non-Javadoc)
6666
* @see java.lang.Object#toString()
6767
*/
6868
@Override
6969
public String toString() {
7070

71-
StringBuilder builder = new StringBuilder(32);
71+
StringBuilder builder = new StringBuilder();
7272
builder.append("UPDATE ").append(table);
7373

7474
if (!assignments.isEmpty()) {
7575
builder.append(" SET ").append(StringUtils.collectionToDelimitedString(this.assignments, ", "));
7676
}
7777

7878
if (this.where != null) {
79-
builder.append(" WHERE ").append(this.where);
79+
builder.append(" ").append(this.where);
8080
}
8181

8282
return builder.toString();

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
package org.springframework.data.relational.core.sql;
1717

1818
import java.util.ArrayList;
19+
import java.util.Arrays;
20+
import java.util.Collection;
1921
import java.util.List;
2022

2123
import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign;
22-
import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssignAnd;
2324
import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhere;
2425
import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr;
2526
import org.springframework.lang.Nullable;
@@ -31,13 +32,13 @@
3132
* @author Mark Paluch
3233
* @since 1.1
3334
*/
34-
class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAndOr, UpdateAssign, UpdateAssignAnd {
35+
class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAndOr, UpdateAssign {
3536

3637
private Table table;
3738
private List<Assignment> assignments = new ArrayList<>();
3839
private @Nullable Condition where;
3940

40-
/*
41+
/*
4142
* (non-Javadoc)
4243
* @see org.springframework.data.relational.core.sql.UpdateBuilder#table(org.springframework.data.relational.core.sql.Table)
4344
*/
@@ -51,7 +52,7 @@ public UpdateAssign table(Table table) {
5152
return this;
5253
}
5354

54-
/*
55+
/*
5556
* (non-Javadoc)
5657
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(org.springframework.data.relational.core.sql.Assignment)
5758
*/
@@ -65,16 +66,33 @@ public DefaultUpdateBuilder set(Assignment assignment) {
6566
return this;
6667
}
6768

68-
/*
69+
/*
6970
* (non-Javadoc)
70-
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssignAnd#and(org.springframework.data.relational.core.sql.Assignment)
71+
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(org.springframework.data.relational.core.sql.Assignment...)
7172
*/
7273
@Override
73-
public DefaultUpdateBuilder and(Assignment assignment) {
74-
return set(assignment);
74+
public UpdateWhere set(Assignment... assignments) {
75+
76+
Assert.notNull(assignments, "Assignment must not be null!");
77+
78+
return set(Arrays.asList(assignments));
79+
}
80+
81+
/*
82+
* (non-Javadoc)
83+
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(java.util.Collection)
84+
*/
85+
@Override
86+
public UpdateWhere set(Collection<? extends Assignment> assignments) {
87+
88+
Assert.notNull(assignments, "Assignment must not be null!");
89+
90+
this.assignments.addAll(assignments);
91+
92+
return this;
7593
}
7694

77-
/*
95+
/*
7896
* (non-Javadoc)
7997
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhere#where(org.springframework.data.relational.core.sql.Condition)
8098
*/
@@ -88,7 +106,7 @@ public UpdateWhereAndOr where(Condition condition) {
88106
return this;
89107
}
90108

91-
/*
109+
/*
92110
* (non-Javadoc)
93111
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr#and(org.springframework.data.relational.core.sql.Condition)
94112
*/
@@ -102,7 +120,7 @@ public UpdateWhereAndOr and(Condition condition) {
102120
return this;
103121
}
104122

105-
/*
123+
/*
106124
* (non-Javadoc)
107125
* @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr#or(org.springframework.data.relational.core.sql.Condition)
108126
*/
@@ -116,7 +134,7 @@ public UpdateWhereAndOr or(Condition condition) {
116134
return this;
117135
}
118136

119-
/*
137+
/*
120138
* (non-Javadoc)
121139
* @see org.springframework.data.relational.core.sql.UpdateBuilder.BuildUpdate#build()
122140
*/

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@
2525
*/
2626
class DeleteValidator extends AbstractImportValidator {
2727

28-
public static void validate(Delete select) {
29-
new DeleteValidator().doValidate(select);
28+
/**
29+
* Validates a {@link Delete} statement.
30+
*
31+
* @param delete the {@link Delete} statement.
32+
* @throws IllegalStateException if the statement is not valid.
33+
*/
34+
public static void validate(Delete delete) {
35+
new DeleteValidator().doValidate(delete);
3036
}
3137

3238
private void doValidate(Delete select) {

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.HashSet;
1919
import java.util.Set;
20+
import java.util.Stack;
2021

2122
/**
2223
* Validator for {@link Select} statements.
@@ -29,12 +30,20 @@
2930
*/
3031
class SelectValidator extends AbstractImportValidator {
3132

33+
private final Stack<Select> selects = new Stack<>();
34+
3235
private int selectFieldCount;
3336
private Set<Table> requiredBySelect = new HashSet<>();
3437
private Set<Table> requiredByOrderBy = new HashSet<>();
3538

3639
private Set<Table> join = new HashSet<>();
3740

41+
/**
42+
* Validates a {@link Select} statement.
43+
*
44+
* @param select the {@link Select} statement.
45+
* @throws IllegalStateException if the statement is not valid.
46+
*/
3847
public static void validate(Select select) {
3948
new SelectValidator().doValidate(select);
4049
}
@@ -76,6 +85,14 @@ private void doValidate(Select select) {
7685
@Override
7786
public void enter(Visitable segment) {
7887

88+
if (segment instanceof Select) {
89+
selects.push((Select) segment);
90+
}
91+
92+
if (selects.size() > 1) {
93+
return;
94+
}
95+
7996
super.enter(segment);
8097

8198
if (segment instanceof AsteriskFromTable && parent instanceof Select) {
@@ -107,15 +124,23 @@ public void enter(Visitable segment) {
107124
if (segment instanceof Table && parent instanceof Join) {
108125
join.add((Table) segment);
109126
}
127+
}
110128

111-
if (segment instanceof Where) {
129+
/*
130+
* (non-Javadoc)
131+
* @see org.springframework.data.relational.core.sql.AbstractImportValidator#leave(org.springframework.data.relational.core.sql.Visitable)
132+
*/
133+
@Override
134+
public void leave(Visitable segment) {
112135

113-
segment.visit(item -> {
136+
if (segment instanceof Select) {
137+
selects.remove(segment);
138+
}
114139

115-
if (item instanceof Table) {
116-
requiredByWhere.add((Table) item);
117-
}
118-
});
140+
if (selects.size() > 1) {
141+
return;
119142
}
143+
144+
super.leave(segment);
120145
}
121146
}

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/UpdateBuilder.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.data.relational.core.sql;
1717

18+
import java.util.Collection;
19+
1820
/**
1921
* Entry point to construct an {@link Update} statement.
2022
*
@@ -44,22 +46,25 @@ interface UpdateAssign {
4446
* @return {@code this} builder.
4547
* @see Assignment
4648
*/
47-
UpdateAssignAnd set(Assignment assignment);
48-
}
49+
UpdateWhere set(Assignment assignment);
4950

50-
/**
51-
* Interface exposing {@code SET} methods.
52-
*/
53-
interface UpdateAssignAnd extends UpdateWhere {
51+
/**
52+
* Apply one or more {@link Assignment SET assignments}.
53+
*
54+
* @param assignments the {@link Assignment column assignments}.
55+
* @return {@code this} builder.
56+
* @see Assignment
57+
*/
58+
UpdateWhere set(Assignment... assignments);
5459

5560
/**
56-
* Apply a {@link Assignment SET assignment}.
61+
* Apply one or more {@link Assignment SET assignments}.
5762
*
58-
* @param assignment a single {@link Assignment column assignment}.
63+
* @param assignments the {@link Assignment column assignments}.
5964
* @return {@code this} builder.
6065
* @see Assignment
6166
*/
62-
UpdateAssignAnd and(Assignment assignment);
67+
UpdateWhere set(Collection<? extends Assignment> assignments);
6368
}
6469

6570
/**

spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/DeleteValidatorUnitTests.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import org.junit.Test;
2121

2222
/**
23-
* Unit tests for {@link SelectValidator}.
23+
* Unit tests for {@link DeleteValidator}.
2424
*
2525
* @author Mark Paluch
2626
*/
@@ -40,4 +40,18 @@ public void shouldReportMissingTableForDeleteViaWhere() {
4040
}).isInstanceOf(IllegalStateException.class)
4141
.hasMessageContaining("Required table [table] by a WHERE predicate not imported by FROM [bar]");
4242
}
43+
44+
@Test // DATAJDBC-335
45+
public void shouldIgnoreImportsFromSubselectsInWhereClause() {
46+
47+
Table foo = SQL.table("foo");
48+
Column bar = foo.column("bar");
49+
50+
Table floo = SQL.table("floo");
51+
Column bah = floo.column("bah");
52+
53+
Select subselect = Select.builder().select(bah).from(floo).build();
54+
55+
assertThat(Delete.builder().from(foo).where(Conditions.in(bar, subselect)).build()).isNotNull();
56+
}
4357
}

0 commit comments

Comments
 (0)