Skip to content

Fix DerefExpr sequence dispatch and iterator sharing - #109

Merged
JohannesLichtenberger merged 2 commits into
masterfrom
fix/derefexpr-sequence-dispatch
Jul 21, 2026
Merged

Fix DerefExpr sequence dispatch and iterator sharing#109
JohannesLichtenberger merged 2 commits into
masterfrom
fix/derefexpr-sequence-dispatch

Conversation

@JohannesLichtenberger

Copy link
Copy Markdown
Member

Problem

DerefExpr dispatched on the concrete ItemSequence/LazySequence classes and silently derefed every other Sequence implementation to the empty sequence — notably FlatteningSequence, which is what a parenthesized expression (SequenceExpr) evaluates to. As a result:

count((for $x in 1 to 3 return {"a": $x}).a)

returned 0 without ever evaluating the pipeline.

A second latent issue: the lazy mapping sequence captured one shared base iterator, so a second iterate() call resumed the exhausted first iteration (count($s) + count($s) over a let-bound deref returned 3 instead of 6).

Fix

  • Keep every original dispatch branch bit-identical, and add the missing tail: any other non-item Sequence is mapped lazily per item (non-record items still deref to empty, exactly like the original's per-item mapping).
  • Open a fresh base iterator per iterate() call on the returned lazy sequence.

Tests

Four regressions in JsonTest:

  • parenthesized-FLWOR deref: count((for $i in 1 to 3 return {"a": $i}).a)3 (was 0)
  • records lacking the field are skipped: → 2
  • plain parenthesized record sequence: ({"a": 1}, {"b": 2}, {"a": 3}).a1 3
  • double iteration is fresh: count($s) + count($s)6 (was 3)

Full suite: 1262 tests, 0 failures, 0 errors.

Also bumps the version to 1.0-alpha9-SNAPSHOT so downstream consumers (sirix) can pin a snapshot version that provably contains this fix.


Generated by Claude Code

claude added 2 commits July 21, 2026 18:13
DerefExpr dispatched on the concrete ItemSequence/LazySequence classes and
silently derefed every other Sequence implementation to the empty
sequence — notably FlatteningSequence, which is what a parenthesized
expression (SequenceExpr) evaluates to. As a result
(for $x in 1 to 3 return {"a": $x}).a returned empty without ever
evaluating the pipeline.

Keep every original branch bit-identical and add the missing tail: any
other non-item Sequence is mapped lazily per item (non-record items still
deref to empty). Also open a FRESH base iterator per iterate() call on
the returned lazy sequence — the shared captured iterator previously made
a second iteration resume the exhausted first one.

Regression tests: parenthesized-FLWOR deref (count 3, was 0),
missing-field skip, plain parenthesized record sequence, and
double-iteration freshness.
@JohannesLichtenberger
JohannesLichtenberger merged commit 1ab3961 into master Jul 21, 2026
1 check passed
@JohannesLichtenberger
JohannesLichtenberger deleted the fix/derefexpr-sequence-dispatch branch July 21, 2026 18:17
@sonarqubecloud

Copy link
Copy Markdown

JohannesLichtenberger pushed a commit to sirixdb/sirix that referenced this pull request Jul 21, 2026
… per-IndexType container slots

- Bump io.sirix:brackit to 1.0-alpha9-SNAPSHOT (main + tests artifacts),
  which carries the upstream DerefExpr sequence-dispatch fix
  (sirixdb/brackit#109): (pipe).field over parenthesized pipelines now
  evaluates the pipe and iterates freshly per pass.
- Drop the temporary SirixDerefExpr port and its translator override —
  redundant now that the fix ships in brackit itself.
- Sticky-winner codec election for the KEYVALUELEAFPAGE body bake-off:
  only probe pages (first 8 per thread, then every Nth,
  -Dsirix.codecBakeoff.probeInterval, default 16) run all three codecs
  and (re-)elect a winner; pages in between encode with the elected
  codec alone (~3x less encode work). The codec byte keeps the format
  self-describing; probeInterval=1 restores exhaustive pick-smallest
  for byte-identical golden files. Both body writers (template-dedup
  and inline) now share one emit helper instead of two copies.
- Per-IndexType most-recent page-container slots in the storage engine
  writer: interleaved index streams during shredding no longer thrash
  the shared two-slot LRU into access-ordered HashMap probes. Slots are
  stamped only at the post-CoW site (never frozen), and invalidated at
  snapshot rotation, commit reset, and close.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants