Skip to content

feat(sql): support streaming IN subqueries with mark joins - #2514

Open
ksushant6566 wants to merge 1 commit into
getdozer:mainfrom
ksushant6566:feat/1659-streaming-in-subquery
Open

ksushant6566 wants to merge 1 commit into
getdozer:mainfrom
ksushant6566:feat/1659-streaming-in-subquery

Conversation

@ksushant6566

@ksushant6566 ksushant6566 commented Sep 9, 2026

Copy link
Copy Markdown

Adds the remaining dynamic IN (SELECT ...) case from #1659 through a two-input mark join in the streaming DAG. An inner insert can admit already-seen outer rows; deleting the final matching inner value retracts them. Inner duplicates preserve membership without multiplying outer rows.

SELECT * FROM orders
WHERE customer_id IN (
  SELECT customer_id FROM customers WHERE active = 1
);

The join retains outer-row multiplicity and reference-counts inner values. It applies complete update/batch deltas before emitting nullable membership changes. Same-type keys use a hash index; cross-type values use Dozer's SQL equality conversions, rejecting incomparable non-null operands explicitly. The normal selection stage evaluates compound predicates and removes internal mark fields before projection or aggregation, so SELECT * retains its original schema.

The planner handles multiple and nested IN/NOT IN predicates, scalar left operands, CTEs and parenthesized UNION branches. Supporting nullable membership also required correcting AND/OR three-valued evaluation and nullable metadata. Qualified column resolution now checks the qualifier even when only one field name matches, so a correlated reference cannot silently bind to an inner column. Query-local CTE names are restored at the query boundary instead of leaking into sibling subqueries.

Scope: uncorrelated, single-column subqueries. TTL-bearing inputs are rejected before any state mutation because existing TTL index eviction emits no delete events; silently expiring membership would leave downstream rows stale. Existing ORDER BY/LIMIT restrictions remain. The prior static-list IN implementation is retained.

Demo

Watch the approximately 34-second MP4, or download the original terminal recording.

Actual streaming SQL inputs, emitted changes and result rows

This executes the actual parser, schema validation, generated DAG and processors with in-memory source events. It shows late inner matches, duplicate suppression, atomic key updates and retractions. Run cargo test -p dozer-sql --no-default-features in_subquery_demo -- --nocapture to reproduce it. Details are in dozer-tests/in_subquery/README.md.

Validation

  • On clean upstream 8b0b4cc, the new parser/DAG regression fails with UnsupportedExpression(InSubquery ...).
  • cargo test --locked -p dozer-sql -p dozer-sql-expression --no-default-features: 238 SQL tests and 27 expression tests pass; one pre-existing SQL test remains ignored. Doc tests pass.
  • cargo check --locked -p dozer-cli --no-default-features passes with Rust 1.78, including the full CLI dependency graph.
  • 24 new SQL-to-DAG cases cover both arrival orders, all outer WHERE update transitions, inner key updates, identical updates, duplicate/NULL batches, empty-set and literal-NULL semantics, compound negation, numeric/string conversion, incompatible comparisons, nested/parenthesized queries, CTE shadowing, shared sources and TTL rejection without state mutation. A deterministic oracle checks 360 successive stream changes.
  • Independent agent review supplied additional regressions, reproduced the NULL/qualifier/scope failures and verified their fixes.
  • cargo clippy --locked -p dozer-sql -p dozer-sql-expression --no-default-features --all-targets succeeds with warnings, including the existing large error types. Rustfmt and git diff --check pass.

AI assistance: implemented and tested with Codex.

Fixes #1659
/claim #1659

@CLAassistant

CLAassistant commented Sep 9, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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.

Support for IN clause in streaming SQL

2 participants