From 661195af530884cf8ed73e3f43ada6326aaa5dc3 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Fri, 2 Jul 2021 14:19:18 +0200 Subject: [PATCH] [jOOQ/jOOQ#11543] Emulate FOR UPDATE .. WAIT n using SET SESSION innodb_lock_wait_timeout in MySQL dialects --- .../org/jooq/SelectForUpdateWaitStep.java | 6 +++-- jOOQ/src/main/java/org/jooq/SelectQuery.java | 2 +- jOOQ/src/main/java/org/jooq/impl/ForLock.java | 22 +++++++++++++++++-- jOOQ/src/main/java/org/jooq/impl/Tools.java | 8 ++++++- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/SelectForUpdateWaitStep.java b/jOOQ/src/main/java/org/jooq/SelectForUpdateWaitStep.java index aa127c0c12..ebd26feb2a 100644 --- a/jOOQ/src/main/java/org/jooq/SelectForUpdateWaitStep.java +++ b/jOOQ/src/main/java/org/jooq/SelectForUpdateWaitStep.java @@ -39,11 +39,13 @@ package org.jooq; import org.jetbrains.annotations.*; - +// ... // ... import static org.jooq.SQLDialect.MARIADB; +// ... import static org.jooq.SQLDialect.MYSQL; // ... +// ... import static org.jooq.SQLDialect.POSTGRES; // ... // ... @@ -119,7 +121,7 @@ public interface SelectForUpdateWaitStep extends SelectForStep * @see SelectQuery#setForLockModeWait(int) */ @NotNull @CheckReturnValue - @Support({ MARIADB, POSTGRES }) + @Support({ MARIADB, MYSQL, POSTGRES }) SelectForStep wait(int seconds); /** diff --git a/jOOQ/src/main/java/org/jooq/SelectQuery.java b/jOOQ/src/main/java/org/jooq/SelectQuery.java index d1156534d0..d4e9901c0e 100644 --- a/jOOQ/src/main/java/org/jooq/SelectQuery.java +++ b/jOOQ/src/main/java/org/jooq/SelectQuery.java @@ -1170,7 +1170,7 @@ public interface SelectQuery extends Select, ConditionProvi * * @param seconds The number of seconds to wait for a lock */ - @Support({ MARIADB, POSTGRES }) + @Support({ MARIADB, MYSQL, POSTGRES }) void setForLockModeWait(int seconds); /** diff --git a/jOOQ/src/main/java/org/jooq/impl/ForLock.java b/jOOQ/src/main/java/org/jooq/impl/ForLock.java index 232f53c1c9..4d4e565d25 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ForLock.java +++ b/jOOQ/src/main/java/org/jooq/impl/ForLock.java @@ -48,7 +48,9 @@ import static org.jooq.SQLDialect.H2; import static org.jooq.SQLDialect.HSQLDB; import static org.jooq.SQLDialect.MARIADB; // ... +// ... import static org.jooq.SQLDialect.MYSQL; +// ... import static org.jooq.SQLDialect.POSTGRES; // ... // ... @@ -65,7 +67,10 @@ import static org.jooq.impl.Keywords.K_WITH; import static org.jooq.impl.Keywords.K_WITH_LOCK; import static org.jooq.impl.Names.N_LOCK_TIMEOUT; import static org.jooq.impl.QueryPartCollectionView.wrap; +import static org.jooq.impl.Tools.appendSQL; import static org.jooq.impl.Tools.prependSQL; +import static org.jooq.impl.Tools.BooleanDataKey.DATA_GROUP_CONCAT_MAX_LEN_SET; +import static org.jooq.impl.Tools.BooleanDataKey.DATA_LOCK_WAIT_TIMEOUT_SET; import java.util.Set; @@ -77,6 +82,7 @@ import org.jooq.QueryPart; import org.jooq.SQLDialect; import org.jooq.Select; import org.jooq.Table; +import org.jooq.impl.Tools.BooleanDataKey; import org.jooq.impl.Tools.DataExtendedKey; /** @@ -92,7 +98,8 @@ final class ForLock extends AbstractQueryPart { - private static final Set EMULATE_FOR_UPDATE_WAIT = SQLDialect.supportedBy(POSTGRES); + private static final Set EMULATE_FOR_UPDATE_WAIT_MY = SQLDialect.supportedUntil(MYSQL); + private static final Set EMULATE_FOR_UPDATE_WAIT_PG = SQLDialect.supportedBy(POSTGRES); QueryPartList> forLockOf; TableList forLockOfTables; @@ -168,9 +175,20 @@ final class ForLock extends AbstractQueryPart { if (forLockWaitMode != null) { // [#11243] PostgreSQL FOR UPDATE WAIT emulation - if (forLockWaitMode == ForLockWaitMode.WAIT && EMULATE_FOR_UPDATE_WAIT.contains(ctx.dialect())) { + if (forLockWaitMode == ForLockWaitMode.WAIT && EMULATE_FOR_UPDATE_WAIT_PG.contains(ctx.dialect())) { prependSQL(ctx.skipUpdateCount(), ctx.dsl().setLocal(N_LOCK_TIMEOUT, inline(forLockWait * 1000))); } + else if (forLockWaitMode == ForLockWaitMode.WAIT && EMULATE_FOR_UPDATE_WAIT_MY.contains(ctx.dialect())) { + if (ctx.data(DATA_LOCK_WAIT_TIMEOUT_SET) == null) { + ctx.skipUpdateCounts(2).data(DATA_LOCK_WAIT_TIMEOUT_SET, true); + + prependSQL(ctx, + ctx.dsl().query("{set} @t = @@innodb_lock_wait_timeout"), + ctx.dsl().query("{set} @@innodb_lock_wait_timeout = {0}", inline(forLockWait)) + ); + appendSQL(ctx, ctx.dsl().query("{set} @@innodb_lock_wait_timeout = @t")); + } + } else { ctx.sql(' ').visit(forLockWaitMode.toKeyword()); diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 8f9b3a9350..b724040b98 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -538,7 +538,13 @@ final class Tools { * [#12092] Whether the @@group_concat_max_len value has already been * set. */ - DATA_GROUP_CONCAT_MAX_LEN_SET + DATA_GROUP_CONCAT_MAX_LEN_SET, + + /** + * [#11543] Whether the @@innodb_lock_wait_timeout value has already + * been set. + */ + DATA_LOCK_WAIT_TIMEOUT_SET }