Community
Participate
Working Groups
I've run into an odd bug when eclipselink decides to perform a class-hierarchy read by switching on the dtype rather than using an outer-join across all subclasses. The bug is reproducible but not consistent, i.e., I have seen eclipselink fail for some patterns and succeed with (apparently) similar patterns. The essence of the problem is that the "select dtype" portion of the SQL string does not always use the alias. Instead, it uses a "tablespace+tablename.dtype", which causes a 'multi-part identifier "tablespace+tablename.dtype" could not be bound' SQL error. The error has appeared using both the CriteriaBuilder and JPQL. Consider the following example: int join_pk_parameter; CriteriaQuery<A> c = cb.createQuery(A.class); Root<A> a = c.from(A.class); Root<TempJoin> t = c.from(TempJoin.class); Root<B> b = c.from(B.class); c.select(a) .where( cb.and( cb.equal(t.get("join_pk"), join_pk_parameter), cb.equal(b.get("target_fk"), t.get("join_fk")), cb.equal(b.get("a_fk"), a.get("pk")) ) ) ; where: class "A" is the superclass of a type hierarchy class "TempJoin" is a utility class for temporary "join" values, i.e., for use where a typical "IN" clause has a great many values. class "B" is merely being joined. SELECT a FROM A a, B b, TempJoin t WHERE t.join_pk = :join_pk_parameter AND t.join_fk = b.target_fk AND b.a_fk = a.pk (Note: The above JPQL is eyeballed, so pardon me if I typed it wrong. The CriteriaBuilder code is the actual code I am using.) In English, I have a starting collection of primary keys I have inserted into table TempJoin with a join_pk_parameter primary key. I use this to join to table B via a "target_fk", then a join from table B to table A, which is my desired result. If eclipselink queries the "A" class hierarchy with an outer join, it works fine. If eclipselink decides to query the "A" class hierarchy with a "dtype" query first, then a series of subclass queries, then it fails as follows: SELECT DISTINCT dbo.A.dtype FROM dbo.B t0, dbo.TEMP_JOIN t2, dbo.A t1 WHERE ((t0.A_FK = t1.PK) AND ((t0.TARGET_fk = t2.FK) AND (t2.JOINPK = ?))) which causes a SQL exception: "The multi-part identifier "dbo.A.dtype" could not be bound." Obviously it cannot be bound. The query should actually read: SELECT DISTINCT t1.dtype FROM dbo.B t0, dbo.TEMP_JOIN t2, dbo.A t1 WHERE ((t0.A_FK = t1.PK) AND ((t0.TARGET_fk = t2.FK) AND (t2.JOINPK = ?))) Interesting, the problem is dependent on dynamic issues. For example, if I add one additional line to the where clause: int join_pk_parameter; CriteriaQuery<A> c = cb.createQuery(A.class); Root<A> a = c.from(A.class); Root<TempJoin> t = c.from(TempJoin.class); Root<B> b = c.from(B.class); c.select(a) .where( cb.and( cb.isNotNull(a.get("pk")), //REQUIRED TO AVOID THE DTYPE BUG cb.equal(t.get("join_pk"), join_pk_parameter), cb.equal(b.get("target_fk"), t.get("join_fk")), cb.equal(b.get("a_fk"), a.get("pk")) ) ) ; then eclipselink actually constructs the query correctly. Further evidence of the dynamic aspect is that I actually have my own builder constructor instance on top of the CriteriaBuilder (to prevent duplicated Root objects and give me flexible ordering of the query construction). When I add the additional line to my builder, I still see the error, so slightly different construction causes different results. For now, the only reliable workaround I can find is to force an ORDER BY clause. This causes eclipselink to always choose the outer-join approach for class hierarchy queries.
Setting target and priority. See the following page for the meanings of these fields: http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines Community: Please vote for this bug if it is important to you. Votes are one of the main criteria we use to determine which bugs to fix next.
I think after so many years with no activity on this bug the following is worth pointing out: - I can confirm that the bug still exists and that the description appears accurate. - I can also confirm that the workaround described by Rich MacDonald (adding an ORDER BY clause even if it's not needed) is still functional.
I think I came across a similar problem - query SELECT tr FROM Transaction tr LEFT JOIN Mtm mtm ON mtm.trans = tr AND m.createdAt = :at WHERE mtm.id IS NULL AND tr.createdAt < :to Results in: SELECT DISTINCT transaction._type FROM transaction t1 LEFT OUTER JOIN mtm t0 ON ((t0.trade_id = t1.ID) AND (t0.created_at = ?)) WHERE ((t0.ID IS NULL) AND (t1.created_at < ?)) If I swap the conditions arround, it's fixed: SELECT tr FROM Transaction tr LEFT JOIN Mtm mtm ON mtm.trans = tr AND m.createdAt = :at WHERE tr.createdAt < :to AND mtm.id IS NULL SELECT DISTINCT t1._type FROM transaction t1 LEFT OUTER JOIN mtm t0 ON ((t0.trade_id = t1.ID) AND (t0.created_at = ?)) WHERE ((t0.ID IS NULL) AND (t1.created_at < ?)) The problem is, that in org.eclipse.persistence.internal.expressions.SQLSelectStatement#writeField alias is retrieved like this: if (field.getTable() != lastTable) { lastTable = field.getTable(); currentAlias = getBuilder().aliasForTable(lastTable); // This is really for the special case where things were pre-aliased if (currentAlias == null) { currentAlias = lastTable; } } but getBuilder() is bound to the first expression appearing in where clause, but the first expression - mtm.id IS NULL - does not contain alias for table transaction. I don't understand why tableAliases is not used to retrieve alias in SQLSelectStatement
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink