Skip to content

Commit

Permalink
Implement eliminate limit rule
Browse files Browse the repository at this point in the history
  • Loading branch information
lewiszlw committed Feb 4, 2024
1 parent 95da8de commit d5d70a2
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 12 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# BustubX - a relational database for educational purpose (CMU 15-445)
- [ ] DDL
- [ ] DML
- [ ] Rule-based Optimizer
- [ ] Volcano Executor
- [x] Rule-based Optimizer
- [x] Volcano Executor
- [ ] Parallel Execution
- [ ] B+ Tree Index
- [ ] Multi-Version Concurrency Control
Expand Down
11 changes: 7 additions & 4 deletions bustubx/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
planner::{LogicalPlanner, PlannerContext},
storage::{DiskManager, Tuple},
};
use crate::optimizer::LogicalOptimizer;

pub struct Database {
disk_manager: Arc<DiskManager>,
Expand Down Expand Up @@ -50,11 +51,13 @@ impl Database {
}

pub fn run(&mut self, sql: &str) -> BustubxResult<Vec<Tuple>> {
let logical_plan = self.build_logical_plan(sql)?;
println!("logical plan: \n{}", logical_plan);
let logical_plan = self.create_logical_plan(sql)?;
// println!("logical plan: \n{}", logical_plan);

let optimized_logical_plan = LogicalOptimizer::new().optimize(&logical_plan)?;

// logical plan -> physical plan
let physical_plan = PhysicalPlanner::new().create_physical_plan(logical_plan);
let physical_plan = PhysicalPlanner::new().create_physical_plan(optimized_logical_plan);
// println!("{:?}", physical_plan);

let execution_ctx = ExecutionContext::new(&mut self.catalog);
Expand All @@ -66,7 +69,7 @@ impl Database {
Ok(tuples)
}

pub fn build_logical_plan(&mut self, sql: &str) -> BustubxResult<LogicalPlan> {
pub fn create_logical_plan(&mut self, sql: &str) -> BustubxResult<LogicalPlan> {
// sql -> ast
let stmts = crate::parser::parse_sql(sql)?;
if stmts.len() != 1 {
Expand Down
11 changes: 9 additions & 2 deletions bustubx/src/optimizer/logical_optimizer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::BustubxResult;
use crate::optimizer::rule::PushDownLimit;
use crate::optimizer::rule::{EliminateLimit, PushDownLimit};

Check warning on line 2 in bustubx/src/optimizer/logical_optimizer.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused import: `PushDownLimit`
use crate::planner::logical_plan::LogicalPlan;
use std::sync::Arc;

Expand Down Expand Up @@ -38,14 +38,21 @@ pub struct LogicalOptimizer {
impl LogicalOptimizer {
pub fn new() -> Self {
let rules: Vec<Arc<dyn LogicalOptimizerRule + Sync + Send>> =
vec![Arc::new(PushDownLimit {})];
vec![Arc::new(EliminateLimit {})];

Self {
rules,
max_passes: 3,
}
}

pub fn with_rules(rules: Vec<Arc<dyn LogicalOptimizerRule + Send + Sync>>) -> Self {
Self {
rules,
max_passes: 3,
}
}

pub fn optimize(&self, plan: &LogicalPlan) -> BustubxResult<LogicalPlan> {
let mut new_plan = plan.clone();
let mut i = 0;
Expand Down
2 changes: 1 addition & 1 deletion bustubx/src/optimizer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod logical_optimizer;
mod rule;
pub mod rule;

pub use logical_optimizer::{LogicalOptimizer, LogicalOptimizerRule};
70 changes: 70 additions & 0 deletions bustubx/src/optimizer/rule/eliminate_limit.rs
Original file line number Diff line number Diff line change
@@ -1 +1,71 @@
use crate::optimizer::logical_optimizer::ApplyOrder;
use crate::optimizer::LogicalOptimizerRule;
use crate::planner::logical_plan::{EmptyRelation, LogicalPlan};
use crate::BustubxResult;

pub struct EliminateLimit;

impl LogicalOptimizerRule for EliminateLimit {
fn try_optimize(&self, plan: &LogicalPlan) -> BustubxResult<Option<LogicalPlan>> {
if let LogicalPlan::Limit(limit) = plan {
match limit.limit {
Some(fetch) => {
if fetch == 0 {
return Ok(Some(LogicalPlan::EmptyRelation(EmptyRelation {
produce_one_row: false,
schema: limit.input.schema().clone(),
})));
}
}
None => {
if limit.offset == 0 {
let input = limit.input.as_ref();
// input also can be Limit, so we should apply again.
return Ok(Some(
self.try_optimize(input)?.unwrap_or_else(|| input.clone()),
));
}
}
}
}
Ok(None)
}

fn name(&self) -> &str {
"EliminateLimit"
}

fn apply_order(&self) -> Option<ApplyOrder> {
Some(ApplyOrder::BottomUp)
}
}

#[cfg(test)]
mod tests {
use crate::optimizer::rule::EliminateLimit;
use crate::optimizer::LogicalOptimizer;
use crate::planner::logical_plan::LogicalPlan;
use crate::Database;
use std::sync::Arc;

fn build_optimizer() -> LogicalOptimizer {
LogicalOptimizer::with_rules(vec![Arc::new(EliminateLimit)])
}
#[test]
fn eliminate_limit() {
let mut db = Database::new_temp().unwrap();
db.run("create table t1 (a int)").unwrap();

let plan = db.create_logical_plan("select a from t1 limit 0").unwrap();
let optimized_plan = build_optimizer().optimize(&plan).unwrap();
assert!(matches!(optimized_plan, LogicalPlan::EmptyRelation(_)));

let plan = db.create_logical_plan("select a from t1 offset 0").unwrap();
let optimized_plan = build_optimizer().optimize(&plan).unwrap();
if let LogicalPlan::Project(p) = optimized_plan {
assert!(matches!(p.input.as_ref(), LogicalPlan::TableScan(_)));
} else {
panic!("the first node should be project");
}
}
}
7 changes: 4 additions & 3 deletions bustubx/src/planner/logical_plan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ mod table_scan;
mod util;
mod values;

use crate::catalog::{SchemaRef, EMPTY_SCHEMA_REF, INSERT_OUTPUT_SCHEMA_REF};
use crate::{BustubxError, BustubxResult};
pub use create_index::CreateIndex;
pub use create_table::CreateTable;
pub use empty_relation::EmptyRelation;
Expand All @@ -22,11 +20,14 @@ pub use join::{Join, JoinType};
pub use limit::Limit;
pub use project::Project;
pub use sort::{OrderByExpr, Sort};
use std::sync::Arc;
pub use table_scan::TableScan;
pub use util::*;
pub use values::Values;

use crate::catalog::{SchemaRef, EMPTY_SCHEMA_REF, INSERT_OUTPUT_SCHEMA_REF};
use crate::{BustubxError, BustubxResult};
use std::sync::Arc;

#[derive(Debug, Clone)]
pub enum LogicalPlan {
CreateTable(CreateTable),
Expand Down

0 comments on commit d5d70a2

Please sign in to comment.