Skip to content

Fix query planner bug leading to HTTP 500 NET-536#70

Merged
kalabukdima merged 3 commits into
masterfrom
fix-query-planner-cross-table-row-selection
May 20, 2026
Merged

Fix query planner bug leading to HTTP 500 NET-536#70
kalabukdima merged 3 commits into
masterfrom
fix-query-planner-cross-table-row-selection

Conversation

@kalabukdima
Copy link
Copy Markdown
Contributor

Fix: query planner routed simplified relations to the wrong scan table

What broke

Hotblocks returned 500 Internal Server Error for queries like this: {"logs": [{"transaction": true}], "fromBlock": N, "includeAllBlocks": true}. The response was:

failed to read column 'block_number'
Caused by:
  0: failed to read values buffer
  1: range list is out of bounds: 26693 < 30966

Where 26693 is the row count of the chunk's logs table and 30966 is the row count of the same chunk's transactions table.

Root cause

PlanBuilder::simplify() in crates/query/src/plan/plan.rs rewrites the plan when a query has a predicate-less selector (the no-filter shape selects the whole table; the simplification adds a direct full scan and drops anything redundant).

When the surviving relation isn't a "full rel" (its input_key doesn't match the input table's primary_key), the relation still needs to be evaluated against rows from its input_table. The current code keyed the new scan on rel.output_table() instead:

let table = rel.output_table();  // wrong

In execute_scans each scan reads rows from scan.table and pushes their row indexes into relation_inputs[rel_idx]. eval_join then interprets those indexes as positions in rel.input_table(). With the wrong key, transactions row indexes (0..30966) were fed into a slot that eval_join later applied as a row_selection to the logs table (0..26693 rows) → out-of-bounds in pagination.rs.

For EVM log selectors the trigger is structural: logs.primary_key = [block_number, log_index] but the join's input_key = [block_number, transaction_index], so is_full_rel(rel) returns false and the relation always survives simplification.

Fix

Rel::input_table() accessor added next to the existing output_table(). simplify() now keys the new scan on rel.input_table().

To safeguard against other occurrences, PlanBuilder::assert_scan_relation_invariant() runs at the end of simplify() and checks that every scan owns only relations whose input_table matches the scan's own table — the contract execute_scans already assumes. Running this assert! in release is cheap — planning runs once per request, and the cost is a short vector walk.

Tests

Added unit tests in plan.rs:

  • simplify_attaches_surviving_relations_to_input_table_scan — the direct reproducer.
  • simplify_drops_full_rel_and_replaces_with_direct_scan — covers the full-rel branch: relation is dropped and replaced with a direct scan.
  • simplify_preserves_invariant_with_mixed_predicated_and_unpredicated_scans — predicated and predicate-less scans on the same table coexist; invariant still holds.
  • assert_scan_relation_invariant_panics_on_input_table_mismatch — independently verifies the guard fires on a manually mismatched plan.

kalabukdima and others added 2 commits May 20, 2026 11:16
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kalabukdima kalabukdima requested a review from denisbsu May 20, 2026 09:43
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@denisbsu denisbsu left a comment

Choose a reason for hiding this comment

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

lgtm

@kalabukdima kalabukdima merged commit 62ccfa9 into master May 20, 2026
1 check passed
@kalabukdima kalabukdima deleted the fix-query-planner-cross-table-row-selection branch May 20, 2026 15:38
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