feat: add LateralJoinRel support (inference + builders) - #228
Merged
nielspardon merged 1 commit intoJul 29, 2026
Merged
Conversation
nielspardon
marked this pull request as draft
July 20, 2026 11:42
This was referenced Jul 20, 2026
Closed
nielspardon
marked this pull request as ready for review
July 20, 2026 14:22
nielspardon
force-pushed
the
feat/lateral-join-inference
branch
from
July 20, 2026 14:26
37cab51 to
3f5afe9
Compare
nielspardon
requested review from
andrew-coleman,
benbellick,
bestbeforetoday,
tokoko and
vbarua
July 21, 2026 06:51
nielspardon
force-pushed
the
feat/lateral-join-inference
branch
2 times, most recently
from
July 27, 2026 15:54
68922fd to
d926068
Compare
nielspardon
marked this pull request as draft
July 27, 2026 15:56
nielspardon
force-pushed
the
feat/lateral-join-inference
branch
from
July 29, 2026 11:10
d926068 to
d802db1
Compare
nielspardon
marked this pull request as ready for review
July 29, 2026 11:14
Substrait v0.96.0 (substrait-io#205) adds LateralJoinRel, whose right (dependent) input is evaluated once per left row and references the current left row via OuterReference.rel_reference pointing to the join's RelCommon.rel_anchor. Inference (type_inference.py): - infer_rel_schema handles the "lateral_join" rel type; output columns follow the same per-join-type shapes as a regular JoinRel (INNER/LEFT -> left+right, LEFT_SEMI/LEFT_ANTI -> left only, LEFT_MARK -> +mark). - id-based outer references resolve through the plan-wide _AnchorScope added in substrait-io#239. A lateral join's anchor denotes its *left* row, so _AnchorScope resolves it against the left input's schema. While the right input is inferred the left schema is bound to the anchor via _outer_anchor_binding (a scoped _AnchorScope chained to any enclosing one, so nested lateral joins compose); this also lets the builder infer the right input before the join relation is assembled. No separate outer_anchors map -- id-based resolution is unified on _AnchorScope. Builders (handle-based correlation): - builders.plan.lateral_join(left, right, type, ...): right is a function of a LateralInput handle to the left; handle.column(...) emits the id-based outer reference. The builder allocates a rel_anchor, infers the right input under _outer_anchor_binding, and assembles via _plan_from so shared subtrees propagate. - DataFrame.lateral_join(right, how, *, on, post_filter) + LateralLeft.col(): the DataFrame-layer handle. Capturing the handle avoids nesting-depth bookkeeping and makes referencing outside a lateral join impossible. - rel_anchor allocation: next_rel_anchor() is unique within a build; fresh_rel_anchors() resets numbering per materialization. DataFrame._finalize builds under fresh_rel_anchors, then normalizes any correlated-subquery steps_out to id-based via to_id_based_outer_references (substrait-io#239); its anchor pre-scan keeps DataFrame-correlation anchors clear of the lateral-join ones. Closes substrait-io#205.
nielspardon
force-pushed
the
feat/lateral-join-inference
branch
from
July 29, 2026 12:11
d802db1 to
06d8230
Compare
andrew-coleman
approved these changes
Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds LateralJoinRel support (Substrait v0.96.0, #205) to schema inference and the builder / DataFrame layers. A lateral join evaluates its right (dependent) input once per left row; the right input references the current left row via
OuterReference.rel_referencepointing at the join'sRelCommon.rel_anchor.Rebased onto
mainand refactored to build on the id-based outer-reference resolution merged in #239, so there is now a single resolution mechanism (_AnchorScope) — this PR no longer adds its ownouter_anchorsmap.Inference (
type_inference.py)infer_rel_schemahandles thelateral_joinrel type; output columns follow the same per-join-type shapes as a regularJoinRel(INNER/LEFT → left+right, LEFT_SEMI/LEFT_ANTI → left only, LEFT_MARK → +mark)._AnchorScope. A lateral-join anchor denotes the left row, so_AnchorScoperesolves it against the left input's schema (one small special case). While the right input is inferred, the left schema is bound to the anchor via a new_outer_anchor_bindingcontext manager (a scoped_AnchorScopechained to any enclosing one), so:Builders
builders.plan.lateral_join(left, right, type, ...):rightis a function of aLateralInputhandle to the left;handle.column(...)emits the id-based outer reference. The builder allocates arel_anchor, infers the right input under_outer_anchor_binding, and assembles via_plan_fromso shared subtrees (CTEs) propagate.DataFrame.lateral_join(right, how, *, on, post_filter)+LateralLeft.col(): the DataFrame-layer handle. Capturing the handle avoids nesting-depth bookkeeping and makes referencing outside a lateral join impossible. Only INNER and left-oriented join types are valid.next_rel_anchor()is unique within a build;fresh_rel_anchors()resets numbering per materialization.DataFrame._finalizebuilds underfresh_rel_anchors, then normalizes any correlated-subquerysteps_outto id-based viato_id_based_outer_references(feat!: id-based outer-reference resolution (Substrait v0.89.0) #239) — whose anchor pre-scan keeps DataFrame-correlation anchors clear of the lateral-join ones.Testing
rel_referenceresolving against the left row, and the unknown-anchor error.plan.lateral_joinandDataFrame.lateral_join(correlated right input, join types, post-filter).ruff check+ruff format --checkclean.Closes #205.
🤖 Generated with AI