Skip to main content

JoinOperator

Enum JoinOperator 

Source
pub enum JoinOperator<X: Extension = NoExt> {
    Inner {
        straight: bool,
        inner: bool,
        constraint: JoinConstraint<X>,
        meta: Meta,
    },
    LeftOuter {
        outer: bool,
        constraint: JoinConstraint<X>,
        meta: Meta,
    },
    RightOuter {
        outer: bool,
        constraint: JoinConstraint<X>,
        meta: Meta,
    },
    FullOuter {
        outer: bool,
        constraint: JoinConstraint<X>,
        meta: Meta,
    },
    AsOf {
        kind: AsOfJoinKind,
        constraint: JoinConstraint<X>,
        meta: Meta,
    },
    Cross {
        meta: Meta,
    },
    Positional {
        meta: Meta,
    },
    Semi {
        asof: bool,
        side: SemiAntiSide,
        constraint: JoinConstraint<X>,
        meta: Meta,
    },
    Anti {
        asof: bool,
        side: SemiAntiSide,
        constraint: JoinConstraint<X>,
        meta: Meta,
    },
    Apply {
        kind: ApplyKind,
        meta: Meta,
    },
}
Expand description

The SQL join operator forms represented by the AST.

Variants§

§

Inner

An [INNER] JOIN — keeps only row pairs that satisfy the constraint.

Fields

§straight: bool

MySQL STRAIGHT_JOIN: an inner join that additionally forces the optimizer to read the left table before the right. It is semantically a plain INNER JOIN, so it is the canonical inner-join shape carrying this surface tag (a join-order hint) rather than a new operator variant — mirroring how SetQuantifier::All preserves an explicit ALL. false is a bare [INNER] JOIN; only MySQL parses the true spelling (gated by JoinSyntax::straight_join).

§inner: bool

Whether the redundant INNER keyword was written (INNER JOIN vs a bare JOIN — the two are exact synonyms). A source-fidelity render replays it; a target re-spell and the redacted fingerprint drop it. Always false under straight (STRAIGHT_JOIN is its own keyword, never spelled INNER).

§constraint: JoinConstraint<X>

The join condition (ON/USING/NATURAL/none); see JoinConstraint.

§meta: Meta

Source location and node identity.

§

LeftOuter

A LEFT [OUTER] JOIN — keeps every left row, NULL-padding unmatched right columns.

Fields

§outer: bool

Whether the redundant OUTER keyword was written (LEFT OUTER JOIN vs a bare LEFT JOIN). Fidelity only, like Inner::inner.

§constraint: JoinConstraint<X>

The join condition (ON/USING/NATURAL/none); see JoinConstraint.

§meta: Meta

Source location and node identity.

§

RightOuter

A RIGHT [OUTER] JOIN — keeps every right row, NULL-padding unmatched left columns.

Fields

§outer: bool

Whether the redundant OUTER keyword was written (RIGHT OUTER JOIN).

§constraint: JoinConstraint<X>

The join condition (ON/USING/NATURAL/none); see JoinConstraint.

§meta: Meta

Source location and node identity.

§

FullOuter

A FULL [OUTER] JOIN — keeps all rows from both sides, NULL-padding non-matches.

Fields

§outer: bool

Whether the redundant OUTER keyword was written (FULL OUTER JOIN).

§constraint: JoinConstraint<X>

The join condition (ON/USING/NATURAL/none); see JoinConstraint.

§meta: Meta

Source location and node identity.

§

AsOf

DuckDB ASOF [INNER|LEFT|RIGHT|FULL [OUTER]] JOIN: an inexact-match temporal join pairing each left row with the nearest right row under the ON inequality. A new operator (nearest-match semantics), not a spelling of the side joins — DuckDB serializes it as an orthogonal ref_type: ASOF on top of the join_type side, mirrored here as kind. The engine parse-requires an ON/USING constraint (a bare ASOF JOIN is a syntax error), so the parser never builds JoinConstraint::None here; the inequality requirement itself is bind-time (ASOF JOIN … ON a = b parses, then fails DuckDB’s binder), so an equality constraint still parses. Gated by JoinSyntax::asof_join.

Fields

§kind: AsOfJoinKind

Which side the ASOF join keeps; see AsOfJoinKind.

§constraint: JoinConstraint<X>

The join condition (ON/USING/NATURAL/none); see JoinConstraint.

§meta: Meta

Source location and node identity.

§

Cross

A CROSS JOIN — the unconstrained Cartesian product.

Fields

§meta: Meta

Source location and node identity.

§

Positional

DuckDB POSITIONAL JOIN: pairs rows by position (first with first, …). Like Cross it never carries a constraint — the engine parse-rejects a trailing ON/USING and any side keyword (POSITIONAL LEFT JOIN is a syntax error) — so the variant has no constraint or kind field. Gated by JoinSyntax::positional_join.

Fields

§meta: Meta

Source location and node identity.

§

Semi

DuckDB [ASOF|NATURAL] SEMI JOIN: a semi-join — keeps each left row that has at least one right match, projecting left columns only. DuckDB serializes it as a join_type: SEMI (engine-verified on 1.5.4), mutually exclusive with the INNER/LEFT/RIGHT/FULL sides (LEFT SEMI JOIN is a syntax error), so it is a new operator rather than a side spelling. It composes only with the REGULAR, NATURAL (NATURAL SEMI JOIN, carried as JoinConstraint::Natural) and ASOF (ASOF SEMI JOIN, asof = true) ref-types — never a side, CROSS, or POSITIONAL. Like AsOf it parse-requires an ON/USING constraint (a bare SEMI JOIN is a syntax error) unless NATURAL supplies the match, so the parser never builds JoinConstraint::None here. ASOF and NATURAL never co-occur (both engine parse-rejected), so asof: true always carries an ON/USING constraint.

The side axis records the Spark/Hive/Databricks sided spelling — LEFT SEMI JOIN / RIGHT SEMI JOIN — as one operator with DuckDB’s side-less SEMI JOIN rather than a separate variant (the AsOfJoinKind/ApplyKind axis precedent): all three are the same semi-join, differing only in whether an explicit side keyword is written and which side’s rows are tested. The two spellings come from different engine families and are gated apart — DuckDB’s side-less form by JoinSyntax::semi_anti_join, the sided form by JoinSyntax::sided_semi_anti_join (DuckDB engine-parse-rejects LEFT SEMI JOIN). The two axes are mutually exclusive: SemiAntiSide::Left/Right never carry the DuckDB-only ASOF/NATURAL compositions, so a sided operator always has asof: false and an ON/USING constraint (Spark requires the qualifier).

Fields

§asof: bool

Whether the asof form was present in the source.

§side: SemiAntiSide

Which sided spelling (LEFT/RIGHT/side-less); see SemiAntiSide.

§constraint: JoinConstraint<X>

The join condition (ON/USING/NATURAL/none); see JoinConstraint.

§meta: Meta

Source location and node identity.

§

Anti

DuckDB [ASOF|NATURAL] ANTI JOIN / Spark [LEFT|RIGHT] ANTI JOIN: an anti-join — keeps each left row with no right match. The Semi counterpart: identical grammar (DuckDB serializes join_type: ANTI) with the opposite membership test, so see Semi for the composition, constraint, asof-flag, and side rules and the two gates.

Fields

§asof: bool

Whether the asof form was present in the source.

§side: SemiAntiSide

Which sided spelling (LEFT/RIGHT/side-less); see SemiAntiSide.

§constraint: JoinConstraint<X>

The join condition (ON/USING/NATURAL/none); see JoinConstraint.

§meta: Meta

Source location and node identity.

§

Apply

MSSQL CROSS APPLY / OUTER APPLY: an implicitly-correlated (lateral) join whose right operand — a derived table (SELECT …) or a table-valued function call — may reference columns of the left source. Like Cross it never carries an ON/USING constraint (the correlation is positional, in the right operand’s own references), so the variant holds no constraint. The kind axis is the CROSS/OUTER flavour — inner-style vs left-style row preservation — mirroring how AsOf records its side on a kind rather than splitting into per-spelling variants: CROSS APPLY and OUTER APPLY are one grammar production differing only by that keyword. Gated by JoinSyntax::apply_join.

Fields

§kind: ApplyKind

The CROSS/OUTER apply flavour; see ApplyKind.

§meta: Meta

Source location and node identity.

Trait Implementations§

Source§

impl<X: Clone + Extension> Clone for JoinOperator<X>

Source§

fn clone(&self) -> JoinOperator<X>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<X: Debug + Extension> Debug for JoinOperator<X>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de, X> Deserialize<'de> for JoinOperator<X>
where X: Deserialize<'de> + Extension,

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<X: Eq + Extension> Eq for JoinOperator<X>

Source§

impl<X: Hash + Extension> Hash for JoinOperator<X>

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<X: PartialEq + Extension> PartialEq for JoinOperator<X>

Source§

fn eq(&self, other: &JoinOperator<X>) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl<X: Extension + Render> Render for JoinOperator<X>

Source§

fn render(&self, ctx: &RenderCtx<'_>, f: &mut Formatter<'_>) -> Result

Return the render for this value.
Source§

fn operand_binding_power(&self) -> Option<BindingPower>

The binding power this node contributes when it appears as an operand, or None (the default) for a self-delimiting node — an atom, call, or constructor — that never needs parentheses. Read more
Source§

impl<X> Serialize for JoinOperator<X>
where X: Serialize + Extension,

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<X: Extension> Spanned for JoinOperator<X>

Source§

fn span(&self) -> Span

Return the span for this value.
Source§

impl<X: PartialEq + Extension> StructuralPartialEq for JoinOperator<X>

Auto Trait Implementations§

§

impl<X> Freeze for JoinOperator<X>
where X: Freeze,

§

impl<X> RefUnwindSafe for JoinOperator<X>
where X: RefUnwindSafe,

§

impl<X> Send for JoinOperator<X>
where X: Send,

§

impl<X> Sync for JoinOperator<X>
where X: Sync,

§

impl<X> Unpin for JoinOperator<X>
where X: Unpin,

§

impl<X> UnsafeUnpin for JoinOperator<X>
where X: UnsafeUnpin,

§

impl<X> UnwindSafe for JoinOperator<X>
where X: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> DynAstExt for T
where T: Extension + Render + 'static,

Source§

fn as_any(&self) -> &(dyn Any + 'static)

Erase to &dyn Any for downcasting a node back to its concrete type.
Source§

fn dyn_clone(&self) -> Box<dyn DynAstExt>

Clone into a fresh box — the object-safe stand-in for Clone (whose Self-returning signature cannot go through a vtable).
Source§

fn dyn_eq(&self, other: &dyn DynAstExt) -> bool

Structural equality against another erased node — the object-safe stand-in for PartialEq (whose &Self argument cannot go through a vtable). Equal iff other holds the same concrete type and that type deems the values equal; differently-typed nodes are never equal.
Source§

fn dyn_hash(&self, state: &mut dyn Hasher)

Feed this node’s hash into an erased hasher — the object-safe stand-in for Hash::hash (whose generic H: Hasher cannot go through a vtable).
Source§

impl<T> Extension for T
where T: Clone + Debug + Eq + Hash + Spanned,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> RenderExt for T
where T: Render,

Source§

fn displayed<'a>(&'a self, ctx: &'a RenderCtx<'a>) -> Displayed<'a, T>

Pair this node with an explicit canonical RenderCtx so format!, to_string, and {} render it. This is the canonical path: the ctx’s resolver and source must match the node’s parse.
Source§

fn debug_sql<'a>(&'a self, resolver: &'a dyn Resolver) -> DebugSql<'a, Self>
where Self: Sized,

Render this node for debugging against an explicitly-supplied resolver (the debug-SQL mitigation), returning a Display adapter. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.