[OPENJPA-2956] Unwrap ID(), honour null precedence and reject set operations in memory - #178
[OPENJPA-2956] Unwrap ID(), honour null precedence and reject set operations in memory#178rzo1 wants to merge 2 commits into
Conversation
…rations in memory Three separate defects on the in-memory path, all reachable: the executor is selected whenever a candidate collection is supplied, when the store does not support datastore execution, or when dirty instances are queried with FlushBeforeQueries disabled. ID() returned the internal identity wrapper rather than the raw key, so a comparison against the plain key threw a ClassCastException out of Filters.convert for numeric ids, never matched for an @EmbeddedId, and matched only by accident for a String id. It now unwraps exactly as the JDBC projection does. The wrapper-returning getObjectId() is unchanged. NULLS FIRST and NULLS LAST were ignored: the comparator hard coded nulls last when ascending and first when descending, so two of the four combinations were right by chance and two were silently wrong. The requested precedence is now threaded through, falling back to the previous policy when none is given. Set operations produced a NullPointerException from a compound expression with no filter, or an empty result. They are now rejected with a message that says why the query is running in memory and how to avoid it: the executor is built for one candidate extent and has no multiset semantics, and a candidate collection has no defined meaning across operands. Note that the in-memory path cannot yet be exercised end to end from JPQL with an identification variable: JPQLExpressionBuilder casts the value from getThis() to Path, and the in-memory factory returns a Val, so it fails with a ClassCastException. That is an older, separate defect and wants its own issue.
solomax
left a comment
There was a problem hiding this comment.
Do we need tests for this?
…rejection Review feedback. Both cases run through the in-memory executor by supplying a candidate collection, and both fail against the unchanged kernel: the null precedence test because the comparator ignored NULLS FIRST/LAST, the set operation test because the query failed with a NullPointerException instead of saying it cannot be evaluated in memory. ID() is deliberately not covered. It cannot be reached from JPQL in memory at all: JPQLExpressionBuilder casts the value from getThis() to Path, the in-memory factory returns a Val, and the query dies with a ClassCastException before the identity is evaluated. That is an older, separate defect; a test for ID() has to wait for it.
|
Added tests for two of the three, in
before the identity is ever evaluated. I confirmed that by writing the test and watching it error. That is an older defect, unrelated to this change, and I would rather fix it in its own issue than bundle a Happy to open that issue and add the |
Three separate defects, all reachable: the in-memory executor is selected whenever a candidate collection is supplied, when the store does not support datastore execution (openjpa-xmlstore), or when dirty instances are queried with
FlushBeforeQueriesdisabled.ID()returned the internal identity wrapper rather than the raw key, so a comparison against the plain key threwClassCastExceptionout ofFilters.convertfor numeric ids, never matched for an@EmbeddedId(OpenJPAId.equalsrequires class equality), and matched only by accident for a String id. It now unwraps exactly as the JDBC projection does. One correction to the review comment: JDBC does not unwrap the comparison operand — it normalises the other side, and its only unwrap isGetNativeObjectId.load(). The wrapper-returninggetObjectId()is unchanged.NULLS FIRST/NULLS LASTwere ignored: the comparator hard-coded nulls last when ascending and first when descending, so two of the four combinations were already right and two were silently wrong. The requested precedence is now threaded through, falling back to the previous policy when none is given — so rejecting these instead would have been a regression.Set operations produced a
NullPointerExceptionfrom a compoundQueryExpressionswith no filter, or an empty result. They are now rejected with a message saying why the query is running in memory and how to avoid it. Implementing them would be a feature, not a fix: the executor is built for a single candidate extent,setCandidateCollectionhas no defined meaning across operands, and the kernel has no multiset semantics for the ALL variants.Note that the in-memory path cannot yet be exercised end to end from JPQL with an identification variable:
JPQLExpressionBuildercasts the value fromgetThis()toPath, and the in-memory factory returns aVal, so it fails with aClassCastException. That is an older, separate defect and wants its own issue; it is why theID()change has no end-to-end test here.