From 3894573b067a80c9d035428b828372a96e18cec2 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 5 Nov 2024 10:24:18 +0100 Subject: [PATCH] Fix a bunch of issues encountered with ORM 6 --- CHANGELOG.md | 4 +- .../impl/ResolvingQueryGenerator.java | 2 +- .../OracleToStringJsonFunction.java | 3 +- .../PostgreSQLToStringJsonFunction.java | 3 +- .../PostgreSQLToStringXmlFunction.java | 3 +- core/testsuite-hibernate/pom.xml | 32 +- .../entity/IntegerProperty.java | 2 +- .../entity/Property.java | 2 +- .../entity/PropertyHolder.java | 2 +- .../entity/StringProperty.java | 2 +- .../testsuite/hibernate/AnyMappingTest.java | 2 +- .../view/processor/ClassWriter.java | 4 +- .../persistence/view/processor/Context.java | 6 +- entity-view/testsuite/pom.xml | 1 + .../AbstractEntityViewRemoveDocumentTest.java | 7 +- ...pdateSubviewInverseOneToOneEntityTest.java | 3 +- .../base/HibernateExtendedQuerySupport.java | 493 ++++++++++-------- .../hibernate/base/HibernateJpaProvider.java | 2 +- parent/pom.xml | 2 +- 19 files changed, 328 insertions(+), 247 deletions(-) rename core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/{hibernate6 => hibernate}/entity/IntegerProperty.java (93%) rename core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/{hibernate6 => hibernate}/entity/Property.java (69%) rename core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/{hibernate6 => hibernate}/entity/PropertyHolder.java (95%) rename core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/{hibernate6 => hibernate}/entity/StringProperty.java (93%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c97654dc0..468fc53ff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ None yet ### Bug fixes -None yet +* Fix missing cascading deletes for deletes that contain joins or CTEs +* Fix some issues with PostgreSQL and Oracle multiset SQL rendering with Hibernate ORM 6+ +* Fix returning clause rendering for PostgreSQL with Hibernate ORM 6+ ### Backwards-incompatible changes diff --git a/core/impl/src/main/java/com/blazebit/persistence/impl/ResolvingQueryGenerator.java b/core/impl/src/main/java/com/blazebit/persistence/impl/ResolvingQueryGenerator.java index 42bf21cfd5..de2842bff7 100644 --- a/core/impl/src/main/java/com/blazebit/persistence/impl/ResolvingQueryGenerator.java +++ b/core/impl/src/main/java/com/blazebit/persistence/impl/ResolvingQueryGenerator.java @@ -950,7 +950,7 @@ private void renderEquality(Expression left, Expression right, boolean negated, rewriteToIdParam(right); } } else { - if (expressionToSplit == null || dbmsDialect.supportsAnsiRowValueConstructor() || !(left instanceof ParameterExpression) && !(right instanceof ParameterExpression)) { + if (expressionToSplit == null || !(left instanceof ParameterExpression) && !(right instanceof ParameterExpression)) { left.accept(this); sb.append(operator); if (quantifier != PredicateQuantifier.ONE) { diff --git a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/OracleToStringJsonFunction.java b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/OracleToStringJsonFunction.java index c2e44130a2..40c1fe5fb0 100644 --- a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/OracleToStringJsonFunction.java +++ b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/OracleToStringJsonFunction.java @@ -38,8 +38,7 @@ public void render(FunctionRenderContext context, String[] fields, String[] sele context.addChunk(postChunk); context.addChunk(subquery.substring(fromIndex)); } else { - int limitIndex = SqlUtils.indexOfLimit(subquery, orderByIndex); - if (limitIndex == -1) { + if (SqlUtils.indexOfLimit(subquery, orderByIndex) == -1 && SqlUtils.indexOfFetchFirst(subquery, orderByIndex) == -1) { context.addChunk(preChunk); StringBuilder sb = new StringBuilder(fromIndex); diff --git a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/PostgreSQLToStringJsonFunction.java b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/PostgreSQLToStringJsonFunction.java index 8a0fefca71..dde6fc1696 100644 --- a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/PostgreSQLToStringJsonFunction.java +++ b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringjson/PostgreSQLToStringJsonFunction.java @@ -26,8 +26,7 @@ public void render(FunctionRenderContext context, String[] fields, String[] sele context.addChunk("))"); context.addChunk(subquery.substring(fromIndex)); } else { - int limitIndex = SqlUtils.indexOfLimit(subquery, orderByIndex); - if (limitIndex == -1) { + if (SqlUtils.indexOfLimit(subquery, orderByIndex) == -1 && SqlUtils.indexOfFetchFirst(subquery, orderByIndex) == -1) { renderJsonObjectArguments(context, fields, selectItemExpressions); context.addChunk("))"); context.addChunk(" OVER ("); diff --git a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringxml/PostgreSQLToStringXmlFunction.java b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringxml/PostgreSQLToStringXmlFunction.java index d88768c7c5..df7851f706 100644 --- a/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringxml/PostgreSQLToStringXmlFunction.java +++ b/core/impl/src/main/java/com/blazebit/persistence/impl/function/tostringxml/PostgreSQLToStringXmlFunction.java @@ -26,8 +26,7 @@ public void render(FunctionRenderContext context, String[] fields, String[] sele context.addChunk("))"); context.addChunk(subquery.substring(fromIndex)); } else { - int limitIndex = SqlUtils.indexOfLimit(subquery, orderByIndex); - if (limitIndex == -1) { + if (SqlUtils.indexOfLimit(subquery, orderByIndex) == -1 && SqlUtils.indexOfFetchFirst(subquery, orderByIndex) == -1) { renderXmlElementArguments(context, fields, selectItemExpressions); context.addChunk("))"); context.addChunk(" OVER ("); diff --git a/core/testsuite-hibernate/pom.xml b/core/testsuite-hibernate/pom.xml index 9197e9d580..0914275eff 100644 --- a/core/testsuite-hibernate/pom.xml +++ b/core/testsuite-hibernate/pom.xml @@ -13,7 +13,7 @@ com.blazebit.persistence.core.testsuite.hibernate - com.blazebit.persistence.testsuite + com.blazebit.persistence.testsuite.hibernate 0 @@ -634,5 +634,35 @@ + + + hibernate-apt + + + + maven-compiler-plugin + + true + true + + + + + + + + eclipselink + + + + maven-compiler-plugin + + true + true + + + + + diff --git a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/IntegerProperty.java b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/IntegerProperty.java similarity index 93% rename from core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/IntegerProperty.java rename to core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/IntegerProperty.java index fb1590cbb2..80b894d573 100644 --- a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/IntegerProperty.java +++ b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/IntegerProperty.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Blazebit */ -package com.blazebit.persistence.testsuite.hibernate6.entity; +package com.blazebit.persistence.testsuite.hibernate.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; diff --git a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/Property.java b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/Property.java similarity index 69% rename from core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/Property.java rename to core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/Property.java index 0642001176..f09bf115ff 100644 --- a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/Property.java +++ b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/Property.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Blazebit */ -package com.blazebit.persistence.testsuite.hibernate6.entity; +package com.blazebit.persistence.testsuite.hibernate.entity; public interface Property { diff --git a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/PropertyHolder.java b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/PropertyHolder.java similarity index 95% rename from core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/PropertyHolder.java rename to core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/PropertyHolder.java index ce28991a94..2a0fa10966 100644 --- a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/PropertyHolder.java +++ b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/PropertyHolder.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Blazebit */ -package com.blazebit.persistence.testsuite.hibernate6.entity; +package com.blazebit.persistence.testsuite.hibernate.entity; import jakarta.persistence.Column; import jakarta.persistence.DiscriminatorType; diff --git a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/StringProperty.java b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/StringProperty.java similarity index 93% rename from core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/StringProperty.java rename to core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/StringProperty.java index 232b1b7fbc..fc98840bd5 100644 --- a/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate6/entity/StringProperty.java +++ b/core/testsuite-hibernate/src/main/java/com/blazebit/persistence/testsuite/hibernate/entity/StringProperty.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Blazebit */ -package com.blazebit.persistence.testsuite.hibernate6.entity; +package com.blazebit.persistence.testsuite.hibernate.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; diff --git a/core/testsuite-hibernate/src/test/java/com/blazebit/persistence/testsuite/hibernate/AnyMappingTest.java b/core/testsuite-hibernate/src/test/java/com/blazebit/persistence/testsuite/hibernate/AnyMappingTest.java index 46726c751d..f9a6e80c1e 100644 --- a/core/testsuite-hibernate/src/test/java/com/blazebit/persistence/testsuite/hibernate/AnyMappingTest.java +++ b/core/testsuite-hibernate/src/test/java/com/blazebit/persistence/testsuite/hibernate/AnyMappingTest.java @@ -6,7 +6,7 @@ import com.blazebit.persistence.CriteriaBuilder; import com.blazebit.persistence.testsuite.AbstractCoreTest; -import com.blazebit.persistence.testsuite.hibernate6.entity.PropertyHolder; +import com.blazebit.persistence.testsuite.hibernate.entity.PropertyHolder; import org.junit.jupiter.api.Test; import static org.junit.Assert.assertTrue; diff --git a/entity-view/processor/src/main/java/com/blazebit/persistence/view/processor/ClassWriter.java b/entity-view/processor/src/main/java/com/blazebit/persistence/view/processor/ClassWriter.java index 305e5fe157..b45e1aed9c 100644 --- a/entity-view/processor/src/main/java/com/blazebit/persistence/view/processor/ClassWriter.java +++ b/entity-view/processor/src/main/java/com/blazebit/persistence/view/processor/ClassWriter.java @@ -135,9 +135,9 @@ public static String writeGeneratedAnnotation(ImportContext importContext, Conte public static void writeGeneratedAnnotation(StringBuilder generatedAnnotation, ImportContext importContext, Context context) { generatedAnnotation.append("@"); if (importContext == null) { - generatedAnnotation.append(context.getGeneratedAnnotation().getQualifiedName().toString()); + generatedAnnotation.append(context.getGeneratedAnnotation()); } else { - generatedAnnotation.append(importContext.importType(context.getGeneratedAnnotation().getQualifiedName().toString())); + generatedAnnotation.append(importContext.importType(context.getGeneratedAnnotation())); } generatedAnnotation.append("(value = \"") .append(EntityViewAnnotationProcessor.class.getName()); diff --git a/entity-view/processor/src/main/java/com/blazebit/persistence/view/processor/Context.java b/entity-view/processor/src/main/java/com/blazebit/persistence/view/processor/Context.java index 5a0ffff264..64a7b11d38 100644 --- a/entity-view/processor/src/main/java/com/blazebit/persistence/view/processor/Context.java +++ b/entity-view/processor/src/main/java/com/blazebit/persistence/view/processor/Context.java @@ -43,7 +43,7 @@ public class Context { private static final Object NULL_OBJECT = new Object(); private final ProcessingEnvironment pe; private final boolean logDebug; - private final TypeElement generatedAnnotation; + private final String generatedAnnotation; private final Map metaEntityViews = new ConcurrentHashMap<>(); private final ConcurrentMap generatedModelClasses = new ConcurrentHashMap<>(); @@ -73,7 +73,7 @@ public Context(ProcessingEnvironment pe) { Map optionalParameters = new HashMap<>(); Map> converters = new HashMap<>(); - generatedAnnotation = pe.getElementUtils().getTypeElement("javax.annotation.processing.Generated"); + generatedAnnotation = "javax.annotation.processing.Generated"; for (TypeConverter typeConverter : ServiceLoader.load(TypeConverter.class, Context.class.getClassLoader())) { typeConverter.addRegistrations(converters); } @@ -195,7 +195,7 @@ public boolean markGenerated(String name) { return generatedModelClasses.putIfAbsent(name, Boolean.TRUE) == null; } - public TypeElement getGeneratedAnnotation() { + public String getGeneratedAnnotation() { return generatedAnnotation; } diff --git a/entity-view/testsuite/pom.xml b/entity-view/testsuite/pom.xml index f072adfa95..6b7cd58f96 100644 --- a/entity-view/testsuite/pom.xml +++ b/entity-view/testsuite/pom.xml @@ -891,6 +891,7 @@ -AstrictCascadingCheck=false -AdefaultVersionAttributeName=version -AdefaultVersionAttributeType=java.lang.Long + -AaddGeneratedAnnotation=false org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor diff --git a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/remove/cascade/AbstractEntityViewRemoveDocumentTest.java b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/remove/cascade/AbstractEntityViewRemoveDocumentTest.java index f5b2a4a3a0..8160a3e061 100644 --- a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/remove/cascade/AbstractEntityViewRemoveDocumentTest.java +++ b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/remove/cascade/AbstractEntityViewRemoveDocumentTest.java @@ -205,6 +205,9 @@ protected AssertStatementBuilder deleteDocumentOwned(AssertStatementBuilder buil .assertDelete().forRelation(Document.class, "peopleListBag").and() .assertDelete().forRelation(Document.class, "peopleCollectionBag").and(); } + if (isQueryStrategy() && !simpleDelete && dbmsDialect.supportsModificationQueryInWithClause()) { + return builder; + } if (supportsNestedEmbeddables()) { builder .assertDelete().forRelation(Document.class, "nameContainerMap").and() @@ -228,7 +231,9 @@ protected AssertStatementBuilder deletePersonOwned(AssertStatementBuilder builde .assertDelete().forRelation(Person.class, "favoriteDocuments").and() ; } - + if (isQueryStrategy() && !simpleDelete && dbmsDialect.supportsModificationQueryInWithClause()) { + return builder; + } return builder .assertDelete().forRelation(Person.class, "localized").and() ; diff --git a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/onetoone/entity/EntityViewUpdateSubviewInverseOneToOneEntityTest.java b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/onetoone/entity/EntityViewUpdateSubviewInverseOneToOneEntityTest.java index 7f72397d45..e9e67a94f3 100644 --- a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/onetoone/entity/EntityViewUpdateSubviewInverseOneToOneEntityTest.java +++ b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/onetoone/entity/EntityViewUpdateSubviewInverseOneToOneEntityTest.java @@ -13,6 +13,7 @@ import com.blazebit.persistence.testsuite.base.jpa.assertion.AssertStatementBuilder; import com.blazebit.persistence.testsuite.base.jpa.category.NoEclipselink; +import com.blazebit.persistence.testsuite.base.jpa.category.NoHibernate; import com.blazebit.persistence.testsuite.entity.Document; import com.blazebit.persistence.testsuite.entity.DocumentForSimpleOneToOne; import com.blazebit.persistence.testsuite.entity.DocumentInfoSimple; @@ -32,7 +33,7 @@ */ @RunWith(Parameterized.class) // NOTE: Hibernate has a bug when selecting inverse one-to-ones: https://hibernate.atlassian.net/browse/HHH-12885 -@Category({ NoEclipselink.class}) +@Category({ NoHibernate.class, NoEclipselink.class}) public class EntityViewUpdateSubviewInverseOneToOneEntityTest extends AbstractEntityViewUpdateTest { private DocumentForSimpleOneToOne doc1; diff --git a/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateExtendedQuerySupport.java b/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateExtendedQuerySupport.java index 31a9e8d1e9..af942014cf 100644 --- a/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateExtendedQuerySupport.java +++ b/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateExtendedQuerySupport.java @@ -21,17 +21,23 @@ import org.hibernate.HibernateException; import org.hibernate.NonUniqueResultException; import org.hibernate.ScrollMode; +import org.hibernate.action.internal.BulkOperationCleanupAction; +import org.hibernate.dialect.DmlTargetColumnQualifierSupport; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.internal.FilterJdbcParameter; +import org.hibernate.internal.util.MutableObject; import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.BoundedConcurrentHashMap; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.MappingModelExpressible; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; +import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.IllegalQueryOperationException; import org.hibernate.query.TupleTransformer; @@ -58,6 +64,7 @@ import org.hibernate.query.sqm.sql.SqmTranslation; import org.hibernate.query.sqm.sql.SqmTranslator; import org.hibernate.query.sqm.sql.SqmTranslatorFactory; +import org.hibernate.query.sqm.tree.SqmDmlStatement; import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.expression.SqmParameter; @@ -81,12 +88,16 @@ import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.delete.DeleteStatement; +import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.from.CollectionTableGroup; import org.hibernate.sql.ast.tree.from.LazyTableGroup; +import org.hibernate.sql.ast.tree.from.MutatingTableReferenceGroupWrapper; import org.hibernate.sql.ast.tree.from.NamedTableReference; import org.hibernate.sql.ast.tree.from.TableGroup; +import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; import org.hibernate.sql.ast.tree.insert.InsertStatement; +import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; @@ -108,6 +119,7 @@ import org.hibernate.sql.results.internal.RowTransformerSingularReturnImpl; import org.hibernate.sql.results.internal.RowTransformerStandardImpl; import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter; +import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.TupleMetadata; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping; import org.hibernate.sql.results.spi.ListResultsConsumer; @@ -131,6 +143,7 @@ import java.util.Spliterator; import java.util.Spliterators; import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.logging.Logger; import java.util.stream.Stream; @@ -214,11 +227,7 @@ public String getSql(EntityManager em, Query query) { QuerySqmImpl hqlQuery = query.unwrap(QuerySqmImpl.class); SessionFactoryImplementor factory = hqlQuery.getSessionFactory(); CacheableSqmInterpretation interpretation = buildQueryPlan(query); - try { - return getJdbcOperation(factory, interpretation, hqlQuery).getSqlString(); - } finally { - interpretation.domainParameterXref.clearExpansions(); - } + return getJdbcOperation(factory, interpretation, hqlQuery).getSqlString(); } @Override @@ -228,43 +237,205 @@ public boolean getSqlContainsLimit() { @Override public List getCascadingDeleteSql(EntityManager em, Query query) { - SessionFactoryImplementor sfi = em.unwrap(SessionImplementor.class).getSessionFactory(); QuerySqmImpl hqlQuery = query.unwrap(QuerySqmImpl.class); if (hqlQuery.getSqmStatement() instanceof SqmDeleteStatement) { - SqmDeleteStatement deleteStatement = (SqmDeleteStatement) hqlQuery.getSqmStatement(); - String mutatingEntityName = deleteStatement.getTarget().getModel().getHibernateEntityName(); - EntityMappingType entityDescriptor = sfi.getMappingMetamodel().getEntityDescriptor(mutatingEntityName); - SqlAstTranslatorFactory sqlAstTranslatorFactory = sfi.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory(); - List deleteSqls = new ArrayList<>(); - entityDescriptor.visitConstraintOrderedTables( - (tableExpression, tableKeyColumnsVisitationSupplier) -> { - - // final TableReference targetTableReference = new TableReference( - // tableExpression, - // null, - // false, - // sfi - // ); - - final Predicate matchingIdsPredicate = null;//new InSubQueryPredicate(); - // matchingIdsPredicateProducer.produceRestriction( - // ids, - // entityDescriptor, - // targetTableReference, - // tableKeyColumnsVisitationSupplier, - // query - // ); - - // final SqlAstDeleteTranslator sqlAstTranslator = sqlAstTranslatorFactory.buildDeleteTranslator( sfi ); - // final JdbcDelete jdbcOperation = sqlAstTranslator.translate( new DeleteStatement( targetTableReference, matchingIdsPredicate ) ); - } - ); + List deletes = getCollectionTableDeletes( hqlQuery ).deletes; + + List deleteSqls = new ArrayList<>( deletes.size() ); + for ( JdbcOperationQueryMutation delete : deletes ) { + deleteSqls.add( delete.getSqlString() ); + } return deleteSqls; } return Collections.EMPTY_LIST; } + private static class CollectionTableDeleteInfo { + private final List deletes; + private final JdbcParameterBindings parameterBindings; + + public CollectionTableDeleteInfo( + List deletes, + JdbcParameterBindings parameterBindings) { + this.deletes = deletes; + this.parameterBindings = parameterBindings; + } + } + + private static CollectionTableDeleteInfo getCollectionTableDeletes(QuerySqmImpl hqlQuery) { + SessionFactoryImplementor sfi = hqlQuery.getSessionFactory(); + SqmDeleteStatement deleteStatement = (SqmDeleteStatement) hqlQuery.getSqmStatement(); + String mutatingEntityName = deleteStatement.getTarget().getModel().getHibernateEntityName(); + EntityMappingType entityDescriptor = sfi.getMappingMetamodel().getEntityDescriptor(mutatingEntityName); + + CacheableSqmInterpretation sqmInterpretation = buildQueryPlan( hqlQuery ); + + Map, Map, List>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref( + hqlQuery.getDomainParameterXref(), + sqmInterpretation.getSqmTranslation()::getJdbcParamsBySqmParam + ); + + final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings( + hqlQuery.getQueryParameterBindings(), + hqlQuery.getDomainParameterXref(), + jdbcParamsXref, + sfi.getRuntimeMetamodels().getMappingMetamodel(), + sqmInterpretation.getSqmTranslation().getFromClauseAccess()::findTableGroup, + new SqmParameterMappingModelResolutionAccess() { + @Override @SuppressWarnings("unchecked") + public MappingModelExpressible getResolvedMappingModelType(SqmParameter parameter) { + return (MappingModelExpressible) sqmInterpretation.getSqmTranslation().getSqmParameterMappingModelTypeResolutions().get(parameter); + } + }, + hqlQuery.getSession() + ); + hqlQuery.getDomainParameterXref().clearExpansions(); + DeleteStatement sqlAst = (DeleteStatement) sqmInterpretation.getSqmTranslation().getSqlAst(); + final boolean missingRestriction = sqlAst.getRestriction() == null; + return new CollectionTableDeleteInfo( getCollectionTableDeletes( + entityDescriptor, + (tableReference, attributeMapping) -> { + final TableGroup collectionTableGroup = new MutatingTableReferenceGroupWrapper( + new NavigablePath( attributeMapping.getRootPathName() ), + attributeMapping, + (NamedTableReference) tableReference + ); + + final MutableObject additionalPredicate = new MutableObject<>(); + attributeMapping.getCollectionDescriptor().applyBaseRestrictions( + p -> additionalPredicate.set( Predicate.combinePredicates( additionalPredicate.get(), p ) ), + collectionTableGroup, + sfi.getJdbcServices().getDialect().getDmlTargetColumnQualifierSupport() == DmlTargetColumnQualifierSupport.TABLE_ALIAS, + hqlQuery.getSession().getLoadQueryInfluencers().getEnabledFilters(), + null, + null + ); + + if ( missingRestriction ) { + return additionalPredicate.get(); + } + + final ForeignKeyDescriptor fkDescriptor = attributeMapping.getKeyDescriptor(); + final Expression fkColumnExpression = MappingModelCreationHelper.buildColumnReferenceExpression( + collectionTableGroup, + fkDescriptor.getKeyPart(), + null, + sfi + ); + + final QuerySpec matchingIdSubQuery = new QuerySpec( false ); + + final MutatingTableReferenceGroupWrapper tableGroup = new MutatingTableReferenceGroupWrapper( + new NavigablePath( attributeMapping.getRootPathName() ), + attributeMapping, + sqlAst.getTargetTable() + ); + final Expression fkTargetColumnExpression = MappingModelCreationHelper.buildColumnReferenceExpression( + tableGroup, + fkDescriptor.getTargetPart(), + sqmInterpretation.getSqmTranslation().getSqlExpressionResolver(), + sfi + ); + matchingIdSubQuery.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, fkTargetColumnExpression ) ); + + matchingIdSubQuery.getFromClause().addRoot( + tableGroup + ); + + matchingIdSubQuery.applyPredicate( sqlAst.getRestriction() ); + + return Predicate.combinePredicates( + additionalPredicate.get(), + new InSubQueryPredicate( fkColumnExpression, matchingIdSubQuery, false ) + ); + }, + jdbcParameterBindings, + SqmJdbcExecutionContextAdapter.usingLockingAndPaging( hqlQuery ) + ), jdbcParameterBindings); + } + + private static List getCollectionTableDeletes( + EntityMappingType entityDescriptor, + BiFunction restrictionProducer, + JdbcParameterBindings jdbcParameterBindings, + ExecutionContext executionContext) { + List pluralAttributeMappings = collectCollectionTables( entityDescriptor ); + List deletes = new ArrayList<>( pluralAttributeMappings.size() ); + for ( PluralAttributeMapping attributeMapping : pluralAttributeMappings ) { + final String separateCollectionTable = attributeMapping.getSeparateCollectionTable(); + + final SessionFactoryImplementor sessionFactory = executionContext.getSession().getFactory(); + final JdbcServices jdbcServices = sessionFactory.getJdbcServices(); + + final NamedTableReference tableReference = new NamedTableReference( + separateCollectionTable, + DeleteStatement.DEFAULT_ALIAS, + true + ); + + final DeleteStatement sqlAstDelete = new DeleteStatement( + tableReference, + restrictionProducer.apply( tableReference, attributeMapping ) + ); + + deletes.add( jdbcServices.getJdbcEnvironment() + .getSqlAstTranslatorFactory() + .buildDeleteTranslator( sessionFactory, sqlAstDelete ) + .translate( jdbcParameterBindings, executionContext.getQueryOptions() ) + ); + } + return deletes; + } + + private static List collectCollectionTables(EntityMappingType entityDescriptor) { + List pluralAttributeMappings = new ArrayList<>(); + collectCollectionTables( entityDescriptor, pluralAttributeMappings ); + return pluralAttributeMappings; + } + + private static void collectCollectionTables(EntityMappingType entityDescriptor, List pluralAttributeMappings) { + if ( ! entityDescriptor.getEntityPersister().hasCollections() ) { + // none to clean-up + return; + } + + entityDescriptor.visitSubTypeAttributeMappings( + attributeMapping -> { + if ( attributeMapping instanceof PluralAttributeMapping ) { + PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping; + if (pluralAttributeMapping.getSeparateCollectionTable() != null) { + pluralAttributeMappings.add( pluralAttributeMapping ); + } + } else if ( attributeMapping instanceof EmbeddedAttributeMapping ) { + collectCollectionTables( + (EmbeddedAttributeMapping) attributeMapping, + pluralAttributeMappings + ); + } + } + ); + } + + private static void collectCollectionTables(EmbeddedAttributeMapping attributeMapping, List pluralAttributeMappings) { + attributeMapping.visitSubParts( + modelPart -> { + if ( modelPart instanceof PluralAttributeMapping ) { + PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping; + if (pluralAttributeMapping.getSeparateCollectionTable() != null) { + pluralAttributeMappings.add( pluralAttributeMapping ); + } + } else if ( modelPart instanceof EmbeddedAttributeMapping ) { + collectCollectionTables( + (EmbeddedAttributeMapping) modelPart, + pluralAttributeMappings + ); + } + }, + null + ); + } + @Override public String getSqlAlias(EntityManager em, Query query, String alias, int queryPartNumber) { QuerySqmImpl hqlQuery = query.unwrap(QuerySqmImpl.class); @@ -280,6 +451,7 @@ public String getSqlAlias(EntityManager em, Query query, String alias, int query NavigablePath navigablePath = findNavigablePath(alias, querySpec); CacheableSqmInterpretation interpretation = buildQuerySpecPlan(query); + interpretation.domainParameterXref.clearExpansions(); TableGroup tableGroup = getTableGroup(interpretation, navigablePath); return tableGroup.getPrimaryTableReference().getIdentificationVariable(); } @@ -309,12 +481,7 @@ public SqlFromInfo getSqlFromInfo(EntityManager em, Query query, String alias, i // Note that it is important, this interpretation does not come from a cache, // otherwise bad things will happen due to this mutation primaryTableReference.setPrunedTableExpression(primaryTableReference.getTableId() + "/**/"); - String sql; - try { - sql = getJdbcOperation(sfi, interpretation, hqlQuery).getSqlString(); - } finally { - interpretation.domainParameterXref.clearExpansions(); - } + String sql = getJdbcOperation(sfi, interpretation, hqlQuery).getSqlString(); int startIndex = sql.indexOf(fakeFromText); int endIndex = startIndex + fromText.length(); return new SqlFromInfo() { @@ -513,7 +680,8 @@ private List getResultList(com.blazebit.persistence.spi.ServiceProvider serviceP final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(0); for (Query participatingQuery : participatingQueries) { CacheableSqmInterpretation interpretation = buildQueryPlan(participatingQuery); - JdbcOperationQuery jdbcOperation = getJdbcOperation(sessionFactory, interpretation, participatingQuery.unwrap(QuerySqmImpl.class)); + JdbcTranslation translation = getJdbcTranslation(sessionFactory, interpretation, participatingQuery.unwrap(QuerySqmImpl.class)); + JdbcOperationQuery jdbcOperation = translation.query; if (query == participatingQuery) { // Don't copy over the limit and offset parameters because we need to use the LimitHandler for now JdbcOperationQuerySelect select = (JdbcOperationQuerySelect) jdbcOperation; @@ -527,26 +695,7 @@ private List getResultList(com.blazebit.persistence.spi.ServiceProvider serviceP } affectedTableNames.addAll(jdbcOperation.getAffectedTableNames()); filterJdbcParameters.addAll(jdbcOperation.getFilterJdbcParameters()); - final Map, Map, List>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref( - interpretation.domainParameterXref, - interpretation.getSqmTranslation()::getJdbcParamsBySqmParam - ); - - final JdbcParameterBindings tempJdbcParameterBindings = SqmUtil.createJdbcParameterBindings( - participatingQuery.unwrap(QuerySqmImpl.class).getQueryParameterBindings(), - interpretation.domainParameterXref, - jdbcParamsXref, - session.getFactory().getRuntimeMetamodels().getMappingMetamodel(), - interpretation.tableGroupAccess::findTableGroup, - new SqmParameterMappingModelResolutionAccess() { - @Override - @SuppressWarnings("unchecked") - public MappingModelExpressible getResolvedMappingModelType(SqmParameter parameter) { - return (MappingModelExpressible) interpretation.sqmTranslation.getSqmParameterMappingModelTypeResolutions().get(parameter); - } - }, - session - ); + final JdbcParameterBindings tempJdbcParameterBindings = translation.parameterBindings; if (!tempJdbcParameterBindings.getBindings().isEmpty()) { tempJdbcParameterBindings.visitBindings(jdbcParameterBindings::addBinding); } @@ -632,30 +781,12 @@ private Object getResultStream(com.blazebit.persistence.spi.ServiceProvider serv final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(0); for (Query participatingQuery : participatingQueries) { CacheableSqmInterpretation interpretation = buildQueryPlan(participatingQuery); - JdbcOperationQuery jdbcOperation = getJdbcOperation(sessionFactory, interpretation, participatingQuery.unwrap(QuerySqmImpl.class)); + JdbcTranslation translation = getJdbcTranslation(sessionFactory, interpretation, participatingQuery.unwrap(QuerySqmImpl.class)); + JdbcOperationQuery jdbcOperation = translation.query; parameterBinders.addAll(jdbcOperation.getParameterBinders()); affectedTableNames.addAll(jdbcOperation.getAffectedTableNames()); filterJdbcParameters.addAll(jdbcOperation.getFilterJdbcParameters()); - final Map, Map, List>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref( - interpretation.domainParameterXref, - interpretation.getSqmTranslation()::getJdbcParamsBySqmParam - ); - - final JdbcParameterBindings tempJdbcParameterBindings = SqmUtil.createJdbcParameterBindings( - executionContext.getQueryParameterBindings(), - interpretation.domainParameterXref, - jdbcParamsXref, - session.getFactory().getRuntimeMetamodels().getMappingMetamodel(), - interpretation.tableGroupAccess::findTableGroup, - new SqmParameterMappingModelResolutionAccess() { - @Override - @SuppressWarnings("unchecked") - public MappingModelExpressible getResolvedMappingModelType(SqmParameter parameter) { - return (MappingModelExpressible) interpretation.sqmTranslation.getSqmParameterMappingModelTypeResolutions().get(parameter); - } - }, - session - ); + final JdbcParameterBindings tempJdbcParameterBindings = translation.parameterBindings; if (!tempJdbcParameterBindings.getBindings().isEmpty()) { tempJdbcParameterBindings.visitBindings(jdbcParameterBindings::addBinding); } @@ -877,30 +1008,12 @@ public int executeUpdate(com.blazebit.persistence.spi.ServiceProvider servicePro final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(0); for (Query participatingQuery : participatingQueries) { CacheableSqmInterpretation interpretation = buildQueryPlan(participatingQuery); - JdbcOperationQuery jdbcOperation = getJdbcOperation(sessionFactory, interpretation, participatingQuery.unwrap(QuerySqmImpl.class)); + JdbcTranslation translation = getJdbcTranslation(sessionFactory, interpretation, participatingQuery.unwrap(QuerySqmImpl.class)); + JdbcOperationQuery jdbcOperation = translation.query; parameterBinders.addAll(jdbcOperation.getParameterBinders()); affectedTableNames.addAll(jdbcOperation.getAffectedTableNames()); filterJdbcParameters.addAll(jdbcOperation.getFilterJdbcParameters()); - final Map, Map, List>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref( - interpretation.domainParameterXref, - interpretation.getSqmTranslation()::getJdbcParamsBySqmParam - ); - - final JdbcParameterBindings tempJdbcParameterBindings = SqmUtil.createJdbcParameterBindings( - participatingQuery.unwrap(DomainQueryExecutionContext.class).getQueryParameterBindings(), - interpretation.domainParameterXref, - jdbcParamsXref, - session.getFactory().getRuntimeMetamodels().getMappingMetamodel(), - interpretation.tableGroupAccess::findTableGroup, - new SqmParameterMappingModelResolutionAccess() { - @Override - @SuppressWarnings("unchecked") - public MappingModelExpressible getResolvedMappingModelType(SqmParameter parameter) { - return (MappingModelExpressible) interpretation.sqmTranslation.getSqmParameterMappingModelTypeResolutions().get(parameter); - } - }, - session - ); + final JdbcParameterBindings tempJdbcParameterBindings = translation.parameterBindings; if (!tempJdbcParameterBindings.getBindings().isEmpty()) { tempJdbcParameterBindings.visitBindings(jdbcParameterBindings::addBinding); } @@ -985,44 +1098,21 @@ public ReturningResult executeReturning(com.blazebit.persistence.spi.S final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(0); for (Query participatingQuery : participatingQueries) { CacheableSqmInterpretation interpretation = buildQueryPlan(participatingQuery); - JdbcOperationQuery jdbcOperation = getJdbcOperation(sessionFactory, interpretation, participatingQuery.unwrap(QuerySqmImpl.class)); + JdbcTranslation translation = getJdbcTranslation(sessionFactory, interpretation, participatingQuery.unwrap(QuerySqmImpl.class)); + JdbcOperationQuery jdbcOperation = translation.query; // Exclude limit/offset parameters from example query if (participatingQuery != exampleQuery) { parameterBinders.addAll(jdbcOperation.getParameterBinders()); } affectedTableNames.addAll(jdbcOperation.getAffectedTableNames()); filterJdbcParameters.addAll(jdbcOperation.getFilterJdbcParameters()); - final Map, Map, List>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref( - interpretation.domainParameterXref, - interpretation.getSqmTranslation()::getJdbcParamsBySqmParam - ); - final JdbcParameterBindings tempJdbcParameterBindings = SqmUtil.createJdbcParameterBindings( - participatingQuery.unwrap(DomainQueryExecutionContext.class).getQueryParameterBindings(), - interpretation.domainParameterXref, - jdbcParamsXref, - session.getFactory().getRuntimeMetamodels().getMappingMetamodel(), - interpretation.tableGroupAccess::findTableGroup, - new SqmParameterMappingModelResolutionAccess() { - @Override - @SuppressWarnings("unchecked") - public MappingModelExpressible getResolvedMappingModelType(SqmParameter parameter) { - return (MappingModelExpressible) interpretation.sqmTranslation.getSqmParameterMappingModelTypeResolutions().get(parameter); - } - }, - session - ); + final JdbcParameterBindings tempJdbcParameterBindings = translation.parameterBindings; if (!tempJdbcParameterBindings.getBindings().isEmpty()) { tempJdbcParameterBindings.visitBindings(jdbcParameterBindings::addBinding); } } - // Create combined query parameters - // List queryStrings = new ArrayList<>(participatingQueries.size()); - // Set querySpaces = new HashSet<>(); - // QueryParamEntry queryParametersEntry = createQueryParameters(em, participatingQueries, queryStrings, querySpaces); - // QueryParameters queryParameters = queryParametersEntry.queryParameters; - // Create plan for example query JdbcOperationQuerySelect exampleQueryJdbcOperation = (JdbcOperationQuerySelect) getJdbcOperation(exampleQuery); @@ -1036,37 +1126,12 @@ public MappingModelExpressible getResolvedMappingModelType(SqmParameter returningResult = new HibernateReturningResult(); - // if (!queryPlanEntry.isFromCache()) { - // prepareQueryPlan(queryPlan, queryParametersEntry.specifications, finalSql, session, modificationBaseQuery, true, dbmsDialect); - // queryPlan = putQueryPlanIfAbsent(sfi, cacheKey, queryPlan); - // } - // - // if (queryPlan.getTranslators().length > 1) { - // throw new IllegalArgumentException("No support for multiple translators yet!"); - // } - // - // QueryTranslator queryTranslator = queryPlan.getTranslators()[0]; - // - // // If the DBMS doesn't support inclusion of cascading deletes in a with clause, we have to execute them manually - // StatementExecutor executor = getExecutor(queryTranslator, session, modificationBaseQuery); - // List originalDeletes = Collections.emptyList(); - // - // if (executor != null && executor instanceof DeleteExecutor) { - // originalDeletes = getField(executor, "deletes"); - // } - // - // // Extract query loader for native listing - // QueryLoader queryLoader = getField(queryTranslator, "queryLoader"); // Do the native list operation with custom session and combined parameters /* * NATIVE LIST START */ - // hibernateAccess.checkTransactionSynchStatus(session); - // queryParameters.validateParameters(); - // autoFlush(querySpaces, session); - List results = Collections.EMPTY_LIST; boolean success = false; @@ -1076,7 +1141,7 @@ public MappingModelExpressible getResolvedMappingModelType(SqmParameter querySqm = modificationBaseQuery.unwrap( QuerySqmImpl.class ); + SqmStatement modificationSqmStatement = querySqm.getSqmStatement(); + if ( modificationSqmStatement instanceof SqmDmlStatement) { + SqmDmlStatement sqmDmlStatement = (SqmDmlStatement) modificationSqmStatement; + BulkOperationCleanupAction.schedule( executionContext.getSession(), sqmDmlStatement ); + if ( !dbmsDialect.supportsModificationQueryInWithClause() && sqmDmlStatement instanceof SqmDeleteStatement ) { + Function statementCreator = sql -> session.getJdbcCoordinator() + .getStatementPreparer() + .prepareStatement( sql ); + BiConsumer expectationCheck = (integer, preparedStatement) -> { }; + SqmJdbcExecutionContextAdapter executionContextAdapter = SqmJdbcExecutionContextAdapter.usingLockingAndPaging( + modificationBaseQuery.unwrap( DomainQueryExecutionContext.class ) ); + CollectionTableDeleteInfo collectionTableDeletes = getCollectionTableDeletes( querySqm ); + for ( JdbcOperationQueryMutation delete : collectionTableDeletes.deletes ) { + session.getFactory().getJdbcServices().getJdbcMutationExecutor().execute( + delete, + collectionTableDeletes.parameterBindings, + statementCreator, + expectationCheck, + executionContextAdapter + ); + } + } + } + } results = session.getFactory().getJdbcServices().getJdbcSelectExecutor().list( realJdbcSelect, @@ -1157,7 +1203,7 @@ public boolean hasQueryExecutionToBeAddedToStatistics() { ListResultsConsumer.UniqueSemantic.FILTER ); } catch (HibernateException e) { - LOG.severe("Could not execute the following SQL query: " + sqlOverride); + LOG.severe("Could not execute the following SQL query: " + finalSql); if (session.getFactory().getSessionFactoryOptions().isJpaBootstrap()) { throw session.getExceptionConverter().convert(e); } else { @@ -1166,23 +1212,6 @@ public boolean hasQueryExecutionToBeAddedToStatistics() { } finally { interpretation.domainParameterXref.clearExpansions(); } -// try { -// // for (String delete : originalDeletes) { -// // hibernateAccess.doExecute(executor, delete, queryParameters, session, queryParametersEntry.specifications); -// // } -// results = getResultList(serviceProvider, participatingQueries, exampleQuery, finalSql, queryPlanCacheEnabled, hibernateAccess.wrapExecutionContext(exampleQuery, dbmsDialect, returningColumnTypes, returningResult)); -// // results = hibernateAccess.list(queryLoader, wrapSession(session, dbmsDialect, returningColumns, returningColumnTypes, returningResult), queryParameters); -// success = true; -// } catch (HibernateException e) { -// LOG.severe("Could not execute the following SQL query: " + sqlOverride); -// if (session.getFactory().getSessionFactoryOptions().isJpaBootstrap()) { -// throw session.getExceptionConverter().convert(e); -// } else { -// throw e; -// } -// } finally { -// // hibernateAccess.afterTransaction(session, success); -// } /* * NATIVE LIST END */ @@ -1312,10 +1341,25 @@ private JdbcOperationQuery getJdbcOperation(Query query) { // JdbcSelect jdbcSelect = getField(cacheableSqmInterpretation, "jdbcSelect"); // return jdbcSelect; // } - return getJdbcOperation(factory, buildQueryPlan(query), hqlQuery); + CacheableSqmInterpretation interpretation = buildQueryPlan( query ); + return getJdbcOperation( factory, interpretation, hqlQuery ); } private JdbcOperationQuery getJdbcOperation(SessionFactoryImplementor factory, CacheableSqmInterpretation interpretation, QuerySqmImpl query) { + return getJdbcTranslation( factory, interpretation, query ).query; + } + + private static class JdbcTranslation { + private final JdbcOperationQuery query; + private final JdbcParameterBindings parameterBindings; + + public JdbcTranslation(JdbcOperationQuery query, JdbcParameterBindings parameterBindings) { + this.query = query; + this.parameterBindings = parameterBindings; + } + } + + private JdbcTranslation getJdbcTranslation(SessionFactoryImplementor factory, CacheableSqmInterpretation interpretation, QuerySqmImpl query) { JdbcEnvironment jdbcEnvironment = factory.getJdbcServices().getJdbcEnvironment(); SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory(); SqmTranslation sqmTranslation = interpretation.getSqmTranslation(); @@ -1340,19 +1384,20 @@ public MappingModelExpressible getResolvedMappingModelType(SqmParameter translator = sqlAstTranslatorFactory.buildSelectTranslator(factory, (SelectStatement) sqlAst); - return translator.translate(jdbcParameterBindings, query.getQueryOptions()); + return new JdbcTranslation(translator.translate(jdbcParameterBindings, query.getQueryOptions()), jdbcParameterBindings); } else if (sqlAst instanceof DeleteStatement) { SqlAstTranslator translator = sqlAstTranslatorFactory.buildDeleteTranslator(factory, (DeleteStatement) sqlAst); - return translator.translate(jdbcParameterBindings, query.getQueryOptions()); + return new JdbcTranslation(translator.translate(jdbcParameterBindings, query.getQueryOptions()), jdbcParameterBindings); } else if (sqlAst instanceof UpdateStatement) { SqlAstTranslator translator = sqlAstTranslatorFactory.buildUpdateTranslator(factory, (UpdateStatement) sqlAst); - return translator.translate(jdbcParameterBindings, query.getQueryOptions()); + return new JdbcTranslation(translator.translate(jdbcParameterBindings, query.getQueryOptions()), jdbcParameterBindings); } else if (sqlAst instanceof InsertStatement) { SqlAstTranslator translator = sqlAstTranslatorFactory.buildInsertTranslator(factory, (InsertStatement) sqlAst); - return translator.translate(jdbcParameterBindings, query.getQueryOptions()); + return new JdbcTranslation(translator.translate(jdbcParameterBindings, query.getQueryOptions()), jdbcParameterBindings); } throw new UnsupportedOperationException(); } diff --git a/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateJpaProvider.java b/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateJpaProvider.java index 9f67519a3e..93fe562d99 100644 --- a/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateJpaProvider.java +++ b/integration/hibernate6-base/src/main/java/com/blazebit/persistence/integration/hibernate/base/HibernateJpaProvider.java @@ -1636,7 +1636,7 @@ public Object getIdentifier(Object entity) { if (entity instanceof HibernateProxy) { return ((HibernateProxy) entity).getHibernateLazyInitializer().getIdentifier(); } - return persistenceUnitUtil.getIdentifier(entity); + return entity == null ? null : persistenceUnitUtil.getIdentifier(entity); } @Override diff --git a/parent/pom.xml b/parent/pom.xml index 61bc9f2ce2..f309d2a4a9 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -81,7 +81,7 @@ 5.1.2.Final 3.2.12.Final 4.8.89 - 2.16.2 + 2.15.4 9.5 6.4.1