From b286fe1abcb61a5f27db2cf74cc2a39f711f479e Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Fri, 24 Sep 2021 16:39:04 +0200 Subject: [PATCH] [jOOQ/jOOQ#12465] [jOOQ/jOOQ#12432] Extract more CompareConditions Including: - IN - NOT_IN --- jOOQ/src/main/java/org/jooq/Context.java | 15 ++ jOOQ/src/main/java/org/jooq/Field.java | 60 ++++---- .../java/org/jooq/impl/AbstractContext.java | 7 +- .../java/org/jooq/impl/AbstractField.java | 37 +++-- .../main/java/org/jooq/impl/ArraySelect.java | 5 +- .../java/org/jooq/impl/CompareCondition.java | 80 +---------- jOOQ/src/main/java/org/jooq/impl/Eq.java | 10 +- jOOQ/src/main/java/org/jooq/impl/Ge.java | 2 +- jOOQ/src/main/java/org/jooq/impl/Gt.java | 2 +- jOOQ/src/main/java/org/jooq/impl/In.java | 128 ++++++++++++++++++ jOOQ/src/main/java/org/jooq/impl/Le.java | 2 +- jOOQ/src/main/java/org/jooq/impl/Like.java | 12 +- jOOQ/src/main/java/org/jooq/impl/Lt.java | 2 +- jOOQ/src/main/java/org/jooq/impl/Ne.java | 2 +- jOOQ/src/main/java/org/jooq/impl/NotIn.java | 128 ++++++++++++++++++ .../java/org/jooq/impl/ScalarSubquery.java | 3 +- 16 files changed, 350 insertions(+), 145 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/impl/In.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/NotIn.java diff --git a/jOOQ/src/main/java/org/jooq/Context.java b/jOOQ/src/main/java/org/jooq/Context.java index 6583b16485..f2bdc31ada 100644 --- a/jOOQ/src/main/java/org/jooq/Context.java +++ b/jOOQ/src/main/java/org/jooq/Context.java @@ -78,6 +78,21 @@ public interface Context> extends Scope { @NotNull C visit(QueryPart part) throws DataAccessException; + /** + * Visit a QueryPart as a subquery in the current + * Context. + *

+ * This method is called by certain QueryPart implementations + * to recursively visit component QueryParts. + * + * @param part The component QueryPart + * @throws DataAccessException If something went wrong while visiting the + * component QueryPart, e.g. when binding a + * variable + */ + @NotNull + C visitSubquery(QueryPart part) throws DataAccessException; + /** * TODO [#2667] * diff --git a/jOOQ/src/main/java/org/jooq/Field.java b/jOOQ/src/main/java/org/jooq/Field.java index b96bc576dc..bee61acda8 100644 --- a/jOOQ/src/main/java/org/jooq/Field.java +++ b/jOOQ/src/main/java/org/jooq/Field.java @@ -806,6 +806,17 @@ extends @Support Condition gt(Field arg2); + /** + * The IN operator. + *

+ * The subquery must return exactly one field. This is not checked + * by jOOQ and will result in syntax errors in the database, if not used + * correctly. + */ + @NotNull + @Support + Condition in(Select> arg2); + /** * The IS_DISTINCT_FROM operator. *

@@ -1052,6 +1063,21 @@ extends @Support Condition notEqual(Field arg2); + /** + * The NOT_IN operator. + *

+ * The subquery must return exactly one field. This is not checked + * by jOOQ and will result in syntax errors in the database, if not used + * correctly. + *

+ * If any of the passed values is NULL, then the + * condition will be NULL (or false, depending on + * the dialect) as well. This is standard SQL behaviour. + */ + @NotNull + @Support + Condition notIn(Select> arg2); + /** * The NOT_LIKE operator. * @@ -1428,7 +1454,7 @@ extends * also to express the "ARRAY contains" operator. For example:

      * // Use this expression
      * val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })
-     *
+     * 
      * // ... to render this SQL
      * ARRAY[1, 2, 3] @> ARRAY[1, 2]
      * 
@@ -1457,7 +1483,7 @@ extends * also to express the "ARRAY contains" operator. For example:
      * // Use this expression
      * val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })
-     *
+     * 
      * // ... to render this SQL
      * ARRAY[1, 2, 3] @> ARRAY[1, 2]
      * 
@@ -2415,19 +2441,6 @@ extends @Support Condition in(Field... values); - /** - * Create a condition to check this field against a subquery. - *

- * Note that the subquery must return exactly one field. This is not checked - * by jOOQ and will result in syntax errors in the database, if not used - * correctly. - *

- * SQL: this in (select...) - */ - @NotNull - @Support - Condition in(Select> query); - /** * Create a condition to check this field against several values. *

@@ -2520,23 +2533,6 @@ extends @Support Condition notIn(Field... values); - /** - * Create a condition to check this field against a subquery. - *

- * Note that the subquery must return exactly one field. This is not checked - * by jOOQ and will result in syntax errors in the database, if not used - * correctly. - *

- * Note that if any of the passed values is NULL, then the - * condition will be NULL (or false, depending on - * the dialect) as well. This is standard SQL behaviour. - *

- * SQL: this not in (select...) - */ - @NotNull - @Support - Condition notIn(Select> query); - // ------------------------------------------------------------------------ // BETWEEN predicates // ------------------------------------------------------------------------ diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java index 311e73e5a5..d62bc96be7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java @@ -95,7 +95,6 @@ import org.jooq.conf.SettingsTools; import org.jooq.conf.StatementType; import org.jooq.tools.StringUtils; -import org.jetbrains.annotations.NotNull; /** * @author Lukas Eder @@ -309,6 +308,12 @@ abstract class AbstractContext> extends AbstractScope imple return (C) this; } + @Override + public final C visitSubquery(QueryPart part) { + Tools.visitSubquery(this, part); + return (C) this; + } + protected abstract void visit0(QueryPartInternal internal); private final C toggle(boolean b, BooleanSupplier get, BooleanConsumer set, Consumer consumer) { diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java index 99ecd86881..6fe3cdaad3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java @@ -438,6 +438,12 @@ abstract class AbstractField extends AbstractTypedNamed implements Field> arg2) { + return new In(this, arg2); + } + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public final Condition isDistinctFrom(T arg2) { @@ -607,6 +613,12 @@ abstract class AbstractField extends AbstractTypedNamed implements Field> arg2) { + return new NotIn(this, arg2); + } + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public final LikeEscapeStep notLike(String pattern) { @@ -1247,11 +1259,6 @@ abstract class AbstractField extends AbstractTypedNamed implements Field> query) { - return compare(IN, query); - } - @SuppressWarnings("unchecked") @Override public final Condition notIn(T... values) { @@ -1282,11 +1289,6 @@ abstract class AbstractField extends AbstractTypedNamed implements Field> query) { - return compare(NOT_IN, query); - } - @Override public final Condition between(T minValue, T maxValue) { return between(Tools.field(minValue, this), Tools.field(maxValue, this)); @@ -1487,9 +1489,20 @@ abstract class AbstractField extends AbstractTypedNamed implements Field(this, nullSafe(field, getDataType())); - default: - return new CompareCondition(this, nullSafe(field, getDataType()), comparator); + case IN: + if (field instanceof ScalarSubquery) + return new In<>(this, (Select>) ((ScalarSubquery) field).query); + + break; + + case NOT_IN: + if (field instanceof ScalarSubquery) + return new NotIn<>(this, (Select>) ((ScalarSubquery) field).query); + + break; } + + throw new IllegalArgumentException("Comparator not supported: " + comparator); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/ArraySelect.java b/jOOQ/src/main/java/org/jooq/impl/ArraySelect.java index 146a6163b1..7cd2e10570 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ArraySelect.java +++ b/jOOQ/src/main/java/org/jooq/impl/ArraySelect.java @@ -73,8 +73,6 @@ final class ArraySelect extends AbstractField { - - case H2: { Table t = select.asTable("t", "c"); Field c = t.field("c"); @@ -86,8 +84,7 @@ final class ArraySelect extends AbstractField { } default: - ctx.visit(K_ARRAY); - visitSubquery(ctx, select); + ctx.visit(K_ARRAY).visitSubquery(select); break; } diff --git a/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java b/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java index 339bfb7dca..1798e0e32b 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java @@ -38,81 +38,14 @@ package org.jooq.impl; -import static java.lang.Boolean.TRUE; -import static org.jooq.Clause.CONDITION; -import static org.jooq.Clause.CONDITION_COMPARISON; -import static org.jooq.Comparator.IN; -import static org.jooq.Comparator.NOT_IN; -// ... -import static org.jooq.impl.DSL.asterisk; -import static org.jooq.impl.DSL.row; -import static org.jooq.impl.DSL.select; -import static org.jooq.impl.Tools.embeddedFields; -import static org.jooq.impl.Tools.nullSafe; -import static org.jooq.impl.Tools.nullableIf; -import static org.jooq.impl.Tools.BooleanDataKey.DATA_MULTISET_CONDITION; -import static org.jooq.impl.Transformations.subqueryWithLimit; -import static org.jooq.impl.Transformations.transformInConditionSubqueryWithLimitToDerivedTable; - -import org.jooq.Clause; import org.jooq.Comparator; import org.jooq.Context; -import org.jooq.Field; // ... -import org.jooq.Select; /** * @author Lukas Eder */ -final class CompareCondition extends AbstractCondition { - - private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON }; - - final Field field1; - final Field field2; - final Comparator comparator; - - CompareCondition(Field field1, Field field2, Comparator comparator) { - this.field1 = nullableIf(comparator.supportsNulls(), nullSafe(field1, field2.getDataType())); - this.field2 = nullableIf(comparator.supportsNulls(), nullSafe(field2, field1.getDataType())); - this.comparator = comparator; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public final void accept(Context ctx) { - boolean field1Embeddable = field1.getDataType().isEmbeddable(); - SelectQueryImpl s; - - if (field1Embeddable && field2 instanceof ScalarSubquery) - ctx.visit(row(embeddedFields(field1)).compare(comparator, ((ScalarSubquery) field2).query)); - else if (field1Embeddable && field2.getDataType().isEmbeddable()) - ctx.visit(row(embeddedFields(field1)).compare(comparator, embeddedFields(field2))); - else if ((comparator == IN || comparator == NOT_IN) - && (s = subqueryWithLimit(field2)) != null - && transformInConditionSubqueryWithLimitToDerivedTable(ctx.configuration())) { - - - - } - else if (field1.getDataType().isMultiset() - && field2.getDataType().isMultiset() - && !TRUE.equals(ctx.data(DATA_MULTISET_CONDITION))) - ctx.data(DATA_MULTISET_CONDITION, true, c -> c.visit(this)); - else - accept0(ctx); - } - - private final void accept0(Context ctx) { - - - - - - - - ctx.visit(field1).sql(' ').visit(comparator.toKeyword()).sql(' ').visit(field2); - } +final class CompareCondition { @@ -139,15 +72,4 @@ final class CompareCondition extends AbstractCondition { - - - - - - - - @Override - public final Clause[] clauses(Context ctx) { - return CLAUSES; - } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Eq.java b/jOOQ/src/main/java/org/jooq/impl/Eq.java index 3f3be1d4cc..3387954659 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Eq.java +++ b/jOOQ/src/main/java/org/jooq/impl/Eq.java @@ -97,7 +97,7 @@ extends - Eq.acceptCompareCondition(ctx, this, arg1, arg2, RowN::eq, RowN::eq, c -> c.visit(arg1).sql(" = ").visit(arg2)); + Eq.acceptCompareCondition(ctx, this, arg1, org.jooq.Comparator.EQUALS, arg2, RowN::eq, RowN::eq, c -> c.visit(arg1).sql(" = ").visit(arg2)); } @Override @@ -113,6 +113,7 @@ extends Context ctx, AbstractCondition condition, Field arg1, + org.jooq.Comparator op, Field arg2, BiFunction, Condition> compareRowSubquery, BiFunction compareRowRow, @@ -125,6 +126,13 @@ extends ctx.visit(compareRowSubquery.apply(row(embeddedFields(arg1)), ((ScalarSubquery) arg2).query)); else if (field1Embeddable && arg2.getDataType().isEmbeddable()) ctx.visit(compareRowRow.apply(row(embeddedFields(arg1)), row(embeddedFields(arg2)))); + else if ((op == org.jooq.Comparator.IN || op == org.jooq.Comparator.NOT_IN) + && (s = Transformations.subqueryWithLimit(arg2)) != null + && Transformations.transformInConditionSubqueryWithLimitToDerivedTable(ctx.configuration())) { + + + + } else if (arg1.getDataType().isMultiset() && arg2.getDataType().isMultiset() && !Boolean.TRUE.equals(ctx.data(DATA_MULTISET_CONDITION))) diff --git a/jOOQ/src/main/java/org/jooq/impl/Ge.java b/jOOQ/src/main/java/org/jooq/impl/Ge.java index 2c257b0e14..9d30da4eba 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Ge.java +++ b/jOOQ/src/main/java/org/jooq/impl/Ge.java @@ -95,7 +95,7 @@ extends - Eq.acceptCompareCondition(ctx, this, arg1, arg2, RowN::ge, RowN::ge, c -> c.visit(arg1).sql(" >= ").visit(arg2)); + Eq.acceptCompareCondition(ctx, this, arg1, org.jooq.Comparator.GREATER_OR_EQUAL, arg2, RowN::ge, RowN::ge, c -> c.visit(arg1).sql(" >= ").visit(arg2)); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/Gt.java b/jOOQ/src/main/java/org/jooq/impl/Gt.java index 29cf348be4..624f439ac3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Gt.java +++ b/jOOQ/src/main/java/org/jooq/impl/Gt.java @@ -95,7 +95,7 @@ extends - Eq.acceptCompareCondition(ctx, this, arg1, arg2, RowN::gt, RowN::gt, c -> c.visit(arg1).sql(" > ").visit(arg2)); + Eq.acceptCompareCondition(ctx, this, arg1, org.jooq.Comparator.GREATER, arg2, RowN::gt, RowN::gt, c -> c.visit(arg1).sql(" > ").visit(arg2)); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/In.java b/jOOQ/src/main/java/org/jooq/impl/In.java new file mode 100644 index 0000000000..97e0bd88c8 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/In.java @@ -0,0 +1,128 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: http://www.jooq.org/licenses + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.impl; + +import static org.jooq.impl.DSL.*; +import static org.jooq.impl.Internal.*; +import static org.jooq.impl.Keywords.*; +import static org.jooq.impl.Names.*; +import static org.jooq.impl.SQLDataType.*; +import static org.jooq.impl.Tools.*; +import static org.jooq.impl.Tools.BooleanDataKey.*; +import static org.jooq.impl.Tools.DataExtendedKey.*; +import static org.jooq.impl.Tools.DataKey.*; +import static org.jooq.SQLDialect.*; + +import org.jooq.*; +import org.jooq.Record; +import org.jooq.conf.*; +import org.jooq.impl.*; +import org.jooq.tools.*; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + + +/** + * The IN statement. + */ +@SuppressWarnings({ "rawtypes", "unchecked", "unused" }) +final class In +extends + AbstractCondition +{ + + final Field arg1; + final Select> arg2; + + In( + Field arg1, + Select> arg2 + ) { + + this.arg1 = nullSafeNotNull(arg1, (DataType) OTHER); + this.arg2 = arg2; + } + + // ------------------------------------------------------------------------- + // XXX: QueryPart API + // ------------------------------------------------------------------------- + + + + @Override + public final void accept(Context ctx) { + + + + + + + + ScalarSubquery f = new ScalarSubquery<>(arg2, arg1.getDataType()); + Eq.acceptCompareCondition(ctx, this, arg1, org.jooq.Comparator.IN, f, RowN::eq, RowN::eq, c -> c.visit(arg1).sql(' ').visit(K_IN).sql(' ').visit(f)); + } + + + + + + + + + + + + + // ------------------------------------------------------------------------- + // The Object API + // ------------------------------------------------------------------------- + + @Override + public boolean equals(Object that) { + if (that instanceof In) { + return + StringUtils.equals(arg1, ((In) that).arg1) && + StringUtils.equals(arg2, ((In) that).arg2) + ; + } + else + return super.equals(that); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/Le.java b/jOOQ/src/main/java/org/jooq/impl/Le.java index ab6c2f47fa..a9602d1837 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Le.java +++ b/jOOQ/src/main/java/org/jooq/impl/Le.java @@ -95,7 +95,7 @@ extends - Eq.acceptCompareCondition(ctx, this, arg1, arg2, RowN::le, RowN::le, c -> c.visit(arg1).sql(" <= ").visit(arg2)); + Eq.acceptCompareCondition(ctx, this, arg1, org.jooq.Comparator.LESS_OR_EQUAL, arg2, RowN::le, RowN::le, c -> c.visit(arg1).sql(" <= ").visit(arg2)); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/Like.java b/jOOQ/src/main/java/org/jooq/impl/Like.java index 3783341523..d927cd5e51 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Like.java +++ b/jOOQ/src/main/java/org/jooq/impl/Like.java @@ -46,12 +46,6 @@ import static org.jooq.impl.Tools.*; import static org.jooq.impl.Tools.BooleanDataKey.*; import static org.jooq.impl.Tools.DataExtendedKey.*; import static org.jooq.impl.Tools.DataKey.*; -import static org.jooq.Comparator.LIKE; -import static org.jooq.Comparator.LIKE_IGNORE_CASE; -import static org.jooq.Comparator.NOT_LIKE; -import static org.jooq.Comparator.NOT_LIKE_IGNORE_CASE; -import static org.jooq.Comparator.NOT_SIMILAR_TO; -import static org.jooq.Comparator.SIMILAR_TO; import static org.jooq.SQLDialect.*; import org.jooq.*; @@ -165,7 +159,7 @@ implements // [#1159] [#1725] Some dialects cannot auto-convert the LHS operand to a // VARCHAR when applying a LIKE predicate - if ((op == LIKE || op == NOT_LIKE || op == SIMILAR_TO || op == NOT_SIMILAR_TO) + if ((op == org.jooq.Comparator.LIKE || op == org.jooq.Comparator.NOT_LIKE || op == org.jooq.Comparator.SIMILAR_TO || op == org.jooq.Comparator.NOT_SIMILAR_TO) && arg1.getType() != String.class && REQUIRES_CAST_ON_LIKE.contains(ctx.dialect())) { arg1 = castIfNeeded(arg1, String.class); @@ -173,10 +167,10 @@ implements // [#1423] [#9889] PostgreSQL and H2 support ILIKE natively. Other dialects // need to emulate this as LOWER(lhs) LIKE LOWER(rhs) - else if ((op == LIKE_IGNORE_CASE || op == NOT_LIKE_IGNORE_CASE) && NO_SUPPORT_ILIKE.contains(ctx.dialect())) { + else if ((op == org.jooq.Comparator.LIKE_IGNORE_CASE || op == org.jooq.Comparator.NOT_LIKE_IGNORE_CASE) && NO_SUPPORT_ILIKE.contains(ctx.dialect())) { arg1 = DSL.lower((Field) arg1); arg2 = DSL.lower((Field) arg2); - op = (op == LIKE_IGNORE_CASE ? LIKE : NOT_LIKE); + op = (op == org.jooq.Comparator.LIKE_IGNORE_CASE ? org.jooq.Comparator.LIKE : org.jooq.Comparator.NOT_LIKE); } boolean castRhs = castRhs(ctx, arg2); diff --git a/jOOQ/src/main/java/org/jooq/impl/Lt.java b/jOOQ/src/main/java/org/jooq/impl/Lt.java index 1a970df12f..cf16c4eac7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Lt.java +++ b/jOOQ/src/main/java/org/jooq/impl/Lt.java @@ -95,7 +95,7 @@ extends - Eq.acceptCompareCondition(ctx, this, arg1, arg2, RowN::lt, RowN::lt, c -> c.visit(arg1).sql(" < ").visit(arg2)); + Eq.acceptCompareCondition(ctx, this, arg1, org.jooq.Comparator.LESS, arg2, RowN::lt, RowN::lt, c -> c.visit(arg1).sql(" < ").visit(arg2)); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/Ne.java b/jOOQ/src/main/java/org/jooq/impl/Ne.java index 5f2347ecba..b91bc58e56 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Ne.java +++ b/jOOQ/src/main/java/org/jooq/impl/Ne.java @@ -95,7 +95,7 @@ extends - Eq.acceptCompareCondition(ctx, this, arg1, arg2, RowN::ne, RowN::ne, c -> c.visit(arg1).sql(" <> ").visit(arg2)); + Eq.acceptCompareCondition(ctx, this, arg1, org.jooq.Comparator.NOT_EQUALS, arg2, RowN::ne, RowN::ne, c -> c.visit(arg1).sql(" <> ").visit(arg2)); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/NotIn.java b/jOOQ/src/main/java/org/jooq/impl/NotIn.java new file mode 100644 index 0000000000..001019b380 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/NotIn.java @@ -0,0 +1,128 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: http://www.jooq.org/licenses + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.impl; + +import static org.jooq.impl.DSL.*; +import static org.jooq.impl.Internal.*; +import static org.jooq.impl.Keywords.*; +import static org.jooq.impl.Names.*; +import static org.jooq.impl.SQLDataType.*; +import static org.jooq.impl.Tools.*; +import static org.jooq.impl.Tools.BooleanDataKey.*; +import static org.jooq.impl.Tools.DataExtendedKey.*; +import static org.jooq.impl.Tools.DataKey.*; +import static org.jooq.SQLDialect.*; + +import org.jooq.*; +import org.jooq.Record; +import org.jooq.conf.*; +import org.jooq.impl.*; +import org.jooq.tools.*; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + + +/** + * The NOT IN statement. + */ +@SuppressWarnings({ "rawtypes", "unchecked", "unused" }) +final class NotIn +extends + AbstractCondition +{ + + final Field arg1; + final Select> arg2; + + NotIn( + Field arg1, + Select> arg2 + ) { + + this.arg1 = nullSafeNotNull(arg1, (DataType) OTHER); + this.arg2 = arg2; + } + + // ------------------------------------------------------------------------- + // XXX: QueryPart API + // ------------------------------------------------------------------------- + + + + @Override + public final void accept(Context ctx) { + + + + + + + + ScalarSubquery f = new ScalarSubquery<>(arg2, arg1.getDataType()); + Eq.acceptCompareCondition(ctx, this, arg1, org.jooq.Comparator.NOT_IN, f, RowN::eq, RowN::eq, c -> c.visit(arg1).sql(' ').visit(K_NOT_IN).sql(' ').visit(f)); + } + + + + + + + + + + + + + // ------------------------------------------------------------------------- + // The Object API + // ------------------------------------------------------------------------- + + @Override + public boolean equals(Object that) { + if (that instanceof NotIn) { + return + StringUtils.equals(arg1, ((NotIn) that).arg1) && + StringUtils.equals(arg2, ((NotIn) that).arg2) + ; + } + else + return super.equals(that); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/ScalarSubquery.java b/jOOQ/src/main/java/org/jooq/impl/ScalarSubquery.java index 6cf15f25d1..61ac4445cf 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ScalarSubquery.java +++ b/jOOQ/src/main/java/org/jooq/impl/ScalarSubquery.java @@ -50,6 +50,7 @@ import java.util.Set; import org.jooq.Context; import org.jooq.DataType; +import org.jooq.Record1; import org.jooq.SQLDialect; import org.jooq.Select; @@ -77,8 +78,6 @@ final class ScalarSubquery extends AbstractField { - - // HSQLDB allows for using WITH inside of IN, see: https://sourceforge.net/p/hsqldb/bugs/1617/ // We'll still emulate CTE in scalar subqueries with a derived tables in all cases. if (q != null && q.with != null && NO_SUPPORT_WITH_IN_SCALAR_SUBQUERY.contains(ctx.dialect()))