Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.internal;

import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.query.spi.AbstractQueryParameter;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.type.BindableType;


/**
* QueryParameter impl for unnamed JPA Criteria-parameters.
*/
public class QueryParameterIdentifiedImpl<T> extends AbstractQueryParameter<T> {
/**
* Create an identified parameter descriptor from the SQM parameter
*
* @param parameter The source parameter info
*
* @return The parameter descriptor
*/
public static <T> QueryParameterIdentifiedImpl<T> fromSqm(SqmJpaCriteriaParameterWrapper<T> parameter) {
assert parameter.getName() == null;
assert parameter.getPosition() == null;
return new QueryParameterIdentifiedImpl<>(
parameter.getUnnamedParameterId(),
parameter.allowMultiValuedBinding(),
parameter.getAnticipatedType()
);
}

private final int unnamedParameterId;

private QueryParameterIdentifiedImpl(int unnamedParameterId, boolean allowMultiValuedBinding, @Nullable BindableType<T> anticipatedType) {
super( allowMultiValuedBinding, anticipatedType );
this.unnamedParameterId = unnamedParameterId;
}

public int getUnnamedParameterId() {
return unnamedParameterId;
}

@Override
public NamedQueryMemento.ParameterMemento toMemento() {
return session -> new QueryParameterIdentifiedImpl<>( unnamedParameterId, allowsMultiValuedBinding(), getHibernateType() );
}

@Override
public boolean equals(Object o) {
return this == o
|| o instanceof QueryParameterIdentifiedImpl<?>
&& unnamedParameterId == ( (QueryParameterIdentifiedImpl<?>) o ).unnamedParameterId;
}

@Override
public int hashCode() {
return unnamedParameterId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ else if ( parameter.getPosition() != null ) {

protected <P> QueryParameterBinding<P> locateBinding(QueryParameterImplementor<P> parameter) {
getCheckOpen();
return getQueryParameterBindings().getBinding( parameter );
return getQueryParameterBindings().getBinding( getQueryParameter( parameter ) );
}

protected <P> QueryParameterBinding<P> locateBinding(String name) {
Expand All @@ -732,7 +732,11 @@ protected <P> QueryParameterBinding<P> locateBinding(int position) {
public boolean isBound(Parameter<?> param) {
getCheckOpen();
final QueryParameterImplementor<?> parameter = getParameterMetadata().resolve( param );
return parameter != null && getQueryParameterBindings().isBound( parameter );
return parameter != null && getQueryParameterBindings().isBound( getQueryParameter( parameter ) );
}

protected <P> QueryParameterImplementor<P> getQueryParameter(QueryParameterImplementor<P> parameter) {
return parameter;
}

public <T> T getParameterValue(Parameter<T> param) {
Expand All @@ -743,7 +747,7 @@ public <T> T getParameterValue(Parameter<T> param) {
throw new IllegalArgumentException( "The parameter [" + param + "] is not part of this Query" );
}

final QueryParameterBinding<T> binding = getQueryParameterBindings().getBinding( parameter );
final QueryParameterBinding<T> binding = getQueryParameterBindings().getBinding( getQueryParameter( parameter ) );
if ( binding == null || !binding.isBound() ) {
throw new IllegalStateException( "Parameter value not yet bound : " + param.toString() );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public AbstractQueryParameter(boolean allowMultiValuedBinding, BindableType<T> a
@Override
public void disallowMultiValuedBinding() {
QUERY_MESSAGE_LOGGER.debugf( "QueryParameter#disallowMultiValuedBinding() called: %s", this );
this.allowMultiValuedBinding = true;
this.allowMultiValuedBinding = false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.spi.SelectQueryPlan;
import org.hibernate.query.sqm.spi.NamedSqmQueryMemento;
import org.hibernate.query.sqm.tree.SqmStatement;
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;
Expand Down Expand Up @@ -150,20 +150,39 @@ else if ( bindType != null ) {
} );

// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
for ( SqmParameter<?> sqmParameter : getDomainParameterXref().getParameterResolutions().getSqmParameters() ) {
bindValueBindCriteriaParameters( getDomainParameterXref(), parameterBindings );
}

protected static void bindValueBindCriteriaParameters(
DomainParameterXref domainParameterXref,
QueryParameterBindings bindings) {
for ( var entry : domainParameterXref.getQueryParameters().entrySet() ) {
final var sqmParameter = entry.getValue().get( 0 );
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> wrapper ) {
bindCriteriaParameter( wrapper );
@SuppressWarnings("unchecked")
final var criteriaParameter = (JpaCriteriaParameter<Object>) wrapper.getJpaCriteriaParameter();
if ( criteriaParameter instanceof ValueBindJpaCriteriaParameter<?> ) {
// Use the anticipated type for binding the value if possible
//noinspection unchecked
final var parameter = (QueryParameterImplementor<Object>) entry.getKey();
bindings.getBinding( parameter )
.setBindValue( criteriaParameter.getValue(), criteriaParameter.getAnticipatedType() );
}
}
}
}

protected <T> void bindCriteriaParameter(SqmJpaCriteriaParameterWrapper<T> sqmParameter) {
final JpaCriteriaParameter<T> criteriaParameter = sqmParameter.getJpaCriteriaParameter();
if ( criteriaParameter instanceof ValueBindJpaCriteriaParameter<?> ) {
// Use the anticipated type for binding the value if possible
getQueryParameterBindings()
.getBinding( criteriaParameter )
.setBindValue( criteriaParameter.getValue(), criteriaParameter.getAnticipatedType() );
@Override
protected <P> QueryParameterImplementor<P> getQueryParameter(QueryParameterImplementor<P> parameter) {
if ( parameter instanceof JpaCriteriaParameter<?> criteriaParameter ) {
final var parameterWrapper = getDomainParameterXref().getParameterResolutions()
.getJpaCriteriaParamResolutions()
.get( criteriaParameter );
//noinspection unchecked
return (QueryParameterImplementor<P>) getDomainParameterXref().getQueryParameter( parameterWrapper );
}
else {
return parameter;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@

import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.hibernate.internal.util.collections.LinkedIdentityHashMap;
import org.hibernate.query.internal.QueryParameterIdentifiedImpl;
import org.hibernate.query.internal.QueryParameterNamedImpl;
import org.hibernate.query.internal.QueryParameterPositionalImpl;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sqm.SqmTreeTransformationLogger;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
Expand All @@ -31,7 +30,7 @@
public class DomainParameterXref {

public static final DomainParameterXref EMPTY = new DomainParameterXref(
new LinkedIdentityHashMap<>( 0 ),
new LinkedHashMap<>( 0 ),
new IdentityHashMap<>( 0 ),
SqmStatement.ParameterResolutions.empty()
);
Expand All @@ -46,8 +45,8 @@ public static DomainParameterXref from(SqmStatement<?> sqmStatement) {
}
else {
final int sqmParamCount = parameterResolutions.getSqmParameters().size();
final Map<QueryParameterImplementor<?>, List<SqmParameter<?>>> sqmParamsByQueryParam =
new LinkedIdentityHashMap<>( sqmParamCount );
final LinkedHashMap<QueryParameterImplementor<?>, List<SqmParameter<?>>> sqmParamsByQueryParam =
new LinkedHashMap<>( sqmParamCount );
final IdentityHashMap<SqmParameter<?>, QueryParameterImplementor<?>> queryParamBySqmParam =
new IdentityHashMap<>( sqmParamCount );

Expand All @@ -60,48 +59,27 @@ public static DomainParameterXref from(SqmStatement<?> sqmStatement) {
);
}

// `xrefMap` is used to help maintain the proper cardinality between an
// SqmParameter and a QueryParameter. Multiple SqmParameter references
// can map to the same QueryParameter. Consider, e.g.,
// `.. where a.b = :param or a.c = :param`. Here we have 2 SqmParameter
// references (one for each occurrence of `:param`) both of which map to
// the same QueryParameter.
final Map<SqmParameter<?>, QueryParameterImplementor<?>> xrefMap = new TreeMap<>();

final QueryParameterImplementor<?> queryParameter = xrefMap.computeIfAbsent(
sqmParameter,
parameter -> {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> sqmJpaCriteriaParameterWrapper ) {
return sqmJpaCriteriaParameterWrapper.getJpaCriteriaParameter();
}
else if ( sqmParameter.getName() != null ) {
return QueryParameterNamedImpl.fromSqm( sqmParameter );
}
else if ( sqmParameter.getPosition() != null ) {
return QueryParameterPositionalImpl.fromSqm( sqmParameter );
}
else {
throw new UnsupportedOperationException(
"Unexpected SqmParameter type : " + sqmParameter );
}
}
);

if ( !sqmParameter.allowMultiValuedBinding() ) {
if ( queryParameter.allowsMultiValuedBinding() ) {
SqmTreeTransformationLogger.LOGGER.debugf(
"SqmParameter [%s] does not allow multi-valued binding, " +
"but mapped to existing QueryParameter [%s] that does - " +
"disallowing multi-valued binding",
sqmParameter,
queryParameter
);
queryParameter.disallowMultiValuedBinding();
final QueryParameterImplementor<?> queryParameter;
if ( sqmParameter.getName() != null ) {
queryParameter = QueryParameterNamedImpl.fromSqm( sqmParameter );
}
else if ( sqmParameter.getPosition() != null ) {
queryParameter = QueryParameterPositionalImpl.fromSqm( sqmParameter );
}
else if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) {
final SqmJpaCriteriaParameterWrapper<?> criteriaParameter = (SqmJpaCriteriaParameterWrapper<?>) sqmParameter;
if ( sqmParameter.allowMultiValuedBinding()
&& sqmParameter.getExpressible() != null
&& sqmParameter.getExpressible().getSqmType() instanceof BasicCollectionType ) {
// The wrapper parameter was inferred to be of a basic collection type,
// so we disallow multivalued bindings, because binding a list of collections isn't useful
criteriaParameter.getJpaCriteriaParameter().disallowMultiValuedBinding();
}
queryParameter = QueryParameterIdentifiedImpl.fromSqm( criteriaParameter );
}
else if ( sqmParameter.getExpressible() != null
&& sqmParameter.getExpressible().getSqmType() instanceof BasicCollectionType ) {
queryParameter.disallowMultiValuedBinding();
else {
throw new UnsupportedOperationException(
"Unexpected SqmParameter type : " + sqmParameter );
}

sqmParamsByQueryParam.computeIfAbsent( queryParameter, impl -> new ArrayList<>() ).add( sqmParameter );
Expand All @@ -118,13 +96,13 @@ else if ( sqmParameter.getExpressible() != null

private final SqmStatement.ParameterResolutions parameterResolutions;

private final Map<QueryParameterImplementor<?>, List<SqmParameter<?>>> sqmParamsByQueryParam;
private final LinkedHashMap<QueryParameterImplementor<?>, List<SqmParameter<?>>> sqmParamsByQueryParam;
private final IdentityHashMap<SqmParameter<?>, QueryParameterImplementor<?>> queryParamBySqmParam;

private Map<SqmParameter<?>,List<SqmParameter<?>>> expansions;

private DomainParameterXref(
Map<QueryParameterImplementor<?>, List<SqmParameter<?>>> sqmParamsByQueryParam,
LinkedHashMap<QueryParameterImplementor<?>, List<SqmParameter<?>>> sqmParamsByQueryParam,
IdentityHashMap<SqmParameter<?>, QueryParameterImplementor<?>> queryParamBySqmParam,
SqmStatement.ParameterResolutions parameterResolutions) {
this.sqmParamsByQueryParam = sqmParamsByQueryParam;
Expand Down Expand Up @@ -180,10 +158,7 @@ public List<SqmParameter<?>> getSqmParameters(QueryParameterImplementor<?> query
}

public QueryParameterImplementor<?> getQueryParameter(SqmParameter<?> sqmParameter) {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> parameterWrapper ) {
return parameterWrapper.getJpaCriteriaParameter();
}
else if ( sqmParameter instanceof QueryParameterImplementor<?> parameterImplementor ) {
if ( sqmParameter instanceof QueryParameterImplementor<?> parameterImplementor ) {
return parameterImplementor;
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
Expand Down Expand Up @@ -226,11 +224,7 @@ public SqmQueryImpl(
parameterBindings = parameterMetadata.createBindings( session.getFactory() );

// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> wrapper ) {
bindCriteriaParameter( wrapper );
}
}
bindValueBindCriteriaParameters( domainParameterXref, parameterBindings );

validateQuery( expectedResultType, sqm, hql );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@
import org.hibernate.query.sqm.spi.InterpretationsKeySource;
import org.hibernate.query.sqm.spi.SqmSelectionQueryImplementor;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection;
Expand Down Expand Up @@ -194,11 +192,7 @@ public SqmSelectionQueryImpl(
parameterBindings = parameterMetadata.createBindings( session.getFactory() );

// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> wrapper ) {
bindCriteriaParameter( wrapper );
}
}
bindValueBindCriteriaParameters( domainParameterXref, parameterBindings );

resultType = determineResultType( sqm, expectedResultType );

Expand Down Expand Up @@ -254,11 +248,7 @@ <E> SqmSelectionQueryImpl(AbstractSqmSelectionQuery<?> original, KeyedPage<E> ke
original.getQueryParameterBindings().visitBindings( this::setBindValues );

// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
for ( SqmParameter<?> sqmParameter : domainParameterXref.getParameterResolutions().getSqmParameters() ) {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> parameterWrapper ) {
bindCriteriaParameter( parameterWrapper );
}
}
bindValueBindCriteriaParameters( domainParameterXref, parameterBindings );

//noinspection unchecked
expectedResultType = (Class<R>) KeyedResult.class;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5932,7 +5932,7 @@ public MappingModelExpressible<?> determineValueMapping(SqmExpression<?> sqmExpr

private MappingModelExpressible<?> determineValueMapping(SqmExpression<?> sqmExpression, FromClauseIndex fromClauseIndex) {
if ( sqmExpression instanceof SqmParameter ) {
return determineValueMapping( (SqmParameter<?>) sqmExpression );
return determineValueMapping( getSqmParameter( sqmExpression ) );
}

if ( sqmExpression instanceof SqmPath ) {
Expand Down Expand Up @@ -8151,10 +8151,12 @@ private InListPredicate processInSingleCriteriaParameter(
SqmInListPredicate<?> sqmPredicate,
JpaCriteriaParameter<?> jpaCriteriaParameter) {
assert jpaCriteriaParameter.allowsMultiValuedBinding();
final QueryParameterBinding<?> domainParamBinding = domainParameterBindings.getBinding( jpaCriteriaParameter );

final SqmJpaCriteriaParameterWrapper<?> sqmWrapper = jpaCriteriaParamResolutions.get( jpaCriteriaParameter );
final QueryParameterImplementor<?> domainParam = domainParameterXref.getQueryParameter( sqmWrapper );
final QueryParameterBinding<?> domainParamBinding = domainParameterBindings.getBinding( domainParam );
if ( domainParamBinding.isMultiValued() ) {
final SqmJpaCriteriaParameterWrapper<?> sqmWrapper = jpaCriteriaParamResolutions.get( jpaCriteriaParameter );
return processInSingleParameter( sqmPredicate, sqmWrapper, jpaCriteriaParameter, domainParamBinding );
return processInSingleParameter( sqmPredicate, sqmWrapper, domainParam, domainParamBinding );
}
else {
return null;
Expand Down
Loading
Loading