Skip to main content

oxisql_parse/
plan.rs

1//! Logical plan type definitions for OxiSQL.
2//!
3//! This module defines the AST-level relational algebra types produced by the
4//! planner.  All types are re-exported from the crate root.
5
6use crate::optimizer::JoinAlgoHint;
7
8// ── Logical Plan ─────────────────────────────────────────────────────────────
9
10/// AST-level logical query plan produced by [`crate::plan_statement`].
11///
12/// Each variant represents a relational algebra operator.  The tree is
13/// built bottom-up: leaf nodes (e.g. `Scan`) are wrapped by operator nodes
14/// (`Filter`, `Project`, …) as query features are encountered.
15#[derive(Debug, Clone)]
16pub enum LogicalPlan {
17    /// Table scan.  `alias` is the `AS` alias, if any.
18    Scan {
19        /// The fully-qualified table name as it appears in the query.
20        table: String,
21        /// Optional alias (`AS x`).
22        alias: Option<String>,
23        /// Optional row-count cap injected by the optimizer's limit push-through
24        /// pass.  `None` means the scan is unbounded.
25        limit: Option<usize>,
26    },
27    /// Row filter (`WHERE`).
28    Filter {
29        /// The plan being filtered.
30        input: Box<LogicalPlan>,
31        /// The `WHERE` expression rendered as a string.
32        predicate: String,
33    },
34    /// Column projection (`SELECT col1, col2, …`).
35    Project {
36        /// The plan whose rows are projected.
37        input: Box<LogicalPlan>,
38        /// The projected column expressions as strings.
39        columns: Vec<String>,
40    },
41    /// Binary join of two inputs.
42    Join {
43        /// Left input.
44        left: Box<LogicalPlan>,
45        /// Right input.
46        right: Box<LogicalPlan>,
47        /// The `ON` expression rendered as a string.
48        on: String,
49        /// The join type (INNER, LEFT, RIGHT, FULL, CROSS).
50        join_type: JoinType,
51        /// Algorithm hint set by [`crate::optimizer::JoinAlgorithmPass`].
52        algo_hint: Option<JoinAlgoHint>,
53    },
54    /// Aggregation (`GROUP BY` / aggregate functions).
55    Aggregate {
56        /// The plan whose rows are aggregated.
57        input: Box<LogicalPlan>,
58        /// `GROUP BY` expressions rendered as strings.
59        group_by: Vec<String>,
60        /// Aggregate function expressions rendered as strings.
61        aggregates: Vec<String>,
62    },
63    /// Row ordering (`ORDER BY`).
64    Sort {
65        /// The plan whose rows are sorted.
66        input: Box<LogicalPlan>,
67        /// The sort key expressions.
68        order_by: Vec<SortExpr>,
69    },
70    /// Row count / offset restriction (`LIMIT … OFFSET …`).
71    Limit {
72        /// The plan being limited.
73        input: Box<LogicalPlan>,
74        /// Maximum number of rows, if specified.
75        count: Option<u64>,
76        /// Number of rows to skip, if specified.
77        offset: Option<u64>,
78    },
79    /// Constant row source (`INSERT … VALUES …`).
80    Values {
81        /// Column names from the INSERT column list.
82        columns: Vec<String>,
83        /// Number of value rows.
84        rows: usize,
85    },
86    /// Placeholder for statements that produce no relational plan.
87    Empty,
88    /// A SQL set operation: `UNION`, `INTERSECT`, or `EXCEPT`.
89    SetOp {
90        /// The set-operation kind.
91        op: SetOpType,
92        /// `true` for `UNION ALL` / `INTERSECT ALL` / `EXCEPT ALL`.
93        all: bool,
94        /// Left input plan.
95        left: Box<LogicalPlan>,
96        /// Right input plan.
97        right: Box<LogicalPlan>,
98    },
99    /// A CTE definition node.
100    ///
101    /// The `query` field is the plan for the CTE's own defining body (`AS (...)`).
102    /// The query that *uses* this CTE is built by the surrounding planner; this
103    /// variant retains only the CTE definition itself.
104    Cte {
105        /// The CTE name as introduced before the `AS` keyword.
106        name: String,
107        /// Plan for the CTE-defining sub-query (`AS ( ... )`).
108        query: Box<LogicalPlan>,
109        /// `true` when the entire `WITH` clause was `WITH RECURSIVE`.
110        recursive: bool,
111    },
112    /// Reference to a previously defined CTE by name.
113    CteRef {
114        /// The CTE name being referenced.
115        name: String,
116    },
117    /// Window-function layer sitting over a base plan.
118    Window {
119        /// The input plan over which windows are computed.
120        input: Box<LogicalPlan>,
121        /// The window functions defined in the SELECT projection.
122        functions: Vec<WindowFunctionDef>,
123    },
124    /// A scalar subquery that returns a single value (used in SELECT or WHERE).
125    Subquery {
126        /// The inner query plan.
127        query: Box<LogicalPlan>,
128        /// Optional alias applied to the subquery expression.
129        alias: Option<String>,
130    },
131    /// `EXISTS (subquery)` — used in WHERE predicates.
132    Exists {
133        /// The inner subquery plan.
134        subquery: Box<LogicalPlan>,
135        /// `true` when the expression is `NOT EXISTS`.
136        negated: bool,
137    },
138    /// `expr IN (subquery)` — used in WHERE predicates.
139    InSubquery {
140        /// The expression being tested (e.g. `"col1"`).
141        expr: String,
142        /// The inner subquery plan.
143        subquery: Box<LogicalPlan>,
144        /// `true` when the expression is `NOT IN`.
145        negated: bool,
146    },
147    /// A plan node that materializes named expression bindings for CSE.
148    ///
149    /// Each `(alias, expr_string)` pair in `bindings` declares a named
150    /// intermediate value that downstream nodes can reference by alias.
151    /// A `Compute` node is an optimization artifact introduced by the
152    /// common-subexpression-elimination pass; it adds zero compute overhead
153    /// and is transparent to most plan traversals.
154    Compute {
155        /// The input plan whose output rows are annotated with bindings.
156        input: Box<LogicalPlan>,
157        /// Named expression bindings: `(alias, expr_string)` pairs.
158        bindings: Vec<(String, String)>,
159    },
160}
161
162/// Set-operation kind.
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub enum SetOpType {
165    /// `UNION`
166    Union,
167    /// `INTERSECT`
168    Intersect,
169    /// `EXCEPT` (or `MINUS`)
170    Except,
171}
172
173/// A single window-function definition extracted from a SELECT projection.
174#[derive(Debug, Clone, PartialEq)]
175pub struct WindowFunctionDef {
176    /// The function name (e.g. `ROW_NUMBER`, `RANK`).
177    pub name: String,
178    /// The function arguments rendered as strings.
179    pub args: Vec<String>,
180    /// `PARTITION BY` expressions rendered as strings.
181    pub partition_by: Vec<String>,
182    /// `ORDER BY` keys.
183    pub order_by: Vec<SortExpr>,
184    /// The alias applied to the expression in the projection.
185    pub alias: String,
186}
187
188/// Join algorithm / semantic type.
189#[derive(Debug, Clone, PartialEq, Eq)]
190pub enum JoinType {
191    /// `INNER JOIN` — only matching rows.
192    Inner,
193    /// `LEFT [OUTER] JOIN` — all rows from the left side.
194    Left,
195    /// `RIGHT [OUTER] JOIN` — all rows from the right side.
196    Right,
197    /// `FULL [OUTER] JOIN` — all rows from both sides.
198    Full,
199    /// `CROSS JOIN` — cartesian product.
200    Cross,
201    /// Semi-join: return each left row that has at least one matching right row.
202    /// Used internally by the decorrelation pass (e.g. `EXISTS` rewrites).
203    LeftSemi,
204    /// Anti-join: return each left row that has *no* matching right row.
205    /// Used internally by the decorrelation pass (e.g. `NOT EXISTS` rewrites).
206    LeftAnti,
207}
208
209/// A single `ORDER BY` sort key.
210#[derive(Debug, Clone, PartialEq)]
211pub struct SortExpr {
212    /// The column / expression being sorted.
213    pub column: String,
214    /// `true` for ascending (`ASC`), `false` for descending (`DESC`).
215    pub ascending: bool,
216}