Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.11] Backport to 3.11: Upgrade to Hibernate ORM 6.5.2 and configure Hibernate ORM/Reactive with database product names instead of dialect names for core dialects #40675

Merged
merged 5 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@
bytebuddy.version (just below), hibernate-orm.version-for-documentation (in docs/pom.xml)
and both hibernate-orm.version and antlr.version in build-parent/pom.xml
WARNING again for diffs that don't provide enough context: when updating, see above -->
<hibernate-orm.version>6.5.0.Final</hibernate-orm.version>
<bytebuddy.version>1.14.12</bytebuddy.version> <!-- Version controlled by Hibernate ORM's needs -->
<hibernate-orm.version>6.5.2.Final</hibernate-orm.version>
<bytebuddy.version>1.14.15</bytebuddy.version> <!-- Version controlled by Hibernate ORM's needs -->
<hibernate-commons-annotations.version>6.0.6.Final</hibernate-commons-annotations.version> <!-- version controlled by Hibernate ORM -->
<hibernate-reactive.version>2.3.0.Final</hibernate-reactive.version>
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.hibernate.orm.deployment.spi;

import java.util.Optional;
import java.util.Set;

import io.quarkus.builder.item.MultiBuildItem;

Expand All @@ -9,15 +10,74 @@
*/
public final class DatabaseKindDialectBuildItem extends MultiBuildItem {
private final String dbKind;
private final String dialect;
private final Optional<String> databaseProductName;
private final Optional<String> dialect;
private final Set<String> matchingDialects;
private final Optional<String> defaultDatabaseProductVersion;

/**
* @param dbKind The DB Kind set through {@code quarkus.datasource.db-kind}
* @param databaseProductName The corresponding database-product-name to set in Hibernate ORM.
* See {@code org.hibernate.dialect.Database} for information on how this name is resolved to a dialect.
* @param dialects The corresponding dialects in Hibernate ORM,
* to detect the dbKind when using database multi-tenancy.
*/
public static DatabaseKindDialectBuildItem forCoreDialect(String dbKind, String databaseProductName,
Set<String> dialects) {
return new DatabaseKindDialectBuildItem(dbKind, Optional.empty(), Optional.of(databaseProductName),
dialects, Optional.empty());
}

/**
* @param dbKind The DB Kind set through {@code quarkus.datasource.db-kind}
* @param databaseProductName The corresponding database-product-name to set in Hibernate ORM.
* See {@code org.hibernate.dialect.Database} for information on how this name is resolved to a dialect.
* @param dialects The corresponding dialects in Hibernate ORM,
* to detect the dbKind when using database multi-tenancy.
* @param defaultDatabaseProductVersion The default database-product-version to set in Hibernate ORM.
* This is useful when the default version of the dialect in Hibernate ORM
* is lower than what we expect in Quarkus.
*/
public static DatabaseKindDialectBuildItem forCoreDialect(String dbKind, String databaseProductName,
Set<String> dialects, String defaultDatabaseProductVersion) {
return new DatabaseKindDialectBuildItem(dbKind, Optional.empty(), Optional.of(databaseProductName),
dialects, Optional.of(defaultDatabaseProductVersion));
}

/**
* @param dbKind The DB Kind set through {@code quarkus.datasource.db-kind}
* @param dialect The corresponding dialect to set in Hibernate ORM.
* See {@code org.hibernate.dialect.Database} for information on how this name is resolved to a dialect.
*/
public static DatabaseKindDialectBuildItem forThirdPartyDialect(String dbKind, String dialect) {
return new DatabaseKindDialectBuildItem(dbKind, Optional.of(dialect), Optional.empty(), Set.of(dialect),
Optional.empty());
}

/**
* @param dbKind The DB Kind set through {@code quarkus.datasource.db-kind}
* @param dialect The corresponding dialect to set in Hibernate ORM.
* See {@code org.hibernate.dialect.Database} for information on how this name is resolved to a dialect.
* @param defaultDatabaseProductVersion The default database-product-version to set in Hibernate ORM.
* This is useful when the default version of the dialect in Hibernate ORM
* is lower than what we expect in Quarkus.
*/
public static DatabaseKindDialectBuildItem forThirdPartyDialect(String dbKind, String dialect,
String defaultDatabaseProductVersion) {
return new DatabaseKindDialectBuildItem(dbKind, Optional.of(dialect), Optional.empty(),
Set.of(dialect), Optional.of(defaultDatabaseProductVersion));
}

/**
* @param dbKind The DB Kind set through {@code quarkus.datasource.db-kind}
* @param dialect The corresponding dialect to set in Hibernate ORM.
* @deprecated Use {@link #forCoreDialect(String, String, Set)}(different arguments!)
* for core Hibernate ORM dialects to avoid warnings on startup,
* or {@link #forThirdPartyDialect(String, String)} for community or third-party dialects.
*/
@Deprecated
public DatabaseKindDialectBuildItem(String dbKind, String dialect) {
this(dbKind, dialect, Optional.empty());
this(dbKind, Optional.of(dialect), Optional.empty(), Set.of(dialect), Optional.empty());
}

/**
Expand All @@ -27,15 +87,22 @@ public DatabaseKindDialectBuildItem(String dbKind, String dialect) {
* @param defaultDatabaseProductVersion The default database-product-version to set in Hibernate ORM.
* This is useful when the default version of the dialect in Hibernate ORM
* is lower than what we expect in Quarkus.
* @deprecated Use {@link #forCoreDialect(String, String, Set, String)}(different arguments!)
* for core Hibernate ORM dialects to avoid warnings on startup,
* or {@link #forThirdPartyDialect(String, String, String)} for community or third-party dialects.
*/
@Deprecated
public DatabaseKindDialectBuildItem(String dbKind, String dialect, String defaultDatabaseProductVersion) {
this(dbKind, dialect, Optional.of(defaultDatabaseProductVersion));
this(dbKind, Optional.of(dialect), Optional.empty(), Set.of(dialect), Optional.of(defaultDatabaseProductVersion));
}

private DatabaseKindDialectBuildItem(String dbKind, String dialect,
private DatabaseKindDialectBuildItem(String dbKind, Optional<String> dialect,
Optional<String> databaseProductName, Set<String> matchingDialects,
Optional<String> defaultDatabaseProductVersion) {
this.dbKind = dbKind;
this.dialect = dialect;
this.matchingDialects = matchingDialects;
this.databaseProductName = databaseProductName;
this.defaultDatabaseProductVersion = defaultDatabaseProductVersion;
}

Expand All @@ -44,9 +111,21 @@ public String getDbKind() {
}

public String getDialect() {
return dialect.get();
}

public Optional<String> getDialectOptional() {
return dialect;
}

public Set<String> getMatchingDialects() {
return matchingDialects;
}

public Optional<String> getDatabaseProductName() {
return databaseProductName;
}

public Optional<String> getDefaultDatabaseProductVersion() {
return defaultDatabaseProductVersion;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ void setupLogFilters(BuildProducer<LogCleanupFilterBuildItem> filters) {
// Silence incubating settings warnings as we will use some for compatibility
filters.produce(new LogCleanupFilterBuildItem("org.hibernate.orm.incubating",
"HHH90006001"));
// https://hibernate.atlassian.net/browse/HHH-16546
filters.produce(new LogCleanupFilterBuildItem("org.hibernate.tuple.entity.EntityMetamodel", "HHH000157"));

//This "deprecation" warning isn't practical for the specific Quarkus needs, as it reminds users they don't need
//to set the 'hibernate.dialect' property, however it's being set by Quarkus buildsteps so they can't avoid it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,24 +162,27 @@ public final class HibernateOrmProcessor {
@BuildStep
void registerHibernateOrmMetadataForCoreDialects(
BuildProducer<DatabaseKindDialectBuildItem> producer) {
producer.produce(new DatabaseKindDialectBuildItem(DatabaseKind.DB2,
"org.hibernate.dialect.DB2Dialect"));
producer.produce(new DatabaseKindDialectBuildItem(DatabaseKind.DERBY,
"org.hibernate.dialect.DerbyDialect"));
producer.produce(new DatabaseKindDialectBuildItem(DatabaseKind.H2,
producer.produce(DatabaseKindDialectBuildItem.forCoreDialect(DatabaseKind.DB2, "DB2",
Set.of("org.hibernate.dialect.DB2Dialect")));
producer.produce(DatabaseKindDialectBuildItem.forCoreDialect(DatabaseKind.DERBY, "Apache Derby",
Set.of("org.hibernate.dialect.DerbyDialect")));
producer.produce(DatabaseKindDialectBuildItem.forCoreDialect(DatabaseKind.H2, "H2",
Set.of("org.hibernate.dialect.H2Dialect"),
// Using our own default version is extra important for H2
// See https://github.com/quarkusio/quarkus/issues/1886
"org.hibernate.dialect.H2Dialect", DialectVersions.Defaults.H2));
producer.produce(new DatabaseKindDialectBuildItem(DatabaseKind.MARIADB,
"org.hibernate.dialect.MariaDBDialect", DialectVersions.Defaults.MARIADB));
producer.produce(new DatabaseKindDialectBuildItem(DatabaseKind.MSSQL,
"org.hibernate.dialect.SQLServerDialect", DialectVersions.Defaults.MSSQL));
producer.produce(new DatabaseKindDialectBuildItem(DatabaseKind.MYSQL,
"org.hibernate.dialect.MySQLDialect"));
producer.produce(new DatabaseKindDialectBuildItem(DatabaseKind.ORACLE,
"org.hibernate.dialect.OracleDialect"));
producer.produce(new DatabaseKindDialectBuildItem(DatabaseKind.POSTGRESQL,
"org.hibernate.dialect.PostgreSQLDialect"));
DialectVersions.Defaults.H2));
producer.produce(DatabaseKindDialectBuildItem.forCoreDialect(DatabaseKind.MARIADB, "MariaDB",
Set.of("org.hibernate.dialect.MariaDBDialect"),
DialectVersions.Defaults.MARIADB));
producer.produce(DatabaseKindDialectBuildItem.forCoreDialect(DatabaseKind.MSSQL, "Microsoft SQL Server",
Set.of("org.hibernate.dialect.SQLServerDialect"),
DialectVersions.Defaults.MSSQL));
producer.produce(DatabaseKindDialectBuildItem.forCoreDialect(DatabaseKind.MYSQL, "MySQL",
Set.of("org.hibernate.dialect.MySQLDialect")));
producer.produce(DatabaseKindDialectBuildItem.forCoreDialect(DatabaseKind.ORACLE, "Oracle",
Set.of("org.hibernate.dialect.OracleDialect")));
producer.produce(DatabaseKindDialectBuildItem.forCoreDialect(DatabaseKind.POSTGRESQL, "PostgreSQL",
Set.of("org.hibernate.dialect.PostgreSQLDialect")));
}

@BuildStep
Expand Down Expand Up @@ -1107,23 +1110,26 @@ private static void collectDialectConfig(String persistenceUnitName,
}

Optional<String> dialect = explicitDialect;
Optional<String> dbProductName = Optional.empty();
Optional<String> dbProductVersion = explicitDbMinVersion;
if (dbKind.isPresent() || explicitDialect.isPresent()) {
for (DatabaseKindDialectBuildItem item : dbKindMetadataBuildItems) {
if (dbKind.isPresent() && DatabaseKind.is(dbKind.get(), item.getDbKind())
// Set the default version based on the dialect when we don't have a datasource
// (i.e. for database multi-tenancy)
|| explicitDialect.isPresent() && explicitDialect.get().equals(item.getDialect())) {
if (explicitDialect.isEmpty()) {
dialect = Optional.of(item.getDialect());
|| explicitDialect.isPresent() && item.getMatchingDialects().contains(explicitDialect.get())) {
dbProductName = item.getDatabaseProductName();
if (dbProductName.isEmpty() && explicitDialect.isEmpty()) {
// Use dialects only as a last resort, prefer product name or explicitly user-provided dialect
dialect = item.getDialectOptional();
}
if (explicitDbMinVersion.isEmpty()) {
dbProductVersion = item.getDefaultDatabaseProductVersion();
}
break;
}
}
if (dialect.isEmpty()) {
if (dialect.isEmpty() && dbProductName.isEmpty()) {
throw new ConfigurationException(
"The Hibernate ORM extension could not guess the dialect from the database kind '" + dbKind.get()
+ "'. Add an explicit '"
Expand All @@ -1134,6 +1140,8 @@ private static void collectDialectConfig(String persistenceUnitName,

if (dialect.isPresent()) {
puPropertiesCollector.accept(AvailableSettings.DIALECT, dialect.get());
} else if (dbProductName.isPresent()) {
puPropertiesCollector.accept(AvailableSettings.JAKARTA_HBM2DDL_DB_NAME, dbProductName.get());
} else {
// We only get here with the database multi-tenancy strategy; see the initial check, up top.
assert multiTenancyStrategy == MultiTenancyStrategy.DATABASE;
Expand All @@ -1148,7 +1156,7 @@ private static void collectDialectConfig(String persistenceUnitName,

if (persistenceUnitConfig.dialect().storageEngine().isPresent()) {
// Only actually set the storage engines if MySQL or MariaDB
if (isMySQLOrMariaDB(dialect.get())) {
if (isMySQLOrMariaDB(dbKind, dialect)) {
// The storage engine has to be set as a system property.
// We record it so that we can later run checks (because we can only set a single value)
storageEngineCollector.add(persistenceUnitConfig.dialect().storageEngine().get());
Expand Down Expand Up @@ -1609,9 +1617,15 @@ private static Class[] toArray(final Set<Class<?>> interfaces) {
return interfaces.toArray(new Class[interfaces.size()]);
}

private static boolean isMySQLOrMariaDB(String dialect) {
String lowercaseDialect = dialect.toLowerCase(Locale.ROOT);
return lowercaseDialect.contains("mysql") || lowercaseDialect.contains("mariadb");
private static boolean isMySQLOrMariaDB(Optional<String> dbKind, Optional<String> dialect) {
if (dbKind.isPresent() && (DatabaseKind.isMySQL(dbKind.get()) || DatabaseKind.isMariaDB(dbKind.get()))) {
return true;
}
if (dialect.isPresent()) {
String lowercaseDialect = dialect.get().toLowerCase(Locale.ROOT);
return lowercaseDialect.contains("mysql") || lowercaseDialect.contains("mariadb");
}
return false;
}

private static final class ProxyCache {
Expand Down

This file was deleted.

Loading
Loading