Skip to content

Commit 4d9cb1b

Browse files
beikovsebersole
authored andcommitted
HHH-18563 Add set clause foreign key target tables to affected tables
1 parent 55e39ab commit 4d9cb1b

File tree

12 files changed

+348
-70
lines changed

12 files changed

+348
-70
lines changed

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

+48-2
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;
@@ -55,7 +56,9 @@
5556
import org.hibernate.sql.ast.tree.select.QueryPart;
5657
import org.hibernate.sql.ast.tree.select.QuerySpec;
5758
import org.hibernate.sql.ast.tree.select.SelectClause;
59+
import org.hibernate.sql.ast.tree.select.SelectStatement;
5860
import org.hibernate.sql.ast.tree.select.SortSpecification;
61+
import org.hibernate.sql.ast.tree.update.Assignable;
5962
import org.hibernate.sql.ast.tree.update.Assignment;
6063
import org.hibernate.sql.ast.tree.update.UpdateStatement;
6164
import org.hibernate.sql.exec.spi.JdbcOperation;
@@ -668,13 +671,43 @@ private boolean supportsOffsetFetchClause() {
668671
return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY );
669672
}
670673

674+
@Override
675+
protected void renderNull(Literal literal) {
676+
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.NO_UNTYPED ) {
677+
switch ( literal.getJdbcMapping().getJdbcType().getDdlTypeCode() ) {
678+
case SqlTypes.BLOB:
679+
appendSql( "to_blob(null)" );
680+
break;
681+
case SqlTypes.CLOB:
682+
appendSql( "to_clob(null)" );
683+
break;
684+
case SqlTypes.NCLOB:
685+
appendSql( "to_nclob(null)" );
686+
break;
687+
default:
688+
super.renderNull( literal );
689+
break;
690+
}
691+
}
692+
else {
693+
super.renderNull( literal );
694+
}
695+
}
696+
671697
@Override
672698
protected void visitSetAssignment(Assignment assignment) {
699+
final Assignable assignable = assignment.getAssignable();
700+
if ( assignable instanceof SqmPathInterpretation<?> ) {
701+
final String affectedTableName = ( (SqmPathInterpretation<?>) assignable ).getAffectedTableName();
702+
if ( affectedTableName != null ) {
703+
addAffectedTableName( affectedTableName );
704+
}
705+
}
673706
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
707+
final Expression assignedValue = assignment.getAssignedValue();
674708
if ( columnReferences.size() == 1 ) {
675709
columnReferences.get( 0 ).appendColumnForWrite( this );
676710
appendSql( '=' );
677-
final Expression assignedValue = assignment.getAssignedValue();
678711
final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple( assignedValue );
679712
if ( sqlTuple != null ) {
680713
assert sqlTuple.getExpressions().size() == 1;
@@ -684,7 +717,7 @@ protected void visitSetAssignment(Assignment assignment) {
684717
assignedValue.accept( this );
685718
}
686719
}
687-
else {
720+
else if ( assignedValue instanceof SelectStatement ) {
688721
char separator = OPEN_PARENTHESIS;
689722
for ( ColumnReference columnReference : columnReferences ) {
690723
appendSql( separator );
@@ -694,5 +727,18 @@ protected void visitSetAssignment(Assignment assignment) {
694727
appendSql( ")=" );
695728
assignment.getAssignedValue().accept( this );
696729
}
730+
else {
731+
assert assignedValue instanceof SqlTupleContainer;
732+
final List<? extends Expression> expressions = ( (SqlTupleContainer) assignedValue ).getSqlTuple().getExpressions();
733+
columnReferences.get( 0 ).appendColumnForWrite( this, null );
734+
appendSql( '=' );
735+
expressions.get( 0 ).accept( this );
736+
for ( int i = 1; i < columnReferences.size(); i++ ) {
737+
appendSql( ',' );
738+
columnReferences.get( i ).appendColumnForWrite( this, null );
739+
appendSql( '=' );
740+
expressions.get( i ).accept( this );
741+
}
742+
}
697743
}
698744
}

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

+49-3
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;
@@ -53,7 +54,9 @@
5354
import org.hibernate.sql.ast.tree.select.QueryPart;
5455
import org.hibernate.sql.ast.tree.select.QuerySpec;
5556
import org.hibernate.sql.ast.tree.select.SelectClause;
57+
import org.hibernate.sql.ast.tree.select.SelectStatement;
5658
import org.hibernate.sql.ast.tree.select.SortSpecification;
59+
import org.hibernate.sql.ast.tree.update.Assignable;
5760
import org.hibernate.sql.ast.tree.update.Assignment;
5861
import org.hibernate.sql.ast.tree.update.UpdateStatement;
5962
import org.hibernate.sql.exec.spi.JdbcOperation;
@@ -625,13 +628,43 @@ private boolean supportsOffsetFetchClause() {
625628
return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY );
626629
}
627630

631+
@Override
632+
protected void renderNull(Literal literal) {
633+
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.NO_UNTYPED ) {
634+
switch ( literal.getJdbcMapping().getJdbcType().getDdlTypeCode() ) {
635+
case SqlTypes.BLOB:
636+
appendSql( "to_blob(null)" );
637+
break;
638+
case SqlTypes.CLOB:
639+
appendSql( "to_clob(null)" );
640+
break;
641+
case SqlTypes.NCLOB:
642+
appendSql( "to_nclob(null)" );
643+
break;
644+
default:
645+
super.renderNull( literal );
646+
break;
647+
}
648+
}
649+
else {
650+
super.renderNull( literal );
651+
}
652+
}
653+
628654
@Override
629655
protected void visitSetAssignment(Assignment assignment) {
656+
final Assignable assignable = assignment.getAssignable();
657+
if ( assignable instanceof SqmPathInterpretation<?> ) {
658+
final String affectedTableName = ( (SqmPathInterpretation<?>) assignable ).getAffectedTableName();
659+
if ( affectedTableName != null ) {
660+
addAffectedTableName( affectedTableName );
661+
}
662+
}
630663
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
664+
final Expression assignedValue = assignment.getAssignedValue();
631665
if ( columnReferences.size() == 1 ) {
632666
columnReferences.get( 0 ).appendColumnForWrite( this );
633667
appendSql( '=' );
634-
final Expression assignedValue = assignment.getAssignedValue();
635668
final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple( assignedValue );
636669
if ( sqlTuple != null ) {
637670
assert sqlTuple.getExpressions().size() == 1;
@@ -641,15 +674,28 @@ protected void visitSetAssignment(Assignment assignment) {
641674
assignedValue.accept( this );
642675
}
643676
}
644-
else {
677+
else if ( assignedValue instanceof SelectStatement ) {
645678
char separator = OPEN_PARENTHESIS;
646679
for ( ColumnReference columnReference : columnReferences ) {
647680
appendSql( separator );
648681
columnReference.appendColumnForWrite( this );
649682
separator = COMMA_SEPARATOR_CHAR;
650683
}
651684
appendSql( ")=" );
652-
assignment.getAssignedValue().accept( this );
685+
assignedValue.accept( this );
686+
}
687+
else {
688+
assert assignedValue instanceof SqlTupleContainer;
689+
final List<? extends Expression> expressions = ( (SqlTupleContainer) assignedValue ).getSqlTuple().getExpressions();
690+
columnReferences.get( 0 ).appendColumnForWrite( this, null );
691+
appendSql( '=' );
692+
expressions.get( 0 ).accept( this );
693+
for ( int i = 1; i < columnReferences.size(); i++ ) {
694+
appendSql( ',' );
695+
columnReferences.get( i ).appendColumnForWrite( this, null );
696+
appendSql( '=' );
697+
expressions.get( i ).accept( this );
698+
}
653699
}
654700
}
655701

hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertHandler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ private List<Assignment> getCompatibleAssignments(InsertSelectStatement dmlState
12991299
final List<Assignment> assignments = conflictClause.getAssignments();
13001300
for ( Assignment assignment : assignments ) {
13011301
for ( ColumnReference targetColumn : dmlStatement.getTargetColumns() ) {
1302-
if ( targetColumn.equals( assignment.getAssignable() ) ) {
1302+
if ( assignment.getAssignable().getColumnReferences().contains( targetColumn ) ) {
13031303
if ( compatibleAssignments == null ) {
13041304
compatibleAssignments = new ArrayList<>( assignments.size() );
13051305
}

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

+53-46
Original file line numberDiff line numberDiff line change
@@ -857,36 +857,57 @@ public List<Assignment> visitSetClause(SqmSetClause setClause) {
857857
final SqmExpression<?> assignmentValue = sqmAssignment.getValue();
858858
final SqmParameter<?> assignmentValueParameter = getSqmParameter( assignmentValue );
859859
final Expression pathSqlExpression = assignedPathInterpretation.getSqlExpression();
860-
final List<? extends Expression> targetColumnReferences =
861-
pathSqlExpression instanceof SqlTuple sqlTuple
862-
? sqlTuple.getExpressions()
860+
//noinspection unchecked
861+
final List<ColumnReference> targetColumnReferences =
862+
pathSqlExpression instanceof SqlTupleContainer sqlTuple
863+
? (List<ColumnReference>) sqlTuple.getSqlTuple().getExpressions()
863864
: pathSqlExpression.getColumnReference().getColumnReferences();
864865
if ( assignmentValueParameter != null ) {
866+
final ArrayList<Expression> expressions = new ArrayList<>( targetColumnReferences.size() );
865867
consumeSqmParameter(
866868
assignmentValueParameter,
867869
assignedPathInterpretation.getExpressionType(),
868-
(index, jdbcParameter) -> addAssignment(
869-
assignments,
870-
aggregateColumnAssignmentHandler,
871-
targetColumnReferences.get( index ),
872-
jdbcParameter
873-
)
870+
(index, jdbcParameter) -> expressions.add( jdbcParameter )
874871
);
875-
}
876-
else if ( assignmentValue instanceof SqmLiteralNull<?> ) {
877-
for ( Expression columnReference : targetColumnReferences ) {
872+
if ( pathSqlExpression instanceof SqlTupleContainer ) {
878873
addAssignment(
879874
assignments,
880875
aggregateColumnAssignmentHandler,
881-
columnReference,
882-
new QueryLiteral<>( null, (BasicValuedMapping) columnReference.getExpressionType() )
876+
(Assignable) assignedPathInterpretation,
877+
targetColumnReferences,
878+
new SqlTuple( expressions, assignedPathInterpretation.getExpressionType() )
883879
);
884880
}
881+
else {
882+
assert expressions.size() == 1;
883+
addAssignment(
884+
assignments,
885+
aggregateColumnAssignmentHandler,
886+
(Assignable) assignedPathInterpretation,
887+
targetColumnReferences,
888+
expressions.get( 0 )
889+
);
890+
}
891+
}
892+
else if ( pathSqlExpression instanceof SqlTupleContainer
893+
&& assignmentValue instanceof SqmLiteralNull<?> ) {
894+
final ArrayList<Expression> expressions = new ArrayList<>( targetColumnReferences.size() );
895+
for ( ColumnReference targetColumnReference : targetColumnReferences ) {
896+
expressions.add( new QueryLiteral<>( null,
897+
(SqlExpressible) targetColumnReference.getExpressionType() ) );
898+
}
899+
addAssignment(
900+
assignments,
901+
aggregateColumnAssignmentHandler,
902+
(Assignable) assignedPathInterpretation,
903+
targetColumnReferences,
904+
new SqlTuple( expressions, assignedPathInterpretation.getExpressionType() )
905+
);
885906
}
886907
else {
887908
addAssignments(
888909
(Expression) assignmentValue.accept( this ),
889-
assignedPathInterpretation.getExpressionType(),
910+
assignedPathInterpretation,
890911
targetColumnReferences,
891912
assignments,
892913
aggregateColumnAssignmentHandler
@@ -908,35 +929,18 @@ else if ( assignmentValue instanceof SqmLiteralNull<?> ) {
908929

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

942946
private void checkAssignment(Expression valueExpression, ModelPart assignedPathType) {
@@ -957,12 +961,15 @@ private void checkAssignment(Expression valueExpression, ModelPart assignedPathT
957961
private void addAssignment(
958962
List<Assignment> assignments,
959963
AggregateColumnAssignmentHandler aggregateColumnAssignmentHandler,
960-
Expression columnReference,
964+
Assignable assignable,
965+
List<ColumnReference> targetColumnReferences,
961966
Expression valueExpression) {
962967
if ( aggregateColumnAssignmentHandler != null ) {
963-
aggregateColumnAssignmentHandler.addAssignment( assignments.size(), (ColumnReference) columnReference );
968+
for ( ColumnReference targetColumnReference : targetColumnReferences ) {
969+
aggregateColumnAssignmentHandler.addAssignment( assignments.size(), targetColumnReference );
970+
}
964971
}
965-
assignments.add( new Assignment( (ColumnReference) columnReference, valueExpression ) );
972+
assignments.add( new Assignment( assignable, valueExpression ) );
966973
}
967974

968975
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

+30
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;

0 commit comments

Comments
 (0)