HHH-16786 Fix NPE in SqmParameterInterpretation when binding null for select item in insert-select statement
This commit is contained in:
parent
521a36f5d6
commit
be38746810
|
@ -192,7 +192,6 @@ import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedRoot;
|
||||
import org.hibernate.query.sqm.tree.expression.Conversion;
|
||||
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
|
||||
|
@ -5509,11 +5508,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
);
|
||||
}
|
||||
return new SqmParameterInterpretation(
|
||||
sqmParameter,
|
||||
queryParameter,
|
||||
jdbcParametersForSqm,
|
||||
valueMapping,
|
||||
qp -> binding
|
||||
valueMapping
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
package org.hibernate.query.sqm.sql.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
|
@ -17,12 +15,7 @@ import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
|||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -38,22 +31,13 @@ import org.hibernate.type.descriptor.java.JavaType;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmParameterInterpretation implements Expression, DomainResultProducer, SqlTupleContainer {
|
||||
private final SqmParameter<?> sqmParameter;
|
||||
private final QueryParameterImplementor<?> queryParameter;
|
||||
private final MappingModelExpressible<?> valueMapping;
|
||||
private final Function<QueryParameterImplementor<?>, QueryParameterBinding<?>> queryParameterBindingResolver;
|
||||
private final List<JdbcParameter> jdbcParameters;
|
||||
private Expression resolvedExpression;
|
||||
|
||||
public SqmParameterInterpretation(
|
||||
SqmParameter<?> sqmParameter,
|
||||
QueryParameterImplementor<?> queryParameter,
|
||||
List<JdbcParameter> jdbcParameters,
|
||||
MappingModelExpressible<?> valueMapping,
|
||||
Function<QueryParameterImplementor<?>, QueryParameterBinding<?>> queryParameterBindingResolver) {
|
||||
this.sqmParameter = sqmParameter;
|
||||
this.queryParameter = queryParameter;
|
||||
this.queryParameterBindingResolver = queryParameterBindingResolver;
|
||||
MappingModelExpressible<?> valueMapping) {
|
||||
|
||||
if ( valueMapping instanceof EntityAssociationMapping ) {
|
||||
final EntityAssociationMapping mapping = (EntityAssociationMapping) valueMapping;
|
||||
|
@ -109,39 +93,21 @@ public class SqmParameterInterpretation implements Expression, DomainResultProdu
|
|||
throw new SemanticException( "Composite query parameter cannot be used in select" );
|
||||
}
|
||||
|
||||
BindableType<?> nodeType = sqmParameter.getNodeType();
|
||||
if ( nodeType == null ) {
|
||||
final QueryParameterBinding<?> binding = queryParameterBindingResolver.apply( queryParameter );
|
||||
nodeType = binding.getBindType();
|
||||
}
|
||||
final SessionFactoryImplementor sessionFactory = creationState.getSqlAstCreationState()
|
||||
.getCreationContext()
|
||||
.getSessionFactory();
|
||||
|
||||
final SqmExpressible<?> sqmExpressible = nodeType.resolveExpressible( sessionFactory );
|
||||
final JavaType<?> jdbcJavaType;
|
||||
final BasicValueConverter<?, ?> converter;
|
||||
if ( sqmExpressible instanceof JdbcMapping ) {
|
||||
final JdbcMapping jdbcMapping = (JdbcMapping) sqmExpressible;
|
||||
jdbcJavaType = jdbcMapping.getJdbcJavaType();
|
||||
converter = jdbcMapping.getValueConverter();
|
||||
}
|
||||
else {
|
||||
jdbcJavaType = sqmExpressible.getExpressibleJavaType();
|
||||
converter = null;
|
||||
}
|
||||
final JdbcMapping jdbcMapping = resolvedExpression.getExpressionType().getSingleJdbcMapping();
|
||||
final JavaType<?> jdbcJavaType = jdbcMapping.getJdbcJavaType();
|
||||
final BasicValueConverter<?, ?> converter = jdbcMapping.getValueConverter();
|
||||
|
||||
final SqlSelection sqlSelection = creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
|
||||
resolvedExpression,
|
||||
jdbcJavaType,
|
||||
null,
|
||||
sessionFactory.getTypeConfiguration()
|
||||
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory().getTypeConfiguration()
|
||||
);
|
||||
|
||||
return new BasicResult(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
sqmExpressible.getExpressibleJavaType(),
|
||||
jdbcMapping.getMappedJavaType(),
|
||||
converter
|
||||
);
|
||||
}
|
||||
|
@ -165,31 +131,11 @@ public class SqmParameterInterpretation implements Expression, DomainResultProdu
|
|||
throw new SemanticException( "Composite query parameter cannot be used in select" );
|
||||
}
|
||||
|
||||
BindableType<?> nodeType = sqmParameter.getNodeType();
|
||||
if ( nodeType == null ) {
|
||||
final QueryParameterBinding<?> binding = queryParameterBindingResolver.apply( queryParameter );
|
||||
nodeType = binding.getBindType();
|
||||
}
|
||||
|
||||
final SessionFactoryImplementor sessionFactory = creationState.getSqlAstCreationState()
|
||||
.getCreationContext()
|
||||
.getSessionFactory();
|
||||
|
||||
final SqmExpressible<?> sqmExpressible = nodeType.resolveExpressible( sessionFactory );
|
||||
final JavaType<?> jdbcJavaType;
|
||||
if ( sqmExpressible instanceof JdbcMapping ) {
|
||||
final JdbcMapping jdbcMapping = (JdbcMapping) sqmExpressible;
|
||||
jdbcJavaType = jdbcMapping.getJdbcJavaType();
|
||||
}
|
||||
else {
|
||||
jdbcJavaType = sqmExpressible.getExpressibleJavaType();
|
||||
}
|
||||
|
||||
return creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
|
||||
resolvedExpression,
|
||||
jdbcJavaType,
|
||||
resolvedExpression.getExpressionType().getSingleJdbcMapping().getMappedJavaType(),
|
||||
null,
|
||||
sessionFactory.getTypeConfiguration()
|
||||
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test;
|
|||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
@ -37,8 +38,8 @@ public class InsertSelectTests {
|
|||
public void prepareTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.persist( new EntitySource( "A" ) );
|
||||
session.persist( new EntitySource( "A" ) );
|
||||
session.persist( new EntitySource( 1, "A" ) );
|
||||
session.persist( new EntitySource( 2, "A" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -100,25 +101,47 @@ public class InsertSelectTests {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-16786")
|
||||
public void testInsertSelectParameterInference(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
statementInspector.clear();
|
||||
session.createMutationQuery(
|
||||
"insert into EntityEntry (id, name, source) " +
|
||||
"select 1, 'abc', :source from EntityEntry e"
|
||||
).setParameter( "source", null ).executeUpdate();
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "EntityEntry")
|
||||
public static class EntityEntry {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Integer id;
|
||||
String name;
|
||||
@ManyToOne
|
||||
EntitySource source;
|
||||
}
|
||||
|
||||
@Entity(name = "EntitySource")
|
||||
public static class EntitySource {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Integer id;
|
||||
String name;
|
||||
|
||||
public EntitySource() {
|
||||
}
|
||||
|
||||
public EntitySource(String name) {
|
||||
public EntitySource(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public EntitySource(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue