diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java index cd5efebb21..1b34fddfc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java @@ -12,6 +12,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; @@ -20,6 +21,7 @@ import java.util.function.Consumer; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.FetchMode; +import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.annotations.AnyDiscriminatorValue; import org.hibernate.annotations.AnyDiscriminatorValues; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java index c22405753a..abf1cb8fd5 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java @@ -46,13 +46,10 @@ import org.hibernate.annotations.QueryCacheLayout; import org.hibernate.annotations.RowId; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLDeleteAll; -import org.hibernate.annotations.SQLDeletes; import org.hibernate.annotations.SQLInsert; -import org.hibernate.annotations.SQLInserts; import org.hibernate.annotations.SQLRestriction; import org.hibernate.annotations.SQLSelect; import org.hibernate.annotations.SQLUpdate; -import org.hibernate.annotations.SQLUpdates; import org.hibernate.annotations.SecondaryRow; import org.hibernate.annotations.SecondaryRows; import org.hibernate.annotations.SelectBeforeUpdate; @@ -147,7 +144,9 @@ import static org.hibernate.boot.model.internal.AnnotatedJoinColumn.buildInherit import static org.hibernate.boot.model.internal.BinderHelper.extractFromPackage; import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull; import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation; +import static org.hibernate.boot.model.internal.BinderHelper.getOverrideAnnotation; import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation; +import static org.hibernate.boot.model.internal.BinderHelper.overrideMatchesDialect; import static org.hibernate.boot.model.internal.BinderHelper.noConstraint; import static org.hibernate.boot.model.internal.BinderHelper.toAliasEntityMap; import static org.hibernate.boot.model.internal.BinderHelper.toAliasTableMap; @@ -167,6 +166,7 @@ import static org.hibernate.internal.util.StringHelper.isEmpty; import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.StringHelper.nullIfEmpty; import static org.hibernate.internal.util.StringHelper.unqualify; +import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty; import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY; @@ -1410,9 +1410,9 @@ public class EntityBinder { private void bindCustomSql() { final String primaryTableName = persistentClass.getTable().getName(); - AnnotationUsage sqlInsert = findMatchingSqlAnnotation( primaryTableName, SQLInsert.class, SQLInserts.class ); + AnnotationUsage sqlInsert = resolveCustomSqlAnnotation( annotatedClass, SQLInsert.class, primaryTableName ); if ( sqlInsert == null ) { - sqlInsert = findMatchingSqlAnnotation( "", SQLInsert.class, SQLInserts.class ); + sqlInsert = resolveCustomSqlAnnotation( annotatedClass, SQLInsert.class, "" ); } if ( sqlInsert != null ) { persistentClass.setCustomSQLInsert( @@ -1426,9 +1426,9 @@ public class EntityBinder { } } - AnnotationUsage sqlUpdate = findMatchingSqlAnnotation( primaryTableName, SQLUpdate.class, SQLUpdates.class ); + AnnotationUsage sqlUpdate = resolveCustomSqlAnnotation( annotatedClass, SQLUpdate.class, primaryTableName ); if ( sqlUpdate == null ) { - sqlUpdate = findMatchingSqlAnnotation( "", SQLUpdate.class, SQLUpdates.class ); + sqlUpdate = resolveCustomSqlAnnotation( annotatedClass, SQLUpdate.class, "" ); } if ( sqlUpdate != null ) { persistentClass.setCustomSQLUpdate( @@ -1442,9 +1442,9 @@ public class EntityBinder { } } - AnnotationUsage sqlDelete = findMatchingSqlAnnotation( primaryTableName, SQLDelete.class, SQLDeletes.class ); + AnnotationUsage sqlDelete = resolveCustomSqlAnnotation( annotatedClass, SQLDelete.class, primaryTableName ); if ( sqlDelete == null ) { - sqlDelete = findMatchingSqlAnnotation( "", SQLDelete.class, SQLDeletes.class ); + sqlDelete = resolveCustomSqlAnnotation( annotatedClass, SQLDelete.class, "" ); } if ( sqlDelete != null ) { persistentClass.setCustomSQLDelete( @@ -1458,7 +1458,7 @@ public class EntityBinder { } } - final AnnotationUsage sqlDeleteAll = annotatedClass.getAnnotationUsage( SQLDeleteAll.class ); + final AnnotationUsage sqlDeleteAll = resolveCustomSqlAnnotation( annotatedClass, SQLDeleteAll.class, "" ); if ( sqlDeleteAll != null ) { throw new AnnotationException("@SQLDeleteAll does not apply to entities: " + persistentClass.getEntityName()); @@ -1493,6 +1493,33 @@ public class EntityBinder { } } + private AnnotationUsage resolveCustomSqlAnnotation( + ClassDetails annotatedClass, + Class annotationType, + String tableName) { + final Class overrideAnnotation = getOverrideAnnotation( annotationType ); + final List> dialectOverrides = annotatedClass.getRepeatedAnnotationUsages( overrideAnnotation ); + if ( isNotEmpty( dialectOverrides ) ) { + for ( AnnotationUsage dialectOverride : dialectOverrides ) { + if ( !overrideMatchesDialect( dialectOverride, context.getMetadataCollector().getDatabase().getDialect() ) ) { + continue; + } + + final AnnotationUsage override = dialectOverride.getNestedUsage( "override" ); + if ( isEmpty( tableName ) + && isEmpty( override.getString( "table" ) ) ) { + return override; + } + else if ( isNotEmpty( tableName ) + && tableName.equals( override.getString( "table" ) ) ) { + return override; + } + } + } + + return annotatedClass.getNamedAnnotationUsage( annotationType, tableName, "table" ); + } + private void bindFilters() { for ( AnnotationUsage filter : filters ) { final String filterName = filter.getString( "name" ); @@ -2249,8 +2276,9 @@ public class EntityBinder { final String tableName = join.getTable().getQuotedName(); final AnnotationUsage matchingTable = findMatchingComplementaryTableAnnotation( tableName ); + final AnnotationUsage sqlInsert = - findMatchingSqlAnnotation( tableName, SQLInsert.class, SQLInserts.class ); + resolveCustomSqlAnnotation( annotatedClass, SQLInsert.class, tableName ); if ( sqlInsert != null ) { join.setCustomSQLInsert( sqlInsert.getString( "sql" ).trim(), @@ -2275,7 +2303,7 @@ public class EntityBinder { } final AnnotationUsage sqlUpdate = - findMatchingSqlAnnotation( tableName, SQLUpdate.class, SQLUpdates.class ); + resolveCustomSqlAnnotation( annotatedClass, SQLUpdate.class, tableName ); if ( sqlUpdate != null ) { join.setCustomSQLUpdate( sqlUpdate.getString( "sql" ).trim(), @@ -2300,7 +2328,7 @@ public class EntityBinder { } final AnnotationUsage sqlDelete = - findMatchingSqlAnnotation( tableName, SQLDelete.class, SQLDeletes.class ); + resolveCustomSqlAnnotation( annotatedClass, SQLDelete.class, tableName ); if ( sqlDelete != null ) { join.setCustomSQLDelete( sqlDelete.getString( "sql" ).trim(), diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java b/hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java index a3f41846ff..500a472893 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java @@ -203,6 +203,14 @@ public interface HibernateAnnotations { AnnotationDescriptor DIALECT_OVERRIDE_FILTER_DEFS = createOrmDescriptor( DialectOverride.FilterDefs.class, DIALECT_OVERRIDE_FILTER_DEF_OVERRIDES ); AnnotationDescriptor DIALECT_OVERRIDE_VERSION = createOrmDescriptor( DialectOverride.Version.class ); + AnnotationDescriptor DIALECT_OVERRIDE_SQL_INSERTS = createOrmDescriptor( DialectOverride.SQLInserts.class ); + AnnotationDescriptor DIALECT_OVERRIDE_SQL_INSERT = createOrmDescriptor( DialectOverride.SQLInsert.class, DIALECT_OVERRIDE_SQL_INSERTS ); + AnnotationDescriptor DIALECT_OVERRIDE_SQL_UPDATES = createOrmDescriptor( DialectOverride.SQLUpdates.class ); + AnnotationDescriptor DIALECT_OVERRIDE_SQL_UPDATE = createOrmDescriptor( DialectOverride.SQLUpdate.class, DIALECT_OVERRIDE_SQL_UPDATES ); + AnnotationDescriptor DIALECT_OVERRIDE_SQL_DELETES = createOrmDescriptor( DialectOverride.SQLDeletes.class ); + AnnotationDescriptor DIALECT_OVERRIDE_SQL_DELETE = createOrmDescriptor( DialectOverride.SQLDelete.class, DIALECT_OVERRIDE_SQL_DELETES ); + AnnotationDescriptor DIALECT_OVERRIDE_SQL_DELETE_ALLS = createOrmDescriptor( DialectOverride.SQLDeleteAlls.class ); + AnnotationDescriptor DIALECT_OVERRIDE_SQL_DELETE_ALL = createOrmDescriptor( DialectOverride.SQLDeleteAll.class, DIALECT_OVERRIDE_SQL_DELETE_ALLS ); static void forEachAnnotation(Consumer> consumer) { OrmAnnotationHelper.forEachOrmAnnotation( HibernateAnnotations.class, consumer );