From 0adbf40c49cdbb5d478a5be34ba446c1f4294209 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 6 Jun 2022 14:39:22 -0500 Subject: [PATCH] HHH-15316 - Session.createQuery() doesn't accept JpaCriteriaInsertSelect --- .../engine/spi/SessionDelegatorBaseImpl.java | 12 +++ .../engine/spi/SessionLazyDelegator.java | 23 +++++- .../AbstractSharedSessionContract.java | 28 +++++-- .../org/hibernate/query/QueryProducer.java | 7 ++ .../criteria/JpaCriteriaInsertSelect.java | 15 ++++ .../tree/insert/SqmInsertSelectStatement.java | 2 + .../query/criteria/InsertSelectTests.java | 73 +++++++++++++++++++ 7 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/InsertSelectTests.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java index c46684daee..617a908d95 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java @@ -49,6 +49,7 @@ import org.hibernate.procedure.ProcedureCall; import org.hibernate.query.MutationQuery; import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaInsertSelect; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryProducerImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor; @@ -450,14 +451,22 @@ public class SessionDelegatorBaseImpl implements SessionImplementor { @Override public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaUpdate updateQuery) { + //noinspection resource return delegate().createMutationQuery( updateQuery ); } @Override public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery) { + //noinspection resource return delegate().createMutationQuery( deleteQuery ); } + @Override + public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") JpaCriteriaInsertSelect insertSelect) { + //noinspection resource + return delegate().createMutationQuery( insertSelect ); + } + @Override public QueryImplementor createQuery(CriteriaQuery criteriaQuery) { return queryDelegate().createQuery( criteriaQuery ); @@ -525,11 +534,13 @@ public class SessionDelegatorBaseImpl implements SessionImplementor { @Override public SelectionQuery createNamedSelectionQuery(String name) { + //noinspection resource return delegate().createNamedSelectionQuery( name ); } @Override public SelectionQuery createNamedSelectionQuery(String name, Class resultType) { + //noinspection resource return delegate().createNamedSelectionQuery( name, resultType ); } @@ -649,6 +660,7 @@ public class SessionDelegatorBaseImpl implements SessionImplementor { return delegate.createStoredProcedureCall( procedureName, resultSetMappings ); } + @SuppressWarnings("rawtypes") @Override public SharedSessionBuilder sessionWithOptions() { return delegate.sessionWithOptions(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java index 7bcb96c80e..54e47b68a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java @@ -38,6 +38,7 @@ import org.hibernate.query.NativeQuery; import org.hibernate.query.Query; import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaInsertSelect; import org.hibernate.stat.SessionStatistics; import jakarta.persistence.EntityGraph; @@ -476,6 +477,7 @@ public class SessionLazyDelegator implements Session { return this.lazySession.get().getLobHelper(); } + @SuppressWarnings("rawtypes") @Override public SharedSessionBuilder sessionWithOptions() { return this.lazySession.get().sessionWithOptions(); @@ -511,6 +513,7 @@ public class SessionLazyDelegator implements Session { return this.lazySession.get().createQuery( queryString, resultClass ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public Query createQuery(String queryString) { @@ -522,6 +525,7 @@ public class SessionLazyDelegator implements Session { return this.lazySession.get().createNamedQuery( name, resultClass ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public Query createNamedQuery(String name) { @@ -533,12 +537,14 @@ public class SessionLazyDelegator implements Session { return this.lazySession.get().createQuery( criteriaQuery ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public Query createQuery(CriteriaDelete deleteQuery) { return this.lazySession.get().createQuery( deleteQuery ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public Query createQuery(CriteriaUpdate updateQuery) { @@ -605,7 +611,7 @@ public class SessionLazyDelegator implements Session { return this.lazySession.get().createStoredProcedureQuery( procedureName ); } - @Override @SuppressWarnings({"rawtypes", "unchecked"}) + @Override public ProcedureCall createStoredProcedureQuery(String procedureName, Class... resultClasses) { return this.lazySession.get().createStoredProcedureQuery( procedureName, resultClasses ); } @@ -640,6 +646,7 @@ public class SessionLazyDelegator implements Session { return this.lazySession.get().doReturningWork( work ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public NativeQuery createNativeQuery(String sqlString) { @@ -656,6 +663,7 @@ public class SessionLazyDelegator implements Session { return this.lazySession.get().createNativeQuery( sqlString, resultClass, tableAlias ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public NativeQuery createNativeQuery(String sqlString, String resultSetMappingName) { @@ -688,15 +696,20 @@ public class SessionLazyDelegator implements Session { } @Override - public MutationQuery createMutationQuery(CriteriaUpdate updateQuery) { + public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaUpdate updateQuery) { return this.lazySession.get().createMutationQuery( updateQuery ); } @Override - public MutationQuery createMutationQuery(CriteriaDelete deleteQuery) { + public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery) { return this.lazySession.get().createMutationQuery( deleteQuery ); } + @Override + public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") JpaCriteriaInsertSelect insertSelect) { + return this.lazySession.get().createMutationQuery( insertSelect ); + } + @Override public MutationQuery createNativeMutationQuery(String sqlString) { return this.lazySession.get().createNativeMutationQuery( sqlString ); @@ -717,18 +730,21 @@ public class SessionLazyDelegator implements Session { return this.lazySession.get().createNamedMutationQuery( name ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public Query getNamedQuery(String queryName) { return this.lazySession.get().getNamedQuery( queryName ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public NativeQuery getNamedNativeQuery(String name) { return this.lazySession.get().getNamedNativeQuery( name ); } + @SuppressWarnings("rawtypes") @Override @Deprecated public NativeQuery getNamedNativeQuery(String name, String resultSetMapping) { @@ -813,6 +829,7 @@ public class SessionLazyDelegator implements Session { @Override public T unwrap(Class cls) { if ( cls.isAssignableFrom( Session.class ) ) { + //noinspection unchecked return (T) this; } return this.lazySession.get().unwrap( cls ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index b9ef285eb9..68ecc11274 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -15,13 +15,6 @@ import java.util.Locale; import java.util.TimeZone; import java.util.UUID; import java.util.function.Function; -import jakarta.persistence.FlushModeType; -import jakarta.persistence.NamedNativeQuery; -import jakarta.persistence.TransactionRequiredException; -import jakarta.persistence.Tuple; -import jakarta.persistence.criteria.CriteriaDelete; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaUpdate; import org.hibernate.CacheMode; import org.hibernate.EmptyInterceptor; @@ -68,6 +61,7 @@ import org.hibernate.query.QueryTypeMismatchException; import org.hibernate.query.SelectionQuery; import org.hibernate.query.UnknownNamedQueryException; import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaInsertSelect; import org.hibernate.query.hql.spi.SqmQueryImplementor; import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedResultSetMappingMemento; @@ -86,6 +80,7 @@ import org.hibernate.query.sqm.spi.NamedSqmQueryMemento; 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.insert.SqmInsertSelectStatement; import org.hibernate.query.sqm.tree.select.SqmQueryGroup; import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; @@ -98,6 +93,14 @@ import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoo import org.hibernate.resource.transaction.spi.TransactionCoordinator; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; +import jakarta.persistence.FlushModeType; +import jakarta.persistence.NamedNativeQuery; +import jakarta.persistence.TransactionRequiredException; +import jakarta.persistence.Tuple; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaUpdate; + import static java.lang.Boolean.TRUE; /** @@ -1163,6 +1166,17 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont } } + @Override + public MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") JpaCriteriaInsertSelect insertSelect) { + checkOpen(); + try { + return new QuerySqmImpl<>( (SqmInsertSelectStatement) insertSelect, null, this ); + } + catch ( RuntimeException e ) { + throw getExceptionConverter().convert( e ); + } + } + @Override @SuppressWarnings("UnnecessaryLocalVariable") public ProcedureCall getNamedProcedureCall(String name) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java index 8e6412e19d..ea46b58c44 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java @@ -6,6 +6,8 @@ */ package org.hibernate.query; +import org.hibernate.query.criteria.JpaCriteriaInsertSelect; + import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; @@ -208,6 +210,11 @@ public interface QueryProducer { */ MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery); + /** + * Create a {@link MutationQuery} from the given insert-select criteria tree + */ + MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") JpaCriteriaInsertSelect insertSelect); + /** * Create a {@link NativeQuery} instance for the given native (SQL) statement * diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaInsertSelect.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaInsertSelect.java index 674c32ad48..344231b2ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaInsertSelect.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaInsertSelect.java @@ -6,6 +6,8 @@ */ package org.hibernate.query.criteria; +import org.hibernate.Incubating; + /** * A representation of SqmInsertSelectStatement at the * {@link org.hibernate.query.criteria} level, even though JPA does @@ -13,7 +15,20 @@ package org.hibernate.query.criteria; * * @see org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement * + * @apiNote Incubating mainly for 2 purposes:
    + *
  • + * to decide how to handle the typing for the "selection part". Should it + * be {@code } or {@code }. For the time being we expose it as + * {@code } because that is what was done (without intention) originally, + * and it is the easiest form to validate + *
  • + *
  • + * Would be better to expose non-SQM contracts here + *
  • + *
