[jOOQ/jOOQ#13326] Emulate UPDATE .. FROM with MERGE, where available

This commit is contained in:
Lukas Eder 2022-03-30 17:44:19 +02:00
parent d1b3f33072
commit befb89b9d1
3 changed files with 82 additions and 11 deletions

View File

@ -41,6 +41,15 @@ package org.jooq;
// ...
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;
// ...
import static org.jooq.SQLDialect.FIREBIRD;
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
// ...
// ...
// ...
import static org.jooq.SQLDialect.POSTGRES;
@ -48,6 +57,8 @@ import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
// ...
import java.util.Collection;
@ -94,21 +105,21 @@ public interface UpdateFromStep<R extends Record> extends UpdateWhereStep<R> {
* Add a <code>FROM</code> clause to the query.
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES, SQLITE })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
UpdateWhereStep<R> from(TableLike<?> table);
/**
* Add a <code>FROM</code> clause to the query.
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES, SQLITE })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
UpdateWhereStep<R> from(TableLike<?>... table);
/**
* Add a <code>FROM</code> clause to the query.
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES, SQLITE })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
UpdateWhereStep<R> from(Collection<? extends TableLike<?>> tables);
/**
@ -123,7 +134,7 @@ public interface UpdateFromStep<R extends Record> extends UpdateWhereStep<R> {
* @see SQL
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES, SQLITE })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
@PlainSQL
UpdateWhereStep<R> from(SQL sql);
@ -139,7 +150,7 @@ public interface UpdateFromStep<R extends Record> extends UpdateWhereStep<R> {
* @see SQL
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES, SQLITE })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
@PlainSQL
UpdateWhereStep<R> from(String sql);
@ -156,7 +167,7 @@ public interface UpdateFromStep<R extends Record> extends UpdateWhereStep<R> {
* @see SQL
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES, SQLITE })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
@PlainSQL
UpdateWhereStep<R> from(String sql, Object... bindings);
@ -173,7 +184,7 @@ public interface UpdateFromStep<R extends Record> extends UpdateWhereStep<R> {
* @see SQL
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES, SQLITE })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
@PlainSQL
UpdateWhereStep<R> from(String sql, QueryPart... parts);
@ -183,6 +194,6 @@ public interface UpdateFromStep<R extends Record> extends UpdateWhereStep<R> {
* @see DSL#table(Name)
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES, SQLITE })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
UpdateWhereStep<R> from(Name name);
}

View File

@ -42,19 +42,26 @@ package org.jooq;
// ...
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;
// ...
import static org.jooq.SQLDialect.FIREBIRD;
// ...
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
// ...
// ...
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
// ...
import static org.jooq.SQLDialect.YUGABYTEDB;
import java.util.Collection;
@ -362,7 +369,7 @@ public interface UpdateQuery<R extends Record> extends StoreQuery<R>, ConditionP
*
* @param from The added tables
*/
@Support({ POSTGRES, SQLITE, YUGABYTEDB })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
void addFrom(TableLike<?> from);
/**
@ -370,7 +377,7 @@ public interface UpdateQuery<R extends Record> extends StoreQuery<R>, ConditionP
*
* @param from The added tables
*/
@Support({ POSTGRES, SQLITE, YUGABYTEDB })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
void addFrom(TableLike<?>... from);
/**
@ -378,7 +385,7 @@ public interface UpdateQuery<R extends Record> extends StoreQuery<R>, ConditionP
*
* @param from The added tables
*/
@Support({ POSTGRES, SQLITE, YUGABYTEDB })
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
void addFrom(Collection<? extends TableLike<?>> from);
// ------------------------------------------------------------------------

View File

@ -52,9 +52,11 @@ import static org.jooq.Clause.UPDATE_WHERE;
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
// ...
import static org.jooq.SQLDialect.DERBY;
// ...
import static org.jooq.SQLDialect.FIREBIRD;
// ...
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
@ -74,6 +76,7 @@ import static org.jooq.SQLDialect.SQLITE;
// ...
import static org.jooq.SQLDialect.YUGABYTEDB;
import static org.jooq.conf.SettingsTools.getExecuteUpdateWithoutWhere;
import static org.jooq.impl.DSL.mergeInto;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.select;
@ -89,8 +92,10 @@ import static org.jooq.impl.Tools.findAny;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import org.jooq.Clause;
import org.jooq.Condition;
@ -102,6 +107,7 @@ import org.jooq.FieldOrRowOrSelect;
import org.jooq.Operator;
import org.jooq.OrderField;
// ...
import org.jooq.QueryPart;
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.Record10;
@ -153,6 +159,7 @@ import org.jooq.SQLDialect;
import org.jooq.Scope;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.TableLike;
import org.jooq.UpdateQuery;
import org.jooq.impl.FieldMapForUpdate.SetClause;
@ -177,6 +184,8 @@ implements
private static final Set<SQLDialect> EMULATE_FROM_WITH_MERGE = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, HSQLDB);
// LIMIT is not supported at all
private static final Set<SQLDialect> NO_SUPPORT_LIMIT = SQLDialect.supportedUntil(CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE, YUGABYTEDB);
@ -530,6 +539,11 @@ implements
@Override
final void accept0(Context<?> ctx) {
if (!from.isEmpty() && EMULATE_FROM_WITH_MERGE.contains(ctx.dialect())) {
acceptFromAsMerge(ctx);
return;
}
@ -544,6 +558,45 @@ implements
accept1(ctx);
}
private final void acceptFromAsMerge(Context<?> ctx) {
// TODO: What about RETURNING?
// TODO: What if there are multiple FROM tables?
// TODO: What if there are SET ROW = ROW assignment(s)?
// TODO: What if there are SET ROW = (SELECT ..) assignment(s)?
Table<?> s;
boolean patchSource = true;
Condition c = condition;
FieldMapForUpdate um = updateMap;
if (orderBy.isEmpty() && limit == null) {
if (from.size() == 1 && from.get(0) instanceof TableImpl && !(patchSource = false))
s = from.get(0);
else
s = select().from(from).asTable("s");
}
else
s = select().from(from).orderBy(orderBy).limit(limit).asTable("s");
if (patchSource && ctx.configuration().requireCommercial(() -> "The UPDATE .. FROM to MERGE transformation requires commercial only logic. Please upgrade to the jOOQ Professional Edition or jOOQ Enterprise Edition")) {
}
ctx.visit(mergeInto(table).using(s).on(c).whenMatchedThenUpdate().set(um));
}
private final UpdateQueryImpl<R> copy(Consumer<? super UpdateQueryImpl<R>> consumer) {
UpdateQueryImpl<R> u = new UpdateQueryImpl<>(configuration(), with, table);