Skip to main content

aegis_query/
planner.rs

1//! Aegis Query Planner
2//!
3//! Transforms analyzed SQL statements into optimized query plans.
4//! Implements cost-based optimization with rule-based transformations.
5//!
6//! Key Features:
7//! - Logical plan generation from AST
8//! - Cost-based join ordering
9//! - Predicate pushdown optimization
10//! - Index selection
11//!
12//! @version 0.1.0
13//! @author AutomataNexus Development Team
14
15use crate::ast::{
16    BinaryOperator, Expression, FromClause, JoinClause, JoinType, SelectColumn, SelectStatement,
17    SetOperationType, Statement, TableReference,
18};
19use aegis_common::DataType;
20use std::collections::HashMap;
21use std::sync::Arc;
22use thiserror::Error;
23
24// =============================================================================
25// Error Types
26// =============================================================================
27
28#[derive(Debug, Error)]
29pub enum PlannerError {
30    #[error("Table not found: {0}")]
31    TableNotFound(String),
32
33    #[error("Column not found: {0}")]
34    ColumnNotFound(String),
35
36    #[error("Unsupported operation: {0}")]
37    UnsupportedOperation(String),
38
39    #[error("Internal planner error: {0}")]
40    Internal(String),
41}
42
43pub type PlannerResult<T> = Result<T, PlannerError>;
44
45// =============================================================================
46// Query Plan
47// =============================================================================
48
49/// A complete query plan ready for execution.
50#[derive(Debug, Clone)]
51pub struct QueryPlan {
52    pub root: PlanNode,
53    pub estimated_cost: f64,
54    pub estimated_rows: u64,
55}
56
57/// A node in the query plan tree.
58#[derive(Debug, Clone)]
59pub enum PlanNode {
60    Scan(ScanNode),
61    Filter(FilterNode),
62    Project(ProjectNode),
63    Join(JoinNode),
64    Aggregate(AggregateNode),
65    Sort(SortNode),
66    Limit(LimitNode),
67    Empty,
68    // DDL nodes
69    CreateTable(CreateTableNode),
70    DropTable(DropTableNode),
71    AlterTable(AlterTableNode),
72    CreateIndex(CreateIndexNode),
73    DropIndex(DropIndexNode),
74    // DML nodes
75    Insert(InsertNode),
76    Update(UpdateNode),
77    Delete(DeleteNode),
78    // Set operations
79    SetOperation(SetOperationNode),
80    // Transaction control
81    BeginTransaction,
82    CommitTransaction,
83    RollbackTransaction,
84}
85
86/// Set operation node (UNION, INTERSECT, EXCEPT).
87#[derive(Debug, Clone)]
88pub struct SetOperationNode {
89    pub op: SetOperationType,
90    pub left: Box<PlanNode>,
91    pub right: Box<PlanNode>,
92}
93
94// =============================================================================
95// Plan Node Types
96// =============================================================================
97
98/// Table scan operation.
99#[derive(Debug, Clone)]
100pub struct ScanNode {
101    pub table_name: String,
102    pub alias: Option<String>,
103    pub columns: Vec<String>,
104    pub index_scan: Option<IndexScan>,
105}
106
107/// Index scan specification.
108#[derive(Debug, Clone)]
109pub struct IndexScan {
110    pub index_name: String,
111    pub key_range: KeyRange,
112}
113
114/// Key range for index scans.
115#[derive(Debug, Clone)]
116pub struct KeyRange {
117    pub start: Option<PlanExpression>,
118    pub start_inclusive: bool,
119    pub end: Option<PlanExpression>,
120    pub end_inclusive: bool,
121}
122
123/// Filter operation.
124#[derive(Debug, Clone)]
125pub struct FilterNode {
126    pub input: Box<PlanNode>,
127    pub predicate: PlanExpression,
128}
129
130/// Projection operation.
131#[derive(Debug, Clone)]
132pub struct ProjectNode {
133    pub input: Box<PlanNode>,
134    pub expressions: Vec<ProjectionExpr>,
135}
136
137/// A projection expression with optional alias.
138#[derive(Debug, Clone)]
139pub struct ProjectionExpr {
140    pub expr: PlanExpression,
141    pub alias: Option<String>,
142}
143
144/// Join operation.
145#[derive(Debug, Clone)]
146pub struct JoinNode {
147    pub left: Box<PlanNode>,
148    pub right: Box<PlanNode>,
149    pub join_type: PlanJoinType,
150    pub condition: Option<PlanExpression>,
151    pub strategy: JoinStrategy,
152}
153
154/// Join type in plan.
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub enum PlanJoinType {
157    Inner,
158    Left,
159    Right,
160    Full,
161    Cross,
162}
163
164/// Physical join strategy.
165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166pub enum JoinStrategy {
167    NestedLoop,
168    HashJoin,
169    MergeJoin,
170}
171
172/// Aggregation operation.
173#[derive(Debug, Clone)]
174pub struct AggregateNode {
175    pub input: Box<PlanNode>,
176    pub group_by: Vec<PlanExpression>,
177    pub aggregates: Vec<AggregateExpr>,
178}
179
180/// Aggregate expression.
181#[derive(Debug, Clone)]
182pub struct AggregateExpr {
183    pub function: AggregateFunction,
184    pub argument: Option<PlanExpression>,
185    pub distinct: bool,
186    pub alias: Option<String>,
187}
188
189/// Aggregate functions.
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum AggregateFunction {
192    Count,
193    Sum,
194    Avg,
195    Min,
196    Max,
197}
198
199/// Sort operation.
200#[derive(Debug, Clone)]
201pub struct SortNode {
202    pub input: Box<PlanNode>,
203    pub order_by: Vec<SortKey>,
204}
205
206/// Sort key specification.
207#[derive(Debug, Clone)]
208pub struct SortKey {
209    pub expr: PlanExpression,
210    pub ascending: bool,
211    pub nulls_first: bool,
212}
213
214/// Limit operation.
215#[derive(Debug, Clone)]
216pub struct LimitNode {
217    pub input: Box<PlanNode>,
218    pub limit: Option<u64>,
219    pub offset: Option<u64>,
220}
221
222// =============================================================================
223// DDL Plan Nodes
224// =============================================================================
225
226/// CREATE TABLE operation.
227#[derive(Debug, Clone)]
228pub struct CreateTableNode {
229    pub table_name: String,
230    pub columns: Vec<CreateColumnDef>,
231    pub constraints: Vec<CreateTableConstraint>,
232    pub if_not_exists: bool,
233}
234
235/// Column definition for CREATE TABLE.
236#[derive(Debug, Clone)]
237pub struct CreateColumnDef {
238    pub name: String,
239    pub data_type: DataType,
240    pub nullable: bool,
241    pub default: Option<PlanExpression>,
242    pub primary_key: bool,
243    pub unique: bool,
244}
245
246/// Table constraint for CREATE TABLE.
247#[derive(Debug, Clone)]
248pub enum CreateTableConstraint {
249    PrimaryKey {
250        columns: Vec<String>,
251    },
252    Unique {
253        columns: Vec<String>,
254    },
255    ForeignKey {
256        columns: Vec<String>,
257        ref_table: String,
258        ref_columns: Vec<String>,
259    },
260    Check {
261        expression: PlanExpression,
262    },
263}
264
265/// DROP TABLE operation.
266#[derive(Debug, Clone)]
267pub struct DropTableNode {
268    pub table_name: String,
269    pub if_exists: bool,
270}
271
272/// ALTER TABLE operation.
273#[derive(Debug, Clone)]
274pub struct AlterTableNode {
275    pub table_name: String,
276    pub operations: Vec<PlanAlterOperation>,
277}
278
279/// ALTER TABLE operation type.
280#[derive(Debug, Clone)]
281pub enum PlanAlterOperation {
282    AddColumn(CreateColumnDef),
283    DropColumn {
284        name: String,
285        if_exists: bool,
286    },
287    RenameColumn {
288        old_name: String,
289        new_name: String,
290    },
291    AlterColumn {
292        name: String,
293        data_type: Option<DataType>,
294        set_not_null: Option<bool>,
295        set_default: Option<Option<PlanExpression>>,
296    },
297    RenameTable {
298        new_name: String,
299    },
300    AddConstraint(CreateTableConstraint),
301    DropConstraint {
302        name: String,
303    },
304}
305
306/// CREATE INDEX operation.
307#[derive(Debug, Clone)]
308pub struct CreateIndexNode {
309    pub index_name: String,
310    pub table_name: String,
311    pub columns: Vec<String>,
312    pub unique: bool,
313    pub if_not_exists: bool,
314}
315
316/// DROP INDEX operation.
317#[derive(Debug, Clone)]
318pub struct DropIndexNode {
319    pub index_name: String,
320    pub if_exists: bool,
321}
322
323// =============================================================================
324// DML Plan Nodes
325// =============================================================================
326
327/// Source for INSERT data in a query plan.
328#[derive(Debug, Clone)]
329pub enum InsertPlanSource {
330    /// Direct values (INSERT INTO ... VALUES ...)
331    Values(Vec<Vec<PlanExpression>>),
332    /// Subquery (INSERT INTO ... SELECT ...)
333    Query(Box<PlanNode>),
334}
335
336/// INSERT operation.
337#[derive(Debug, Clone)]
338pub struct InsertNode {
339    pub table_name: String,
340    pub columns: Vec<String>,
341    pub source: InsertPlanSource,
342}
343
344/// UPDATE operation.
345#[derive(Debug, Clone)]
346pub struct UpdateNode {
347    pub table_name: String,
348    pub assignments: Vec<(String, PlanExpression)>,
349    pub where_clause: Option<PlanExpression>,
350}
351
352/// DELETE operation.
353#[derive(Debug, Clone)]
354pub struct DeleteNode {
355    pub table_name: String,
356    pub where_clause: Option<PlanExpression>,
357}
358
359// =============================================================================
360// Plan Expressions
361// =============================================================================
362
363/// Expression in a query plan.
364#[derive(Debug, Clone)]
365pub enum PlanExpression {
366    Column {
367        table: Option<String>,
368        name: String,
369        data_type: DataType,
370    },
371    Literal(PlanLiteral),
372    BinaryOp {
373        left: Box<PlanExpression>,
374        op: PlanBinaryOp,
375        right: Box<PlanExpression>,
376    },
377    UnaryOp {
378        op: PlanUnaryOp,
379        expr: Box<PlanExpression>,
380    },
381    Function {
382        name: String,
383        args: Vec<PlanExpression>,
384        return_type: DataType,
385    },
386    Cast {
387        expr: Box<PlanExpression>,
388        target_type: DataType,
389    },
390    IsNull {
391        expr: Box<PlanExpression>,
392        negated: bool,
393    },
394    /// CASE expression
395    Case {
396        operand: Option<Box<PlanExpression>>,
397        conditions: Vec<(PlanExpression, PlanExpression)>,
398        else_result: Option<Box<PlanExpression>>,
399    },
400    /// IN list expression (e.g., x IN (1, 2, 3))
401    InList {
402        expr: Box<PlanExpression>,
403        list: Vec<PlanExpression>,
404        negated: bool,
405    },
406    /// BETWEEN expression (e.g., x BETWEEN 1 AND 10)
407    Between {
408        expr: Box<PlanExpression>,
409        low: Box<PlanExpression>,
410        high: Box<PlanExpression>,
411        negated: bool,
412    },
413    /// LIKE pattern matching expression
414    Like {
415        expr: Box<PlanExpression>,
416        pattern: Box<PlanExpression>,
417        negated: bool,
418    },
419    /// IN subquery expression (e.g., x IN (SELECT y FROM t))
420    InSubquery {
421        expr: Box<PlanExpression>,
422        subquery: Box<PlanNode>,
423        negated: bool,
424    },
425    /// EXISTS subquery expression
426    Exists {
427        subquery: Box<PlanNode>,
428        negated: bool,
429    },
430    /// Scalar subquery (returns single value)
431    ScalarSubquery(Box<PlanNode>),
432    /// Placeholder for parameterized queries ($1, $2, etc.)
433    Placeholder(usize),
434}
435
436/// Literal values in plan.
437#[derive(Debug, Clone)]
438pub enum PlanLiteral {
439    Null,
440    Boolean(bool),
441    Integer(i64),
442    Float(f64),
443    String(String),
444}
445
446/// Binary operators in plan.
447#[derive(Debug, Clone, Copy, PartialEq, Eq)]
448pub enum PlanBinaryOp {
449    Add,
450    Subtract,
451    Multiply,
452    Divide,
453    Modulo,
454    Equal,
455    NotEqual,
456    LessThan,
457    LessThanOrEqual,
458    GreaterThan,
459    GreaterThanOrEqual,
460    And,
461    Or,
462    Concat,
463}
464
465/// Unary operators in plan.
466#[derive(Debug, Clone, Copy, PartialEq, Eq)]
467pub enum PlanUnaryOp {
468    Not,
469    Negative,
470}
471
472// =============================================================================
473// Schema Information
474// =============================================================================
475
476/// Schema information for planning.
477#[derive(Debug, Clone, Default)]
478pub struct PlannerSchema {
479    tables: HashMap<String, TableInfo>,
480    indexes: HashMap<String, Vec<IndexInfo>>,
481}
482
483/// Table metadata for planning.
484#[derive(Debug, Clone)]
485pub struct TableInfo {
486    pub name: String,
487    pub columns: Vec<ColumnInfo>,
488    pub row_count: u64,
489}
490
491/// Column metadata for planning.
492#[derive(Debug, Clone)]
493pub struct ColumnInfo {
494    pub name: String,
495    pub data_type: DataType,
496    pub nullable: bool,
497}
498
499/// Index metadata for planning.
500#[derive(Debug, Clone)]
501pub struct IndexInfo {
502    pub name: String,
503    pub columns: Vec<String>,
504    pub unique: bool,
505}
506
507impl PlannerSchema {
508    pub fn new() -> Self {
509        Self::default()
510    }
511
512    pub fn add_table(&mut self, table: TableInfo) {
513        self.tables.insert(table.name.clone(), table);
514    }
515
516    pub fn add_index(&mut self, table: &str, index: IndexInfo) {
517        self.indexes
518            .entry(table.to_string())
519            .or_default()
520            .push(index);
521    }
522
523    pub fn get_table(&self, name: &str) -> Option<&TableInfo> {
524        self.tables.get(name)
525    }
526
527    pub fn get_indexes(&self, table: &str) -> Option<&Vec<IndexInfo>> {
528        self.indexes.get(table)
529    }
530}
531
532// =============================================================================
533// Planner
534// =============================================================================
535
536/// Query planner that transforms AST into execution plans.
537pub struct Planner {
538    schema: Arc<PlannerSchema>,
539}
540
541impl Planner {
542    pub fn new(schema: Arc<PlannerSchema>) -> Self {
543        Self { schema }
544    }
545
546    /// Plan a statement.
547    pub fn plan(&self, statement: &Statement) -> PlannerResult<QueryPlan> {
548        match statement {
549            Statement::Select(select) => self.plan_select(select),
550            Statement::Insert(insert) => self.plan_insert(insert),
551            Statement::Update(update) => self.plan_update(update),
552            Statement::Delete(delete) => self.plan_delete(delete),
553            Statement::CreateTable(create) => self.plan_create_table(create),
554            Statement::DropTable(drop) => self.plan_drop_table(drop),
555            Statement::AlterTable(alter) => self.plan_alter_table(alter),
556            Statement::CreateIndex(create) => self.plan_create_index(create),
557            Statement::DropIndex(drop) => self.plan_drop_index(drop),
558            Statement::SetOperation(set_op) => self.plan_set_operation(set_op),
559            Statement::Begin => Ok(QueryPlan {
560                root: PlanNode::BeginTransaction,
561                estimated_cost: 0.0,
562                estimated_rows: 0,
563            }),
564            Statement::Commit => Ok(QueryPlan {
565                root: PlanNode::CommitTransaction,
566                estimated_cost: 0.0,
567                estimated_rows: 0,
568            }),
569            Statement::Rollback => Ok(QueryPlan {
570                root: PlanNode::RollbackTransaction,
571                estimated_cost: 0.0,
572                estimated_rows: 0,
573            }),
574        }
575    }
576
577    /// Plan a CREATE TABLE statement.
578    fn plan_create_table(
579        &self,
580        create: &crate::ast::CreateTableStatement,
581    ) -> PlannerResult<QueryPlan> {
582        let mut columns: Vec<CreateColumnDef> = Vec::new();
583        for col in &create.columns {
584            let primary_key = col
585                .constraints
586                .iter()
587                .any(|c| matches!(c, crate::ast::ColumnConstraint::PrimaryKey));
588            let unique = col
589                .constraints
590                .iter()
591                .any(|c| matches!(c, crate::ast::ColumnConstraint::Unique));
592
593            let default = match &col.default {
594                Some(e) => Some(self.plan_expression(e)?),
595                None => None,
596            };
597
598            columns.push(CreateColumnDef {
599                name: col.name.clone(),
600                data_type: col.data_type.clone(),
601                nullable: col.nullable,
602                default,
603                primary_key,
604                unique,
605            });
606        }
607
608        let constraints: Vec<CreateTableConstraint> = create
609            .constraints
610            .iter()
611            .map(|c| match c {
612                crate::ast::TableConstraint::PrimaryKey { columns } => {
613                    Ok(CreateTableConstraint::PrimaryKey {
614                        columns: columns.clone(),
615                    })
616                }
617                crate::ast::TableConstraint::Unique { columns } => {
618                    Ok(CreateTableConstraint::Unique {
619                        columns: columns.clone(),
620                    })
621                }
622                crate::ast::TableConstraint::ForeignKey {
623                    columns,
624                    ref_table,
625                    ref_columns,
626                } => Ok(CreateTableConstraint::ForeignKey {
627                    columns: columns.clone(),
628                    ref_table: ref_table.clone(),
629                    ref_columns: ref_columns.clone(),
630                }),
631                crate::ast::TableConstraint::Check { expression } => {
632                    Ok(CreateTableConstraint::Check {
633                        expression: self.plan_expression(expression)?,
634                    })
635                }
636            })
637            .collect::<PlannerResult<Vec<_>>>()?;
638
639        Ok(QueryPlan {
640            root: PlanNode::CreateTable(CreateTableNode {
641                table_name: create.name.clone(),
642                columns,
643                constraints,
644                if_not_exists: create.if_not_exists,
645            }),
646            estimated_cost: 1.0,
647            estimated_rows: 0,
648        })
649    }
650
651    /// Plan a DROP TABLE statement.
652    fn plan_drop_table(&self, drop: &crate::ast::DropTableStatement) -> PlannerResult<QueryPlan> {
653        Ok(QueryPlan {
654            root: PlanNode::DropTable(DropTableNode {
655                table_name: drop.name.clone(),
656                if_exists: drop.if_exists,
657            }),
658            estimated_cost: 1.0,
659            estimated_rows: 0,
660        })
661    }
662
663    /// Plan an ALTER TABLE statement.
664    fn plan_alter_table(
665        &self,
666        alter: &crate::ast::AlterTableStatement,
667    ) -> PlannerResult<QueryPlan> {
668        let operations = alter
669            .operations
670            .iter()
671            .map(|op| match op {
672                crate::ast::AlterTableOperation::AddColumn(col) => {
673                    Ok(PlanAlterOperation::AddColumn(CreateColumnDef {
674                        name: col.name.clone(),
675                        data_type: col.data_type.clone(),
676                        nullable: col.nullable,
677                        default: col
678                            .default
679                            .as_ref()
680                            .map(|e| self.plan_expression(e))
681                            .transpose()?,
682                        primary_key: false,
683                        unique: false,
684                    }))
685                }
686                crate::ast::AlterTableOperation::DropColumn { name, if_exists } => {
687                    Ok(PlanAlterOperation::DropColumn {
688                        name: name.clone(),
689                        if_exists: *if_exists,
690                    })
691                }
692                crate::ast::AlterTableOperation::RenameColumn { old_name, new_name } => {
693                    Ok(PlanAlterOperation::RenameColumn {
694                        old_name: old_name.clone(),
695                        new_name: new_name.clone(),
696                    })
697                }
698                crate::ast::AlterTableOperation::AlterColumn {
699                    name,
700                    data_type,
701                    set_not_null,
702                    set_default,
703                } => {
704                    let default_expr = match set_default {
705                        Some(Some(expr)) => Some(Some(self.plan_expression(expr)?)),
706                        Some(None) => Some(None),
707                        None => None,
708                    };
709                    Ok(PlanAlterOperation::AlterColumn {
710                        name: name.clone(),
711                        data_type: data_type.clone(),
712                        set_not_null: *set_not_null,
713                        set_default: default_expr,
714                    })
715                }
716                crate::ast::AlterTableOperation::RenameTable { new_name } => {
717                    Ok(PlanAlterOperation::RenameTable {
718                        new_name: new_name.clone(),
719                    })
720                }
721                crate::ast::AlterTableOperation::AddConstraint(constraint) => {
722                    let plan_constraint = match constraint {
723                        crate::ast::TableConstraint::PrimaryKey { columns } => {
724                            CreateTableConstraint::PrimaryKey {
725                                columns: columns.clone(),
726                            }
727                        }
728                        crate::ast::TableConstraint::Unique { columns } => {
729                            CreateTableConstraint::Unique {
730                                columns: columns.clone(),
731                            }
732                        }
733                        crate::ast::TableConstraint::ForeignKey {
734                            columns,
735                            ref_table,
736                            ref_columns,
737                        } => CreateTableConstraint::ForeignKey {
738                            columns: columns.clone(),
739                            ref_table: ref_table.clone(),
740                            ref_columns: ref_columns.clone(),
741                        },
742                        crate::ast::TableConstraint::Check { expression } => {
743                            CreateTableConstraint::Check {
744                                expression: self.plan_expression(expression)?,
745                            }
746                        }
747                    };
748                    Ok(PlanAlterOperation::AddConstraint(plan_constraint))
749                }
750                crate::ast::AlterTableOperation::DropConstraint { name } => {
751                    Ok(PlanAlterOperation::DropConstraint { name: name.clone() })
752                }
753            })
754            .collect::<PlannerResult<Vec<_>>>()?;
755
756        Ok(QueryPlan {
757            root: PlanNode::AlterTable(AlterTableNode {
758                table_name: alter.name.clone(),
759                operations,
760            }),
761            estimated_cost: 1.0,
762            estimated_rows: 0,
763        })
764    }
765
766    /// Plan a CREATE INDEX statement.
767    fn plan_create_index(
768        &self,
769        create: &crate::ast::CreateIndexStatement,
770    ) -> PlannerResult<QueryPlan> {
771        Ok(QueryPlan {
772            root: PlanNode::CreateIndex(CreateIndexNode {
773                index_name: create.name.clone(),
774                table_name: create.table.clone(),
775                columns: create.columns.clone(),
776                unique: create.unique,
777                if_not_exists: create.if_not_exists,
778            }),
779            estimated_cost: 1.0,
780            estimated_rows: 0,
781        })
782    }
783
784    /// Plan a DROP INDEX statement.
785    fn plan_drop_index(&self, drop: &crate::ast::DropIndexStatement) -> PlannerResult<QueryPlan> {
786        Ok(QueryPlan {
787            root: PlanNode::DropIndex(DropIndexNode {
788                index_name: drop.name.clone(),
789                if_exists: drop.if_exists,
790            }),
791            estimated_cost: 1.0,
792            estimated_rows: 0,
793        })
794    }
795
796    /// Plan an INSERT statement.
797    fn plan_insert(&self, insert: &crate::ast::InsertStatement) -> PlannerResult<QueryPlan> {
798        let columns = insert.columns.clone().unwrap_or_default();
799
800        let (source, estimated_rows) = match &insert.source {
801            crate::ast::InsertSource::Values(rows) => {
802                let values = rows
803                    .iter()
804                    .map(|row| {
805                        row.iter()
806                            .map(|expr| self.plan_expression(expr))
807                            .collect::<PlannerResult<Vec<_>>>()
808                    })
809                    .collect::<PlannerResult<Vec<_>>>()?;
810                let num_rows = values.len() as u64;
811                (InsertPlanSource::Values(values), num_rows)
812            }
813            crate::ast::InsertSource::Query(select) => {
814                // Plan the SELECT subquery
815                let subquery_plan = self.plan_select(select)?;
816                let estimated_rows = subquery_plan.estimated_rows;
817                (
818                    InsertPlanSource::Query(Box::new(subquery_plan.root)),
819                    estimated_rows,
820                )
821            }
822        };
823
824        Ok(QueryPlan {
825            root: PlanNode::Insert(InsertNode {
826                table_name: insert.table.clone(),
827                columns,
828                source,
829            }),
830            estimated_cost: estimated_rows as f64,
831            estimated_rows,
832        })
833    }
834
835    /// Plan an UPDATE statement.
836    fn plan_update(&self, update: &crate::ast::UpdateStatement) -> PlannerResult<QueryPlan> {
837        let assignments: Vec<(String, PlanExpression)> = update
838            .assignments
839            .iter()
840            .map(|a| Ok((a.column.clone(), self.plan_expression(&a.value)?)))
841            .collect::<PlannerResult<Vec<_>>>()?;
842
843        let where_clause = update
844            .where_clause
845            .as_ref()
846            .map(|e| self.plan_expression(e))
847            .transpose()?;
848
849        // Estimate rows based on table info
850        let estimated_rows = self
851            .schema
852            .get_table(&update.table)
853            .map(|t| t.row_count)
854            .unwrap_or(100);
855
856        Ok(QueryPlan {
857            root: PlanNode::Update(UpdateNode {
858                table_name: update.table.clone(),
859                assignments,
860                where_clause,
861            }),
862            estimated_cost: estimated_rows as f64,
863            estimated_rows,
864        })
865    }
866
867    /// Plan a DELETE statement.
868    fn plan_delete(&self, delete: &crate::ast::DeleteStatement) -> PlannerResult<QueryPlan> {
869        let where_clause = delete
870            .where_clause
871            .as_ref()
872            .map(|e| self.plan_expression(e))
873            .transpose()?;
874
875        // Estimate rows based on table info
876        let estimated_rows = self
877            .schema
878            .get_table(&delete.table)
879            .map(|t| t.row_count)
880            .unwrap_or(100);
881
882        Ok(QueryPlan {
883            root: PlanNode::Delete(DeleteNode {
884                table_name: delete.table.clone(),
885                where_clause,
886            }),
887            estimated_cost: estimated_rows as f64,
888            estimated_rows,
889        })
890    }
891
892    /// Plan a set operation (UNION, INTERSECT, EXCEPT).
893    fn plan_set_operation(
894        &self,
895        set_op: &crate::ast::SetOperationStatement,
896    ) -> PlannerResult<QueryPlan> {
897        let left_plan = self.plan(set_op.left.as_ref())?;
898        let right_plan = self.plan(set_op.right.as_ref())?;
899        let estimated_rows = left_plan.estimated_rows + right_plan.estimated_rows;
900        let estimated_cost =
901            left_plan.estimated_cost + right_plan.estimated_cost + estimated_rows as f64;
902
903        Ok(QueryPlan {
904            root: PlanNode::SetOperation(SetOperationNode {
905                op: set_op.op,
906                left: Box::new(left_plan.root),
907                right: Box::new(right_plan.root),
908            }),
909            estimated_cost,
910            estimated_rows,
911        })
912    }
913
914    /// Plan a SELECT statement.
915    fn plan_select(&self, select: &SelectStatement) -> PlannerResult<QueryPlan> {
916        let mut plan = self.plan_from_clause(&select.from)?;
917
918        if let Some(ref where_clause) = select.where_clause {
919            let predicate = self.plan_expression(where_clause)?;
920            plan = PlanNode::Filter(FilterNode {
921                input: Box::new(plan),
922                predicate,
923            });
924        }
925
926        if !select.group_by.is_empty() || self.has_aggregates(&select.columns) {
927            plan = self.plan_aggregation(plan, select)?;
928        }
929
930        if let Some(ref having) = select.having {
931            let predicate = self.plan_expression(having)?;
932            plan = PlanNode::Filter(FilterNode {
933                input: Box::new(plan),
934                predicate,
935            });
936        }
937
938        plan = self.plan_projection(plan, &select.columns)?;
939
940        if !select.order_by.is_empty() {
941            let order_by: Vec<SortKey> = select
942                .order_by
943                .iter()
944                .map(|item| {
945                    Ok(SortKey {
946                        expr: self.plan_expression(&item.expression)?,
947                        ascending: item.ascending,
948                        nulls_first: item.nulls_first.unwrap_or(!item.ascending),
949                    })
950                })
951                .collect::<PlannerResult<Vec<_>>>()?;
952
953            plan = PlanNode::Sort(SortNode {
954                input: Box::new(plan),
955                order_by,
956            });
957        }
958
959        if select.limit.is_some() || select.offset.is_some() {
960            plan = PlanNode::Limit(LimitNode {
961                input: Box::new(plan),
962                limit: select.limit,
963                offset: select.offset,
964            });
965        }
966
967        let (estimated_cost, estimated_rows) = self.estimate_cost(&plan);
968
969        Ok(QueryPlan {
970            root: plan,
971            estimated_cost,
972            estimated_rows,
973        })
974    }
975
976    /// Plan FROM clause.
977    fn plan_from_clause(&self, from: &Option<FromClause>) -> PlannerResult<PlanNode> {
978        let from = match from {
979            Some(f) => f,
980            None => return Ok(PlanNode::Empty),
981        };
982
983        let mut plan = self.plan_table_reference(&from.source)?;
984
985        for join in &from.joins {
986            plan = self.plan_join(plan, join)?;
987        }
988
989        Ok(plan)
990    }
991
992    /// Plan a table reference.
993    fn plan_table_reference(&self, table_ref: &TableReference) -> PlannerResult<PlanNode> {
994        match table_ref {
995            TableReference::Table { name, alias } => {
996                let columns = if let Some(info) = self.schema.get_table(name) {
997                    info.columns.iter().map(|c| c.name.clone()).collect()
998                } else {
999                    Vec::new()
1000                };
1001
1002                Ok(PlanNode::Scan(ScanNode {
1003                    table_name: name.clone(),
1004                    alias: alias.clone(),
1005                    columns,
1006                    index_scan: None,
1007                }))
1008            }
1009            TableReference::Subquery { query, alias: _ } => self.plan_select(query).map(|p| p.root),
1010        }
1011    }
1012
1013    /// Plan a join.
1014    fn plan_join(&self, left: PlanNode, join: &JoinClause) -> PlannerResult<PlanNode> {
1015        let right = self.plan_table_reference(&join.table)?;
1016        let condition = join
1017            .condition
1018            .as_ref()
1019            .map(|c| self.plan_expression(c))
1020            .transpose()?;
1021
1022        let join_type = match join.join_type {
1023            JoinType::Inner => PlanJoinType::Inner,
1024            JoinType::Left => PlanJoinType::Left,
1025            JoinType::Right => PlanJoinType::Right,
1026            JoinType::Full => PlanJoinType::Full,
1027            JoinType::Cross => PlanJoinType::Cross,
1028        };
1029
1030        let strategy = self.choose_join_strategy(&left, &right, &condition);
1031
1032        Ok(PlanNode::Join(JoinNode {
1033            left: Box::new(left),
1034            right: Box::new(right),
1035            join_type,
1036            condition,
1037            strategy,
1038        }))
1039    }
1040
1041    /// Choose join strategy based on cost estimation.
1042    fn choose_join_strategy(
1043        &self,
1044        _left: &PlanNode,
1045        _right: &PlanNode,
1046        condition: &Option<PlanExpression>,
1047    ) -> JoinStrategy {
1048        if condition.is_none() {
1049            return JoinStrategy::NestedLoop;
1050        }
1051
1052        JoinStrategy::HashJoin
1053    }
1054
1055    /// Check if select columns contain aggregates.
1056    fn has_aggregates(&self, columns: &[SelectColumn]) -> bool {
1057        columns.iter().any(|col| match col {
1058            SelectColumn::Expression { expr, .. } => self.expression_has_aggregate(expr),
1059            _ => false,
1060        })
1061    }
1062
1063    /// Check if expression contains aggregate function.
1064    fn expression_has_aggregate(&self, expr: &Expression) -> bool {
1065        match expr {
1066            Expression::Function { name, .. } => {
1067                matches!(
1068                    name.to_uppercase().as_str(),
1069                    "COUNT" | "SUM" | "AVG" | "MIN" | "MAX"
1070                )
1071            }
1072            Expression::BinaryOp { left, right, .. } => {
1073                self.expression_has_aggregate(left) || self.expression_has_aggregate(right)
1074            }
1075            _ => false,
1076        }
1077    }
1078
1079    /// Plan aggregation.
1080    fn plan_aggregation(
1081        &self,
1082        input: PlanNode,
1083        select: &SelectStatement,
1084    ) -> PlannerResult<PlanNode> {
1085        let group_by: Vec<PlanExpression> = select
1086            .group_by
1087            .iter()
1088            .map(|e| self.plan_expression(e))
1089            .collect::<PlannerResult<Vec<_>>>()?;
1090
1091        let mut aggregates = Vec::new();
1092        for col in &select.columns {
1093            if let SelectColumn::Expression { expr, alias } = col {
1094                if let Some(agg) = self.extract_aggregate(expr, alias.clone())? {
1095                    aggregates.push(agg);
1096                }
1097            }
1098        }
1099
1100        Ok(PlanNode::Aggregate(AggregateNode {
1101            input: Box::new(input),
1102            group_by,
1103            aggregates,
1104        }))
1105    }
1106
1107    /// Extract aggregate from expression.
1108    fn extract_aggregate(
1109        &self,
1110        expr: &Expression,
1111        alias: Option<String>,
1112    ) -> PlannerResult<Option<AggregateExpr>> {
1113        match expr {
1114            Expression::Function {
1115                name,
1116                args,
1117                distinct,
1118            } => {
1119                let func = match name.to_uppercase().as_str() {
1120                    "COUNT" => AggregateFunction::Count,
1121                    "SUM" => AggregateFunction::Sum,
1122                    "AVG" => AggregateFunction::Avg,
1123                    "MIN" => AggregateFunction::Min,
1124                    "MAX" => AggregateFunction::Max,
1125                    _ => return Ok(None),
1126                };
1127
1128                let argument = if args.is_empty() {
1129                    None
1130                } else {
1131                    Some(self.plan_expression(&args[0])?)
1132                };
1133
1134                Ok(Some(AggregateExpr {
1135                    function: func,
1136                    argument,
1137                    distinct: *distinct,
1138                    alias,
1139                }))
1140            }
1141            _ => Ok(None),
1142        }
1143    }
1144
1145    /// Plan projection.
1146    fn plan_projection(
1147        &self,
1148        input: PlanNode,
1149        columns: &[SelectColumn],
1150    ) -> PlannerResult<PlanNode> {
1151        let mut expressions = Vec::new();
1152
1153        for col in columns {
1154            match col {
1155                SelectColumn::AllColumns => {
1156                    expressions.push(ProjectionExpr {
1157                        expr: PlanExpression::Column {
1158                            table: None,
1159                            name: "*".to_string(),
1160                            data_type: DataType::Any,
1161                        },
1162                        alias: None,
1163                    });
1164                }
1165                SelectColumn::TableAllColumns(table) => {
1166                    expressions.push(ProjectionExpr {
1167                        expr: PlanExpression::Column {
1168                            table: Some(table.clone()),
1169                            name: "*".to_string(),
1170                            data_type: DataType::Any,
1171                        },
1172                        alias: None,
1173                    });
1174                }
1175                SelectColumn::Expression { expr, alias } => {
1176                    expressions.push(ProjectionExpr {
1177                        expr: self.plan_expression(expr)?,
1178                        alias: alias.clone(),
1179                    });
1180                }
1181            }
1182        }
1183
1184        Ok(PlanNode::Project(ProjectNode {
1185            input: Box::new(input),
1186            expressions,
1187        }))
1188    }
1189
1190    /// Convert AST expression to plan expression.
1191    fn plan_expression(&self, expr: &Expression) -> PlannerResult<PlanExpression> {
1192        match expr {
1193            Expression::Literal(lit) => Ok(PlanExpression::Literal(match lit {
1194                crate::ast::Literal::Null => PlanLiteral::Null,
1195                crate::ast::Literal::Boolean(b) => PlanLiteral::Boolean(*b),
1196                crate::ast::Literal::Integer(i) => PlanLiteral::Integer(*i),
1197                crate::ast::Literal::Float(f) => PlanLiteral::Float(*f),
1198                crate::ast::Literal::String(s) => PlanLiteral::String(s.clone()),
1199            })),
1200
1201            Expression::Column(col_ref) => Ok(PlanExpression::Column {
1202                table: col_ref.table.clone(),
1203                name: col_ref.column.clone(),
1204                data_type: DataType::Any,
1205            }),
1206
1207            Expression::BinaryOp { left, op, right } => {
1208                let plan_op = match op {
1209                    BinaryOperator::Add => PlanBinaryOp::Add,
1210                    BinaryOperator::Subtract => PlanBinaryOp::Subtract,
1211                    BinaryOperator::Multiply => PlanBinaryOp::Multiply,
1212                    BinaryOperator::Divide => PlanBinaryOp::Divide,
1213                    BinaryOperator::Modulo => PlanBinaryOp::Modulo,
1214                    BinaryOperator::Equal => PlanBinaryOp::Equal,
1215                    BinaryOperator::NotEqual => PlanBinaryOp::NotEqual,
1216                    BinaryOperator::LessThan => PlanBinaryOp::LessThan,
1217                    BinaryOperator::LessThanOrEqual => PlanBinaryOp::LessThanOrEqual,
1218                    BinaryOperator::GreaterThan => PlanBinaryOp::GreaterThan,
1219                    BinaryOperator::GreaterThanOrEqual => PlanBinaryOp::GreaterThanOrEqual,
1220                    BinaryOperator::And => PlanBinaryOp::And,
1221                    BinaryOperator::Or => PlanBinaryOp::Or,
1222                    BinaryOperator::Concat => PlanBinaryOp::Concat,
1223                };
1224
1225                Ok(PlanExpression::BinaryOp {
1226                    left: Box::new(self.plan_expression(left)?),
1227                    op: plan_op,
1228                    right: Box::new(self.plan_expression(right)?),
1229                })
1230            }
1231
1232            Expression::UnaryOp { op, expr } => {
1233                let plan_op = match op {
1234                    crate::ast::UnaryOperator::Not => PlanUnaryOp::Not,
1235                    crate::ast::UnaryOperator::Negative => PlanUnaryOp::Negative,
1236                    crate::ast::UnaryOperator::Positive => {
1237                        return self.plan_expression(expr);
1238                    }
1239                };
1240
1241                Ok(PlanExpression::UnaryOp {
1242                    op: plan_op,
1243                    expr: Box::new(self.plan_expression(expr)?),
1244                })
1245            }
1246
1247            Expression::Function { name, args, .. } => {
1248                let planned_args: Vec<PlanExpression> = args
1249                    .iter()
1250                    .map(|a| self.plan_expression(a))
1251                    .collect::<PlannerResult<Vec<_>>>()?;
1252
1253                Ok(PlanExpression::Function {
1254                    name: name.clone(),
1255                    args: planned_args,
1256                    return_type: DataType::Any,
1257                })
1258            }
1259
1260            Expression::IsNull { expr, negated } => Ok(PlanExpression::IsNull {
1261                expr: Box::new(self.plan_expression(expr)?),
1262                negated: *negated,
1263            }),
1264
1265            Expression::Cast { expr, data_type } => Ok(PlanExpression::Cast {
1266                expr: Box::new(self.plan_expression(expr)?),
1267                target_type: data_type.clone(),
1268            }),
1269
1270            Expression::Case {
1271                operand,
1272                conditions,
1273                else_result,
1274            } => {
1275                let planned_operand = operand
1276                    .as_ref()
1277                    .map(|e| self.plan_expression(e))
1278                    .transpose()?
1279                    .map(Box::new);
1280
1281                let planned_conditions = conditions
1282                    .iter()
1283                    .map(|(cond, result)| {
1284                        Ok((self.plan_expression(cond)?, self.plan_expression(result)?))
1285                    })
1286                    .collect::<PlannerResult<Vec<_>>>()?;
1287
1288                let planned_else = else_result
1289                    .as_ref()
1290                    .map(|e| self.plan_expression(e))
1291                    .transpose()?
1292                    .map(Box::new);
1293
1294                Ok(PlanExpression::Case {
1295                    operand: planned_operand,
1296                    conditions: planned_conditions,
1297                    else_result: planned_else,
1298                })
1299            }
1300
1301            Expression::InList {
1302                expr,
1303                list,
1304                negated,
1305            } => {
1306                let planned_list = list
1307                    .iter()
1308                    .map(|e| self.plan_expression(e))
1309                    .collect::<PlannerResult<Vec<_>>>()?;
1310
1311                Ok(PlanExpression::InList {
1312                    expr: Box::new(self.plan_expression(expr)?),
1313                    list: planned_list,
1314                    negated: *negated,
1315                })
1316            }
1317
1318            Expression::Between {
1319                expr,
1320                low,
1321                high,
1322                negated,
1323            } => Ok(PlanExpression::Between {
1324                expr: Box::new(self.plan_expression(expr)?),
1325                low: Box::new(self.plan_expression(low)?),
1326                high: Box::new(self.plan_expression(high)?),
1327                negated: *negated,
1328            }),
1329
1330            Expression::Like {
1331                expr,
1332                pattern,
1333                negated,
1334            } => Ok(PlanExpression::Like {
1335                expr: Box::new(self.plan_expression(expr)?),
1336                pattern: Box::new(self.plan_expression(pattern)?),
1337                negated: *negated,
1338            }),
1339
1340            Expression::InSubquery {
1341                expr,
1342                subquery,
1343                negated,
1344            } => {
1345                let subquery_plan = self.plan_select(subquery)?;
1346                Ok(PlanExpression::InSubquery {
1347                    expr: Box::new(self.plan_expression(expr)?),
1348                    subquery: Box::new(subquery_plan.root),
1349                    negated: *negated,
1350                })
1351            }
1352
1353            Expression::Exists { subquery, negated } => {
1354                let subquery_plan = self.plan_select(subquery)?;
1355                Ok(PlanExpression::Exists {
1356                    subquery: Box::new(subquery_plan.root),
1357                    negated: *negated,
1358                })
1359            }
1360
1361            Expression::Subquery(subquery) => {
1362                let subquery_plan = self.plan_select(subquery)?;
1363                Ok(PlanExpression::ScalarSubquery(Box::new(subquery_plan.root)))
1364            }
1365
1366            Expression::Placeholder(idx) => Ok(PlanExpression::Placeholder(*idx)),
1367        }
1368    }
1369
1370    /// Estimate cost and row count for a plan.
1371    fn estimate_cost(&self, node: &PlanNode) -> (f64, u64) {
1372        match node {
1373            PlanNode::Scan(scan) => {
1374                let rows = self
1375                    .schema
1376                    .get_table(&scan.table_name)
1377                    .map(|t| t.row_count)
1378                    .unwrap_or(1000);
1379                let cost = rows as f64 * 1.0;
1380                (cost, rows)
1381            }
1382
1383            PlanNode::Filter(filter) => {
1384                let (input_cost, input_rows) = self.estimate_cost(&filter.input);
1385                let selectivity = 0.1;
1386                let rows = (input_rows as f64 * selectivity) as u64;
1387                let cost = input_cost + input_rows as f64 * 0.1;
1388                (cost, rows.max(1))
1389            }
1390
1391            PlanNode::Project(project) => {
1392                let (input_cost, input_rows) = self.estimate_cost(&project.input);
1393                let cost = input_cost + input_rows as f64 * 0.01;
1394                (cost, input_rows)
1395            }
1396
1397            PlanNode::Join(join) => {
1398                let (left_cost, left_rows) = self.estimate_cost(&join.left);
1399                let (right_cost, right_rows) = self.estimate_cost(&join.right);
1400
1401                let rows = match join.join_type {
1402                    PlanJoinType::Cross => left_rows * right_rows,
1403                    _ => (left_rows + right_rows) / 2,
1404                };
1405
1406                let join_cost = match join.strategy {
1407                    JoinStrategy::NestedLoop => left_rows as f64 * right_rows as f64,
1408                    JoinStrategy::HashJoin => {
1409                        left_rows as f64 + right_rows as f64 + right_rows as f64 * 1.2
1410                    }
1411                    JoinStrategy::MergeJoin => {
1412                        left_rows as f64 * 2.0_f64.log2()
1413                            + right_rows as f64 * 2.0_f64.log2()
1414                            + (left_rows + right_rows) as f64
1415                    }
1416                };
1417
1418                (left_cost + right_cost + join_cost, rows)
1419            }
1420
1421            PlanNode::Aggregate(agg) => {
1422                let (input_cost, input_rows) = self.estimate_cost(&agg.input);
1423                let groups = if agg.group_by.is_empty() {
1424                    1
1425                } else {
1426                    (input_rows as f64).sqrt() as u64
1427                };
1428                let cost = input_cost + input_rows as f64 * 0.5;
1429                (cost, groups.max(1))
1430            }
1431
1432            PlanNode::Sort(sort) => {
1433                let (input_cost, input_rows) = self.estimate_cost(&sort.input);
1434                let sort_cost = input_rows as f64 * (input_rows as f64).log2();
1435                (input_cost + sort_cost, input_rows)
1436            }
1437
1438            PlanNode::Limit(limit) => {
1439                let (input_cost, input_rows) = self.estimate_cost(&limit.input);
1440                let rows = limit.limit.unwrap_or(input_rows).min(input_rows);
1441                (input_cost, rows)
1442            }
1443
1444            PlanNode::Empty => (0.0, 1),
1445
1446            // DDL operations have minimal cost
1447            PlanNode::CreateTable(_) => (1.0, 0),
1448            PlanNode::DropTable(_) => (1.0, 0),
1449            PlanNode::AlterTable(_) => (1.0, 0),
1450            PlanNode::CreateIndex(_) => (1.0, 0),
1451            PlanNode::DropIndex(_) => (1.0, 0),
1452
1453            // DML operations
1454            PlanNode::Insert(insert) => {
1455                let rows = match &insert.source {
1456                    InsertPlanSource::Values(values) => values.len() as u64,
1457                    InsertPlanSource::Query(subquery) => {
1458                        let (_, estimated_rows) = self.estimate_cost(subquery);
1459                        estimated_rows
1460                    }
1461                };
1462                (rows as f64, rows)
1463            }
1464            PlanNode::Update(update) => {
1465                let rows = self
1466                    .schema
1467                    .get_table(&update.table_name)
1468                    .map(|t| t.row_count)
1469                    .unwrap_or(100);
1470                (rows as f64, rows)
1471            }
1472            PlanNode::Delete(delete) => {
1473                let rows = self
1474                    .schema
1475                    .get_table(&delete.table_name)
1476                    .map(|t| t.row_count)
1477                    .unwrap_or(100);
1478                (rows as f64, rows)
1479            }
1480
1481            // Set operations
1482            PlanNode::SetOperation(set_op) => {
1483                let (left_cost, left_rows) = self.estimate_cost(&set_op.left);
1484                let (right_cost, right_rows) = self.estimate_cost(&set_op.right);
1485                let rows = left_rows + right_rows;
1486                let cost = left_cost + right_cost + rows as f64;
1487                (cost, rows)
1488            }
1489
1490            // Transaction control
1491            PlanNode::BeginTransaction
1492            | PlanNode::CommitTransaction
1493            | PlanNode::RollbackTransaction => (0.0, 0),
1494        }
1495    }
1496}
1497
1498// =============================================================================
1499// Tests
1500// =============================================================================
1501
1502#[cfg(test)]
1503mod tests {
1504    use super::*;
1505    use crate::ast::{ColumnRef, FromClause, Literal, OrderByItem, TableReference};
1506
1507    fn create_test_schema() -> Arc<PlannerSchema> {
1508        let mut schema = PlannerSchema::new();
1509
1510        schema.add_table(TableInfo {
1511            name: "users".to_string(),
1512            columns: vec![
1513                ColumnInfo {
1514                    name: "id".to_string(),
1515                    data_type: DataType::Integer,
1516                    nullable: false,
1517                },
1518                ColumnInfo {
1519                    name: "name".to_string(),
1520                    data_type: DataType::Text,
1521                    nullable: false,
1522                },
1523                ColumnInfo {
1524                    name: "email".to_string(),
1525                    data_type: DataType::Text,
1526                    nullable: true,
1527                },
1528            ],
1529            row_count: 10000,
1530        });
1531
1532        schema.add_table(TableInfo {
1533            name: "orders".to_string(),
1534            columns: vec![
1535                ColumnInfo {
1536                    name: "id".to_string(),
1537                    data_type: DataType::Integer,
1538                    nullable: false,
1539                },
1540                ColumnInfo {
1541                    name: "user_id".to_string(),
1542                    data_type: DataType::Integer,
1543                    nullable: false,
1544                },
1545                ColumnInfo {
1546                    name: "amount".to_string(),
1547                    data_type: DataType::Float,
1548                    nullable: false,
1549                },
1550            ],
1551            row_count: 50000,
1552        });
1553
1554        Arc::new(schema)
1555    }
1556
1557    #[test]
1558    fn test_plan_simple_select() {
1559        let schema = create_test_schema();
1560        let planner = Planner::new(schema);
1561
1562        let select = SelectStatement {
1563            distinct: false,
1564            columns: vec![SelectColumn::AllColumns],
1565            from: Some(FromClause {
1566                source: TableReference::Table {
1567                    name: "users".to_string(),
1568                    alias: None,
1569                },
1570                joins: vec![],
1571            }),
1572            where_clause: None,
1573            group_by: vec![],
1574            having: None,
1575            order_by: vec![],
1576            limit: None,
1577            offset: None,
1578        };
1579
1580        let plan = planner.plan(&Statement::Select(select)).unwrap();
1581
1582        assert!(plan.estimated_rows > 0);
1583        assert!(plan.estimated_cost > 0.0);
1584    }
1585
1586    #[test]
1587    fn test_plan_select_with_filter() {
1588        let schema = create_test_schema();
1589        let planner = Planner::new(schema);
1590
1591        let select = SelectStatement {
1592            distinct: false,
1593            columns: vec![SelectColumn::AllColumns],
1594            from: Some(FromClause {
1595                source: TableReference::Table {
1596                    name: "users".to_string(),
1597                    alias: None,
1598                },
1599                joins: vec![],
1600            }),
1601            where_clause: Some(Expression::BinaryOp {
1602                left: Box::new(Expression::Column(ColumnRef {
1603                    table: None,
1604                    column: "id".to_string(),
1605                })),
1606                op: BinaryOperator::Equal,
1607                right: Box::new(Expression::Literal(Literal::Integer(1))),
1608            }),
1609            group_by: vec![],
1610            having: None,
1611            order_by: vec![],
1612            limit: None,
1613            offset: None,
1614        };
1615
1616        let plan = planner.plan(&Statement::Select(select)).unwrap();
1617
1618        match &plan.root {
1619            PlanNode::Project(p) => match p.input.as_ref() {
1620                PlanNode::Filter(_) => {}
1621                _ => panic!("Expected filter node"),
1622            },
1623            _ => panic!("Expected project node"),
1624        }
1625    }
1626
1627    #[test]
1628    fn test_plan_select_with_order_by() {
1629        let schema = create_test_schema();
1630        let planner = Planner::new(schema);
1631
1632        let select = SelectStatement {
1633            distinct: false,
1634            columns: vec![SelectColumn::AllColumns],
1635            from: Some(FromClause {
1636                source: TableReference::Table {
1637                    name: "users".to_string(),
1638                    alias: None,
1639                },
1640                joins: vec![],
1641            }),
1642            where_clause: None,
1643            group_by: vec![],
1644            having: None,
1645            order_by: vec![OrderByItem {
1646                expression: Expression::Column(ColumnRef {
1647                    table: None,
1648                    column: "name".to_string(),
1649                }),
1650                ascending: true,
1651                nulls_first: None,
1652            }],
1653            limit: Some(10),
1654            offset: None,
1655        };
1656
1657        let plan = planner.plan(&Statement::Select(select)).unwrap();
1658
1659        match &plan.root {
1660            PlanNode::Limit(l) => match l.input.as_ref() {
1661                PlanNode::Sort(_) => {}
1662                _ => panic!("Expected sort node"),
1663            },
1664            _ => panic!("Expected limit node"),
1665        }
1666    }
1667
1668    #[test]
1669    fn test_plan_set_operation_union() {
1670        let schema = create_test_schema();
1671        let planner = Planner::new(schema);
1672
1673        let set_op = crate::ast::SetOperationStatement {
1674            op: SetOperationType::Union,
1675            left: Box::new(Statement::Select(SelectStatement {
1676                columns: vec![SelectColumn::AllColumns],
1677                from: Some(FromClause {
1678                    source: TableReference::Table {
1679                        name: "users".to_string(),
1680                        alias: None,
1681                    },
1682                    joins: vec![],
1683                }),
1684                ..Default::default()
1685            })),
1686            right: Box::new(Statement::Select(SelectStatement {
1687                columns: vec![SelectColumn::AllColumns],
1688                from: Some(FromClause {
1689                    source: TableReference::Table {
1690                        name: "orders".to_string(),
1691                        alias: None,
1692                    },
1693                    joins: vec![],
1694                }),
1695                ..Default::default()
1696            })),
1697        };
1698
1699        let plan = planner.plan(&Statement::SetOperation(set_op)).unwrap();
1700
1701        match &plan.root {
1702            PlanNode::SetOperation(node) => {
1703                assert_eq!(node.op, SetOperationType::Union);
1704            }
1705            _ => panic!("Expected SetOperation node"),
1706        }
1707        assert!(plan.estimated_rows > 0);
1708        assert!(plan.estimated_cost > 0.0);
1709    }
1710}