+ * * @author Steve Ebersole */ +@Incubating public interface JpaCriteriaInsertSelect extends JpaManipulationCriteria { } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java index 9032136acb..6e65f00e02 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.hibernate.Incubating; import org.hibernate.query.criteria.JpaCriteriaInsertSelect; import org.hibernate.query.criteria.JpaPredicate; import org.hibernate.query.sqm.NodeBuilder; @@ -26,6 +27,7 @@ import org.hibernate.query.sqm.tree.select.SqmQuerySpec; /** * @author Steve Ebersole */ +@Incubating public class SqmInsertSelectStatement extends AbstractSqmInsertStatement implements JpaCriteriaInsertSelect { private SqmQueryPart selectQueryPart; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/InsertSelectTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/InsertSelectTests.java new file mode 100644 index 0000000000..6f73f97655 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/InsertSelectTests.java @@ -0,0 +1,73 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.orm.test.query.criteria; + +import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder; +import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.select.SqmSelectStatement; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +/** + * @author Steve Ebersole + */ +@DomainModel(annotatedClasses = InsertSelectTests.AnEntity.class) +@SessionFactory +public class InsertSelectTests { + @Test + public void simpleTest(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + final SqmCriteriaNodeBuilder criteriaBuilder = (SqmCriteriaNodeBuilder) session.getCriteriaBuilder(); + final SqmInsertSelectStatement insertSelect = criteriaBuilder.createCriteriaInsertSelect( AnEntity.class ); + final SqmSelectStatement select = criteriaBuilder.createQuery( AnEntity.class ); + insertSelect.setSelectQueryPart( select.getQuerySpec() ); + select.from( AnEntity.class ); + session.createMutationQuery( insertSelect ).executeUpdate(); + } ); + } + + @SuppressWarnings("unused") + @Entity( name = "AnEntity" ) + @Table( name = "AnEntity" ) + public static class AnEntity { + @Id + @GeneratedValue + private Integer id; + @Basic + private String name; + + private AnEntity() { + // for use by Hibernate + } + + public AnEntity(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +}