diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java index f1b67c50ac8e..09e2b7e07d2f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java @@ -11,6 +11,7 @@ import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.metamodel.model.domain.TupleType; import org.hibernate.query.BindingContext; import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.tree.SqmTypedNode; @@ -76,10 +77,13 @@ public void validate( int count = 0; for (SqmTypedNode argument : arguments) { // JdbcTypeIndicators indicators = typeConfiguration.getCurrentBaseSqlTypeIndicators(); - SqmExpressible nodeType = argument.getNodeType(); - FunctionParameterType type = count < types.length ? types[count++] : types[types.length - 1]; + final SqmExpressible nodeType = argument.getNodeType(); + final FunctionParameterType type = count < types.length ? types[count++] : types[types.length - 1]; if ( nodeType != null && type != FunctionParameterType.ANY ) { - JavaType javaType = nodeType.getRelationalJavaType(); + if ( nodeType instanceof TupleType ) { + throwTupleError(type, functionName, count); + } + final JavaType javaType = nodeType.getRelationalJavaType(); if (javaType != null) { checkArgumentType( functionName, count, argument, type, javaType ); } @@ -289,6 +293,18 @@ private static void throwError( } } + private static void throwTupleError( + FunctionParameterType type, String functionName, int paramNumber) { + throw new FunctionArgumentException( + String.format( + "Parameter %d of function '%s()' has type '%s', but argument is a tuple", + paramNumber, + functionName, + type + ) + ); + } + @Override public String getSignature() { String sig = delegate.getSignature(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index 46e050d7e66e..bfe6f7a5dad3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -5965,8 +5965,8 @@ else if ( binaryArithmetic.getRightHandOperand().getNodeType() == nodeType ) { protected MappingModelExpressible getInferredValueMapping() { final MappingModelExpressible inferredMapping = resolveInferredType(); if ( inferredMapping != null ) { - if ( inferredMapping instanceof PluralAttributeMapping ) { - return ( (PluralAttributeMapping) inferredMapping ).getElementDescriptor(); + if ( inferredMapping instanceof PluralAttributeMapping pluralAttributeMapping ) { + return pluralAttributeMapping.getElementDescriptor(); } else if ( !( inferredMapping instanceof JavaObjectType ) ) { // Never report back the "object type" as inferred type and instead rely on the value type @@ -6070,8 +6070,8 @@ else if ( paramType instanceof EntityDomainType ) { // Try to infer the value mapping since the other side apparently is a path source final MappingModelExpressible inferredMapping = resolveInferredType(); if ( inferredMapping != null ) { - if ( inferredMapping instanceof PluralAttributeMapping ) { - return resolveInferredValueMappingForParameter( ( (PluralAttributeMapping) inferredMapping ).getElementDescriptor() ); + if ( inferredMapping instanceof PluralAttributeMapping pluralAttributeMapping ) { + return resolveInferredValueMappingForParameter( pluralAttributeMapping.getElementDescriptor() ); } else if ( !( inferredMapping instanceof JavaObjectType ) ) { // Do not report back the "object type" as inferred type and instead try to rely on the paramSqmType.getExpressibleJavaType() @@ -6263,23 +6263,8 @@ public Object visitTuple(SqmTuple sqmTuple) { final List> groupedExpressions = sqmTuple.getGroupedExpressions(); final int size = groupedExpressions.size(); final List expressions = new ArrayList<>( size ); - final MappingModelExpressible mappingModelExpressible = resolveInferredType(); - final EmbeddableMappingType embeddableMappingType = - mappingModelExpressible instanceof ValueMapping valueMapping - ? (EmbeddableMappingType) valueMapping.getMappedType() - : null; - if ( embeddableMappingType == null ) { - try { - inferrableTypeAccessStack.push( () -> null ); - for ( int i = 0; i < size; i++ ) { - expressions.add( (Expression) groupedExpressions.get( i ).accept( this ) ); - } - } - finally { - inferrableTypeAccessStack.pop(); - } - } - else { + if ( resolveInferredType() instanceof ValueMapping valueMapping + && valueMapping.getMappedType() instanceof EmbeddableMappingType embeddableMappingType ) { for ( int i = 0; i < size; i++ ) { final AttributeMapping attributeMapping = embeddableMappingType.getAttributeMapping( i ); inferrableTypeAccessStack.push( () -> attributeMapping ); @@ -6291,17 +6276,31 @@ public Object visitTuple(SqmTuple sqmTuple) { } } } - final MappingModelExpressible valueMapping; - if ( mappingModelExpressible != null ) { - valueMapping = mappingModelExpressible; + else { + try { + inferrableTypeAccessStack.push( () -> null ); + for ( int i = 0; i < size; i++ ) { + expressions.add( (Expression) groupedExpressions.get( i ).accept( this ) ); + } + } + finally { + inferrableTypeAccessStack.pop(); + } + } + return new SqlTuple( expressions, tupleValueMapping( sqmTuple ) ); + } + + private MappingModelExpressible tupleValueMapping(SqmTuple sqmTuple) { + final MappingModelExpressible inferredType = resolveInferredType(); + if ( inferredType != null ) { + return inferredType; + } + else if ( sqmTuple.getExpressible() instanceof MappingModelExpressible modelExpressible ) { + return modelExpressible; } else { - valueMapping = - sqmTuple.getExpressible() instanceof MappingModelExpressible modelExpressible - ? modelExpressible - : null; + return null; } - return new SqlTuple( expressions, valueMapping ); } @Override