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}