Skip to content

Commit a73f76e

Browse files
committed
HHH-18563 Add foreign key target tables to affected tables
1 parent f3185dc commit a73f76e

File tree

11 files changed

+211
-46
lines changed

11 files changed

+211
-46
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.hibernate.query.common.FetchClauseType;
2323
import org.hibernate.query.common.FrameExclusion;
2424
import org.hibernate.query.common.FrameKind;
25+
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
2526
import org.hibernate.sql.ast.Clause;
2627
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
2728
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
@@ -56,6 +57,7 @@
5657
import org.hibernate.sql.ast.tree.select.QuerySpec;
5758
import org.hibernate.sql.ast.tree.select.SelectClause;
5859
import org.hibernate.sql.ast.tree.select.SortSpecification;
60+
import org.hibernate.sql.ast.tree.update.Assignable;
5961
import org.hibernate.sql.ast.tree.update.Assignment;
6062
import org.hibernate.sql.ast.tree.update.UpdateStatement;
6163
import org.hibernate.sql.exec.spi.JdbcOperation;
@@ -670,6 +672,13 @@ private boolean supportsOffsetFetchClause() {
670672

671673
@Override
672674
protected void visitSetAssignment(Assignment assignment) {
675+
final Assignable assignable = assignment.getAssignable();
676+
if ( assignable instanceof SqmPathInterpretation<?> ) {
677+
final String affectedTableName = ( (SqmPathInterpretation<?>) assignable ).getAffectedTableName();
678+
if ( affectedTableName != null ) {
679+
addAffectedTableName( affectedTableName );
680+
}
681+
}
673682
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
674683
if ( columnReferences.size() == 1 ) {
675684
columnReferences.get( 0 ).appendColumnForWrite( this );

hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.hibernate.query.common.FetchClauseType;
2121
import org.hibernate.query.common.FrameExclusion;
2222
import org.hibernate.query.common.FrameKind;
23+
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
2324
import org.hibernate.sql.ast.Clause;
2425
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
2526
import org.hibernate.sql.ast.spi.SqlSelection;
@@ -54,6 +55,7 @@
5455
import org.hibernate.sql.ast.tree.select.QuerySpec;
5556
import org.hibernate.sql.ast.tree.select.SelectClause;
5657
import org.hibernate.sql.ast.tree.select.SortSpecification;
58+
import org.hibernate.sql.ast.tree.update.Assignable;
5759
import org.hibernate.sql.ast.tree.update.Assignment;
5860
import org.hibernate.sql.ast.tree.update.UpdateStatement;
5961
import org.hibernate.sql.exec.spi.JdbcOperation;
@@ -627,6 +629,13 @@ private boolean supportsOffsetFetchClause() {
627629

628630
@Override
629631
protected void visitSetAssignment(Assignment assignment) {
632+
final Assignable assignable = assignment.getAssignable();
633+
if ( assignable instanceof SqmPathInterpretation<?> ) {
634+
final String affectedTableName = ( (SqmPathInterpretation<?>) assignable ).getAffectedTableName();
635+
if ( affectedTableName != null ) {
636+
addAffectedTableName( affectedTableName );
637+
}
638+
}
630639
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
631640
if ( columnReferences.size() == 1 ) {
632641
columnReferences.get( 0 ).appendColumnForWrite( this );

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -858,36 +858,53 @@ public List<Assignment> visitSetClause(SqmSetClause setClause) {
858858
final SqmExpression<?> assignmentValue = sqmAssignment.getValue();
859859
final SqmParameter<?> assignmentValueParameter = getSqmParameter( assignmentValue );
860860
final Expression pathSqlExpression = assignedPathInterpretation.getSqlExpression();
861-
final List<? extends Expression> targetColumnReferences =
861+
//noinspection unchecked
862+
final List<ColumnReference> targetColumnReferences =
862863
pathSqlExpression instanceof SqlTuple sqlTuple
863-
? sqlTuple.getExpressions()
864+
? (List<ColumnReference>) sqlTuple.getExpressions()
864865
: pathSqlExpression.getColumnReference().getColumnReferences();
865866
if ( assignmentValueParameter != null ) {
867+
final ArrayList<Expression> expressions = new ArrayList<>( targetColumnReferences.size() );
866868
consumeSqmParameter(
867869
assignmentValueParameter,
868870
assignedPathInterpretation.getExpressionType(),
869-
(index, jdbcParameter) -> addAssignment(
870-
assignments,
871-
aggregateColumnAssignmentHandler,
872-
targetColumnReferences.get( index ),
873-
jdbcParameter
874-
)
871+
(index, jdbcParameter) -> expressions.add( jdbcParameter )
875872
);
873+
if ( pathSqlExpression instanceof SqlTuple ) {
874+
addAssignment(
875+
assignments,
876+
aggregateColumnAssignmentHandler,
877+
(Assignable) assignedPathInterpretation,
878+
targetColumnReferences,
879+
new SqlTuple( expressions, assignedPathInterpretation.getExpressionType() )
880+
);
881+
}
882+
else {
883+
assert expressions.size() == 1;
884+
addAssignment(
885+
assignments,
886+
aggregateColumnAssignmentHandler,
887+
(Assignable) assignedPathInterpretation,
888+
targetColumnReferences,
889+
expressions.get( 0 )
890+
);
891+
}
876892
}
877893
else if ( assignmentValue instanceof SqmLiteralNull<?> ) {
878894
for ( Expression columnReference : targetColumnReferences ) {
879895
addAssignment(
880896
assignments,
881897
aggregateColumnAssignmentHandler,
882-
columnReference,
898+
(Assignable) assignedPathInterpretation,
899+
targetColumnReferences,
883900
new QueryLiteral<>( null, (BasicValuedMapping) columnReference.getExpressionType() )
884901
);
885902
}
886903
}
887904
else {
888905
addAssignments(
889906
(Expression) assignmentValue.accept( this ),
890-
assignedPathInterpretation.getExpressionType(),
907+
assignedPathInterpretation,
891908
targetColumnReferences,
892909
assignments,
893910
aggregateColumnAssignmentHandler
@@ -909,35 +926,18 @@ else if ( assignmentValue instanceof SqmLiteralNull<?> ) {
909926

910927
private void addAssignments(
911928
Expression valueExpression,
912-
ModelPart assignedPathType,
913-
List<? extends Expression> targetColumnReferences,
929+
SqmPathInterpretation<?> assignedPathInterpretation,
930+
List<ColumnReference> targetColumnReferences,
914931
ArrayList<Assignment> assignments,
915-
AggregateColumnAssignmentHandler assignmentHandler) {
916-
checkAssignment( valueExpression, assignedPathType );
917-
if ( valueExpression instanceof SqlTuple sqlTuple ) {
918-
addTupleAssignments( targetColumnReferences, assignments, assignmentHandler, sqlTuple );
919-
}
920-
else if ( valueExpression instanceof EmbeddableValuedPathInterpretation<?> embeddable ) {
921-
addTupleAssignments( targetColumnReferences, assignments, assignmentHandler, embeddable.getSqlTuple() );
922-
}
923-
else {
924-
for ( Expression columnReference : targetColumnReferences ) {
925-
addAssignment( assignments, assignmentHandler, columnReference, valueExpression );
926-
}
927-
}
928-
}
929-
930-
private void addTupleAssignments(
931-
List<? extends Expression> targetColumnReferences,
932-
ArrayList<Assignment> assignments,
933-
AggregateColumnAssignmentHandler aggregateColumnAssignmentHandler,
934-
SqlTuple sqlTuple) {
935-
final List<? extends Expression> expressions = sqlTuple.getExpressions();
936-
assert targetColumnReferences.size() == expressions.size();
937-
for ( int i = 0; i < targetColumnReferences.size(); i++ ) {
938-
final ColumnReference columnReference = (ColumnReference) targetColumnReferences.get( i );
939-
addAssignment( assignments, aggregateColumnAssignmentHandler, columnReference, expressions.get( i ) );
940-
}
932+
AggregateColumnAssignmentHandler aggregateColumnAssignmentHandler) {
933+
checkAssignment( valueExpression, assignedPathInterpretation.getExpressionType() );
934+
addAssignment(
935+
assignments,
936+
aggregateColumnAssignmentHandler,
937+
(Assignable) assignedPathInterpretation,
938+
targetColumnReferences,
939+
valueExpression
940+
);
941941
}
942942

943943
private void checkAssignment(Expression valueExpression, ModelPart assignedPathType) {
@@ -958,12 +958,15 @@ private void checkAssignment(Expression valueExpression, ModelPart assignedPathT
958958
private void addAssignment(
959959
List<Assignment> assignments,
960960
AggregateColumnAssignmentHandler aggregateColumnAssignmentHandler,
961-
Expression columnReference,
961+
Assignable assignable,
962+
List<ColumnReference> targetColumnReferences,
962963
Expression valueExpression) {
963964
if ( aggregateColumnAssignmentHandler != null ) {
964-
aggregateColumnAssignmentHandler.addAssignment( assignments.size(), (ColumnReference) columnReference );
965+
for ( ColumnReference targetColumnReference : targetColumnReferences ) {
966+
aggregateColumnAssignmentHandler.addAssignment( assignments.size(), targetColumnReference );
967+
}
965968
}
966-
assignments.add( new Assignment( (ColumnReference) columnReference, valueExpression ) );
969+
assignments.add( new Assignment( assignable, valueExpression ) );
967970
}
968971

969972
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/BasicValuedPathInterpretation.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import org.hibernate.metamodel.MappingMetamodel;
1212
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
13+
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
1314
import org.hibernate.metamodel.mapping.EntityMappingType;
1415
import org.hibernate.metamodel.mapping.MappingType;
1516
import org.hibernate.metamodel.mapping.ModelPart;
@@ -31,6 +32,8 @@
3132
import org.hibernate.sql.ast.tree.from.TableReference;
3233
import org.hibernate.sql.ast.tree.update.Assignable;
3334

35+
import org.checkerframework.checker.nullness.qual.Nullable;
36+
3437
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
3538
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
3639
import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded;
@@ -124,15 +127,37 @@ else if ( expression instanceof SqlSelectionExpression ) {
124127
}
125128

126129
private final ColumnReference columnReference;
130+
private final @Nullable String affectedTableName;
127131

128132
public BasicValuedPathInterpretation(
129133
ColumnReference columnReference,
130134
NavigablePath navigablePath,
131135
BasicValuedModelPart mapping,
132136
TableGroup tableGroup) {
137+
this( columnReference, navigablePath, mapping, tableGroup, determineAffectedTableName( tableGroup, mapping ) );
138+
}
139+
140+
private static @Nullable String determineAffectedTableName(TableGroup tableGroup, BasicValuedModelPart mapping) {
141+
final ModelPartContainer modelPart = tableGroup.getModelPart();
142+
if ( modelPart instanceof EntityAssociationMapping ) {
143+
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) modelPart;
144+
if ( !associationMapping.containsTableReference( mapping.getContainingTableExpression() ) ) {
145+
return associationMapping.getAssociatedEntityMappingType().getMappedTableDetails().getTableName();
146+
}
147+
}
148+
return null;
149+
}
150+
151+
public BasicValuedPathInterpretation(
152+
ColumnReference columnReference,
153+
NavigablePath navigablePath,
154+
BasicValuedModelPart mapping,
155+
TableGroup tableGroup,
156+
@Nullable String affectedTableName) {
133157
super( navigablePath, mapping, tableGroup );
134158
assert columnReference != null;
135159
this.columnReference = columnReference;
160+
this.affectedTableName = affectedTableName;
136161
}
137162

138163
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -143,6 +168,11 @@ public Expression getSqlExpression() {
143168
return columnReference;
144169
}
145170

171+
@Override
172+
public @Nullable String getAffectedTableName() {
173+
return affectedTableName;
174+
}
175+
146176
@Override
147177
public ColumnReference getColumnReference() {
148178
return columnReference;

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EmbeddableValuedPathInterpretation.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import org.hibernate.metamodel.MappingMetamodel;
1212
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
13+
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
1314
import org.hibernate.metamodel.mapping.EntityMappingType;
1415
import org.hibernate.metamodel.mapping.ModelPartContainer;
1516
import org.hibernate.metamodel.model.domain.EntityDomainType;
@@ -26,6 +27,8 @@
2627
import org.hibernate.sql.ast.tree.from.TableGroup;
2728
import org.hibernate.sql.ast.tree.update.Assignable;
2829

30+
import org.checkerframework.checker.nullness.qual.Nullable;
31+
2932
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
3033
import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded;
3134

@@ -79,21 +82,48 @@ else if ( lhs.getNodeType() instanceof EntityDomainType ) {
7982
}
8083

8184
private final SqlTuple sqlExpression;
85+
private final @Nullable String affectedTableName;
8286

8387
public EmbeddableValuedPathInterpretation(
8488
SqlTuple sqlExpression,
8589
NavigablePath navigablePath,
8690
EmbeddableValuedModelPart mapping,
8791
TableGroup tableGroup) {
92+
this( sqlExpression, navigablePath, mapping, tableGroup, determineAffectedTableName( tableGroup, mapping ) );
93+
}
94+
95+
public EmbeddableValuedPathInterpretation(
96+
SqlTuple sqlExpression,
97+
NavigablePath navigablePath,
98+
EmbeddableValuedModelPart mapping,
99+
TableGroup tableGroup,
100+
@Nullable String affectedTableName) {
88101
super( navigablePath, mapping, tableGroup );
89102
this.sqlExpression = sqlExpression;
103+
this.affectedTableName = affectedTableName;
104+
}
105+
106+
private static @Nullable String determineAffectedTableName(TableGroup tableGroup, EmbeddableValuedModelPart mapping) {
107+
final ModelPartContainer modelPart = tableGroup.getModelPart();
108+
if ( modelPart instanceof EntityAssociationMapping ) {
109+
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) modelPart;
110+
if ( !associationMapping.containsTableReference( mapping.getContainingTableExpression() ) ) {
111+
return associationMapping.getAssociatedEntityMappingType().getMappedTableDetails().getTableName();
112+
}
113+
}
114+
return null;
90115
}
91116

92117
@Override
93118
public SqlTuple getSqlExpression() {
94119
return sqlExpression;
95120
}
96121

122+
@Override
123+
public @Nullable String getAffectedTableName() {
124+
return affectedTableName;
125+
}
126+
97127
@Override
98128
public void accept(SqlAstWalker sqlTreeWalker) {
99129
sqlExpression.accept( sqlTreeWalker );

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
2020
import org.hibernate.metamodel.mapping.MappingModelExpressible;
2121
import org.hibernate.metamodel.mapping.ModelPart;
22+
import org.hibernate.metamodel.mapping.ModelPartContainer;
2223
import org.hibernate.metamodel.mapping.SelectableConsumer;
2324
import org.hibernate.metamodel.mapping.ValuedModelPart;
2425
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
@@ -48,10 +49,12 @@
4849
import org.hibernate.sql.results.graph.Fetchable;
4950

5051
import jakarta.persistence.criteria.Selection;
52+
import org.checkerframework.checker.nullness.qual.Nullable;
5153

5254
public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpretation<T>
5355
implements SqlTupleContainer, Assignable {
5456
private final Expression sqlExpression;
57+
private final @Nullable String affectedTableName;
5558

5659
public static <T> EntityValuedPathInterpretation<T> from(
5760
SqmEntityValuedSimplePath<T> sqmPath,
@@ -415,15 +418,41 @@ public EntityValuedPathInterpretation(
415418
NavigablePath navigablePath,
416419
TableGroup tableGroup,
417420
EntityValuedModelPart mapping) {
421+
this( sqlExpression, navigablePath, tableGroup, mapping, determineAffectedTableName( tableGroup, mapping ) );
422+
}
423+
424+
public EntityValuedPathInterpretation(
425+
Expression sqlExpression,
426+
NavigablePath navigablePath,
427+
TableGroup tableGroup,
428+
EntityValuedModelPart mapping,
429+
@Nullable String affectedTableName) {
418430
super( navigablePath, mapping, tableGroup );
419431
this.sqlExpression = sqlExpression;
432+
this.affectedTableName = affectedTableName;
433+
}
434+
435+
private static @Nullable String determineAffectedTableName(TableGroup tableGroup, EntityValuedModelPart mapping) {
436+
final ModelPartContainer modelPart = tableGroup.getModelPart();
437+
if ( modelPart instanceof EntityAssociationMapping && mapping instanceof ValuedModelPart ) {
438+
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) modelPart;
439+
if ( !associationMapping.containsTableReference( ( (ValuedModelPart) mapping ).getContainingTableExpression() ) ) {
440+
return associationMapping.getAssociatedEntityMappingType().getMappedTableDetails().getTableName();
441+
}
442+
}
443+
return null;
420444
}
421445

422446
@Override
423447
public Expression getSqlExpression() {
424448
return sqlExpression;
425449
}
426450

451+
@Override
452+
public @Nullable String getAffectedTableName() {
453+
return affectedTableName;
454+
}
455+
427456
@Override
428457
public void accept(SqlAstWalker sqlTreeWalker) {
429458
sqlExpression.accept( sqlTreeWalker );

0 commit comments

Comments
 (0)