HHH-6686 fix JQL exception in face of 'empty'
This commit is contained in:
parent
f1d1e62478
commit
a6934467f7
|
@ -18,7 +18,6 @@ import java.util.Set;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.hql.internal.antlr.HqlBaseParser;
|
import org.hibernate.hql.internal.antlr.HqlBaseParser;
|
||||||
import org.hibernate.hql.internal.antlr.HqlTokenTypes;
|
import org.hibernate.hql.internal.antlr.HqlTokenTypes;
|
||||||
import org.hibernate.hql.internal.ast.util.ASTPrinter;
|
|
||||||
import org.hibernate.hql.internal.ast.util.ASTUtil;
|
import org.hibernate.hql.internal.ast.util.ASTUtil;
|
||||||
import org.hibernate.hql.internal.ast.util.TokenPrinters;
|
import org.hibernate.hql.internal.ast.util.TokenPrinters;
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
|
@ -116,7 +115,7 @@ public final class HqlParser extends HqlBaseParser {
|
||||||
* @param token The token.
|
* @param token The token.
|
||||||
* @param ex The recognition exception.
|
* @param ex The recognition exception.
|
||||||
*
|
*
|
||||||
* @return AST - The new AST.
|
* @return The new AST.
|
||||||
*
|
*
|
||||||
* @throws antlr.RecognitionException if the substitution was not possible.
|
* @throws antlr.RecognitionException if the substitution was not possible.
|
||||||
* @throws antlr.TokenStreamException if the substitution was not possible.
|
* @throws antlr.TokenStreamException if the substitution was not possible.
|
||||||
|
@ -159,7 +158,7 @@ public final class HqlParser extends HqlBaseParser {
|
||||||
*
|
*
|
||||||
* @param x The sub tree to transform, the parent is assumed to be NOT.
|
* @param x The sub tree to transform, the parent is assumed to be NOT.
|
||||||
*
|
*
|
||||||
* @return AST - The equivalent sub-tree.
|
* @return The equivalent sub-tree.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AST negateNode(AST x) {
|
public AST negateNode(AST x) {
|
||||||
|
@ -286,7 +285,7 @@ public final class HqlParser extends HqlBaseParser {
|
||||||
*
|
*
|
||||||
* @param x The equality expression.
|
* @param x The equality expression.
|
||||||
*
|
*
|
||||||
* @return AST - The clean sub-tree.
|
* @return The clean sub-tree.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AST processEqualityExpression(AST x) {
|
public AST processEqualityExpression(AST x) {
|
||||||
|
@ -348,6 +347,10 @@ public final class HqlParser extends HqlBaseParser {
|
||||||
private AST createSubquery(AST node) {
|
private AST createSubquery(AST node) {
|
||||||
AST ast = ASTUtil.createParent( astFactory, RANGE, "RANGE", node );
|
AST ast = ASTUtil.createParent( astFactory, RANGE, "RANGE", node );
|
||||||
ast = ASTUtil.createParent( astFactory, FROM, "from", ast );
|
ast = ASTUtil.createParent( astFactory, FROM, "from", ast );
|
||||||
|
|
||||||
|
AST alias = ASTUtil.createSibling( astFactory, ALIAS, "_", node );
|
||||||
|
ASTUtil.insertChild( ASTUtil.createSibling( astFactory, SELECT, "select", ast ), astFactory.create(IDENT, alias.getText() ) );
|
||||||
|
|
||||||
ast = ASTUtil.createParent( astFactory, SELECT_FROM, "SELECT_FROM", ast );
|
ast = ASTUtil.createParent( astFactory, SELECT_FROM, "SELECT_FROM", ast );
|
||||||
ast = ASTUtil.createParent( astFactory, QUERY, "QUERY", ast );
|
ast = ASTUtil.createParent( astFactory, QUERY, "QUERY", ast );
|
||||||
return ast;
|
return ast;
|
||||||
|
@ -489,12 +492,12 @@ public final class HqlParser extends HqlBaseParser {
|
||||||
LOG.debugf( "Registering discovered request to treat(%s as %s)", path, subclassName );
|
LOG.debugf( "Registering discovered request to treat(%s as %s)", path, subclassName );
|
||||||
|
|
||||||
if ( treatMap == null ) {
|
if ( treatMap == null ) {
|
||||||
treatMap = new HashMap<String, Set<String>>();
|
treatMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> subclassNames = treatMap.get( path );
|
Set<String> subclassNames = treatMap.get( path );
|
||||||
if ( subclassNames == null ) {
|
if ( subclassNames == null ) {
|
||||||
subclassNames = new HashSet<String>();
|
subclassNames = new HashSet<>();
|
||||||
treatMap.put( path, subclassNames );
|
treatMap.put( path, subclassNames );
|
||||||
}
|
}
|
||||||
subclassNames.add( subclassName );
|
subclassNames.add( subclassName );
|
||||||
|
@ -512,11 +515,11 @@ public final class HqlParser extends HqlBaseParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Set<String>> getTreatMap() {
|
public Map<String, Set<String>> getTreatMap() {
|
||||||
return treatMap == null ? Collections.<String, Set<String>>emptyMap() : treatMap;
|
return treatMap == null ? Collections.emptyMap() : treatMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void panic() {
|
public static void panic() {
|
||||||
//overriden to avoid System.exit
|
//overridden to avoid System.exit
|
||||||
throw new QueryException( "Parser: panic" );
|
throw new QueryException( "Parser: panic" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,6 @@ public class PluralAttributeExpressionsTest extends AbstractMetamodelSpecificTes
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue( jiraKey = "HHH-11225" )
|
@TestForIssue( jiraKey = "HHH-11225" )
|
||||||
@FailureExpected( jiraKey = "HHH-6686")
|
|
||||||
public void testElementMapIsEmptyHql() {
|
public void testElementMapIsEmptyHql() {
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
entityManager.createQuery( "select m from MapEntity m where m.localized is empty" ).getResultList();
|
entityManager.createQuery( "select m from MapEntity m where m.localized is empty" ).getResultList();
|
||||||
|
@ -81,7 +80,6 @@ public class PluralAttributeExpressionsTest extends AbstractMetamodelSpecificTes
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue( jiraKey = "HHH-11225" )
|
@TestForIssue( jiraKey = "HHH-11225" )
|
||||||
@FailureExpected( jiraKey = "HHH-6686")
|
|
||||||
public void testElementMapIsEmptyCriteria() {
|
public void testElementMapIsEmptyCriteria() {
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
final HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) entityManager.getCriteriaBuilder();
|
final HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) entityManager.getCriteriaBuilder();
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
package org.hibernate.query;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nathan Xu
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-6686")
|
||||||
|
public class IsEmptyJQLTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
private Long personWithoutNicknameId = 1L;
|
||||||
|
private Long personaWithSingleNicknameId = 2L;
|
||||||
|
private Long personWithMultipleNicknamesId = 3L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Person.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJQLContainingEmpty() {
|
||||||
|
List<Person> personWithNicknames = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
return entityManager.createQuery(
|
||||||
|
"select p from Person p where p.nicknames is not empty", Person.class )
|
||||||
|
.getResultList();
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals( new HashSet<>( Arrays.asList(personaWithSingleNicknameId, personWithMultipleNicknamesId)),
|
||||||
|
personWithNicknames.stream().map( Person::getId ).collect( Collectors.toSet() ));
|
||||||
|
|
||||||
|
List<Person> personWithOutNickname = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
return entityManager.createQuery(
|
||||||
|
"select p from Person p where p.nicknames is empty", Person.class )
|
||||||
|
.getResultList();
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals( Collections.singleton(personWithoutNicknameId),
|
||||||
|
personWithOutNickname.stream().map( Person::getId ).collect( Collectors.toSet() ));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterEntityManagerFactoryBuilt() {
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
Person personaWithoutNickname = new Person();
|
||||||
|
personaWithoutNickname.setId(personWithoutNicknameId);
|
||||||
|
|
||||||
|
Person personaWithSingleNickname = new Person();
|
||||||
|
personaWithSingleNickname.getNicknames().add( "nickname" );
|
||||||
|
personaWithSingleNickname.setId(personaWithSingleNicknameId);
|
||||||
|
|
||||||
|
Person personWithMultipleNicknames = new Person();
|
||||||
|
personWithMultipleNicknames.getNicknames().addAll( Arrays.asList( "nickName1", "nickName2" ) );
|
||||||
|
personWithMultipleNicknames.setId(personWithMultipleNicknamesId);
|
||||||
|
|
||||||
|
entityManager.persist( personaWithoutNickname );
|
||||||
|
entityManager.persist( personaWithSingleNickname );
|
||||||
|
entityManager.persist( personWithMultipleNicknames );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Person")
|
||||||
|
public static class Person {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> nicknames = new ArrayList<>();
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getNicknames() {
|
||||||
|
return nicknames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNicknames(List<String> nicknames) {
|
||||||
|
this.nicknames = nicknames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue