fix(parser): preserve Oracle PRIOR position on all condition expressions (#2601) - #2602
Merged
manticore-projects merged 1 commit intoSep 11, 2026
Merged
Conversation
…ons (JSQLParser#2601) Condition() drops the consumed PRIOR keyword unless the parsed condition implements SupportsOldOracleJoinSyntax: BETWEEN / LIKE / SIMILAR TO / IS NULL / IS TRUE / IS UNKNOWN / IS DISTINCT FROM / MEMBER OF silently lose it, InExpression throws IllegalArgumentException, and comparisons keep it in toString() but lose it in the deparser. The eight classes now implement the interface (real prior field, explicit reject for the join operator), InExpression stores the position instead of rejecting it, and ExpressionDeParser renders PRIOR for all of them including both positions of OldOracleJoinBinaryExpression. Signed-off-by: 付典 <fudianchn@gmail.com>
Contributor
|
Thank you much! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AI disclosure: this change was prepared with AI coding agents, reviewed and revised line by line by me.
What
Between,LikeExpression,SimilarToExpression,IsNullExpression,IsBooleanExpression,IsUnknownExpression,IsDistinctExpressionandMemberOfExpressionnow implementSupportsOldOracleJoinSyntaxwith a real prior position,InExpressionstores the position instead of rejecting it, andExpressionDeParserrendersPRIORfor all of them plus both positions ofOldOracleJoinBinaryExpression. 20 new cases inOraclePriorPositionTest. No grammar change.Why
Condition()consumes a leadingPRIORand only propagates it onto conditions that implementSupportsOldOracleJoinSyntax. For the eight classes above the keyword is silently dropped (WHERE PRIOR a BETWEEN 1 AND 2deparses withoutPRIOR, inverting hierarchical-query semantics),PRIOR a IN (1, 2)throwsIllegalArgumentException, and comparisons losePRIORthrough the deparser althoughtoString()keeps it. Fixes #2601.How
Each of the eight classes carries an
oraclePriorPositionfield, rendersPRIORbefore its left expression intoString()and in itsExpressionDeParservisit, and rejectssetOldOracleJoinSyntaxwith an explicitIllegalArgumentException(mirroring howInExpressionused to reject prior positions: unsupported means explicit rejection, not silent acceptance; the(+)operator keeps its existing route through the operandColumn, as in #2564 / #2600).InExpressionreplaces its always-throwsetOraclePriorPositionwith a stored field and rendersPRIORintoString()and the deparser.deparse(OldOracleJoinBinaryExpression, ...)gains the twoPRIORpositions alongside the existing(+)marks. The grammar needs no change: theinstanceofgate inCondition()picks the new implementations up automatically. Known boundary, disclosed:ExpressionValidatorreportsFeature.oraclePriorPositionfor comparisons carrying PRIOR but not yet for these nine kinds (lenient direction only); aligning that is left as a follow-up.PRIORon the BETWEEN start operand (a BETWEEN PRIOR 1 AND 2, a plain ParseException today) is a separate grammar gap and is left out of scope.Root cause
Condition()consumes thePRIORtoken into a localoraclePriorand applies it onlyif (result instanceof SupportsOldOracleJoinSyntax); everything else discards it at parse time.Testing
net.sf.jsqlparser.expression.operators.relational.OraclePriorPositionTest: encoder cases for every condition kind (includingSIMILAR TOon both tokenizations,NOTforms, theISNULL/NOTNULLshorthands,IS FALSE,IS NOT UNKNOWN, theINform that used to throw), deparser guards forPRIOR a = b/a = PRIOR band aPRIORcomparison inside a joinONclause (all used to losePRIORin the round-trip), the unchanged plain forms, and combinations (NOT PRIOR, several conditions in one WHERE,PRIORcombined with(+)on a BETWEEN operand). On master, the encoder cases fail (silent loss /IllegalArgumentException, verified per form) and the comparison round-trip guards fail through the deparser; all 26 pass with this change.Between.setOraclePriorPositiona no-op turns the 3 BETWEEN cases red only; makingInExpression.setOraclePriorPositiona no-op turns the 2 IN cases red only; removing only the deparser's PRIOR guard forBetweenturns the 4 BETWEEN round-trip cases red while the AST assertions still see the position, proving toString() and the deparser are pinned independently; reverting only the two PRIOR marks indeparse(OldOracleJoinBinaryExpression, ...)turns exactly the 4 comparison round-trip cases red (the two guards, the ON-clause case and the multi-condition case) while all AST assertions stay green../gradlew checkandmvn verifyare green (full suite).PRIORis bit-identical (the only new work is a setter call whenPRIORis present); the corpus contains noPRIOR, so a benchmark could not exercise the changed path.Verification of the original issue
SELECT * FROM emp WHERE PRIOR empno BETWEEN 100 AND 2007cc86386: parses,toString()is... WHERE empno BETWEEN 100 AND 200(PRIOR lost)Between.getOraclePriorPosition()isORACLE_PRIOR_START, deparse identical to the input.Fixes #2601