[jOOQ/jOOQ#7539] Support for SQLDialect.CLICKHOUSE - WIP
This commit is contained in:
parent
72f3c5339b
commit
bd062f8107
@ -284,7 +284,12 @@ implements
|
||||
|
||||
final void acceptArguments3(Context<?> ctx, QueryPartCollectionView<Field<?>> args, Function<? super Field<?>, ? extends Field<?>> fun) {
|
||||
if (args.isEmpty() && this instanceof Count)
|
||||
args = QueryPartListView.wrap(ASTERISK.get());
|
||||
|
||||
// [#7539] Work around https://github.com/ClickHouse/ClickHouse/issues/61004
|
||||
if (ctx.family() == CLICKHOUSE && filter.hasWhere())
|
||||
args = QueryPartListView.wrap();
|
||||
else
|
||||
args = QueryPartListView.wrap(ASTERISK.get());
|
||||
|
||||
if (!filter.hasWhere() || supportsFilter(ctx))
|
||||
ctx.visit(wrap(args).map(fun));
|
||||
|
||||
@ -100,6 +100,9 @@ implements
|
||||
case TRINO:
|
||||
return false;
|
||||
|
||||
case CLICKHOUSE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@ -120,6 +123,10 @@ implements
|
||||
ctx.visit(arrayConcat(arg1, array(arg2)));
|
||||
break;
|
||||
|
||||
case CLICKHOUSE:
|
||||
ctx.visit(function(N_arrayPushBack, getDataType(), arg1, arg2));
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx.visit(function(N_ARRAY_APPEND, getDataType(), arg1, arg2));
|
||||
break;
|
||||
|
||||
@ -92,6 +92,17 @@ implements
|
||||
// XXX: QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
final boolean parenthesised(Context<?> ctx) {
|
||||
switch (ctx.family()) {
|
||||
case CLICKHOUSE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
switch (ctx.family()) {
|
||||
@ -101,6 +112,10 @@ implements
|
||||
|
||||
|
||||
|
||||
case CLICKHOUSE:
|
||||
ctx.visit(function(N_arrayConcat, getDataType(), arg1, arg2));
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx.sql('(').visit(arg1).sql(" || ").visit(arg2).sql(')');
|
||||
break;
|
||||
|
||||
@ -100,6 +100,9 @@ implements
|
||||
case TRINO:
|
||||
return false;
|
||||
|
||||
case CLICKHOUSE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@ -120,6 +123,10 @@ implements
|
||||
ctx.visit(arrayConcat(array(arg1), arg2));
|
||||
break;
|
||||
|
||||
case CLICKHOUSE:
|
||||
ctx.visit(function(N_arrayPushFront, getDataType(), arg2, arg1));
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx.visit(function(N_ARRAY_PREPEND, getDataType(), arg1, arg2));
|
||||
break;
|
||||
|
||||
@ -103,6 +103,10 @@ implements
|
||||
|
||||
|
||||
|
||||
case CLICKHOUSE:
|
||||
ctx.visit(function(N_LENGTH, getDataType(), array));
|
||||
break;
|
||||
|
||||
case DUCKDB:
|
||||
ctx.visit(function(N_ARRAY_LENGTH, getDataType(), array));
|
||||
break;
|
||||
|
||||
@ -96,6 +96,7 @@ final class Choose<T> extends AbstractField<T> implements QOM.Choose<T> {
|
||||
|
||||
|
||||
|
||||
case CLICKHOUSE:
|
||||
case CUBRID:
|
||||
case DERBY:
|
||||
case DUCKDB:
|
||||
|
||||
@ -113,6 +113,7 @@ implements
|
||||
|
||||
|
||||
|
||||
case CLICKHOUSE:
|
||||
case CUBRID:
|
||||
case DERBY:
|
||||
case DUCKDB:
|
||||
@ -162,6 +163,7 @@ implements
|
||||
|
||||
|
||||
|
||||
case CLICKHOUSE:
|
||||
case CUBRID:
|
||||
case DERBY:
|
||||
case DUCKDB:
|
||||
|
||||
@ -22108,7 +22108,7 @@ public class DSL {
|
||||
* Calculate the cardinality of an array field.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ DUCKDB, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, DUCKDB, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static Field<Integer> cardinality(Field<? extends Object[]> array) {
|
||||
return new Cardinality(array);
|
||||
}
|
||||
@ -22121,7 +22121,7 @@ public class DSL {
|
||||
* @param index is wrapped as {@link DSL#val(Object)}.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ DUCKDB, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, DUCKDB, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T> arrayGet(Field<T[]> array, int index) {
|
||||
return new ArrayGet<>(array, Tools.field(index));
|
||||
}
|
||||
@ -22132,7 +22132,7 @@ public class DSL {
|
||||
* Get an array element at a given index (1 based).
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ DUCKDB, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, DUCKDB, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T> arrayGet(Field<T[]> array, Field<Integer> index) {
|
||||
return new ArrayGet<>(array, index);
|
||||
}
|
||||
@ -22143,7 +22143,7 @@ public class DSL {
|
||||
* Concatenate two arrays.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayConcat(T[] arg1, T[] arg2) {
|
||||
return new ArrayConcat<>(Tools.field(arg1), Tools.field(arg2));
|
||||
}
|
||||
@ -22154,7 +22154,7 @@ public class DSL {
|
||||
* Concatenate two arrays.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayConcat(T[] arg1, Field<T[]> arg2) {
|
||||
return new ArrayConcat<>(Tools.field(arg1), arg2);
|
||||
}
|
||||
@ -22165,7 +22165,7 @@ public class DSL {
|
||||
* Concatenate two arrays.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayConcat(Field<T[]> arg1, T[] arg2) {
|
||||
return new ArrayConcat<>(arg1, Tools.field(arg2, arg1));
|
||||
}
|
||||
@ -22176,7 +22176,7 @@ public class DSL {
|
||||
* Concatenate two arrays.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayConcat(Field<T[]> arg1, Field<T[]> arg2) {
|
||||
return new ArrayConcat<>(arg1, arg2);
|
||||
}
|
||||
@ -22189,7 +22189,7 @@ public class DSL {
|
||||
* @param arg2 is wrapped as {@link DSL#val(Object)}.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayAppend(T[] arg1, T arg2) {
|
||||
return new ArrayAppend<>(Tools.field(arg1), Tools.field(arg2));
|
||||
}
|
||||
@ -22200,7 +22200,7 @@ public class DSL {
|
||||
* Append an element to an array.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayAppend(T[] arg1, Field<T> arg2) {
|
||||
return new ArrayAppend<>(Tools.field(arg1), arg2);
|
||||
}
|
||||
@ -22213,7 +22213,7 @@ public class DSL {
|
||||
* @param arg2 is wrapped as {@link DSL#val(Object)}.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayAppend(Field<T[]> arg1, T arg2) {
|
||||
return new ArrayAppend<>(arg1, Tools.field(arg2));
|
||||
}
|
||||
@ -22224,7 +22224,7 @@ public class DSL {
|
||||
* Append an element to an array.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayAppend(Field<T[]> arg1, Field<T> arg2) {
|
||||
return new ArrayAppend<>(arg1, arg2);
|
||||
}
|
||||
@ -22237,7 +22237,7 @@ public class DSL {
|
||||
* @param arg1 is wrapped as {@link DSL#val(Object)}.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayPrepend(T arg1, T[] arg2) {
|
||||
return new ArrayPrepend<>(Tools.field(arg1), Tools.field(arg2));
|
||||
}
|
||||
@ -22250,7 +22250,7 @@ public class DSL {
|
||||
* @param arg1 is wrapped as {@link DSL#val(Object)}.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayPrepend(T arg1, Field<T[]> arg2) {
|
||||
return new ArrayPrepend<>(Tools.field(arg1), arg2);
|
||||
}
|
||||
@ -22261,7 +22261,7 @@ public class DSL {
|
||||
* Prepend an element to an array.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayPrepend(Field<T> arg1, T[] arg2) {
|
||||
return new ArrayPrepend<>(arg1, Tools.field(arg2));
|
||||
}
|
||||
@ -22272,7 +22272,7 @@ public class DSL {
|
||||
* Prepend an element to an array.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
@Support({ CLICKHOUSE, H2, HSQLDB, POSTGRES, TRINO, YUGABYTEDB })
|
||||
public static <T> Field<T[]> arrayPrepend(Field<T> arg1, Field<T[]> arg2) {
|
||||
return new ArrayPrepend<>(arg1, arg2);
|
||||
}
|
||||
|
||||
@ -48,6 +48,7 @@ import static org.jooq.impl.Identifiers.QUOTES;
|
||||
import static org.jooq.impl.Identifiers.QUOTE_END_DELIMITER;
|
||||
import static org.jooq.impl.Identifiers.QUOTE_END_DELIMITER_ESCAPED;
|
||||
import static org.jooq.impl.Identifiers.QUOTE_START_DELIMITER;
|
||||
import static org.jooq.impl.JoinTable.NO_SUPPORT_NESTED_JOIN;
|
||||
import static org.jooq.impl.Tools.EMPTY_PARAM;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_COUNT_BIND_VALUES;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_FORCE_STATIC_STATEMENT;
|
||||
@ -306,18 +307,24 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
// TODO: subqueryLevel() is lower than scopeLevel if we use implicit join in procedural logic
|
||||
else if (e1.joinNode != null && e1.joinNode.hasJoinPaths()) {
|
||||
DefaultRenderContext ctx = new DefaultRenderContext(this, false);
|
||||
ctx.data(DATA_RENDER_IMPLICIT_JOIN, true);
|
||||
replacedSQL = ctx
|
||||
.declareTables(true)
|
||||
.sql('(')
|
||||
.formatIndentStart(e1.indent)
|
||||
.formatIndentStart()
|
||||
.formatNewLine()
|
||||
.visit(e1.joinNode.joinTree())
|
||||
.formatNewLine()
|
||||
.sql(')')
|
||||
.render();
|
||||
boolean noNesting = !NO_SUPPORT_NESTED_JOIN.contains(ctx.dialect());
|
||||
|
||||
ctx.data(DATA_RENDER_IMPLICIT_JOIN, true);
|
||||
ctx.declareTables(true);
|
||||
|
||||
if (noNesting)
|
||||
ctx.sql('(')
|
||||
.formatIndentStart(e1.indent)
|
||||
.formatIndentStart()
|
||||
.formatNewLine();
|
||||
|
||||
ctx.visit(e1.joinNode.joinTree());
|
||||
|
||||
if (noNesting)
|
||||
ctx.formatNewLine()
|
||||
.sql(')');
|
||||
|
||||
replacedSQL = ctx.render();
|
||||
insertedBindValues = ctx.bindValues();
|
||||
}
|
||||
else {
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.SQLDialect.CLICKHOUSE;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.DERBY;
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
@ -66,7 +67,7 @@ import org.jooq.TableOptions;
|
||||
*/
|
||||
class DerivedTable<R extends Record> extends AbstractTable<R> implements QOM.DerivedTable<R> {
|
||||
|
||||
static final Set<SQLDialect> NO_SUPPORT_CORRELATED_DERIVED_TABLE = SQLDialect.supportedUntil(DERBY, H2, MARIADB);
|
||||
static final Set<SQLDialect> NO_SUPPORT_CORRELATED_DERIVED_TABLE = SQLDialect.supportedUntil(CLICKHOUSE, DERBY, H2, MARIADB);
|
||||
private final Lazy<Select<R>> query;
|
||||
|
||||
DerivedTable(Select<R> query) {
|
||||
|
||||
@ -95,7 +95,8 @@ implements
|
||||
|
||||
|
||||
|
||||
static final Set<SQLDialect> EMULATE_DISTINCT_PREDICATE = SQLDialect.supportedUntil(CLICKHOUSE, CUBRID, DERBY);
|
||||
static final Set<SQLDialect> EMULATE_DISTINCT_PREDICATE = SQLDialect.supportedUntil(CUBRID, DERBY);
|
||||
static final Set<SQLDialect> EMULATE_WITH_ARRAYS = SQLDialect.supportedBy(CLICKHOUSE);
|
||||
static final Set<SQLDialect> SUPPORT_DISTINCT_WITH_ARROW = SQLDialect.supportedBy(MARIADB, MYSQL);
|
||||
|
||||
|
||||
@ -123,6 +124,10 @@ implements
|
||||
else if (EMULATE_DISTINCT_PREDICATE.contains(ctx.dialect()))
|
||||
ctx.visit(notExists(select(arg1.as("x")).intersect(select(arg2.as("x")))));
|
||||
|
||||
// [#7539] While INTERSECT is supported, correlating subqueries hardly is in ClickHouse
|
||||
else if (EMULATE_WITH_ARRAYS.contains(ctx.dialect()))
|
||||
ctx.visit(function(N_arrayUniq, INTEGER, array(arg1, arg2)).eq(inline(2)));
|
||||
|
||||
// MySQL knows the <=> operator
|
||||
else if (SUPPORT_DISTINCT_WITH_ARROW.contains(ctx.dialect()))
|
||||
ctx.visit(condition("{not}({0} <=> {1})", arg1, arg2));
|
||||
|
||||
@ -116,6 +116,10 @@ implements
|
||||
else if (IsDistinctFrom.EMULATE_DISTINCT_PREDICATE.contains(ctx.dialect()))
|
||||
ctx.visit(exists(select(arg1.as("x")).intersect(select(arg2.as("x")))));
|
||||
|
||||
// [#7539] While INTERSECT is supported, correlating subqueries hardly is in ClickHouse
|
||||
else if (IsDistinctFrom.EMULATE_WITH_ARRAYS.contains(ctx.dialect()))
|
||||
ctx.visit(function(N_arrayUniq, INTEGER, array(arg1, arg2)).eq(inline(1)));
|
||||
|
||||
// MySQL knows the <=> operator
|
||||
else if (IsDistinctFrom.SUPPORT_DISTINCT_WITH_ARROW.contains(ctx.dialect()))
|
||||
ctx.visit(condition("{0} <=> {1}", arg1, arg2));
|
||||
|
||||
@ -178,6 +178,7 @@ abstract class JoinTable<J extends JoinTable<J>> extends AbstractJoinTable<J> {
|
||||
static final Set<SQLDialect> EMULATE_JOIN_USING = SQLDialect.supportedBy(CUBRID, IGNITE);
|
||||
static final Set<SQLDialect> EMULATE_APPLY = SQLDialect.supportedBy(FIREBIRD, POSTGRES, TRINO, YUGABYTEDB);
|
||||
static final Set<SQLDialect> EMUlATE_SEMI_ANTI_JOIN = SQLDialect.supportedBy(CUBRID, DERBY, DUCKDB, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, TRINO, YUGABYTEDB);
|
||||
static final Set<SQLDialect> NO_SUPPORT_NESTED_JOIN = SQLDialect.supportedBy(CLICKHOUSE);
|
||||
|
||||
final Table<?> lhs;
|
||||
final Table<?> rhs;
|
||||
|
||||
@ -73,6 +73,7 @@ final class Names {
|
||||
static final Name N_ARRAY_AGG = systemName("array_agg");
|
||||
static final Name N_ARRAY_CONSTRUCT = systemName("array_construct");
|
||||
static final Name N_ARRAY_CONSTRUCT_COMPACT = systemName("array_construct_compact");
|
||||
static final Name N_arrayUniq = systemName("arrayUniq");
|
||||
static final Name N_BITCOUNT = systemName("bitcount");
|
||||
static final Name N_bitCount = systemName("bitCount");
|
||||
static final Name N_BITWISE_AND_AGG = systemName("bitwise_and_agg");
|
||||
@ -644,6 +645,9 @@ final class Names {
|
||||
static final Name N_XMLSERIALIZE = systemName("xmlserialize");
|
||||
static final Name N_XMLSERIALIZE_CONTENT = systemName("xmlserialize_content");
|
||||
static final Name N_XOR = systemName("xor");
|
||||
static final Name N_arrayConcat = systemName("arrayConcat");
|
||||
static final Name N_arrayPushBack = systemName("arrayPushBack");
|
||||
static final Name N_arrayPushFront = systemName("arrayPushFront");
|
||||
static final Name N_bitAnd = systemName("bitAnd");
|
||||
static final Name N_bitNot = systemName("bitNot");
|
||||
static final Name N_bitOr = systemName("bitOr");
|
||||
|
||||
@ -8738,16 +8738,18 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
|
||||
return parseFieldAddDatePart(MINUTE);
|
||||
else if (parseFunctionNameIf("ADD_SECONDS"))
|
||||
return parseFieldAddDatePart(SECOND);
|
||||
else if (parseFunctionNameIf("ARRAY_APPEND"))
|
||||
else if (parseFunctionNameIf("ARRAY_APPEND", "arrayPushBack"))
|
||||
return parseFunctionArgs2((f1, f2) -> arrayAppend((Field<Void[]>) f1, (Field<Void>) f2));
|
||||
else if (parseFunctionNameIf("ARRAY_CAT", "ARRAY_CONCAT"))
|
||||
else if (parseFunctionNameIf("ARRAY_CAT", "ARRAY_CONCAT", "arrayConcat"))
|
||||
return parseFunctionArgs2((f1, f2) -> arrayConcat(f1, f2));
|
||||
else if (parseFunctionNameIf("ARRAY_GET"))
|
||||
else if (parseFunctionNameIf("ARRAY_GET", "arrayElement"))
|
||||
return parseFunctionArgs2((f1, f2) -> arrayGet(f1, f2));
|
||||
else if (parseFunctionNameIf("ARRAY_OVERLAP", "ARRAYS_OVERLAP"))
|
||||
return parseFunctionArgs2((f1, f2) -> arrayOverlap((Field<Void[]>) f1, (Field<Void[]>) f2));
|
||||
else if (parseFunctionNameIf("ARRAY_PREPEND"))
|
||||
return parseFunctionArgs2((f1, f2) -> arrayPrepend((Field<Void>) f1, (Field<Void[]>) f2));
|
||||
else if (parseFunctionNameIf("arrayPushFront"))
|
||||
return parseFunctionArgs2((f1, f2) -> arrayPrepend((Field<Void>) f2, (Field<Void[]>) f1));
|
||||
else if (parseFunctionNameIf("ARRAY_REMOVE"))
|
||||
return parseFunctionArgs2((f1, f2) -> arrayRemove((Field<Void[]>) f1, (Field<Void>) f2));
|
||||
else if (parseFunctionNameIf("ARRAY_REPLACE"))
|
||||
|
||||
@ -1439,16 +1439,16 @@ public final class QOM {
|
||||
|
||||
public /*sealed*/ interface ScalarSubquery<T>
|
||||
extends
|
||||
Field<T>,
|
||||
UOperator1<Select<? extends Record1<T>>, ScalarSubquery<T>>
|
||||
org.jooq.Field<T>,
|
||||
UOperator1<org.jooq.Select<? extends org.jooq.Record1<T>>, ScalarSubquery<T>>
|
||||
/*permits
|
||||
ScalarSubquery*/
|
||||
{}
|
||||
|
||||
public /*sealed*/ interface RowSubquery
|
||||
extends
|
||||
Row,
|
||||
UOperator1<Select<?>, RowSubquery>
|
||||
org.jooq.Row,
|
||||
UOperator1<org.jooq.Select<?>, RowSubquery>
|
||||
{}
|
||||
|
||||
public /*sealed*/ interface Neg<T>
|
||||
|
||||
@ -65,11 +65,17 @@ import static org.jooq.SQLDialect.SQLITE;
|
||||
import static org.jooq.SQLDialect.TRINO;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.YUGABYTEDB;
|
||||
import static org.jooq.impl.DSL.array;
|
||||
import static org.jooq.impl.DSL.exists;
|
||||
import static org.jooq.impl.DSL.function;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.notExists;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.Keywords.K_IS;
|
||||
import static org.jooq.impl.Keywords.K_NOT;
|
||||
import static org.jooq.impl.Names.NQ_SELECT;
|
||||
import static org.jooq.impl.Names.N_arrayUniq;
|
||||
import static org.jooq.impl.SQLDataType.INTEGER;
|
||||
import static org.jooq.impl.SubqueryCharacteristics.PREDICAND;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
|
||||
@ -87,18 +93,19 @@ import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class RowIsDistinctFrom extends AbstractCondition implements UNotYetImplemented {
|
||||
private static final Set<SQLDialect> EMULATE_DISTINCT = SQLDialect.supportedBy(CLICKHOUSE, CUBRID, DERBY);
|
||||
static final Set<SQLDialect> EMULATE_DISTINCT = SQLDialect.supportedBy(CUBRID, DERBY);
|
||||
static final Set<SQLDialect> EMULATE_WITH_ARRAYS = SQLDialect.supportedBy(CLICKHOUSE);
|
||||
|
||||
// An emulation may be required only for the version where a subquery is used
|
||||
// E.g. in HSQLDB: https://sourceforge.net/p/hsqldb/bugs/1579/
|
||||
// Or in PostgreSQL: https://twitter.com/pg_xocolatl/status/1260344255035379714
|
||||
private static final Set<SQLDialect> EMULATE_DISTINCT_SELECT = SQLDialect.supportedBy(HSQLDB, POSTGRES, TRINO, YUGABYTEDB);
|
||||
private static final Set<SQLDialect> SUPPORT_DISTINCT_WITH_ARROW = SQLDialect.supportedBy(MARIADB, MYSQL);
|
||||
static final Set<SQLDialect> EMULATE_DISTINCT_SELECT = SQLDialect.supportedBy(HSQLDB, POSTGRES, TRINO, YUGABYTEDB);
|
||||
static final Set<SQLDialect> SUPPORT_DISTINCT_WITH_ARROW = SQLDialect.supportedBy(MARIADB, MYSQL);
|
||||
|
||||
private final Row lhs;
|
||||
private final Row rhsRow;
|
||||
private final Select<?> rhsSelect;
|
||||
private final boolean not;
|
||||
private final Row lhs;
|
||||
private final Row rhsRow;
|
||||
private final Select<?> rhsSelect;
|
||||
private final boolean not;
|
||||
|
||||
RowIsDistinctFrom(Row lhs, Row rhs, boolean not) {
|
||||
this.lhs = lhs;
|
||||
@ -147,6 +154,17 @@ final class RowIsDistinctFrom extends AbstractCondition implements UNotYetImplem
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
else if (EMULATE_WITH_ARRAYS.contains(ctx.dialect())) {
|
||||
ctx.visit(
|
||||
function(N_arrayUniq, INTEGER,
|
||||
array(
|
||||
lhs,
|
||||
rhsRow != null ? rhsRow : CustomField.of(NQ_SELECT, SQLDataType.RECORD, c -> visitSubquery(c, rhsSelect, PREDICAND))
|
||||
)
|
||||
).eq(inline(not ? 1 : 2))
|
||||
);
|
||||
}
|
||||
|
||||
// SQLite knows the IS / IS NOT predicate
|
||||
else if (SQLITE == ctx.family()) {
|
||||
ctx.visit(lhs).sql(' ').visit(K_IS).sql(' ');
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.SQLDialect.CLICKHOUSE;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
// ...
|
||||
@ -63,6 +64,7 @@ import org.jooq.Select;
|
||||
@SuppressWarnings("unchecked")
|
||||
final class ScalarSubquery<T> extends AbstractField<T> implements QOM.ScalarSubquery<T> {
|
||||
|
||||
static final Set<SQLDialect> NO_SUPPORT_CORRELATED_SUBQUERY = SQLDialect.supportedBy(CLICKHOUSE);
|
||||
static final Set<SQLDialect> NO_SUPPORT_WITH_IN_SCALAR_SUBQUERY = SQLDialect.supportedBy(HSQLDB);
|
||||
final Select<?> query;
|
||||
final boolean predicandSubquery;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user