[jOOQ/jOOQ#14560] Refactor QuantifiedSelectImpl into separate subtypes
This commit is contained in:
parent
361fd95cc9
commit
eb6ce5087e
@ -120,8 +120,8 @@ final class Array<T> extends AbstractField<T[]> implements QOM.Array<T> {
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final UnmodifiableList<? extends Field<?>> $elements() {
|
||||
return QOM.unmodifiable(fields.fields);
|
||||
public final UnmodifiableList<? extends Field<T>> $elements() {
|
||||
return (UnmodifiableList<? extends Field<T>>) QOM.unmodifiable(fields.fields);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -37,7 +37,6 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.Keywords.K_TABLE;
|
||||
import static org.jooq.impl.Keywords.K_UNNEST;
|
||||
import static org.jooq.impl.Names.N_ARRAY_TABLE;
|
||||
|
||||
@ -432,6 +432,7 @@ import org.jooq.conf.RenderQuotedNames;
|
||||
import org.jooq.conf.Settings;
|
||||
import org.jooq.exception.SQLDialectNotSupportedException;
|
||||
import org.jooq.impl.QOM.DocumentOrContent;
|
||||
import org.jooq.impl.QOM.Quantifier;
|
||||
import org.jooq.impl.QOM.ResultOption;
|
||||
import org.jooq.tools.StringUtils;
|
||||
import org.jooq.tools.jdbc.JDBCUtils;
|
||||
@ -10917,7 +10918,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, YUGABYTEDB })
|
||||
public static <T> QuantifiedSelect<Record1<T>> all(T... array) {
|
||||
return array instanceof Field[] ? all((Field<T>[]) array) : new QuantifiedSelectImpl<>(Quantifier.ALL, val(array));
|
||||
return array instanceof Field[] ? all((Field<T>[]) array) : new QuantifiedArray<>(Quantifier.ALL, val(array));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10938,7 +10939,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, YUGABYTEDB })
|
||||
public static <T> QuantifiedSelect<Record1<T>> all(Field<T[]> array) {
|
||||
return new QuantifiedSelectImpl<>(Quantifier.ALL, array);
|
||||
return new QuantifiedArray<>(Quantifier.ALL, array);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10960,7 +10961,7 @@ public class DSL {
|
||||
@Support
|
||||
@SafeVarargs
|
||||
public static <T> QuantifiedSelect<Record1<T>> all(Field<T>... fields) {
|
||||
return new QuantifiedSelectImpl<>(Quantifier.ALL, fields);
|
||||
return new QuantifiedArray<>(Quantifier.ALL, new Array<>(asList(fields)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10999,7 +11000,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, YUGABYTEDB })
|
||||
public static <T> QuantifiedSelect<Record1<T>> any(T... array) {
|
||||
return array instanceof Field[] ? any((Field<T>[]) array) : new QuantifiedSelectImpl<>(Quantifier.ANY, val(array));
|
||||
return array instanceof Field[] ? any((Field<T>[]) array) : new QuantifiedArray<>(Quantifier.ANY, val(array));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -11020,7 +11021,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, YUGABYTEDB })
|
||||
public static <T> QuantifiedSelect<Record1<T>> any(Field<T[]> array) {
|
||||
return new QuantifiedSelectImpl<>(Quantifier.ANY, array);
|
||||
return new QuantifiedArray<>(Quantifier.ANY, array);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -11042,7 +11043,7 @@ public class DSL {
|
||||
@Support
|
||||
@SafeVarargs
|
||||
public static <T> QuantifiedSelect<Record1<T>> any(Field<T>... fields) {
|
||||
return new QuantifiedSelectImpl<>(Quantifier.ANY, fields);
|
||||
return new QuantifiedArray<>(Quantifier.ANY, new Array<>(asList(fields)));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -1016,6 +1016,40 @@ public final class QOM {
|
||||
@NotNull default Select<?> $field() { return $arg1(); }
|
||||
}
|
||||
|
||||
public sealed interface Quantified
|
||||
extends
|
||||
org.jooq.QueryPart
|
||||
permits
|
||||
QuantifiedSelect,
|
||||
QuantifiedArray
|
||||
{}
|
||||
|
||||
public sealed interface QuantifiedSelect<R extends Record>
|
||||
extends
|
||||
Quantified,
|
||||
UOperator2<Quantifier, Select<R>, QuantifiedSelect<R>>
|
||||
permits
|
||||
org.jooq.impl.QuantifiedSelectImpl
|
||||
{
|
||||
@NotNull default Quantifier $quantifier() { return $arg1(); }
|
||||
@NotNull default QuantifiedSelect<R> $quantifier(Quantifier newQuantifier) { return $arg1(newQuantifier); }
|
||||
@NotNull default Select<R> $select() { return $arg2(); }
|
||||
@NotNull default QuantifiedSelect<R> $array(Select<R> newSelect) { return $arg2(newSelect); }
|
||||
}
|
||||
|
||||
public sealed interface QuantifiedArray<T>
|
||||
extends
|
||||
Quantified,
|
||||
UOperator2<Quantifier, Field<T[]>, QuantifiedArray<T>>
|
||||
permits
|
||||
org.jooq.impl.QuantifiedArray
|
||||
{
|
||||
@NotNull default Quantifier $quantifier() { return $arg1(); }
|
||||
@NotNull default QuantifiedArray<T> $quantifier(Quantifier newQuantifier) { return $arg1(newQuantifier); }
|
||||
@NotNull default Field<T[]> $array() { return $arg2(); }
|
||||
@NotNull default QuantifiedArray<T> $array(Field<T[]> newArray) { return $arg2(newArray); }
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Rows
|
||||
@ -1506,7 +1540,7 @@ public final class QOM {
|
||||
/*permits
|
||||
org.jooq.impl.Array*/
|
||||
{
|
||||
@NotNull UnmodifiableList<? extends Field<?>> $elements();
|
||||
@NotNull UnmodifiableList<? extends Field<T>> $elements();
|
||||
}
|
||||
|
||||
public /*sealed*/ interface ArrayQuery<T>
|
||||
@ -8257,6 +8291,23 @@ public final class QOM {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>Quantifier</code> type.
|
||||
* <p>
|
||||
* A quantifier for quantified selects.
|
||||
*/
|
||||
public enum Quantifier {
|
||||
ANY(keyword("any")),
|
||||
ALL(keyword("all")),
|
||||
;
|
||||
|
||||
final Keyword keyword;
|
||||
|
||||
private Quantifier(Keyword keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
192
jOOQ/src/main/java/org/jooq/impl/QuantifiedArray.java
Normal file
192
jOOQ/src/main/java/org/jooq/impl/QuantifiedArray.java
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.table;
|
||||
import static org.jooq.impl.DSL.val;
|
||||
import static org.jooq.impl.QOM.Quantifier.ANY;
|
||||
import static org.jooq.impl.SubqueryCharacteristics.PREDICAND;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Function2;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.QuantifiedSelect;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Record1;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.impl.QOM.Quantifier;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
import org.jooq.impl.Tools.BooleanDataKey;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class QuantifiedArray<T>
|
||||
extends
|
||||
AbstractQueryPart
|
||||
implements
|
||||
QuantifiedSelect<Record1<T>>,
|
||||
QOM.QuantifiedArray<T> {
|
||||
|
||||
final Quantifier quantifier;
|
||||
final Field<T[]> array;
|
||||
|
||||
QuantifiedArray(Quantifier quantifier, Field<T[]> array) {
|
||||
this.quantifier = quantifier;
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
boolean extraParentheses = false ;
|
||||
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
ctx.visit(quantifier.keyword);
|
||||
ctx.sql(extraParentheses ? " ((" : " (");
|
||||
visitSubquery(ctx, delegate(ctx), PREDICAND, false);
|
||||
ctx.sql(extraParentheses ? "))" : ")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private final QueryPart delegate(Context<?> ctx) {
|
||||
if (array instanceof QOM.Array<T> a) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
// [#869] Postgres supports this syntax natively
|
||||
|
||||
|
||||
case POSTGRES:
|
||||
case YUGABYTEDB:
|
||||
return array;
|
||||
|
||||
default: {
|
||||
Select<Record1<T>> select = null;
|
||||
|
||||
for (Field<T> value : a.$elements())
|
||||
if (select == null)
|
||||
select = select(value);
|
||||
else
|
||||
select = select.unionAll(select(value));
|
||||
|
||||
return select;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (ctx.family()) {
|
||||
|
||||
// [#869] Postgres supports this syntax natively
|
||||
|
||||
|
||||
case POSTGRES:
|
||||
case YUGABYTEDB:
|
||||
return array;
|
||||
|
||||
// [#869] H2 and HSQLDB can emulate this syntax by unnesting
|
||||
// the array in a subselect
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
return select().from(table(array));
|
||||
|
||||
// [#1048] All other dialects emulate unnesting of arrays using
|
||||
// UNION ALL-connected subselects
|
||||
default: {
|
||||
|
||||
// The Informix database has an interesting bug when quantified comparison predicates
|
||||
// use nested derived tables with UNION ALL
|
||||
if (array instanceof Param) {
|
||||
Object[] values0 = ((Param<? extends Object[]>) array).getValue();
|
||||
|
||||
Select<Record1<Object>> select = null;
|
||||
for (Object value : values0)
|
||||
if (select == null)
|
||||
select = select(val(value));
|
||||
else
|
||||
select = select.unionAll(select(val(value)));
|
||||
|
||||
return select;
|
||||
}
|
||||
else
|
||||
return select().from(table(array));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Function2<? super Quantifier, ? super Field<T[]>, ? extends QuantifiedArray<T>> $constructor() {
|
||||
return (q, a) -> new QuantifiedArray<>(q, a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Quantifier $arg1() {
|
||||
return quantifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T[]> $arg2() {
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@ -80,6 +80,7 @@ import static org.jooq.impl.SQLDataType.VARCHAR;
|
||||
import static org.jooq.impl.Tools.characterLiteral;
|
||||
import static org.jooq.impl.Tools.embeddedFields;
|
||||
import static org.jooq.impl.Tools.map;
|
||||
import static org.jooq.impl.Tools.quantify;
|
||||
import static org.jooq.impl.Transformations.transformInConditionSubqueryWithLimitToDerivedTable;
|
||||
import static org.jooq.impl.Transformations.subqueryWithLimit;
|
||||
import static org.jooq.tools.Convert.convert;
|
||||
@ -99,6 +100,8 @@ import org.jooq.Record1;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.impl.QOM.Array;
|
||||
import org.jooq.impl.QOM.Quantifier;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
|
||||
/**
|
||||
@ -106,18 +109,18 @@ import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
*/
|
||||
final class QuantifiedComparisonCondition extends AbstractCondition implements LikeEscapeStep, UNotYetImplemented {
|
||||
|
||||
private static final Clause[] CLAUSES = { CONDITION, CONDITION_BETWEEN };
|
||||
private static final Set<SQLDialect> NO_SUPPORT_QUANTIFIED_LIKE = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, SQLITE);
|
||||
private static final Set<SQLDialect> NO_SUPPORT_QUANTIFIED_SIMILAR_TO = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTEDB);
|
||||
private static final Set<SQLDialect> SUPPORTS_QUANTIFIED_ARRAYS = SQLDialect.supportedBy(POSTGRES);
|
||||
private static final Clause[] CLAUSES = { CONDITION, CONDITION_BETWEEN };
|
||||
private static final Set<SQLDialect> NO_SUPPORT_QUANTIFIED_LIKE = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, SQLITE);
|
||||
private static final Set<SQLDialect> NO_SUPPORT_QUANTIFIED_SIMILAR_TO = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTEDB);
|
||||
private static final Set<SQLDialect> SUPPORTS_QUANTIFIED_ARRAYS = SQLDialect.supportedBy(POSTGRES);
|
||||
|
||||
private final QuantifiedSelectImpl<?> query;
|
||||
private final Field<?> field;
|
||||
private final Comparator comparator;
|
||||
private Character escape;
|
||||
private final QuantifiedSelect<?> query;
|
||||
private final Field<?> field;
|
||||
private final Comparator comparator;
|
||||
private Character escape;
|
||||
|
||||
QuantifiedComparisonCondition(QuantifiedSelect<?> query, Field<?> field, Comparator comparator) {
|
||||
this.query = (QuantifiedSelectImpl<?>) query;
|
||||
this.query = query;
|
||||
this.field = field;
|
||||
this.comparator = comparator;
|
||||
}
|
||||
@ -137,11 +140,15 @@ final class QuantifiedComparisonCondition extends AbstractCondition implements L
|
||||
ctx.visit(row(embeddedFields(field)).compare(comparator, query));
|
||||
}
|
||||
else if ((comparator == EQUALS || comparator == NOT_EQUALS)
|
||||
&& (s = subqueryWithLimit(query.query)) != null
|
||||
&& (query instanceof QOM.QuantifiedSelect)
|
||||
&& (s = subqueryWithLimit(((QOM.QuantifiedSelect<?>) query).$select())) != null
|
||||
&& transformInConditionSubqueryWithLimitToDerivedTable(ctx.configuration())) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -157,9 +164,9 @@ final class QuantifiedComparisonCondition extends AbstractCondition implements L
|
||||
accept0(ctx);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
private final void accept0(Context<?> ctx) {
|
||||
boolean quantifiedArray = query.array instanceof Param<?>;
|
||||
boolean quantifiedArrayParam = query instanceof QOM.QuantifiedArray<?> a ? a.$arg2() instanceof Param : false;
|
||||
boolean quantifiedArray = query instanceof QOM.QuantifiedArray<?> a ? a.$arg2() instanceof Array : false;
|
||||
boolean emulateOperator;
|
||||
|
||||
switch (comparator) {
|
||||
@ -180,21 +187,23 @@ final class QuantifiedComparisonCondition extends AbstractCondition implements L
|
||||
|
||||
// [#9224] Special case when a SQL dialect actually supports quantified
|
||||
// arrays, such as x = any(?::int[]) in PostgreSQL
|
||||
if (quantifiedArray && SUPPORTS_QUANTIFIED_ARRAYS.contains(ctx.dialect()) && !emulateOperator) {
|
||||
if (quantifiedArrayParam && SUPPORTS_QUANTIFIED_ARRAYS.contains(ctx.dialect()) && !emulateOperator) {
|
||||
accept1(ctx);
|
||||
}
|
||||
else if (query.values != null || quantifiedArray) {
|
||||
else if (quantifiedArrayParam || quantifiedArray) {
|
||||
QOM.QuantifiedArray<?> a = (org.jooq.impl.QOM.QuantifiedArray<?>) query;
|
||||
ctx.visit(DSL.condition(
|
||||
query.quantifier == Quantifier.ALL ? Operator.AND : Operator.OR,
|
||||
query.values != null
|
||||
? map(query.values, v -> comparisonCondition(comparator, (Field<String>) v))
|
||||
: map(((Param<? extends Object[]>) query.array).getValue(), v -> v instanceof Field ? comparisonCondition(comparator, (Field<String>) v) : comparisonCondition(comparator, v))
|
||||
a.$quantifier() == Quantifier.ALL ? Operator.AND : Operator.OR,
|
||||
a.$array() instanceof Array
|
||||
? map(((Array) a.$array()).$elements(), v -> comparisonCondition(comparator, (Field<String>) v))
|
||||
: map(((Param<? extends Object[]>) a.$array()).getValue(), v -> v instanceof Field ? comparisonCondition(comparator, (Field<String>) v) : comparisonCondition(comparator, v))
|
||||
));
|
||||
}
|
||||
else if ((query.array != null || query.query != null) && emulateOperator) {
|
||||
else if (emulateOperator) {
|
||||
Field<String> pattern = DSL.field(name("pattern"), VARCHAR);
|
||||
Condition condition;
|
||||
Field<Boolean> lhs;
|
||||
|
||||
switch (comparator) {
|
||||
case NOT_LIKE:
|
||||
case NOT_SIMILAR_TO:
|
||||
@ -212,11 +221,20 @@ final class QuantifiedComparisonCondition extends AbstractCondition implements L
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
Table<?> t = query.array != null
|
||||
? new ArrayTable(query.array).asTable("t", "pattern")
|
||||
: new AliasedSelect<>(query.query, true, true, false, name("pattern")).as("t");
|
||||
Select<Record1<Boolean>> select = select(condition).from(t);
|
||||
ctx.visit(lhs.eq(query.quantifier.apply(select)));
|
||||
Table<?> t;
|
||||
Quantifier q;
|
||||
|
||||
if (query instanceof QuantifiedArray<?> a) {
|
||||
t = new ArrayTable(a.$array()).asTable("t", "pattern");
|
||||
q = a.$quantifier();
|
||||
}
|
||||
else {
|
||||
QOM.QuantifiedSelect<?> s = (QOM.QuantifiedSelect<?>) query;
|
||||
t = new AliasedSelect<>(s.$select(), true, true, false, name("pattern")).as("t");
|
||||
q = s.$quantifier();
|
||||
}
|
||||
|
||||
ctx.visit(lhs.eq(quantify(q, select(condition).from(t))));
|
||||
}
|
||||
else {
|
||||
accept1(ctx);
|
||||
|
||||
@ -39,55 +39,40 @@ package org.jooq.impl;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.table;
|
||||
import static org.jooq.impl.DSL.val;
|
||||
import static org.jooq.impl.Quantifier.ANY;
|
||||
import static org.jooq.impl.QOM.Quantifier.ANY;
|
||||
import static org.jooq.impl.SubqueryCharacteristics.PREDICAND;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.Function2;
|
||||
import org.jooq.QuantifiedSelect;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Record1;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
import org.jooq.impl.QOM.Quantifier;
|
||||
import org.jooq.impl.Tools.BooleanDataKey;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class QuantifiedSelectImpl<R extends Record> extends AbstractQueryPart implements QuantifiedSelect<R>, UNotYetImplemented {
|
||||
final class QuantifiedSelectImpl<R extends Record>
|
||||
extends
|
||||
AbstractQueryPart
|
||||
implements
|
||||
QuantifiedSelect<R>,
|
||||
QOM.QuantifiedSelect<R>
|
||||
{
|
||||
|
||||
final Quantifier quantifier;
|
||||
final Select<R> query;
|
||||
final Field<? extends Object[]> array;
|
||||
final Field<?>[] values;
|
||||
final Quantifier quantifier;
|
||||
final Select<R> query;
|
||||
|
||||
QuantifiedSelectImpl(Quantifier quantifier, Select<R> query) {
|
||||
this.quantifier = quantifier;
|
||||
this.query = query;
|
||||
this.array = null;
|
||||
this.values = null;
|
||||
}
|
||||
|
||||
QuantifiedSelectImpl(Quantifier quantifier, Field<? extends Object[]> array) {
|
||||
this.quantifier = quantifier;
|
||||
this.query = null;
|
||||
this.array = array;
|
||||
this.values = null;
|
||||
}
|
||||
|
||||
QuantifiedSelectImpl(Quantifier quantifier, Field<?>... values) {
|
||||
this.quantifier = quantifier;
|
||||
this.query = null;
|
||||
this.array = null;
|
||||
this.values = values;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
@ -102,77 +87,31 @@ final class QuantifiedSelectImpl<R extends Record> extends AbstractQueryPart imp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
ctx.visit(quantifier.toKeyword());
|
||||
ctx.visit(quantifier.keyword);
|
||||
ctx.sql(extraParentheses ? " ((" : " (");
|
||||
visitSubquery(ctx, delegate(ctx.configuration()), PREDICAND, false);
|
||||
visitSubquery(ctx, query, PREDICAND, false);
|
||||
ctx.sql(extraParentheses ? "))" : ")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private final QueryPart delegate(Configuration ctx) {
|
||||
if (query != null) {
|
||||
return query;
|
||||
}
|
||||
else if (values != null) {
|
||||
Select<Record1<?>> select = null;
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
for (Field value : values)
|
||||
if (select == null)
|
||||
select = select(value);
|
||||
else
|
||||
select = select.unionAll(select(value));
|
||||
@Override
|
||||
public final Function2<? super Quantifier, ? super Select<R>, ? extends QOM.QuantifiedSelect<R>> $constructor() {
|
||||
return (q, s) -> new QuantifiedSelectImpl<>(q, s);
|
||||
}
|
||||
|
||||
return select;
|
||||
}
|
||||
else {
|
||||
switch (ctx.family()) {
|
||||
@Override
|
||||
public final Quantifier $arg1() {
|
||||
return quantifier;
|
||||
}
|
||||
|
||||
// [#869] Postgres supports this syntax natively
|
||||
|
||||
|
||||
case POSTGRES:
|
||||
case YUGABYTEDB:
|
||||
return array;
|
||||
|
||||
// [#869] H2 and HSQLDB can emulate this syntax by unnesting
|
||||
// the array in a subselect
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
return create(ctx).select().from(table(array));
|
||||
|
||||
// [#1048] All other dialects emulate unnesting of arrays using
|
||||
// UNION ALL-connected subselects
|
||||
default: {
|
||||
|
||||
// The Informix database has an interesting bug when quantified comparison predicates
|
||||
// use nested derived tables with UNION ALL
|
||||
if (array instanceof Param) {
|
||||
Object[] values0 = ((Param<? extends Object[]>) array).getValue();
|
||||
|
||||
Select<Record1<Object>> select = null;
|
||||
for (Object value : values0)
|
||||
if (select == null)
|
||||
select = select(val(value));
|
||||
else
|
||||
select = select.unionAll(select(val(value)));
|
||||
|
||||
return select;
|
||||
}
|
||||
else {
|
||||
return select().from(table(array));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final Select<R> $arg2() {
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.all;
|
||||
import static org.jooq.impl.DSL.any;
|
||||
|
||||
import org.jooq.Keyword;
|
||||
import org.jooq.QuantifiedSelect;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Select;
|
||||
|
||||
/**
|
||||
* A quantifier used for quantified comparison predicates
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
enum Quantifier {
|
||||
|
||||
/**
|
||||
* The <code>ANY</code> quantifier
|
||||
*/
|
||||
ANY("any"),
|
||||
|
||||
/**
|
||||
* The <code>ALL</code> quantifier
|
||||
*/
|
||||
ALL("all"),
|
||||
|
||||
;
|
||||
|
||||
private final String sql;
|
||||
private final Keyword keyword;
|
||||
|
||||
private Quantifier(String sql) {
|
||||
this.sql = sql;
|
||||
this.keyword = DSL.keyword(sql);
|
||||
}
|
||||
|
||||
public final String toSQL() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public final Keyword toKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public <R extends Record> QuantifiedSelect<R> apply(Select<R> select) {
|
||||
switch (this) {
|
||||
case ANY:
|
||||
return any(select);
|
||||
case ALL:
|
||||
return all(select);
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,12 +48,13 @@ import static org.jooq.impl.DSL.noCondition;
|
||||
import static org.jooq.impl.DSL.notExists;
|
||||
import static org.jooq.impl.DSL.row;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.Quantifier.ALL;
|
||||
import static org.jooq.impl.Quantifier.ANY;
|
||||
import static org.jooq.impl.QOM.Quantifier.ALL;
|
||||
import static org.jooq.impl.QOM.Quantifier.ANY;
|
||||
import static org.jooq.impl.SubqueryCharacteristics.PREDICAND;
|
||||
import static org.jooq.impl.Tools.embeddedFieldsRow;
|
||||
import static org.jooq.impl.Tools.fieldNames;
|
||||
import static org.jooq.impl.Tools.fieldsByName;
|
||||
import static org.jooq.impl.Tools.quantify;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
import static org.jooq.impl.Transformations.transformInConditionSubqueryWithLimitToDerivedTable;
|
||||
import static org.jooq.impl.Transformations.subqueryWithLimit;
|
||||
@ -73,6 +74,7 @@ import org.jooq.Row;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.SelectOrderByStep;
|
||||
import org.jooq.impl.QOM.Quantifier;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
import org.jooq.impl.QOM.UTransient;
|
||||
import org.jooq.impl.Tools.BooleanDataKey;
|
||||
@ -218,6 +220,13 @@ final class RowSubqueryCondition extends AbstractCondition implements UNotYetImp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
accept0(ctx);
|
||||
|
||||
@ -111,6 +111,8 @@ import static org.jooq.impl.DDLStatementType.DROP_SCHEMA;
|
||||
import static org.jooq.impl.DDLStatementType.DROP_SEQUENCE;
|
||||
import static org.jooq.impl.DDLStatementType.DROP_TABLE;
|
||||
import static org.jooq.impl.DDLStatementType.DROP_VIEW;
|
||||
import static org.jooq.impl.DSL.all;
|
||||
import static org.jooq.impl.DSL.any;
|
||||
import static org.jooq.impl.DSL.asterisk;
|
||||
import static org.jooq.impl.DSL.concat;
|
||||
import static org.jooq.impl.DSL.escape;
|
||||
@ -298,6 +300,7 @@ import org.jooq.Param;
|
||||
// ...
|
||||
import org.jooq.QualifiedAsterisk;
|
||||
import org.jooq.QualifiedRecord;
|
||||
import org.jooq.QuantifiedSelect;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.Record;
|
||||
@ -343,6 +346,7 @@ import org.jooq.exception.MappingException;
|
||||
import org.jooq.exception.NoDataFoundException;
|
||||
import org.jooq.exception.TemplatingException;
|
||||
import org.jooq.exception.TooManyRowsException;
|
||||
import org.jooq.impl.QOM.Quantifier;
|
||||
import org.jooq.impl.QOM.UEmpty;
|
||||
import org.jooq.impl.ResultsImpl.ResultOrRowsImpl;
|
||||
import org.jooq.tools.Ints;
|
||||
@ -7416,4 +7420,15 @@ final class Tools {
|
||||
else
|
||||
return Convert.convertArray(array, type);
|
||||
}
|
||||
|
||||
static final <R extends Record> QuantifiedSelect<R> quantify(Quantifier q, Select<R> select) {
|
||||
switch (q) {
|
||||
case ANY:
|
||||
return any(select);
|
||||
case ALL:
|
||||
return all(select);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported quantifier: " + q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user