Implement SQM copying for JPA Criteria API uses

This commit is contained in:
Christian Beikov 2022-01-24 15:54:42 +01:00
parent 5446291171
commit 0ad5796ffd
161 changed files with 3411 additions and 519 deletions

View File

@ -79,6 +79,17 @@ Traditionally, Hibernate has considered the names locally scoped.
If enabled, the names used by `@TableGenerator` and `@SequenceGenerator` will be considered global so configuring two different generators
with the same name will cause a `java.lang.IllegalArgumentException` to be thrown at boot time.
`*hibernate.jpa.compliance.criteria_copy*` (e.g. `true` (default value) or `false` )::
The Jakarta Persistence spec says that mutations done to `CriteriaQuery`, `CriteriaUpdate` and `CriteriaDelete`
after such objects were used to create a `jakarta.persistence.Query` may not affect that query.
This requirement makes it necessary to copy these objects because the APIs allow mutations.
+
If disabled, it is assumed that users do not mutate the criteria query afterwards
and due to that, no copy will be created, which will improve performance.
+
By default, no copies are created to not hurt performance. When enabled,
criteria query objects are copied, as required by the JPA specification.
[[configurations-database-connection]]
=== Database connection properties

View File

@ -19,6 +19,10 @@ import org.hibernate.query.sqm.NullPrecedence;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
/**
* Enumerates the configuration properties supported by Hibernate, including
* properties defined by the JPA specification.
@ -2364,6 +2368,24 @@ public interface AvailableSettings {
*/
String JPA_LOAD_BY_ID_COMPLIANCE = "hibernate.jpa.compliance.load_by_id";
/**
* When enabled, specifies that {@linkplain org.hibernate.query.Query queries}
* created through {@link jakarta.persistence.EntityManager#createQuery(CriteriaQuery)},
* {@link jakarta.persistence.EntityManager#createQuery(CriteriaUpdate)} or
* {@link jakarta.persistence.EntityManager#createQuery(CriteriaDelete)}
* must create a copy of the passed object such that the resulting {@link jakarta.persistence.Query}
* is not affected by any mutations to the original criteria query.
* <p>
* If disabled, it is assumed that users do not mutate the criteria query afterwards
* and due to that, no copy will be created, which will improve performance.
* <p>
* By default, no copies are created to not hurt performance. When enabled,
* criteria query objects are copied, as required by the JPA specification.
*
* @since 6.0
*/
String JPA_CRITERIA_COPY_COMPLIANCE = "hibernate.jpa.compliance.criteria_copy";
/**
* Determines if the identifier value stored in the database table backing a
* {@linkplain jakarta.persistence.TableGenerator table generator} is the last

View File

@ -209,6 +209,16 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
delegate.setCacheMode( cm );
}
@Override
public void setJpaCriteriaCopyComplianceEnabled(boolean jpaCriteriaCopyComplianceEnabled) {
delegate.setJpaCriteriaCopyComplianceEnabled( jpaCriteriaCopyComplianceEnabled );
}
@Override
public boolean isJpaCriteriaCopyComplianceEnabled() {
return delegate.isJpaCriteriaCopyComplianceEnabled();
}
@Override
public boolean isOpen() {
return delegate.isOpen();

View File

@ -332,6 +332,10 @@ public interface SharedSessionContractImplementor
void setCacheMode(CacheMode cm);
void setJpaCriteriaCopyComplianceEnabled(boolean jpaCriteriaCopyComplianceEnabled);
boolean isJpaCriteriaCopyComplianceEnabled();
/**
* Set the flush mode for this session.
* <p/>

View File

@ -81,6 +81,7 @@ import org.hibernate.query.sql.spi.NativeQueryImplementor;
import org.hibernate.query.sqm.SqmSelectionQuery;
import org.hibernate.query.sqm.internal.QuerySqmImpl;
import org.hibernate.query.sqm.internal.SqmSelectionQueryImpl;
import org.hibernate.query.sqm.internal.SqmUtil;
import org.hibernate.query.sqm.tree.SqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
@ -141,6 +142,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
private final PhysicalConnectionHandlingMode connectionHandlingMode;
private CacheMode cacheMode;
private boolean jpaCriteriaCopyComplianceEnabled;
protected boolean closed;
protected boolean waitingForAutoClose;
@ -158,7 +160,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
this.factory = factory;
this.fastSessionServices = factory.getFastSessionServices();
this.cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this );
setJpaCriteriaCopyComplianceEnabled( factory.getJpaMetamodel().getJpaCompliance().isJpaCriteriaCopyComplianceEnabled() );
this.flushMode = options.getInitialSessionFlushMode();
@ -643,6 +645,15 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
this.cacheMode = cacheMode;
}
@Override
public void setJpaCriteriaCopyComplianceEnabled(boolean jpaCriteriaCopyComplianceEnabled) {
this.jpaCriteriaCopyComplianceEnabled = jpaCriteriaCopyComplianceEnabled;
}
@Override
public boolean isJpaCriteriaCopyComplianceEnabled() {
return jpaCriteriaCopyComplianceEnabled;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// dynamic HQL handling
@ -705,6 +716,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public <R> SelectionQuery<R> createSelectionQuery(CriteriaQuery<R> criteria) {
SqmUtil.verifyIsSelectStatement( (SqmStatement<?>) criteria, null );
return new SqmSelectionQueryImpl<>( (SqmSelectStatement<R>) criteria, this );
}

View File

@ -152,6 +152,7 @@ import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_CRITERIA_COPY_COMPLIANCE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
@ -2599,6 +2600,9 @@ public class SessionImpl
)
);
break;
case JPA_CRITERIA_COPY_COMPLIANCE:
setJpaCriteriaCopyComplianceEnabled( Boolean.parseBoolean( value.toString() ) );
break;
}
}

View File

@ -21,6 +21,7 @@ public class JpaComplianceImpl implements JpaCompliance {
private final boolean closedCompliance;
private final boolean cachingCompliance;
private final boolean loadByIdCompliance;
private final boolean criteriaCopyCompliance;
public JpaComplianceImpl(
boolean listCompliance,
@ -31,7 +32,8 @@ public class JpaComplianceImpl implements JpaCompliance {
boolean transactionCompliance,
boolean closedCompliance,
boolean cachingCompliance,
boolean loadByIdCompliance) {
boolean loadByIdCompliance,
boolean criteriaCopyCompliance) {
this.queryCompliance = queryCompliance;
this.transactionCompliance = transactionCompliance;
this.listCompliance = listCompliance;
@ -41,6 +43,7 @@ public class JpaComplianceImpl implements JpaCompliance {
this.globalGeneratorNameScopeCompliance = globalGeneratorNameScopeCompliance;
this.orderByMappingCompliance = orderByMappingCompliance;
this.loadByIdCompliance = loadByIdCompliance;
this.criteriaCopyCompliance = criteriaCopyCompliance;
}
@Override
@ -88,6 +91,11 @@ public class JpaComplianceImpl implements JpaCompliance {
return loadByIdCompliance;
}
@Override
public boolean isJpaCriteriaCopyComplianceEnabled() {
return criteriaCopyCompliance;
}
public static class JpaComplianceBuilder {
private boolean queryCompliance;
private boolean listCompliance;
@ -98,6 +106,7 @@ public class JpaComplianceImpl implements JpaCompliance {
private boolean transactionCompliance;
private boolean closedCompliance;
private boolean loadByIdCompliance;
private boolean criteriaCopyCompliance;
public JpaComplianceBuilder() {
}
@ -147,6 +156,11 @@ public class JpaComplianceImpl implements JpaCompliance {
return this;
}
public JpaComplianceBuilder setJpaCriteriaCopyComplianceEnabled(boolean jpaCriteriaCopyComplianceEnabled) {
this.criteriaCopyCompliance = jpaCriteriaCopyComplianceEnabled;
return this;
}
JpaCompliance createJpaCompliance() {
return new JpaComplianceImpl(
listCompliance,
@ -157,7 +171,8 @@ public class JpaComplianceImpl implements JpaCompliance {
transactionCompliance,
closedCompliance,
cachingCompliance,
loadByIdCompliance
loadByIdCompliance,
criteriaCopyCompliance
);
}
}

View File

@ -26,6 +26,7 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
private boolean closedCompliance;
private boolean cachingCompliance;
private boolean loadByIdCompliance;
private boolean criteriaCopyCompliance;
public MutableJpaComplianceImpl(Map configurationSettings) {
this(
@ -92,6 +93,12 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
configurationSettings,
jpaByDefault
);
criteriaCopyCompliance = ConfigurationHelper.getBoolean(
AvailableSettings.JPA_CRITERIA_COPY_COMPLIANCE,
configurationSettings,
jpaByDefault
);
}
@Override
@ -134,6 +141,16 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
return orderByMappingCompliance;
}
@Override
public boolean isLoadByIdComplianceEnabled() {
return loadByIdCompliance;
}
@Override
public boolean isJpaCriteriaCopyComplianceEnabled() {
return criteriaCopyCompliance;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mutators
@ -182,8 +199,8 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
}
@Override
public boolean isLoadByIdComplianceEnabled() {
return loadByIdCompliance;
public void setJpaCriteriaCopyComplianceEnabled(boolean jpaCriteriaCopyComplianceEnabled) {
this.criteriaCopyCompliance = jpaCriteriaCopyComplianceEnabled;
}
@Override
@ -197,7 +214,8 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
.setTransactionCompliance( transactionCompliance )
.setClosedCompliance( closedCompliance )
.setCachingCompliance( cachingCompliance )
.setLoadByIdCompliance( loadByIdCompliance );
.setLoadByIdCompliance( loadByIdCompliance )
.setJpaCriteriaCopyComplianceEnabled( criteriaCopyCompliance );
return builder.createJpaCompliance();
}
}

View File

@ -154,4 +154,22 @@ public interface JpaCompliance {
* @since 6.0
*/
boolean isLoadByIdComplianceEnabled();
/**
* JPA says that mutations done to {@link jakarta.persistence.criteria.CriteriaQuery},
* {@link jakarta.persistence.criteria.CriteriaUpdate} and {@link jakarta.persistence.criteria.CriteriaDelete}
* after such objects were used to create a {@link jakarta.persistence.Query} may not affect that query.
* This requirement makes it necessary to copy these objects because the APIs allow mutations.
*
* If disabled, it is assumed that users do not mutate the criteria query afterwards
* and due to that, no copy will be created, which will improve performance.
*
* By default, no copies are created to not hurt performance. When enabled,
* criteria query objects are copied, as required by the JPA specification.
*
* @see org.hibernate.cfg.AvailableSettings#JPA_CRITERIA_COPY_COMPLIANCE
*
* @since 6.0
*/
boolean isJpaCriteriaCopyComplianceEnabled();
}

View File

@ -28,5 +28,7 @@ public interface MutableJpaCompliance extends JpaCompliance {
void setLoadByIdCompliance(boolean enabled);
void setJpaCriteriaCopyComplianceEnabled(boolean jpaCriteriaCopyComplianceEnabled);
JpaCompliance immutableCopy();
}

View File

@ -21,6 +21,7 @@ import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.sql.internal.DiscriminatorPathInterpretation;
import org.hibernate.query.sqm.sql.internal.SelfInterpretingSqmPath;
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.AbstractSqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
@ -50,6 +51,18 @@ public class DiscriminatorSqmPath extends AbstractSqmPath implements SelfInterpr
this.entityDescriptor = entityDescriptor;
}
@Override
public DiscriminatorSqmPath copy(SqmCopyContext context) {
final DiscriminatorSqmPath existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
return context.registerCopy(
this,
(DiscriminatorSqmPath) getLhs().copy( context ).type()
);
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
if ( ! entityDescriptor.hasSubclasses() ) {

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.query;
import org.hibernate.QueryException;
/**
* Indicates an attempt to call {@link QueryProducer#createMutationQuery(String)},
* {@link QueryProducer#createNamedMutationQuery(String)} or
@ -16,8 +14,12 @@ import org.hibernate.QueryException;
*
* @author Steve Ebersole
*/
public class IllegalMutationQueryException extends QueryException {
public class IllegalMutationQueryException extends IllegalQueryOperationException {
public IllegalMutationQueryException(String message) {
super( message );
}
public IllegalMutationQueryException(String message, String queryString) {
super( message, queryString, null );
}
}

View File

@ -6,20 +6,18 @@
*/
package org.hibernate.query;
import org.hibernate.QueryException;
/**
* Indicates an attempt to call {@link QueryProducer#createSelectionQuery(String)}
* with a non-selection query (generally a mutation query)
*
* @author Steve Ebersole
*/
public class IllegalSelectQueryException extends QueryException {
public class IllegalSelectQueryException extends IllegalQueryOperationException {
public IllegalSelectQueryException(String message) {
super( message );
}
public IllegalSelectQueryException(String message, String queryString) {
super( message, queryString );
super( message, queryString, null );
}
}

View File

@ -12,17 +12,17 @@ import java.math.BigInteger;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import jakarta.persistence.criteria.Expression;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.hql.HqlInterpretationException;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
@ -31,6 +31,8 @@ import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import jakarta.persistence.criteria.Expression;
/**
* @author Steve Ebersole
*/
@ -55,6 +57,11 @@ public class FullyQualifiedReflectivePathTerminal
this.expressibleType = null;
}
@Override
public FullyQualifiedReflectivePathTerminal copy(SqmCopyContext context) {
return this;
}
@SuppressWarnings("unchecked")
private Function<SemanticQueryWalker, ?> resolveTerminalSemantic() {
return semanticQueryWalker -> {

View File

@ -6,10 +6,12 @@
*/
package org.hibernate.query.spi;
import java.sql.Types;
import java.time.Instant;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -22,6 +24,9 @@ import jakarta.persistence.LockModeType;
import jakarta.persistence.NoResultException;
import jakarta.persistence.Parameter;
import jakarta.persistence.TemporalType;
import jakarta.persistence.Tuple;
import jakarta.persistence.TupleElement;
import jakarta.persistence.criteria.CompoundSelection;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
@ -31,18 +36,36 @@ import org.hibernate.LockOptions;
import org.hibernate.NonUniqueResultException;
import org.hibernate.ScrollMode;
import org.hibernate.TypeMismatchException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.spi.AppliedGraph;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.BindableType;
import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.QueryTypeMismatchException;
import org.hibernate.query.SelectionQuery;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.hql.spi.NamedHqlQueryMemento;
import org.hibernate.query.internal.ScrollableResultsIterator;
import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.select.SqmQueryGroup;
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.sql.exec.internal.CallbackImpl;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_STORE_MODE;
@ -68,6 +91,64 @@ public abstract class AbstractSelectionQuery<R>
super( session );
}
protected TupleMetadata buildTupleMetadata(SqmStatement<?> statement, Class<R> resultType) {
if ( resultType != null && Tuple.class.isAssignableFrom( resultType ) ) {
final List<SqmSelection<?>> selections = ( (SqmSelectStatement<?>) statement ).getQueryPart()
.getFirstQuerySpec()
.getSelectClause()
.getSelections();
// resultType is Tuple..
if ( getQueryOptions().getTupleTransformer() == null ) {
final Map<TupleElement<?>, Integer> tupleElementMap;
if ( selections.size() == 1 && selections.get( 0 ).getSelectableNode() instanceof CompoundSelection<?> ) {
final List<? extends JpaSelection<?>> selectionItems = selections.get( 0 )
.getSelectableNode()
.getSelectionItems();
tupleElementMap = new IdentityHashMap<>( selectionItems.size() );
for ( int i = 0; i < selectionItems.size(); i++ ) {
tupleElementMap.put( selectionItems.get( i ), i );
}
}
else {
tupleElementMap = new IdentityHashMap<>( selections.size() );
for ( int i = 0; i < selections.size(); i++ ) {
final SqmSelection<?> selection = selections.get( i );
tupleElementMap.put( selection.getSelectableNode(), i );
}
}
return new TupleMetadata( tupleElementMap );
}
throw new IllegalArgumentException(
"Illegal combination of Tuple resultType and (non-JpaTupleBuilder) TupleTransformer : " +
getQueryOptions().getTupleTransformer()
);
}
return null;
}
protected void applyOptions(NamedHqlQueryMemento memento) {
applyOptions( (NamedQueryMemento) memento );
if ( memento.getFirstResult() != null ) {
setFirstResult( memento.getFirstResult() );
}
if ( memento.getMaxResults() != null ) {
setMaxResults( memento.getMaxResults() );
}
if ( memento.getParameterTypes() != null ) {
for ( Map.Entry<String, String> entry : memento.getParameterTypes().entrySet() ) {
final QueryParameterImplementor<?> parameter = getParameterMetadata().getQueryParameter( entry.getKey() );
final BasicType<?> type = getSessionFactory().getTypeConfiguration()
.getBasicTypeRegistry()
.getRegisteredType( entry.getValue() );
parameter.applyAnticipatedType( type );
}
}
}
protected void applyOptions(NamedQueryMemento memento) {
if ( memento.getHints() != null ) {
memento.getHints().forEach( this::applyHint );
@ -106,6 +187,143 @@ public abstract class AbstractSelectionQuery<R>
}
}
protected void visitQueryReturnType(
SqmQueryPart<R> queryPart,
Class<R> resultType,
SessionFactoryImplementor factory) {
if ( queryPart instanceof SqmQuerySpec<?> ) {
final SqmQuerySpec<R> sqmQuerySpec = (SqmQuerySpec<R>) queryPart;
final List<SqmSelection<?>> sqmSelections = sqmQuerySpec.getSelectClause().getSelections();
if ( sqmSelections == null || sqmSelections.isEmpty() ) {
// make sure there is at least one root
final List<SqmRoot<?>> sqmRoots = sqmQuerySpec.getFromClause().getRoots();
if ( sqmRoots == null || sqmRoots.isEmpty() ) {
throw new IllegalArgumentException( "Criteria did not define any query roots" );
}
// if there is a single root, use that as the selection
if ( sqmRoots.size() == 1 ) {
final SqmRoot<?> sqmRoot = sqmRoots.get( 0 );
sqmQuerySpec.getSelectClause().add( sqmRoot, null );
}
else {
throw new IllegalArgumentException( );
}
}
if ( resultType != null ) {
checkQueryReturnType( sqmQuerySpec, resultType, factory );
}
}
else {
final SqmQueryGroup<R> queryGroup = (SqmQueryGroup<R>) queryPart;
for ( SqmQueryPart<R> sqmQueryPart : queryGroup.getQueryParts() ) {
visitQueryReturnType( sqmQueryPart, resultType, factory );
}
}
}
protected static <T> void checkQueryReturnType(
SqmQuerySpec<T> querySpec,
Class<T> resultClass,
SessionFactoryImplementor sessionFactory) {
if ( resultClass == null ) {
// nothing to check
return;
}
final List<SqmSelection<?>> selections = querySpec.getSelectClause().getSelections();
if ( resultClass.isArray() ) {
// todo (6.0) : implement
}
else if ( Tuple.class.isAssignableFrom( resultClass ) ) {
// todo (6.0) : implement
}
else {
final boolean jpaQueryComplianceEnabled = sessionFactory.getSessionFactoryOptions()
.getJpaCompliance()
.isJpaQueryComplianceEnabled();
if ( selections.size() != 1 ) {
final String errorMessage = "Query result-type error - multiple selections: use Tuple or array";
if ( jpaQueryComplianceEnabled ) {
throw new IllegalArgumentException( errorMessage );
}
else {
throw new QueryTypeMismatchException( errorMessage );
}
}
final SqmSelection<?> sqmSelection = selections.get( 0 );
if ( sqmSelection.getSelectableNode() instanceof SqmParameter ) {
final SqmParameter<?> sqmParameter = (SqmParameter<?>) sqmSelection.getSelectableNode();
// we may not yet know a selection type
if ( sqmParameter.getNodeType() == null || sqmParameter.getNodeType().getExpressibleJavaType() == null ) {
// we can't verify the result type up front
return;
}
}
if ( jpaQueryComplianceEnabled ) {
return;
}
verifyResultType( resultClass, sqmSelection.getNodeType(), sessionFactory );
}
}
protected static <T> void verifyResultType(
Class<T> resultClass,
SqmExpressible<?> sqmExpressible,
SessionFactoryImplementor sessionFactory) {
assert sqmExpressible != null;
assert sqmExpressible.getExpressibleJavaType() != null;
final Class<?> javaTypeClass = sqmExpressible.getExpressibleJavaType().getJavaTypeClass();
if ( !resultClass.isAssignableFrom( javaTypeClass ) ) {
// Special case for date because we always report java.util.Date as expression type
// But the expected resultClass could be a subtype of that, so we need to check the JdbcType
if ( javaTypeClass == Date.class ) {
JdbcType jdbcType = null;
if ( sqmExpressible instanceof BasicDomainType<?> ) {
jdbcType = ( (BasicDomainType<?>) sqmExpressible).getJdbcType();
}
else if ( sqmExpressible instanceof SqmPathSource<?> ) {
final DomainType<?> domainType = ( (SqmPathSource<?>) sqmExpressible).getSqmPathType();
if ( domainType instanceof BasicDomainType<?> ) {
jdbcType = ( (BasicDomainType<?>) domainType ).getJdbcType();
}
}
if ( jdbcType != null ) {
switch ( jdbcType.getJdbcTypeCode() ) {
case Types.DATE:
if ( resultClass.isAssignableFrom( java.sql.Date.class ) ) {
return;
}
break;
case Types.TIME:
if ( resultClass.isAssignableFrom( java.sql.Time.class ) ) {
return;
}
break;
case Types.TIMESTAMP:
if ( resultClass.isAssignableFrom( java.sql.Timestamp.class ) ) {
return;
}
break;
}
}
}
final String errorMessage = String.format(
"Specified result type [%s] did not match Query selection type [%s] - multiple selections: use Tuple or array",
resultClass.getName(),
sqmExpressible.getExpressibleJavaType().getJavaType().getTypeName()
);
throw new QueryTypeMismatchException( errorMessage );
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// execution
@ -686,4 +904,8 @@ public abstract class AbstractSelectionQuery<R>
super.setProperties( bean );
return this;
}
public SessionFactoryImplementor getSessionFactory() {
return getSession().getFactory();
}
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.query.sqm.function;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.query.ReturnableType;
@ -13,6 +14,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmAggregateFunction;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
@ -43,6 +45,34 @@ public class SelfRenderingSqmAggregateFunction<T> extends SelfRenderingSqmFuncti
this.filter = filter;
}
@Override
public SelfRenderingSqmAggregateFunction<T> copy(SqmCopyContext context) {
final SelfRenderingSqmAggregateFunction<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final List<SqmTypedNode<?>> arguments = new ArrayList<>( getArguments().size() );
for ( SqmTypedNode<?> argument : getArguments() ) {
arguments.add( argument.copy( context ) );
}
final SelfRenderingSqmAggregateFunction<T> expression = context.registerCopy(
this,
new SelfRenderingSqmAggregateFunction<>(
getFunctionDescriptor(),
getRenderingSupport(),
arguments,
filter == null ? null : filter.copy( context ),
getImpliedResultType(),
getArgumentsValidator(),
getReturnTypeResolver(),
nodeBuilder(),
getFunctionName()
)
);
copyTo( expression, context );
return expression;
}
@Override
public SelfRenderingFunctionSqlAstExpression convertToSqlAst(SqmToSqlAstConverter walker) {
final ReturnableType<?> resultType = resolveResultType(

View File

@ -18,6 +18,7 @@ import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
@ -52,14 +53,49 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
this.returnTypeResolver = returnTypeResolver;
}
@Override
public SelfRenderingSqmFunction<T> copy(SqmCopyContext context) {
final SelfRenderingSqmFunction<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final List<SqmTypedNode<?>> arguments = new ArrayList<>( getArguments().size() );
for ( SqmTypedNode<?> argument : getArguments() ) {
arguments.add( argument.copy( context ) );
}
final SelfRenderingSqmFunction<T> expression = context.registerCopy(
this,
new SelfRenderingSqmFunction<>(
getFunctionDescriptor(),
getRenderingSupport(),
arguments,
getImpliedResultType(),
getArgumentsValidator(),
getReturnTypeResolver(),
nodeBuilder(),
getFunctionName()
)
);
copyTo( expression, context );
return expression;
}
public FunctionRenderingSupport getRenderingSupport() {
return renderingSupport;
}
protected ReturnableType<T> getImpliedResultType() {
return impliedResultType;
}
protected ArgumentsValidator getArgumentsValidator() {
return argumentsValidator;
}
protected FunctionReturnTypeResolver getReturnTypeResolver() {
return returnTypeResolver;
}
protected static List<SqlAstNode> resolveSqlAstArguments(List<? extends SqmTypedNode<?>> sqmArguments, SqmToSqlAstConverter walker) {
if ( sqmArguments == null || sqmArguments.isEmpty() ) {
return emptyList();

View File

@ -85,12 +85,13 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
String hql,
DomainParameterXref domainParameterXref,
Class<R> resultType,
TupleMetadata tupleMetadata,
QueryOptions queryOptions) {
this.sqm = sqm;
this.hql = hql;
this.domainParameterXref = domainParameterXref;
this.rowTransformer = determineRowTransformer( sqm, resultType, queryOptions );
this.rowTransformer = determineRowTransformer( sqm, resultType, tupleMetadata, queryOptions );
this.listInterpreter = (unused, executionContext, sqmInterpretation, jdbcParameterBindings) -> {
final SharedSessionContractImplementor session = executionContext.getSession();
@ -178,6 +179,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
private RowTransformer<R> determineRowTransformer(
SqmSelectStatement<?> sqm,
Class<R> resultType,
TupleMetadata tupleMetadata,
QueryOptions queryOptions) {
if ( resultType == null || resultType.isArray() ) {
if ( queryOptions.getTupleTransformer() != null ) {
@ -191,27 +193,10 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
// NOTE : if we get here, a result-type of some kind (other than Object[].class) was specified
final List<SqmSelection<?>> selections = sqm.getQueryPart().getFirstQuerySpec().getSelectClause().getSelections();
if ( Tuple.class.isAssignableFrom( resultType ) ) {
if ( tupleMetadata != null ) {
// resultType is Tuple..
if ( queryOptions.getTupleTransformer() == null ) {
final Map<TupleElement<?>, Integer> tupleElementMap;
if ( selections.size() == 1 && selections.get( 0 ).getSelectableNode() instanceof CompoundSelection<?> ) {
final List<? extends JpaSelection<?>> selectionItems = selections.get( 0 )
.getSelectableNode()
.getSelectionItems();
tupleElementMap = new IdentityHashMap<>( selectionItems.size() );
for ( int i = 0; i < selectionItems.size(); i++ ) {
tupleElementMap.put( selectionItems.get( i ), i );
}
}
else {
tupleElementMap = new IdentityHashMap<>( selections.size() );
for ( int i = 0; i < selections.size(); i++ ) {
final SqmSelection<?> selection = selections.get( i );
tupleElementMap.put( selection.getSelectableNode(), i );
}
}
return (RowTransformer<R>) new RowTransformerJpaTupleImpl( new TupleMetadata( tupleElementMap ) );
return (RowTransformer<R>) new RowTransformerJpaTupleImpl( tupleMetadata );
}
throw new IllegalArgumentException(

View File

@ -16,6 +16,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
@ -77,7 +78,6 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryInterpretationCache;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.query.spi.SelectQueryPlan;
import org.hibernate.query.sqm.SqmExpressible;
@ -85,6 +85,7 @@ import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.internal.SqmInterpretationsKey.InterpretationsKeySource;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
@ -103,7 +104,7 @@ import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.type.BasicType;
import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import static org.hibernate.jpa.HibernateHints.HINT_CACHEABLE;
@ -135,7 +136,7 @@ public class QuerySqmImpl<R>
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QuerySqmImpl.class );
private final String hql;
private final SqmStatement<?> sqm;
private final SqmStatement<R> sqm;
private final ParameterMetadataImplementor parameterMetadata;
private final DomainParameterXref domainParameterXref;
@ -143,6 +144,7 @@ public class QuerySqmImpl<R>
private final QueryParameterBindingsImpl parameterBindings;
private final Class<R> resultType;
private final TupleMetadata tupleMetadata;
/**
* Creates a Query instance from a named HQL memento
@ -171,31 +173,11 @@ public class QuerySqmImpl<R>
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
validateStatement( sqm, resultType );
setComment( hql );
applyOptions( memento );
}
protected void applyOptions(NamedHqlQueryMemento memento) {
super.applyOptions( memento );
if ( memento.getFirstResult() != null ) {
setFirstResult( memento.getFirstResult() );
}
if ( memento.getMaxResults() != null ) {
setMaxResults( memento.getMaxResults() );
}
if ( memento.getParameterTypes() != null ) {
for ( Map.Entry<String, String> entry : memento.getParameterTypes().entrySet() ) {
final QueryParameterImplementor<?> parameter = getParameterMetadata().getQueryParameter( entry.getKey() );
final BasicType<?> type = getSessionFactory().getTypeConfiguration()
.getBasicTypeRegistry()
.getRegisteredType( entry.getValue() );
parameter.applyAnticipatedType( type );
}
}
this.tupleMetadata = buildTupleMetadata( sqm, resultType );
}
/**
@ -218,24 +200,10 @@ public class QuerySqmImpl<R>
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
validateStatement( sqm, resultType );
setComment( hql );
//noinspection rawtypes
final SqmStatement sqmStatement = hqlInterpretation.getSqmStatement();
if ( resultType != null ) {
SqmUtil.verifyIsSelectStatement( sqmStatement, hql );
visitQueryReturnType(
( (SqmSelectStatement<R>) sqmStatement ).getQueryPart(),
resultType,
session.getFactory()
);
}
else if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
verifyImmutableEntityUpdate( hql, (SqmUpdateStatement<R>) sqmStatement, session.getFactory() );
}
else if ( sqmStatement instanceof SqmInsertStatement<?> ) {
verifyInsertTypesMatch( hql, (SqmInsertStatement<R>) sqmStatement );
}
this.tupleMetadata = buildTupleMetadata( sqm, resultType );
}
/**
@ -247,11 +215,16 @@ public class QuerySqmImpl<R>
SharedSessionContractImplementor producer) {
super( producer );
this.hql = CRITERIA_HQL_STRING;
this.sqm = criteria;
if ( producer.isJpaCriteriaCopyComplianceEnabled() ) {
this.sqm = criteria.copy( SqmCopyContext.simpleContext() );
}
else {
this.sqm = criteria;
}
setComment( hql );
this.domainParameterXref = DomainParameterXref.from( criteria );
this.domainParameterXref = DomainParameterXref.from( this.sqm );
if ( ! domainParameterXref.hasParameters() ) {
this.parameterMetadata = ParameterMetadataImpl.EMPTY;
}
@ -275,7 +248,7 @@ public class QuerySqmImpl<R>
}
}
if ( resultType != null ) {
if ( sqm instanceof SqmSelectStatement<?> ) {
SqmUtil.verifyIsSelectStatement( sqm, null );
final SqmQueryPart<R> queryPart = ( (SqmSelectStatement<R>) sqm ).getQueryPart();
// For criteria queries, we have to validate the fetch structure here
@ -286,154 +259,56 @@ public class QuerySqmImpl<R>
producer.getFactory()
);
}
else if ( sqm instanceof SqmUpdateStatement<?> ) {
final SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqm;
verifyImmutableEntityUpdate( CRITERIA_HQL_STRING, updateStatement, producer.getFactory() );
if ( updateStatement.getSetClause() == null || updateStatement.getSetClause().getAssignments().isEmpty() ) {
throw new IllegalArgumentException( "No assignments specified as part of UPDATE criteria" );
else {
if ( resultType != null ) {
throw new IllegalQueryOperationException(
"Result type given for a non-SELECT Query",
hql,
null
);
}
if ( sqm instanceof SqmUpdateStatement<?> ) {
final SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqm;
verifyImmutableEntityUpdate( CRITERIA_HQL_STRING, updateStatement, producer.getFactory() );
if ( updateStatement.getSetClause() == null || updateStatement.getSetClause()
.getAssignments()
.isEmpty() ) {
throw new IllegalArgumentException( "No assignments specified as part of UPDATE criteria" );
}
}
else if ( sqm instanceof SqmInsertStatement<?> ) {
verifyInsertTypesMatch( CRITERIA_HQL_STRING, (SqmInsertStatement<R>) sqm );
}
}
else if ( sqm instanceof SqmInsertStatement<?> ) {
verifyInsertTypesMatch( CRITERIA_HQL_STRING, (SqmInsertStatement<R>) sqm );
}
this.resultType = resultType;
this.tupleMetadata = buildTupleMetadata( criteria, resultType );
}
private void visitQueryReturnType(
SqmQueryPart<R> queryPart,
Class<R> resultType,
SessionFactoryImplementor factory) {
if ( queryPart instanceof SqmQuerySpec<?> ) {
final SqmQuerySpec<R> sqmQuerySpec = (SqmQuerySpec<R>) queryPart;
final List<SqmSelection<?>> sqmSelections = sqmQuerySpec.getSelectClause().getSelections();
if ( sqmSelections == null || sqmSelections.isEmpty() ) {
// make sure there is at least one root
final List<SqmRoot<?>> sqmRoots = sqmQuerySpec.getFromClause().getRoots();
if ( sqmRoots == null || sqmRoots.isEmpty() ) {
throw new IllegalArgumentException( "Criteria did not define any query roots" );
}
// if there is a single root, use that as the selection
if ( sqmRoots.size() == 1 ) {
final SqmRoot<?> sqmRoot = sqmRoots.get( 0 );
sqmQuerySpec.getSelectClause().add( sqmRoot, null );
}
else {
throw new IllegalArgumentException( );
}
}
if ( resultType != null ) {
checkQueryReturnType( sqmQuerySpec, resultType, factory );
}
}
else {
final SqmQueryGroup<R> queryGroup = (SqmQueryGroup<R>) queryPart;
for ( SqmQueryPart<R> sqmQueryPart : queryGroup.getQueryParts() ) {
visitQueryReturnType( sqmQueryPart, resultType, factory );
}
}
}
private static <T> void checkQueryReturnType(
SqmQuerySpec<T> querySpec,
Class<T> resultClass,
SessionFactoryImplementor sessionFactory) {
if ( resultClass == null ) {
// nothing to check
return;
}
final List<SqmSelection<?>> selections = querySpec.getSelectClause().getSelections();
if ( resultClass.isArray() ) {
// todo (6.0) : implement
}
else if ( Tuple.class.isAssignableFrom( resultClass ) ) {
// todo (6.0) : implement
}
else {
final boolean jpaQueryComplianceEnabled = sessionFactory.getSessionFactoryOptions()
.getJpaCompliance()
.isJpaQueryComplianceEnabled();
if ( selections.size() != 1 ) {
final String errorMessage = "Query result-type error - multiple selections: use Tuple or array";
if ( jpaQueryComplianceEnabled ) {
throw new IllegalArgumentException( errorMessage );
}
else {
throw new QueryTypeMismatchException( errorMessage );
}
}
final SqmSelection<?> sqmSelection = selections.get( 0 );
if ( sqmSelection.getSelectableNode() instanceof SqmParameter ) {
final SqmParameter<?> sqmParameter = (SqmParameter<?>) sqmSelection.getSelectableNode();
// we may not yet know a selection type
if ( sqmParameter.getNodeType() == null || sqmParameter.getNodeType().getExpressibleJavaType() == null ) {
// we can't verify the result type up front
return;
}
}
if ( jpaQueryComplianceEnabled ) {
return;
}
verifyResultType( resultClass, sqmSelection.getNodeType(), sessionFactory );
}
}
private static <T> void verifyResultType(
Class<T> resultClass,
SqmExpressible<?> sqmExpressible,
SessionFactoryImplementor sessionFactory) {
assert sqmExpressible != null;
assert sqmExpressible.getExpressibleJavaType() != null;
final Class<?> javaTypeClass = sqmExpressible.getExpressibleJavaType().getJavaTypeClass();
if ( !resultClass.isAssignableFrom( javaTypeClass ) ) {
// Special case for date because we always report java.util.Date as expression type
// But the expected resultClass could be a subtype of that, so we need to check the JdbcType
if ( javaTypeClass == Date.class ) {
JdbcType jdbcType = null;
if ( sqmExpressible instanceof BasicDomainType<?> ) {
jdbcType = ( (BasicDomainType<?>) sqmExpressible).getJdbcType();
}
else if ( sqmExpressible instanceof SqmPathSource<?> ) {
final DomainType<?> domainType = ( (SqmPathSource<?>) sqmExpressible).getSqmPathType();
if ( domainType instanceof BasicDomainType<?> ) {
jdbcType = ( (BasicDomainType<?>) domainType ).getJdbcType();
}
}
if ( jdbcType != null ) {
switch ( jdbcType.getJdbcTypeCode() ) {
case Types.DATE:
if ( resultClass.isAssignableFrom( java.sql.Date.class ) ) {
return;
}
break;
case Types.TIME:
if ( resultClass.isAssignableFrom( java.sql.Time.class ) ) {
return;
}
break;
case Types.TIMESTAMP:
if ( resultClass.isAssignableFrom( java.sql.Timestamp.class ) ) {
return;
}
break;
}
}
}
final String errorMessage = String.format(
"Specified result type [%s] did not match Query selection type [%s] - multiple selections: use Tuple or array",
resultClass.getName(),
sqmExpressible.getExpressibleJavaType().getJavaType().getTypeName()
private void validateStatement(SqmStatement<R> sqmStatement, Class<R> resultType) {
if ( sqmStatement instanceof SqmSelectStatement<?> ) {
SqmUtil.verifyIsSelectStatement( sqmStatement, hql );
visitQueryReturnType(
( (SqmSelectStatement<R>) sqmStatement ).getQueryPart(),
resultType,
getSessionFactory()
);
throw new QueryTypeMismatchException( errorMessage );
}
else {
if ( resultType != null ) {
throw new IllegalQueryOperationException(
"Result type given for a non-SELECT Query",
hql,
null
);
}
if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
SqmUpdateStatement<R> updateStatement = (SqmUpdateStatement<R>) sqmStatement;
verifyImmutableEntityUpdate( hql, updateStatement, getSessionFactory() );
}
else if ( sqmStatement instanceof SqmInsertStatement<?> ) {
verifyInsertTypesMatch( hql, (SqmInsertStatement<R>) sqmStatement );
}
}
}
@ -548,10 +423,6 @@ public class QuerySqmImpl<R>
return parameterBindings;
}
public SessionFactoryImplementor getSessionFactory() {
return getSession().getFactory();
}
@Override
public QueryParameterBindings getParameterBindings() {
return getQueryParameterBindings();
@ -739,6 +610,7 @@ public class QuerySqmImpl<R>
getQueryString(),
getDomainParameterXref(),
resultType,
tupleMetadata,
queryOptions
);
}

View File

@ -56,11 +56,13 @@ import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.query.spi.SelectQueryPlan;
import org.hibernate.query.sqm.SqmSelectionQuery;
import org.hibernate.query.sqm.internal.SqmInterpretationsKey.InterpretationsKeySource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.sql.results.internal.TupleMetadata;
import static org.hibernate.jpa.HibernateHints.HINT_CACHEABLE;
import static org.hibernate.jpa.HibernateHints.HINT_CACHE_MODE;
@ -81,13 +83,14 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
public static final String CRITERIA_HQL_STRING = "<criteria>";
private final String hql;
private final SqmSelectStatement<?> sqm;
private final SqmSelectStatement<R> sqm;
private final ParameterMetadataImplementor parameterMetadata;
private final DomainParameterXref domainParameterXref;
private final QueryParameterBindingsImpl parameterBindings;
private final Class<R> resultType;
private final TupleMetadata tupleMetadata;
public SqmSelectionQueryImpl(
String hql,
@ -95,16 +98,19 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
SharedSessionContractImplementor session) {
super( session );
this.hql = hql;
this.sqm = (SqmSelectStatement<?>) hqlInterpretation.getSqmStatement();
//noinspection unchecked
this.sqm = (SqmSelectStatement<R>) hqlInterpretation.getSqmStatement();
this.parameterMetadata = hqlInterpretation.getParameterMetadata();
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
this.resultType = determineResultType( sqm );
visitQueryReturnType( sqm.getQueryPart(), null, getSessionFactory() );
this.resultType = null;
setComment( hql );
this.tupleMetadata = null;
}
public SqmSelectionQueryImpl(
@ -123,51 +129,33 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
(s) -> queryEngine.getHqlTranslator().translate( hql )
);
if ( !( hqlInterpretation.getSqmStatement() instanceof SqmSelectStatement ) ) {
throw new IllegalSelectQueryException( "Expecting a selection query, but found `" + hql + "`", hql );
}
this.sqm = (SqmSelectStatement<?>) hqlInterpretation.getSqmStatement();
SqmUtil.verifyIsSelectStatement( hqlInterpretation.getSqmStatement(), hql );
//noinspection unchecked
this.sqm = (SqmSelectStatement<R>) hqlInterpretation.getSqmStatement();
this.parameterMetadata = hqlInterpretation.getParameterMetadata();
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
visitQueryReturnType( sqm.getQueryPart(), resultType, getSessionFactory() );
setComment( hql );
if ( resultType != null ) {
final Class<R> determinedResultType = determineResultType( sqm );
if ( !resultType.isAssignableFrom( determinedResultType ) ) {
throw new QueryTypeMismatchException(
String.format(
Locale.ROOT,
"SelectionQuery result-type error - expecting `%s`, but found `%s`",
resultType.getName(),
determinedResultType.getName()
)
);
}
}
}
private static <T> Class<T> determineResultType(SqmSelectStatement<?> sqm) {
final List<SqmSelection<?>> selections = sqm.getQuerySpec().getSelectClause().getSelections();
if ( selections.size() == 1 ) {
final SqmSelection<?> sqmSelection = selections.get( 0 );
//noinspection unchecked
return (Class<T>) sqmSelection.getNodeJavaType().getJavaTypeClass();
}
//noinspection unchecked
return (Class<T>) Object[].class;
applyOptions( memento );
this.tupleMetadata = buildTupleMetadata( sqm, resultType );
}
public SqmSelectionQueryImpl(
SqmSelectStatement<R> sqm,
SqmSelectStatement<R> criteria,
SharedSessionContractImplementor session) {
super( session );
this.hql = CRITERIA_HQL_STRING;
this.sqm = sqm;
if ( session.isJpaCriteriaCopyComplianceEnabled() ) {
this.sqm = criteria.copy( SqmCopyContext.simpleContext() );
}
else {
this.sqm = criteria;
}
this.domainParameterXref = DomainParameterXref.from( sqm );
if ( ! domainParameterXref.hasParameters() ) {
@ -195,7 +183,21 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
this.resultType = determineResultType( sqm );
visitQueryReturnType( sqm.getQueryPart(), resultType, getSessionFactory() );
setComment( hql );
this.tupleMetadata = buildTupleMetadata( sqm, resultType );
}
private static <T> Class<T> determineResultType(SqmSelectStatement<?> sqm) {
final List<SqmSelection<?>> selections = sqm.getQuerySpec().getSelectClause().getSelections();
if ( selections.size() == 1 ) {
final SqmSelection<?> sqmSelection = selections.get( 0 );
//noinspection unchecked
return (Class<T>) sqmSelection.getNodeJavaType().getJavaTypeClass();
}
//noinspection unchecked
return (Class<T>) Object[].class;
}
@SuppressWarnings("rawtypes")
@ -217,10 +219,6 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
return parameterBindings;
}
protected SessionFactoryImplementor getSessionFactory() {
return getSession().getSessionFactory();
}
@Override
public String getQueryString() {
return hql;
@ -373,6 +371,7 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
getQueryString(),
getDomainParameterXref(),
resultType,
tupleMetadata,
queryOptions
);
}

View File

@ -34,6 +34,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.query.IllegalSelectQueryException;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
@ -78,15 +79,14 @@ public class SqmUtil {
public static void verifyIsSelectStatement(SqmStatement<?> sqm, String hqlString) {
if ( ! isSelect( sqm ) ) {
throw new IllegalQueryOperationException(
throw new IllegalSelectQueryException(
String.format(
Locale.ROOT,
"Expecting a SELECT Query [%s], but found %s",
SqmSelectStatement.class.getName(),
sqm.getClass().getName()
),
hqlString,
null
hqlString
);
}
}

View File

@ -9,10 +9,12 @@ package org.hibernate.query.sqm.tree;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
@ -22,12 +24,13 @@ import org.hibernate.query.sqm.tree.select.SqmSubQuery;
public abstract class AbstractSqmDmlStatement<E>
extends AbstractSqmStatement<E>
implements SqmDmlStatement<E> {
private final Map<String, SqmCteStatement<?>> cteStatements = new LinkedHashMap<>();
private final Map<String, SqmCteStatement<?>> cteStatements;
private boolean withRecursiveCte;
private SqmRoot<E> target;
public AbstractSqmDmlStatement(SqmQuerySource querySource, NodeBuilder nodeBuilder) {
super( querySource, nodeBuilder );
this.cteStatements = new LinkedHashMap<>();
}
public AbstractSqmDmlStatement(SqmRoot<E> target, SqmQuerySource querySource, NodeBuilder nodeBuilder) {
@ -35,6 +38,27 @@ public abstract class AbstractSqmDmlStatement<E>
this.target = target;
}
public AbstractSqmDmlStatement(
NodeBuilder builder,
SqmQuerySource querySource,
Set<SqmParameter<?>> parameters,
Map<String, SqmCteStatement<?>> cteStatements,
boolean withRecursiveCte,
SqmRoot<E> target) {
super( builder, querySource, parameters );
this.cteStatements = cteStatements;
this.withRecursiveCte = withRecursiveCte;
this.target = target;
}
protected Map<String, SqmCteStatement<?>> copyCteStatements(SqmCopyContext context) {
final Map<String, SqmCteStatement<?>> cteStatements = new LinkedHashMap<>( this.cteStatements.size() );
for ( Map.Entry<String, SqmCteStatement<?>> entry : this.cteStatements.entrySet() ) {
cteStatements.put( entry.getKey(), entry.getValue().copy( context ) );
}
return cteStatements;
}
@Override
public boolean isWithRecursive() {
return withRecursiveCte;

View File

@ -6,20 +6,25 @@
*/
package org.hibernate.query.sqm.tree;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.metamodel.EntityType;
import java.util.Map;
import java.util.Set;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.criteria.JpaCriteriaBase;
import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.metamodel.EntityType;
/**
* @author Christian Beikov
*/
@ -36,6 +41,27 @@ public abstract class AbstractSqmRestrictedDmlStatement<T> extends AbstractSqmDm
super( target, querySource, nodeBuilder );
}
public AbstractSqmRestrictedDmlStatement(
NodeBuilder builder,
SqmQuerySource querySource,
Set<SqmParameter<?>> parameters,
Map<String, SqmCteStatement<?>> cteStatements,
boolean withRecursiveCte,
SqmRoot<T> target) {
super( builder, querySource, parameters, cteStatements, withRecursiveCte, target );
}
protected SqmWhereClause copyWhereClause(SqmCopyContext context) {
if ( getWhereClause() == null ) {
return null;
}
else {
final SqmWhereClause whereClause = new SqmWhereClause( nodeBuilder() );
whereClause.setPredicate( getWhereClause().getPredicate().copy( context ) );
return whereClause;
}
}
public Root<T> from(Class<T> entityClass) {
final EntityDomainType<T> entity = nodeBuilder().getDomainModel().entity( entityClass );
SqmRoot<T> root = new SqmRoot<>( entity, null, false, nodeBuilder() );

View File

@ -12,15 +12,16 @@ import java.util.Set;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.internal.ParameterCollector;
import org.hibernate.query.sqm.internal.SqmUtil;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.internal.ParameterCollector;
/**
* @author Steve Ebersole
*/
public abstract class AbstractSqmStatement<T> extends AbstractSqmNode implements SqmStatement<T>, ParameterCollector {
private final SqmQuerySource querySource;
private Set<SqmParameter<?>> parameters;
public AbstractSqmStatement(
SqmQuerySource querySource,
@ -29,7 +30,27 @@ public abstract class AbstractSqmStatement<T> extends AbstractSqmNode implements
this.querySource = querySource;
}
private Set<SqmParameter<?>> parameters;
protected AbstractSqmStatement(
NodeBuilder builder,
SqmQuerySource querySource,
Set<SqmParameter<?>> parameters) {
super( builder );
this.querySource = querySource;
this.parameters = parameters;
}
protected Set<SqmParameter<?>> copyParameters(SqmCopyContext context) {
if ( parameters == null ) {
return null;
}
else {
final Set<SqmParameter<?>> parameters = new HashSet<>( this.parameters.size() );
for ( SqmParameter<?> parameter : this.parameters ) {
parameters.add( parameter.copy( context ) );
}
return parameters;
}
}
@Override
public SqmQuerySource getQuerySource() {

View File

@ -0,0 +1,40 @@
/*
* 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.sqm.tree;
import java.util.IdentityHashMap;
/**
*
*/
public interface SqmCopyContext {
<T> T getCopy(T original);
<T> T registerCopy(T original, T copy);
static SqmCopyContext simpleContext() {
final IdentityHashMap<Object, Object> map = new IdentityHashMap<>();
return new SqmCopyContext() {
@Override
public <T> T getCopy(T original) {
//noinspection unchecked
return (T) map.get( original );
}
@Override
public <T> T registerCopy(T original, T copy) {
final Object old = map.put( original, copy );
if ( old != null ) {
throw new IllegalArgumentException( "Already registered a copy: " + old );
}
return copy;
}
};
}
}

View File

@ -25,4 +25,6 @@ public interface SqmNode extends JpaCriteriaNode {
}
NodeBuilder nodeBuilder();
SqmNode copy(SqmCopyContext context);
}

View File

@ -14,4 +14,6 @@ import org.hibernate.query.criteria.JpaCriteriaBase;
* @author Steve Ebersole
*/
public interface SqmQuery<T> extends JpaCriteriaBase, SqmNode {
@Override
SqmQuery<T> copy(SqmCopyContext context);
}

View File

@ -33,6 +33,9 @@ public interface SqmStatement<T> extends SqmQuery<T>, JpaQueryableCriteria<T>, S
ParameterResolutions resolveParameters();
@Override
SqmStatement<T> copy(SqmCopyContext context);
interface ParameterResolutions {
ParameterResolutions EMPTY = new ParameterResolutions() {
@Override

View File

@ -30,4 +30,7 @@ public interface SqmTypedNode<T> extends SqmNode, SqmExpressibleAccessor<T> {
}
SqmExpressible<T> getNodeType();
@Override
SqmTypedNode<T> copy(SqmCopyContext context);
}

View File

@ -15,6 +15,7 @@ import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -70,6 +71,55 @@ public class SqmCteStatement<T> extends AbstractSqmNode implements SqmVisitableN
this.noCycleValue = '\0';
}
private SqmCteStatement(
NodeBuilder builder,
SqmCteContainer cteContainer,
SqmCteTable cteTable,
CteMaterialization materialization,
SqmStatement<?> cteDefinition,
CteSearchClauseKind searchClauseKind,
List<SqmSearchClauseSpecification> searchBySpecifications,
List<SqmCteTableColumn> cycleColumns,
SqmCteTableColumn cycleMarkColumn,
char cycleValue,
char noCycleValue) {
super( builder );
this.cteContainer = cteContainer;
this.cteTable = cteTable;
this.materialization = materialization;
this.cteDefinition = cteDefinition;
this.searchClauseKind = searchClauseKind;
this.searchBySpecifications = searchBySpecifications;
this.cycleColumns = cycleColumns;
this.cycleMarkColumn = cycleMarkColumn;
this.cycleValue = cycleValue;
this.noCycleValue = noCycleValue;
}
@Override
public SqmCteStatement<T> copy(SqmCopyContext context) {
final SqmCteStatement<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
return context.registerCopy(
this,
new SqmCteStatement<>(
nodeBuilder(),
cteContainer,
cteTable,
materialization,
cteDefinition.copy( context ),
searchClauseKind,
searchBySpecifications,
cycleColumns,
cycleMarkColumn,
cycleValue,
noCycleValue
)
);
}
public SqmCteTable getCteTable() {
return cteTable;
}

View File

@ -10,6 +10,7 @@ import java.io.Serializable;
import org.hibernate.query.sqm.NullPrecedence;
import org.hibernate.query.sqm.SortOrder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Christian Beikov
@ -25,6 +26,14 @@ public class SqmSearchClauseSpecification implements Serializable {
this.nullPrecedence = nullPrecedence;
}
public SqmSearchClauseSpecification copy(SqmCopyContext context) {
return new SqmSearchClauseSpecification(
cteColumn,
sortOrder,
nullPrecedence
);
}
public SqmCteTableColumn getCteColumn() {
return cteColumn;
}

View File

@ -6,16 +6,23 @@
*/
package org.hibernate.query.sqm.tree.delete;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
import java.util.Map;
import java.util.Set;
import org.hibernate.query.criteria.JpaCriteriaDelete;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.AbstractSqmRestrictedDmlStatement;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
/**
* @author Steve Ebersole
@ -41,6 +48,37 @@ public class SqmDeleteStatement<T>
);
}
public SqmDeleteStatement(
NodeBuilder builder,
SqmQuerySource querySource,
Set<SqmParameter<?>> parameters,
Map<String, SqmCteStatement<?>> cteStatements,
boolean withRecursiveCte,
SqmRoot<T> target) {
super( builder, querySource, parameters, cteStatements, withRecursiveCte, target );
}
@Override
public SqmDeleteStatement<T> copy(SqmCopyContext context) {
final SqmDeleteStatement<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmDeleteStatement<T> statement = context.registerCopy(
this,
new SqmDeleteStatement<>(
nodeBuilder(),
getQuerySource(),
copyParameters( context ),
copyCteStatements( context ),
isWithRecursive(),
getTarget().copy( context )
)
);
statement.setWhereClause( copyWhereClause( context ) );
return statement;
}
@Override
public SqmDeleteStatement<T> where(Expression<Boolean> restriction) {
setWhere( restriction );

View File

@ -6,19 +6,16 @@
*/
package org.hibernate.query.sqm.tree.domain;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.PersistentAttribute;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmJoinable;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.spi.SqmCreationHelper;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmFrom;
@ -27,6 +24,10 @@ import org.hibernate.type.descriptor.java.JavaType;
import org.jboss.logging.Logger;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
/**
* Models a join based on a mapped attribute reference.
*
@ -79,6 +80,11 @@ public abstract class AbstractSqmAttributeJoin<O,T>
this.fetched = fetched;
}
protected void copyTo(AbstractSqmAttributeJoin<O, T> target, SqmCopyContext context) {
super.copyTo( target, context );
this.onClausePredicate = onClausePredicate == null ? null : onClausePredicate.copy( context );
}
@Override
public SqmFrom<?, O> getLhs() {
//noinspection unchecked

View File

@ -14,15 +14,6 @@ import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import jakarta.persistence.criteria.Fetch;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.metamodel.CollectionAttribute;
import jakarta.persistence.metamodel.ListAttribute;
import jakarta.persistence.metamodel.MapAttribute;
import jakarta.persistence.metamodel.PluralAttribute;
import jakarta.persistence.metamodel.SetAttribute;
import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
@ -34,14 +25,16 @@ import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.metamodel.model.domain.SetPersistentAttribute;
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.SemanticException;
import org.hibernate.query.criteria.JpaEntityJoin;
import org.hibernate.query.criteria.JpaPath;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.spi.SqmCreationHelper;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
@ -50,6 +43,16 @@ import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import jakarta.persistence.criteria.Fetch;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.metamodel.CollectionAttribute;
import jakarta.persistence.metamodel.ListAttribute;
import jakarta.persistence.metamodel.MapAttribute;
import jakarta.persistence.metamodel.PluralAttribute;
import jakarta.persistence.metamodel.SetAttribute;
import jakarta.persistence.metamodel.SingularAttribute;
/**
* Convenience base class for SqmFrom implementations
*
@ -115,6 +118,22 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
super( navigablePath, referencedNavigable, null, nodeBuilder );
}
protected void copyTo(AbstractSqmFrom<O, T> target, SqmCopyContext context) {
super.copyTo( target, context );
if ( joins != null ) {
target.joins = new ArrayList<>( joins.size() );
for ( SqmJoin<T, ?> join : joins ) {
target.joins.add( join.copy( context ) );
}
}
if ( treats != null ) {
target.treats = new ArrayList<>( treats.size() );
for ( SqmFrom<?, ?> treat : treats ) {
target.treats.add( treat.copy( context ) );
}
}
}
@Override
public String getExplicitAlias() {
return alias;

View File

@ -21,8 +21,11 @@ import org.hibernate.metamodel.model.domain.PersistentAttribute;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmJoin;
/**
* @author Steve Ebersole
@ -48,6 +51,16 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
this.lhs = lhs;
}
protected void copyTo(AbstractSqmPath<T> target, SqmCopyContext context) {
super.copyTo( target, context );
if ( reusablePaths != null ) {
target.reusablePaths = new HashMap<>( reusablePaths.size() );
for ( Map.Entry<String, SqmPath<?>> entry : reusablePaths.entrySet() ) {
target.reusablePaths.put( entry.getKey(), entry.getValue().copy( context ) );
}
}
}
@Override
public SqmPathSource<T> getNodeType() {
return (SqmPathSource<T>) super.getNodeType();

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.query.sqm.tree.domain;
import jakarta.persistence.metamodel.EntityType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.PathException;
@ -15,6 +13,9 @@ import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import jakarta.persistence.metamodel.EntityType;
/**
* @author Andrea Boriero
@ -30,7 +31,27 @@ public class NonAggregatedCompositeSimplePath<T> extends SqmEntityValuedSimplePa
assert referencedPathSource.getSqmPathType() instanceof EntityType;
}
@Override
public NonAggregatedCompositeSimplePath<T> copy(SqmCopyContext context) {
final NonAggregatedCompositeSimplePath<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final NonAggregatedCompositeSimplePath<T> path = context.registerCopy(
this,
new NonAggregatedCompositeSimplePath<>(
getNavigablePath(),
getReferencedPathSource(),
getLhs().copy( context ),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public SqmPath<?> resolvePathPart(
String name,

View File

@ -11,10 +11,11 @@ import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.PathException;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Steve Ebersole
@ -42,6 +43,27 @@ public class SqmAnyValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
assert referencedPathSource.getSqmPathType() instanceof AnyMappingDomainType;
}
@Override
public SqmAnyValuedSimplePath<T> copy(SqmCopyContext context) {
final SqmAnyValuedSimplePath<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmAnyValuedSimplePath<T> path = context.registerCopy(
this,
new SqmAnyValuedSimplePath<>(
getNavigablePath(),
getReferencedPathSource(),
getLhs().copy( context ),
getExplicitAlias(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public <S extends T> SqmTreatedPath<T, S> treatAs(Class<S> treatJavaType) throws PathException {
throw new NotYetImplementedFor6Exception();

View File

@ -7,8 +7,6 @@
package org.hibernate.query.sqm.tree.domain;
import java.util.Collection;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
import org.hibernate.metamodel.model.domain.EntityDomainType;
@ -18,10 +16,14 @@ import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
/**
* @author Steve Ebersole
*/
@ -47,6 +49,28 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
super( lhs, navigablePath, attribute, alias, joinType, fetched, nodeBuilder );
}
@Override
public SqmBagJoin<O, E> copy(SqmCopyContext context) {
final SqmBagJoin<O, E> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmBagJoin<O, E> path = context.registerCopy(
this,
new SqmBagJoin<>(
getLhs().copy( context ),
getNavigablePath(),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public BagPersistentAttribute<O,E> getReferencedPathSource() {
return (BagPersistentAttribute<O,E>) super.getReferencedPathSource();

View File

@ -1,57 +0,0 @@
/*
* 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.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
/**
* A path that is wrapping an entity type literal.
*
* @author Christian Beikov
* @see SqmPath#type()
*/
public class SqmBasicValuedEntityTypePath<T> extends SqmBasicValuedSimplePath<T> {
private final SqmLiteralEntityType<T> literal;
public SqmBasicValuedEntityTypePath(
NavigablePath navigablePath,
EntityDomainType<T> referencedPathSource,
SqmPath<?> lhs,
NodeBuilder nodeBuilder) {
this( navigablePath, referencedPathSource, lhs, null, nodeBuilder );
}
public SqmBasicValuedEntityTypePath(
NavigablePath navigablePath,
EntityDomainType<T> referencedPathSource,
SqmPath<?> lhs,
String explicitAlias,
NodeBuilder nodeBuilder) {
super( navigablePath, referencedPathSource, lhs, explicitAlias, nodeBuilder );
this.literal = new SqmLiteralEntityType<>( referencedPathSource, nodeBuilder );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Visitation
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitEntityTypeLiteralExpression( literal );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "type(" );
super.appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -16,6 +16,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.type.descriptor.java.BasicJavaType;
import org.hibernate.type.descriptor.java.JavaType;
@ -42,6 +43,27 @@ public class SqmBasicValuedSimplePath<T>
super( navigablePath, referencedPathSource, lhs, explicitAlias, nodeBuilder );
}
@Override
public SqmBasicValuedSimplePath<T> copy(SqmCopyContext context) {
final SqmBasicValuedSimplePath<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmBasicValuedSimplePath<T> path = context.registerCopy(
this,
new SqmBasicValuedSimplePath<>(
getNavigablePath(),
getReferencedPathSource(),
getLhs().copy( context ),
getExplicitAlias(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SemanticPathPart

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -49,6 +50,29 @@ public class SqmCorrelatedBagJoin<O, T> extends SqmBagJoin<O, T> implements SqmC
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedBagJoin<O, T> copy(SqmCopyContext context) {
final SqmCorrelatedBagJoin<O, T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedBagJoin<O, T> path = context.registerCopy(
this,
new SqmCorrelatedBagJoin<>(
getLhs().copy( context ),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder(),
correlatedRootJoin.copy( context ),
correlationParent.copy( context )
)
);
copyTo( path, context );
return path;
}
@Override
public SqmBagJoin<O, T> getCorrelationParent() {
return correlationParent;

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -41,6 +42,26 @@ public class SqmCorrelatedCrossJoin<T> extends SqmCrossJoin<T> implements SqmCor
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedCrossJoin<T> copy(SqmCopyContext context) {
final SqmCorrelatedCrossJoin<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedCrossJoin<T> path = context.registerCopy(
this,
new SqmCorrelatedCrossJoin<>(
getReferencedPathSource(),
getExplicitAlias(),
getRoot().copy( context ),
correlatedRootJoin.copy( context ),
correlationParent.copy( context )
)
);
copyTo( path, context );
return path;
}
@Override
public SqmCrossJoin<T> getCorrelationParent() {
return correlationParent;

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -44,6 +45,27 @@ public class SqmCorrelatedEntityJoin<T> extends SqmEntityJoin<T> implements SqmC
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedEntityJoin<T> copy(SqmCopyContext context) {
final SqmCorrelatedEntityJoin<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedEntityJoin<T> path = context.registerCopy(
this,
new SqmCorrelatedEntityJoin<>(
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
getRoot().copy( context ),
correlatedRootJoin.copy( context ),
correlationParent.copy( context )
)
);
copyTo( path, context );
return path;
}
@Override
public SqmEntityJoin<T> getCorrelationParent() {
return correlationParent;

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -49,6 +50,29 @@ public class SqmCorrelatedListJoin<O, T> extends SqmListJoin<O, T> implements Sq
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedListJoin<O, T> copy(SqmCopyContext context) {
final SqmCorrelatedListJoin<O, T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedListJoin<O, T> path = context.registerCopy(
this,
new SqmCorrelatedListJoin<>(
getLhs().copy( context ),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder(),
correlatedRootJoin.copy( context ),
correlationParent.copy( context )
)
);
copyTo( path, context );
return path;
}
@Override
public SqmListJoin<O, T> getCorrelationParent() {
return correlationParent;

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -49,6 +50,29 @@ public class SqmCorrelatedMapJoin<O, K, V> extends SqmMapJoin<O, K, V> implement
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedMapJoin<O, K, V> copy(SqmCopyContext context) {
final SqmCorrelatedMapJoin<O, K, V> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedMapJoin<O, K, V> path = context.registerCopy(
this,
new SqmCorrelatedMapJoin<>(
getLhs().copy( context ),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder(),
correlatedRootJoin.copy( context ),
correlationParent.copy( context )
)
);
copyTo( path, context );
return path;
}
@Override
public SqmMapJoin<O, K, V> getCorrelationParent() {
return correlationParent;

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.query.sqm.tree.domain;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -30,6 +31,20 @@ public class SqmCorrelatedPluralPartJoin<O, T> extends SqmPluralPartJoin<O, T> i
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedPluralPartJoin<O, T> copy(SqmCopyContext context) {
final SqmCorrelatedPluralPartJoin<O, T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedPluralPartJoin<O, T> path = context.registerCopy(
this,
new SqmCorrelatedPluralPartJoin<>( correlationParent.copy( context ) )
);
copyTo( path, context );
return path;
}
@Override
public SqmPluralPartJoin<O, T> getCorrelationParent() {
return correlationParent;

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmRoot;
/**
@ -27,6 +28,20 @@ public class SqmCorrelatedRoot<T> extends SqmRoot<T> implements SqmPathWrapper<T
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedRoot<T> copy(SqmCopyContext context) {
final SqmCorrelatedRoot<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedRoot<T> path = context.registerCopy(
this,
new SqmCorrelatedRoot<>( correlationParent.copy( context ) )
);
copyTo( path, context );
return path;
}
@Override
public SqmRoot<T> getCorrelationParent() {
return correlationParent;

View File

@ -10,6 +10,7 @@ import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -26,6 +27,24 @@ public class SqmCorrelatedRootJoin<T> extends SqmRoot<T> implements SqmCorrelati
super( navigablePath, referencedNavigable, nodeBuilder );
}
@Override
public SqmCorrelatedRootJoin<T> copy(SqmCopyContext context) {
final SqmCorrelatedRootJoin<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedRootJoin<T> path = context.registerCopy(
this,
new SqmCorrelatedRootJoin<>(
getNavigablePath(),
getReferencedPathSource(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@SuppressWarnings("unchecked")
public static <X, J extends SqmJoin<X, ?>> SqmCorrelatedRootJoin<X> create(J correlationParent, J correlatedJoin) {
final SqmFrom<?, X> parentPath = (SqmFrom<?, X>) correlationParent.getParentPath();

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.SetPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -49,6 +50,29 @@ public class SqmCorrelatedSetJoin<O, T> extends SqmSetJoin<O, T> implements SqmC
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedSetJoin<O, T> copy(SqmCopyContext context) {
final SqmCorrelatedSetJoin<O, T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedSetJoin<O, T> path = context.registerCopy(
this,
new SqmCorrelatedSetJoin<>(
getLhs().copy( context ),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder(),
correlatedRootJoin.copy( context ),
correlationParent.copy( context )
)
);
copyTo( path, context );
return path;
}
@Override
public SqmSetJoin<O, T> getCorrelationParent() {
return correlationParent;

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -49,6 +50,29 @@ public class SqmCorrelatedSingularJoin<O, T> extends SqmSingularJoin<O, T> imple
this.correlationParent = correlationParent;
}
@Override
public SqmCorrelatedSingularJoin<O, T> copy(SqmCopyContext context) {
final SqmCorrelatedSingularJoin<O, T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCorrelatedSingularJoin<O, T> path = context.registerCopy(
this,
new SqmCorrelatedSingularJoin<>(
getLhs().copy( context ),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder(),
correlatedRootJoin.copy( context ),
correlationParent.copy( context )
)
);
copyTo( path, context );
return path;
}
@Override
public SqmSingularJoin<O, T> getCorrelationParent() {
return correlationParent;

View File

@ -10,25 +10,42 @@ import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Steve Ebersole
*/
public class SqmElementAggregateFunction<T> extends AbstractSqmSpecificPluralPartPath<T> {
public static final String NAVIGABLE_NAME = "{max-element}";
private final String functionName;
public SqmElementAggregateFunction(SqmPath<?> pluralDomainPath, String functionName) {
//noinspection unchecked
super(
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), "{" + functionName + "-element}" ),
pluralDomainPath,
(PluralPersistentAttribute<?, ?, T>) pluralDomainPath.getReferencedPathSource()
);
this.functionName = functionName;
}
@Override
public SqmElementAggregateFunction<T> copy(SqmCopyContext context) {
final SqmElementAggregateFunction<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmElementAggregateFunction<T> path = context.registerCopy(
this,
new SqmElementAggregateFunction<>(
getLhs().copy( context ),
functionName
)
);
copyTo( path, context );
return path;
}
public String getFunctionName() {
return functionName;
}

View File

@ -16,6 +16,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -46,6 +47,27 @@ public class SqmEmbeddedValuedSimplePath<T>
assert referencedPathSource.getSqmPathType() instanceof EmbeddableDomainType;
}
@Override
public SqmEmbeddedValuedSimplePath<T> copy(SqmCopyContext context) {
final SqmEmbeddedValuedSimplePath<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmEmbeddedValuedSimplePath<T> path = context.registerCopy(
this,
new SqmEmbeddedValuedSimplePath<>(
getNavigablePath(),
getReferencedPathSource(),
getLhs().copy( context ),
getExplicitAlias(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public SqmPath<?> resolvePathPart(
String name,

View File

@ -13,6 +13,7 @@ import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Steve Ebersole
@ -26,6 +27,26 @@ public class SqmEntityValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
super( navigablePath, referencedPathSource, lhs, nodeBuilder );
}
@Override
public SqmEntityValuedSimplePath<T> copy(SqmCopyContext context) {
final SqmEntityValuedSimplePath<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmEntityValuedSimplePath<T> path = context.registerCopy(
this,
new SqmEntityValuedSimplePath<>(
getNavigablePath(),
getReferencedPathSource(),
getLhs().copy( context ),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public SqmPath<?> resolvePathPart(
String name,

View File

@ -12,20 +12,19 @@ import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Steve Ebersole
*/
public class SqmIndexAggregateFunction<T> extends AbstractSqmSpecificPluralPartPath<T> {
public static final String NAVIGABLE_NAME = "{max-index}";
private final SqmPathSource<T> indexPathSource;
private final String functionName;
public SqmIndexAggregateFunction(SqmPath<?> pluralDomainPath, String functionName) {
//noinspection unchecked
super(
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), "{" + functionName + "-index}" ),
pluralDomainPath,
(PluralPersistentAttribute<?, ?, T>) pluralDomainPath.getReferencedPathSource()
);
@ -44,6 +43,24 @@ public class SqmIndexAggregateFunction<T> extends AbstractSqmSpecificPluralPartP
}
}
@Override
public SqmIndexAggregateFunction<T> copy(SqmCopyContext context) {
final SqmIndexAggregateFunction<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmIndexAggregateFunction<T> path = context.registerCopy(
this,
new SqmIndexAggregateFunction<>(
getLhs().copy( context ),
functionName
)
);
copyTo( path, context );
return path;
}
public String getFunctionName() {
return functionName;
}

View File

@ -12,6 +12,8 @@ import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.PathException;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
/**
@ -32,7 +34,25 @@ public class SqmIndexedCollectionAccessPath<T> extends AbstractSqmPath<T> implem
pluralDomainPath.nodeBuilder()
);
this.selectorExpression = selectorExpression;
}
@Override
public SqmIndexedCollectionAccessPath<T> copy(SqmCopyContext context) {
final SqmIndexedCollectionAccessPath<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmIndexedCollectionAccessPath<T> path = context.registerCopy(
this,
new SqmIndexedCollectionAccessPath<T>(
getNavigablePath(),
getLhs().copy( context ),
selectorExpression.copy( context )
)
);
copyTo( path, context );
return path;
}
public SqmExpression<?> getSelectorExpression() {

View File

@ -7,8 +7,6 @@
package org.hibernate.query.sqm.tree.domain;
import java.util.List;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
@ -19,10 +17,14 @@ import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
/**
* @author Steve Ebersole
*/
@ -50,6 +52,28 @@ public class SqmListJoin<O,E>
super( lhs, navigablePath, listAttribute, alias, joinType, fetched, nodeBuilder );
}
@Override
public SqmListJoin<O, E> copy(SqmCopyContext context) {
final SqmListJoin<O, E> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmListJoin<O, E> path = context.registerCopy(
this,
new SqmListJoin<>(
getLhs().copy( context ),
getNavigablePath(),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public ListPersistentAttribute<O, E> getReferencedPathSource() {
return (ListPersistentAttribute<O, E>) super.getReferencedPathSource();

View File

@ -16,6 +16,7 @@ import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.type.descriptor.java.JavaType;
@ -52,6 +53,19 @@ public class SqmMapEntryReference<K,V>
.getDescriptor( Map.Entry.class );
}
@Override
public SqmMapEntryReference<K, V> copy(SqmCopyContext context) {
final SqmMapEntryReference<K, V> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmMapEntryReference<K, V> path = context.registerCopy(
this,
new SqmMapEntryReference<>( mapPath.copy( context ), nodeBuilder() )
);
return path;
}
@Override
public String getAlias() {
return explicitAlias;

View File

@ -20,6 +20,7 @@ import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
@ -50,6 +51,28 @@ public class SqmMapJoin<O, K, V>
super( lhs, navigablePath, pluralValuedNavigable, alias, joinType, fetched, nodeBuilder );
}
@Override
public SqmMapJoin<O, K, V> copy(SqmCopyContext context) {
final SqmMapJoin<O, K, V> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmMapJoin<O, K, V> path = context.registerCopy(
this,
new SqmMapJoin<>(
getLhs().copy( context ),
getNavigablePath(),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public MapPersistentAttribute<O, K, V> getReferencedPathSource() {
return(MapPersistentAttribute<O, K, V>) super.getReferencedPathSource();

View File

@ -24,6 +24,8 @@ import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.ParsingException;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmNode;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.type.descriptor.java.JavaType;
@ -156,4 +158,7 @@ public interface SqmPath<T> extends SqmExpression<T>, SemanticPathPart, JpaPath<
@Override
<Y> SqmPath<Y> get(String attributeName);
@Override
SqmPath<T> copy(SqmCopyContext context);
}

View File

@ -14,6 +14,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.spi.SqmCreationHelper;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin;
@ -57,6 +58,27 @@ public class SqmPluralPartJoin<O,T> extends AbstractSqmJoin<O,T> implements SqmQ
);
}
@Override
public SqmPluralPartJoin<O, T> copy(SqmCopyContext context) {
final SqmPluralPartJoin<O, T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmPluralPartJoin<O, T> path = context.registerCopy(
this,
new SqmPluralPartJoin<>(
(SqmFrom<?, O>) getLhs().copy( context ),
getNavigablePath(),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public SqmPredicate getJoinPredicate() {
return null;

View File

@ -18,6 +18,7 @@ import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.hql.spi.SqmPathRegistry;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.from.SqmFrom;
@ -48,6 +49,27 @@ public class SqmPluralValuedSimplePath<E> extends AbstractSqmSimplePath<E> {
super( navigablePath, referencedNavigable, lhs, explicitAlias, nodeBuilder );
}
@Override
public SqmPluralValuedSimplePath<E> copy(SqmCopyContext context) {
final SqmPluralValuedSimplePath<E> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmPluralValuedSimplePath<E> path = context.registerCopy(
this,
new SqmPluralValuedSimplePath<>(
getNavigablePath(),
getReferencedPathSource(),
getLhs().copy( context ),
getExplicitAlias(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public PluralPersistentAttribute<?, ?, E> getReferencedPathSource() {
return (PluralPersistentAttribute<?, ?, E>) super.getReferencedPathSource();

View File

@ -7,9 +7,6 @@
package org.hibernate.query.sqm.tree.domain;
import java.util.Set;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.SetPersistentAttribute;
@ -19,10 +16,15 @@ import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.criteria.JpaSetJoin;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
/**
* @author Steve Ebersole
*/
@ -49,6 +51,28 @@ public class SqmSetJoin<O, E>
super( lhs, navigablePath, pluralValuedNavigable, alias, joinType, fetched, nodeBuilder );
}
@Override
public SqmSetJoin<O, E> copy(SqmCopyContext context) {
final SqmSetJoin<O, E> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmSetJoin<O, E> path = context.registerCopy(
this,
new SqmSetJoin<>(
getLhs().copy( context ),
getNavigablePath(),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public SetPersistentAttribute<O,E> getReferencedPathSource() {
return (SetPersistentAttribute<O, E>) super.getReferencedPathSource();

View File

@ -14,6 +14,7 @@ import org.hibernate.query.spi.NavigablePath;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmJoinable;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmFrom;
@ -53,6 +54,28 @@ public class SqmSingularJoin<O,T> extends AbstractSqmAttributeJoin<O,T> {
super( lhs, navigablePath, joinedNavigable, alias, joinType, fetched, nodeBuilder );
}
@Override
public SqmSingularJoin<O, T> copy(SqmCopyContext context) {
final SqmSingularJoin<O, T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmSingularJoin<O, T> path = context.registerCopy(
this,
new SqmSingularJoin<>(
getLhs().copy( context ),
getNavigablePath(),
getReferencedPathSource(),
getExplicitAlias(),
getSqmJoinType(),
isFetched(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override
public SingularPersistentAttribute<O, T> getReferencedPathSource() {
return (SingularPersistentAttribute<O, T>) super.getReferencedPathSource();

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmJoin;
@ -42,10 +43,21 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<T, ?>) join );
public SqmTreatedBagJoin<O, T, S> copy(SqmCopyContext context) {
final SqmTreatedBagJoin<O, T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedBagJoin<O, T, S> path = context.registerCopy(
this,
new SqmTreatedBagJoin<>(
wrappedPath.copy( context ),
treatTarget,
getExplicitAlias()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
import org.hibernate.query.sqm.tree.from.SqmJoin;
@ -34,10 +35,21 @@ public class SqmTreatedCrossJoin<T, S extends T> extends SqmCrossJoin<S> impleme
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<T, ?>) join );
public SqmTreatedCrossJoin<T, S> copy(SqmCopyContext context) {
final SqmTreatedCrossJoin<T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedCrossJoin<T, S> path = context.registerCopy(
this,
new SqmTreatedCrossJoin<>(
wrappedPath.copy( context ),
treatTarget,
getExplicitAlias()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
import org.hibernate.query.sqm.tree.from.SqmJoin;
@ -37,10 +38,21 @@ public class SqmTreatedEntityJoin<T, S extends T> extends SqmEntityJoin<S> imple
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<T, ?>) join );
public SqmTreatedEntityJoin<T, S> copy(SqmCopyContext context) {
final SqmTreatedEntityJoin<T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedEntityJoin<T, S> path = context.registerCopy(
this,
new SqmTreatedEntityJoin<>(
wrappedPath.copy( context ),
treatTarget,
getExplicitAlias()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -11,6 +11,7 @@ import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmJoin;
@ -44,10 +45,21 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<T, ?>) join );
public SqmTreatedListJoin<O, T, S> copy(SqmCopyContext context) {
final SqmTreatedListJoin<O, T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedListJoin<O, T, S> path = context.registerCopy(
this,
new SqmTreatedListJoin<>(
wrappedPath.copy( context ),
treatTarget,
getExplicitAlias()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmJoin;
/**
@ -40,10 +41,21 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<V, ?>) join );
public SqmTreatedMapJoin<O, K, V, S> copy(SqmCopyContext context) {
final SqmTreatedMapJoin<O, K, V, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedMapJoin<O, K, V, S> path = context.registerCopy(
this,
new SqmTreatedMapJoin<>(
wrappedPath.copy( context ),
treatTarget,
getExplicitAlias()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmJoin;
@ -39,10 +40,21 @@ public class SqmTreatedPluralPartJoin<O,T, S extends T> extends SqmPluralPartJoi
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<T, ?>) join );
public SqmTreatedPluralPartJoin<O, T, S> copy(SqmCopyContext context) {
final SqmTreatedPluralPartJoin<O, T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedPluralPartJoin<O, T, S> path = context.registerCopy(
this,
new SqmTreatedPluralPartJoin<>(
wrappedPath.copy( context ),
treatTarget,
getExplicitAlias()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -37,10 +38,20 @@ public class SqmTreatedRoot<T, S extends T> extends SqmRoot<S> implements SqmTre
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<T, ?>) join );
public SqmRoot<S> copy(SqmCopyContext context) {
final SqmTreatedRoot<T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedRoot<T, S> path = context.registerCopy(
this,
new SqmTreatedRoot<>(
wrappedPath.copy( context ),
treatTarget
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.SetPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmJoin;
@ -42,10 +43,21 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<T, ?>) join );
public SqmTreatedSetJoin<O, T, S> copy(SqmCopyContext context) {
final SqmTreatedSetJoin<O, T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedSetJoin<O, T, S> path = context.registerCopy(
this,
new SqmTreatedSetJoin<>(
wrappedPath.copy( context ),
treatTarget,
getExplicitAlias()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.PathException;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Steve Ebersole
@ -56,9 +57,22 @@ public class SqmTreatedSimplePath<T, S extends T>
}
@Override
public void registerReusablePath(SqmPath<?> path) {
super.registerReusablePath( path );
wrappedPath.registerReusablePath( path );
public SqmTreatedSimplePath<T, S> copy(SqmCopyContext context) {
final SqmTreatedSimplePath<T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedSimplePath<T, S> path = context.registerCopy(
this,
new SqmTreatedSimplePath<>(
wrappedPath.copy( context ),
getTreatTarget(),
nodeBuilder()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -10,6 +10,7 @@ import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmJoin;
@ -42,10 +43,21 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
}
@Override
public void addSqmJoin(SqmJoin<S, ?> join) {
super.addSqmJoin( join );
//noinspection unchecked
wrappedPath.addSqmJoin( (SqmJoin<T, ?>) join );
public SqmTreatedSingularJoin<O, T, S> copy(SqmCopyContext context) {
final SqmTreatedSingularJoin<O, T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedSingularJoin<O, T, S> path = context.registerCopy(
this,
new SqmTreatedSingularJoin<>(
wrappedPath.copy( context ),
treatTarget,
getExplicitAlias()
)
);
copyTo( path, context );
return path;
}
@Override

View File

@ -9,7 +9,6 @@ package org.hibernate.query.sqm.tree.expression;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import jakarta.persistence.criteria.Expression;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaSelection;
@ -22,6 +21,8 @@ import org.hibernate.query.sqm.tree.predicate.SqmInPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.type.descriptor.java.JavaType;
import jakarta.persistence.criteria.Expression;
import static org.hibernate.query.internal.QueryHelper.highestPrecedenceType;
/**

View File

@ -16,6 +16,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
@ -45,6 +46,12 @@ public class JpaCriteriaParameter<T>
this.allowsMultiValuedBinding = allowsMultiValuedBinding;
}
protected JpaCriteriaParameter(JpaCriteriaParameter<T> original) {
super( original.getNodeType(), original.nodeBuilder() );
this.name = original.name;
this.allowsMultiValuedBinding = original.allowsMultiValuedBinding;
}
private static <T> SqmExpressible<T> toSqmType(BindableType<T> type, NodeBuilder nodeBuilder) {
if ( type == null ) {
return null;
@ -54,6 +61,12 @@ public class JpaCriteriaParameter<T>
);
}
@Override
public JpaCriteriaParameter<T> copy(SqmCopyContext context) {
// Don't create a copy of regular parameters because identity is important here
return this;
}
@Override
public String getName() {
return name;

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* Models a reference to a {@link org.hibernate.query.sqm.tree.select.SqmAliasedNode}
@ -23,6 +24,22 @@ public class SqmAliasedNodeRef extends AbstractSqmExpression<Integer> {
this.position = position;
}
private SqmAliasedNodeRef(SqmAliasedNodeRef original) {
super( original.getNodeType(), original.nodeBuilder() );
this.position = original.position;
}
@Override
public SqmAliasedNodeRef copy(SqmCopyContext context) {
final SqmAliasedNodeRef existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmAliasedNodeRef expression = context.registerCopy( this, new SqmAliasedNodeRef( this ) );
copyTo( expression, context );
return expression;
}
public int getPosition() {
return position;
}

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
/**
@ -22,6 +23,23 @@ public class SqmAny<T> extends AbstractSqmExpression<T> {
this.subquery = subquery;
}
@Override
public SqmAny<T> copy(SqmCopyContext context) {
final SqmAny<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmAny<T> expression = context.registerCopy(
this,
new SqmAny<>(
subquery.copy( context ),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
public SqmSubQuery<T> getSubquery() {
return subquery;
}

View File

@ -11,6 +11,7 @@ import org.hibernate.query.sqm.BinaryArithmeticOperator;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
/**
@ -61,6 +62,26 @@ public class SqmBinaryArithmetic<T> extends AbstractSqmExpression<T> implements
applyInferableType( expressibleType );
}
@Override
public SqmBinaryArithmetic<T> copy(SqmCopyContext context) {
final SqmBinaryArithmetic<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmBinaryArithmetic<T> expression = context.registerCopy(
this,
new SqmBinaryArithmetic<>(
operator,
lhsOperand.copy( context ),
rhsOperand.copy( context ),
getNodeType(),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitBinaryArithmeticExpression( this );

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Gavin King
@ -27,6 +28,25 @@ public class SqmByUnit extends AbstractSqmExpression<Long> {
this.duration = duration;
}
@Override
public SqmByUnit copy(SqmCopyContext context) {
final SqmByUnit existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmByUnit expression = context.registerCopy(
this,
new SqmByUnit(
unit.copy( context ),
duration.copy( context ),
getNodeType(),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
public SqmDurationUnit<?> getUnit() {
return unit;
}

View File

@ -14,6 +14,7 @@ import org.hibernate.query.internal.QueryHelper;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import jakarta.persistence.criteria.Expression;
@ -41,6 +42,35 @@ public class SqmCaseSearched<R>
this.whenFragments = new ArrayList<>( estimateWhenSize );
}
@Override
public SqmCaseSearched<R> copy(SqmCopyContext context) {
final SqmCaseSearched<R> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCaseSearched<R> caseSearched = context.registerCopy(
this,
new SqmCaseSearched<>(
getNodeType(),
whenFragments.size(),
nodeBuilder()
)
);
for ( WhenFragment<R> whenFragment : whenFragments ) {
caseSearched.whenFragments.add(
new WhenFragment<>(
whenFragment.predicate.copy( context ),
whenFragment.result.copy( context )
)
);
}
if ( otherwise != null ) {
caseSearched.otherwise = otherwise.copy( context );
}
copyTo( caseSearched, context );
return caseSearched;
}
public List<WhenFragment<R>> getWhenFragments() {
return whenFragments;
}

View File

@ -9,8 +9,6 @@ package org.hibernate.query.sqm.tree.expression;
import java.util.ArrayList;
import java.util.List;
import jakarta.persistence.criteria.Expression;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaSimpleCase;
@ -19,9 +17,12 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import jakarta.persistence.criteria.Expression;
/**
* @author Steve Ebersole
*/
@ -48,6 +49,36 @@ public class SqmCaseSimple<T, R>
this.fixture = fixture;
}
@Override
public SqmCaseSimple<T, R> copy(SqmCopyContext context) {
final SqmCaseSimple<T, R> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCaseSimple<T, R> caseSearched = context.registerCopy(
this,
new SqmCaseSimple<>(
fixture.copy( context ),
getNodeType(),
whenFragments.size(),
nodeBuilder()
)
);
for ( SqmCaseSimple.WhenFragment<T, R> whenFragment : whenFragments ) {
caseSearched.whenFragments.add(
new SqmCaseSimple.WhenFragment<>(
whenFragment.checkValue.copy( context ),
whenFragment.result.copy( context )
)
);
}
if ( otherwise != null ) {
caseSearched.otherwise = otherwise.copy( context );
}
copyTo( caseSearched, context );
return caseSearched;
}
public SqmExpression<T> getFixture() {
return fixture;
}
@ -131,6 +162,11 @@ public class SqmCaseSimple<T, R>
this.result = result;
}
private WhenFragment(WhenFragment<T, R> original, SqmCopyContext context) {
this.checkValue = original.checkValue.copy( context );
this.result = original.result.copy( context );
}
public SqmExpression<T> getCheckValue() {
return checkValue;
}

View File

@ -11,6 +11,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -70,6 +71,11 @@ public class SqmCastTarget<T> extends AbstractSqmNode implements SqmTypedNode<T>
this.scale = scale;
}
@Override
public SqmCastTarget<T> copy(SqmCopyContext context) {
return this;
}
public ReturnableType<T> getType() {
return type;
}

View File

@ -6,6 +6,9 @@
*/
package org.hibernate.query.sqm.tree.expression;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.query.criteria.JpaCoalesce;
import org.hibernate.query.criteria.JpaExpression;
@ -13,10 +16,9 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import jakarta.persistence.criteria.Expression;
import java.util.ArrayList;
import java.util.List;
/**
* @author Steve Ebersole
@ -42,6 +44,27 @@ public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoale
this.arguments = new ArrayList<>( numberOfArguments );
}
@Override
public SqmCoalesce<T> copy(SqmCopyContext context) {
final SqmCoalesce<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCoalesce<T> coalesce = context.registerCopy(
this,
new SqmCoalesce<>(
getNodeType(),
arguments.size(),
nodeBuilder()
)
);
for ( SqmExpression<? extends T> argument : arguments ) {
coalesce.arguments.add( argument.copy( context ) );
}
copyTo( coalesce, context );
return coalesce;
}
public SqmFunctionDescriptor getFunctionDescriptor() {
return functionDescriptor;
}

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Christian Beikov
@ -18,6 +19,20 @@ public class SqmCollation extends SqmLiteral<String> {
super(value, inherentType, nodeBuilder);
}
@Override
public SqmCollation copy(SqmCopyContext context) {
final SqmCollation existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCollation expression = context.registerCopy(
this,
new SqmCollation( getLiteralValue(), getNodeType(), nodeBuilder() )
);
copyTo( expression, context );
return expression;
}
@Override
public <R> R accept(SemanticQueryWalker<R> walker) {
return walker.visitCollation( this );

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPath;
/**
@ -29,6 +30,24 @@ public class SqmCollectionSize extends AbstractSqmExpression<Integer> {
this.pluralPath = pluralPath;
}
@Override
public SqmCollectionSize copy(SqmCopyContext context) {
final SqmCollectionSize existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmCollectionSize expression = context.registerCopy(
this,
new SqmCollectionSize(
pluralPath.copy( context ),
getNodeType(),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
public SqmPath<?> getPluralPath() {
return pluralPath;
}

View File

@ -10,6 +10,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -21,10 +22,25 @@ public class SqmDistinct<T> extends AbstractSqmNode implements SqmTypedNode<T>,
private final SqmExpression<T> expression;
public SqmDistinct(SqmExpression<T> expression, NodeBuilder builder) {
super(builder);
super( builder );
this.expression = expression;
}
@Override
public SqmDistinct<T> copy(SqmCopyContext context) {
final SqmDistinct<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
return context.registerCopy(
this,
new SqmDistinct<>(
expression.copy( context ),
nodeBuilder()
)
);
}
public SqmExpression<T> getExpression() {
return expression;
}

View File

@ -12,6 +12,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -28,6 +29,11 @@ public class SqmDurationUnit<T> extends AbstractSqmNode implements SqmTypedNode<
this.unit = unit;
}
@Override
public SqmDurationUnit<T> copy(SqmCopyContext context) {
return this;
}
public ReturnableType<T> getType() {
return type;
}

View File

@ -16,6 +16,7 @@ import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.type.descriptor.java.EnumJavaType;
@ -42,6 +43,25 @@ public class SqmEnumLiteral<E extends Enum<E>> extends AbstractSqmExpression<E>
setExpressibleType( this );
}
@Override
public SqmEnumLiteral<E> copy(SqmCopyContext context) {
final SqmEnumLiteral<E> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmEnumLiteral<E> expression = context.registerCopy(
this,
new SqmEnumLiteral<>(
enumValue,
referencedEnumTypeDescriptor,
enumValueName,
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
public E getEnumValue() {
return enumValue;
}

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
/**
@ -22,6 +23,20 @@ public class SqmEvery<T> extends AbstractSqmExpression<T> {
this.subquery = subquery;
}
@Override
public SqmEvery<T> copy(SqmCopyContext context) {
final SqmEvery<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmEvery<T> expression = context.registerCopy(
this,
new SqmEvery<>( subquery.copy( context ), nodeBuilder() )
);
copyTo( expression, context );
return expression;
}
public SqmSubQuery<T> getSubquery() {
return subquery;
}

View File

@ -18,6 +18,7 @@ import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
@ -102,6 +103,9 @@ public interface SqmExpression<T> extends SqmSelectableNode<T>, JpaExpression<T>
@Override
SqmPredicate in(Expression<Collection<?>> values);
@Override
SqmExpression<T> copy(SqmCopyContext context);
default <X> SqmExpression<X> castAs(DomainType<X> type) {
if ( getNodeType() == type ) {
return (SqmExpression<X>) this;

View File

@ -12,6 +12,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -28,6 +29,11 @@ public class SqmExtractUnit<T> extends AbstractSqmNode implements SqmTypedNode<T
this.type = type;
}
@Override
public SqmExtractUnit<T> copy(SqmCopyContext context) {
return this;
}
public TemporalUnit getUnit() {
return unit;
}

View File

@ -21,6 +21,7 @@ import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
@ -51,16 +52,6 @@ public class SqmFieldLiteral<T> implements SqmExpression<T>, SqmExpressible<T>,
);
}
private static <T> T extractValue(Field field) {
try {
//noinspection unchecked
return (T) field.get( null );
}
catch (IllegalAccessException e) {
throw new QueryException( "Could not access Field value for SqmFieldLiteral", e );
}
}
public SqmFieldLiteral(
T value,
JavaType<T> fieldJavaType,
@ -74,6 +65,33 @@ public class SqmFieldLiteral<T> implements SqmExpression<T>, SqmExpressible<T>,
this.expressible = this;
}
private static <T> T extractValue(Field field) {
try {
//noinspection unchecked
return (T) field.get( null );
}
catch (IllegalAccessException e) {
throw new QueryException( "Could not access Field value for SqmFieldLiteral", e );
}
}
@Override
public SqmFieldLiteral<T> copy(SqmCopyContext context) {
final SqmFieldLiteral<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
return context.registerCopy(
this,
new SqmFieldLiteral<>(
value,
fieldJavaType,
fieldName,
nodeBuilder()
)
);
}
public T getValue() {
return value;
}

View File

@ -12,6 +12,7 @@ import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* Effectively a query-literal but we want to handle it specially in the SQM -> SQL AST conversion
@ -51,6 +52,24 @@ public class SqmFormat extends SqmLiteral<String> {
}
}
@Override
public SqmFormat copy(SqmCopyContext context) {
final SqmFormat existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmFormat expression = context.registerCopy(
this,
new SqmFormat(
getLiteralValue(),
getNodeType(),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
@Override
public <R> R accept(SemanticQueryWalker<R> walker) {
return walker.visitFormat( this );

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.query.sqm.tree.expression;
import java.util.List;
import org.hibernate.query.criteria.JpaFunction;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.hql.spi.SqmCreationState;
@ -19,8 +21,6 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import java.util.List;
/**
* A SQM function
*

View File

@ -11,6 +11,7 @@ import java.util.function.Consumer;
import org.hibernate.query.BindableType;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
@ -35,6 +36,22 @@ public class SqmJpaCriteriaParameterWrapper<T>
this.jpaCriteriaParameter = jpaCriteriaParameter;
}
@Override
public SqmJpaCriteriaParameterWrapper<T> copy(SqmCopyContext context) {
final SqmJpaCriteriaParameterWrapper<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
return context.registerCopy(
this,
new SqmJpaCriteriaParameterWrapper<>(
getNodeType(),
jpaCriteriaParameter.copy( context ),
nodeBuilder()
)
);
}
@Override
public String getName() {
return jpaCriteriaParameter.getName();

View File

@ -10,6 +10,7 @@ import org.hibernate.query.internal.QueryLiteralHelper;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -36,6 +37,24 @@ public class SqmLiteral<T> extends AbstractSqmExpression<T> {
this.value = null;
}
@Override
public SqmLiteral<T> copy(SqmCopyContext context) {
final SqmLiteral<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmLiteral<T> expression = context.registerCopy(
this,
new SqmLiteral<>(
getLiteralValue(),
getNodeType(),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
public T getLiteralValue() {
return value;
}

View File

@ -13,6 +13,7 @@ import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
@ -35,6 +36,23 @@ public class SqmLiteralEntityType<T>
this.entityType = entityType;
}
@Override
public SqmLiteralEntityType<T> copy(SqmCopyContext context) {
final SqmLiteralEntityType<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmLiteralEntityType<T> expression = context.registerCopy(
this,
new SqmLiteralEntityType<>(
entityType,
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
@Override
public EntityDomainType<T> getNodeType() {
return entityType;

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Steve Ebersole
@ -26,6 +27,23 @@ public class SqmLiteralNull<T> extends SqmLiteral<T> {
super( expressibleType, nodeBuilder );
}
@Override
public SqmLiteralNull<T> copy(SqmCopyContext context) {
final SqmLiteralNull<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmLiteralNull<T> expression = context.registerCopy(
this,
new SqmLiteralNull<>(
getNodeType(),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitLiteral( this );

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
/**
@ -49,6 +50,25 @@ public class SqmModifiedSubQueryExpression<T> extends AbstractSqmExpression<T> {
this.modifier = modifier;
}
@Override
public SqmModifiedSubQueryExpression<T> copy(SqmCopyContext context) {
final SqmModifiedSubQueryExpression<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmModifiedSubQueryExpression<T> expression = context.registerCopy(
this,
new SqmModifiedSubQueryExpression<>(
subQuery.copy( context ),
modifier,
getNodeType(),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
public Modifier getModifier() {
return modifier;
}

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* Represents a named query parameter in the SQM tree.
@ -31,6 +32,25 @@ public class SqmNamedParameter<T> extends AbstractSqmParameter<T> {
this.name = name;
}
@Override
public SqmNamedParameter<T> copy(SqmCopyContext context) {
final SqmNamedParameter<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmNamedParameter<T> expression = context.registerCopy(
this,
new SqmNamedParameter<>(
name,
allowMultiValuedBinding(),
getNodeType(),
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitNamedParameterExpression( this );

Some files were not shown because too many files have changed in this diff Show More