Repository navigation
Join implementation
Implementation reference checked against f5e786f. Fundamental explanations remain in docs/arch.
compiler.cpp composes a join program with
jt_dispatch and jt_materialize. Init, process, stream probe, semi/anti and
outer finalization, and destruction are operations dispatched through it;
they are not a public table of independently bound function pointers.
CompileJoinHash exports jt_hash_left and jt_hash_right for repartitioning.
gen.cpp and
join_gen.cpp provide key/residual/materialization
code; generic kernels are under qdb/kernel/join.
TInnerJoinProcessor and TCrossJoinProcessor live in
join_exec.cpp.
Retained rows use packed (batch_index << 32) | row_index identifiers.
kNullRowId = -1 represents the absent side. A transient stream batch uses a
batch-index sentinel only while its residual and output are being processed.
PairBuffer.Data[2*i] and [2*i+1] hold the left/right row identifiers. Kernel
code owns capacity growth; the processor drains pending pairs before reusing
it. Row-store bases are refreshed on calls because growing their backing
vectors can invalidate a previous base pointer.
The shared hash-table ABI uses dense buffers for bucket row count, capacity, and row-id storage. This is distinct from aggregation's typed reducer states. String keys own their persistent bytes through the common arena lifecycle.
EJoinStreamMode records symmetric, left-against-right, or right-against-left
streaming. Estimates can select build-first inner execution at the current
10:1 asymmetry threshold. Outer joins retain both sides and finalize unmatched
rows; residual rejection does not mark a row matched.
Runtime kernels accept Inner, Left, Right, Full, LeftSemi, and LeftAnti.
RightSemi/RightAnti enum values are not directly accepted by CompileJoin.
String and nullable keys and outer residuals are supported; the old exclusions
are obsolete. Join lifecycle and dispatch signatures from earlier revisions
are retained only as historical notes in
the migration archive.