surrealpatch/lib/src/idx/planner/mod.rs
2023-07-06 14:57:42 +00:00

106 lines
2.6 KiB
Rust

pub(crate) mod executor;
pub(crate) mod plan;
mod tree;
use crate::ctx::Context;
use crate::dbs::{Iterable, Options, Transaction};
use crate::err::Error;
use crate::idx::planner::executor::QueryExecutor;
use crate::idx::planner::plan::{Plan, PlanBuilder};
use crate::idx::planner::tree::{Node, Tree};
use crate::sql::{Cond, Operator, Table};
use std::collections::HashMap;
pub(crate) struct QueryPlanner<'a> {
opt: &'a Options,
cond: &'a Option<Cond>,
/// There is one executor per table
executors: HashMap<String, QueryExecutor>,
}
impl<'a> QueryPlanner<'a> {
pub(crate) fn new(opt: &'a Options, cond: &'a Option<Cond>) -> Self {
Self {
opt,
cond,
executors: HashMap::default(),
}
}
pub(crate) async fn get_iterable(
&mut self,
ctx: &Context<'_>,
txn: &Transaction,
t: Table,
) -> Result<Iterable, Error> {
let res = Tree::build(ctx, self.opt, txn, &t, self.cond).await?;
if let Some((node, im)) = res {
if let Some(plan) = AllAndStrategy::build(&node)? {
let e = QueryExecutor::new(self.opt, txn, &t, im, Some(plan.e.clone())).await?;
self.executors.insert(t.0.clone(), e);
return Ok(Iterable::Index(t, plan));
}
let e = QueryExecutor::new(self.opt, txn, &t, im, None).await?;
self.executors.insert(t.0.clone(), e);
}
Ok(Iterable::Table(t))
}
pub(crate) fn finish(self) -> Option<HashMap<String, QueryExecutor>> {
if self.executors.is_empty() {
None
} else {
Some(self.executors)
}
}
}
struct AllAndStrategy {
b: PlanBuilder,
}
/// Successful if every boolean operators are AND
/// and there is at least one condition covered by an index
impl AllAndStrategy {
fn build(node: &Node) -> Result<Option<Plan>, Error> {
let mut s = AllAndStrategy {
b: PlanBuilder::default(),
};
match s.eval_node(node) {
Ok(_) => match s.b.build() {
Ok(p) => Ok(Some(p)),
Err(Error::BypassQueryPlanner) => Ok(None),
Err(e) => Err(e),
},
Err(Error::BypassQueryPlanner) => Ok(None),
Err(e) => Err(e),
}
}
fn eval_node(&mut self, node: &Node) -> Result<(), Error> {
match node {
Node::Expression {
io: index_option,
left,
right,
exp: expression,
} => {
if let Some(io) = index_option {
self.b.add_index_option(expression.clone(), io.clone());
}
self.eval_expression(left, right, expression.operator())
}
Node::Unsupported => Err(Error::BypassQueryPlanner),
_ => Ok(()),
}
}
fn eval_expression(&mut self, left: &Node, right: &Node, op: &Operator) -> Result<(), Error> {
if op.eq(&Operator::Or) {
return Err(Error::BypassQueryPlanner);
}
self.eval_node(left)?;
self.eval_node(right)?;
Ok(())
}
}