mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 15:02:05 -03:30
fix: moving h2 logic out of Database so that it can be resolved (#43750)
closes: #43687 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
parent
9e98f2bf96
commit
74e5da49c7
@ -106,7 +106,7 @@ public final class Database {
|
||||
public String apply(String namedProperty, String alias) {
|
||||
if ("dev-file".equalsIgnoreCase(alias)) {
|
||||
var separator = escapeReplacements(File.separator);
|
||||
return amendH2(new StringBuilder()
|
||||
return new StringBuilder()
|
||||
.append("jdbc:h2:file:")
|
||||
.append("${kc.db-url-path:${kc.home.dir:%s}}".formatted(escapeReplacements(System.getProperty("user.home"))))
|
||||
.append(separator)
|
||||
@ -115,10 +115,9 @@ public final class Database {
|
||||
.append(getFolder(namedProperty))
|
||||
.append(separator)
|
||||
.append(getDbName(namedProperty))
|
||||
.append(getProperty(DatabaseOptions.DB_URL_PROPERTIES, namedProperty))
|
||||
.toString());
|
||||
.toString();
|
||||
}
|
||||
return amendH2("jdbc:h2:mem:%s%s".formatted(getDbName(namedProperty), getProperty(DatabaseOptions.DB_URL_PROPERTIES, namedProperty)));
|
||||
return "jdbc:h2:mem:%s".formatted(getDbName(namedProperty));
|
||||
}
|
||||
|
||||
private String getFolder(String namedProperty) {
|
||||
@ -139,43 +138,6 @@ public final class Database {
|
||||
return snippet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starting with H2 version 2.x, marking "VALUE" as a non-keyword is necessary as some columns are named "VALUE" in the Keycloak schema.
|
||||
* <p />
|
||||
* Alternatives considered and rejected:
|
||||
* <ul>
|
||||
* <li>customizing H2 Database dialect -> wouldn't work for existing Liquibase scripts.</li>
|
||||
* <li>adding quotes to <code>@Column(name="VALUE")</code> annotations -> would require testing for all DBs, wouldn't work for existing Liquibase scripts.</li>
|
||||
* </ul>
|
||||
* Downsides of this solution: Release notes needed to point out that any H2 JDBC URL parameter with <code>NON_KEYWORDS</code> needs to add the keyword <code>VALUE</code> manually.
|
||||
* @return JDBC URL with <code>NON_KEYWORDS=VALUE</code> appended if the URL doesn't contain <code>NON_KEYWORDS=</code> yet
|
||||
*/
|
||||
private String addH2NonKeywords(String jdbcUrl) {
|
||||
if (!jdbcUrl.contains("NON_KEYWORDS=")) {
|
||||
jdbcUrl = jdbcUrl + ";NON_KEYWORDS=VALUE";
|
||||
}
|
||||
return jdbcUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Required so that the H2 db instance is closed only when the Agroal connection pool is closed during
|
||||
* Keycloak shutdown. We cannot rely on the default H2 ShutdownHook as this can result in the DB being
|
||||
* closed before dependent resources, e.g. JDBC_PING2, are shutdown gracefully. This solution also
|
||||
* requires the Agroal min-pool connection size to be at least 1.
|
||||
*/
|
||||
private String addH2CloseOnExit(String jdbcUrl) {
|
||||
if (!jdbcUrl.contains("DB_CLOSE_ON_EXIT=")) {
|
||||
jdbcUrl = jdbcUrl + ";DB_CLOSE_ON_EXIT=FALSE";
|
||||
}
|
||||
if (!jdbcUrl.contains("DB_CLOSE_DELAY=")) {
|
||||
jdbcUrl = jdbcUrl + ";DB_CLOSE_DELAY=0";
|
||||
}
|
||||
return jdbcUrl;
|
||||
}
|
||||
|
||||
private String amendH2(String jdbcUrl) {
|
||||
return addH2CloseOnExit(addH2NonKeywords(jdbcUrl));
|
||||
}
|
||||
},
|
||||
"liquibase.database.core.H2Database",
|
||||
"dev-mem", "dev-file"
|
||||
|
||||
@ -132,17 +132,12 @@ final class DatabasePropertyMappers implements PropertyMapperGrouping {
|
||||
|
||||
String dbDriver = Configuration.getConfigValue(DatabaseOptions.DB_DRIVER).getValue();
|
||||
String dbUrl = Configuration.getConfigValue(DatabaseOptions.DB_URL).getValue();
|
||||
String dbUrlProperties = Configuration.getConfigValue(DatabaseOptions.DB_URL_PROPERTIES).getValue();
|
||||
|
||||
if (!Objects.equals(Database.getDriver(db, true).orElse(null), dbDriver) &&
|
||||
!Objects.equals(Database.getDriver(db, false).orElse(null), dbDriver)) {
|
||||
// Custom JDBC-Driver, for example, AWS JDBC Wrapper.
|
||||
return null;
|
||||
}
|
||||
if (dbUrlProperties != null && dbUrl != null && dbUrl.contains("${kc.db-url-properties:}") && dbUrlProperties.contains("targetServerType")) {
|
||||
// targetServerType already set to same or different value in db-url-properties, ignore
|
||||
return null;
|
||||
}
|
||||
if (dbUrl != null && dbUrl.contains("targetServerType")) {
|
||||
// targetServerType already set to same or different value in db-url, ignore
|
||||
return null;
|
||||
@ -151,8 +146,57 @@ final class DatabasePropertyMappers implements PropertyMapperGrouping {
|
||||
return "primary";
|
||||
}
|
||||
|
||||
/**
|
||||
* Starting with H2 version 2.x, marking "VALUE" as a non-keyword is necessary as some columns are named "VALUE" in the Keycloak schema.
|
||||
* <p />
|
||||
* Alternatives considered and rejected:
|
||||
* <ul>
|
||||
* <li>customizing H2 Database dialect -> wouldn't work for existing Liquibase scripts.</li>
|
||||
* <li>adding quotes to <code>@Column(name="VALUE")</code> annotations -> would require testing for all DBs, wouldn't work for existing Liquibase scripts.</li>
|
||||
* </ul>
|
||||
* Downsides of this solution: Release notes needed to point out that any H2 JDBC URL parameter with <code>NON_KEYWORDS</code> needs to add the keyword <code>VALUE</code> manually.
|
||||
* @return JDBC URL with <code>NON_KEYWORDS=VALUE</code> appended if the URL doesn't contain <code>NON_KEYWORDS=</code> yet
|
||||
*/
|
||||
private static String addH2NonKeywords(String jdbcUrl) {
|
||||
if (!jdbcUrl.contains("NON_KEYWORDS=")) {
|
||||
jdbcUrl = jdbcUrl + ";NON_KEYWORDS=VALUE";
|
||||
}
|
||||
return jdbcUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Required so that the H2 db instance is closed only when the Agroal connection pool is closed during
|
||||
* Keycloak shutdown. We cannot rely on the default H2 ShutdownHook as this can result in the DB being
|
||||
* closed before dependent resources, e.g. JDBC_PING2, are shutdown gracefully. This solution also
|
||||
* requires the Agroal min-pool connection size to be at least 1.
|
||||
*/
|
||||
private static String addH2CloseOnExit(String jdbcUrl) {
|
||||
if (!jdbcUrl.contains("DB_CLOSE_ON_EXIT=")) {
|
||||
jdbcUrl = jdbcUrl + ";DB_CLOSE_ON_EXIT=FALSE";
|
||||
}
|
||||
if (!jdbcUrl.contains("DB_CLOSE_DELAY=")) {
|
||||
jdbcUrl = jdbcUrl + ";DB_CLOSE_DELAY=0";
|
||||
}
|
||||
return jdbcUrl;
|
||||
}
|
||||
|
||||
private static String amendH2(String jdbcUrl) {
|
||||
return addH2CloseOnExit(addH2NonKeywords(jdbcUrl));
|
||||
}
|
||||
|
||||
private static String getDatabaseUrl(String name, String value, ConfigSourceInterceptorContext c) {
|
||||
return Database.getDefaultUrl(name, value).orElse(null);
|
||||
String url = Database.getDefaultUrl(name, value).orElse(null);
|
||||
if (isDevModeDatabase(value)) {
|
||||
String key = Optional.ofNullable(name).map(
|
||||
n -> DatabaseOptions.Datasources.getNamedKey(DatabaseOptions.DB_URL_PROPERTIES, n).orElseThrow())
|
||||
.orElse(DatabaseOptions.DB_URL_PROPERTIES.getKey());
|
||||
String urlProps = Configuration.getKcConfigValue(key).getValue();
|
||||
if (urlProps != null) {
|
||||
url += urlProps;
|
||||
}
|
||||
url = amendH2(url);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
private static String getXaOrNonXaDriver(String name, String value, ConfigSourceInterceptorContext context) {
|
||||
|
||||
@ -101,7 +101,6 @@ public class DatasourcesConfigurationTest extends AbstractConfigurationTest {
|
||||
assertConfig("db-dialect-store", H2Dialect.class.getName());
|
||||
// XA datasource is the default
|
||||
assertExternalConfig("quarkus.datasource.\"store\".jdbc.driver", JdbcDataSource.class.getName());
|
||||
assertExternalConfig("quarkus.datasource.\"store\".jdbc.url", "jdbc:h2:file:" + Environment.getHomeDir() + "/data/h2-store/keycloakdb-store;NON_KEYWORDS=VALUE;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=0");
|
||||
onAfter();
|
||||
|
||||
ConfigArgsConfigSource.setCliArgs("--db-kind-store=dev-mem");
|
||||
@ -185,6 +184,14 @@ public class DatasourcesConfigurationTest extends AbstractConfigurationTest {
|
||||
"quarkus.datasource.\"asdf\".db-kind", "postgresql"
|
||||
));
|
||||
onAfter();
|
||||
|
||||
ConfigArgsConfigSource.setCliArgs("--db-kind-asdf=dev-file", "--db-url-properties-asdf=;DB_CLOSE_ON_EXIT=true");
|
||||
initConfig();
|
||||
assertExternalConfig(Map.of(
|
||||
"quarkus.datasource.\"asdf\".jdbc.url", "jdbc:h2:file:" + Environment.getHomeDir() + "/data/h2-asdf/keycloakdb-asdf;DB_CLOSE_ON_EXIT=true;NON_KEYWORDS=VALUE;DB_CLOSE_DELAY=0",
|
||||
"quarkus.datasource.\"asdf\".db-kind", "h2"
|
||||
));
|
||||
onAfter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user