1use 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#[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#[derive(Debug, Clone)]
51pub struct QueryPlan {
52 pub root: PlanNode,
53 pub estimated_cost: f64,
54 pub estimated_rows: u64,
55}
56
57#[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 CreateTable(CreateTableNode),
70 DropTable(DropTableNode),
71 AlterTable(AlterTableNode),
72 CreateIndex(CreateIndexNode),
73 DropIndex(DropIndexNode),
74 Insert(InsertNode),
76 Update(UpdateNode),
77 Delete(DeleteNode),
78 SetOperation(SetOperationNode),
80 BeginTransaction,
82 CommitTransaction,
83 RollbackTransaction,
84}
85
86#[derive(Debug, Clone)]
88pub struct SetOperationNode {
89 pub op: SetOperationType,
90 pub left: Box<PlanNode>,
91 pub right: Box<PlanNode>,
92}
93
94#[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#[derive(Debug, Clone)]
109pub struct IndexScan {
110 pub index_name: String,
111 pub key_range: KeyRange,
112}
113
114#[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#[derive(Debug, Clone)]
125pub struct FilterNode {
126 pub input: Box<PlanNode>,
127 pub predicate: PlanExpression,
128}
129
130#[derive(Debug, Clone)]
132pub struct ProjectNode {
133 pub input: Box<PlanNode>,
134 pub expressions: Vec<ProjectionExpr>,
135}
136
137#[derive(Debug, Clone)]
139pub struct ProjectionExpr {
140 pub expr: PlanExpression,
141 pub alias: Option<String>,
142}
143
144#[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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub enum PlanJoinType {
157 Inner,
158 Left,
159 Right,
160 Full,
161 Cross,
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166pub enum JoinStrategy {
167 NestedLoop,
168 HashJoin,
169 MergeJoin,
170}
171
172#[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#[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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum AggregateFunction {
192 Count,
193 Sum,
194 Avg,
195 Min,
196 Max,
197}
198
199#[derive(Debug, Clone)]
201pub struct SortNode {
202 pub input: Box<PlanNode>,
203 pub order_by: Vec<SortKey>,
204}
205
206#[derive(Debug, Clone)]
208pub struct SortKey {
209 pub expr: PlanExpression,
210 pub ascending: bool,
211 pub nulls_first: bool,
212}
213
214#[derive(Debug, Clone)]
216pub struct LimitNode {
217 pub input: Box<PlanNode>,
218 pub limit: Option<u64>,
219 pub offset: Option<u64>,
220}
221
222#[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#[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#[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#[derive(Debug, Clone)]
267pub struct DropTableNode {
268 pub table_name: String,
269 pub if_exists: bool,
270}
271
272#[derive(Debug, Clone)]
274pub struct AlterTableNode {
275 pub table_name: String,
276 pub operations: Vec<PlanAlterOperation>,
277}
278
279#[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#[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#[derive(Debug, Clone)]
318pub struct DropIndexNode {
319 pub index_name: String,
320 pub if_exists: bool,
321}
322
323#[derive(Debug, Clone)]
329pub enum InsertPlanSource {
330 Values(Vec<Vec<PlanExpression>>),
332 Query(Box<PlanNode>),
334}
335
336#[derive(Debug, Clone)]
338pub struct InsertNode {
339 pub table_name: String,
340 pub columns: Vec<String>,
341 pub source: InsertPlanSource,
342}
343
344#[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#[derive(Debug, Clone)]
354pub struct DeleteNode {
355 pub table_name: String,
356 pub where_clause: Option<PlanExpression>,
357}
358
359#[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 {
396 operand: Option<Box<PlanExpression>>,
397 conditions: Vec<(PlanExpression, PlanExpression)>,
398 else_result: Option<Box<PlanExpression>>,
399 },
400 InList {
402 expr: Box<PlanExpression>,
403 list: Vec<PlanExpression>,
404 negated: bool,
405 },
406 Between {
408 expr: Box<PlanExpression>,
409 low: Box<PlanExpression>,
410 high: Box<PlanExpression>,
411 negated: bool,
412 },
413 Like {
415 expr: Box<PlanExpression>,
416 pattern: Box<PlanExpression>,
417 negated: bool,
418 },
419 InSubquery {
421 expr: Box<PlanExpression>,
422 subquery: Box<PlanNode>,
423 negated: bool,
424 },
425 Exists {
427 subquery: Box<PlanNode>,
428 negated: bool,
429 },
430 ScalarSubquery(Box<PlanNode>),
432 Placeholder(usize),
434}
435
436#[derive(Debug, Clone)]
438pub enum PlanLiteral {
439 Null,
440 Boolean(bool),
441 Integer(i64),
442 Float(f64),
443 String(String),
444}
445
446#[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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
467pub enum PlanUnaryOp {
468 Not,
469 Negative,
470}
471
472#[derive(Debug, Clone, Default)]
478pub struct PlannerSchema {
479 tables: HashMap<String, TableInfo>,
480 indexes: HashMap<String, Vec<IndexInfo>>,
481}
482
483#[derive(Debug, Clone)]
485pub struct TableInfo {
486 pub name: String,
487 pub columns: Vec<ColumnInfo>,
488 pub row_count: u64,
489}
490
491#[derive(Debug, Clone)]
493pub struct ColumnInfo {
494 pub name: String,
495 pub data_type: DataType,
496 pub nullable: bool,
497}
498
499#[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
532pub struct Planner {
538 schema: Arc<PlannerSchema>,
539}
540
541impl Planner {
542 pub fn new(schema: Arc<PlannerSchema>) -> Self {
543 Self { schema }
544 }
545
546 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 PlanNode::BeginTransaction
1492 | PlanNode::CommitTransaction
1493 | PlanNode::RollbackTransaction => (0.0, 0),
1494 }
1495 }
1496}
1497
1498#[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}