HHH-15899 Add @PartitionColumn annotation

This commit is contained in:
Christian Beikov 2022-12-20 22:45:58 +01:00
parent fb840ef84f
commit 50db219047
46 changed files with 494 additions and 7 deletions

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 {
}

View File

@ -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<? extends UserType<?>> normalizeUserType(Class<? extends UserType<?>> userType) {
@ -1103,6 +1109,8 @@ public class BasicValueBinder implements JdbcTypeIndicators {
basicValue.setTimeZoneStorageType( timeZoneStorageType );
}
basicValue.setPartitionKey( partitionKey );
if ( temporalPrecision != null ) {
basicValue.setTemporalPrecision( temporalPrecision );
}

View File

@ -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;
}

View File

@ -80,6 +80,7 @@ public abstract class SimpleValue implements KeyValue {
private final List<Selectable> columns = new ArrayList<>();
private final List<Boolean> insertability = new ArrayList<>();
private final List<Boolean> 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<Boolean> list) {
final boolean[] array = new boolean[ list.size() ];
int i = 0;

View File

@ -288,4 +288,9 @@ public abstract class AbstractCompositeIdentifierMapping
return entityMapping;
}
@Override
public boolean hasPartitionedSelectionMapping() {
return false;
}
}

View File

@ -51,4 +51,9 @@ public interface BasicValuedModelPart extends BasicValuedMapping, ValuedModelPar
consumer.accept( 0, this );
return getJdbcTypeCount();
}
@Override
default boolean hasPartitionedSelectionMapping() {
return isPartitioned();
}
}

View File

@ -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;
}
}

View File

@ -91,6 +91,8 @@ public interface ModelPart extends MappingModelExpressible {
return false;
}
boolean hasPartitionedSelectionMapping();
/**
* Create a DomainResult for a specific reference to this ModelPart.
*/

View File

@ -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;

View File

@ -65,4 +65,6 @@ public interface SelectableMapping extends SqlTypedMapping {
boolean isInsertable();
boolean isUpdateable();
boolean isPartitioned();
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -98,6 +98,11 @@ public class BasicValuedCollectionPart
return selectableMapping.isInsertable();
}
@Override
public boolean isPartitioned() {
return selectableMapping.isPartitioned();
}
@Override
public boolean isUpdateable() {
return selectableMapping.isUpdateable();

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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<Object> {
// for now use the AnyType for consistency with write-operations
private final AnyType anyType;

View File

@ -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
);

View File

@ -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 );

View File

@ -203,6 +203,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
creationContext.getTypeConfiguration(),
insertable,
updatable,
false,
dialect,
null
);

View File

@ -214,6 +214,11 @@ public class EmbeddedAttributeMapping
getEmbeddableTypeDescriptor().decompose( domainValue, valueConsumer, session );
}
@Override
public boolean hasPartitionedSelectionMapping() {
return getEmbeddableTypeDescriptor().hasPartitionedSelectionMapping();
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,

View File

@ -355,4 +355,9 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
return FetchTiming.IMMEDIATE;
}
@Override
public boolean hasPartitionedSelectionMapping() {
return getEmbeddableTypeDescriptor().hasPartitionedSelectionMapping();
}
}

View File

@ -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();
}
}

View File

@ -76,6 +76,11 @@ public class EntityRowIdMappingImpl implements EntityRowIdMapping {
return declaringType;
}
@Override
public boolean hasPartitionedSelectionMapping() {
return false;
}
@Override
public <T> DomainResult<T> 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();

View File

@ -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;

View File

@ -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;

View File

@ -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()
);

View File

@ -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()
);

View File

@ -123,6 +123,11 @@ public class OneToManyCollectionPart extends AbstractEntityCollectionPart implem
return fetchAssociationKey;
}
@Override
public boolean hasPartitionedSelectionMapping() {
return false;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// TableGroupJoinProducer

View File

@ -361,6 +361,11 @@ public class PluralAttributeMappingImpl
return fetchTiming;
}
@Override
public boolean hasPartitionedSelectionMapping() {
return false;
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
@ -662,6 +667,7 @@ public class PluralAttributeMappingImpl
return tableGroup;
}
@Override
public void setForeignKeyDescriptor(ForeignKeyDescriptor fkDescriptor) {
this.fkDescriptor = fkDescriptor;
}

View File

@ -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;
}
}

View File

@ -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
);

View File

@ -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();

View File

@ -276,4 +276,9 @@ public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping implements
public AttributeMapping asAttributeMapping() {
return getAttribute();
}
@Override
public boolean hasPartitionedSelectionMapping() {
return attribute.hasPartitionedSelectionMapping();
}
}

View File

@ -716,6 +716,11 @@ public class ToOneAttributeMapping
return canUseParentTableGroup;
}
@Override
public boolean hasPartitionedSelectionMapping() {
return foreignKeyDescriptor.hasPartitionedSelectionMapping();
}
public String getReferencedPropertyName() {
return referencedPropertyName;
}

View File

@ -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

View File

@ -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
);
}
}
);
}
}
}

View File

@ -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
}

View File

@ -331,6 +331,11 @@ public class EntityTableMapping implements TableMapping {
return false;
}
@Override
public boolean isPartitioned() {
return false;
}
@Override
public String getColumnDefinition() {
return null;

View File

@ -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<MutationOperation> mutation = updateBuilder.buildMutation();

View File

@ -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;

View File

@ -360,6 +360,11 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued
return null;
}
@Override
public boolean hasPartitionedSelectionMapping() {
return false;
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,

View File

@ -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
//--------------------------------

View File

@ -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;
}
}
}