Skip to content

Commit 46aa8b3

Browse files
committed
QUARKUS-3363 - Disable JDBC Metadata Defaults in quarkus
Handle Hibernate's `DialectSpecificSettings` as supported Quarkus settings
1 parent 8e6e43d commit 46aa8b3

File tree

8 files changed

+340
-13
lines changed

8 files changed

+340
-13
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.quarkus.hibernate.orm.deployment;
2+
3+
import java.util.Optional;
4+
5+
import io.quarkus.runtime.annotations.ConfigGroup;
6+
import io.quarkus.runtime.configuration.TrimmedStringConverter;
7+
import io.smallrye.config.WithConverter;
8+
9+
/**
10+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.CockroachDialect}
11+
*
12+
* @author Steve Ebersole
13+
*/
14+
@ConfigGroup
15+
public interface CockroachDialectConfig {
16+
/**
17+
* Specialized version string which can be passed into the {@linkplain org.hibernate.dialect.CockroachDialect}
18+
*/
19+
@WithConverter(TrimmedStringConverter.class)
20+
Optional<String> versionString();
21+
22+
default boolean isAnyPropertySet() {
23+
return versionString().isPresent();
24+
}
25+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.quarkus.hibernate.orm.deployment;
2+
3+
import java.util.Optional;
4+
5+
import io.quarkus.runtime.annotations.ConfigDocDefault;
6+
import io.quarkus.runtime.annotations.ConfigGroup;
7+
8+
/**
9+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.HANADialect}
10+
*
11+
* @author Steve Ebersole
12+
*/
13+
@ConfigGroup
14+
public interface HANADialectConfig {
15+
/**
16+
* Specifies the LOB prefetch size.
17+
*
18+
* @see org.hibernate.cfg.DialectSpecificSettings#HANA_MAX_LOB_PREFETCH_SIZE
19+
*/
20+
@ConfigDocDefault("1024")
21+
Optional<Integer> maxLobPrefetchSize();
22+
23+
default boolean isAnyPropertySet() {
24+
return maxLobPrefetchSize().isPresent();
25+
}
26+
}

extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,13 +310,52 @@ interface HibernateOrmConfigPersistenceUnitDialect {
310310
*
311311
* E.g. `MyISAM` or `InnoDB` for MySQL.
312312
*
313+
* @deprecated Use {@code mysql.}{@linkplain MySQLDialectConfig#storageEngine storage-engine} instead
314+
*
313315
* @asciidoclet
314316
*/
315317
@WithConverter(TrimmedStringConverter.class)
318+
@Deprecated
316319
Optional<String> storageEngine();
317320

321+
/**
322+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.CockroachDialect}
323+
*/
324+
CockroachDialectConfig cockroach();
325+
326+
/**
327+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.HANADialect}
328+
*/
329+
HANADialectConfig hana();
330+
331+
/**
332+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.MySQLDialect}
333+
*/
334+
MySQLDialectConfig mysql();
335+
336+
/**
337+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.OracleDialect}
338+
*/
339+
OracleDialectConfig oracle();
340+
341+
/**
342+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.SQLServerDialect}
343+
*/
344+
SqlServerDialectConfig sqlserver();
345+
346+
/**
347+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.SybaseDialect}
348+
*/
349+
SybaseDialectConfig sybase();
350+
318351
default boolean isAnyPropertySet() {
319-
return dialect().isPresent() || storageEngine().isPresent();
352+
return dialect().isPresent() || storageEngine().isPresent()
353+
|| cockroach().isAnyPropertySet()
354+
|| hana().isAnyPropertySet()
355+
|| mysql().isAnyPropertySet()
356+
|| oracle().isAnyPropertySet()
357+
|| sqlserver().isAnyPropertySet()
358+
|| sybase().isAnyPropertySet();
320359
}
321360
}
322361

extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java

Lines changed: 103 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
import static org.hibernate.cfg.AvailableSettings.USE_DIRECT_REFERENCE_CACHE_ENTRIES;
88
import static org.hibernate.cfg.AvailableSettings.USE_QUERY_CACHE;
99
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
10+
import static org.hibernate.cfg.DialectSpecificSettings.COCKROACH_VERSION_STRING;
11+
import static org.hibernate.cfg.DialectSpecificSettings.HANA_MAX_LOB_PREFETCH_SIZE;
12+
import static org.hibernate.cfg.DialectSpecificSettings.MYSQL_BYTES_PER_CHARACTER;
13+
import static org.hibernate.cfg.DialectSpecificSettings.MYSQL_NO_BACKSLASH_ESCAPES;
14+
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_APPLICATION_CONTINUITY;
15+
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_AUTONOMOUS_DATABASE;
16+
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_EXTENDED_STRING_SIZE;
17+
import static org.hibernate.cfg.DialectSpecificSettings.SQL_SERVER_COMPATIBILITY_LEVEL;
18+
import static org.hibernate.cfg.DialectSpecificSettings.SYBASE_ANSI_NULL;
1019

1120
import java.io.IOException;
1221
import java.net.URL;
@@ -1117,7 +1126,10 @@ private static void collectDialectConfig(String persistenceUnitName,
11171126
MultiTenancyStrategy multiTenancyStrategy,
11181127
BuildProducer<SystemPropertyBuildItem> systemProperties,
11191128
BiConsumer<String, String> puPropertiesCollector, Set<String> storageEngineCollector) {
1120-
Optional<String> explicitDialect = persistenceUnitConfig.dialect().dialect();
1129+
final HibernateOrmConfigPersistenceUnit.HibernateOrmConfigPersistenceUnitDialect dialectConfig = persistenceUnitConfig
1130+
.dialect();
1131+
1132+
Optional<String> explicitDialect = dialectConfig.dialect();
11211133
Optional<String> dbKind = jdbcDataSource.map(JdbcDataSourceBuildItem::getDbKind);
11221134
Optional<String> explicitDbMinVersion = jdbcDataSource.flatMap(JdbcDataSourceBuildItem::getDbVersion);
11231135
if (multiTenancyStrategy != MultiTenancyStrategy.DATABASE && jdbcDataSource.isEmpty()) {
@@ -1174,24 +1186,103 @@ private static void collectDialectConfig(String persistenceUnitName,
11741186
persistenceUnitName));
11751187
}
11761188

1177-
if (persistenceUnitConfig.dialect().storageEngine().isPresent()) {
1178-
// Only actually set the storage engines if MySQL or MariaDB
1179-
if (isMySQLOrMariaDB(dbKind, dialect)) {
1180-
// The storage engine has to be set as a system property.
1181-
// We record it so that we can later run checks (because we can only set a single value)
1182-
storageEngineCollector.add(persistenceUnitConfig.dialect().storageEngine().get());
1183-
systemProperties.produce(new SystemPropertyBuildItem(AvailableSettings.STORAGE_ENGINE,
1184-
persistenceUnitConfig.dialect().storageEngine().get()));
1185-
} else {
1189+
if (dbProductVersion.isPresent()) {
1190+
puPropertiesCollector.accept(AvailableSettings.JAKARTA_HBM2DDL_DB_VERSION, dbProductVersion.get());
1191+
}
1192+
1193+
handleDialectSpecificSettings(
1194+
persistenceUnitName,
1195+
systemProperties,
1196+
puPropertiesCollector,
1197+
storageEngineCollector,
1198+
dialectConfig,
1199+
dbKind,
1200+
dialect);
1201+
}
1202+
1203+
private static void handleDialectSpecificSettings(
1204+
String persistenceUnitName,
1205+
BuildProducer<SystemPropertyBuildItem> systemProperties,
1206+
BiConsumer<String, String> puPropertiesCollector,
1207+
Set<String> storageEngineCollector,
1208+
HibernateOrmConfigPersistenceUnit.HibernateOrmConfigPersistenceUnitDialect dialectConfig,
1209+
Optional<String> dbKind,
1210+
Optional<String> dialect) {
1211+
1212+
// todo : do we want dbKind/dialect aware handling for all of these settings (i.e. isMySQLOrMariaDB)?
1213+
// if so, we need to reorganize this code a bit
1214+
1215+
final Optional<String> storageEngine = dialectConfig.mysql().storageEngine()
1216+
.or(() -> dialectConfig.storageEngine().or(Optional::empty));
1217+
if (isMySQLOrMariaDB(dbKind, dialect)) {
1218+
if (storageEngine.isPresent()) {
1219+
storageEngineCollector.add(storageEngine.get());
1220+
systemProperties.produce(new SystemPropertyBuildItem(AvailableSettings.STORAGE_ENGINE, storageEngine.get()));
1221+
}
1222+
applyOptionalIntegerSetting(dialectConfig.mysql().bytesPerCharacter(), MYSQL_BYTES_PER_CHARACTER,
1223+
puPropertiesCollector);
1224+
applyOptionalBooleanSetting(dialectConfig.mysql().noBackslashEscapes(), MYSQL_NO_BACKSLASH_ESCAPES,
1225+
puPropertiesCollector);
1226+
} else {
1227+
if (storageEngine.isPresent()) {
11861228
LOG.warnf("The storage engine set through configuration property '%1$s' is being ignored"
11871229
+ " because the database is neither MySQL nor MariaDB.",
11881230
HibernateOrmRuntimeConfig.puPropertyKey(persistenceUnitName, "dialect.storage-engine"));
11891231
}
1232+
1233+
applyOptionalStringSetting(dialectConfig.cockroach().versionString(), COCKROACH_VERSION_STRING,
1234+
puPropertiesCollector);
1235+
1236+
applyOptionalIntegerSetting(dialectConfig.hana().maxLobPrefetchSize(), HANA_MAX_LOB_PREFETCH_SIZE,
1237+
puPropertiesCollector);
1238+
1239+
applyOptionalIntegerSetting(dialectConfig.mysql().bytesPerCharacter(), MYSQL_BYTES_PER_CHARACTER,
1240+
puPropertiesCollector);
1241+
applyOptionalBooleanSetting(dialectConfig.mysql().noBackslashEscapes(), MYSQL_NO_BACKSLASH_ESCAPES,
1242+
puPropertiesCollector);
1243+
1244+
applyOptionalBooleanSetting(dialectConfig.oracle().applicationContinuity(), ORACLE_APPLICATION_CONTINUITY,
1245+
puPropertiesCollector);
1246+
applyOptionalBooleanSetting(dialectConfig.oracle().autonomous(), ORACLE_AUTONOMOUS_DATABASE,
1247+
puPropertiesCollector);
1248+
applyOptionalBooleanSetting(dialectConfig.oracle().extended(), ORACLE_EXTENDED_STRING_SIZE,
1249+
puPropertiesCollector);
1250+
1251+
applyOptionalStringSetting(dialectConfig.sqlserver().compatibilityLevel(), SQL_SERVER_COMPATIBILITY_LEVEL,
1252+
puPropertiesCollector);
1253+
1254+
applyOptionalBooleanSetting(dialectConfig.sybase().ansinull(), SYBASE_ANSI_NULL, puPropertiesCollector);
11901255
}
1256+
}
11911257

1192-
if (dbProductVersion.isPresent()) {
1193-
puPropertiesCollector.accept(AvailableSettings.JAKARTA_HBM2DDL_DB_VERSION, dbProductVersion.get());
1258+
private static void applyOptionalStringSetting(
1259+
Optional<String> setting,
1260+
String settingName,
1261+
BiConsumer<String, String> puPropertiesCollector) {
1262+
if (setting.isEmpty()) {
1263+
return;
1264+
}
1265+
puPropertiesCollector.accept(settingName, setting.get());
1266+
}
1267+
1268+
private static void applyOptionalIntegerSetting(
1269+
Optional<Integer> setting,
1270+
String settingName,
1271+
BiConsumer<String, String> puPropertiesCollector) {
1272+
if (setting.isEmpty()) {
1273+
return;
1274+
}
1275+
puPropertiesCollector.accept(settingName, Integer.toString(setting.get()));
1276+
}
1277+
1278+
private static void applyOptionalBooleanSetting(
1279+
Optional<Boolean> setting,
1280+
String settingName,
1281+
BiConsumer<String, String> puPropertiesCollector) {
1282+
if (setting.isEmpty()) {
1283+
return;
11941284
}
1285+
puPropertiesCollector.accept(settingName, Boolean.toString(setting.get()));
11951286
}
11961287

11971288
private static void collectDialectConfigForPersistenceXml(String persistenceUnitName,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package io.quarkus.hibernate.orm.deployment;
2+
3+
import java.util.Optional;
4+
5+
import io.quarkus.runtime.annotations.ConfigDocDefault;
6+
import io.quarkus.runtime.annotations.ConfigGroup;
7+
import io.quarkus.runtime.configuration.TrimmedStringConverter;
8+
import io.smallrye.config.WithConverter;
9+
10+
/**
11+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.MySQLDialect},
12+
* though may also affect other dialects such as {@linkplain org.hibernate.dialect.MariaDBDialect}.
13+
*
14+
* @author Steve Ebersole
15+
*/
16+
@ConfigGroup
17+
public interface MySQLDialectConfig {
18+
/**
19+
* Specifies the bytes per character to use based on the database's configured
20+
* <a href="https://dev.mysql.com/doc/refman/8.0/en/charset-charsets.html">charset</a>.
21+
*
22+
* @see org.hibernate.cfg.DialectSpecificSettings#MYSQL_BYTES_PER_CHARACTER
23+
*/
24+
@ConfigDocDefault("4")
25+
Optional<Integer> bytesPerCharacter();
26+
27+
/**
28+
* Specifies whether the {@code NO_BACKSLASH_ESCAPES} sql mode is enabled.
29+
*
30+
* @see org.hibernate.cfg.DialectSpecificSettings#MYSQL_NO_BACKSLASH_ESCAPES
31+
*/
32+
@ConfigDocDefault("false")
33+
Optional<Boolean> noBackslashEscapes();
34+
35+
/**
36+
* The storage engine to use.
37+
*/
38+
@WithConverter(TrimmedStringConverter.class)
39+
Optional<String> storageEngine();
40+
41+
default boolean isAnyPropertySet() {
42+
return bytesPerCharacter().isPresent()
43+
|| noBackslashEscapes().isPresent()
44+
|| storageEngine().isPresent();
45+
}
46+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package io.quarkus.hibernate.orm.deployment;
2+
3+
import java.util.Optional;
4+
5+
import io.quarkus.runtime.annotations.ConfigDocDefault;
6+
import io.quarkus.runtime.annotations.ConfigGroup;
7+
8+
/**
9+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.OracleDialect}
10+
*
11+
* @author Steve Ebersole
12+
*/
13+
@ConfigGroup
14+
public interface OracleDialectConfig {
15+
16+
/**
17+
* Support for Oracle's MAX_STRING_SIZE = EXTENDED.
18+
*
19+
* @see org.hibernate.cfg.DialectSpecificSettings#ORACLE_EXTENDED_STRING_SIZE
20+
*/
21+
@ConfigDocDefault("false")
22+
Optional<Boolean> extended();
23+
24+
/**
25+
* Specifies whether this database is running on an Autonomous Database Cloud Service.
26+
*
27+
* @see org.hibernate.cfg.DialectSpecificSettings#ORACLE_AUTONOMOUS_DATABASE
28+
*/
29+
@ConfigDocDefault("false")
30+
Optional<Boolean> autonomous();
31+
32+
/**
33+
* Specifies whether this database is accessed using a database service protected by Application Continuity.
34+
*
35+
* @see org.hibernate.cfg.DialectSpecificSettings#ORACLE_APPLICATION_CONTINUITY
36+
*/
37+
@ConfigDocDefault("false")
38+
Optional<Boolean> applicationContinuity();
39+
40+
default boolean isAnyPropertySet() {
41+
return extended().isPresent()
42+
|| autonomous().isPresent()
43+
|| applicationContinuity().isPresent();
44+
}
45+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.quarkus.hibernate.orm.deployment;
2+
3+
import java.util.Optional;
4+
5+
import io.quarkus.runtime.annotations.ConfigGroup;
6+
import io.quarkus.runtime.configuration.TrimmedStringConverter;
7+
import io.smallrye.config.WithConverter;
8+
9+
/**
10+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.SQLServerDialect}
11+
*
12+
* @author Steve Ebersole
13+
*/
14+
@ConfigGroup
15+
public interface SqlServerDialectConfig {
16+
/**
17+
* The {@code compatibility_level} as defined in {@code sys.databases}.
18+
*
19+
* @see org.hibernate.cfg.DialectSpecificSettings#SQL_SERVER_COMPATIBILITY_LEVEL
20+
*/
21+
@WithConverter(TrimmedStringConverter.class)
22+
Optional<String> compatibilityLevel();
23+
24+
default boolean isAnyPropertySet() {
25+
return compatibilityLevel().isPresent();
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.quarkus.hibernate.orm.deployment;
2+
3+
import java.util.Optional;
4+
5+
import io.quarkus.runtime.annotations.ConfigDocDefault;
6+
import io.quarkus.runtime.annotations.ConfigGroup;
7+
8+
/**
9+
* Configuration specific to the Hibernate ORM {@linkplain org.hibernate.dialect.SybaseDialect}
10+
*
11+
* @author Steve Ebersole
12+
*/
13+
@ConfigGroup
14+
public interface SybaseDialectConfig {
15+
16+
/**
17+
* Whether the database's {@code ansinull} setting is enabled
18+
*
19+
* @see org.hibernate.cfg.DialectSpecificSettings#SYBASE_ANSI_NULL
20+
*/
21+
@SuppressWarnings("SpellCheckingInspection")
22+
@ConfigDocDefault("false")
23+
Optional<Boolean> ansinull();
24+
25+
default boolean isAnyPropertySet() {
26+
return ansinull().isPresent();
27+
}
28+
}

0 commit comments

Comments
 (0)