Skip to content

Commit 5e84912

Browse files
committed
HHH-19640 update-generated fields and forced version increments
When an entity has fields generated on update, we have to include them in the UPDATE statement even for a "forced" version increment. So we must skip an optimization.
1 parent 8e4bae4 commit 5e84912

File tree

1 file changed

+61
-46
lines changed

1 file changed

+61
-46
lines changed

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,16 @@ public GeneratedValues update(
169169
SharedSessionContractImplementor session) {
170170
final EntityVersionMapping versionMapping = entityPersister().getVersionMapping();
171171
if ( versionMapping != null ) {
172-
final Supplier<GeneratedValues> generatedValuesAccess = handlePotentialImplicitForcedVersionIncrement(
173-
entity,
174-
id,
175-
values,
176-
oldVersion,
177-
incomingDirtyAttributeIndexes,
178-
session,
179-
versionMapping
180-
);
172+
final var generatedValuesAccess =
173+
handlePotentialImplicitForcedVersionIncrement(
174+
entity,
175+
id,
176+
values,
177+
oldVersion,
178+
incomingDirtyAttributeIndexes,
179+
session,
180+
versionMapping
181+
);
181182
if ( generatedValuesAccess != null ) {
182183
return generatedValuesAccess.get();
183184
}
@@ -389,57 +390,71 @@ protected Supplier<GeneratedValues> handlePotentialImplicitForcedVersionIncremen
389390
int[] incomingDirtyAttributeIndexes,
390391
SharedSessionContractImplementor session,
391392
EntityVersionMapping versionMapping) {
392-
// handle case where the only value being updated is the version.
393-
// we handle this case specially from `#coordinateUpdate` to leverage
394-
// `#doVersionUpdate`
395-
final boolean isSimpleVersionUpdate;
393+
// Handle a case where the only value being updated is the version.
394+
// We treat this case specially in `#coordinateUpdate` to leverage
395+
// `#doVersionUpdate`.
396396
final Object newVersion;
397-
398-
if ( incomingDirtyAttributeIndexes != null ) {
399-
if ( incomingDirtyAttributeIndexes.length == 1
400-
&& versionMapping.getVersionAttribute() == entityPersister().getAttributeMapping( incomingDirtyAttributeIndexes[0] ) ) {
401-
// special case of only the version attribute itself as dirty
402-
isSimpleVersionUpdate = true;
403-
newVersion = values[ incomingDirtyAttributeIndexes[0]];
404-
}
405-
else if ( incomingDirtyAttributeIndexes.length == 0 && oldVersion != null ) {
406-
isSimpleVersionUpdate = !versionMapping.areEqual(
407-
values[ versionMapping.getVersionAttribute().getStateArrayPosition() ],
408-
oldVersion,
409-
session
410-
);
411-
newVersion = values[ versionMapping.getVersionAttribute().getStateArrayPosition()];
412-
}
413-
else {
414-
isSimpleVersionUpdate = false;
415-
newVersion = null;
416-
}
417-
}
418-
else {
419-
isSimpleVersionUpdate = false;
420-
newVersion = null;
397+
if ( hasUpdateGeneratedValues() ) {
398+
// if we have any fields generated by the UPDATE event,
399+
// then we have to include the generated fields in the
400+
// update statement
401+
return null;
421402
}
422-
423-
if ( isSimpleVersionUpdate ) {
424-
// we have just the version being updated - use the special handling
425-
assert newVersion != null;
426-
final GeneratedValues generatedValues = doVersionUpdate( entity, id, newVersion, oldVersion, session );
427-
return () -> generatedValues;
403+
else if ( incomingDirtyAttributeIndexes != null ) {
404+
switch ( incomingDirtyAttributeIndexes.length ) {
405+
case 1:
406+
final int dirtyAttributeIndex = incomingDirtyAttributeIndexes[0];
407+
final var versionAttribute = versionMapping.getVersionAttribute();
408+
final var dirtyAttribute = entityPersister().getAttributeMapping( dirtyAttributeIndex );
409+
if ( versionAttribute == dirtyAttribute ) {
410+
// only the version attribute itself is dirty
411+
newVersion = values[dirtyAttributeIndex];
412+
}
413+
else {
414+
// the dirty field is some other field
415+
return null;
416+
}
417+
break;
418+
case 0:
419+
if ( oldVersion != null ) {
420+
newVersion = values[versionMapping.getVersionAttribute().getStateArrayPosition()];
421+
if ( versionMapping.areEqual( newVersion, oldVersion, session ) ) {
422+
return null;
423+
}
424+
}
425+
else {
426+
return null;
427+
}
428+
break;
429+
default:
430+
return null;
431+
}
428432
}
429433
else {
430434
return null;
431435
}
436+
437+
// we have just the version being updated - use the special handling
438+
assert newVersion != null;
439+
final GeneratedValues generatedValues = doVersionUpdate( entity, id, newVersion, oldVersion, session );
440+
return () -> generatedValues;
441+
}
442+
443+
private boolean hasUpdateGeneratedValues() {
444+
final var entityMetamodel = entityPersister().getEntityMetamodel();
445+
return entityMetamodel.hasUpdateGeneratedValues()
446+
|| entityMetamodel.hasPreUpdateGeneratedValues();
432447
}
433448

434449
private static boolean isValueGenerated(Generator generator) {
435450
return generator != null
436-
&& generator.generatesOnUpdate()
437-
&& generator.generatedOnExecution();
451+
&& generator.generatesOnUpdate()
452+
&& generator.generatedOnExecution();
438453
}
439454

440455
private static boolean isValueGenerationInSql(Generator generator, Dialect dialect) {
441456
assert isValueGenerated( generator );
442-
return ( (OnExecutionGenerator) generator ).referenceColumnsInSql(dialect);
457+
return ( (OnExecutionGenerator) generator ).referenceColumnsInSql( dialect );
443458
}
444459

445460
/**

0 commit comments

Comments
 (0)