Exception using CriteriaQuery with subquery

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Exception using CriteriaQuery with subquery

JohnLloydJones
I'm getting an java.util.EmptyStackException when I try to get a count using a criteria query.

The query to get the list of objects works fine here the toCQL():
SELECT q  FROM Question q WHERE ( EXISTS(SELECT r FROM Response r WHERE (r.question = q AND r.text LIKE '%Which%')) OR q.text LIKE '%Which%')

When I try to get just the count it fails with an EmptyStackException;
SELECT COUNT(q.id) FROM Question q WHERE ( EXISTS(SELECT r FROM Response r WHERE (r.question = q AND r.text LIKE '%Which%')) OR q.text LIKE '%Which%')

I tried running jpql queries derived from the above, but they work fine. Alas the application this is from uses  the criteria query logic all over the place, so re-writing to jpql is not possible.

I have two objects: Question which has String attribute text and Response which has String attribute test and Question attribute question.

        final EntityManager m = getEntityManager ();
        final CriteriaBuilder cb = m.getCriteriaBuilder();
        final Class<Question> cls = Question.class;
        final CriteriaQuery<Question> rootQ = cb.createQuery(cls);
        final Root<Question> root = rootQ.from(cls);
        rootQ.select(root);
        rootQ.where(cb.like(root.get("text"), "%Which%"));


        final Subquery<Response> subQ = rootQ.subquery(Response.class);
        final Root<Response> subRoot = subQ.from(Response.class);
        subQ.select(subRoot);

        // Response question = root (Question)
        final Predicate pCorrelate = cb.equal(subRoot.get("question"), root);
        final Predicate pLike = cb.like(subRoot.get("text"), "%Which%");

        final CriteriaQuery<Response> sQuery = cb.createQuery(Response.class);
        sQuery.where(cb.and(pCorrelate, pLike));
        sQuery.from(Response.class);

        // exists(suq query)
        final Predicate pExists = cb.exists(subQ.where(sQuery.getRestriction()));

        // Finally or question condition and response condition
        rootQ.where(cb.or(pExists, rootQ.getRestriction())) ;
        System.out.println("rootQ criteria was " + ((OpenJPACriteriaQuery)rootQ).toCQL());

        final List<Question> questions = m.createQuery(rootQ).getResultList();
        System.out.println("Found " + questions.size() + " items");

The query returns the expected list of questions.

Now if I add the following:

        final CriteriaQuery<Long> cq = cb.createQuery(Long.class);
        final Root<Question> root2 = cq.from(Question.class);
        cq.select(cb.count(root.get("id"))).where(rootQ.getRestriction());

        final TypedQuery<Long> query = m.createQuery(cq);
        System.out.println (query.unwrap(QueryImpl.class).getQueryString());
        System.out.println ("Count was " + query.getSingleResult().intValue());

I get:

Exception in thread "main" <openjpa-2.4.2-r422266:1777108 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: null
        at org.apache.openjpa.kernel.QueryImpl.createExecutor(QueryImpl.java:770)
        at org.apache.openjpa.kernel.QueryImpl.compileForDataStore(QueryImpl.java:713)
        at org.apache.openjpa.kernel.QueryImpl.compileForExecutor(QueryImpl.java:695)
        at org.apache.openjpa.kernel.QueryImpl.getOperation(QueryImpl.java:1535)
        at org.apache.openjpa.kernel.DelegatingQuery.getOperation(DelegatingQuery.java:123)
        at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:268)
        at org.apache.openjpa.persistence.QueryImpl.getResultList(QueryImpl.java:290)
        at org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.java:318)
        at com.kryterion.wa.delegate.BaseDelegate.main(BaseDelegate.java:310)
Caused by: java.util.EmptyStackException
        at java.util.Stack.peek(Stack.java:102)
        at org.apache.openjpa.persistence.criteria.SubqueryImpl.toValue(SubqueryImpl.java:287)
        at org.apache.openjpa.persistence.criteria.Expressions.toValue(Expressions.java:68)
        at org.apache.openjpa.persistence.criteria.Expressions$Exists.toKernelExpression(Expressions.java:1744)
        at org.apache.openjpa.persistence.criteria.PredicateImpl.toKernelExpression(PredicateImpl.java:171)
        at org.apache.openjpa.persistence.criteria.CriteriaExpressionBuilder.evalFilter(CriteriaExpressionBuilder.java:215)
        at org.apache.openjpa.persistence.criteria.CriteriaExpressionBuilder.getQueryExpressions(CriteriaExpressionBuilder.java:75)
        at org.apache.openjpa.persistence.criteria.CriteriaQueryImpl.getQueryExpressions(CriteriaQueryImpl.java:423)
        at org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl.eval(CriteriaBuilderImpl.java:81)
        at org.apache.openjpa.kernel.ExpressionStoreQuery$DataStoreExecutor.<init>(ExpressionStoreQuery.java:763)
        at org.apache.openjpa.kernel.ExpressionStoreQuery.newDataStoreExecutor(ExpressionStoreQuery.java:179)
        at org.apache.openjpa.kernel.QueryImpl.createExecutor(QueryImpl.java:755)
        ... 8 more

Am I doing something wrong or is this https://issues.apache.org/jira/browse/OPENJPA-2098 in a new guise?