HHH-12230 - SelectCase does not work when simultaneously exists in select and group by sections

This commit is contained in:
lukawski-adrian 2018-01-20 20:57:19 +01:00 committed by Vlad Mihalcea
parent 7873729e63
commit 94fe106fb5
27 changed files with 152 additions and 94 deletions

View File

@ -136,11 +136,6 @@ public class CriteriaSubqueryImpl<T> extends ExpressionImpl<T> implements Subque
public String render(RenderingContext renderingContext) {
return subQuery.render( renderingContext );
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -253,7 +253,7 @@ public class QueryStructure<T> implements Serializable {
String sep = "";
for ( Expression grouping : getGroupings() ) {
jpaqlQuery.append( sep )
.append( ( (Renderable) grouping ).render( renderingContext ) );
.append( ( (Renderable) grouping ).renderGroupBy( renderingContext ) );
sep = ", ";
}

View File

@ -15,6 +15,33 @@ import org.hibernate.query.criteria.internal.compile.RenderingContext;
* @author Steve Ebersole
*/
public interface Renderable {
public String render(RenderingContext renderingContext);
public String renderProjection(RenderingContext renderingContext);
/**
* Render clause
*
* @param renderingContext context
* @return rendered expression
*/
String render(RenderingContext renderingContext);
/**
* Render SELECT clause
*
* @param renderingContext context
* @return rendered expression
*/
default String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
/**
* Render GROUP BY clause
*
* @param renderingContext context
*
* @return rendered expression
*/
default String renderGroupBy(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -37,7 +37,7 @@ public interface RenderingContext {
* Register a parameter that was not part of the criteria query (at least not as a parameter).
*
* @param literal The literal value
* @param javaType The java type as whcih to handle the literal value.
* @param javaType The java type as which to handle the literal value.
*
* @return The JPA-QL parameter name
*/

View File

@ -213,9 +213,4 @@ public class BinaryArithmeticOperation<N extends Number>
( (Renderable) getRightHandOperand() ).render( renderingContext )
);
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -76,8 +76,4 @@ public class CoalesceExpression<T> extends ExpressionImpl<T> implements Coalesce
}
return buffer.append( ")" ).toString();
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -88,8 +88,4 @@ public class CompoundSelectionImpl<X>
}
return buff.toString();
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -68,8 +68,4 @@ public class ConcatExpression extends ExpressionImpl<String> implements Serializ
+ " || "
+ ( (Renderable) getString2() ).render( renderingContext ) + ')' ;
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -30,8 +30,4 @@ public class EntityTypeExpression<T> extends ExpressionImpl<T> implements Serial
// todo : is it valid for this to get rendered into the query itself?
throw new IllegalArgumentException( "Unexpected call on EntityTypeExpression#render" );
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -46,8 +46,4 @@ public class ListIndexExpression extends ExpressionImpl<Integer> implements Seri
+ origin.getPathIdentifier()
+ ")";
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -89,6 +89,11 @@ public class LiteralExpression<T> extends ExpressionImpl<T> implements Serializa
}
}
@Override
public String renderGroupBy(RenderingContext renderingContext) {
return renderProjection( renderingContext );
}
@Override
@SuppressWarnings({ "unchecked" })
protected void resetJavaType(Class targetType) {

View File

@ -67,8 +67,4 @@ public class NullifExpression<T> extends ExpressionImpl<T> implements Serializab
+ ( (Renderable) getSecondaryExpression() ).render( renderingContext )
+ ")";
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -72,8 +72,4 @@ public class ParameterExpressionImpl<T>
final ExplicitParameterInfo parameterInfo = renderingContext.registerExplicitParameter( this );
return parameterInfo.render();
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -33,8 +33,4 @@ public class PathTypeExpression<T> extends ExpressionImpl<T> implements Serializ
public String render(RenderingContext renderingContext) {
return "type(" + pathImpl.getPathIdentifier() + ")";
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -119,6 +119,14 @@ public class SearchedCaseExpression<R>
);
}
@Override
public String renderGroupBy(RenderingContext renderingContext) {
return render(
renderingContext,
(Renderable expression, RenderingContext context) -> expression.renderGroupBy( context )
);
}
private String render(
RenderingContext renderingContext,
BiFunction<Renderable, RenderingContext, String> formatter) {

View File

@ -116,6 +116,7 @@ public class SimpleCaseExpression<C,R>
Helper.possibleParameter( getOtherwiseResult(), registry );
}
@Override
public String render(RenderingContext renderingContext) {
return render(
renderingContext,
@ -123,6 +124,7 @@ public class SimpleCaseExpression<C,R>
);
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render(
renderingContext,
@ -130,6 +132,14 @@ public class SimpleCaseExpression<C,R>
);
}
@Override
public String renderGroupBy(RenderingContext renderingContext) {
return render(
renderingContext,
(Renderable expression, RenderingContext context) -> expression.renderGroupBy( context )
);
}
private String render(
RenderingContext renderingContext,
BiFunction<Renderable, RenderingContext, String> formatter) {

View File

@ -50,8 +50,4 @@ public class SizeOfPluralAttributeExpression
public String render(RenderingContext renderingContext) {
return "size(" + getPluralAttributePath().render( renderingContext ) + ")";
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -70,8 +70,4 @@ public class SubqueryComparisonModifierExpression<Y>
public String render(RenderingContext renderingContext) {
return getModifier().rendered() + ( (Renderable) getSubquery() ).render( renderingContext );
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -59,9 +59,4 @@ public class UnaryArithmeticOperation<T>
return ( getOperation() == Operation.UNARY_MINUS ? '-' : '+' )
+ ( (Renderable) getOperand() ).render( renderingContext );
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -51,8 +51,4 @@ public class BasicFunctionExpression<X>
public String render(RenderingContext renderingContext) {
return getFunctionName() + "()";
}
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -91,16 +91,11 @@ public abstract class AbstractFromImpl<Z, X>
}
@Override
public String renderProjection(RenderingContext renderingContext) {
public String render(RenderingContext renderingContext) {
prepareAlias( renderingContext );
return getAlias();
}
@Override
public String render(RenderingContext renderingContext) {
return renderProjection( renderingContext );
}
@Override
public Attribute<?, ?> getAttribute() {
return null;

View File

@ -247,9 +247,4 @@ public abstract class AbstractPathImpl<X>
return getAttribute().getName();
}
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -90,11 +90,6 @@ public class RootImpl<X> extends AbstractFromImpl<X,X> implements Root<X>, Seria
prepareAlias( renderingContext );
return getAlias();
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
public Set<TreatedRoot<? extends X>> getTreats() {
return treats;

View File

@ -48,9 +48,4 @@ public abstract class AbstractSimplePredicate
return render( isNegated(), renderingContext );
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -119,11 +119,6 @@ public class CompoundPredicate
return operatorTextWithSeparator( this.getOperator() );
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
/**
* Create negation of compound predicate by using logic rules:
* 1. not (x || y) is (not x && not y)

View File

@ -102,9 +102,4 @@ public class NegatedPredicateWrapper extends ExpressionImpl<Boolean> implements
public String render(RenderingContext renderingContext) {
return render( isNegated(), renderingContext );
}
@Override
public String renderProjection(RenderingContext renderingContext) {
return render( renderingContext );
}
}

View File

@ -0,0 +1,97 @@
/*
* 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.jpa.test.criteria.selectcase;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.Tuple;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.dialect.PostgreSQL95Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.jpa.test.metadata.Person_;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@TestForIssue(jiraKey = "HHH-12230")
public class GroupBySelectCaseTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Person.class };
}
@Test
@TestForIssue(jiraKey = "HHH-12230")
public void selectCaseInGroupByAndSelectExpression() {
doInJPA( this::entityManagerFactory, entityManager -> {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<Person> from = query.from( Person.class );
Predicate childPredicate = cb.between( from.get( Person_.AGE ), 0, 10 );
Predicate teenagerPredicate = cb.between( from.get( Person_.AGE ), 11, 20 );
CriteriaBuilder.Case<String> selectCase = cb.selectCase();
selectCase.when( childPredicate, "child" )
.when( teenagerPredicate, "teenager" )
.otherwise( "adult" );
query.multiselect( selectCase );
query.groupBy( selectCase );
List<Tuple> resultList = entityManager.createQuery( query ).getResultList();
assertNotNull( resultList );
assertTrue( resultList.isEmpty() );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-12230")
public void selectCaseInOrderByAndSelectExpression() {
doInJPA( this::entityManagerFactory, entityManager -> {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<Person> from = query.from( Person.class );
Predicate childPredicate = cb.between( from.get( Person_.AGE ), 0, 10 );
Predicate teenagerPredicate = cb.between( from.get( Person_.AGE ), 11, 20 );
CriteriaBuilder.Case<String> selectCase = cb.selectCase();
selectCase.when( childPredicate, "child" )
.when( teenagerPredicate, "teenager" )
.otherwise( "adult" );
query.multiselect( selectCase );
query.orderBy( cb.asc( selectCase ) );
List<Tuple> resultList = entityManager.createQuery( query ).getResultList();
assertNotNull( resultList );
assertTrue( resultList.isEmpty() );
} );
}
@Entity(name = "Person")
public static class Person {
@Id
private Long id;
private Integer age;
}
}