Fix // with parenthesized and non-LocationStep expressions#6106
Fix // with parenthesized and non-LocationStep expressions#6106duncdrum merged 1 commit intoeXist-db:developfrom
Conversation
1371de2 to
7bd64bb
Compare
…LocationStep The XQUF grammar changes inadvertently replaced the original handling of // (descendant-or-self) followed by non-LocationStep expressions (such as FilteredExpression wrapping union patterns like //(div|span)[ft:query(...)]). The new code inserted an explicit descendant-or-self::node() step instead of calling setPrimaryAxis(DESCENDANT_SELF_AXIS) on the expression. This broke the Lucene index optimizer, which reads the primary axis from the Union's left/right PathExprs to determine the index search strategy. Restore the original develop behavior: - Call setPrimaryAxis(DESCENDANT_SELF_AXIS) on non-LocationStep expressions - Wrap VariableReferences in SimpleStep - Set abbreviated=true on FilteredExpressions The //(@x) parenthesized attribute pattern remains a pre-existing limitation (see PR eXist-db#6106 for the fix). Update the test to not assert on that pattern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…LocationStep The XQUF grammar changes inadvertently replaced the original handling of // (descendant-or-self) followed by non-LocationStep expressions (such as FilteredExpression wrapping union patterns like //(div|span)[ft:query(...)]). The new code inserted an explicit descendant-or-self::node() step instead of calling setPrimaryAxis(DESCENDANT_SELF_AXIS) on the expression. This broke the Lucene index optimizer, which reads the primary axis from the Union's left/right PathExprs inside a FilteredExpression to determine the index search strategy. Restore the original develop behavior: - Call setPrimaryAxis(DESCENDANT_SELF_AXIS) on non-LocationStep expressions - Wrap VariableReferences in SimpleStep - Set abbreviated=true on FilteredExpressions The //(@x) parenthesized attribute pattern remains a pre-existing limitation (see PR eXist-db#6106 for the fix). Update the test to not assert on that pattern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The failure of |
line-o
left a comment
There was a problem hiding this comment.
This looks like a very valuable addition.
|
Can the commits be squashed into one? |
|
[This response was co-authored with Claude Code. -Joe] Good eye — K2-Steps-31 does test The remaining failure is a pre-existing dedup bug — identical on The root cause is in I'll file a separate issue for the path expression dedup bug. It affects any |
|
[This response was co-authored with Claude Code. -Joe] Will squash into a single commit. |
b55f99d to
a0a7c0b
Compare
|
Squashed - thanks for spotting the need for cleanup! |
Fixed in #6110 |
a0a7c0b to
f2b0901
Compare
The abbreviated descendant-or-self syntax (//) was broken for non-LocationStep right-hand expressions like //(@attr), //(a | b), and //$var. The tree walker called setPrimaryAxis(DESCENDANT_SELF_AXIS) on the right-hand expression, but this is a no-op for non-LocationStep expressions (the method has an empty body in AbstractExpression). Fix: for FilteredExpression and VariableReference, continue calling setPrimaryAxis so the Lucene index optimizer can read the primary axis from inner PathExprs. For all other non-LocationStep expression types, insert an explicit descendant-or-self::node() LocationStep before the expression, correctly expanding the // abbreviation. The inserted step must NOT be marked as abbreviated, because abbreviated descendant-or-self steps get rewritten to descendant-only during analyze(), which would skip direct children. setPrimaryAxis must NOT be called for the generic else branch because it propagates into inner PathExpr children and corrupts their axes (e.g., overwriting an attribute axis in //(@x)). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
f2b0901 to
90df53a
Compare
Summary
//) when followed by non-LocationStep expressions like//(@attr),//(a | b), and//$varsetPrimaryAxis()is a no-op on non-LocationStep classesRoot Cause
In
XQueryTree.g, the DSLASH handler has two branches://child::x): merges the descendant-or-self axis into the step — works correctly//(@x),//(a | b)): calledsetPrimaryAxis(Constants.DESCENDANT_SELF_AXIS), which is defined as an empty method body inAbstractExpression— effectively a no-opFix
Split the non-LocationStep branch into three cases:
VariableReference: retainsetPrimaryAxis+ wrap inSimpleStep(existing behavior, works correctly)FilteredExpression: retainsetPrimaryAxis+ mark abbreviated (preserves Lucene index optimizer, which reads the primary axis from inner PathExprs to determine search strategy)PathExprwrapping parenthesized expressions): insert an explicitdescendant-or-self::node()LocationStep before the expression, correctly expanding//exprto/descendant-or-self::node()/exprper spec.setPrimaryAxismust NOT be called here because it propagates into inner PathExpr children and corrupts their axes (e.g., overwriting an attribute axis in//(@x)). The inserted step must NOT be marked as abbreviated, becauseLocationStep.analyze()rewrites abbreviated descendant-or-self steps to descendant-only, which would skip direct children.What Changed
exist-core/.../parser/XQueryTree.gexist-core/.../xquery/DescendantOrSelfWithNonLocationStepTest.javaSpec Reference
XQuery 3.1 §3.3.5 Abbreviated Syntax: "The abbreviated syntax
//is short for/descendant-or-self::node()/"Related
//followed by reverse axis steps — same handler, different branch)K2-Steps-31(XQTS) fails on bothdevelopand this PR due to a pre-existing dedup bug inPathExprwhen/is followed by a function call — will be addressed in a follow-on PRXQTS Results (W3C XQTS 3.1, full suite)
Improvements (2 tests newly passing):
ParenthesizedExpr-8(prod-ParenthesizedExpr) —//(@attr)now workshof-046(prod-NamedFunctionRef) — higher-order function with//Apparent regressions (9 tests) are pre-existing keyword-as-variable-name parse errors (
ascending,castable,processing-instruction), not caused by this change. These are addressed by PR #6103.Test Plan
DescendantOrSelfWithNonLocationStepTest(4 tests)🤖 Generated with Claude Code