HHH-8699 - Multiselect with boolean predicate

This commit is contained in:
Lukasz Antoniak 2013-11-19 23:27:26 +01:00 committed by Brett Meyer
parent aab9112f37
commit 553f65a360
9 changed files with 217 additions and 2 deletions

View File

@ -409,6 +409,7 @@ selectExpr
| collectionFunction // elements() or indices()
| literal
| arithmeticExpr
| logicalExpr
| parameter
| query
;

View File

@ -246,6 +246,7 @@ selectExpr
| aggregate
| c:constant { out(c); }
| arithmeticExpr
| selectBooleanExpr[false]
| parameter
| sn:SQL_NODE { out(sn); }
| { out("("); } selectStatement { out(")"); }
@ -306,6 +307,11 @@ booleanOp[ boolean parens ]
| #(NOT { out(" not ("); } booleanExpr[false] { out(")"); } )
;
selectBooleanExpr[ boolean parens ]
: booleanOp [ parens ]
| comparisonExpr [ parens ]
;
booleanExpr[ boolean parens ]
: booleanOp [ parens ]
| comparisonExpr [ parens ]
@ -387,6 +393,7 @@ simpleExpr
| count
| parameter
| arithmeticExpr
| selectBooleanExpr[false]
;
constant

View File

@ -29,6 +29,7 @@ import org.hibernate.HibernateException;
import org.hibernate.TypeMismatchException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ColumnHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.type.OneToOneType;
@ -43,7 +44,7 @@ import antlr.collections.AST;
*
* @author Steve Ebersole
*/
public class BinaryLogicOperatorNode extends HqlSqlWalkerNode implements BinaryOperatorNode {
public class BinaryLogicOperatorNode extends AbstractSelectExpression implements BinaryOperatorNode {
/**
* Performs the operator node initialization by seeking out any parameter
* nodes and setting their expected type, if possible.
@ -268,4 +269,8 @@ public class BinaryLogicOperatorNode extends HqlSqlWalkerNode implements BinaryO
public Node getRightHandOperand() {
return (Node) getFirstChild().getNextSibling();
}
public void setScalarColumnText(int i) throws SemanticException {
ColumnHelper.generateSingleScalarColumn( this, i );
}
}

View File

@ -23,6 +23,9 @@
*/
package org.hibernate.hql.internal.ast.tree;
import antlr.SemanticException;
import org.hibernate.hql.internal.ast.util.ColumnHelper;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
@ -31,7 +34,7 @@ import org.hibernate.type.Type;
*
* @author Steve Ebersole
*/
public class UnaryLogicOperatorNode extends HqlSqlWalkerNode implements UnaryOperatorNode {
public class UnaryLogicOperatorNode extends AbstractSelectExpression implements UnaryOperatorNode {
public Node getOperand() {
return (Node) getFirstChild();
}
@ -45,4 +48,8 @@ public class UnaryLogicOperatorNode extends HqlSqlWalkerNode implements UnaryOpe
// logic operators by definition resolve to booleans
return StandardBasicTypes.BOOLEAN;
}
public void setScalarColumnText(int i) throws SemanticException {
ColumnHelper.generateSingleScalarColumn( this, i );
}
}

View File

@ -133,6 +133,7 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
"hql/Image.hbm.xml",
"hql/ComponentContainer.hbm.xml",
"hql/VariousKeywordPropertyEntity.hbm.xml",
"hql/Constructor.hbm.xml",
"batchfetch/ProductLine.hbm.xml",
"cid/Customer.hbm.xml",
"cid/Order.hbm.xml",
@ -212,6 +213,31 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
session.close();
}
@Test
@TestForIssue( jiraKey = "HHH-8699" )
public void testBooleanPredicate() {
final Session session = openSession();
session.getTransaction().begin();
final Constructor constructor = new Constructor();
session.save( constructor );
session.getTransaction().commit();
session.clear();
Constructor.resetConstructorExecutionCount();
session.getTransaction().begin();
final Constructor result = (Constructor) session.createQuery(
"select new Constructor( c.id, c.id is not null, c.id = c.id, c.id + 1, concat( c.id, 'foo' ) ) from Constructor c where c.id = :id"
).setParameter( "id", constructor.getId() ).uniqueResult();
session.getTransaction().commit();
assertEquals( 1, Constructor.getConstructorExecutionCount() );
assertEquals( new Constructor( constructor.getId(), true, true, constructor.getId() + 1, constructor.getId() + "foo" ), result );
session.close();
}
@Test
public void testJpaTypeOperator() {
// just checking syntax here...

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.hql">
<class name="Constructor">
<id name="id" column="ID" type="long">
<generator class="increment"/>
</id>
<property name="someString" type="string"/>
<property name="someNumber" type="int"/>
<property name="someBoolean" type="boolean"/>
<property name="anotherBoolean" type="boolean"/>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,125 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.hql;
import java.io.Serializable;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class Constructor implements Serializable {
private static int CONSTRUCTOR_EXECUTION_COUNT = 0;
private long id;
private String someString;
private Number someNumber;
private boolean someBoolean;
private boolean anotherBoolean;
public Constructor() {
}
public Constructor(long id, boolean someBoolean, boolean anotherBoolean, Number someNumber, String someString) {
this.id = id;
this.someBoolean = someBoolean;
this.anotherBoolean = anotherBoolean;
this.someNumber = someNumber;
this.someString = someString;
++CONSTRUCTOR_EXECUTION_COUNT;
}
@Override
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof Constructor ) ) return false;
Constructor that = (Constructor) o;
if ( anotherBoolean != that.anotherBoolean ) return false;
if ( id != that.id ) return false;
if ( someBoolean != that.someBoolean ) return false;
if ( someNumber != null ? !someNumber.equals( that.someNumber ) : that.someNumber != null ) return false;
if ( someString != null ? !someString.equals( that.someString ) : that.someString != null ) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (someString != null ? someString.hashCode() : 0);
result = 31 * result + (someNumber != null ? someNumber.hashCode() : 0);
result = 31 * result + (someBoolean ? 1 : 0);
result = 31 * result + (anotherBoolean ? 1 : 0);
return result;
}
public boolean isSomeBoolean() {
return someBoolean;
}
public void setSomeBoolean(boolean someBoolean) {
this.someBoolean = someBoolean;
}
public Number getSomeNumber() {
return someNumber;
}
public void setSomeNumber(Number someNumber) {
this.someNumber = someNumber;
}
public String getSomeString() {
return someString;
}
public void setSomeString(String someString) {
this.someString = someString;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public boolean isAnotherBoolean() {
return anotherBoolean;
}
public void setAnotherBoolean(boolean anotherBoolean) {
this.anotherBoolean = anotherBoolean;
}
public static int getConstructorExecutionCount() {
return CONSTRUCTOR_EXECUTION_COUNT;
}
public static void resetConstructorExecutionCount() {
CONSTRUCTOR_EXECUTION_COUNT = 0;
}
}

