[jOOQ/jOOQ#14402] Add support for Databricks SQL - WIP
This includes: - Support backslash escaping in string literals - Support inline COMMENT syntax for CREATE TABLE - Support DISTINCT ON - Support GENERATE_SERIES - Support CTAS and SELECT .. INTO - Support CREATE MATERIALIZED VIEW with column renames - Support H2 style MERGE - Avoid exists(selectOne()), as selectOne() aliases its column and Databricks has a bug here - TIMESTAMP datatype (ignore precision) - Support LIMIT (subquery) - Use TIME -> TIMESTAMP emulation - Support INSERT .. DEFAULT VALUES - Support DELETE .. USING - Fix CHOOSE (index can't be out of bounds, unlike in MySQL)
This commit is contained in:
parent
f4acecfce8
commit
2f60f47282
@ -42,6 +42,7 @@ import static org.jooq.SQLDialect.CLICKHOUSE;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.DUCKDB;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
|
||||
@ -146,7 +146,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
* Add a T-SQL style <code>INTO</code> clause to the <code>SELECT</code>
|
||||
* statement to create a new table from a <code>SELECT</code> statement.
|
||||
*/
|
||||
@Support({ CUBRID, DERBY, H2, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTEDB })
|
||||
@Support({ CUBRID, DERBY, DUCKDB, H2, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTEDB })
|
||||
void setInto(Table<?> table);
|
||||
|
||||
|
||||
|
||||
@ -138,7 +138,7 @@ implements
|
||||
case POSTGRES:
|
||||
case YUGABYTEDB:
|
||||
ctx.visit(ifNotNull(array, notExists(
|
||||
selectOne()
|
||||
select(one())
|
||||
.from(unnest(array).as(N_T, predicate.$arg1().getUnqualifiedName()))
|
||||
.where(DSL.not(predicate.$result()))
|
||||
)));
|
||||
|
||||
@ -138,7 +138,7 @@ implements
|
||||
case POSTGRES:
|
||||
case YUGABYTEDB:
|
||||
ctx.visit(ifNotNull(array, exists(
|
||||
selectOne()
|
||||
select(one())
|
||||
.from(unnest(array).as(N_T, predicate.$arg1().getUnqualifiedName()))
|
||||
.where(predicate.$result())
|
||||
)));
|
||||
|
||||
@ -137,7 +137,7 @@ implements
|
||||
case POSTGRES:
|
||||
case YUGABYTEDB:
|
||||
ctx.visit(ifNotNull(array, notExists(
|
||||
selectOne()
|
||||
select(one())
|
||||
.from(unnest(array).as(N_T, predicate.$arg1().getUnqualifiedName()))
|
||||
.where(predicate.$result())
|
||||
)));
|
||||
|
||||
@ -40,6 +40,7 @@ package org.jooq.impl;
|
||||
import static org.jooq.impl.DSL.choose;
|
||||
import static org.jooq.impl.DSL.function;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.when;
|
||||
import static org.jooq.impl.Names.*;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.nullSafeDataType;
|
||||
@ -123,6 +124,12 @@ final class Choose<T> extends AbstractField<T> implements QOM.Choose<T> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case MARIADB:
|
||||
case MYSQL: {
|
||||
ctx.visit(function(N_ELT, getDataType(), Tools.combine(index, values)));
|
||||
|
||||
@ -368,6 +368,8 @@ implements
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
final QOM.UnmodifiableList<? extends Field<?>> $columns() {
|
||||
return QOM.unmodifiable(map(filter(tableElements, e -> e instanceof Field<?>), e -> (Field<?>) e));
|
||||
}
|
||||
@ -461,8 +463,13 @@ implements
|
||||
else {
|
||||
toSQLCreateTable(ctx);
|
||||
toSQLOnCommit(ctx);
|
||||
toSQLTableClauses(ctx);
|
||||
}
|
||||
|
||||
ctx.end(Clause.CREATE_TABLE);
|
||||
}
|
||||
|
||||
private final void toSQLTableClauses(Context<?> ctx) {
|
||||
// [#7539] ClickHouse has a mandatory ENGINE clause. We default to the two most popular engines for now.
|
||||
if (ctx.family() == CLICKHOUSE) {
|
||||
ctx.formatSeparator().visit(K_ENGINE).sql(' ');
|
||||
@ -505,8 +512,6 @@ implements
|
||||
|
||||
|
||||
|
||||
|
||||
ctx.end(Clause.CREATE_TABLE);
|
||||
}
|
||||
|
||||
private void toSQLCreateTable(Context<?> ctx) {
|
||||
@ -669,6 +674,12 @@ implements
|
||||
private final void acceptCreateTableAsSelect(Context<?> ctx) {
|
||||
toSQLCreateTable(ctx);
|
||||
toSQLOnCommit(ctx);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ctx.formatSeparator()
|
||||
.visit(K_AS);
|
||||
|
||||
@ -705,6 +716,11 @@ implements
|
||||
else if (REQUIRES_WITH_DATA.contains(ctx.dialect()))
|
||||
ctx.formatSeparator()
|
||||
.visit(K_WITH_DATA);
|
||||
|
||||
|
||||
|
||||
|
||||
toSQLTableClauses(ctx);
|
||||
}
|
||||
|
||||
|
||||
@ -739,6 +755,7 @@ implements
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private final void toSQLCreateTableName(Context<?> ctx) {
|
||||
|
||||
@ -91,6 +91,7 @@ final class CurrentTime<T> extends AbstractField<T> implements QOM.CurrentTime<T
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case CLICKHOUSE:
|
||||
|
||||
@ -5215,6 +5215,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
|
||||
|
||||
@ -5241,10 +5242,17 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
@Override
|
||||
final void set0(BindingSetStatementContext<U> ctx, Time value) throws SQLException {
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case DUCKDB:
|
||||
case SQLITE:
|
||||
ctx.statement().setString(ctx.index(), value.toString());
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx.statement().setTime(ctx.index(), value);
|
||||
break;
|
||||
@ -5258,9 +5266,14 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
final Time get0(BindingGetResultSetContext<U> ctx) throws SQLException {
|
||||
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ResultSet.getTime() isn't implemented correctly, see: https://github.com/duckdb/duckdb/issues/10682
|
||||
case DUCKDB: {
|
||||
String time = ctx.resultSet().getString(ctx.index());
|
||||
|
||||
@ -5318,7 +5318,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri
|
||||
|
||||
@Override
|
||||
public boolean fetchExists(Table<?> table, Condition condition) {
|
||||
return fetchExists(selectOne().from(table).where(condition));
|
||||
return fetchExists(select(one()).from(table).where(condition));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -40,6 +40,8 @@ package org.jooq.impl;
|
||||
import static org.jooq.impl.DSL.condition;
|
||||
import static org.jooq.impl.DSL.exists;
|
||||
import static org.jooq.impl.DSL.notExists;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.selectDistinct;
|
||||
import static org.jooq.impl.DSL.selectOne;
|
||||
|
||||
@ -121,10 +123,10 @@ implements
|
||||
return selectDistinct(select)
|
||||
.from(outer)
|
||||
.whereNotExists(
|
||||
selectOne()
|
||||
select(one())
|
||||
.from(divisor)
|
||||
.whereNotExists(
|
||||
selectOne()
|
||||
select(one())
|
||||
.from(dividend)
|
||||
.where(selfJoin)
|
||||
.and(condition)))
|
||||
|
||||
@ -43,6 +43,7 @@ import static org.jooq.SQLDialect.CLICKHOUSE;
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
@ -75,13 +76,14 @@ import static org.jooq.impl.Internal.idiv;
|
||||
import static org.jooq.impl.Internal.imul;
|
||||
import static org.jooq.impl.Internal.isub;
|
||||
import static org.jooq.impl.Keywords.K_TABLE;
|
||||
import static org.jooq.impl.Names.N_EXPLODE;
|
||||
import static org.jooq.impl.Names.N_GENERATE_ARRAY;
|
||||
import static org.jooq.impl.Names.N_GENERATE_SERIES;
|
||||
import static org.jooq.impl.Names.N_GENERATOR;
|
||||
import static org.jooq.impl.Names.N_NUMBERS;
|
||||
import static org.jooq.impl.Names.N_SEQUENCE;
|
||||
import static org.jooq.impl.Names.N_SYSTEM_RANGE;
|
||||
import static org.jooq.impl.Names.N_UNNEST;
|
||||
import static org.jooq.impl.SQLDataType.BIGINT;
|
||||
import static org.jooq.impl.SQLDataType.INTEGER;
|
||||
import static org.jooq.impl.SubqueryCharacteristics.DERIVED_TABLE;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
@ -124,6 +126,8 @@ implements
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private final Field<Integer> from;
|
||||
private final Field<Integer> to;
|
||||
private final Field<Integer> step;
|
||||
@ -232,6 +236,12 @@ implements
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -279,6 +289,8 @@ implements
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -77,6 +77,7 @@ import static org.jooq.impl.ConditionProviderImpl.extractCondition;
|
||||
import static org.jooq.impl.DSL.constraint;
|
||||
import static org.jooq.impl.DSL.default_;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.selectFrom;
|
||||
import static org.jooq.impl.DSL.selectOne;
|
||||
@ -864,6 +865,7 @@ implements
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case DERBY:
|
||||
case MARIADB:
|
||||
@ -969,7 +971,7 @@ implements
|
||||
|
||||
rows = (Select<Record>) selectFrom(select.asTable(DSL.table(name("t")), names))
|
||||
.whereNotExists(
|
||||
selectOne()
|
||||
select(one())
|
||||
.from(table())
|
||||
.where(matchByConflictingKeys(ctx, map))
|
||||
);
|
||||
@ -984,7 +986,7 @@ implements
|
||||
Select<Record> row =
|
||||
select(aliasedFields(map.entrySet().stream().filter(e -> fields.contains(e.getKey())).map(Entry::getValue).collect(toList())))
|
||||
.whereNotExists(
|
||||
selectOne()
|
||||
select(one())
|
||||
.from(table())
|
||||
.where(matchByConflictingKeys(ctx, map))
|
||||
);
|
||||
|
||||
@ -109,6 +109,8 @@ import static org.jooq.impl.DSL.exists;
|
||||
import static org.jooq.impl.DSL.lateral;
|
||||
import static org.jooq.impl.DSL.noCondition;
|
||||
import static org.jooq.impl.DSL.notExists;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.selectFrom;
|
||||
import static org.jooq.impl.DSL.selectOne;
|
||||
import static org.jooq.impl.Keywords.K_ANTI_JOIN;
|
||||
@ -315,11 +317,11 @@ abstract class JoinTable<J extends JoinTable<J>> extends AbstractJoinTable<J> {
|
||||
|
||||
switch (translatedType) {
|
||||
case LEFT_SEMI_JOIN:
|
||||
semiAntiJoinPredicates.add(exists(selectOne().from(rhs).where(condition())));
|
||||
semiAntiJoinPredicates.add(exists(select(one()).from(rhs).where(condition())));
|
||||
break;
|
||||
|
||||
case LEFT_ANTI_JOIN:
|
||||
semiAntiJoinPredicates.add(notExists(selectOne().from(rhs).where(condition())));
|
||||
semiAntiJoinPredicates.add(notExists(select(one()).from(rhs).where(condition())));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -123,6 +123,7 @@ final class Names {
|
||||
static final Name N_ELT = systemName("elt");
|
||||
static final Name N_ENCODE = systemName("encode");
|
||||
static final Name N_EVERY = systemName("every");
|
||||
static final Name N_EXPLODE = systemName("explode");
|
||||
static final Name N_EXTRACT = systemName("extract");
|
||||
static final Name N_FIRST_VALUE = systemName("first_value");
|
||||
static final Name N_FLASHBACK = systemName("flashback");
|
||||
@ -260,6 +261,7 @@ final class Names {
|
||||
static final Name N_SECONDS_BETWEEN = systemName("seconds_between");
|
||||
static final Name N_SEQ4 = systemName("seq4");
|
||||
static final Name N_SEQ8 = systemName("seq8");
|
||||
static final Name N_SEQUENCE = systemName("sequence");
|
||||
static final Name N_SHL = systemName("shl");
|
||||
static final Name N_SHR = systemName("shr");
|
||||
static final Name N_SQL_TSI_DAY = systemName("sql_tsi_day");
|
||||
|
||||
@ -75,6 +75,7 @@ import static org.jooq.SQLDialect.CUBRID;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.DERBY;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
@ -1972,6 +1973,15 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -2030,7 +2040,6 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
|
||||
|
||||
|
||||
case CUBRID:
|
||||
case DUCKDB:
|
||||
case YUGABYTEDB: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user