HHH-16787 Multi-valued parameter with single element parameter list fails with no such element exception

This commit is contained in:
Christian Beikov 2023-06-13 19:10:43 +02:00
parent 6034d357bb
commit 521a36f5d6
9 changed files with 108 additions and 16 deletions

View File

@ -197,15 +197,15 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun
@Override
public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
final List<SqlAstNode> arguments = resolveSqlAstArguments( getArguments(), walker );
final ReturnableType<?> resultType = resolveResultType(
walker.getCreationContext().getMappingMetamodel().getTypeConfiguration()
);
final MappingModelExpressible<?> mappingModelExpressible = resultType == null ? null : getMappingModelExpressible(
walker,
resultType
resultType,
arguments
);
final List<SqlAstNode> arguments = resolveSqlAstArguments( getArguments(), walker );
final SqlAstNode expression = arguments.get( 0 );
if ( expression instanceof SqlTupleContainer ) {
// SqlTupleContainer means this is a composite temporal type i.e. uses `@TimeZoneStorage(COLUMN)`

View File

@ -14,7 +14,6 @@ import org.hibernate.query.ReturnableType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
import org.hibernate.query.sqm.function.SelfRenderingOrderedSetAggregateFunctionSqlAstExpression;
import org.hibernate.query.sqm.function.SelfRenderingSqmAggregateFunction;
import org.hibernate.query.sqm.function.SelfRenderingSqmOrderedSetAggregateFunction;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
@ -110,7 +109,7 @@ public class HypotheticalSetWindowEmulation extends HypotheticalSetFunction {
getFilter() == null ? null : (Predicate) getFilter().accept( walker ),
Collections.emptyList(),
resultType,
getMappingModelExpressible( walker, resultType )
getMappingModelExpressible( walker, resultType, arguments )
);
final Over<Object> windowFunction = new Over<>( function, new ArrayList<>(), withinGroup );
walker.registerQueryTransformer(

View File

@ -160,7 +160,8 @@ public class InverseDistributionFunction extends AbstractSqmSelfRenderingFunctio
@Override
protected MappingModelExpressible<?> getMappingModelExpressible(
SqmToSqlAstConverter walker,
ReturnableType<?> resultType) {
ReturnableType<?> resultType,
List<SqlAstNode> arguments) {
MappingModelExpressible<?> mapping;
if ( resultType instanceof MappingModelExpressible) {
// here we have a BasicType, which can be cast

View File

@ -14,7 +14,6 @@ import org.hibernate.query.ReturnableType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
import org.hibernate.query.sqm.function.SelfRenderingOrderedSetAggregateFunctionSqlAstExpression;
import org.hibernate.query.sqm.function.SelfRenderingSqmAggregateFunction;
import org.hibernate.query.sqm.function.SelfRenderingSqmOrderedSetAggregateFunction;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
@ -105,7 +104,7 @@ public class InverseDistributionWindowEmulation extends InverseDistributionFunct
getFilter() == null ? null : (Predicate) getFilter().accept( walker ),
withinGroup,
resultType,
getMappingModelExpressible( walker, resultType )
getMappingModelExpressible( walker, resultType, arguments )
);
final Over<Object> windowFunction = new Over<>( function, new ArrayList<>(), Collections.emptyList() );
walker.registerQueryTransformer(

View File

@ -89,7 +89,7 @@ public class SelfRenderingSqmAggregateFunction<T> extends SelfRenderingSqmFuncti
arguments,
filter == null ? null : walker.visitNestedTopLevelPredicate( filter ),
resultType,
getMappingModelExpressible( walker, resultType )
getMappingModelExpressible( walker, resultType, arguments )
);
}

View File

@ -115,7 +115,7 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
final ArrayList<SqlAstNode> sqlAstArguments = new ArrayList<>( sqmArguments.size() );
for ( int i = 0; i < sqmArguments.size(); i++ ) {
sqlAstArguments.add(
(SqlAstNode) ( (SqmVisitableNode) sqmArguments.get( i ) ).accept( walker )
(SqlAstNode) sqmArguments.get( i ).accept( walker )
);
}
return sqlAstArguments;
@ -129,7 +129,7 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
for ( int i = 0; i < sqmArguments.size(); i++ ) {
typeAccess.argumentIndex = i;
sqlAstArguments.add(
(SqlAstNode) walker.visitWithInferredType( (SqmVisitableNode) sqmArguments.get( i ), typeAccess )
(SqlAstNode) walker.visitWithInferredType( sqmArguments.get( i ), typeAccess )
);
}
return sqlAstArguments;
@ -150,7 +150,7 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
getRenderingSupport(),
arguments,
resultType,
resultType == null ? null : getMappingModelExpressible( walker, resultType )
resultType == null ? null : getMappingModelExpressible( walker, resultType, arguments )
);
}
@ -175,11 +175,19 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
return resultType;
}
@Deprecated(forRemoval = true)
protected MappingModelExpressible<?> getMappingModelExpressible(
SqmToSqlAstConverter walker,
ReturnableType<?> resultType) {
return getMappingModelExpressible( walker, resultType, resolveSqlAstArguments( getArguments(), walker ) );
}
protected MappingModelExpressible<?> getMappingModelExpressible(
SqmToSqlAstConverter walker,
ReturnableType<?> resultType,
List<SqlAstNode> arguments) {
MappingModelExpressible<?> mapping;
if ( resultType instanceof MappingModelExpressible) {
if ( resultType instanceof MappingModelExpressible ) {
// here we have a BasicType, which can be cast
// directly to BasicValuedMapping
mapping = (MappingModelExpressible<?>) resultType;
@ -204,7 +212,7 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
return null; // this works at least approximately
}
},
resolveSqlAstArguments( getArguments(), walker )
arguments
);
}
return mapping;

View File

@ -127,7 +127,7 @@ public class SelfRenderingSqmOrderedSetAggregateFunction<T> extends SelfRenderin
getFilter() == null ? null : walker.visitNestedTopLevelPredicate( getFilter() ),
withinGroup,
resultType,
getMappingModelExpressible( walker, resultType )
getMappingModelExpressible( walker, resultType, arguments )
);
}

View File

@ -99,7 +99,7 @@ public class SelfRenderingSqmWindowFunction<T> extends SelfRenderingSqmFunction<
respectNulls,
fromFirst,
resultType,
getMappingModelExpressible( walker, resultType )
getMappingModelExpressible( walker, resultType, arguments )
);
}

View File

@ -0,0 +1,85 @@
/*
* 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.orm.test.query.hql;
import java.util.Arrays;
import java.util.Collections;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.FunctionContributor;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry.JavaService;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Basic;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@BootstrapServiceRegistry(
javaServices = {
@JavaService(role = FunctionContributor.class, impl = MultiValuedParameterInFunctionTest.MyFunctionContributor.class)
}
)
@DomainModel(annotatedClasses = MultiValuedParameterInFunctionTest.Post.class)
@SessionFactory
@RequiresDialect(H2Dialect.class)
public class MultiValuedParameterInFunctionTest {
@Test
@JiraKey( "HHH-16787" )
public void testAsQueryParameter(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
session.createQuery( "from Post p where my_function((select p2.id from Post p2 where p2.title in (:name)))=1" )
.setParameter( "name", Collections.singletonList( "1" ) )
.list();
} );
}
@AfterEach
public void dropTestData(SessionFactoryScope scope) {
scope.inTransaction( (session) -> session.createQuery( "delete Post" ).executeUpdate() );
}
@Entity(name = "Post")
@Table(name = "Post")
public static class Post {
@Id
public Integer id;
@Basic
public String title;
private Post() {
// for Hibernate use
}
public Post(Integer id, String title) {
this.id = id;
this.title = title;
}
}
public static class MyFunctionContributor implements FunctionContributor {
@Override
public void contributeFunctions(FunctionContributions functionContributions) {
functionContributions.getFunctionRegistry().registerPattern(
"my_function",
"?1"
);
}
}
}