Skip to content

Commit

Permalink
feat: ExecutionContext introduced
Browse files Browse the repository at this point in the history
  • Loading branch information
can-keklik committed Nov 18, 2024
1 parent 43a36b5 commit 85973bd
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 25 deletions.
4 changes: 0 additions & 4 deletions lykiadb-lang/src/ast/visitor.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
use super::{expr::Expr, stmt::Stmt};

pub trait ExprEvaluator<O, E> {
fn eval(&mut self, e: &Expr) -> Result<O, E>;
}

pub trait Visitor<O, E> {
fn visit_expr(&self, e: &Expr) -> Result<O, E>;
fn visit_stmt(&self, s: &Stmt) -> Result<O, E>;
Expand Down
28 changes: 23 additions & 5 deletions lykiadb-server/src/engine/interpreter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use lykiadb_lang::ast::expr::{Expr, Operation, RangeKind};
use lykiadb_lang::ast::stmt::Stmt;
use lykiadb_lang::ast::visitor::{ExprEvaluator, VisitorMut};
use lykiadb_lang::ast::visitor::VisitorMut;
use lykiadb_lang::parser::program::Program;
use lykiadb_lang::parser::resolver::Resolver;
use lykiadb_lang::parser::Parser;
Expand All @@ -12,6 +12,7 @@ use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};

use super::error::ExecutionError;
use super::stdlib::stdlib;

use crate::plan::planner::Planner;
use crate::util::{alloc_shared, Shared};
Expand Down Expand Up @@ -177,9 +178,26 @@ pub struct Interpreter {
current_program: Option<Arc<Program>>,
}

impl ExprEvaluator<RV, HaltReason> for Interpreter {
fn eval(&mut self, e: &Expr) -> Result<RV, HaltReason> {
self.visit_expr(e)
pub struct ExecutionContext {
interpreter: Shared<Interpreter>
}

impl ExecutionContext {
pub fn new(out: Option<Shared<Output>>) -> ExecutionContext {
let mut env_man = Environment::new();
let native_fns = stdlib(out.clone());
let env = env_man.top();

for (name, value) in native_fns {
env_man.declare(env, name.to_string(), value);
}
ExecutionContext {
interpreter: alloc_shared(Interpreter::new(alloc_shared(env_man))),
}
}

pub fn eval(&mut self, e: &Expr) -> Result<RV, HaltReason> {
self.interpreter.write().unwrap().visit_expr(e)
}
}

Expand Down Expand Up @@ -326,7 +344,7 @@ impl VisitorMut<RV, HaltReason> for Interpreter {
| Expr::Insert { .. }
| Expr::Update { .. }
| Expr::Delete { .. } => {
let mut planner = Planner::new();
let mut planner = Planner::new(ExecutionContext::new(None));

Check warning on line 347 in lykiadb-server/src/engine/interpreter.rs

View check run for this annotation

Codecov / codecov/patch

lykiadb-server/src/engine/interpreter.rs#L347

Added line #L347 was not covered by tests
let plan = planner.build(e)?;
Ok(RV::Undefined)
}
Expand Down
8 changes: 8 additions & 0 deletions lykiadb-server/src/plan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ impl Node {
source._fmt_recursive(f, indent + 1)?;
right._fmt_recursive(f, indent + 1)
}
Node::Limit { source, limit } => {
write!(f, "{}- limit {}{}", indent_str, limit, Self::NEWLINE)?;
source._fmt_recursive(f, indent + 1)
}
Node::Offset { source, offset } => {
write!(f, "{}- offset {}{}", indent_str, offset, Self::NEWLINE)?;
source._fmt_recursive(f, indent + 1)
}
Node::Join {
left,
join_type,
Expand Down
35 changes: 21 additions & 14 deletions lykiadb-server/src/plan/planner.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
use crate::engine::interpreter::HaltReason;
use crate::engine::interpreter::{ExecutionContext, HaltReason};
use lykiadb_lang::ast::{
expr::Expr,
sql::{SqlFrom, SqlJoinType, SqlSelect, SqlSelectCore},
sql::{SqlFrom, SqlJoinType, SqlSelect, SqlSelectCore}
};

use super::{Node, Plan};
pub struct Planner;

impl Default for Planner {
fn default() -> Self {
Self::new()
}
pub struct Planner {
context: ExecutionContext
}

impl Planner {
pub fn new() -> Planner {
Planner {}
pub fn new(ctx: ExecutionContext) -> Planner {
Planner {
context: ctx
}
}

pub fn build(&mut self, expr: &Expr) -> Result<Plan, HaltReason> {
Expand Down Expand Up @@ -62,10 +60,16 @@ impl Planner {
fn build_select(&mut self, query: &SqlSelect) -> Result<Node, HaltReason> {
let mut node: Node = self.build_select_core(&query.core)?;



// ORDER BY
// LIMIT/OFFSET

if let Some(limit) = &query.limit {
if let Some(offset) = &limit.offset {
node = Node::Offset { source: Box::new(node), offset: self.context.eval(&offset)?.as_number().expect("Offset is not correct").floor() as usize }
}

node = Node::Limit { source: Box::new(node), limit: self.context.eval(&limit.count)?.as_number().expect("Limit is not correct").floor() as usize }
}

Ok(node)
}

Expand Down Expand Up @@ -114,10 +118,13 @@ impl Planner {
pub mod test_helpers {
use lykiadb_lang::{ast::stmt::Stmt, parser::program::Program};

use crate::engine::interpreter::ExecutionContext;

use super::Planner;

pub fn expect_plan(query: &str, expected_plan: &str) {
let mut planner = Planner::new();
let ctx = ExecutionContext::new(None);
let mut planner = Planner::new(ctx);

Check warning on line 127 in lykiadb-server/src/plan/planner.rs

View check run for this annotation

Codecov / codecov/patch

lykiadb-server/src/plan/planner.rs#L126-L127

Added lines #L126 - L127 were not covered by tests
let program = query.parse::<Program>().unwrap();
match *program.get_root() {
Stmt::Program { body, .. } if matches!(body.get(0), Some(Stmt::Expression { .. })) => {
Expand Down
16 changes: 16 additions & 0 deletions lykiadb-server/tests/planner/limit_offset
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#[name=limit, run=plan]>

SELECT * FROM books limit 4 + 4;

---
- limit 8
- scan [books as books]

#[name=limit, run=plan]>

SELECT * FROM books limit 5 + 5 offset 5 + 15;

---
- limit 10
- offset 20
- scan [books as books]
5 changes: 3 additions & 2 deletions lykiadb-server/tests/util.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use lykiadb_lang::{ast::stmt::Stmt, parser::program::Program};
use lykiadb_server::plan::planner::Planner;
use lykiadb_server::{engine::interpreter::ExecutionContext, plan::planner::Planner};
use pretty_assertions::assert_eq;

fn expect_plan(query: &str, expected_plan: &str) {
let mut planner = Planner::new();
let ctx = ExecutionContext::new(None);
let mut planner = Planner::new(ctx);
let program = query.parse::<Program>().unwrap();
match *program.get_root() {
Stmt::Program { body, .. } if matches!(body.get(0), Some(Stmt::Expression { .. })) => {
Expand Down

0 comments on commit 85973bd

Please sign in to comment.