HHH-10085 HHH-10143 - Fix issues with Criteria and case expressions
This commit is contained in:
parent
73aa359242
commit
114ea15b30
|
@ -28,7 +28,8 @@ import antlr.collections.AST;
|
|||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SearchedCaseNode extends AbstractSelectExpression implements SelectExpression {
|
||||
public class SearchedCaseNode extends AbstractSelectExpression implements SelectExpression, ExpectedTypeAwareNode {
|
||||
|
||||
@Override
|
||||
public Type getDataType() {
|
||||
// option is used to hold each WHEN/ELSE in turn
|
||||
|
@ -58,8 +59,7 @@ public class SearchedCaseNode extends AbstractSelectExpression implements Select
|
|||
|
||||
option = option.getNextSibling();
|
||||
}
|
||||
|
||||
throw new QueryException( "Could not determine data type for searched case statement" );
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,4 +67,27 @@ public class SearchedCaseNode extends AbstractSelectExpression implements Select
|
|||
ColumnHelper.generateSingleScalarColumn( this, i );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpectedType(Type expectedType) {
|
||||
AST option = getFirstChild();
|
||||
while ( option != null ) {
|
||||
if ( option.getType() == HqlSqlTokenTypes.WHEN ) {
|
||||
if ( ParameterNode.class.isAssignableFrom( option.getFirstChild().getNextSibling().getClass() ) ) {
|
||||
((ParameterNode) option.getFirstChild().getNextSibling()).setExpectedType( expectedType );
|
||||
}
|
||||
}
|
||||
else if ( option.getType() == HqlSqlTokenTypes.ELSE ) {
|
||||
if ( ParameterNode.class.isAssignableFrom( option.getFirstChild().getClass() ) ) {
|
||||
((ParameterNode) option.getFirstChild()).setExpectedType( expectedType );
|
||||
}
|
||||
}
|
||||
|
||||
option = option.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getExpectedType() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ public class SelectClause extends SelectExpressionList {
|
|||
|
||||
Type type = selectExpression.getDataType();
|
||||
if ( type == null ) {
|
||||
throw new IllegalStateException(
|
||||
throw new QueryException(
|
||||
"No data type for node: " + selectExpression.getClass().getName() + " "
|
||||
+ new ASTPrinter( SqlTokenTypes.class ).showAsString( (AST) selectExpression, "" )
|
||||
);
|
||||
|
|
|
@ -27,8 +27,8 @@ import antlr.collections.AST;
|
|||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SimpleCaseNode extends AbstractSelectExpression implements SelectExpression {
|
||||
|
||||
public class SimpleCaseNode extends AbstractSelectExpression implements SelectExpression, ExpectedTypeAwareNode {
|
||||
|
||||
public Type getDataType() {
|
||||
final AST expression = getFirstChild();
|
||||
// option is used to hold each WHEN/ELSE in turn
|
||||
|
@ -58,12 +58,33 @@ public class SimpleCaseNode extends AbstractSelectExpression implements SelectEx
|
|||
|
||||
option = option.getNextSibling();
|
||||
}
|
||||
|
||||
throw new QueryException( "Could not determine data type for simple case statement" );
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setScalarColumnText(int i) throws SemanticException {
|
||||
ColumnHelper.generateSingleScalarColumn( this, i );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpectedType(Type expectedType) {
|
||||
AST option = getFirstChild();
|
||||
while ( option != null ) {
|
||||
if ( option.getType() == HqlSqlTokenTypes.WHEN ) {
|
||||
if ( ParameterNode.class.isAssignableFrom( option.getFirstChild().getNextSibling().getClass() ) ) {
|
||||
((ParameterNode) option.getFirstChild().getNextSibling()).setExpectedType( expectedType );
|
||||
}
|
||||
}
|
||||
else if ( option.getType() == HqlSqlTokenTypes.ELSE ) {
|
||||
if ( ParameterNode.class.isAssignableFrom( option.getFirstChild().getClass() ) ) {
|
||||
((ParameterNode) option.getFirstChild()).setExpectedType( expectedType );
|
||||
}
|
||||
}
|
||||
option = option.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getExpectedType() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.query.criteria.internal.expression;
|
||||
|
||||
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
|
||||
import org.hibernate.query.criteria.internal.compile.RenderingContext;
|
||||
import org.hibernate.query.criteria.internal.expression.function.CastFunction;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class CaseLiteralExpression<T> extends LiteralExpression<T> {
|
||||
|
||||
public CaseLiteralExpression(CriteriaBuilderImpl criteriaBuilder, Class<T> type, T literal) {
|
||||
super( criteriaBuilder, type, literal );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String render(RenderingContext renderingContext) {
|
||||
// There's no need to cast a boolean value and it actually breaks on
|
||||
// MySQL and MariaDB because they don't support casting to bit.
|
||||
// Skip the cast for a boolean literal.
|
||||
if ( getJavaType() == Boolean.class && Boolean.class.isInstance( getLiteral() ) ) {
|
||||
return super.render( renderingContext );
|
||||
}
|
||||
|
||||
// wrapping the result in a cast to determine the node type during the antlr hql parsing phase
|
||||
return CastFunction.CAST_NAME + '(' +
|
||||
super.render( renderingContext ) +
|
||||
" as " +
|
||||
renderingContext.getCastType( getJavaType() ) +
|
||||
')';
|
||||
}
|
||||
}
|
|
@ -49,9 +49,6 @@ public class LiteralExpression<T> extends ExpressionImpl<T> implements Serializa
|
|||
if ( ValueHandlerFactory.isNumeric( literal ) ) {
|
||||
return ValueHandlerFactory.determineAppropriateHandler( (Class) literal.getClass() ).render( literal );
|
||||
}
|
||||
else if ( ValueHandlerFactory.isBoolean( literal ) ) {
|
||||
return ValueHandlerFactory.determineAppropriateHandler( (Class) literal.getClass() ).render( literal );
|
||||
}
|
||||
|
||||
// else...
|
||||
final String parameterName = renderingContext.registerLiteralParameterBinding( getLiteral(), getJavaType() );
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.query.criteria.internal.expression;
|
|||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import javax.persistence.criteria.CriteriaBuilder.Case;
|
||||
import javax.persistence.criteria.Expression;
|
||||
|
||||
|
@ -70,7 +71,7 @@ public class SearchedCaseExpression<R>
|
|||
final Class<R> type = result != null
|
||||
? (Class<R>) result.getClass()
|
||||
: getJavaType();
|
||||
return new CaseLiteralExpression<R>( criteriaBuilder(), type, result );
|
||||
return new LiteralExpression<R>( criteriaBuilder(), type, result );
|
||||
}
|
||||
|
||||
public Case<R> when(Expression<Boolean> condition, Expression<? extends R> result) {
|
||||
|
@ -114,20 +115,33 @@ public class SearchedCaseExpression<R>
|
|||
}
|
||||
|
||||
public String render(RenderingContext renderingContext) {
|
||||
return render(
|
||||
renderingContext,
|
||||
(Renderable expression, RenderingContext context) -> expression.render( context )
|
||||
);
|
||||
}
|
||||
|
||||
public String renderProjection(RenderingContext renderingContext) {
|
||||
return render(
|
||||
renderingContext,
|
||||
(Renderable expression, RenderingContext context) -> expression.renderProjection( context )
|
||||
);
|
||||
}
|
||||
|
||||
private String render(
|
||||
RenderingContext renderingContext,
|
||||
BiFunction<Renderable, RenderingContext, String> formatter) {
|
||||
StringBuilder caseStatement = new StringBuilder( "case" );
|
||||
for ( WhenClause whenClause : getWhenClauses() ) {
|
||||
caseStatement.append( " when " )
|
||||
.append( ( (Renderable) whenClause.getCondition() ).render( renderingContext ) )
|
||||
.append( formatter.apply( (Renderable) whenClause.getCondition(), renderingContext ) )
|
||||
.append( " then " )
|
||||
.append( ( (Renderable) whenClause.getResult() ).render( renderingContext ) );
|
||||
.append( formatter.apply( ((Renderable) whenClause.getResult()), renderingContext ) );
|
||||
}
|
||||
caseStatement.append( " else " )
|
||||
.append( ( (Renderable) getOtherwiseResult() ).render( renderingContext ) )
|
||||
.append( formatter.apply( (Renderable) getOtherwiseResult(), renderingContext ) )
|
||||
.append( " end" );
|
||||
return caseStatement.toString();
|
||||
}
|
||||
|
||||
public String renderProjection(RenderingContext renderingContext) {
|
||||
return render( renderingContext );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.query.criteria.internal.expression;
|
|||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import javax.persistence.criteria.CriteriaBuilder.SimpleCase;
|
||||
import javax.persistence.criteria.Expression;
|
||||
|
||||
|
@ -78,7 +79,7 @@ public class SimpleCaseExpression<C,R>
|
|||
final Class<R> type = result != null
|
||||
? (Class<R>) result.getClass()
|
||||
: getJavaType();
|
||||
return new CaseLiteralExpression<R>( criteriaBuilder(), type, result );
|
||||
return new LiteralExpression<R>( criteriaBuilder(), type, result );
|
||||
}
|
||||
|
||||
public SimpleCase<C, R> when(C condition, Expression<? extends R> result) {
|
||||
|
@ -125,22 +126,35 @@ public class SimpleCaseExpression<C,R>
|
|||
}
|
||||
|
||||
public String render(RenderingContext renderingContext) {
|
||||
return render(
|
||||
renderingContext,
|
||||
(Renderable expression, RenderingContext context) -> expression.render( context )
|
||||
);
|
||||
}
|
||||
|
||||
public String renderProjection(RenderingContext renderingContext) {
|
||||
return render(
|
||||
renderingContext,
|
||||
(Renderable expression, RenderingContext context) -> expression.renderProjection( context )
|
||||
);
|
||||
}
|
||||
|
||||
private String render(
|
||||
RenderingContext renderingContext,
|
||||
BiFunction<Renderable, RenderingContext, String> formatter) {
|
||||
StringBuilder caseExpr = new StringBuilder();
|
||||
caseExpr.append( "case " )
|
||||
.append( ( (Renderable) getExpression() ).render( renderingContext ) );
|
||||
.append( formatter.apply( (Renderable) getExpression(), renderingContext ) );
|
||||
for ( WhenClause whenClause : getWhenClauses() ) {
|
||||
caseExpr.append( " when " )
|
||||
.append( whenClause.getCondition().render( renderingContext ) )
|
||||
.append( " then " )
|
||||
.append( ( (Renderable) whenClause.getResult() ).render( renderingContext ) );
|
||||
.append( formatter.apply( whenClause.getCondition(), renderingContext ) )
|
||||
.append( " then " )
|
||||
.append( formatter.apply( (Renderable) whenClause.getResult(), renderingContext ) );
|
||||
}
|
||||
caseExpr.append( " else " )
|
||||
.append( ( (Renderable) getOtherwiseResult() ).render( renderingContext ) )
|
||||
.append( formatter.apply( (Renderable) getOtherwiseResult(), renderingContext ) )
|
||||
.append( " end" );
|
||||
return caseExpr.toString();
|
||||
}
|
||||
|
||||
public String renderProjection(RenderingContext renderingContext) {
|
||||
return render( renderingContext );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@ public class SelectCaseTest extends BaseEntityManagerFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialect(value = H2Dialect.class, jiraKey = "HHH-10143")
|
||||
public void selectCaseWithValuesShouldWork() {
|
||||
EntityManager entityManager = getOrCreateEntityManager();
|
||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
|
@ -86,7 +85,6 @@ public class SelectCaseTest extends BaseEntityManagerFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialect(value = H2Dialect.class, jiraKey = "HHH-10143")
|
||||
public void simpleSelectCaseWithValuesShouldWork() {
|
||||
EntityManager entityManager = getOrCreateEntityManager();
|
||||
|
||||
|
|
Loading…
Reference in New Issue