HHH-15071 Apply type inference in SQM for like predicate and avoid NPE in query parameters
This commit is contained in:
parent
3d55855a87
commit
7a55c7b34b
|
@ -58,6 +58,6 @@ public abstract class AbstractQueryParameter<T> implements QueryParameterImpleme
|
|||
|
||||
@Override
|
||||
public Class<T> getParameterType() {
|
||||
return anticipatedType.getBindableJavaType();
|
||||
return anticipatedType == null ? null : anticipatedType.getBindableJavaType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
|||
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
||||
|
@ -4805,7 +4806,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return (BasicValuedMapping) paramSqmType;
|
||||
}
|
||||
|
||||
if ( paramSqmType instanceof CompositeSqmPathSource ) {
|
||||
if ( paramSqmType instanceof CompositeSqmPathSource || paramSqmType instanceof EmbeddableDomainType<?> ) {
|
||||
// Try to infer the value mapping since the other side apparently is a path source
|
||||
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
|
||||
if ( inferredValueMapping != null ) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Collection;
|
|||
import java.util.function.Consumer;
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.annotations.Remove;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
|
@ -49,11 +50,8 @@ public interface SqmExpression<T> extends SqmSelectableNode<T>, JpaExpression<T>
|
|||
* @apiNote The SqmExpressible type parameter is dropped here because
|
||||
* the inference could technically cause a change in Java type (i.e.
|
||||
* an implicit cast)
|
||||
*
|
||||
* @deprecated - type inference is now handled during the SQM -> SQL AST transformation
|
||||
*/
|
||||
@Remove
|
||||
@Deprecated
|
||||
@Internal
|
||||
void applyInferableType(SqmExpressible<?> type);
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.tree.predicate;
|
||||
|
||||
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.expression.SqmExpression;
|
||||
|
||||
|
@ -49,6 +51,15 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
|
|||
this.pattern = pattern;
|
||||
this.escapeCharacter = escapeCharacter;
|
||||
this.isCaseSensitive = isCaseSensitive;
|
||||
final SqmExpressible<?> expressibleType = QueryHelper.highestPrecedenceType(
|
||||
matchExpression.getNodeType(),
|
||||
pattern.getNodeType()
|
||||
);
|
||||
matchExpression.applyInferableType( expressibleType );
|
||||
pattern.applyInferableType( expressibleType );
|
||||
if ( escapeCharacter != null ) {
|
||||
escapeCharacter.applyInferableType( expressibleType );
|
||||
}
|
||||
}
|
||||
|
||||
public SqmLikePredicate(
|
||||
|
|
|
@ -10,28 +10,33 @@ 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.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
|
||||
private final SqmExpression leftHandExpression;
|
||||
private final SqmExpression<?> leftHandExpression;
|
||||
private final SqmPath<?> pluralPath;
|
||||
|
||||
public SqmMemberOfPredicate(SqmExpression leftHandExpression, SqmPath<?> pluralPath, NodeBuilder nodeBuilder) {
|
||||
public SqmMemberOfPredicate(SqmExpression<?> leftHandExpression, SqmPath<?> pluralPath, NodeBuilder nodeBuilder) {
|
||||
this( leftHandExpression, pluralPath, false, nodeBuilder );
|
||||
}
|
||||
|
||||
public SqmMemberOfPredicate(
|
||||
SqmExpression leftHandExpression,
|
||||
SqmPath pluralPath,
|
||||
SqmExpression<?> leftHandExpression,
|
||||
SqmPath<?> pluralPath,
|
||||
boolean negated,
|
||||
NodeBuilder nodeBuilder) {
|
||||
super( negated, nodeBuilder );
|
||||
|
||||
this.pluralPath = pluralPath;
|
||||
this.leftHandExpression = leftHandExpression;
|
||||
|
||||
leftHandExpression.applyInferableType(
|
||||
( (SqmPluralValuedSimplePath<?>) pluralPath ).getReferencedPathSource().getElementType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,7 +58,7 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
|
|||
return predicate;
|
||||
}
|
||||
|
||||
public SqmExpression getLeftHandExpression() {
|
||||
public SqmExpression<?> getLeftHandExpression() {
|
||||
return leftHandExpression;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,14 @@ package org.hibernate.orm.test.query.hql;
|
|||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Parameter;
|
||||
import jakarta.persistence.Temporal;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
|
@ -151,6 +154,29 @@ public class ParameterTests extends BaseSqmUnitTest {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParamTypes() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
final Set<Parameter<?>> parameters = session.createQuery(
|
||||
"from Person p where p.pk = :pk and p.name.firstName like :firstName",
|
||||
Person.class
|
||||
).getParameters();
|
||||
assertThat( parameters.size(), equalTo( 2 ) );
|
||||
for ( Parameter<?> parameter : parameters ) {
|
||||
switch ( parameter.getName() ) {
|
||||
case "pk":
|
||||
assertThat( parameter.getParameterType(), equalTo( Integer.class ) );
|
||||
break;
|
||||
case "firstName":
|
||||
assertThat( parameter.getParameterType(), equalTo( String.class ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean exportSchema() {
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue