Skip to content

core/vdbe: Short-circuit index seek on NULL keys in LEFT JOIN#6268

Open
friskypriyanshu wants to merge 4 commits intotursodatabase:mainfrom
friskypriyanshu:fix/left-join-null-index
Open

core/vdbe: Short-circuit index seek on NULL keys in LEFT JOIN#6268
friskypriyanshu wants to merge 4 commits intotursodatabase:mainfrom
friskypriyanshu:fix/left-join-null-index

Conversation

@friskypriyanshu
Copy link
Copy Markdown

Fixes: #6077

Description
Fixes a query optimizer bug where chained LEFT JOINs producing virtual NULL keys were incorrectly matching literal NULLs in downstream indexed tables.

Root Cause & Fix
The VDBE op_seek instruction was evaluating NULL keys against the index instead of short-circuiting (violating NULL = NULL is false).

In core/vdbe/execute.rs (op_seek):

Intercepted RecordSource::Unpacked registers before calling seek_internal.

If any search register evaluates to Null, the seek instantly aborts.

Extracted target_pc to update state.pc directly and returned InsnFunctionStepResult::Step to correctly trigger the "not found" branch.

Testing
Added left_join_null_index_bug.sqltest using the exact schema/query from the issue.

Suite now passes cleanly with correct empty columns for unmatched rows.

Copy link
Copy Markdown

@turso-bot turso-bot bot left a comment

Choose a reason for hiding this comment

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

Please review @pereman2

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 6, 2026

Fossier: Manual Review Requested

@friskypriyanshu is a new contributor. A maintainer should review this PR before merging.

Score Breakdown

Total Score: 69.3/100 | Confidence: 100% | Outcome: REVIEW

Signal Value Score Weight
account_age 1244 1.00 0.10
public_repos 13 0.65 0.06
contribution_history 13 0.07 0.06
follower_ratio 1.0 0.50 0.06
bot_signals False 1.00 0.06
open_prs_elsewhere 2 0.87 0.10
closed_prs_elsewhere 1 0.90 0.11
prior_interaction True 1.00 0.10
pr_content ... 1.00 0.10
commit_email no_email 0.50 0.05
pr_description ... 0.70 0.05
repo_stars 18127 0.30 0.05
org_membership 0 0.20 0.04
commit_verification ... 0.30 0.05
contributor_stars 2 0.04 0.05

@PThorpe92
Copy link
Copy Markdown
Collaborator

/fossier approve

@tursodatabase tursodatabase deleted a comment from github-actions bot Apr 6, 2026
@tursodatabase tursodatabase deleted a comment from github-actions bot Apr 6, 2026
@penberg penberg changed the title fix: short-circuit index seek on NULL keys in LEFT JOIN (#6077) core/vdbe: Short-circuit index seek on NULL keys in LEFT JOIN Apr 7, 2026
@friskypriyanshu
Copy link
Copy Markdown
Author

Hi @penberg @jussisaurio, just a gentle ping on this one. All checks are green, including the fix for the fuzzer regression. Ready for review whenever you have a moment. Thanks!

};

if is_eq_only {
// We only care about Unpacked record sources for this short-circuit
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

isn't it invariant that this is RecordSource::Unpacked, since it's constructed above? Let's do let ... else instead of if let for that reason.

if is_eq_only {
// We only care about Unpacked record sources for this short-circuit
if let RecordSource::Unpacked { start_reg, .. } = record_source {
// Check only the primary register (no need for a loop 'i' here)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why is there no need? This should be part of the comment.

if let RecordSource::Unpacked { start_reg, .. } = record_source {
// Check only the primary register (no need for a loop 'i' here)
if state.registers[start_reg].is_null() {
let offset = match target_pc {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You can use target_pc.as_offset_int() here which has equivalent behavior

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-level LEFT JOIN incorrectly matches NULL-key rows from deeper indexed table

3 participants