View File

@ -52,6 +52,8 @@ import org.hibernate.jpa.test.metamodel.ShelfLife;
import org.hibernate.jpa.test.metamodel.Spouse;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import static org.junit.Assert.assertEquals;
/**
@ -214,6 +216,26 @@ public class QueryBuilderTest extends BaseEntityManagerFunctionalTestCase {
em.close();
}
@Test
@TestForIssue( jiraKey = "HHH-8699" )
public void testMultiselectWithPredicates() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
CriteriaBuilderImpl cb = (CriteriaBuilderImpl) em.getCriteriaBuilder();
CriteriaQuery<Customer> cq = cb.createQuery( Customer.class );
Root<Customer> r = cq.from( Customer.class );
cq.multiselect(
r.get( Customer_.id ), r.get( Customer_.name ),
cb.concat( "Hello ", r.get( Customer_.name ) ), cb.isNotNull( r.get( Customer_.age ) )
);
TypedQuery<Customer> tq = em.createQuery( cq );
tq.getResultList();
em.getTransaction().commit();
em.close();
}
@Test
public void testDateTimeFunctions() {
EntityManager em = getOrCreateEntityManager();

View File

@ -62,6 +62,12 @@ public class Customer implements java.io.Serializable {
this.name = name;
}
// Used by test case for HHH-8699.
public Customer(String id, String name, String greeting, Boolean something) {
this.id = id;
this.name = name;
}
public Customer(String id, String name, Country country) {
this.id = id;
this.name = name;