HHH-17677 handle literal null arguments more elegantly in StandardFunctionReturnTypeResolvers
resolves a very confusing error message
This commit is contained in:
parent
e90dba2c98
commit
78990a7910
|
@ -12,16 +12,15 @@ import java.util.Locale;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.Internal;
|
import org.hibernate.Internal;
|
||||||
import org.hibernate.QueryException;
|
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
|
||||||
import org.hibernate.query.ReturnableType;
|
import org.hibernate.query.ReturnableType;
|
||||||
import org.hibernate.query.sqm.SqmExpressible;
|
import org.hibernate.query.sqm.SqmExpressible;
|
||||||
import org.hibernate.query.sqm.SqmPathSource;
|
import org.hibernate.query.sqm.SqmPathSource;
|
||||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
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.SqlAstNode;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
|
@ -252,7 +251,10 @@ public class StandardFunctionReturnTypeResolvers {
|
||||||
int position) {
|
int position) {
|
||||||
final SqmTypedNode<?> specifiedArgument = arguments.get( position - 1 );
|
final SqmTypedNode<?> specifiedArgument = arguments.get( position - 1 );
|
||||||
final SqmExpressible<?> specifiedArgType = getArgumentExpressible( specifiedArgument );
|
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(
|
throw new FunctionArgumentException(
|
||||||
String.format(
|
String.format(
|
||||||
Locale.ROOT,
|
Locale.ROOT,
|
||||||
|
@ -263,18 +265,19 @@ public class StandardFunctionReturnTypeResolvers {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
return (ReturnableType<?>) specifiedArgType;
|
return (ReturnableType<?>) specifiedArgType;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static SqmExpressible<?> getArgumentExpressible(SqmTypedNode<?> specifiedArgument) {
|
private static SqmExpressible<?> getArgumentExpressible(SqmTypedNode<?> specifiedArgument) {
|
||||||
final SqmExpressible<?> expressible = specifiedArgument.getNodeType();
|
final SqmExpressible<?> expressible = specifiedArgument.getNodeType();
|
||||||
final SqmExpressible<?> specifiedArgType = expressible instanceof SqmTypedNode<?>
|
final SqmExpressible<?> specifiedArgType = expressible instanceof SqmTypedNode<?>
|
||||||
? ( (SqmTypedNode<?>) expressible ).getNodeType()
|
? ( (SqmTypedNode<?>) expressible ).getNodeType()
|
||||||
: expressible;
|
: expressible;
|
||||||
return specifiedArgType instanceof SqmPathSource ?
|
return specifiedArgType instanceof SqmPathSource
|
||||||
( (SqmPathSource<?>) specifiedArgType ).getSqmPathType() :
|
? ( (SqmPathSource<?>) specifiedArgType ).getSqmPathType()
|
||||||
specifiedArgType;
|
: specifiedArgType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JdbcMapping extractArgumentJdbcMapping(
|
public static JdbcMapping extractArgumentJdbcMapping(
|
||||||
|
|
|
@ -11,7 +11,6 @@ import java.util.Objects;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||||
import org.hibernate.metamodel.mapping.SqlExpressible;
|
|
||||||
import org.hibernate.sql.ast.SqlAstWalker;
|
import org.hibernate.sql.ast.SqlAstWalker;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionAccess;
|
import org.hibernate.sql.ast.spi.SqlExpressionAccess;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
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) {
|
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 ) {
|
if ( jdbcJavaType == null || jdbcMapping.getMappedJavaType() == jdbcJavaType ) {
|
||||||
return jdbcMapping.getJdbcValueExtractor();
|
return jdbcMapping.getJdbcValueExtractor();
|
||||||
}
|
}
|
||||||
|
@ -102,6 +104,7 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Expression getExpression() {
|
public Expression getExpression() {
|
||||||
return sqlExpression;
|
return sqlExpression;
|
||||||
|
|
|
@ -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());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue