Skip to content

Disjunction Strategy C (backend): native union primitive in core-relations - #4

Closed
oflatt-claude wants to merge 1 commit into
mainfrom
disjunction-core-relations-union
Closed

Disjunction Strategy C (backend): native union primitive in core-relations#4
oflatt-claude wants to merge 1 commit into
mainfrom
disjunction-core-relations-union

Conversation

@oflatt-claude

Copy link
Copy Markdown
Owner

Part of exploring Strategy C (native backend union) for OR disjunction. Adds a union-of-subqueries primitive to the core-relations free-join engine.

What's here

RuleSetBuilder::add_union(output_arity, branches) — each branch is a sub-query binding a common set of output columns; branch outputs are inserted into a fresh all-key ephemeral table that deduplicates them; downstream rules scan that table to consume the union. Unit-tested (tests::union_disjunction, serial + 32-thread): R(x) := A(x) OR B(x) yields the deduplicated union and fires the downstream action exactly once per distinct tuple.

  • core-relations/src/query.rsadd_union
  • core-relations/src/tests.rsunion_disjunction
  • docs/union-primitive.md — API + how it relates to Strategies B/C + restrictions

Tests: cargo test -p egglog-core-relations → 51 pass (incl. the new test); clippy clean.

Honest status / the B-vs-C distinction

This primitive implements the materialized form of the union (the ephemeral all-key table is the materialization), one level below egglog's rule layer. Observably it matches Strategy B (PR for materialized union), not a fused streaming node.

The genuinely-distinct Strategy C — a single-pass JoinStage::Union that streams branch tuples into the continuation without materializing — was intentionally scoped out: it requires threading nested sub-plan execution through the recursive run_plan / ActionBuffer machinery in core-relations/src/free_join/execute.rs, plus egglog→bridge plumbing to carry OR into the engine. That is a substantially larger change and is not wired to egglog here.

This PR is a draft / foundation, not an end-to-end egglog feature: it is not yet connected to egglog's OR surface syntax. The working end-to-end native implementation of OR is the materialized-union PR (Strategy B).

🤖 Generated with Claude Code

Add `RuleSetBuilder::add_union(output_arity, branches)` to the free-join engine:
each branch is a sub-query that binds a common set of output columns; the branch
outputs are inserted into a fresh ephemeral all-key table, which deduplicates
them. Downstream rules scan that table to consume the union. This is a backend
building block for disjunction (`OR`).

It implements the materialized form of the union (Strategy B, one level below
egglog's rule layer); the fully-fused single-pass `JoinStage::Union` (Strategy C)
is documented as future work. Naive/whole-table evaluation.

- core-relations/src/query.rs: `add_union`
- core-relations/src/tests.rs: `union_disjunction` unit test (serial + parallel)
- docs/union-primitive.md: API, strategy relationship, restrictions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@oflatt-claude

Copy link
Copy Markdown
Owner Author

Superseded by #5, which wires a planner-level union materialization end-to-end through egglog. This standalone core-relations primitive was an isolated exploration and isn't connected to the OR surface syntax.

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