diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/PartitionKey.java b/hibernate-core/src/main/java/org/hibernate/annotations/PartitionKey.java new file mode 100644 index 0000000000..86e8aa08ab --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/PartitionKey.java @@ -0,0 +1,25 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Identifies a field of an entity that holds the partition key of a table. + * + * @since 6.2 + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface PartitionKey { + +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java index a46e923408..ff892f3d62 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java @@ -28,6 +28,7 @@ import org.hibernate.annotations.CollectionIdJavaType; import org.hibernate.annotations.CollectionIdJdbcType; import org.hibernate.annotations.CollectionIdJdbcTypeCode; import org.hibernate.annotations.CollectionIdMutability; +import org.hibernate.annotations.PartitionKey; import org.hibernate.annotations.CollectionIdType; import org.hibernate.annotations.Immutable; import org.hibernate.annotations.JdbcTypeCode; @@ -148,6 +149,7 @@ public class BasicValueBinder implements JdbcTypeIndicators { private EnumType enumType; private TemporalType temporalPrecision; private TimeZoneStorageType timeZoneStorageType; + private boolean partitionKey; private Table table; private AnnotatedColumns columns; @@ -983,6 +985,10 @@ public class BasicValueBinder implements JdbcTypeIndicators { } } } + final PartitionKey partitionKey = attributeXProperty.getAnnotation( PartitionKey.class ); + if ( partitionKey != null ) { + this.partitionKey = true; + } } private static Class> normalizeUserType(Class> userType) { @@ -1103,6 +1109,8 @@ public class BasicValueBinder implements JdbcTypeIndicators { basicValue.setTimeZoneStorageType( timeZoneStorageType ); } + basicValue.setPartitionKey( partitionKey ); + if ( temporalPrecision != null ) { basicValue.setTemporalPrecision( temporalPrecision ); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java index 3d43c6afc8..d163dfdd04 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java @@ -1115,6 +1115,19 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl this.hasSubselectLoadableCollections = hasSubselectCollections; } + public boolean hasPartitionedSelectionMapping() { + if ( getSuperclass() != null && getSuperclass().hasPartitionedSelectionMapping() ) { + return true; + } + for ( Property property : getProperties() ) { + final Value value = property.getValue(); + if ( value instanceof BasicValue && ( (BasicValue) value ).isPartitionKey() ) { + return true; + } + } + return false; + } + public Component getIdentifierMapper() { return identifierMapper; } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index 7a26bf4fc8..bf945dbe6a 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -80,6 +80,7 @@ public abstract class SimpleValue implements KeyValue { private final List columns = new ArrayList<>(); private final List insertability = new ArrayList<>(); private final List updatability = new ArrayList<>(); + private boolean partitionKey; private String typeName; private Properties typeParameters; @@ -120,6 +121,7 @@ public abstract class SimpleValue implements KeyValue { this.columns.addAll( original.columns ); this.insertability.addAll( original.insertability ); this.updatability.addAll( original.updatability ); + this.partitionKey = original.partitionKey; this.typeName = original.typeName; this.typeParameters = original.typeParameters == null ? null : new Properties( original.typeParameters ); this.isVersion = original.isVersion; @@ -866,6 +868,14 @@ public abstract class SimpleValue implements KeyValue { return false; } + public boolean isPartitionKey() { + return partitionKey; + } + + public void setPartitionKey(boolean partitionColumn) { + this.partitionKey = partitionColumn; + } + private static boolean[] extractBooleansFromList(List list) { final boolean[] array = new boolean[ list.size() ]; int i = 0; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java index f9c603940d..7a42edd56b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java @@ -288,4 +288,9 @@ public abstract class AbstractCompositeIdentifierMapping return entityMapping; } + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicValuedModelPart.java index ca8f08ce81..cb19b26378 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicValuedModelPart.java @@ -51,4 +51,9 @@ public interface BasicValuedModelPart extends BasicValuedMapping, ValuedModelPar consumer.accept( 0, this ); return getJdbcTypeCount(); } + + @Override + default boolean hasPartitionedSelectionMapping() { + return isPartitioned(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java index d99adabb93..eb87aa6fe3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java @@ -101,4 +101,14 @@ public interface ManagedMappingType extends MappingType, FetchableContainer { } return false; } + + @Override + default boolean hasPartitionedSelectionMapping() { + for ( AttributeMapping attributeMapping : getAttributeMappings() ) { + if ( attributeMapping.hasPartitionedSelectionMapping() ) { + return true; + } + } + return false; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ModelPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ModelPart.java index c006f43095..4a1d94ae11 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ModelPart.java @@ -91,6 +91,8 @@ public interface ModelPart extends MappingModelExpressible { return false; } + boolean hasPartitionedSelectionMapping(); + /** * Create a DomainResult for a specific reference to this ModelPart. */ diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java index 51d416f570..c83db87009 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java @@ -104,6 +104,11 @@ public interface SelectableConsumer { return false; } + @Override + public boolean isPartitioned() { + return false; + } + @Override public String getColumnDefinition() { // we could probably use the details from `base`, but @@ -217,6 +222,11 @@ public interface SelectableConsumer { return true; } + @Override + public boolean isPartitioned() { + return false; + } + @Override public JdbcMapping getJdbcMapping() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableMapping.java index b94d448a4d..60ee98d152 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableMapping.java @@ -65,4 +65,6 @@ public interface SelectableMapping extends SqlTypedMapping { boolean isInsertable(); boolean isUpdateable(); + + boolean isPartitioned(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java index ef03371638..6d18b3ff16 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java @@ -61,6 +61,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, private final boolean insertable; private final boolean updateable; + private final boolean partitioned; private final MetaType metaType; public AnyDiscriminatorPart( @@ -74,6 +75,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, Integer scale, boolean insertable, boolean updateable, + boolean partitioned, MetaType metaType) { this.navigableRole = partRole; this.declaringType = declaringType; @@ -85,6 +87,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, this.scale = scale; this.insertable = insertable; this.updateable = updateable; + this.partitioned = partitioned; this.metaType = metaType; } @@ -126,6 +129,11 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, return updateable; } + @Override + public boolean isPartitioned() { + return partitioned; + } + @Override public String getCustomReadExpression() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java index 4ea793ebb9..84d223f10b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java @@ -56,6 +56,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { private final boolean nullable; private final boolean insertable; private final boolean updateable; + private final boolean partitioned; private final JdbcMapping jdbcMapping; public AnyKeyPart( @@ -70,6 +71,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { boolean nullable, boolean insertable, boolean updateable, + boolean partitioned, JdbcMapping jdbcMapping) { this.navigableRole = navigableRole; this.table = table; @@ -82,6 +84,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { this.nullable = nullable; this.insertable = insertable; this.updateable = updateable; + this.partitioned = partitioned; this.jdbcMapping = jdbcMapping; } @@ -115,6 +118,11 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { return updateable; } + @Override + public boolean isPartitioned() { + return partitioned; + } + @Override public String getCustomReadExpression() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java index b2722b752a..3737c64bef 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java @@ -63,6 +63,7 @@ public class BasicAttributeMapping private final boolean nullable; private final boolean insertable; private final boolean updateable; + private final boolean partitioned; private final JavaType domainTypeDescriptor; @@ -87,6 +88,7 @@ public class BasicAttributeMapping boolean nullable, boolean insertable, boolean updateable, + boolean partitioned, JdbcMapping jdbcMapping, ManagedMappingType declaringType, PropertyAccess propertyAccess) { @@ -117,6 +119,7 @@ public class BasicAttributeMapping this.nullable = nullable; this.insertable = insertable; this.updateable = updateable; + this.partitioned = partitioned; this.jdbcMapping = jdbcMapping; this.domainTypeDescriptor = jdbcMapping.getJavaTypeDescriptor(); @@ -175,6 +178,7 @@ public class BasicAttributeMapping selectableMapping.isNullable(), insertable, updateable, + selectableMapping.isPartitioned(), original.getJdbcMapping(), declaringType, propertyAccess @@ -231,6 +235,11 @@ public class BasicAttributeMapping return updateable; } + @Override + public boolean isPartitioned() { + return partitioned; + } + @Override public String getCustomReadExpression() { return customReadExpression; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java index 340a109d89..29ca9c0af5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java @@ -314,6 +314,16 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa return insertable; } + @Override + public boolean isPartitioned() { + return false; + } + + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public String getCustomReadExpression() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java index 8534ea73f7..9a9dfa0a71 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java @@ -98,6 +98,11 @@ public class BasicValuedCollectionPart return selectableMapping.isInsertable(); } + @Override + public boolean isPartitioned() { + return selectableMapping.isPartitioned(); + } + @Override public boolean isUpdateable() { return selectableMapping.isUpdateable(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CaseStatementDiscriminatorMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CaseStatementDiscriminatorMappingImpl.java index af13be0674..720e5cb399 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CaseStatementDiscriminatorMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CaseStatementDiscriminatorMappingImpl.java @@ -220,6 +220,16 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator return false; } + @Override + public boolean isPartitioned() { + return false; + } + + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public String getContainingTableExpression() { throw new UnsupportedOperationException(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java index 91997e0597..aa15eae881 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java @@ -89,6 +89,16 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD return false; } + @Override + public boolean isPartitioned() { + return false; + } + + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public boolean isNullable() { return false; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java index e5ffd0cf69..1e3f67c62f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java @@ -24,6 +24,7 @@ import org.hibernate.loader.ast.spi.MultiNaturalIdLoader; import org.hibernate.loader.ast.spi.NaturalIdLoader; import org.hibernate.mapping.IndexedConsumer; import org.hibernate.metamodel.UnsupportedMappingException; +import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMetadata; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; @@ -265,6 +266,16 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement return getJavaType(); } + @Override + public boolean hasPartitionedSelectionMapping() { + for ( AttributeMapping attributeMapping : attributes ) { + if ( attributeMapping.hasPartitionedSelectionMapping() ) { + return true; + } + } + return false; + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ModelPart diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java index da29591ea1..5bc7636c06 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java @@ -357,6 +357,12 @@ public class DiscriminatedAssociationAttributeMapping consumer.accept( getKeyPart() ); } + @Override + public boolean hasPartitionedSelectionMapping() { + return discriminatorMapping.getDiscriminatorPart().isPartitioned() + || discriminatorMapping.getKeyPart().isPartitioned(); + } + public static class MutabilityPlanImpl implements MutabilityPlan { // for now use the AnyType for consistency with write-operations private final AnyType anyType; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java index a1e5545ecf..7a233ff7d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java @@ -6,11 +6,8 @@ */ package org.hibernate.metamodel.mapping.internal; -import java.util.Arrays; -import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; -import java.util.List; import java.util.Locale; import java.util.Map; import java.util.function.Consumer; @@ -98,6 +95,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption metaColumn.getScale(), bootValueMapping.isColumnInsertable( 0 ), bootValueMapping.isColumnUpdateable( 0 ), + bootValueMapping.isPartitionKey(), (MetaType) anyType.getDiscriminatorType() ); @@ -115,6 +113,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption bootValueMapping.isNullable(), bootValueMapping.isColumnInsertable( 1 ), bootValueMapping.isColumnUpdateable( 1 ), + bootValueMapping.isPartitionKey(), keyType ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java index 9928527c64..4cf112f658 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java @@ -127,6 +127,12 @@ public class DiscriminatedCollectionPart implements DiscriminatedAssociationMode return discriminatorMapping; } + @Override + public boolean hasPartitionedSelectionMapping() { + return discriminatorMapping.getDiscriminatorPart().isPartitioned() + || discriminatorMapping.getKeyPart().isPartitioned(); + } + @Override public String toString() { return "DiscriminatedCollectionPart(" + getNavigableRole() + ")@" + System.identityHashCode( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java index 617d57cc53..642e8c50f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java @@ -203,6 +203,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme creationContext.getTypeConfiguration(), insertable, updatable, + false, dialect, null ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java index b5532c1100..21dbe50d10 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java @@ -214,6 +214,11 @@ public class EmbeddedAttributeMapping getEmbeddableTypeDescriptor().decompose( domainValue, valueConsumer, session ); } + @Override + public boolean hasPartitionedSelectionMapping() { + return getEmbeddableTypeDescriptor().hasPartitionedSelectionMapping(); + } + @Override public DomainResult createDomainResult( NavigablePath navigablePath, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java index 5f69d18b1a..5e3f77f98f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java @@ -355,4 +355,9 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF return FetchTiming.IMMEDIATE; } + @Override + public boolean hasPartitionedSelectionMapping() { + return getEmbeddableTypeDescriptor().hasPartitionedSelectionMapping(); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedForeignKeyDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedForeignKeyDescriptor.java index c1a19fd1d9..d9770f60ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedForeignKeyDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedForeignKeyDescriptor.java @@ -598,4 +598,9 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor { public Object disassemble(Object value, SharedSessionContractImplementor session) { return targetSide.getModelPart().disassemble( value, session ); } + + @Override + public boolean hasPartitionedSelectionMapping() { + return keySide.getModelPart().hasPartitionedSelectionMapping(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityRowIdMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityRowIdMappingImpl.java index 4bdd1a4513..49aaeda8c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityRowIdMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityRowIdMappingImpl.java @@ -76,6 +76,11 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping { return declaringType; } + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public DomainResult createDomainResult( NavigablePath navigablePath, @@ -205,6 +210,11 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping { return false; } + @Override + public boolean isPartitioned() { + return false; + } + @Override public JdbcMapping getJdbcMapping() { return rowIdType.getJdbcMapping(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java index 6b127466fd..5a7ffdeda1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java @@ -137,6 +137,16 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti return true; } + @Override + public boolean isPartitioned() { + return false; + } + + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public String getCustomReadExpression() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ExplicitColumnDiscriminatorMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ExplicitColumnDiscriminatorMappingImpl.java index 2e8f2eeba7..7173c51334 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ExplicitColumnDiscriminatorMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ExplicitColumnDiscriminatorMappingImpl.java @@ -132,6 +132,16 @@ public class ExplicitColumnDiscriminatorMappingImpl extends AbstractDiscriminato return false; } + @Override + public boolean isPartitioned() { + return false; + } + + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public boolean hasPhysicalColumn() { return isPhysical; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ManyToManyCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ManyToManyCollectionPart.java index 82cf15ff48..cb7b3ba1af 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ManyToManyCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ManyToManyCollectionPart.java @@ -255,6 +255,7 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple return join; } + @Override public LazyTableGroup createRootTableGroupJoin( NavigablePath navigablePath, TableGroup lhs, @@ -329,6 +330,11 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple return lazyTableGroup; } + @Override + public boolean hasPartitionedSelectionMapping() { + return foreignKey.hasPartitionedSelectionMapping(); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Initialization @@ -464,6 +470,7 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple creationProcess.getCreationContext().getTypeConfiguration(), true, false, + false, creationProcess.getCreationContext().getSessionFactory().getJdbcServices().getDialect(), creationProcess.getSqmFunctionRegistry() ); @@ -630,6 +637,7 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple creationProcess.getCreationContext().getTypeConfiguration(), columnInsertable, columnUpdateable, + ((SimpleValue) fkBootDescriptorSource).isPartitionKey(), dialect, creationProcess.getSqmFunctionRegistry() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java index 51feacb9e4..1c025205e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java @@ -17,7 +17,6 @@ import org.hibernate.FetchMode; import org.hibernate.MappingException; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.SharedSessionContract; -import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.collection.internal.StandardArraySemantics; import org.hibernate.collection.internal.StandardBagSemantics; import org.hibernate.collection.internal.StandardIdentifierBagSemantics; @@ -197,7 +196,7 @@ public class MappingModelCreationHelper { PropertyAccess propertyAccess, CascadeStyle cascadeStyle, MappingModelCreationProcess creationProcess) { - final Value value = bootProperty.getValue(); + final SimpleValue value = (SimpleValue) bootProperty.getValue(); final BasicValue.Resolution resolution = ( (Resolvable) value ).resolve(); SimpleAttributeMetadata attributeMetadata = new SimpleAttributeMetadata( propertyAccess, resolution.getMutabilityPlan(), bootProperty, value ); @@ -240,6 +239,7 @@ public class MappingModelCreationHelper { nullable, insertable, updateable, + value.isPartitionKey(), attrType, declaringType, propertyAccess @@ -430,6 +430,7 @@ public class MappingModelCreationHelper { creationProcess.getCreationContext().getTypeConfiguration(), index.isColumnInsertable( 0 ), index.isColumnUpdateable( 0 ), + false, dialect, creationProcess.getSqmFunctionRegistry() ); @@ -482,6 +483,7 @@ public class MappingModelCreationHelper { creationProcess.getCreationContext().getTypeConfiguration(), index.isColumnInsertable( 0 ), index.isColumnUpdateable( 0 ), + false, dialect, creationProcess.getSqmFunctionRegistry() ); @@ -685,6 +687,7 @@ public class MappingModelCreationHelper { creationProcess.getCreationContext().getTypeConfiguration(), bootValueMappingKey.isColumnInsertable( 0 ), bootValueMappingKey.isColumnUpdateable( 0 ), + false, dialect, creationProcess.getSqmFunctionRegistry() ); @@ -859,6 +862,7 @@ public class MappingModelCreationHelper { creationProcess.getCreationContext().getTypeConfiguration(), value.isColumnInsertable( i ), value.isColumnUpdateable( i ), + ((SimpleValue) value).isPartitionKey(), dialect, creationProcess.getSqmFunctionRegistry() ); @@ -873,6 +877,7 @@ public class MappingModelCreationHelper { creationProcess.getCreationContext().getTypeConfiguration(), value.isColumnInsertable( 0 ), value.isColumnUpdateable( 0 ), + ((SimpleValue) value).isPartitionKey(), dialect, creationProcess.getSqmFunctionRegistry() ); @@ -1181,6 +1186,7 @@ public class MappingModelCreationHelper { creationProcess.getCreationContext().getTypeConfiguration(), insertable, updatable, + false, dialect, creationProcess.getSqmFunctionRegistry() ); @@ -1280,6 +1286,7 @@ public class MappingModelCreationHelper { creationProcess.getCreationContext().getTypeConfiguration(), basicElement.isColumnInsertable( 0 ), basicElement.isColumnUpdateable( 0 ), + basicElement.isPartitionKey(), dialect, creationProcess.getSqmFunctionRegistry() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/OneToManyCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/OneToManyCollectionPart.java index b195cb4096..19d3fd2b30 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/OneToManyCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/OneToManyCollectionPart.java @@ -123,6 +123,11 @@ public class OneToManyCollectionPart extends AbstractEntityCollectionPart implem return fetchAssociationKey; } + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // TableGroupJoinProducer diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java index 095a5985bb..d67842239d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java @@ -361,6 +361,11 @@ public class PluralAttributeMappingImpl return fetchTiming; } + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public DomainResult createDomainResult( NavigablePath navigablePath, @@ -662,6 +667,7 @@ public class PluralAttributeMappingImpl return tableGroup; } + @Override public void setForeignKeyDescriptor(ForeignKeyDescriptor fkDescriptor) { this.fkDescriptor = fkDescriptor; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java index 3a44b201bb..b7bd17d1ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java @@ -31,6 +31,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select private final boolean nullable; private final boolean insertable; private final boolean updateable; + private final boolean partitioned; private final boolean isFormula; public SelectableMappingImpl( @@ -46,6 +47,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select boolean nullable, boolean insertable, boolean updateable, + boolean partitioned, boolean isFormula, JdbcMapping jdbcMapping) { super( columnDefinition, length, precision, scale, jdbcMapping ); @@ -59,6 +61,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select this.nullable = nullable; this.insertable = insertable; this.updateable = updateable; + this.partitioned = partitioned; this.isFormula = isFormula; } @@ -69,6 +72,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select final TypeConfiguration typeConfiguration, boolean insertable, boolean updateable, + boolean partitioned, final Dialect dialect, final SqmFunctionRegistry sqmFunctionRegistry) { return from( @@ -79,6 +83,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select typeConfiguration, insertable, updateable, + partitioned, dialect, sqmFunctionRegistry ); @@ -92,6 +97,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select final TypeConfiguration typeConfiguration, boolean insertable, boolean updateable, + boolean partitioned, final Dialect dialect, final SqmFunctionRegistry sqmFunctionRegistry) { return from( @@ -105,6 +111,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select typeConfiguration, insertable, updateable, + partitioned, dialect, sqmFunctionRegistry ); @@ -119,6 +126,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select final TypeConfiguration typeConfiguration, boolean insertable, boolean updateable, + boolean partitioned, final Dialect dialect, final SqmFunctionRegistry sqmFunctionRegistry) { final String columnExpression; @@ -160,6 +168,7 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select isNullable, insertable, updateable, + partitioned, selectable.isFormula(), jdbcMapping ); @@ -224,4 +233,9 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select public boolean isUpdateable() { return updateable; } + + @Override + public boolean isPartitioned() { + return partitioned; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingsImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingsImpl.java index 12e63ee190..55e8712066 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingsImpl.java @@ -90,6 +90,7 @@ public class SelectableMappingsImpl implements SelectableMappings { typeConfiguration, insertable[i], updateable[i], + false, dialect, sqmFunctionRegistry ); @@ -120,6 +121,7 @@ public class SelectableMappingsImpl implements SelectableMappings { typeConfiguration, false, false, + false, dialect, sqmFunctionRegistry ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java index f85d153106..d736e22ac2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java @@ -546,6 +546,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa return keySide.getModelPart().isUpdateable(); } + @Override + public boolean isPartitioned() { + return keySide.getModelPart().isPartitioned(); + } + @Override public String getCustomReadExpression() { return keySide.getModelPart().getCustomReadExpression(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java index 281da272ca..530cc64b25 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java @@ -276,4 +276,9 @@ public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements public AttributeMapping asAttributeMapping() { return getAttribute(); } + + @Override + public boolean hasPartitionedSelectionMapping() { + return attribute.hasPartitionedSelectionMapping(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java index 024778e247..c1378b2ad2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java @@ -716,6 +716,11 @@ public class ToOneAttributeMapping return canUseParentTableGroup; } + @Override + public boolean hasPartitionedSelectionMapping() { + return foreignKeyDescriptor.hasPartitionedSelectionMapping(); + } + public String getReferencedPropertyName() { return referencedPropertyName; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 71ad95c686..09914261a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -333,6 +333,7 @@ public abstract class AbstractEntityPersister private final boolean hasFormulaProperties; protected final int batchSize; private final boolean hasSubselectLoadableCollections; + private final boolean hasPartitionedSelectionMapping; protected final String rowIdName; // The optional SQL string defined in the where attribute @@ -505,6 +506,7 @@ public abstract class AbstractEntityPersister } batchSize = batch; hasSubselectLoadableCollections = bootDescriptor.hasSubselectLoadableCollections(); + hasPartitionedSelectionMapping = bootDescriptor.hasPartitionedSelectionMapping(); propertyMapping = new BasicEntityPropertyMapping( this ); @@ -5838,6 +5840,10 @@ public abstract class AbstractEntityPersister ); } + @Override + public boolean hasPartitionedSelectionMapping() { + return hasPartitionedSelectionMapping; + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Deprecations diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java index dd6bd409e8..892c6f58e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java @@ -10,7 +10,10 @@ import java.util.List; import org.hibernate.Internal; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.mutation.JdbcValueBindings; +import org.hibernate.engine.jdbc.mutation.ParameterUsage; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.persister.entity.AbstractEntityPersister; @@ -111,4 +114,32 @@ public abstract class AbstractMutationCoordinator { ); } ); } + + protected void bindPartitionColumnValueBindings( + Object[] loadedState, + SharedSessionContractImplementor session, + JdbcValueBindings jdbcValueBindings) { + if ( entityPersister().hasPartitionedSelectionMapping() ) { + entityPersister().forEachAttributeMapping( + (index, attributeMapping) -> { + if ( attributeMapping.hasPartitionedSelectionMapping() ) { + attributeMapping.decompose( + loadedState[index], + (value, jdbcValueMapping) -> { + if ( jdbcValueMapping.isPartitioned() ) { + jdbcValueBindings.bindValue( + value, + jdbcValueMapping, + ParameterUsage.RESTRICT, + session + ); + } + }, + session + ); + } + } + ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/DeleteCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/DeleteCoordinator.java index 1848c25727..36f3e0a472 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/DeleteCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/DeleteCoordinator.java @@ -79,7 +79,7 @@ public class DeleteCoordinator extends AbstractMutationCoordinator { doDynamicDelete( entity, id, rowId, loadedState, session ); } else { - doStaticDelete( entity, id, version, session ); + doStaticDelete( entity, id, entry == null ? null : entry.getLoadedState(), version, session ); } } @@ -253,6 +253,7 @@ public class DeleteCoordinator extends AbstractMutationCoordinator { protected void doStaticDelete( Object entity, Object id, + Object[] loadedState, Object version, SharedSessionContractImplementor session) { final MutationExecutorService mutationExecutorService = session @@ -287,6 +288,9 @@ public class DeleteCoordinator extends AbstractMutationCoordinator { if ( applyVersion ) { applyLocking( version, null, mutationExecutor, session ); } + final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings(); + + bindPartitionColumnValueBindings( loadedState, session, jdbcValueBindings ); applyId( id, null, mutationExecutor, staticOperationGroup, session ); @@ -365,8 +369,20 @@ public class DeleteCoordinator extends AbstractMutationCoordinator { if ( applyVersion ) { // apply any optimistic locking applyOptimisticLocking( deleteGroupBuilder, loadedState, session ); + if ( entityPersister().hasPartitionedSelectionMapping() ) { + entityPersister().forEachSelectable( + (selectionIndex, selectableMapping) -> { + if ( selectableMapping.isPartitioned() ) { + final String tableNameForMutation = + entityPersister().physicalTableNameForMutation( selectableMapping ); + final RestrictedTableMutationBuilder rootTableMutationBuilder = + deleteGroupBuilder.findTableDetailsBuilder( tableNameForMutation ); + rootTableMutationBuilder.addKeyRestrictionLeniently( selectableMapping ); + } + } + ); + } } - // todo (6.2) : apply where + where-fragments } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java index 8ccedfca47..4cbe44c037 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java @@ -331,6 +331,11 @@ public class EntityTableMapping implements TableMapping { return false; } + @Override + public boolean isPartitioned() { + return false; + } + @Override public String getColumnDefinition() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java index cfebe66798..e69aa212f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java @@ -298,6 +298,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple id, rowId, values, + incomingOldValues, valuesAnalysis, session ); @@ -625,6 +626,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple Object id, Object rowId, Object[] values, + Object[] oldValues, UpdateValuesAnalysisImpl valuesAnalysis, SharedSessionContractImplementor session) { final MutationExecutorService mutationExecutorService = session.getSessionFactory() @@ -648,6 +650,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple (position, attribute) -> true, session ); + bindPartitionColumnValueBindings( oldValues, session, mutationExecutor.getJdbcValueBindings() ); try { //noinspection SuspiciousMethodCalls @@ -836,6 +839,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple (attributeIndex, attribute) -> dirtinessChecker.include( attributeIndex, (SingularAttributeMapping) attribute ), session ); + bindPartitionColumnValueBindings( oldValues, session, mutationExecutor.getJdbcValueBindings() ); try { mutationExecutor.execute( @@ -1028,6 +1032,16 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple "?", keyColumn.getJdbcMapping() ) ); + + } + if ( entityPersister().hasPartitionedSelectionMapping() ) { + entityPersister().forEachSelectable( + (selectionIndex, selectableMapping) -> { + if ( selectableMapping.isPartitioned() ) { + tableUpdateBuilder.addKeyRestrictionLeniently( selectableMapping ); + } + } + ); } } ); } @@ -1429,6 +1443,15 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple } ); updateBuilder.addOptimisticLockRestriction( versionMapping ); + if ( entityPersister().hasPartitionedSelectionMapping() ) { + entityPersister().forEachSelectable( + (selectionIndex, selectableMapping) -> { + if ( selectableMapping.isPartitioned() ) { + updateBuilder.addKeyRestrictionLeniently( selectableMapping ); + } + } + ); + } final RestrictedTableMutation mutation = updateBuilder.buildMutation(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicValuedModelPart.java index 28ee17703a..b2040da5e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicValuedModelPart.java @@ -137,6 +137,16 @@ public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingTyp return false; } + @Override + public boolean isPartitioned() { + return false; + } + + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public String getColumnDefinition() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java index 6493c93ee3..79645d9188 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java @@ -360,6 +360,11 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued return null; } + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + @Override public DomainResult createDomainResult( NavigablePath navigablePath, diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleTableGroupProducer.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleTableGroupProducer.java index 0fddae54c4..aae1b04f8f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleTableGroupProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleTableGroupProducer.java @@ -346,6 +346,11 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map return offset - originalOffset; } + @Override + public boolean hasPartitionedSelectionMapping() { + return false; + } + //-------------------------------- // Support for using the anonymous tuple as table reference directly somewhere is not yet implemented //-------------------------------- diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/PartitionKeyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/PartitionKeyTests.java new file mode 100644 index 0000000000..a8ba554e83 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/PartitionKeyTests.java @@ -0,0 +1,111 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.orm.test.sql.partition; + +import org.hibernate.annotations.PartitionKey; + +import org.hibernate.testing.jdbc.SQLStatementInspector; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import static org.assertj.core.api.Assertions.assertThat; + +@DomainModel( annotatedClasses = PartitionKeyTests.PartitionedEntity.class ) +@SessionFactory( useCollectingStatementInspector = true ) +public class PartitionKeyTests { + @Test + public void test(SessionFactoryScope scope) { + final SQLStatementInspector inspector = scope.getCollectingStatementInspector(); + + // update + scope.inTransaction( (session) -> { + final PartitionedEntity entity = session.find( PartitionedEntity.class, 1 ); + inspector.clear(); + entity.setName( "The One" ); + } ); + checkWherePredicate( inspector ); + + // delete + scope.inTransaction( (session) -> { + final PartitionedEntity entity = session.find( PartitionedEntity.class, 1 ); + inspector.clear(); + session.remove( entity ); + } ); + checkWherePredicate( inspector ); + } + + private void checkWherePredicate(SQLStatementInspector inspector) { + assertThat( inspector.getSqlQueries() ).hasSize( 1 ); + assertThat( inspector.getSqlQueries().get( 0 ) ).contains( "tenant_id=?" ); + } + + @BeforeEach + public void prepareTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + session.persist( new PartitionedEntity( 1, 1, "tbd" ) ); + } ); + } + + @AfterEach + public void dropTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + session.createMutationQuery( "delete PartitionedEntity" ).executeUpdate(); + } ); + } + + @Entity( name = "PartitionedEntity" ) + @Table( name = "entity_table" ) + public static class PartitionedEntity { + @Id + private Integer id; + @PartitionKey + @Column(name = "tenant_id", updatable = false) + private Integer tenantId; + @Basic + private String name; + + protected PartitionedEntity() { + // for use by Hibernate + } + + public PartitionedEntity(Integer id, Integer tenantId, String name) { + this.id = id; + this.tenantId = tenantId; + this.name = name; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getTenantId() { + return tenantId; + } + + public void setTenantId(Integer tenantId) { + this.tenantId = tenantId; + } + } +}