HHH-16900 Rework mutation group API

This commit is contained in:
Sanne Grinovero 2023-07-04 13:49:05 +01:00 committed by Sanne Grinovero
parent b1dd13a407
commit fa677f3d62
12 changed files with 144 additions and 89 deletions

View File

@ -70,7 +70,7 @@ public class MutationExecutorPostInsert implements MutationExecutor, JdbcValueBi
);
this.mutationOperationGroup = mutationOperationGroup;
final PreparableMutationOperation identityInsertOperation = mutationOperationGroup.getOperation( mutationTarget.getIdentifierTableName() );
final PreparableMutationOperation identityInsertOperation = (PreparableMutationOperation) mutationOperationGroup.getOperation( mutationTarget.getIdentifierTableName() );
this.identityInsertStatementDetails = ModelMutationHelper.identityPreparation(
identityInsertOperation,
session
@ -78,9 +78,8 @@ public class MutationExecutorPostInsert implements MutationExecutor, JdbcValueBi
List<PreparableMutationOperation> secondaryTableMutations = null;
final List<MutationOperation> operations = mutationOperationGroup.getOperations();
for ( int i = 0; i < operations.size(); i++ ) {
final MutationOperation operation = operations.get( i );
for ( int i = 0; i < mutationOperationGroup.getNumberOfOperations(); i++ ) {
final MutationOperation operation = mutationOperationGroup.getOperation( i );
if ( operation.getTableDetails().isIdentifierTable() ) {
// the identifier table is handled via `identityInsertStatementDetails`

View File

@ -58,7 +58,7 @@ public class MutationExecutorPostInsertSingleTable implements MutationExecutor,
assert mutationOperationGroup.getNumberOfOperations() == 1;
this.operation = mutationOperationGroup.getOperation( mutationTarget.getIdentifierTableName() );
this.operation = (PreparableMutationOperation) mutationOperationGroup.getOperation( mutationTarget.getIdentifierTableName() );
this.identityInsertStatementDetails = identityPreparation( operation, session );
this.valueBindings = new JdbcValueBindingsImpl(

View File

@ -11,7 +11,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
@ -23,7 +22,6 @@ import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
import org.hibernate.engine.jdbc.mutation.spi.BatchKeyAccess;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.sql.model.PreparableMutationOperation;
@ -79,12 +77,10 @@ public class MutationExecutorStandard extends AbstractMutationExecutor implement
List<PreparableMutationOperation> nonBatchedJdbcMutations = null;
List<SelfExecutingUpdateOperation> selfExecutingMutations = null;
final List<MutationOperation> operations = mutationOperationGroup.getOperations();
boolean hasAnyNonBatchedJdbcOperations = false;
for ( int i = operations.size() - 1; i >= 0; i-- ) {
final MutationOperation operation = operations.get( i );
for ( int i = mutationOperationGroup.getNumberOfOperations() - 1; i >= 0; i-- ) {
final MutationOperation operation = mutationOperationGroup.getOperation( i );
if ( operation instanceof SelfExecutingUpdateOperation ) {
final SelfExecutingUpdateOperation selfExecutingMutation = (SelfExecutingUpdateOperation) operation;
if ( selfExecutingMutations == null ) {

View File

@ -260,6 +260,7 @@ import org.hibernate.sql.ast.tree.select.SelectClause;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.sql.exec.spi.JdbcParametersList;
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.sql.model.ast.builder.MutationGroupBuilder;
import org.hibernate.sql.results.graph.DomainResult;
@ -2908,25 +2909,41 @@ public abstract class AbstractEntityPersister
LOG.debugf( " Version select: %s", sqlVersionSelectString );
}
if ( insertCoordinator.getStaticInsertGroup() != null ) {
insertCoordinator.getStaticInsertGroup().forEachOperation( (tablePosition, mutation) -> {
if ( mutation instanceof JdbcOperation ) {
LOG.debugf( " Insert (%s): %s", tablePosition, ( (JdbcOperation) mutation ).getSqlString() );
{
final MutationOperationGroup staticInsertGroup = insertCoordinator.getStaticInsertGroup();
if ( staticInsertGroup != null ) {
for ( int i = 0; i < staticInsertGroup.getNumberOfOperations(); i++ ) {
final MutationOperation mutation = staticInsertGroup.getOperation( i );
if ( mutation instanceof JdbcOperation ) {
LOG.debugf( " Insert (%s): %s", i, ( (JdbcOperation) mutation ).getSqlString() );
}
}
} );
}
}
updateCoordinator.getStaticUpdateGroup().forEachOperation( (tablePosition, mutation) -> {
if ( mutation instanceof JdbcOperation ) {
LOG.debugf( " Update (%s): %s", tablePosition, ( (JdbcOperation) mutation ).getSqlString() );
{
final MutationOperationGroup staticUpdateGroup = updateCoordinator.getStaticUpdateGroup();
if ( staticUpdateGroup != null ) {
for ( int i = 0; i < staticUpdateGroup.getNumberOfOperations(); i++ ) {
final MutationOperation mutation = staticUpdateGroup.getOperation( i );
if ( mutation instanceof JdbcOperation ) {
LOG.debugf( " Update (%s): %s", i, ( (JdbcOperation) mutation ).getSqlString() );
}
}
}
} );
}
deleteCoordinator.getStaticDeleteGroup().forEachOperation( (tablePosition, mutation) -> {
if ( mutation instanceof JdbcOperation ) {
LOG.debugf( " Delete (%s): %s", tablePosition, ( (JdbcOperation) mutation ).getSqlString() );
{
final MutationOperationGroup staticDeleteGroup = deleteCoordinator.getStaticDeleteGroup();
if ( staticDeleteGroup != null ) {
for ( int i = 0; i < staticDeleteGroup.getNumberOfOperations(); i++ ) {
final MutationOperation mutation = staticDeleteGroup.getOperation( i );
if ( mutation instanceof JdbcOperation ) {
LOG.debugf( " Delete (%s): %s", i, ( (JdbcOperation) mutation ).getSqlString() );
}
}
}
} );
}
}
}
@ -6052,12 +6069,14 @@ public abstract class AbstractEntityPersister
}
private String[] extractSqlStrings(MutationOperationGroup operationGroup) {
final String[] strings = new String[operationGroup.getNumberOfOperations()];
operationGroup.forEachOperation( (tableIndex, mutation) -> {
if ( mutation instanceof JdbcOperation ) {
strings[tableIndex] = ( (JdbcOperation) mutation ).getSqlString();
final int numberOfOperations = operationGroup.getNumberOfOperations();
final String[] strings = new String[numberOfOperations];
for ( int i = 0; i < numberOfOperations; i++ ) {
final MutationOperation operation = operationGroup.getOperation( i );
if ( operation instanceof JdbcOperation ) {
strings[i] = ( (JdbcOperation) operation ).getSqlString();
}
} );
}
return strings;
}

View File

@ -32,6 +32,7 @@ import org.hibernate.sql.model.ast.builder.MutationGroupBuilder;
import org.hibernate.sql.model.internal.MutationOperationGroupNone;
import org.hibernate.sql.model.internal.MutationOperationGroupSingle;
import org.hibernate.sql.model.internal.MutationOperationGroupStandard;
import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
@ -91,7 +92,7 @@ public abstract class AbstractMutationCoordinator {
.createMutationOperation( valuesAnalysis, factory() );
return operation == null
? new MutationOperationGroupNone( mutationGroup )
: new MutationOperationGroupSingle( mutationGroup, operation );
: new MutationOperationGroupSingle( mutationGroup, (JdbcMutationOperation) operation );
}
default: {
final List<MutationOperation> operations = arrayList( numberOfTableMutations );

View File

@ -23,6 +23,7 @@ import org.hibernate.metamodel.mapping.EntityRowIdMapping;
import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.sql.model.MutationType;
import org.hibernate.sql.model.ast.ColumnValueBinding;
@ -99,12 +100,13 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
final MutationExecutor mutationExecutor = executor( session, operationGroup );
operationGroup.forEachOperation( (position, mutation) -> {
for ( int i = 0; i < operationGroup.getNumberOfOperations(); i++ ) {
final MutationOperation mutation = operationGroup.getOperation( i );
if ( mutation != null ) {
final String tableName = mutation.getTableDetails().getTableName();
mutationExecutor.getPreparedStatementDetails( tableName );
}
} );
}
applyLocking( null, loadedState, mutationExecutor, session );
@ -215,10 +217,12 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
MutationExecutor mutationExecutor,
MutationOperationGroup operationGroup,
SharedSessionContractImplementor session) {
final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings();
final EntityRowIdMapping rowIdMapping = entityPersister().getRowIdMapping();
operationGroup.forEachOperation( (position, jdbcMutation) -> {
for ( int position = 0; position < operationGroup.getNumberOfOperations(); position++ ) {
final MutationOperation jdbcMutation = operationGroup.getOperation( position );
final EntityTableMapping tableDetails = (EntityTableMapping) jdbcMutation.getTableDetails();
breakDownIdJdbcValues( id, rowId, session, jdbcValueBindings, rowIdMapping, tableDetails );
final PreparedStatementDetails statementDetails = mutationExecutor.getPreparedStatementDetails( tableDetails.getTableName() );
@ -227,7 +231,7 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
//noinspection resource
statementDetails.resolveStatement();
}
} );
}
}
private static void breakDownIdJdbcValues(
@ -281,11 +285,12 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
final MutationExecutor mutationExecutor = executor( session, operationGroupToUse );
staticOperationGroup.forEachOperation( (position, mutation) -> {
for ( int position = 0; position < staticOperationGroup.getNumberOfOperations(); position++ ) {
final MutationOperation mutation = staticOperationGroup.getOperation( position );
if ( mutation != null ) {
mutationExecutor.getPreparedStatementDetails( mutation.getTableDetails().getTableName() );
}
} );
}
if ( applyVersion ) {
applyLocking( version, null, mutationExecutor, session );

View File

@ -28,6 +28,7 @@ import org.hibernate.metamodel.mapping.AttributeMappingsList;
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.sql.model.MutationType;
import org.hibernate.sql.model.TableMapping;
@ -196,22 +197,25 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
TableInclusionChecker tableInclusionChecker,
SharedSessionContractImplementor session) {
final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings();
final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings();
mutationGroup.forEachOperation( (position, operation) -> {
for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) {
final MutationOperation operation = mutationGroup.getOperation( position );
final EntityTableMapping tableDetails = (EntityTableMapping) operation.getTableDetails();
if ( tableInclusionChecker.include( tableDetails ) ) {
final int[] attributeIndexes = tableDetails.getAttributeIndexes();
for ( int i = 0; i < attributeIndexes.length; i++ ) {
final int attributeIndex = attributeIndexes[ i ];
if ( propertyInclusions[attributeIndex] ) {
final AttributeMapping mapping = entityPersister().getAttributeMappings().get( attributeIndex );
final AttributeMapping mapping = attributeMappings.get( attributeIndex );
decomposeAttribute( values[attributeIndex], session, jdbcValueBindings, mapping );
}
}
}
} );
}
mutationGroup.forEachOperation( (position, jdbcOperation) -> {
for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) {
final MutationOperation jdbcOperation = mutationGroup.getOperation( position );
if ( id == null ) {
assert entityPersister().getIdentityInsertDelegate() != null;
}
@ -219,7 +223,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
final EntityTableMapping tableDetails = (EntityTableMapping) jdbcOperation.getTableDetails();
breakDownJdbcValue( id, session, jdbcValueBindings, tableDetails );
}
} );
}
}
protected void breakDownJdbcValue(

View File

@ -800,7 +800,8 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings();
// apply values
jdbcOperationGroup.forEachOperation( (position, operation) -> {
for ( int position = 0; position < jdbcOperationGroup.getNumberOfOperations(); position++ ) {
final MutationOperation operation = jdbcOperationGroup.getOperation( position );
final EntityTableMapping tableMapping = (EntityTableMapping) operation.getTableDetails();
if ( valuesAnalysis.tablesNeedingUpdate.contains( tableMapping ) ) {
final int[] attributeIndexes = tableMapping.getAttributeIndexes();
@ -816,13 +817,14 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
);
}
}
} );
}
// apply keys
jdbcOperationGroup.forEachOperation( (position, operation) -> {
for ( int position = 0; position < jdbcOperationGroup.getNumberOfOperations(); position++ ) {
final MutationOperation operation = jdbcOperationGroup.getOperation( position );
final EntityTableMapping tableMapping = (EntityTableMapping) operation.getTableDetails();
breakDownKeyJdbcValues( id, rowId, session, jdbcValueBindings, tableMapping );
} );
}
}
private void decomposeAttributeForUpdate(

View File

@ -17,6 +17,7 @@ import java.util.function.BiFunction;
* @author Steve Ebersole
*/
public interface MutationOperationGroup {
/**
* The type of mutation (at the model-level) represented by this group.
*/
@ -37,22 +38,41 @@ public interface MutationOperationGroup {
*
* Throws an exception if there are more than one.
*/
<O extends MutationOperation> O getSingleOperation();
MutationOperation getSingleOperation();
<O extends MutationOperation> List<O> getOperations();
/**
* Gets a specific MutationOperation from the group
* @param idx the index, starting from zero.
* @return
*/
MutationOperation getOperation(int idx);
/**
* Get the operation for a specific table.
*/
<O extends MutationOperation> O getOperation(String tableName);
MutationOperation getOperation(String tableName);
/**
* @deprecated Will be removed - use a combination of {@link #getNumberOfOperations()} and {@link #getOperation(int)}
* to iterate the list of operations.
*/
@Deprecated(forRemoval = true)
List<MutationOperation> getOperations();
/**
* Visit each operation
* @deprecated Will be removed - use a combination of {@link #getNumberOfOperations()} and {@link #getOperation(int)}
* to iterate the list of operations.
*/
<O extends MutationOperation> void forEachOperation(BiConsumer<Integer, O> action);
@Deprecated(forRemoval = true)
void forEachOperation(BiConsumer<Integer, MutationOperation> action);
/**
* Test whether any operations match the condition
* @deprecated Will be removed - use a combination of {@link #getNumberOfOperations()} and {@link #getOperation(int)}
* to iterate the list of operations.
*/
<O extends MutationOperation> boolean hasMatching(BiFunction<Integer, O, Boolean> matcher);
@Deprecated(forRemoval = true)
boolean hasMatching(BiFunction<Integer, MutationOperation, Boolean> matcher);
}

View File

@ -35,26 +35,32 @@ public class MutationOperationGroupNone extends AbstractMutationOperationGroup {
}
@Override
public <O extends MutationOperation> O getSingleOperation() {
public MutationOperation getSingleOperation() {
return null;
}
@Override
public <O extends MutationOperation> List<O> getOperations() {
public MutationOperation getOperation(int idx) {
throw new IndexOutOfBoundsException( idx );
}
@Override
public List<MutationOperation> getOperations() {
return Collections.emptyList();
}
@Override
public <O extends MutationOperation> O getOperation(String tableName) {
public MutationOperation getOperation(String tableName) {
return null;
}
@Override
public <O extends MutationOperation> void forEachOperation(BiConsumer<Integer, O> action) {
public void forEachOperation(BiConsumer<Integer, MutationOperation> action) {
}
@Override
public <O extends MutationOperation> boolean hasMatching(BiFunction<Integer, O, Boolean> matcher) {
public boolean hasMatching(BiFunction<Integer, MutationOperation, Boolean> matcher) {
return false;
}
}

View File

@ -15,6 +15,7 @@ import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationTarget;
import org.hibernate.sql.model.MutationType;
import org.hibernate.sql.model.ast.MutationGroup;
import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
@ -22,14 +23,15 @@ import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER
* @author Steve Ebersole
*/
public class MutationOperationGroupSingle extends AbstractMutationOperationGroup {
private final MutationOperation operation;
public MutationOperationGroupSingle(MutationType mutationType, MutationTarget<?> mutationTarget, MutationOperation operation) {
private final JdbcMutationOperation operation;
public MutationOperationGroupSingle(MutationType mutationType, MutationTarget<?> mutationTarget, JdbcMutationOperation operation) {
super( mutationType, mutationTarget );
this.operation = operation;
}
public MutationOperationGroupSingle(MutationGroup mutationGroup, MutationOperation operation) {
public MutationOperationGroupSingle(MutationGroup mutationGroup, JdbcMutationOperation operation) {
this( mutationGroup.getMutationType(), mutationGroup.getMutationTarget(), operation );
}
@ -39,19 +41,23 @@ public class MutationOperationGroupSingle extends AbstractMutationOperationGroup
}
@Override
public <O extends MutationOperation> O getSingleOperation() {
//noinspection unchecked
return (O) operation;
public JdbcMutationOperation getSingleOperation() {
return operation;
}
@Override
public <O extends MutationOperation> List<O> getOperations() {
//noinspection unchecked
return Collections.singletonList( (O) operation );
public MutationOperation getOperation(int idx) {
if ( idx != 0 ) throw new IndexOutOfBoundsException( idx );
return operation;
}
@Override
public <O extends MutationOperation> O getOperation(String tableName) {
public List<MutationOperation> getOperations() {
return Collections.singletonList( operation );
}
@Override
public MutationOperation getOperation(String tableName) {
if ( !tableName.equals( operation.getTableDetails().getTableName() ) ) {
MODEL_MUTATION_LOGGER.debugf(
"Unexpected table name mismatch : `%s` - `%s`",
@ -60,19 +66,17 @@ public class MutationOperationGroupSingle extends AbstractMutationOperationGroup
);
}
//noinspection unchecked
return (O) operation;
return operation;
}
@Override
public <O extends MutationOperation> void forEachOperation(BiConsumer<Integer, O> action) {
//noinspection unchecked
action.accept( 0, (O) operation );
public void forEachOperation(BiConsumer<Integer, MutationOperation> action) {
action.accept( 0, operation );
}
@Override
public <O extends MutationOperation> boolean hasMatching(BiFunction<Integer, O, Boolean> matcher) {
//noinspection unchecked
return matcher.apply( 0, (O) operation );
public boolean hasMatching(BiFunction<Integer, MutationOperation, Boolean> matcher) {
return matcher.apply( 0, operation );
}
}

View File

@ -32,10 +32,9 @@ public class MutationOperationGroupStandard extends AbstractMutationOperationGro
}
@Override
public <O extends MutationOperation> O getSingleOperation() {
public MutationOperation getSingleOperation() {
if ( operations.size() == 1 ) {
//noinspection unchecked
return (O) operations.get( 0 );
return operations.get( 0 );
}
throw new IllegalStateException(
String.format(
@ -47,38 +46,38 @@ public class MutationOperationGroupStandard extends AbstractMutationOperationGro
);
}
@SuppressWarnings("unchecked")
@Override
public <O extends MutationOperation> List<O> getOperations() {
//noinspection rawtypes
return (List) operations;
public MutationOperation getOperation(int idx) {
return operations.get( idx );
}
@SuppressWarnings("unchecked")
@Override
public <O extends MutationOperation> O getOperation(String tableName) {
public List<MutationOperation> getOperations() {
return operations;
}
@Override
public MutationOperation getOperation(String tableName) {
for ( int i = 0; i < operations.size(); i++ ) {
final MutationOperation operation = operations.get( i );
if ( operation.getTableDetails().getTableName().equals( tableName ) ) {
return (O) operation;
return operation;
}
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public <O extends MutationOperation> void forEachOperation(BiConsumer<Integer, O> action) {
public void forEachOperation(BiConsumer<Integer, MutationOperation> action) {
for ( int i = 0; i < operations.size(); i++ ) {
action.accept( i, (O) operations.get( i ) );
action.accept( i, operations.get( i ) );
}
}
@SuppressWarnings("unchecked")
@Override
public <O extends MutationOperation> boolean hasMatching(BiFunction<Integer, O, Boolean> matcher) {
public boolean hasMatching(BiFunction<Integer, MutationOperation, Boolean> matcher) {
for ( int i = 0; i < operations.size(); i++ ) {
if ( matcher.apply( i, (O) operations.get( i ) ) ) {
if ( matcher.apply( i, operations.get( i ) ) ) {
return true;
}
}