Skip to content

Commit 3eabdf0

Browse files
committed
HHH-18563 Add foreign key target tables to affected tables
1 parent 07393b5 commit 3eabdf0

File tree

10 files changed

+208
-35
lines changed

10 files changed

+208
-35
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
@@ -21,6 +21,7 @@
2121
import org.hibernate.query.sqm.FetchClauseType;
2222
import org.hibernate.query.sqm.FrameExclusion;
2323
import org.hibernate.query.sqm.FrameKind;
24+
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
2425
import org.hibernate.sql.ast.Clause;
2526
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
2627
import org.hibernate.sql.ast.spi.SqlSelection;
@@ -52,6 +53,7 @@
5253
import org.hibernate.sql.ast.tree.select.QuerySpec;
5354
import org.hibernate.sql.ast.tree.select.SelectClause;
5455
import org.hibernate.sql.ast.tree.select.SortSpecification;
56+
import org.hibernate.sql.ast.tree.update.Assignable;
5557
import org.hibernate.sql.ast.tree.update.Assignment;
5658
import org.hibernate.sql.ast.tree.update.UpdateStatement;
5759
import org.hibernate.sql.exec.spi.JdbcOperation;
@@ -690,6 +692,13 @@ private boolean supportsOffsetFetchClause() {
690692

691693
@Override
692694
protected void visitSetAssignment(Assignment assignment) {
695+
final Assignable assignable = assignment.getAssignable();
696+
if ( assignable instanceof SqmPathInterpretation<?> ) {
697+
final String affectedTableName = ( (SqmPathInterpretation<?>) assignable ).getAffectedTableName();
698+
if ( affectedTableName != null ) {
699+
addAffectedTableName( affectedTableName );
700+
}
701+
}
693702
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
694703
if ( columnReferences.size() == 1 ) {
695704
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
@@ -19,6 +19,7 @@
1919
import org.hibernate.query.sqm.FetchClauseType;
2020
import org.hibernate.query.sqm.FrameExclusion;
2121
import org.hibernate.query.sqm.FrameKind;
22+
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
2223
import org.hibernate.sql.ast.Clause;
2324
import org.hibernate.sql.ast.spi.SqlSelection;
2425
import org.hibernate.sql.ast.tree.Statement;
@@ -49,6 +50,7 @@
4950
import org.hibernate.sql.ast.tree.select.QuerySpec;
5051
import org.hibernate.sql.ast.tree.select.SelectClause;
5152
import org.hibernate.sql.ast.tree.select.SortSpecification;
53+
import org.hibernate.sql.ast.tree.update.Assignable;
5254
import org.hibernate.sql.ast.tree.update.Assignment;
5355
import org.hibernate.sql.ast.tree.update.UpdateStatement;
5456
import org.hibernate.sql.exec.spi.JdbcOperation;
@@ -633,6 +635,13 @@ private boolean supportsOffsetFetchClause() {
633635

634636
@Override
635637
protected void visitSetAssignment(Assignment assignment) {
638+
final Assignable assignable = assignment.getAssignable();
639+
if ( assignable instanceof SqmPathInterpretation<?> ) {
640+
final String affectedTableName = ( (SqmPathInterpretation<?>) assignable ).getAffectedTableName();
641+
if ( affectedTableName != null ) {
642+
addAffectedTableName( affectedTableName );
643+
}
644+
}
636645
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
637646
if ( columnReferences.size() == 1 ) {
638647
columnReferences.get( 0 ).appendColumnForWrite( this );

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

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -980,16 +980,29 @@ public List<Assignment> visitSetClause(SqmSetClause setClause) {
980980
targetColumnReferences = pathSqlExpression.getColumnReference().getColumnReferences();
981981
}
982982
if ( assignmentValueParameter != null ) {
983+
final ArrayList<Expression> expressions = new ArrayList<>( targetColumnReferences.size() );
983984
consumeSqmParameter(
984985
assignmentValueParameter,
985986
assignedPathInterpretation.getExpressionType(),
986-
(index, jdbcParameter) -> addAssignment(
987-
assignments,
988-
aggregateColumnAssignmentHandler,
989-
targetColumnReferences.get( index ),
990-
jdbcParameter
991-
)
987+
(index, jdbcParameter) -> expressions.add( jdbcParameter )
992988
);
989+
if ( pathSqlExpression instanceof SqlTuple ) {
990+
addAssignment(
991+
assignments,
992+
aggregateColumnAssignmentHandler,
993+
(Assignable) assignedPathInterpretation,
994+
new SqlTuple( expressions, assignedPathInterpretation.getExpressionType() )
995+
);
996+
}
997+
else {
998+
assert expressions.size() == 1;
999+
addAssignment(
1000+
assignments,
1001+
aggregateColumnAssignmentHandler,
1002+
(Assignable) assignedPathInterpretation,
1003+
expressions.get( 0 )
1004+
);
1005+
}
9931006
}
9941007
else if ( assignmentValue instanceof SqmLiteralNull<?> ) {
9951008
for ( ColumnReference columnReference : targetColumnReferences ) {
@@ -1017,27 +1030,12 @@ else if ( assignmentValue instanceof SqmLiteralNull<?> ) {
10171030

10181031
assert assignedPathJdbcCount == valueExprJdbcCount;
10191032

1020-
if ( valueExpression instanceof SqlTuple ) {
1021-
final List<? extends Expression> expressions = ( (SqlTuple) valueExpression ).getExpressions();
1022-
assert targetColumnReferences.size() == expressions.size();
1023-
for ( int i = 0; i < targetColumnReferences.size(); i++ ) {
1024-
final ColumnReference columnReference = targetColumnReferences.get( i );
1025-
addAssignment( assignments, aggregateColumnAssignmentHandler, columnReference, expressions.get( i ) );
1026-
}
1027-
}
1028-
else if ( valueExpression instanceof EmbeddableValuedPathInterpretation<?> ) {
1029-
final List<? extends Expression> expressions = ( (EmbeddableValuedPathInterpretation<?>) valueExpression ).getSqlTuple().getExpressions();
1030-
assert targetColumnReferences.size() == expressions.size();
1031-
for ( int i = 0; i < targetColumnReferences.size(); i++ ) {
1032-
final ColumnReference columnReference = targetColumnReferences.get( i );
1033-
addAssignment( assignments, aggregateColumnAssignmentHandler, columnReference, expressions.get( i ) );
1034-
}
1035-
}
1036-
else {
1037-
for ( ColumnReference columnReference : targetColumnReferences ) {
1038-
addAssignment( assignments, aggregateColumnAssignmentHandler, columnReference, valueExpression );
1039-
}
1040-
}
1033+
addAssignment(
1034+
assignments,
1035+
aggregateColumnAssignmentHandler,
1036+
(Assignable) assignedPathInterpretation,
1037+
valueExpression
1038+
);
10411039
}
10421040
}
10431041
finally {
@@ -1056,12 +1054,12 @@ else if ( valueExpression instanceof EmbeddableValuedPathInterpretation<?> ) {
10561054
private void addAssignment(
10571055
List<Assignment> assignments,
10581056
AggregateColumnAssignmentHandler aggregateColumnAssignmentHandler,
1059-
ColumnReference columnReference,
1057+
Assignable assignable,
10601058
Expression valueExpression) {
10611059
if ( aggregateColumnAssignmentHandler != null ) {
1062-
aggregateColumnAssignmentHandler.addAssignment( assignments.size(), columnReference );
1060+
aggregateColumnAssignmentHandler.addAssignment( assignments.size(), (ColumnReference) assignable );
10631061
}
1064-
assignments.add( new Assignment( columnReference, valueExpression ) );
1062+
assignments.add( new Assignment( assignable, valueExpression ) );
10651063
}
10661064

10671065
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import org.hibernate.metamodel.MappingMetamodel;
1414
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
15+
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
1516
import org.hibernate.metamodel.mapping.EntityMappingType;
1617
import org.hibernate.metamodel.mapping.MappingType;
1718
import org.hibernate.metamodel.mapping.ModelPart;
@@ -25,6 +26,7 @@
2526
import org.hibernate.query.sqm.tree.domain.SqmPath;
2627
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
2728
import org.hibernate.spi.NavigablePath;
29+
import org.hibernate.sql.ast.SqlAstTranslator;
2830
import org.hibernate.sql.ast.SqlAstWalker;
2931
import org.hibernate.sql.ast.tree.expression.ColumnReference;
3032
import org.hibernate.sql.ast.tree.expression.Expression;
@@ -33,6 +35,8 @@
3335
import org.hibernate.sql.ast.tree.from.TableReference;
3436
import org.hibernate.sql.ast.tree.update.Assignable;
3537

38+
import org.checkerframework.checker.nullness.qual.Nullable;
39+
3640
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
3741
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
3842
import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded;
@@ -133,15 +137,37 @@ else if ( expression instanceof SqlSelectionExpression ) {
133137
}
134138

135139
private final ColumnReference columnReference;
140+
private final @Nullable String affectedTableName;
136141

137142
public BasicValuedPathInterpretation(
138143
ColumnReference columnReference,
139144
NavigablePath navigablePath,
140145
BasicValuedModelPart mapping,
141146
TableGroup tableGroup) {
147+
this( columnReference, navigablePath, mapping, tableGroup, determineAffectedTableName( tableGroup, mapping ) );
148+
}
149+
150+
private static @Nullable String determineAffectedTableName(TableGroup tableGroup, BasicValuedModelPart mapping) {
151+
final ModelPartContainer modelPart = tableGroup.getModelPart();
152+
if ( modelPart instanceof EntityAssociationMapping ) {
153+
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) modelPart;
154+
if ( !associationMapping.containsTableReference( mapping.getContainingTableExpression() ) ) {
155+
return associationMapping.getAssociatedEntityMappingType().getMappedTableDetails().getTableName();
156+
}
157+
}
158+
return null;
159+
}
160+
161+
public BasicValuedPathInterpretation(
162+
ColumnReference columnReference,
163+
NavigablePath navigablePath,
164+
BasicValuedModelPart mapping,
165+
TableGroup tableGroup,
166+
@Nullable String affectedTableName) {
142167
super( navigablePath, mapping, tableGroup );
143168
assert columnReference != null;
144169
this.columnReference = columnReference;
170+
this.affectedTableName = affectedTableName;
145171
}
146172

147173
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -152,13 +178,21 @@ public Expression getSqlExpression() {
152178
return columnReference;
153179
}
154180

181+
@Override
182+
public @Nullable String getAffectedTableName() {
183+
return affectedTableName;
184+
}
185+
155186
@Override
156187
public ColumnReference getColumnReference() {
157188
return columnReference;
158189
}
159190

160191
@Override
161192
public void accept(SqlAstWalker sqlTreeWalker) {
193+
if ( affectedTableName != null && sqlTreeWalker instanceof SqlAstTranslator<?> ) {
194+
( (SqlAstTranslator<?>) sqlTreeWalker ).addAffectedTableName( affectedTableName );
195+
}
162196
columnReference.accept( sqlTreeWalker );
163197
}
164198

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import org.hibernate.metamodel.MappingMetamodel;
1414
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
15+
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
1516
import org.hibernate.metamodel.mapping.EntityMappingType;
1617
import org.hibernate.metamodel.mapping.ModelPartContainer;
1718
import org.hibernate.metamodel.model.domain.EntityDomainType;
@@ -20,6 +21,7 @@
2021
import org.hibernate.query.sqm.tree.domain.SqmPath;
2122
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
2223
import org.hibernate.spi.NavigablePath;
24+
import org.hibernate.sql.ast.SqlAstTranslator;
2325
import org.hibernate.sql.ast.SqlAstWalker;
2426
import org.hibernate.sql.ast.tree.expression.ColumnReference;
2527
import org.hibernate.sql.ast.tree.expression.Expression;
@@ -28,6 +30,8 @@
2830
import org.hibernate.sql.ast.tree.from.TableGroup;
2931
import org.hibernate.sql.ast.tree.update.Assignable;
3032

33+
import org.checkerframework.checker.nullness.qual.Nullable;
34+
3135
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
3236
import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded;
3337

@@ -84,23 +88,53 @@ else if ( lhs.getNodeType() instanceof EntityDomainType ) {
8488
}
8589

8690
private final SqlTuple sqlExpression;
91+
private final @Nullable String affectedTableName;
8792

8893
public EmbeddableValuedPathInterpretation(
8994
SqlTuple sqlExpression,
9095
NavigablePath navigablePath,
9196
EmbeddableValuedModelPart mapping,
9297
TableGroup tableGroup) {
98+
this( sqlExpression, navigablePath, mapping, tableGroup, determineAffectedTableName( tableGroup, mapping ) );
99+
}
100+
101+
public EmbeddableValuedPathInterpretation(
102+
SqlTuple sqlExpression,
103+
NavigablePath navigablePath,
104+
EmbeddableValuedModelPart mapping,
105+
TableGroup tableGroup,
106+
@Nullable String affectedTableName) {
93107
super( navigablePath, mapping, tableGroup );
94108
this.sqlExpression = sqlExpression;
109+
this.affectedTableName = affectedTableName;
110+
}
111+
112+
private static @Nullable String determineAffectedTableName(TableGroup tableGroup, EmbeddableValuedModelPart mapping) {
113+
final ModelPartContainer modelPart = tableGroup.getModelPart();
114+
if ( modelPart instanceof EntityAssociationMapping ) {
115+
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) modelPart;
116+
if ( !associationMapping.containsTableReference( mapping.getContainingTableExpression() ) ) {
117+
return associationMapping.getAssociatedEntityMappingType().getMappedTableDetails().getTableName();
118+
}
119+
}
120+
return null;
95121
}
96122

97123
@Override
98124
public SqlTuple getSqlExpression() {
99125
return sqlExpression;
100126
}
101127

128+
@Override
129+
public @Nullable String getAffectedTableName() {
130+
return affectedTableName;
131+
}
132+
102133
@Override
103134
public void accept(SqlAstWalker sqlTreeWalker) {
135+
if ( affectedTableName != null && sqlTreeWalker instanceof SqlAstTranslator<?> ) {
136+
( (SqlAstTranslator<?>) sqlTreeWalker ).addAffectedTableName( affectedTableName );
137+
}
104138
sqlExpression.accept( sqlTreeWalker );
105139
}
106140

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
import org.hibernate.dialect.Dialect;
1515
import org.hibernate.dialect.FunctionalDependencyAnalysisSupport;
1616
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
17+
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
1718
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
1819
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
1920
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
2021
import org.hibernate.metamodel.mapping.EntityMappingType;
2122
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
2223
import org.hibernate.metamodel.mapping.MappingModelExpressible;
2324
import org.hibernate.metamodel.mapping.ModelPart;
25+
import org.hibernate.metamodel.mapping.ModelPartContainer;
2426
import org.hibernate.metamodel.mapping.SelectableConsumer;
2527
import org.hibernate.metamodel.mapping.ValuedModelPart;
2628
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
@@ -36,6 +38,7 @@
3638
import org.hibernate.query.sqm.tree.select.SqmSelection;
3739
import org.hibernate.spi.NavigablePath;
3840
import org.hibernate.sql.ast.Clause;
41+
import org.hibernate.sql.ast.SqlAstTranslator;
3942
import org.hibernate.sql.ast.SqlAstWalker;
4043
import org.hibernate.sql.ast.spi.SqlAstCreationState;
4144
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
@@ -50,10 +53,12 @@
5053
import org.hibernate.sql.results.graph.Fetchable;
5154

5255
import jakarta.persistence.criteria.Selection;
56+
import org.checkerframework.checker.nullness.qual.Nullable;
5357

5458
public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpretation<T>
5559
implements SqlTupleContainer, Assignable {
5660
private final Expression sqlExpression;
61+
private final @Nullable String affectedTableName;
5762

5863
public static <T> EntityValuedPathInterpretation<T> from(
5964
SqmEntityValuedSimplePath<T> sqmPath,
@@ -424,17 +429,46 @@ public EntityValuedPathInterpretation(
424429
NavigablePath navigablePath,
425430
TableGroup tableGroup,
426431
EntityValuedModelPart mapping) {
432+
this( sqlExpression, navigablePath, tableGroup, mapping, determineAffectedTableName( tableGroup, mapping ) );
433+
}
434+
435+
public EntityValuedPathInterpretation(
436+
Expression sqlExpression,
437+
NavigablePath navigablePath,
438+
TableGroup tableGroup,
439+
EntityValuedModelPart mapping,
440+
@Nullable String affectedTableName) {
427441
super( navigablePath, mapping, tableGroup );
428442
this.sqlExpression = sqlExpression;
443+
this.affectedTableName = affectedTableName;
444+
}
445+
446+
private static @Nullable String determineAffectedTableName(TableGroup tableGroup, EntityValuedModelPart mapping) {
447+
final ModelPartContainer modelPart = tableGroup.getModelPart();
448+
if ( modelPart instanceof EntityAssociationMapping && mapping instanceof ValuedModelPart ) {
449+
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) modelPart;
450+
if ( !associationMapping.containsTableReference( ( (ValuedModelPart) mapping ).getContainingTableExpression() ) ) {
451+
return associationMapping.getAssociatedEntityMappingType().getMappedTableDetails().getTableName();
452+
}
453+
}
454+
return null;
429455
}
430456

431457
@Override
432458
public Expression getSqlExpression() {
433459
return sqlExpression;
434460
}
435461

462+
@Override
463+
public @Nullable String getAffectedTableName() {
464+
return affectedTableName;
465+
}
466+
436467
@Override
437468
public void accept(SqlAstWalker sqlTreeWalker) {
469+
if ( affectedTableName != null && sqlTreeWalker instanceof SqlAstTranslator<?> ) {
470+
( (SqlAstTranslator<?>) sqlTreeWalker ).addAffectedTableName( affectedTableName );
471+
}
438472
sqlExpression.accept( sqlTreeWalker );
439473
}
440474

0 commit comments

Comments
 (0)