diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java index 19e54e7a8fb6..081d041a18f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java @@ -159,10 +159,11 @@ private void createIndexOrUniqueKey( String[] columnNames, String[] orderings, boolean unique, + boolean declaredAsIndex, String options, Selectable[] columns) { final IndexOrUniqueKeyNameSource source = - new IndexOrUniqueKeyNameSource( context, table, columnNames, originalKeyName ); + new IndexOrUniqueKeyNameSource( context, table, columnNames, originalKeyName, declaredAsIndex ); boolean hasFormula = false; for ( Selectable selectable : columns ) { if ( selectable.isFormula() ) { @@ -218,6 +219,7 @@ void bindIndexes(Table table, jakarta.persistence.Index[] indexes) { columnExpressions, ordering, unique, + true, options, selectables( table, name, columnExpressions ) ); @@ -236,6 +238,7 @@ void bindUniqueConstraints(Table table, UniqueConstraint[] constraints) { columnNames, null, true, + false, options, columns( table, name, columnNames ) ); @@ -261,17 +264,32 @@ else if ( tmp.endsWith( " asc" ) ) { } } - private class IndexOrUniqueKeyNameSource implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource { + private class IndexOrUniqueKeyNameSource + implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource { private final MetadataBuildingContext buildingContext; private final Table table; private final String[] columnNames; private final String originalKeyName; + private final boolean declaredAsIndex; - public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, String[] columnNames, String originalKeyName) { + private IndexOrUniqueKeyNameSource( + MetadataBuildingContext buildingContext, + Table table, + String[] columnNames, + String originalKeyName, + boolean declaredAsIndex) { this.buildingContext = buildingContext; this.table = table; this.columnNames = columnNames; this.originalKeyName = originalKeyName; + this.declaredAsIndex = declaredAsIndex; + } + + @Override + public Kind kind() { + return declaredAsIndex + ? ImplicitIndexNameSource.super.kind() + : ImplicitUniqueKeyNameSource.super.kind(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitConstraintNameSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitConstraintNameSource.java index 6751d87ca5fc..4a537fc9b489 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitConstraintNameSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitConstraintNameSource.java @@ -11,8 +11,17 @@ * * @author Steve Ebersole */ -public interface ImplicitConstraintNameSource extends ImplicitNameSource { +public sealed interface ImplicitConstraintNameSource + extends ImplicitNameSource + permits ImplicitIndexNameSource, ImplicitUniqueKeyNameSource, ImplicitForeignKeyNameSource { Identifier getTableName(); List getColumnNames(); Identifier getUserProvidedIdentifier(); + Kind kind(); + + enum Kind { + FOREIGN_KEY, + UNIQUE_KEY, + INDEX + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitForeignKeyNameSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitForeignKeyNameSource.java index 6f3f4729447f..4fdbac17567a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitForeignKeyNameSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitForeignKeyNameSource.java @@ -9,7 +9,13 @@ /** * @author Steve Ebersole */ -public interface ImplicitForeignKeyNameSource extends ImplicitConstraintNameSource { +public non-sealed interface ImplicitForeignKeyNameSource + extends ImplicitConstraintNameSource { Identifier getReferencedTableName(); List getReferencedColumnNames(); + + @Override + default Kind kind() { + return Kind.FOREIGN_KEY; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitIndexNameSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitIndexNameSource.java index de47d8fbe9eb..48b591e9da30 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitIndexNameSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitIndexNameSource.java @@ -7,5 +7,10 @@ /** * @author Steve Ebersole */ -public interface ImplicitIndexNameSource extends ImplicitConstraintNameSource { +public non-sealed interface ImplicitIndexNameSource + extends ImplicitConstraintNameSource { + @Override + default Kind kind() { + return Kind.INDEX; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java index e49c25c7e80b..14953031b616 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java @@ -9,6 +9,7 @@ import org.hibernate.HibernateException; import org.hibernate.boot.model.source.spi.AttributePath; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import static org.hibernate.boot.model.naming.ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION; import static org.hibernate.internal.util.StringHelper.isNotEmpty; @@ -92,17 +93,19 @@ public Identifier determineIdentifierColumnName(ImplicitIdentifierColumnNameSour @Override public Identifier determineDiscriminatorColumnName(ImplicitDiscriminatorColumnNameSource source) { + final MetadataBuildingContext context = source.getBuildingContext(); return toIdentifier( - source.getBuildingContext().getEffectiveDefaults().getDefaultDiscriminatorColumnName(), - source.getBuildingContext() + context.getEffectiveDefaults().getDefaultDiscriminatorColumnName(), + context ); } @Override public Identifier determineTenantIdColumnName(ImplicitTenantIdColumnNameSource source) { + final MetadataBuildingContext context = source.getBuildingContext(); return toIdentifier( - source.getBuildingContext().getEffectiveDefaults().getDefaultTenantIdColumnName(), - source.getBuildingContext() + context.getEffectiveDefaults().getDefaultTenantIdColumnName(), + context ); } @@ -113,7 +116,10 @@ public Identifier determineTenantIdColumnName(ImplicitTenantIdColumnNameSource s */ @Override public Identifier determineBasicColumnName(ImplicitBasicColumnNameSource source) { - return toIdentifier( transformAttributePath( source.getAttributePath() ), source.getBuildingContext() ); + return toIdentifier( + transformAttributePath( source.getAttributePath() ), + source.getBuildingContext() + ); } /** @@ -152,25 +158,24 @@ public Identifier determinePrimaryKeyJoinColumnName(ImplicitPrimaryKeyJoinColumn @Override public Identifier determineAnyDiscriminatorColumnName(ImplicitAnyDiscriminatorColumnNameSource source) { - final MetadataBuildingContext buildingContext = source.getBuildingContext(); + final MetadataBuildingContext context = source.getBuildingContext(); return toIdentifier( transformAttributePath( source.getAttributePath() ) - + "_" + buildingContext.getEffectiveDefaults().getDefaultDiscriminatorColumnName(), - buildingContext + + "_" + context.getEffectiveDefaults().getDefaultDiscriminatorColumnName(), + context ); } @Override public Identifier determineAnyKeyColumnName(ImplicitAnyKeyColumnNameSource source) { - final MetadataBuildingContext buildingContext = source.getBuildingContext(); + final MetadataBuildingContext context = source.getBuildingContext(); return toIdentifier( transformAttributePath( source.getAttributePath() ) - + "_" + buildingContext.getEffectiveDefaults().getDefaultIdColumnName(), - buildingContext + + "_" + context.getEffectiveDefaults().getDefaultIdColumnName(), + context ); } - @Override public Identifier determineMapKeyColumnName(ImplicitMapKeyColumnNameSource source) { return toIdentifier( @@ -190,35 +195,25 @@ public Identifier determineListIndexColumnName(ImplicitIndexColumnNameSource sou @Override public Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) { final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); - final MetadataBuildingContext buildingContext = source.getBuildingContext(); - return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( - NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() ) - .generateHashedFkName( "FK", source.getTableName(), - source.getReferencedTableName(), source.getColumnNames() ), - buildingContext - ); + return userProvidedIdentifier == null + ? generateConstraintName( source ) + : userProvidedIdentifier; } @Override public Identifier determineUniqueKeyName(ImplicitUniqueKeyNameSource source) { final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); - final MetadataBuildingContext buildingContext = source.getBuildingContext(); - return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( - NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() ) - .generateHashedConstraintName( "UK", source.getTableName(), source.getColumnNames() ), - buildingContext - ); + return userProvidedIdentifier == null + ? generateConstraintName( source ) + : userProvidedIdentifier; } @Override public Identifier determineIndexName(ImplicitIndexNameSource source) { final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); - final MetadataBuildingContext buildingContext = source.getBuildingContext(); - return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( - NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() ) - .generateHashedConstraintName( "IDX", source.getTableName(), source.getColumnNames() ), - buildingContext - ); + return userProvidedIdentifier == null + ? generateConstraintName( source ) + : userProvidedIdentifier; } /** @@ -235,18 +230,85 @@ protected String transformAttributePath(AttributePath attributePath) { } /** - * Easy hook to build an Identifier using the keyword safe IdentifierHelper. + * Easy hook to build an {@link Identifier} using the keyword safe + * {@link org.hibernate.engine.jdbc.env.spi.IdentifierHelper}. * * @param stringForm The String form of the name - * @param buildingContext Access to the IdentifierHelper + * @param buildingContext Access to the {@code IdentifierHelper} * * @return The identifier */ protected Identifier toIdentifier(String stringForm, MetadataBuildingContext buildingContext) { - return buildingContext.getMetadataCollector() - .getDatabase() - .getJdbcEnvironment() - .getIdentifierHelper() - .toIdentifier( stringForm ); + return toIdentifier( stringForm, + buildingContext.getMetadataCollector() + .getDatabase() + .getJdbcEnvironment() + .getIdentifierHelper() ); + } + + /** + * Easy hook to build an {@link Identifier} using the keyword safe + * {@link org.hibernate.engine.jdbc.env.spi.IdentifierHelper}. + * + * @param stringForm The String form of the name + * @param identifierHelper The {@code IdentifierHelper} + * + * @return The identifier + */ + protected Identifier toIdentifier(String stringForm, IdentifierHelper identifierHelper) { + return identifierHelper.toIdentifier( stringForm ); + } + + /** + * Generate a name for the given constraint. + * + * @return The identifier + */ + protected Identifier generateConstraintName(ImplicitConstraintNameSource source) { + return toIdentifier( generateConstraintNameString( source ), source.getBuildingContext() ); + } + + /** + * Generate a name for the given constraint. + * + * @return The name as a string + */ + protected String generateConstraintNameString(ImplicitConstraintNameSource source) { + final NamingHelper namingHelper = namingHelper( source.getBuildingContext() ); + final String prefix = constraintNamePrefix( source.kind() ); + return source instanceof ImplicitForeignKeyNameSource foreignKeySource + ? namingHelper.generateHashedFkName( + prefix, + source.getTableName(), + // include the referenced table in the hash + foreignKeySource.getReferencedTableName(), + source.getColumnNames() + ) + : namingHelper.generateHashedConstraintName( + prefix, + source.getTableName(), + source.getColumnNames() + ); + } + + /** + * Obtain a {@link NamingHelper} for use in constraint name generation. + */ + protected NamingHelper namingHelper(MetadataBuildingContext context) { + return NamingHelper.withCharset( context.getBuildingOptions().getSchemaCharset() ); + } + + /** + * The prefix for a generated constraint name of the given + * {@linkplain ImplicitConstraintNameSource.Kind kind}. + * + * @return The prefix as a string + */ + protected String constraintNamePrefix(ImplicitConstraintNameSource.Kind kind) { + return switch ( kind ) { + case INDEX -> "IDX"; + case UNIQUE_KEY -> "UK"; + case FOREIGN_KEY -> "FK"; + }; } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyHbmImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyHbmImpl.java index 53bcbd51c94a..70f190be3866 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyHbmImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyHbmImpl.java @@ -4,7 +4,7 @@ */ package org.hibernate.boot.model.naming; -import org.hibernate.internal.util.StringHelper; +import static org.hibernate.internal.util.StringHelper.unqualify; /** * Implements the original legacy naming behavior. @@ -19,7 +19,7 @@ public class ImplicitNamingStrategyLegacyHbmImpl extends ImplicitNamingStrategyJ @Override protected String transformEntityName(EntityNaming entityNaming) { - return StringHelper.unqualify( entityNaming.getEntityName() ); + return unqualify( entityNaming.getEntityName() ); } @Override @@ -37,21 +37,21 @@ public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) { source.getBuildingContext() ); } - - return super.determineJoinColumnName( source ); + else { + return super.determineJoinColumnName( source ); + } } - @Override public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) { if ( source.getAssociationOwningAttributePath() != null ) { final String name = source.getOwningPhysicalTableName() + '_' + transformAttributePath( source.getAssociationOwningAttributePath() ); - return toIdentifier( name, source.getBuildingContext() ); } - - return super.determineJoinTableName( source ); + else { + return super.determineJoinTableName( source ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyJpaImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyJpaImpl.java index 171bd66030de..11b0f065288f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyJpaImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyJpaImpl.java @@ -4,6 +4,8 @@ */ package org.hibernate.boot.model.naming; +import org.hibernate.boot.model.naming.ImplicitJoinColumnNameSource.Nature; + /** * Implementation of the ImplicitNamingStrategy contract which conforms to the * naming rules initially implemented by Hibernate for JPA 1.0, prior to many @@ -23,27 +25,22 @@ public class ImplicitNamingStrategyLegacyJpaImpl extends ImplicitNamingStrategyJ @Override public Identifier determineCollectionTableName(ImplicitCollectionTableNameSource source) { - Identifier identifier = toIdentifier( - source.getOwningPhysicalTableName().getText() + "_" + transformAttributePath( source.getOwningAttributePath() ), + final Identifier owningPhysicalTableName = source.getOwningPhysicalTableName(); + final Identifier identifier = toIdentifier( + owningPhysicalTableName.getText() + + "_" + transformAttributePath( source.getOwningAttributePath() ), source.getBuildingContext() ); - if ( source.getOwningPhysicalTableName().isQuoted() ) { - identifier = Identifier.quote( identifier ); - } - return identifier; + return owningPhysicalTableName.isQuoted() ? Identifier.quote( identifier ) : identifier; } @Override public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) { final String ownerPortion = source.getOwningPhysicalTableName(); - final String ownedPortion; - if ( source.getNonOwningPhysicalTableName() != null ) { - ownedPortion = source.getNonOwningPhysicalTableName(); - } - else { - ownedPortion = transformAttributePath( source.getAssociationOwningAttributePath() ); - } - + final String ownedPortion = + source.getNonOwningPhysicalTableName() == null + ? transformAttributePath( source.getAssociationOwningAttributePath() ) + : source.getNonOwningPhysicalTableName(); return toIdentifier( ownerPortion + "_" + ownedPortion, source.getBuildingContext() ); } @@ -54,10 +51,8 @@ public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) { // // The spec-compliant one implements the clarified {EntityName}_{ReferencedColumnName} // naming. Here we implement the older {TableName}_{ReferencedColumnName} naming - final String name; - -// if ( source.getNature() == ImplicitJoinColumnNameSource.Nature.ENTITY -// && source.getAttributePath() != null ) { +// final String name; +// if ( source.getNature() == Nature.ENTITY && source.getAttributePath() != null ) { // // many-to-one / one-to-one // // // // legacy naming used the attribute name here, following suit with legacy hbm naming @@ -65,19 +60,12 @@ public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) { // // NOTE : attribute path being null here would be an error, so for now don't bother checking // name = transformAttributePath( source.getAttributePath() ); // } -// else if ( source.getNature() == ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION - if ( source.getNature() == ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION - || source.getAttributePath() == null ) { - name = source.getReferencedTableName().getText() - + '_' - + source.getReferencedColumnName().getText(); - } - else { - name = transformAttributePath( source.getAttributePath() ) - + '_' - + source.getReferencedColumnName().getText(); - } - +// else if ( source.getNature() == Nature.ELEMENT_COLLECTION + final String qualifier = + source.getNature() == Nature.ELEMENT_COLLECTION || source.getAttributePath() == null + ? source.getReferencedTableName().getText() + : transformAttributePath( source.getAttributePath() ); + final String name = qualifier + '_' + source.getReferencedColumnName().getText(); return toIdentifier( name, source.getBuildingContext() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitUniqueKeyNameSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitUniqueKeyNameSource.java index 273b4c5f10bb..930309505d12 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitUniqueKeyNameSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitUniqueKeyNameSource.java @@ -7,6 +7,10 @@ /** * @author Steve Ebersole */ -public interface ImplicitUniqueKeyNameSource extends ImplicitConstraintNameSource { - +public non-sealed interface ImplicitUniqueKeyNameSource + extends ImplicitConstraintNameSource { + @Override + default Kind kind() { + return Kind.UNIQUE_KEY; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/AttributePath.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/AttributePath.java index 4df032796385..a046c88eef2d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/AttributePath.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/AttributePath.java @@ -4,7 +4,7 @@ */ package org.hibernate.boot.model.source.spi; -import org.hibernate.internal.util.StringHelper; +import static org.hibernate.internal.util.StringHelper.split; /** * An attribute path is, generally speaking, the path of attribute names back @@ -40,14 +40,15 @@ public AttributePath(AttributePath parent, String property) { } public static AttributePath parse(String path) { - if ( path == null ) { - return null; + if ( path != null ) { + AttributePath attributePath = new AttributePath(); + for ( String part : split( ".", path ) ) { + attributePath = attributePath.append( part ); + } + return attributePath; } - - AttributePath attributePath = new AttributePath(); - for ( String part : StringHelper.split( ".", path ) ) { - attributePath = attributePath.append( part ); + else { + return null; } - return attributePath; } }