Skip to content

feat(sql): JOIN ... USING / NATURAL / CROSS (SQLR-5)#158

Merged
joaoh82 merged 1 commit into
mainfrom
sqlr5-join-using-natural-cross
Jun 2, 2026
Merged

feat(sql): JOIN ... USING / NATURAL / CROSS (SQLR-5)#158
joaoh82 merged 1 commit into
mainfrom
sqlr5-join-using-natural-cross

Conversation

@joaoh82
Copy link
Copy Markdown
Owner

@joaoh82 joaoh82 commented Jun 1, 2026

Summary

Completes the SQLR-5 JOIN surface. PR #99 shipped INNER / LEFT / RIGHT / FULL OUTER JOIN ... ON ...; this adds the three related shapes SQLite supports, all riding the existing nested-loop driver:

  • JOIN ... USING (col[, col…]) — lowered to left.col = right.col AND-chained per column. The joined-on column shows once in SELECT * (left copy kept), matching SQLite.
  • NATURAL JOIN — auto-discovers the shared column names, then behaves exactly like USING (<shared>). No shared columns ⇒ a cross product (SQLite behavior). Combines with flavors (NATURAL LEFT JOIN).
  • CROSS JOIN — the cross product; rewritten to INNER JOIN ... ON true at parse time.

How

  • Parser (src/sql/parser/select.rs): JoinClause.on: Exprconstraint: JoinConstraintKind (On/Using/Natural). USING/NATURAL no longer error; CROSS is rewritten to ON true.
  • Executor (src/sql/executor.rs): resolve_join_constraint synthesizes the equality predicate against live schemas (left qualifier picked per column so join chains resolve correctly), and SELECT * de-duplicates USING/NATURAL columns.

The synthesized predicates flow through the same eval_predicate_scope path as ON, so NULL/truthiness semantics and outer-join NULL-padding are inherited unchanged.

Tests

8 new executor tests (replacing the old using_or_natural_join_returns_not_implemented):

  • join_using_matches_same_rows_as_on, select_star_using_dedups_joined_column
  • natural_join_matches_on_all_shared_columns, select_star_natural_dedups_shared_columns
  • natural_join_without_common_columns_is_cross_product
  • cross_join_produces_cartesian_product, left_outer_join_using_preserves_unmatched_left
  • using_unknown_column_errors

Verification

  • cargo build / cargo test (CI exclude set) — 611 lib + all integration tests pass
  • cargo fmt --all --check, cargo clippy (no new warnings), cargo doc — clean
  • REPL smoke checks for USING (id shown once), NATURAL (k1,k2 once, matched on both), CROSS (full product) — all correct
  • Docs updated: supported-sql.md, sql-engine.md, roadmap.md, README.md, web docs

🤖 Generated with Claude Code

PR #99 shipped INNER/LEFT/RIGHT/FULL OUTER JOIN ... ON; the three
related shapes SQLite supports were still rejected as NotImplemented.
This wires all three through the existing nested-loop join driver.

Parser (src/sql/parser/select.rs):
- JoinClause.on: Expr → constraint: JoinConstraintKind (On/Using/Natural).
- USING (cols) is narrowed to a list of column names; NATURAL is carried
  as-is (it needs schemas the parser doesn't have); CROSS JOIN is
  rewritten to ON true at parse time.

Executor (src/sql/executor.rs):
- resolve_join_constraint lowers USING/NATURAL into the synthesized
  `left.col = right.col [AND …]` predicate, schema-aware: the left
  qualifier is picked per column so join chains resolve correctly, and
  NATURAL auto-discovers the shared column names (none ⇒ cross product,
  matching SQLite).
- SELECT * de-duplicates USING/NATURAL columns per the SQLite
  convention — the joined-on column shows once, taking the left copy.

Tests: 8 new executor tests (USING≡ON rows, SELECT* dedup for USING and
NATURAL, NATURAL multi-column AND, NATURAL-without-common-cols cross
product, CROSS cartesian product, LEFT OUTER USING, USING unknown-column
error), replacing the old "returns NotImplemented" test. Docs updated
(supported-sql, sql-engine, roadmap, README, web docs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
rust-sqlite Ready Ready Preview, Comment Jun 1, 2026 9:03pm

Request Review

@joaoh82 joaoh82 merged commit 47c8963 into main Jun 2, 2026
21 checks passed
@joaoh82 joaoh82 mentioned this pull request Jun 2, 2026
joaoh82 added a commit that referenced this pull request Jun 2, 2026
Bump every product manifest 0.11.0 → 0.12.0 and refresh Cargo.lock.

Headline change since 0.11.0: JOIN ... USING / NATURAL / CROSS support
(SQLR-5, #158). Backward-compatible for embedders — the public
Connection/Statement/Rows/Value API is unchanged.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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