[jOOQ/jOOQ#7539] More ClickHouse support

This includes:

- Fix UUID_TO_BIN()
- Support asterisks on joins
- Various JSON fixes
This commit is contained in:
Lukas Eder 2024-04-03 18:04:48 +02:00
parent 3b80a2e1d2
commit 96ad496948
11 changed files with 45 additions and 12 deletions

View File

@ -39,6 +39,7 @@ package org.jooq.impl;
// ...
// ...
import static org.jooq.SQLDialect.CLICKHOUSE;
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.DUCKDB;
import static org.jooq.SQLDialect.FIREBIRD;
@ -74,7 +75,7 @@ import org.jooq.impl.QOM.UnmodifiableList;
final class AsteriskImpl extends AbstractQueryPart implements Asterisk {
static final Lazy<AsteriskImpl> INSTANCE = Lazy.of(() -> new AsteriskImpl(new QueryPartList<>()));
static final Set<SQLDialect> SUPPORT_NATIVE_EXCEPT = SQLDialect.supportedBy(H2);
static final Set<SQLDialect> NO_SUPPORT_UNQUALIFIED_COMBINED = SQLDialect.supportedBy(DERBY, FIREBIRD, HSQLDB, MARIADB, MYSQL);
static final Set<SQLDialect> NO_SUPPORT_UNQUALIFIED_COMBINED = SQLDialect.supportedBy(CLICKHOUSE, DERBY, FIREBIRD, HSQLDB, MARIADB, MYSQL);

View File

@ -3969,7 +3969,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
}
@Override
void sqlBind0(BindingSQLContext<U> ctx, Record value) throws SQLException {
final void sqlBind0(BindingSQLContext<U> ctx, Record value) throws SQLException {
Cast.renderCastIf(ctx.render(),
c -> super.sqlBind0(ctx, value),
c -> pgRenderRecordCast(ctx.render()),
@ -4105,7 +4105,11 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
result = DefaultResultBinding.readMultiset(ctx, row, type.getType(),
s -> s != null && (s.startsWith("[") || s.startsWith("{")) ? "[" + s + "]" : null,
s -> s != null && (s.startsWith("<")) ? "<result>" + s + "</result>" : null,
s -> s instanceof Struct x ? asList(x) : null
s -> s instanceof Struct x
? asList(x)
: s instanceof List<?> l
? asList(l)
: null
);
return isEmpty(result) ? null : result.get(0);
@ -4416,7 +4420,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
throw new UnsupportedOperationException("Multiset emulation not yet supported: " + emulation);
}
static <R extends Record> Result<R> readMultisetList(Scope ctx, AbstractRow<R> row, Class<R> recordType, List<?> l) throws SQLException {
static final <R extends Record> Result<R> readMultisetList(Scope ctx, AbstractRow<R> row, Class<R> recordType, List<?> l) throws SQLException {
return new ListHandler<>(ctx.dsl(), row, recordType).read(l);
}

View File

@ -210,7 +210,7 @@ implements
// [#7539] ARRAY types can't mix data types, so use TUPLE for degrees > 1
if (fields.size() > 1)
ctx.visit(function(N_toJSONString, getDataType(), function(N_TUPLE, OTHER, fields.toArray(EMPTY_FIELD))));
ctx.visit(function(N_toJSONString, getDataType(), function(N_TUPLE, OTHER, map(fields, e -> JSONEntryImpl.jsonCast(ctx, e), Field[]::new))));
else
ctx.visit(function(N_toJSONString, getDataType(), array(fields)));

View File

@ -238,6 +238,12 @@ final class JSONEntryImpl<T> extends AbstractQueryPart implements JSONEntry<T>,
break;
case CLICKHOUSE:
if (isType(type, Boolean.class))
return field.cast(BOOLEAN);
break;
case SQLITE:
if (isType(type, Boolean.class))
return function(N_JSON, SQLDataType.JSON, booleanCase(field));

View File

@ -245,9 +245,15 @@ implements
}
case CLICKHOUSE: {
ctx.visit(function(N_toJSONString, getDataType(), function(N_MAP, OTHER,
flatMap(entries, e -> Arrays.<Field<?>>asList(e.key(), e.value())).toArray(EMPTY_FIELD)
)));
if (entries.isEmpty())
ctx.visit(function(N_toJSONString, getDataType(), function(N_MAP, OTHER)));
else if (entries.size() == 1)
ctx.visit(toJSONString(ctx, getDataType(), entries.get(0)));
else
ctx.visit(function(N_jsonMergePatch, getDataType(),
map(entries, e -> toJSONString(ctx, getDataType(), e), Field[]::new)
));
break;
}
@ -273,6 +279,12 @@ implements
}
}
static final Field<?> toJSONString(Context<?> ctx, DataType<?> t, JSONEntry<?> e) {
return function(N_toJSONString, t, function(N_MAP, OTHER,
e.key(), JSONEntryImpl.jsonCast(ctx, e.value())
));
}
static final Field<?> absentOnNullIf(
BooleanSupplier test,
Function1<Field<?>, Field<?>> e,

View File

@ -72,8 +72,14 @@ final class ListHandler<R extends Record> {
for (Object o : list)
result.add(newRecord(true, recordType, row, ctx.configuration()).operate(r -> {
if (o instanceof Struct s) {
Object[] attributes = s.getAttributes();
Object[] attributes =
o instanceof Struct s
? s.getAttributes()
: o instanceof List<?> l
? l.toArray()
: null;
if (attributes != null) {
// [#13400] Recurse for nested MULTISET or ROW types
for (int i = 0; i < attributes.length && i < row.size(); i++) {

View File

@ -180,6 +180,7 @@ final class Names {
static final Name N_JSON_TYPE = systemName("json_type");
static final Name N_JSON_UNQUOTE = systemName("json_unquote");
static final Name N_JSON_VALUE = systemName("json_value");
static final Name N_jsonMergePatch = systemName("jsonMergePatch");
static final Name N_LAG = systemName("lag");
static final Name N_lagInFrame = systemName("lagInFrame");
static final Name N_LAST_VALUE = systemName("last_value");

View File

@ -42,6 +42,7 @@ package org.jooq.impl;
// ...
// ...
// ...
import static org.jooq.SQLDialect.CLICKHOUSE;
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
@ -96,7 +97,7 @@ import org.jooq.Table;
*/
final class SelectIsNull extends AbstractCondition implements QOM.SelectIsNull {
static final Set<SQLDialect> EMULATE_NULL_QUERY = SQLDialect.supportedBy(CUBRID, DERBY, DUCKDB, FIREBIRD, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE, TRINO, YUGABYTEDB);
static final Set<SQLDialect> EMULATE_NULL_QUERY = SQLDialect.supportedBy(CLICKHOUSE, CUBRID, DERBY, DUCKDB, FIREBIRD, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE, TRINO, YUGABYTEDB);
final Select<?> select;

View File

@ -108,6 +108,7 @@ implements
case CLICKHOUSE:
case DERBY:
case DUCKDB:
case H2:

View File

@ -107,6 +107,7 @@ implements
case CLICKHOUSE:
case DUCKDB:
case MARIADB:
case MYSQL:

View File

@ -119,7 +119,7 @@ implements
case CLICKHOUSE:
ctx.visit(function(N_UUIDStringToNum, BINARY(16), uuid));
ctx.visit(function(N_UUIDStringToNum, BINARY(16), DSL.cast(uuid, VARCHAR)));
break;