Skip to content

fix(engine): relationship property values return correct value on MATCH traversal (closes #367)#386

Merged
ryaker merged 2 commits intomainfrom
fix/rel-prop-traversal-367
Mar 30, 2026
Merged

fix(engine): relationship property values return correct value on MATCH traversal (closes #367)#386
ryaker merged 2 commits intomainfrom
fix/rel-prop-traversal-367

Conversation

@ryaker
Copy link
Copy Markdown
Owner

@ryaker ryaker commented Mar 30, 2026

Summary

  • Root cause: can_use_one_hop_chunked in pipeline_exec.rs did not guard against inline relationship property filters ([r:KNOWS {weight: 0.9}]). Queries with such filters were routed to the chunked pipeline, which has no edge-property read or filter stage — so the inline filter was silently ignored, returning rows that should have been excluded.
  • Fix: Added a single guard !pat.rels[0].props.is_empty() in can_use_one_hop_chunked to fall back to the row engine (execute_one_hop) when any inline rel prop filter is present. The row engine correctly reads edge_props.bin and applies the filter.
  • Regression tests: Added crates/sparrowdb/tests/regression_367.rs with 4 end-to-end tests covering float filter + projection, exclusion of non-matching edges, integer filter + exclusion, and post-checkpoint behaviour.

Root Cause Detail

The query MATCH (a)-[r:KNOWS {weight: 0.9}]->(b) RETURN r.weight went through this path:

  1. Parser produces rel_pat.props = [{key:"weight", value:0.9}]
  2. can_use_one_hop_chunked — existing guards excluded RETURN/WHERE edge-var refs, but not inline rel prop filters (which live in pat.rels[0].props, not in the WHERE clause)
  3. Chunked pipeline executes: ScanByLabel → ReadNodeProps(src) → GetNeighbors → ReadNodeProps(dst) → MaterializeRows — no edge-props read, no filter
  4. All neighbor edges pass, r.weight projects as Null

The fix is minimal and correct: fall back to the proven row engine for any query that needs edge-property filtering. A future enhancement could add an edge-prop filter stage to the chunked pipeline.

Test plan

  • cargo check -p sparrowdb passes
  • cargo fmt --all no diffs
  • crates/sparrowdb/tests/regression_367.rs — 4 new tests all pass
  • crates/sparrowdb/tests/spa_178_edge_properties.rs — all 11 tests pass (2 were failing before fix)
  • crates/sparrowdb/tests/spa_229_edge_prop_float.rs — all 4 pass
  • crates/sparrowdb/tests/spa_261_edge_props_perf.rs — all 4 pass
  • Full cargo test -p sparrowdb — only pre-existing regression_355 failures (unrelated)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed relationship property filtering in query execution. Queries with inline relationship property filters (e.g., [r:KNOWS {since:2020}]) that project relationship properties now execute correctly and maintain consistency across database checkpoints.

…loses #367)

The chunked one-hop pipeline (`execute_one_hop_chunked`) had no edge-property
read or filter stage. `can_use_one_hop_chunked` correctly excluded queries
referencing edge variables in RETURN or WHERE, but did NOT exclude queries
with inline relationship property filters (e.g. `[r:KNOWS {weight: 0.9}]`).

Such queries were routed to the chunked path, which ignored the inline filter
entirely — returning rows that should have been excluded and projecting edge
prop values as Null.

Fix: add a `!pat.rels[0].props.is_empty()` guard to `can_use_one_hop_chunked`
so any query with an inline rel prop filter falls back to the row engine
(`execute_one_hop`) where the filter is properly evaluated after reading
edge_props.bin.

Added regression_367.rs covering: float filter + projection, exclusion of
non-matching edges, integer filter + exclusion, and post-checkpoint behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Mar 30, 2026

User does not have a PR Review subscription.

Go to Team management and add this email to the PR Review subscription.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Warning

Rate limit exceeded

@ryaker has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 18 minutes and 14 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 18 minutes and 14 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b0a6b1cc-f933-4c48-abf6-70233be873d0

📥 Commits

Reviewing files that changed from the base of the PR and between d0e8963 and f995349.

📒 Files selected for processing (1)
  • crates/sparrowdb-execution/src/engine/pipeline_exec.rs
📝 Walkthrough

Walkthrough

Updated Engine::can_use_one_hop_chunked to add a guard rejecting chunked Phase 2 execution when relationship patterns contain inline property filters, preventing incorrect handling of relationship edge-property filters. Added comprehensive regression test suite covering relationship property filtering, projection, and checkpoint persistence.

Changes

Cohort / File(s) Summary
Engine Execution Guard
crates/sparrowdb-execution/src/engine/pipeline_exec.rs
Added condition to can_use_one_hop_chunked that rejects chunked execution when relationship pattern contains inline property filters (pat.rels[0].props.is_empty() == false), forcing fallback to row engine for correct property filter handling.
Regression Tests
crates/sparrowdb/tests/regression_367.rs
New test file with four test cases covering relationship property filtering and projection scenarios: basic filter+project, non-matching filter exclusion, integer property filtering, and post-checkpoint persistence of edge properties and filters.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #245: Modifies executor gating for one-hop/chunked execution to block optimized paths when relationship edge properties are referenced, ensuring correct edge-prop handling.
  • PR #227: Introduces RelPattern.props and inline rel-prop filtering logic that this PR's guard directly references.
  • PR #375: Updates chunked-pipeline eligibility checks in pipeline_exec.rs with additional guards forcing fallback to row engine.

Suggested labels

size:M

Poem

🐰 A hop through the pipeline, we pause to reflect,
When edges wear properties, we must reconnect,
The filter won't chunked, the engine takes care,
Relationship secrets, now handled with flair! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main fix: relationship property values returning correct values on MATCH traversal. It directly corresponds to the primary changeset which adds a guard in can_use_one_hop_chunked to prevent chunked execution when relationship property filters are present, and adds regression tests. The title is concise, specific, and summarizes the core issue being resolved.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rel-prop-traversal-367

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ryaker
Copy link
Copy Markdown
Owner Author

ryaker commented Mar 30, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/sparrowdb-execution/src/engine/pipeline_exec.rs (1)

1099-1116: Consider adding the same rel.props guard to can_use_two_hop_chunked and can_use_mutual_neighbors_chunked for consistency.

The two-hop path checks for edge-property references in RETURN/WHERE (lines 1099-1116) and node inline props (line 1125), but doesn't guard against inline relationship property filters (rel.props). A query like:

MATCH (a)-[r1:KNOWS {weight: 0.9}]->(b)-[r2:KNOWS]->(c) RETURN r1.weight

would have the same issue fixed here for one-hop. The same applies to can_use_mutual_neighbors_chunked (lines 738-755).

♻️ Suggested guard for two-hop
 // Inline prop filters on node patterns are not evaluated by the chunked
 // two-hop path — fall back to the row engine.  (See `#362`.)
 if pat.nodes.iter().any(|n| !n.props.is_empty()) {
     return false;
 }
+// Inline prop filters on relationship patterns are not evaluated by the
+// chunked two-hop path — fall back to the row engine.  (See `#367`.)
+if pat.rels.iter().any(|r| !r.props.is_empty()) {
+    return false;
+}
 // id(n) and other NodeRef-dependent functions require the row engine (`#372`).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/sparrowdb-execution/src/engine/pipeline_exec.rs` around lines 1099 -
1116, The two-hop and mutual-neighbors chunked checks need the same guard
against inline relationship property filters as the one-hop logic: in
can_use_two_hop_chunked and can_use_mutual_neighbors_chunked, when iterating
pattern relationships (pat.rels) and checking rel.var, also check rel.props
(e.g., if !rel.props.is_empty()) and return false if any relationship has inline
properties, so queries with relationship property filters (rel.props) are
excluded just like node inline props; add this condition alongside the existing
rel.var/ref-in-return and expr_references_var checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/sparrowdb-execution/src/engine/pipeline_exec.rs`:
- Around line 1099-1116: The two-hop and mutual-neighbors chunked checks need
the same guard against inline relationship property filters as the one-hop
logic: in can_use_two_hop_chunked and can_use_mutual_neighbors_chunked, when
iterating pattern relationships (pat.rels) and checking rel.var, also check
rel.props (e.g., if !rel.props.is_empty()) and return false if any relationship
has inline properties, so queries with relationship property filters (rel.props)
are excluded just like node inline props; add this condition alongside the
existing rel.var/ref-in-return and expr_references_var checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3e5072ec-18de-4954-9f4e-12ca7a273091

📥 Commits

Reviewing files that changed from the base of the PR and between 6a7bf3c and d0e8963.

📒 Files selected for processing (2)
  • crates/sparrowdb-execution/src/engine/pipeline_exec.rs
  • crates/sparrowdb/tests/regression_367.rs

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses issue #367 where inline relationship property filters were not being correctly evaluated in the chunked one-hop path. The fix involves falling back to the row engine when relationship properties are present in the pattern to ensure filters are applied correctly. Additionally, a comprehensive regression test suite has been added to verify the fix across various scenarios, including property projections and post-checkpoint behavior. I have no feedback to provide.

…unked paths

CodeRabbit review noted the one-hop fix in #367 left the same gap in
can_use_two_hop_chunked and can_use_mutual_neighbors_chunked: inline
relationship property filters (e.g. [r:KNOWS {weight: 0.9}]) would still
be silently ignored when routed through those chunked paths.

- Add `pat.rels.iter().any(|r| !r.props.is_empty())` guard to
  can_use_mutual_neighbors_chunked (alongside the existing edge-var checks)
- Add the same guard to can_use_two_hop_chunked (after the node-props guard)

Both functions now consistently fall back to the row engine whenever any
inline rel prop filter is present, matching the one-hop behaviour.

Co-Authored-By: Claude <noreply@anthropic.com>
@ryaker ryaker merged commit f71c853 into main Mar 30, 2026
5 checks passed
@ryaker ryaker deleted the fix/rel-prop-traversal-367 branch March 30, 2026 16:32
@github-actions
Copy link
Copy Markdown

Benchmark Results

(no benchmarks found)

✅ No regressions detected

1 similar comment
@github-actions
Copy link
Copy Markdown

Benchmark Results

(no benchmarks found)

✅ No regressions detected

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.

1 participant