Close prepared statement used to set the lock timeout

Closes #16801
This commit is contained in:
Alexander Schwartz 2023-02-02 18:45:08 +01:00 committed by Michal Hajas
parent 71d292ff70
commit 48aae83891

View file

@ -22,6 +22,7 @@ import java.sql.Connection;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -148,7 +149,7 @@ import org.keycloak.provider.EnvironmentDependentProviderFactory;
import org.keycloak.sessions.RootAuthenticationSessionModel; import org.keycloak.sessions.RootAuthenticationSessionModel;
import org.keycloak.transaction.JtaTransactionManagerLookup; import org.keycloak.transaction.JtaTransactionManagerLookup;
public class JpaMapStorageProviderFactory implements public class JpaMapStorageProviderFactory implements
AmphibianProviderFactory<MapStorageProvider>, AmphibianProviderFactory<MapStorageProvider>,
MapStorageProviderFactory, MapStorageProviderFactory,
EnvironmentDependentProviderFactory { EnvironmentDependentProviderFactory {
@ -288,8 +289,16 @@ public class JpaMapStorageProviderFactory implements
if (lockTimeout != null) { if (lockTimeout != null) {
em.unwrap(SessionImpl.class) em.unwrap(SessionImpl.class)
.doWork(connection -> { .doWork(connection -> {
PreparedStatement preparedStatement = connection.prepareStatement("SET LOCAL lock_timeout = '" + lockTimeout + "';"); // 'SET LOCAL lock_timeout = ...' can't be used with parameters in a prepared statement, leads to an
preparedStatement.execute(); // 'ERROR: syntax error at or near "$1"'
// on PostgreSQL.
// Using 'set_config()' instead as described here: https://www.postgresql.org/message-id/CAKFQuwbMaoO9%3DVUY1K0Nz5YBDyE6YQ9A_A6ncCxD%2Bt0yK1AxJg%40mail.gmail.com
// See https://www.postgresql.org/docs/13/functions-admin.html for the documentation on this function
try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT set_config('lock_timeout', ?, true)")) {
preparedStatement.setString(1, String.valueOf(lockTimeout));
ResultSet resultSet = preparedStatement.executeQuery();
resultSet.close();
}
}); });
} else { } else {
logger.warnf("Database %s used without lockTimeout option configured. This can result in deadlock where one connection waits for a pessimistic write lock forever.", databaseShortName); logger.warnf("Database %s used without lockTimeout option configured. This can result in deadlock where one connection waits for a pessimistic write lock forever.", databaseShortName);
@ -490,8 +499,8 @@ public class JpaMapStorageProviderFactory implements
} else { } else {
Class.forName(config.get("driver")); Class.forName(config.get("driver"));
return DriverManager.getConnection( return DriverManager.getConnection(
StringPropertyReplacer.replaceProperties(config.get("url"), System.getProperties()), StringPropertyReplacer.replaceProperties(config.get("url"), System.getProperties()),
config.get("user"), config.get("user"),
config.get("password")); config.get("password"));
} }
} catch (ClassNotFoundException | SQLException | NamingException e) { } catch (ClassNotFoundException | SQLException | NamingException e) {