Skip to content

Commit 2c549e2

Browse files
committed
Bug 417259: Add support for parameters within CriteriaBuilder HAVING clause
Signed-off-by: Will Dazey <[email protected]>
1 parent b67fcd5 commit 2c549e2

File tree

2 files changed

+191
-4
lines changed

2 files changed

+191
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright (c) 2021 IBM Corporation, Oracle, and/or affiliates. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0,
7+
* or the Eclipse Distribution License v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
// Contributors:
13+
// IBM - Bug 417259: Add support for Parameters in CriteriaBuilder in HAVING clause
14+
package org.eclipse.persistence.jpa.test.query;
15+
16+
import static org.junit.Assert.assertEquals;
17+
import static org.junit.Assert.assertNotNull;
18+
19+
import java.util.List;
20+
import javax.persistence.EntityManager;
21+
import javax.persistence.EntityManagerFactory;
22+
import javax.persistence.TypedQuery;
23+
import javax.persistence.criteria.CriteriaBuilder;
24+
import javax.persistence.criteria.CriteriaQuery;
25+
import javax.persistence.criteria.ParameterExpression;
26+
import javax.persistence.criteria.Root;
27+
28+
import org.eclipse.persistence.jpa.test.framework.DDLGen;
29+
import org.eclipse.persistence.jpa.test.framework.Emf;
30+
import org.eclipse.persistence.jpa.test.framework.EmfRunner;
31+
import org.eclipse.persistence.jpa.test.framework.Property;
32+
import org.eclipse.persistence.jpa.test.query.model.EntityTbl01;
33+
import org.eclipse.persistence.jpa.test.query.model.EntityTbl01_;
34+
import org.junit.Test;
35+
import org.junit.runner.RunWith;
36+
37+
@RunWith(EmfRunner.class)
38+
public class TestQueryHaving {
39+
@Emf(createTables = DDLGen.DROP_CREATE, classes = { EntityTbl01.class },
40+
properties = { @Property(name="eclipselink.logging.level", value="FINE")})
41+
private EntityManagerFactory emf;
42+
43+
private static boolean POPULATED = false;
44+
45+
@Test
46+
public void testQueryHavingLiterals1() {
47+
if (emf == null)
48+
return;
49+
50+
if(!POPULATED)
51+
populate();
52+
53+
EntityManager em = emf.createEntityManager();
54+
55+
try {
56+
TypedQuery<String> query = em.createQuery(""
57+
+ "SELECT t.itemString1 FROM EntityTbl01 t "
58+
+ "GROUP BY t.itemString1 HAVING COUNT(t.itemString1) > 2", String.class);
59+
60+
List<String> dto01 = query.getResultList();
61+
assertNotNull(dto01);
62+
assertEquals(1, dto01.size());
63+
assertEquals("A", dto01.get(0));
64+
65+
// equivalent CriteriaBuilder
66+
CriteriaBuilder cb = em.getCriteriaBuilder();
67+
CriteriaQuery<String> cquery = cb.createQuery(String.class);
68+
Root<EntityTbl01> root = cquery.from(EntityTbl01.class);
69+
cquery.multiselect(root.get(EntityTbl01_.itemString1));
70+
71+
cquery.groupBy(root.get(EntityTbl01_.itemString1));
72+
cquery.having(cb.greaterThan(cb.count(root.get(EntityTbl01_.itemString1)), 2L));
73+
74+
query = em.createQuery(cquery);
75+
dto01 = query.getResultList();
76+
assertNotNull(dto01);
77+
assertEquals(1, dto01.size());
78+
assertEquals("A", dto01.get(0));
79+
} finally {
80+
if (em.getTransaction().isActive()) {
81+
em.getTransaction().rollback();
82+
}
83+
if(em.isOpen()) {
84+
em.close();
85+
}
86+
}
87+
}
88+
89+
@Test
90+
public void testQueryHavingParameters1() {
91+
if (emf == null)
92+
return;
93+
94+
if(!POPULATED)
95+
populate();
96+
97+
EntityManager em = emf.createEntityManager();
98+
99+
try {
100+
TypedQuery<String> query = em.createQuery(""
101+
+ "SELECT t.itemString1 FROM EntityTbl01 t "
102+
+ "GROUP BY t.itemString1 HAVING COUNT(t.itemString1) > ?1", String.class);
103+
query.setParameter(1, 2);
104+
105+
List<String> dto01 = query.getResultList();
106+
assertNotNull(dto01);
107+
assertEquals(1, dto01.size());
108+
assertEquals("A", dto01.get(0));
109+
110+
// equivalent CriteriaBuilder
111+
CriteriaBuilder cb = em.getCriteriaBuilder();
112+
CriteriaQuery<String> cquery = cb.createQuery(String.class);
113+
Root<EntityTbl01> root = cquery.from(EntityTbl01.class);
114+
cquery.multiselect(root.get(EntityTbl01_.itemString1));
115+
116+
ParameterExpression<Long> checkParam1 = cb.parameter(Long.class);
117+
cquery.groupBy(root.get(EntityTbl01_.itemString1));
118+
cquery.having(cb.greaterThan(cb.count(root.get(EntityTbl01_.itemString1)), checkParam1));
119+
120+
query = em.createQuery(cquery);
121+
query.setParameter(checkParam1, 2L);
122+
dto01 = query.getResultList();
123+
assertNotNull(dto01);
124+
assertEquals(1, dto01.size());
125+
assertEquals("A", dto01.get(0));
126+
} finally {
127+
if (em.getTransaction().isActive()) {
128+
em.getTransaction().rollback();
129+
}
130+
if(em.isOpen()) {
131+
em.close();
132+
}
133+
}
134+
}
135+
136+
private void populate() {
137+
EntityManager em = emf.createEntityManager();
138+
try {
139+
em.getTransaction().begin();
140+
141+
EntityTbl01 tbl1 = new EntityTbl01();
142+
tbl1.setKeyString("Key10");
143+
tbl1.setItemString1("A");
144+
tbl1.setItemString2(null);
145+
tbl1.setItemString3("C");
146+
tbl1.setItemString4("D");
147+
tbl1.setItemInteger1(3);
148+
em.persist(tbl1);
149+
150+
EntityTbl01 tbl2 = new EntityTbl01();
151+
tbl2.setKeyString("Key11");
152+
tbl2.setItemString1("A");
153+
tbl2.setItemString2("B");
154+
tbl2.setItemString3("C");
155+
tbl2.setItemString4(null);
156+
tbl2.setItemInteger1(4);
157+
em.persist(tbl2);
158+
159+
EntityTbl01 tbl3 = new EntityTbl01();
160+
tbl3.setKeyString("Key12");
161+
tbl3.setItemString1(null);
162+
tbl3.setItemString2("B");
163+
tbl3.setItemString3("C");
164+
tbl3.setItemString4("D");
165+
tbl3.setItemInteger1(3);
166+
em.persist(tbl3);
167+
168+
EntityTbl01 tbl4 = new EntityTbl01();
169+
tbl4.setKeyString("Key13");
170+
tbl4.setItemString1("A");
171+
tbl4.setItemString2("B");
172+
tbl4.setItemString3("C");
173+
tbl4.setItemString4(null);
174+
tbl4.setItemInteger1(4);
175+
em.persist(tbl4);
176+
177+
em.getTransaction().commit();
178+
179+
POPULATED = true;
180+
} finally {
181+
if(em.isOpen()) {
182+
em.close();
183+
}
184+
}
185+
}
186+
}

jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/AbstractQueryImpl.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@ public AbstractQuery<T> groupBy(Expression<?>... grouping){
112112
* @return the modified query
113113
*/
114114
@Override
115-
public AbstractQuery<T> having(Expression<Boolean> restriction){
116-
if (((InternalExpression)restriction).isCompoundExpression() || ((InternalExpression)restriction).isPredicate()){
115+
public AbstractQuery<T> having(Expression<Boolean> restriction) {
116+
findRootAndParameters(restriction);
117+
if (((InternalExpression)restriction).isCompoundExpression() || ((InternalExpression)restriction).isPredicate()) {
117118
this.havingClause = (Predicate) restriction;
118-
}else{
119+
} else {
119120
this.havingClause = queryBuilder.isTrue(restriction);
120121
}
121-
122122
return this;
123123
}
124124

@@ -139,6 +139,7 @@ public AbstractQuery<T> having(Predicate... restrictions){
139139
for (Predicate predicate : restrictions) {
140140
conjunction = this.queryBuilder.and(conjunction, predicate);
141141
}
142+
findRootAndParameters(conjunction);
142143
this.havingClause = conjunction;
143144
}
144145
return this;

0 commit comments

Comments
 (0)