diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java index 1a56627a5..12c41a7d8 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AbstractImportValidator.java @@ -18,6 +18,8 @@ package org.springframework.data.relational.core.sql; import java.util.HashSet; import java.util.Set; +import org.springframework.lang.Nullable; + /** * Validator for statements to import columns. * @@ -42,13 +44,7 @@ abstract class AbstractImportValidator implements Visitor { } if (segment instanceof Where) { - - segment.visit(item -> { - - if (item instanceof Table) { - requiredByWhere.add((Table) item); - } - }); + segment.visit(new SubselectFilteringWhereVisitor()); } if (segment instanceof Join || segment instanceof OrderByField || segment instanceof From @@ -63,4 +59,45 @@ abstract class AbstractImportValidator implements Visitor { */ @Override public void leave(Visitable segment) {} + + /** + * {@link Visitor} that skips sub-{@link Select} and collects columns within a {@link Where} clause. + */ + class SubselectFilteringWhereVisitor implements Visitor { + + private @Nullable Select selectFilter; + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.core.sql.Visitor#enter(org.springframework.data.relational.core.sql.Visitable) + */ + @Override + public void enter(Visitable segment) { + + if (selectFilter != null) { + return; + } + + if (segment instanceof Select) { + this.selectFilter = (Select) segment; + return; + } + + if (segment instanceof Table) { + requiredByWhere.add((Table) segment); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.core.sql.Visitor#leave(org.springframework.data.relational.core.sql.Visitable) + */ + @Override + public void leave(Visitable segment) { + + if (this.selectFilter == segment) { + this.selectFilter = null; + } + } + } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java index 8ded7e530..8304bf56a 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/AssignValue.java @@ -65,14 +65,14 @@ public class AssignValue extends AbstractSegment implements Assignment { return value; } - /* + /* * (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { - StringBuilder builder = new StringBuilder(32); + StringBuilder builder = new StringBuilder(); return builder.append(this.column).append(" = ").append(this.value).toString(); } } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java index 74ba30f2e..135fdffde 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdate.java @@ -40,7 +40,7 @@ class DefaultUpdate implements Update { this.where = where != null ? new Where(where) : null; } - /* + /* * (non-Javadoc) * @see org.springframework.data.relational.core.sql.Visitable#visit(org.springframework.data.relational.core.sql.Visitor) */ @@ -61,14 +61,14 @@ class DefaultUpdate implements Update { visitor.leave(this); } - /* + /* * (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { - StringBuilder builder = new StringBuilder(32); + StringBuilder builder = new StringBuilder(); builder.append("UPDATE ").append(table); if (!assignments.isEmpty()) { @@ -76,7 +76,7 @@ class DefaultUpdate implements Update { } if (this.where != null) { - builder.append(" WHERE ").append(this.where); + builder.append(" ").append(this.where); } return builder.toString(); diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java index 8418765cf..8fcbb3c33 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DefaultUpdateBuilder.java @@ -16,10 +16,11 @@ package org.springframework.data.relational.core.sql; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign; -import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssignAnd; import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhere; import org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr; import org.springframework.lang.Nullable; @@ -31,13 +32,13 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 1.1 */ -class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAndOr, UpdateAssign, UpdateAssignAnd { +class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAndOr, UpdateAssign { private Table table; private List assignments = new ArrayList<>(); private @Nullable Condition where; - /* + /* * (non-Javadoc) * @see org.springframework.data.relational.core.sql.UpdateBuilder#table(org.springframework.data.relational.core.sql.Table) */ @@ -51,7 +52,7 @@ class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAnd return this; } - /* + /* * (non-Javadoc) * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(org.springframework.data.relational.core.sql.Assignment) */ @@ -65,16 +66,33 @@ class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAnd return this; } - /* + /* * (non-Javadoc) - * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssignAnd#and(org.springframework.data.relational.core.sql.Assignment) + * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(org.springframework.data.relational.core.sql.Assignment...) */ @Override - public DefaultUpdateBuilder and(Assignment assignment) { - return set(assignment); + public UpdateWhere set(Assignment... assignments) { + + Assert.notNull(assignments, "Assignment must not be null!"); + + return set(Arrays.asList(assignments)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateAssign#set(java.util.Collection) + */ + @Override + public UpdateWhere set(Collection assignments) { + + Assert.notNull(assignments, "Assignment must not be null!"); + + this.assignments.addAll(assignments); + + return this; } - /* + /* * (non-Javadoc) * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhere#where(org.springframework.data.relational.core.sql.Condition) */ @@ -88,7 +106,7 @@ class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAnd return this; } - /* + /* * (non-Javadoc) * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr#and(org.springframework.data.relational.core.sql.Condition) */ @@ -102,7 +120,7 @@ class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAnd return this; } - /* + /* * (non-Javadoc) * @see org.springframework.data.relational.core.sql.UpdateBuilder.UpdateWhereAndOr#or(org.springframework.data.relational.core.sql.Condition) */ @@ -116,7 +134,7 @@ class DefaultUpdateBuilder implements UpdateBuilder, UpdateWhere, UpdateWhereAnd return this; } - /* + /* * (non-Javadoc) * @see org.springframework.data.relational.core.sql.UpdateBuilder.BuildUpdate#build() */ diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java index bf07e0e2f..51e327727 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/DeleteValidator.java @@ -25,8 +25,14 @@ package org.springframework.data.relational.core.sql; */ class DeleteValidator extends AbstractImportValidator { - public static void validate(Delete select) { - new DeleteValidator().doValidate(select); + /** + * Validates a {@link Delete} statement. + * + * @param delete the {@link Delete} statement. + * @throws IllegalStateException if the statement is not valid. + */ + public static void validate(Delete delete) { + new DeleteValidator().doValidate(delete); } private void doValidate(Delete select) { diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java index d8254c937..5a199bf32 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/SelectValidator.java @@ -17,6 +17,7 @@ package org.springframework.data.relational.core.sql; import java.util.HashSet; import java.util.Set; +import java.util.Stack; /** * Validator for {@link Select} statements. @@ -29,12 +30,20 @@ import java.util.Set; */ class SelectValidator extends AbstractImportValidator { + private final Stack