HHH-17677 handle literal null arguments more elegantly in StandardFunctionReturnTypeResolvers

resolves a very confusing error message
This commit is contained in:
Gavin King 2024-01-25 14:19:58 +01:00 committed by Christian Beikov
parent e90dba2c98
commit 78990a7910
3 changed files with 34 additions and 10 deletions

View File

@ -12,16 +12,15 @@ import java.util.Locale;
import java.util.function.Supplier;
import org.hibernate.Internal;
import org.hibernate.QueryException;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.NullSqmExpressible;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.BasicType;
@ -252,7 +251,10 @@ public class StandardFunctionReturnTypeResolvers {
int position) {
final SqmTypedNode<?> specifiedArgument = arguments.get( position - 1 );
final SqmExpressible<?> specifiedArgType = getArgumentExpressible( specifiedArgument );
if ( specifiedArgType != null && !(specifiedArgType instanceof ReturnableType ) ) {
if ( specifiedArgType == null || specifiedArgType instanceof NullSqmExpressible ) {
return null;
}
else if ( !(specifiedArgType instanceof ReturnableType) ) {
throw new FunctionArgumentException(
String.format(
Locale.ROOT,
@ -263,8 +265,9 @@ public class StandardFunctionReturnTypeResolvers {
)
);
}
return (ReturnableType<?>) specifiedArgType;
else {
return (ReturnableType<?>) specifiedArgType;
}
}
private static SqmExpressible<?> getArgumentExpressible(SqmTypedNode<?> specifiedArgument) {
@ -272,9 +275,9 @@ public class StandardFunctionReturnTypeResolvers {
final SqmExpressible<?> specifiedArgType = expressible instanceof SqmTypedNode<?>
? ( (SqmTypedNode<?>) expressible ).getNodeType()
: expressible;
return specifiedArgType instanceof SqmPathSource ?
( (SqmPathSource<?>) specifiedArgType ).getSqmPathType() :
specifiedArgType;
return specifiedArgType instanceof SqmPathSource
? ( (SqmPathSource<?>) specifiedArgType ).getSqmPathType()
: specifiedArgType;
}
public static JdbcMapping extractArgumentJdbcMapping(

View File

@ -11,7 +11,6 @@ import java.util.Objects;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.SqlExpressible;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlExpressionAccess;
import org.hibernate.sql.ast.spi.SqlSelection;
@ -93,7 +92,10 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
}
private static ValueExtractor determineValueExtractor(Expression sqlExpression, JavaType<?> jdbcJavaType) {
final JdbcMapping jdbcMapping = sqlExpression.getExpressionType().getSingleJdbcMapping();
final JdbcMappingContainer expressionType = sqlExpression.getExpressionType();
final JdbcMapping jdbcMapping = expressionType == null
? JavaObjectType.INSTANCE
: expressionType.getSingleJdbcMapping();
if ( jdbcJavaType == null || jdbcMapping.getMappedJavaType() == jdbcJavaType ) {
return jdbcMapping.getJdbcValueExtractor();
}
@ -102,6 +104,7 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
}
}
@Override
public Expression getExpression() {
return sqlExpression;

View File

@ -2248,4 +2248,22 @@ public class FunctionTests {
}
);
}
@Test
@SkipForDialect(dialectClass = H2Dialect.class)
@SkipForDialect(dialectClass = DerbyDialect.class)
@SkipForDialect(dialectClass = HSQLDialect.class)
@SkipForDialect(dialectClass = DB2Dialect.class)
public void testNullInCoalesce(SessionFactoryScope scope) {
scope.inTransaction(s -> {
assertEquals("hello",
s.createQuery("select coalesce(null, :word)", String.class)
.setParameter("word", "hello")
.getSingleResultOrNull());
assertEquals("hello",
s.createQuery("select coalesce(:word, null)", String.class)
.setParameter("word", "hello")
.getSingleResultOrNull());
});
}
}