Fix multi value parameters expansion for SelfRenderingSqmFunction

This commit is contained in:
Andrea Boriero 2021-07-08 18:45:37 +02:00
parent 3f7044eebe
commit ab8cfe0d83
5 changed files with 56 additions and 2 deletions

View File

@ -3006,7 +3006,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
private SqmExpression<?> visitFinalFunctionArgument(HqlParser.ExpressionContext expression) { private SqmExpression<?> visitFinalFunctionArgument(HqlParser.ExpressionContext expression) {
// the final argument to a function may accept multi-value parameter (varargs), // the final argument to a function may accept multi-value parameter (varargs),
// but only if we are operating in non-strict JPA mode // but only if we are operating in non-strict JPA mode
parameterDeclarationContextStack.push( creationOptions::useStrictJpaCompliance ); parameterDeclarationContextStack.push( () -> !creationOptions.useStrictJpaCompliance() );
try { try {
return (SqmExpression<?>) expression.accept( this ); return (SqmExpression<?>) expression.accept( this );
} }

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmDistinct; import org.hibernate.query.sqm.tree.expression.SqmDistinct;

View File

@ -17,7 +17,9 @@ import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmFunction; import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -60,8 +62,22 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
final ArrayList<SqlAstNode> sqlAstArguments = new ArrayList<>( sqmArguments.size() ); final ArrayList<SqlAstNode> sqlAstArguments = new ArrayList<>( sqmArguments.size() );
for ( SqmTypedNode<?> sqmArgument : sqmArguments ) { for ( SqmTypedNode<?> sqmArgument : sqmArguments ) {
if ( sqmArgument instanceof SqmParameter ) {
final SqmParameter sqmParameter = (SqmParameter) sqmArgument;
if ( sqmParameter.allowMultiValuedBinding() ) {
final List<Expression> expressions = walker.expandSelfRenderingFunctionMultiValueParameter( sqmParameter );
for ( int i = 0; i < expressions.size(); i++ ) {
sqlAstArguments.add( expressions.get( i ) );
}
}
else {
sqlAstArguments.add( (SqlAstNode) ( (SqmVisitableNode) sqmArgument ).accept( walker ) ); sqlAstArguments.add( (SqlAstNode) ( (SqmVisitableNode) sqmArgument ).accept( walker ) );
} }
}
else {
sqlAstArguments.add( (SqlAstNode) ( (SqmVisitableNode) sqmArgument ).accept( walker ) );
}
}
return sqlAstArguments; return sqlAstArguments;
} }

View File

@ -4943,4 +4943,34 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return selection; return selection;
} }
} }
@Override
public List<Expression> expandSelfRenderingFunctionMultiValueParameter(SqmParameter sqmParameter) {
assert sqmParameter.allowMultiValuedBinding();
final QueryParameterImplementor<?> domainParam = domainParameterXref.getQueryParameter(
sqmParameter );
final QueryParameterBinding domainParamBinding = domainParameterBindings.getBinding(
domainParam );
final Collection bindValues = domainParamBinding.getBindValues();
final int bindValuesSize = bindValues.size();
final List<Expression> result = new ArrayList<>( bindValuesSize );
boolean first = true;
for ( int i = 0; i < bindValuesSize; i++ ) {
final SqmParameter sqmParamToConsume;
// for each bind value create an "expansion"
if ( first ) {
sqmParamToConsume = sqmParameter;
first = false;
}
else {
sqmParamToConsume = sqmParameter.copy();
domainParameterXref.addExpansion( domainParam, sqmParameter, sqmParamToConsume );
}
final Expression expression = consumeSqmParameter( sqmParamToConsume );
result.add( expression );
}
return result;
}
} }

View File

@ -6,10 +6,14 @@
*/ */
package org.hibernate.query.sqm.sql; package org.hibernate.query.sqm.sql;
import java.util.List;
import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.Stack;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.Expression;
/** /**
* Specialized SemanticQueryWalker (SQM visitor) for producing SQL AST. * Specialized SemanticQueryWalker (SQM visitor) for producing SQL AST.
@ -18,4 +22,7 @@ import org.hibernate.sql.ast.Clause;
*/ */
public interface SqmToSqlAstConverter extends SemanticQueryWalker<Object>, SqlAstCreationState { public interface SqmToSqlAstConverter extends SemanticQueryWalker<Object>, SqlAstCreationState {
Stack<Clause> getCurrentClauseStack(); Stack<Clause> getCurrentClauseStack();
List<Expression> expandSelfRenderingFunctionMultiValueParameter(SqmParameter sqmParameter);
} }