Skip to content

Commit 74cc07d

Browse files
committed
HHH-17170 Support custom sql mutations for associated collections
1 parent 61d5ab4 commit 74cc07d

File tree

6 files changed

+180
-150
lines changed

6 files changed

+180
-150
lines changed

hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java

Lines changed: 4 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
2727
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
2828
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
29-
import org.hibernate.persister.collection.mutation.CollectionTableMapping;
3029
import org.hibernate.persister.collection.mutation.DeleteRowsCoordinator;
3130
import org.hibernate.persister.collection.mutation.DeleteRowsCoordinatorNoOp;
3231
import org.hibernate.persister.collection.mutation.DeleteRowsCoordinatorStandard;
@@ -44,17 +43,14 @@
4443
import org.hibernate.persister.spi.PersisterCreationContext;
4544
import org.hibernate.sql.ast.SqlAstTranslator;
4645
import org.hibernate.sql.ast.tree.from.TableGroup;
47-
import org.hibernate.sql.model.ast.ColumnValueParameterList;
4846
import org.hibernate.sql.model.ast.MutatingTableReference;
4947
import org.hibernate.sql.model.ast.RestrictedTableMutation;
5048
import org.hibernate.sql.model.ast.TableInsert;
5149
import org.hibernate.sql.model.ast.TableMutation;
52-
import org.hibernate.sql.model.ast.builder.TableDeleteBuilderStandard;
50+
import org.hibernate.sql.model.ast.builder.CollectionRowDeleteBuilder;
5351
import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard;
5452
import org.hibernate.sql.model.ast.builder.TableUpdateBuilderStandard;
55-
import org.hibernate.sql.model.jdbc.JdbcDeleteMutation;
5653
import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
57-
import org.hibernate.sql.model.jdbc.JdbcUpdateMutation;
5854

5955
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
6056

