Properly handle parameters and null literals as plain select items
This commit is contained in:
parent
5b5254fbd6
commit
37b03ecc05
|
@ -19,10 +19,10 @@ import org.hibernate.query.sqm.tree.SqmVisitableNode;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class SqmCastTarget<T> extends AbstractSqmNode implements SqmTypedNode<T>, SqmVisitableNode {
|
public class SqmCastTarget<T> extends AbstractSqmNode implements SqmTypedNode<T>, SqmVisitableNode {
|
||||||
private AllowableFunctionReturnType<T> type;
|
private final AllowableFunctionReturnType<T> type;
|
||||||
private Long length;
|
private final Long length;
|
||||||
private Integer precision;
|
private final Integer precision;
|
||||||
private Integer scale;
|
private final Integer scale;
|
||||||
|
|
||||||
public Long getLength() {
|
public Long getLength() {
|
||||||
return length;
|
return length;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.hibernate.internal.FilterJdbcParameter;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.Stack;
|
import org.hibernate.internal.util.collections.Stack;
|
||||||
import org.hibernate.internal.util.collections.StandardStack;
|
import org.hibernate.internal.util.collections.StandardStack;
|
||||||
|
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||||
|
@ -49,6 +50,7 @@ import org.hibernate.sql.ast.Clause;
|
||||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.SqlAstWalker;
|
import org.hibernate.sql.ast.SqlAstWalker;
|
||||||
import org.hibernate.sql.ast.tree.MutationStatement;
|
import org.hibernate.sql.ast.tree.MutationStatement;
|
||||||
|
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||||
import org.hibernate.sql.ast.tree.cte.CteColumn;
|
import org.hibernate.sql.ast.tree.cte.CteColumn;
|
||||||
import org.hibernate.sql.ast.tree.cte.CteContainer;
|
import org.hibernate.sql.ast.tree.cte.CteContainer;
|
||||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||||
|
@ -1807,7 +1809,7 @@ public abstract class AbstractSqlAstWalker implements SqlAstWalker, SqlAppender
|
||||||
for ( int i = 0; i < size; i++ ) {
|
for ( int i = 0; i < size; i++ ) {
|
||||||
final SqlSelection sqlSelection = sqlSelections.get( i );
|
final SqlSelection sqlSelection = sqlSelections.get( i );
|
||||||
appendSql( separator );
|
appendSql( separator );
|
||||||
sqlSelection.accept( this );
|
visitSqlSelection( sqlSelection );
|
||||||
appendSql( " c" );
|
appendSql( " c" );
|
||||||
appendSql( Integer.toString( i ) );
|
appendSql( Integer.toString( i ) );
|
||||||
separator = COMA_SEPARATOR;
|
separator = COMA_SEPARATOR;
|
||||||
|
@ -1851,7 +1853,7 @@ public abstract class AbstractSqlAstWalker implements SqlAstWalker, SqlAppender
|
||||||
for ( int i = 0; i < size; i++ ) {
|
for ( int i = 0; i < size; i++ ) {
|
||||||
final SqlSelection sqlSelection = sqlSelections.get( i );
|
final SqlSelection sqlSelection = sqlSelections.get( i );
|
||||||
appendSql( separator );
|
appendSql( separator );
|
||||||
sqlSelection.accept( this );
|
visitSqlSelection( sqlSelection );
|
||||||
separator = COMA_SEPARATOR;
|
separator = COMA_SEPARATOR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1934,9 +1936,63 @@ public abstract class AbstractSqlAstWalker implements SqlAstWalker, SqlAppender
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitSqlSelection(SqlSelection sqlSelection) {
|
public void visitSqlSelection(SqlSelection sqlSelection) {
|
||||||
// do nothing... this is handled #visitSelectClause
|
final Expression expression = sqlSelection.getExpression();
|
||||||
|
// Null literals have to be casted in the select clause
|
||||||
|
if ( expression instanceof Literal ) {
|
||||||
|
final Literal literal = (Literal) expression;
|
||||||
|
if ( literal.getLiteralValue() == null ) {
|
||||||
|
renderNullCast( literal );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
renderLiteral( literal, dialect.requiresCastingOfParametersInSelectClause() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( expression instanceof NullnessLiteral ) {
|
||||||
|
renderNullCast( expression );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expression.accept( this );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void renderNullCast(Expression expression) {
|
||||||
|
final List<SqlAstNode> arguments = new ArrayList<>( 2 );
|
||||||
|
arguments.add( expression );
|
||||||
|
arguments.add( new CastTarget( (BasicValuedMapping) expression.getExpressionType() ) );
|
||||||
|
castFunction().render( this, arguments, this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void renderLiteral(Literal literal, boolean castParameter) {
|
||||||
|
assert literal.getExpressionType().getJdbcTypeCount() == 1;
|
||||||
|
final JdbcMapping jdbcMapping = literal.getJdbcMapping();
|
||||||
|
final JdbcLiteralFormatter literalFormatter = jdbcMapping.getSqlTypeDescriptor()
|
||||||
|
.getJdbcLiteralFormatter( jdbcMapping.getJavaTypeDescriptor() );
|
||||||
|
// If we encounter a plain literal in the select clause which has no literal formatter, we must render it as parameter
|
||||||
|
if ( literalFormatter == null ) {
|
||||||
|
parameterBinders.add( literal );
|
||||||
|
|
||||||
|
final LiteralAsParameter<Object> jdbcParameter = new LiteralAsParameter<>( literal );
|
||||||
|
if ( castParameter ) {
|
||||||
|
final List<SqlAstNode> arguments = new ArrayList<>( 2 );
|
||||||
|
arguments.add( jdbcParameter );
|
||||||
|
arguments.add( new CastTarget( (BasicValuedMapping) jdbcMapping ) );
|
||||||
|
castFunction().render( this, arguments, this );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appendSql( PARAM_MARKER );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appendSql(
|
||||||
|
literalFormatter.toJdbcLiteral(
|
||||||
|
literal.getLiteralValue(),
|
||||||
|
dialect,
|
||||||
|
getWrapperOptions()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// FROM clause
|
// FROM clause
|
||||||
|
@ -2617,36 +2673,13 @@ public abstract class AbstractSqlAstWalker implements SqlAstWalker, SqlAppender
|
||||||
appendSql( "null" );
|
appendSql( "null" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void visitLiteral(Literal literal) {
|
private void visitLiteral(Literal literal) {
|
||||||
if ( literal.getLiteralValue() == null ) {
|
if ( literal.getLiteralValue() == null ) {
|
||||||
// todo : not sure we allow this "higher up"
|
// todo : not sure we allow this "higher up"
|
||||||
appendSql( SqlAppender.NULL_KEYWORD );
|
appendSql( SqlAppender.NULL_KEYWORD );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert literal.getExpressionType().getJdbcTypeCount() == 1;
|
renderLiteral( literal, false );
|
||||||
final JdbcMapping jdbcMapping = literal.getJdbcMapping();
|
|
||||||
final JdbcLiteralFormatter literalFormatter = jdbcMapping.getSqlTypeDescriptor().getJdbcLiteralFormatter( jdbcMapping.getJavaTypeDescriptor() );
|
|
||||||
if ( literalFormatter == null ) {
|
|
||||||
parameterBinders.add( literal );
|
|
||||||
|
|
||||||
final LiteralAsParameter<Object> jdbcParameter = new LiteralAsParameter<>( literal );
|
|
||||||
if ( clauseStack.getCurrent() == Clause.SELECT && dialect.requiresCastingOfParametersInSelectClause() ) {
|
|
||||||
castFunction().render( this, Collections.singletonList( jdbcParameter ), this );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
appendSql( PARAM_MARKER );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
appendSql(
|
|
||||||
literalFormatter.toJdbcLiteral(
|
|
||||||
literal.getLiteralValue(),
|
|
||||||
dialect,
|
|
||||||
getWrapperOptions()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,14 @@ import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class CastTarget implements Expression, SqlAstNode {
|
public class CastTarget implements Expression, SqlAstNode {
|
||||||
private BasicValuedMapping type;
|
private final BasicValuedMapping type;
|
||||||
private Long length;
|
private final Long length;
|
||||||
private Integer precision;
|
private final Integer precision;
|
||||||
private Integer scale;
|
private final Integer scale;
|
||||||
|
|
||||||
|
public CastTarget(BasicValuedMapping type) {
|
||||||
|
this( type, null, null, null );
|
||||||
|
}
|
||||||
|
|
||||||
public CastTarget(BasicValuedMapping type, Long length, Integer precision, Integer scale) {
|
public CastTarget(BasicValuedMapping type, Long length, Integer precision, Integer scale) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|
Loading…
Reference in New Issue