diff --git a/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnection.java b/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnection.java index aa3fb961e..771a923e9 100644 --- a/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnection.java +++ b/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnection.java @@ -33,6 +33,7 @@ import io.r2dbc.spi.Connection; import io.r2dbc.spi.IsolationLevel; import io.r2dbc.spi.Lifecycle; +import io.r2dbc.spi.R2dbcNonTransientResourceException; import io.r2dbc.spi.TransactionDefinition; import io.r2dbc.spi.ValidationDepth; import org.jetbrains.annotations.Nullable; @@ -74,6 +75,10 @@ public final class MySqlConnection implements Connection, Lifecycle, ConnectionS private static final ServerVersion MYSQL_8 = ServerVersion.create(8, 0, 0); + private static final ServerVersion MYSQL_STATEMENT_TIMEOUT = ServerVersion.create(5, 7, 4); + + private static final ServerVersion MARIA_STATEMENT_TIMEOUT = ServerVersion.create(10, 2, 0); + private static final BiConsumer> PING = (message, sink) -> { if (message instanceof ErrorMessage) { ErrorMessage msg = (ErrorMessage) message; @@ -396,21 +401,26 @@ public Mono setLockWaitTimeout(Duration timeout) { @Override public Mono setStatementTimeout(Duration timeout) { requireNonNull(timeout, "timeout must not be null"); - final ServerVersion supportedVersion = ServerVersion.create(5, 7, 4); - long time = timeout.toMillis(); - ServerVersion serverVersion = context.getServerVersion(); - boolean serverSupportTimeout = serverVersion.isGreaterThanOrEqualTo(supportedVersion); - - if (!serverSupportTimeout) { - return Mono.defer(() -> Mono.error(new RuntimeException( - "Query timeout is not supported by the server. (Required MySQL 5.7.4+)"))); + final boolean isMariaDb = context.getCapability().isMariaDb(); + final ServerVersion serverVersion = context.getServerVersion(); + final String sql = isMariaDb ? "SET max_statement_time=" + timeout.getSeconds() + : "SET SESSION MAX_EXECUTION_TIME=" + timeout.toMillis(); + + // mariadb: https://mariadb.com/kb/en/aborting-statements/ + // mysql: https://dev.mysql.com/blog-archive/server-side-select-statement-timeouts/ + if (isMariaDb && serverVersion.isGreaterThanOrEqualTo(MARIA_STATEMENT_TIMEOUT) + || !isMariaDb && serverVersion.isGreaterThanOrEqualTo(MYSQL_STATEMENT_TIMEOUT)) { + return QueryFlow.executeVoid(client, sql); } - String sqlStatement = String.format("SET SESSION MAX_EXECUTION_TIME=%s", time); - return QueryFlow.execute(client, sqlStatement) - .doOnError(error -> { - logger.error("Error setting statement timeout", error); - }).then(); + return Mono.error( + new R2dbcNonTransientResourceException( + "Statement timeout is not supported by server version " + serverVersion, + "HY000", + -1, + sql + ) + ); } boolean isSessionAutoCommit() {