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
|
@Override
|
||||||
public Class<T> getParameterType() {
|
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.internal.OrdinalEnumValueConverter;
|
||||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
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.EntityDomainType;
|
||||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||||
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
||||||
|
@ -4805,7 +4806,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
return (BasicValuedMapping) paramSqmType;
|
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
|
// Try to infer the value mapping since the other side apparently is a path source
|
||||||
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
|
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
|
||||||
if ( inferredValueMapping != null ) {
|
if ( inferredValueMapping != null ) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Collection;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import jakarta.persistence.criteria.Expression;
|
import jakarta.persistence.criteria.Expression;
|
||||||
|
|
||||||
|
import org.hibernate.Internal;
|
||||||
import org.hibernate.annotations.Remove;
|
import org.hibernate.annotations.Remove;
|
||||||
import org.hibernate.query.ReturnableType;
|
import org.hibernate.query.ReturnableType;
|
||||||
import org.hibernate.metamodel.model.domain.DomainType;
|
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
|
* @apiNote The SqmExpressible type parameter is dropped here because
|
||||||
* the inference could technically cause a change in Java type (i.e.
|
* the inference could technically cause a change in Java type (i.e.
|
||||||
* an implicit cast)
|
* an implicit cast)
|
||||||
*
|
|
||||||
* @deprecated - type inference is now handled during the SQM -> SQL AST transformation
|
|
||||||
*/
|
*/
|
||||||
@Remove
|
@Internal
|
||||||
@Deprecated
|
|
||||||
void applyInferableType(SqmExpressible<?> type);
|
void applyInferableType(SqmExpressible<?> type);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.sqm.tree.predicate;
|
package org.hibernate.query.sqm.tree.predicate;
|
||||||
|
|
||||||
|
import org.hibernate.query.internal.QueryHelper;
|
||||||
import org.hibernate.query.sqm.NodeBuilder;
|
import org.hibernate.query.sqm.NodeBuilder;
|
||||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
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.SqmCopyContext;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||||
|
|
||||||
|
@ -49,6 +51,15 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
|
||||||
this.pattern = pattern;
|
this.pattern = pattern;
|
||||||
this.escapeCharacter = escapeCharacter;
|
this.escapeCharacter = escapeCharacter;
|
||||||
this.isCaseSensitive = isCaseSensitive;
|
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(
|
public SqmLikePredicate(
|
||||||
|
|
|
@ -10,28 +10,33 @@ import org.hibernate.query.sqm.NodeBuilder;
|
||||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
|
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
|
public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
|
||||||
private final SqmExpression leftHandExpression;
|
private final SqmExpression<?> leftHandExpression;
|
||||||
private final SqmPath<?> pluralPath;
|
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 );
|
this( leftHandExpression, pluralPath, false, nodeBuilder );
|
||||||
}
|
}
|
||||||
|
|
||||||
public SqmMemberOfPredicate(
|
public SqmMemberOfPredicate(
|
||||||
SqmExpression leftHandExpression,
|
SqmExpression<?> leftHandExpression,
|
||||||
SqmPath pluralPath,
|
SqmPath<?> pluralPath,
|
||||||
boolean negated,
|
boolean negated,
|
||||||
NodeBuilder nodeBuilder) {
|
NodeBuilder nodeBuilder) {
|
||||||
super( negated, nodeBuilder );
|
super( negated, nodeBuilder );
|
||||||
|
|
||||||
this.pluralPath = pluralPath;
|
this.pluralPath = pluralPath;
|
||||||
this.leftHandExpression = leftHandExpression;
|
this.leftHandExpression = leftHandExpression;
|
||||||
|
|
||||||
|
leftHandExpression.applyInferableType(
|
||||||
|
( (SqmPluralValuedSimplePath<?>) pluralPath ).getReferencedPathSource().getElementType()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,7 +58,7 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
|
||||||
return predicate;
|
return predicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SqmExpression getLeftHandExpression() {
|
public SqmExpression<?> getLeftHandExpression() {
|
||||||
return leftHandExpression;
|
return leftHandExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,14 @@ package org.hibernate.orm.test.query.hql;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import jakarta.persistence.Embeddable;
|
import jakarta.persistence.Embeddable;
|
||||||
import jakarta.persistence.Embedded;
|
import jakarta.persistence.Embedded;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Parameter;
|
||||||
import jakarta.persistence.Temporal;
|
import jakarta.persistence.Temporal;
|
||||||
import jakarta.persistence.TemporalType;
|
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
|
@Override
|
||||||
protected boolean exportSchema() {
|
protected boolean exportSchema() {
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in New Issue