mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-17 00:24:57 +00:00
HHH-15030 - SelectQuery, MutationQuery, etc
This commit is contained in:
parent
159792209a
commit
3365a4fe54
@ -53,6 +53,7 @@
|
||||
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
|
||||
import org.hibernate.query.IllegalMutationQueryException;
|
||||
import org.hibernate.query.IllegalNamedQueryOptionsException;
|
||||
import org.hibernate.query.IllegalSelectQueryException;
|
||||
import org.hibernate.query.JpaQuery;
|
||||
import org.hibernate.query.MutationQuery;
|
||||
import org.hibernate.query.SelectionQuery;
|
||||
@ -61,6 +62,7 @@
|
||||
import org.hibernate.query.hql.spi.NamedHqlQueryMemento;
|
||||
import org.hibernate.query.hql.spi.SqmQueryImplementor;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.query.spi.HqlInterpretation;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
import org.hibernate.query.spi.QueryInterpretationCache;
|
||||
@ -671,19 +673,20 @@ public SelectionQuery createSelectQuery(String hqlString) {
|
||||
try {
|
||||
final QueryEngine queryEngine = getFactory().getQueryEngine();
|
||||
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
|
||||
|
||||
final SqmSelectionQuery query = new SqmSelectQueryImpl(
|
||||
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
|
||||
hqlString,
|
||||
interpretationCache.resolveHqlInterpretation(
|
||||
hqlString,
|
||||
s -> queryEngine.getHqlTranslator().translate( hqlString )
|
||||
),
|
||||
this
|
||||
s -> queryEngine.getHqlTranslator().translate( hqlString )
|
||||
);
|
||||
|
||||
applyQuerySettingsAndHints( query );
|
||||
if ( hqlInterpretation.getSqmStatement() instanceof SqmDmlStatement ) {
|
||||
throw new IllegalSelectQueryException( "Expecting a selection query, but found `" + hqlString + "`" );
|
||||
}
|
||||
|
||||
final SqmSelectionQuery query = new SqmSelectQueryImpl( hqlString, hqlInterpretation, this );
|
||||
query.setComment( hqlString );
|
||||
|
||||
applyQuerySettingsAndHints( query );
|
||||
|
||||
return query;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
@ -1016,7 +1019,7 @@ public MutationQuery createNamedMutationQuery(String queryName) {
|
||||
final Boolean isUnequivocallySelect = query.isSelectQuery();
|
||||
if ( isUnequivocallySelect == TRUE ) {
|
||||
throw new IllegalMutationQueryException(
|
||||
"Expecting a named native mutation query (" + queryName + "), but found `" + nativeMemento.getSqlString() + "`"
|
||||
"Expecting named native query (" + queryName + ") to be a mutation query, but found `" + nativeMemento.getSqlString() + "`"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.query;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
|
||||
/**
|
||||
* Indicates an attempt to call {@link QueryProducer#createSelectQuery(String)},
|
||||
* {@link QueryProducer#name(String)} or
|
||||
* {@link QueryProducer#createNativeMutationQuery(String)} with a non-mutation
|
||||
* query (generally a select query)
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IllegalSelectQueryException extends QueryException {
|
||||
public IllegalSelectQueryException(String message) {
|
||||
super( message );
|
||||
}
|
||||
|
||||
public IllegalSelectQueryException(String message, String queryString) {
|
||||
super( message, queryString );
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface JpaQuery extends CommonQueryContract, SelectionQuery, MutationQuery, jakarta.persistence.Query {
|
||||
public interface JpaQuery extends SelectionQuery, MutationQuery, jakarta.persistence.Query {
|
||||
@Override
|
||||
default List<?> getResultList() {
|
||||
return SelectionQuery.super.getResultList();
|
||||
|
@ -13,6 +13,7 @@
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Incubating;
|
||||
|
||||
import jakarta.persistence.Parameter;
|
||||
import jakarta.persistence.TemporalType;
|
||||
@ -24,6 +25,7 @@
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface MutationQuery extends CommonQueryContract {
|
||||
|
||||
/**
|
||||
|
@ -25,10 +25,13 @@
|
||||
*/
|
||||
public interface QueryProducer {
|
||||
/**
|
||||
* Create a {@link Query} instance for the given HQL/JPQL query, or
|
||||
* HQL/JPQL insert, update, or delete statement.
|
||||
* Create a {@link Query} instance for the given HQL query, or
|
||||
* HQL insert, update, or delete statement.
|
||||
*
|
||||
* @param queryString The HQL/JPQL query
|
||||
* @apiNote Returns a raw Query reference, as opposed to unbounded (`<?>`),
|
||||
* to match {@link jakarta.persistence.EntityManager#createQuery(String)}
|
||||
*
|
||||
* @param queryString The HQL query
|
||||
*
|
||||
* @return The {@link Query} instance for manipulation and execution
|
||||
*
|
||||
@ -42,21 +45,12 @@ public interface QueryProducer {
|
||||
Query createQuery(String queryString);
|
||||
|
||||
/**
|
||||
* Create a {@link SelectionQuery} reference for the given HQL.
|
||||
*
|
||||
* Only valid for select queries
|
||||
*
|
||||
* @see jakarta.persistence.EntityManager#createQuery(String)
|
||||
*/
|
||||
SelectionQuery createSelectQuery(String hqlString);
|
||||
|
||||
/**
|
||||
* Create a typed {@link Query} instance for the given HQL/JPQL query string.
|
||||
* Create a typed {@link Query} instance for the given HQL query string.
|
||||
* <p>
|
||||
* The returned {@code Query} may be executed by calling
|
||||
* {@link Query#getResultList()} or {@link Query#getSingleResult()}.
|
||||
*
|
||||
* @param queryString The HQL/JPQL query
|
||||
* @param queryString The HQL query
|
||||
* @param resultClass The type of the query result
|
||||
* @return The Query instance for manipulation and execution
|
||||
*
|
||||
@ -65,59 +59,21 @@ public interface QueryProducer {
|
||||
<R> Query<R> createQuery(String queryString, Class<R> resultClass);
|
||||
|
||||
/**
|
||||
* Create a MutationQuery reference for the given HQL insert,
|
||||
* update, or delete statement.
|
||||
* Create a {@link Query} for the given JPA {@link CriteriaQuery}
|
||||
*/
|
||||
MutationQuery createMutationQuery(String hqlString);
|
||||
<R> Query<R> createQuery(CriteriaQuery<R> criteriaQuery);
|
||||
|
||||
/**
|
||||
* Create a typed {@link Query} instance for the given named query.
|
||||
* The named query might be defined in HQL or in native SQL.
|
||||
*
|
||||
* @param name the name of a pre-defined, named query
|
||||
*
|
||||
* @return The {@link Query} instance for manipulation and execution
|
||||
*
|
||||
* @throws IllegalArgumentException if a query has not been
|
||||
* defined with the given name or if the query string is
|
||||
* found to be invalid
|
||||
*
|
||||
* @see jakarta.persistence.EntityManager#createNamedQuery(String)
|
||||
*
|
||||
* @deprecated use {@link #createNamedQuery(String, Class)} or {@link #createNamedMutationQuery(String)}
|
||||
* Create a {@link MutationQuery} for the given JPA {@link CriteriaUpdate}
|
||||
*/
|
||||
@Deprecated(since = "6.0") @SuppressWarnings("rawtypes")
|
||||
Query createNamedQuery(String name);
|
||||
@SuppressWarnings("rawtypes")
|
||||
Query createQuery(CriteriaUpdate updateQuery);
|
||||
|
||||
/**
|
||||
* Create a typed {@link Query} instance for the given named query.
|
||||
* The named query might be defined in HQL or in native SQL.
|
||||
*
|
||||
* @param name the name of a query defined in metadata
|
||||
* @param resultClass the type of the query result
|
||||
*
|
||||
* @return The {@link Query} instance for manipulation and execution
|
||||
*
|
||||
* @throws IllegalArgumentException if a query has not been
|
||||
* defined with the given name or if the query string is
|
||||
* found to be invalid or if the query result is found to
|
||||
* not be assignable to the specified type
|
||||
*
|
||||
* @see jakarta.persistence.EntityManager#createNamedQuery(String,Class)
|
||||
* Create a {@link MutationQuery} for the given JPA {@link CriteriaDelete}
|
||||
*/
|
||||
<R> Query<R> createNamedQuery(String name, Class<R> resultClass);
|
||||
|
||||
/**
|
||||
* Create a {@link MutationQuery} instance for the given named insert,
|
||||
* update, or delete HQL query. The named query might be defined as
|
||||
* {@linkplain jakarta.persistence.NamedQuery HQL}) or
|
||||
* {@linkplain jakarta.persistence.NamedNativeQuery native-SQL}.
|
||||
*
|
||||
* @throws IllegalArgumentException if no query has been
|
||||
* defined with the given name or if the query string is
|
||||
* found to be invalid (a selection e.g.)
|
||||
*/
|
||||
MutationQuery createNamedMutationQuery(String name);
|
||||
@SuppressWarnings("rawtypes")
|
||||
Query createQuery(CriteriaDelete deleteQuery);
|
||||
|
||||
/**
|
||||
* Create a {@link NativeQuery} instance for the given native (SQL) query
|
||||
@ -177,7 +133,7 @@ public interface QueryProducer {
|
||||
*
|
||||
* @see jakarta.persistence.EntityManager#createNativeQuery(String,Class)
|
||||
* @see jakarta.persistence.SqlResultSetMapping
|
||||
*
|
||||
*
|
||||
* @deprecated use {@link #createNativeQuery(String, String, Class)}
|
||||
*/
|
||||
@Deprecated(since = "6.0") @SuppressWarnings("rawtypes")
|
||||
@ -198,13 +154,25 @@ public interface QueryProducer {
|
||||
<R> NativeQuery<R> createNativeQuery(String sqlString, String resultSetMappingName, Class<R> resultClass);
|
||||
|
||||
/**
|
||||
* Create a {@link NativeQuery} instance for the given native (SQL) statement
|
||||
* Create a {@link SelectionQuery} reference for the given HQL.
|
||||
*
|
||||
* @param sqlString a native SQL statement string
|
||||
* Only valid for select queries
|
||||
*
|
||||
* @return The NativeQuery instance for manipulation and execution
|
||||
* @see jakarta.persistence.EntityManager#createQuery(String)
|
||||
*
|
||||
* @throws IllegalSelectQueryException if the given HQL query
|
||||
* is an insert, update or delete query
|
||||
*/
|
||||
MutationQuery createNativeMutationQuery(String sqlString);
|
||||
SelectionQuery createSelectQuery(String hqlString);
|
||||
|
||||
/**
|
||||
* Create a MutationQuery reference for the given HQL insert,
|
||||
* update, or delete statement.
|
||||
*
|
||||
* @throws IllegalMutationQueryException if the given HQL query
|
||||
* is a select query
|
||||
*/
|
||||
MutationQuery createMutationQuery(String hqlString);
|
||||
|
||||
/**
|
||||
* Create a `MutationQuery` from the given update criteria tree
|
||||
@ -217,19 +185,64 @@ public interface QueryProducer {
|
||||
MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery);
|
||||
|
||||
/**
|
||||
* Create a {@link Query} for the given JPA {@link CriteriaQuery}
|
||||
* Create a {@link NativeQuery} instance for the given native (SQL) statement
|
||||
*
|
||||
* @param sqlString a native SQL statement string
|
||||
*
|
||||
* @return The NativeQuery instance for manipulation and execution
|
||||
*/
|
||||
<R> Query<R> createQuery(CriteriaQuery<R> criteriaQuery);
|
||||
MutationQuery createNativeMutationQuery(String sqlString);
|
||||
|
||||
/**
|
||||
* Create a {@link MutationQuery} for the given JPA {@link CriteriaUpdate}
|
||||
* Create a typed {@link Query} instance for the given named query.
|
||||
* The named query might be defined in HQL or in native SQL.
|
||||
*
|
||||
* @param name the name of a pre-defined, named query
|
||||
*
|
||||
* @return The {@link Query} instance for manipulation and execution
|
||||
*
|
||||
* @throws IllegalArgumentException if a query has not been
|
||||
* defined with the given name or if the query string is
|
||||
* found to be invalid
|
||||
*
|
||||
* @see jakarta.persistence.EntityManager#createNamedQuery(String)
|
||||
*
|
||||
* @deprecated use {@link #createNamedQuery(String, Class)} or {@link #createNamedMutationQuery(String)}
|
||||
*/
|
||||
Query createQuery(@SuppressWarnings("rawtypes") CriteriaUpdate updateQuery);
|
||||
@Deprecated(since = "6.0") @SuppressWarnings("rawtypes")
|
||||
Query createNamedQuery(String name);
|
||||
|
||||
/**
|
||||
* Create a {@link MutationQuery} for the given JPA {@link CriteriaDelete}
|
||||
* Create a typed {@link Query} instance for the given named query.
|
||||
* The named query might be defined in HQL or in native SQL.
|
||||
*
|
||||
* @param name the name of a query defined in metadata
|
||||
* @param resultClass the type of the query result
|
||||
*
|
||||
* @return The {@link Query} instance for manipulation and execution
|
||||
*
|
||||
* @throws IllegalArgumentException if a query has not been
|
||||
* defined with the given name or if the query string is
|
||||
* found to be invalid or if the query result is found to
|
||||
* not be assignable to the specified type
|
||||
*
|
||||
* @see jakarta.persistence.EntityManager#createNamedQuery(String,Class)
|
||||
*/
|
||||
Query createQuery(@SuppressWarnings("rawtypes") CriteriaDelete deleteQuery);
|
||||
<R> Query<R> createNamedQuery(String name, Class<R> resultClass);
|
||||
|
||||
/**
|
||||
* Create a {@link MutationQuery} instance for the given named insert,
|
||||
* update, or delete HQL query. The named query might be defined as
|
||||
* {@linkplain jakarta.persistence.NamedQuery HQL}) or
|
||||
* {@linkplain jakarta.persistence.NamedNativeQuery native-SQL}.
|
||||
*
|
||||
* @throws IllegalMutationQueryException if the given HQL query is a select query
|
||||
* @throws UnknownNamedQueryException if no query has been defined with the given name
|
||||
*/
|
||||
MutationQuery createNamedMutationQuery(String name);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@link Query} instance for the named query.
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
@ -37,6 +38,7 @@
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface SelectionQuery extends CommonQueryContract {
|
||||
/**
|
||||
* Execute the query and return the query results as a {@link List}.
|
||||
|
@ -29,8 +29,6 @@ public interface QueryProducerImplementor extends QueryProducer {
|
||||
FlushMode getHibernateFlushMode();
|
||||
CacheMode getCacheMode();
|
||||
|
||||
// todo : define list/scroll/iterate methods here...
|
||||
|
||||
@Override @SuppressWarnings("rawtypes")
|
||||
QueryImplementor getNamedQuery(String queryName);
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
@ -119,6 +120,7 @@ public class NativeQueryImpl<R>
|
||||
|
||||
private final QueryOptionsImpl queryOptions = new QueryOptionsImpl();
|
||||
|
||||
private Boolean startsWithSelect;
|
||||
private Set<String> querySpaces;
|
||||
private Callback callback;
|
||||
|
||||
@ -524,9 +526,22 @@ public Boolean isSelectQuery() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( startsWithSelect() ) {
|
||||
// as a last resort, see if the SQL starts with "select"
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean startsWithSelect() {
|
||||
if ( startsWithSelect == null ) {
|
||||
startsWithSelect = sqlString.toLowerCase( Locale.ROOT ).startsWith( "select " );
|
||||
}
|
||||
return startsWithSelect;
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Execution
|
||||
|
||||
|
@ -82,19 +82,10 @@ void basicInvalidNamedHqlDeleteTest(SessionFactoryScope scope) {
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExpectedException( IllegalMutationQueryException.class )
|
||||
void basicInvalidNamedNativeDeleteTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
try {
|
||||
// we do not know unequivocally whether this is a select or mutation
|
||||
// - this will be an execution exception
|
||||
session.createNamedMutationQuery( "invalid-native" ).executeUpdate();
|
||||
fail( "Expecting query to fail" );
|
||||
}
|
||||
catch (PersistenceException expected) {
|
||||
assertThat( expected.getCause() ).isNotNull();
|
||||
assertThat( expected.getCause().getCause() ).isNotNull();
|
||||
assertThat( expected.getCause().getCause() ).isInstanceOf( SQLException.class );
|
||||
}
|
||||
session.createNamedMutationQuery( "invalid-native" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user