diff --git a/hibernate-core/src/main/antlr/hql-sql.g b/hibernate-core/src/main/antlr/hql-sql.g
index 51437f6a21..3a4c382056 100644
--- a/hibernate-core/src/main/antlr/hql-sql.g
+++ b/hibernate-core/src/main/antlr/hql-sql.g
@@ -409,6 +409,7 @@ selectExpr
| collectionFunction // elements() or indices()
| literal
| arithmeticExpr
+ | logicalExpr
| parameter
| query
;
diff --git a/hibernate-core/src/main/antlr/sql-gen.g b/hibernate-core/src/main/antlr/sql-gen.g
index 40eeb94d48..29279301e7 100644
--- a/hibernate-core/src/main/antlr/sql-gen.g
+++ b/hibernate-core/src/main/antlr/sql-gen.g
@@ -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
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/BinaryLogicOperatorNode.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/BinaryLogicOperatorNode.java
index 0b8f40561d..be9f09765b 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/BinaryLogicOperatorNode.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/BinaryLogicOperatorNode.java
@@ -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 );
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/UnaryLogicOperatorNode.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/UnaryLogicOperatorNode.java
index 197237dfad..02842d0526 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/UnaryLogicOperatorNode.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/UnaryLogicOperatorNode.java
@@ -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 );
+ }
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
index 26cb5bf005..d6aed4a5b6 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
@@ -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...
diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/Constructor.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/hql/Constructor.hbm.xml
new file mode 100644
index 0000000000..d9d56f576a
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/hql/Constructor.hbm.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/Constructor.java b/hibernate-core/src/test/java/org/hibernate/test/hql/Constructor.java
new file mode 100644
index 0000000000..557827a80c
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/hql/Constructor.java
@@ -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;
+ }
+}
diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java
index d4200b4b2b..ffdbba50fd 100644
--- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java
+++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java
@@ -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 cq = cb.createQuery( Customer.class );
+ Root 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 tq = em.createQuery( cq );
+ tq.getResultList();
+
+ em.getTransaction().commit();
+ em.close();
+ }
+
@Test
public void testDateTimeFunctions() {
EntityManager em = getOrCreateEntityManager();
diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/metamodel/Customer.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/metamodel/Customer.java
index 81b1047614..907434ce34 100644
--- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/metamodel/Customer.java
+++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/metamodel/Customer.java
@@ -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;