persistence@glassfish.java.net

Re: Is it legal to have a JPQL query that has multiple LEFT JOIN FETCHes?

From: Michael Bouschen <Michael.Bouschen_at_Sun.COM>
Date: Tue, 20 Feb 2007 11:46:52 +0100

Hi Jon,

I tried to reproduce the NPE using a similar LEFT JOIN FETCH query, but
it works on my side. I also tried joining a OneToMany relationship of
the same class similar what you did with the i.subItems, but I'm not
able to reproduce the NPE.

Could you please file an issue at
https://glassfish.dev.java.net/servlets/ProjectIssues using
entity-persistence as subcomponent. It would be great if you could
attach a test case to the issue that allows us to reproduce the NPE.

Thanks!

Regards Michael

> Thanks Tom. The following is the exact query and stack trace. If I
> left join to i.reservations instead of i.subItems it works fine. i.e.
> maybe it has something to do with the fact that it's joining to itself?
>
> Feb 19, 2007 3:53:04 PM
> edu.uchicago.at.reservations.ReservationsService findAvailableItems
> FINEST: SELECT i FROM Item i LEFT JOIN FETCH i.subItems ORDER BY i.name
> Feb 19, 2007 3:53:04 PM
> oracle.toplink.essentials.session.file:/J:/Reservations/ReservationsLibrary/build/classes/-Reservations
>
> WARNING:
> java.lang.NullPointerException
> at
> oracle.toplink.essentials.internal.expressions.SQLSelectStatement.appendFromClauseForOuterJoin(SQLSelectStatement.java:347)
>
> at
> oracle.toplink.essentials.internal.expressions.SQLSelectStatement.appendFromClauseToWriter(SQLSelectStatement.java:452)
>
> at
> oracle.toplink.essentials.internal.expressions.SQLSelectStatement.printSQL(SQLSelectStatement.java:1310)
>
> at
> oracle.toplink.essentials.internal.expressions.SQLSelectStatement.buildCall(SQLSelectStatement.java:683)
>
> at
> oracle.toplink.essentials.descriptors.ClassDescriptor.buildCallFromStatement(ClassDescriptor.java:548)
>
> at
> oracle.toplink.essentials.internal.queryframework.StatementQueryMechanism.setCallFromStatement(StatementQueryMechanism.java:393)
>
> at
> oracle.toplink.essentials.internal.queryframework.ExpressionQueryMechanism.prepareReportQuerySelectAllRows(ExpressionQueryMechanism.java:1379)
>
> at
> oracle.toplink.essentials.queryframework.ReportQuery.prepareSelectAllRows(ReportQuery.java:988)
>
> at
> oracle.toplink.essentials.queryframework.ReadAllQuery.prepare(ReadAllQuery.java:398)
>
> at
> oracle.toplink.essentials.queryframework.ReportQuery.prepare(ReportQuery.java:904)
>
> at
> oracle.toplink.essentials.queryframework.DatabaseQuery.checkPrepare(DatabaseQuery.java:387)
>
> at
> oracle.toplink.essentials.queryframework.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:469)
>
> at
> oracle.toplink.essentials.queryframework.DatabaseQuery.execute(DatabaseQuery.java:587)
>
> at
> oracle.toplink.essentials.queryframework.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:677)
>
> at
> oracle.toplink.essentials.queryframework.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:731)
>
> at
> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2219)
>
> at
> oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:937)
>
> at
> oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:909)
>
> at
> oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:335)
>
> at
> oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.getResultList(EJBQueryImpl.java:442)
>
> at
> edu.uchicago.at.reservations.ReservationsService.findAvailableItems(ReservationsService.java:61)
>
> at
> edu.uchicago.at.reservations.ReservationsServiceTest.testFindAvailableItems(ReservationsServiceTest.java:91)
>
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>
> at java.lang.reflect.Method.invoke(Method.java:585)
> at junit.framework.TestCase.runTest(TestCase.java:154)
> at junit.framework.TestCase.runBare(TestCase.java:127)
> at junit.framework.TestResult$1.protect(TestResult.java:106)
> at junit.framework.TestResult.runProtected(TestResult.java:124)
>
> Jon
>
> ----- Original Message ----- From: "Tom Ware" <tom.ware_at_Oracle.com>
> To: <persistence_at_glassfish.dev.java.net>
> Sent: Monday, February 19, 2007 3:27 PM
> Subject: Re: Is it legal to have a JPQL query that has multiple LEFT
> JOIN FETCHes?
>
>
>> Hi Jon,
>>
>> I am a bit surprised you are seeing an issue with the query you list
>> below.
>>
>> Our test framework has some similar queries that work. For instance:
>>
>> "SELECT e from Employee e JOIN FETCH e.projects"
>>
>> Is the exception trace for your current query the same as for the
>> previous query?
>>
>> BTW: I took a quick look at the BNF for JPQL and it seems your
>> double joining query is not legal. JPQL requires a
>> range_variable_declaration for each fetch join. That means:
>> Item i LEFT JOIN FETCH i.reservations
>>
>> Is Legal
>>
>> And the second part:
>>
>> LEFT JOIN FETCH i.subItems
>> Is missing something. (you can't join to "Item i" from the previous
>> clause)
>>
>> -Tom
>>
>>
>> Jon Miller wrote:
>>
>>> I just tried the following which throws a NPE too. So, it looks like
>>> it's probably the fact that I'm mapping to the same class rather
>>> than the fact that I had two LEFT JOINs which is what I thought
>>> might have been the original problem. Is this a bug?
>>>
>>> SELECT i FROM Item i LEFT JOIN FETCH i.subItems ORDER BY i.name
>>>
>>> Jon
>>>
>>
>> --
>> Tom Ware
>> Principal Software Engineer
>> Oracle Canada Inc.
>>
>> Direct: (613) 783-4598
>> Email: tom.ware_at_oracle.com
>>