@@ -410,40 +406,6 @@ else if ( attributeMapping.getIndexDescriptor() != null ) {
410406
// Update handling
411407

412408
private JdbcMutationOperation generateUpdateRowOperation(MutatingTableReference tableReference) {
413-
if ( getIdentifierTableMapping().getUpdateDetails().getCustomSql() != null ) {
414-
return buildCustomSqlUpdateRowOperation( tableReference );
415-
}
416-
417-
return buildGeneratedUpdateRowOperation( tableReference );
418-
419-
}
420-
421-
private JdbcMutationOperation buildCustomSqlUpdateRowOperation(MutatingTableReference tableReference) {
422-
final PluralAttributeMapping attribute = getAttributeMapping();
423-
assert attribute != null;
424-
425-
final ForeignKeyDescriptor foreignKey = attribute.getKeyDescriptor();
426-
assert foreignKey != null;
427-
428-
final int keyColumnCount = foreignKey.getJdbcTypeCount();
429-
final ColumnValueParameterList parameterBinders = new ColumnValueParameterList(
430-
tableReference,
431-
ParameterUsage.RESTRICT,
432-
keyColumnCount
433-
);
434-
foreignKey.getKeyPart().forEachSelectable( parameterBinders );
435-
436-
return new JdbcUpdateMutation(
437-
getCollectionTableMapping(),
438-
this,
439-
getCollectionTableMapping().getUpdateDetails().getCustomSql(),
440-
getCollectionTableMapping().getUpdateDetails().isCallable(),
441-
getCollectionTableMapping().getUpdateDetails().getExpectation(),
442-
parameterBinders
443-
);
444-
}
445-
446-
private JdbcMutationOperation buildGeneratedUpdateRowOperation(MutatingTableReference tableReference) {
447409
final RestrictedTableMutation<JdbcMutationOperation> sqlAst = generateUpdateRowAst( tableReference );
448410

449411
final SqlAstTranslator<JdbcMutationOperation> translator = getFactory().getJdbcServices()
@@ -458,6 +420,7 @@ private RestrictedTableMutation<JdbcMutationOperation> generateUpdateRowAst(Muta
458420
final PluralAttributeMapping attribute = getAttributeMapping();
459421
assert attribute != null;
460422

423+
// note that custom sql update row details are handled by TableUpdateBuilderStandard
461424
final TableUpdateBuilderStandard<?> updateBuilder = new TableUpdateBuilderStandard<>(
462425
this,
463426
tableReference,
@@ -620,41 +583,6 @@ private void applyUpdateRowRestrictions(
620583
// Delete handling
621584

622585
private JdbcMutationOperation generateDeleteRowOperation(MutatingTableReference tableReference) {
623-
if ( getIdentifierTableMapping().getDeleteRowDetails().getCustomSql() != null ) {
624-
return buildCustomSqlDeleteRowOperation( tableReference );
625-
}
626-
627-
return buildGeneratedDeleteRowOperation( tableReference );
628-
}
629-
630-
private JdbcMutationOperation buildCustomSqlDeleteRowOperation(MutatingTableReference tableReference) {
631-
final PluralAttributeMapping attribute = getAttributeMapping();
632-
assert attribute != null;
633-
634-
final ForeignKeyDescriptor foreignKey = attribute.getKeyDescriptor();
635-
assert foreignKey != null;
636-
637-
final CollectionTableMapping tableMapping = (CollectionTableMapping) tableReference.getTableMapping();
638-
639-
final int keyColumnCount = foreignKey.getJdbcTypeCount();
640-
final ColumnValueParameterList parameterBinders = new ColumnValueParameterList(
641-
tableReference,
642-
ParameterUsage.RESTRICT,
643-
keyColumnCount
644-
);
645-
foreignKey.getKeyPart().forEachSelectable( parameterBinders );
646-
647-
return new JdbcDeleteMutation(
648-
tableMapping,
649-
this,
650-
tableMapping.getDeleteDetails().getCustomSql(),
651-
tableMapping.getDeleteDetails().isCallable(),
652-
tableMapping.getDeleteDetails().getExpectation(),
653-
parameterBinders
654-
);
655-
}
656-
657-
private JdbcMutationOperation buildGeneratedDeleteRowOperation(MutatingTableReference tableReference) {
658586
final RestrictedTableMutation<JdbcMutationOperation> sqlAst = generateDeleteRowAst( tableReference );
659587

660588
final SqlAstTranslator<JdbcMutationOperation> translator = getFactory().getJdbcServices()
@@ -672,7 +600,8 @@ private RestrictedTableMutation<JdbcMutationOperation> generateDeleteRowAst(Muta
672600
final ForeignKeyDescriptor fkDescriptor = pluralAttribute.getKeyDescriptor();
673601
assert fkDescriptor != null;
674602

675-
final TableDeleteBuilderStandard deleteBuilder = new TableDeleteBuilderStandard(
603+
// note that custom sql delete row details are handled by CollectionRowDeleteBuilder
604+
final CollectionRowDeleteBuilder deleteBuilder = new CollectionRowDeleteBuilder(
676605
this,
677606
tableReference,
678607
getFactory(),

hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java

Lines changed: 5 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
2121
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
2222
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
23-
import org.hibernate.sql.model.internal.MutationOperationGroupFactory;
2423
import org.hibernate.engine.jdbc.mutation.internal.MutationQueryOptions;
2524
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
2625
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@@ -38,7 +37,6 @@
3837
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
3938
import org.hibernate.metamodel.mapping.internal.OneToManyCollectionPart;
4039
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
41-
import org.hibernate.persister.collection.mutation.CollectionTableMapping;
4240
import org.hibernate.persister.collection.mutation.DeleteRowsCoordinator;
4341
import org.hibernate.persister.collection.mutation.DeleteRowsCoordinatorNoOp;
4442
import org.hibernate.persister.collection.mutation.DeleteRowsCoordinatorStandard;
@@ -74,11 +72,11 @@
7472
import org.hibernate.sql.model.ast.MutatingTableReference;
7573
import org.hibernate.sql.model.ast.RestrictedTableMutation;
7674
import org.hibernate.sql.model.ast.TableUpdate;
75+
import org.hibernate.sql.model.ast.builder.CollectionRowDeleteByUpdateSetNullBuilder;
7776
import org.hibernate.sql.model.ast.builder.TableUpdateBuilderStandard;
77+
import org.hibernate.sql.model.internal.MutationOperationGroupFactory;
7878
import org.hibernate.sql.model.internal.TableUpdateStandard;
79-
import org.hibernate.sql.model.jdbc.JdbcDeleteMutation;
8079
import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
81-
import org.hibernate.sql.model.jdbc.JdbcUpdateMutation;
8280

8381
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
8482
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
@@ -518,41 +516,6 @@ && getElementPersisterInternal() instanceof UnionSubclassEntityPersister ) {
518516
}
519517

520518
private JdbcMutationOperation generateDeleteRowOperation(MutatingTableReference tableReference) {
521-
if ( getIdentifierTableMapping().getDeleteRowDetails().getCustomSql() != null ) {
522-
return buildCustomSqlDeleteRowOperation( tableReference );
523-
}
524-
525-
return buildGeneratedDeleteRowOperation( tableReference );
526-
}
527-
528-
private JdbcMutationOperation buildCustomSqlDeleteRowOperation(MutatingTableReference tableReference) {
529-
final PluralAttributeMapping attribute = getAttributeMapping();
530-
assert attribute != null;
531-
532-
final ForeignKeyDescriptor foreignKey = attribute.getKeyDescriptor();
533-
assert foreignKey != null;
534-
535-
final CollectionTableMapping tableMapping = (CollectionTableMapping) tableReference.getTableMapping();
536-
537-
final int keyColumnCount = foreignKey.getJdbcTypeCount();
538-
final ColumnValueParameterList parameterBinders = new ColumnValueParameterList(
539-
tableReference,
540-
ParameterUsage.RESTRICT,
541-
keyColumnCount
542-
);
543-
foreignKey.getKeyPart().forEachSelectable( parameterBinders );
544-
545-
return new JdbcDeleteMutation(
546-
tableMapping,
547-
this,
548-
tableMapping.getDeleteDetails().getCustomSql(),
549-
tableMapping.getDeleteDetails().isCallable(),
550-
tableMapping.getDeleteDetails().getExpectation(),
551-
parameterBinders
552-
);
553-
}
554-
555-
private JdbcMutationOperation buildGeneratedDeleteRowOperation(MutatingTableReference tableReference) {
556519
final RestrictedTableMutation<JdbcMutationOperation> sqlAst = generateDeleteRowAst( tableReference );
557520

558521
final SqlAstTranslator<JdbcMutationOperation> translator = getFactory().getJdbcServices()
@@ -564,7 +527,8 @@ private JdbcMutationOperation buildGeneratedDeleteRowOperation(MutatingTableRefe
564527
}
565528

566529
public RestrictedTableMutation<JdbcMutationOperation> generateDeleteRowAst(MutatingTableReference tableReference) {
567-
final TableUpdateBuilderStandard<MutationOperation> updateBuilder = new TableUpdateBuilderStandard<>(
530+
// note that custom sql delete row details are handled by CollectionRowUpdateBuilder
531+
final CollectionRowDeleteByUpdateSetNullBuilder<MutationOperation> updateBuilder = new CollectionRowDeleteByUpdateSetNullBuilder<>(
568532
this,
569533
tableReference,
570534
getFactory(),
@@ -732,41 +696,7 @@ private void applyInsertRowValues(
732696

733697

734698
private JdbcMutationOperation generateWriteIndexOperation(MutatingTableReference tableReference) {
735-
if ( getIdentifierTableMapping().getUpdateDetails().getCustomSql() != null ) {
736-
return buildCustomSqlWriteIndexOperation( tableReference );
737-
}
738-
739-
return buildGeneratedWriteIndexOperation( tableReference );
740-
}
741-
742-
private JdbcMutationOperation buildCustomSqlWriteIndexOperation(MutatingTableReference tableReference) {
743-
final PluralAttributeMapping attribute = getAttributeMapping();
744-
assert attribute != null;
745-
746-
final ForeignKeyDescriptor foreignKey = attribute.getKeyDescriptor();
747-
assert foreignKey != null;
748-
749-
final CollectionTableMapping tableMapping = (CollectionTableMapping) tableReference.getTableMapping();
750-
751-
final int keyColumnCount = foreignKey.getJdbcTypeCount();
752-
final ColumnValueParameterList parameterBinders = new ColumnValueParameterList(
753-
tableReference,
754-
ParameterUsage.RESTRICT,
755-
keyColumnCount
756-
);
757-
foreignKey.getKeyPart().forEachSelectable( parameterBinders );
758-
759-
return new JdbcUpdateMutation(
760-
tableMapping,
761-
this,
762-
tableMapping.getUpdateDetails().getCustomSql(),
763-
tableMapping.getUpdateDetails().isCallable(),
764-
tableMapping.getUpdateDetails().getExpectation(),
765-
parameterBinders
766-
);
767-
}
768-
769-
private JdbcMutationOperation buildGeneratedWriteIndexOperation(MutatingTableReference tableReference) {
699+
// note that custom sql update details are handled by TableUpdateBuilderStandard
770700
final TableUpdateBuilderStandard<JdbcMutationOperation> updateBuilder = new TableUpdateBuilderStandard<>(
771701
this,
772702
tableReference,
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.sql.model.ast.builder;
8+
9+
import org.hibernate.engine.spi.SessionFactoryImplementor;
10+
import org.hibernate.jdbc.Expectation;
11+
import org.hibernate.persister.collection.mutation.CollectionTableMapping;
12+
import org.hibernate.sql.model.MutationTarget;
13+
import org.hibernate.sql.model.ast.MutatingTableReference;
14+
import org.hibernate.sql.model.ast.TableDelete;
15+
import org.hibernate.sql.model.internal.TableDeleteCustomSql;
16+
import org.hibernate.sql.model.internal.TableDeleteStandard;
17+
18+
/**
19+
* Custom table delete builder for many-to-many collection join tables that handles row deletes
20+
*
21+
* @author Marco Belladelli
22+
*/
23+
public class CollectionRowDeleteBuilder extends TableDeleteBuilderStandard {
24+
public CollectionRowDeleteBuilder(
25+
MutationTarget<?> mutationTarget,
26+
MutatingTableReference tableReference,
27+
SessionFactoryImplementor sessionFactory,
28+
String whereFragment) {
29+
super( mutationTarget, tableReference, sessionFactory, whereFragment );
30+
assert tableReference.getTableMapping() instanceof CollectionTableMapping;
31+
}
32+
33+
@Override
34+
public TableDelete buildMutation() {
35+
final CollectionTableMapping tableMapping = (CollectionTableMapping) getMutatingTable().getTableMapping();
36+
if ( tableMapping.getDeleteRowDetails().getCustomSql() != null ) {
37+
return new TableDeleteCustomSql(
38+
getMutatingTable(),
39+
getMutationTarget(),
40+
getSqlComment(),
41+
getKeyRestrictionBindings(),
42+
getOptimisticLockBindings(),
43+
getParameters()
44+
) {
45+
@Override
46+
public String getCustomSql() {
47+
return tableMapping.getDeleteRowDetails().getCustomSql();
48+
}
49+
50+
@Override
51+
public boolean isCallable() {
52+
return tableMapping.getDeleteRowDetails().isCallable();
53+
}
54+
55+
@Override
56+
public Expectation getExpectation() {
57+
return tableMapping.getDeleteRowDetails().getExpectation();
58+
}
59+
};
60+
}
61+
return new TableDeleteStandard(
62+
getMutatingTable(),
63+
getMutationTarget(),
64+
getSqlComment(),
65+
getKeyRestrictionBindings(),
66+
getOptimisticLockBindings(),
67+
getParameters(),
68+
getWhereFragment()
69+
) {
70+
@Override
71+
public Expectation getExpectation() {
72+
return tableMapping.getDeleteRowDetails().getExpectation();
73+
}
74+
};
75+
}
76+
}

0 commit comments

Comments
 (0)