2023-06-19 18:41:13 +00:00
|
|
|
use crate::err::Error;
|
2023-07-20 12:56:32 +00:00
|
|
|
use crate::idx::ft::MatchRef;
|
2023-09-12 15:43:32 +00:00
|
|
|
use crate::idx::planner::tree::{IndexRef, Node};
|
2023-07-21 18:41:36 +00:00
|
|
|
use crate::sql::with::With;
|
2023-08-01 07:30:13 +00:00
|
|
|
use crate::sql::{Array, Object};
|
2023-07-20 12:56:32 +00:00
|
|
|
use crate::sql::{Expression, Idiom, Operator, Value};
|
2023-09-12 15:43:32 +00:00
|
|
|
use std::collections::hash_map::Entry;
|
|
|
|
use std::collections::{HashMap, HashSet};
|
2023-06-23 20:26:19 +00:00
|
|
|
use std::hash::Hash;
|
|
|
|
use std::sync::Arc;
|
2023-06-19 18:41:13 +00:00
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
pub(super) struct PlanBuilder {
|
|
|
|
indexes: Vec<(Arc<Expression>, IndexOption)>,
|
|
|
|
range_queries: HashMap<IndexRef, RangeQueryBuilder>,
|
|
|
|
with_indexes: Vec<IndexRef>,
|
2023-07-20 12:56:32 +00:00
|
|
|
all_and: bool,
|
|
|
|
all_exp_with_index: bool,
|
2023-06-19 18:41:13 +00:00
|
|
|
}
|
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
impl PlanBuilder {
|
|
|
|
pub(super) fn build(
|
|
|
|
root: Node,
|
|
|
|
with: &Option<With>,
|
|
|
|
with_indexes: Vec<IndexRef>,
|
|
|
|
) -> Result<Plan, Error> {
|
|
|
|
if let Some(With::NoIndex) = with {
|
|
|
|
return Ok(Plan::TableIterator(Some("WITH NOINDEX".to_string())));
|
2023-07-21 18:41:36 +00:00
|
|
|
}
|
2023-07-20 12:56:32 +00:00
|
|
|
let mut b = PlanBuilder {
|
|
|
|
indexes: Vec::new(),
|
2023-09-12 15:43:32 +00:00
|
|
|
range_queries: HashMap::new(),
|
|
|
|
with_indexes,
|
2023-07-20 12:56:32 +00:00
|
|
|
all_and: true,
|
|
|
|
all_exp_with_index: true,
|
|
|
|
};
|
|
|
|
// Browse the AST and collect information
|
2023-09-07 23:36:39 +00:00
|
|
|
if let Err(e) = b.eval_node(root) {
|
|
|
|
return Ok(Plan::TableIterator(Some(e.to_string())));
|
2023-07-21 18:41:36 +00:00
|
|
|
}
|
2023-07-20 12:56:32 +00:00
|
|
|
// If we didn't found any index, we're done with no index plan
|
|
|
|
if b.indexes.is_empty() {
|
2023-09-07 23:36:39 +00:00
|
|
|
return Ok(Plan::TableIterator(Some("NO INDEX FOUND".to_string())));
|
2023-07-20 12:56:32 +00:00
|
|
|
}
|
2023-09-12 15:43:32 +00:00
|
|
|
|
2023-07-20 12:56:32 +00:00
|
|
|
// If every boolean operator are AND then we can use the single index plan
|
|
|
|
if b.all_and {
|
2023-09-12 15:43:32 +00:00
|
|
|
// TODO: This is currently pretty arbitrary
|
|
|
|
// We take the "first" range query if one is available
|
|
|
|
if let Some((ir, rq)) = b.range_queries.drain().take(1).next() {
|
|
|
|
return Ok(Plan::SingleIndexMultiExpression(ir, rq));
|
|
|
|
}
|
|
|
|
// Otherwise we take the first single index option
|
2023-07-20 12:56:32 +00:00
|
|
|
if let Some((e, i)) = b.indexes.pop() {
|
|
|
|
return Ok(Plan::SingleIndex(e, i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If every expression is backed by an index with can use the MultiIndex plan
|
|
|
|
if b.all_exp_with_index {
|
|
|
|
return Ok(Plan::MultiIndex(b.indexes));
|
|
|
|
}
|
2023-09-07 23:36:39 +00:00
|
|
|
Ok(Plan::TableIterator(None))
|
2023-07-21 18:41:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we have an explicit list of index we can use
|
|
|
|
fn filter_index_option(&self, io: Option<IndexOption>) -> Option<IndexOption> {
|
|
|
|
if let Some(io) = &io {
|
2023-09-12 15:43:32 +00:00
|
|
|
if !self.with_indexes.is_empty() && !self.with_indexes.contains(&io.ir()) {
|
|
|
|
return None;
|
2023-07-21 18:41:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
io
|
2023-06-19 18:41:13 +00:00
|
|
|
}
|
|
|
|
|
2023-09-07 23:36:39 +00:00
|
|
|
fn eval_node(&mut self, node: Node) -> Result<(), String> {
|
2023-07-20 12:56:32 +00:00
|
|
|
match node {
|
|
|
|
Node::Expression {
|
|
|
|
io,
|
|
|
|
left,
|
|
|
|
right,
|
|
|
|
exp,
|
|
|
|
} => {
|
|
|
|
if self.all_and && Operator::Or.eq(exp.operator()) {
|
|
|
|
self.all_and = false;
|
|
|
|
}
|
|
|
|
let is_bool = self.check_boolean_operator(exp.operator());
|
2023-07-21 18:41:36 +00:00
|
|
|
if let Some(io) = self.filter_index_option(io) {
|
2023-07-20 12:56:32 +00:00
|
|
|
self.add_index_option(exp, io);
|
|
|
|
} else if self.all_exp_with_index && !is_bool {
|
|
|
|
self.all_exp_with_index = false;
|
|
|
|
}
|
2023-09-07 23:36:39 +00:00
|
|
|
self.eval_node(*left)?;
|
|
|
|
self.eval_node(*right)?;
|
|
|
|
Ok(())
|
2023-07-20 12:56:32 +00:00
|
|
|
}
|
2023-09-07 23:36:39 +00:00
|
|
|
Node::Unsupported(reason) => Err(reason),
|
|
|
|
_ => Ok(()),
|
2023-06-19 18:41:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-20 12:56:32 +00:00
|
|
|
fn check_boolean_operator(&mut self, op: &Operator) -> bool {
|
|
|
|
match op {
|
|
|
|
Operator::Neg | Operator::Or => {
|
|
|
|
if self.all_and {
|
|
|
|
self.all_and = false;
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
|
|
|
Operator::And => true,
|
|
|
|
_ => false,
|
2023-06-23 20:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
fn add_index_option(&mut self, exp: Arc<Expression>, io: IndexOption) {
|
|
|
|
if let IndexOperator::RangePart(o, v) = io.op() {
|
|
|
|
match self.range_queries.entry(io.ir()) {
|
|
|
|
Entry::Occupied(mut e) => {
|
|
|
|
e.get_mut().add(exp.clone(), o, v);
|
|
|
|
}
|
|
|
|
Entry::Vacant(e) => {
|
|
|
|
let mut b = RangeQueryBuilder::default();
|
|
|
|
b.add(exp.clone(), o, v);
|
|
|
|
e.insert(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.indexes.push((exp, io));
|
2023-06-19 18:41:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-20 12:56:32 +00:00
|
|
|
pub(super) enum Plan {
|
2023-09-07 23:36:39 +00:00
|
|
|
TableIterator(Option<String>),
|
2023-09-12 15:43:32 +00:00
|
|
|
SingleIndex(Arc<Expression>, IndexOption),
|
|
|
|
MultiIndex(Vec<(Arc<Expression>, IndexOption)>),
|
|
|
|
SingleIndexMultiExpression(IndexRef, RangeQueryBuilder),
|
2023-07-20 12:56:32 +00:00
|
|
|
}
|
|
|
|
|
2023-06-19 18:41:13 +00:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
2023-07-20 12:56:32 +00:00
|
|
|
pub(crate) struct IndexOption(Arc<Inner>);
|
2023-06-23 20:26:19 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Eq, PartialEq, Hash)]
|
|
|
|
pub(super) struct Inner {
|
2023-09-12 15:43:32 +00:00
|
|
|
ir: IndexRef,
|
2023-06-23 20:26:19 +00:00
|
|
|
id: Idiom,
|
2023-09-12 15:43:32 +00:00
|
|
|
op: IndexOperator,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Eq, PartialEq, Hash)]
|
|
|
|
pub(super) enum IndexOperator {
|
|
|
|
Equality(Array),
|
|
|
|
RangePart(Operator, Value),
|
|
|
|
Matches(String, Option<MatchRef>),
|
2023-06-19 18:41:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl IndexOption {
|
2023-09-12 15:43:32 +00:00
|
|
|
pub(super) fn new(ir: IndexRef, id: Idiom, op: IndexOperator) -> Self {
|
2023-06-23 20:26:19 +00:00
|
|
|
Self(Arc::new(Inner {
|
2023-09-12 15:43:32 +00:00
|
|
|
ir,
|
2023-06-23 20:26:19 +00:00
|
|
|
id,
|
2023-06-19 18:41:13 +00:00
|
|
|
op,
|
2023-06-23 20:26:19 +00:00
|
|
|
}))
|
2023-06-19 18:41:13 +00:00
|
|
|
}
|
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
pub(super) fn ir(&self) -> IndexRef {
|
|
|
|
self.0.ir
|
2023-06-23 20:26:19 +00:00
|
|
|
}
|
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
pub(super) fn op(&self) -> &IndexOperator {
|
2023-06-23 20:26:19 +00:00
|
|
|
&self.0.op
|
|
|
|
}
|
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
pub(super) fn id(&self) -> &Idiom {
|
|
|
|
&self.0.id
|
2023-06-23 20:26:19 +00:00
|
|
|
}
|
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
pub(crate) fn explain(&self, e: &mut HashMap<&str, Value>) {
|
|
|
|
match self.op() {
|
|
|
|
IndexOperator::Equality(a) => {
|
|
|
|
let v = if a.len() == 1 {
|
|
|
|
a[0].clone()
|
|
|
|
} else {
|
|
|
|
Value::Array(a.clone())
|
|
|
|
};
|
|
|
|
e.insert("operator", Value::from(Operator::Equal.to_string()));
|
|
|
|
e.insert("value", v);
|
|
|
|
}
|
|
|
|
IndexOperator::Matches(qs, a) => {
|
|
|
|
e.insert("operator", Value::from(Operator::Matches(*a).to_string()));
|
|
|
|
e.insert("value", Value::from(qs.to_owned()));
|
|
|
|
}
|
|
|
|
IndexOperator::RangePart(op, v) => {
|
|
|
|
e.insert("operator", Value::from(op.to_string()));
|
|
|
|
e.insert("value", v.to_owned());
|
|
|
|
}
|
|
|
|
};
|
2023-06-23 20:26:19 +00:00
|
|
|
}
|
2023-09-12 15:43:32 +00:00
|
|
|
}
|
2023-06-23 20:26:19 +00:00
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
#[derive(Debug, Default, Eq, PartialEq, Hash)]
|
|
|
|
pub(super) struct RangeValue {
|
|
|
|
pub(super) value: Value,
|
|
|
|
pub(super) inclusive: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RangeValue {
|
|
|
|
fn set_to(&mut self, v: &Value) {
|
|
|
|
if self.value.is_none() {
|
|
|
|
self.value = v.clone();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if self.value.lt(v) {
|
|
|
|
self.value = v.clone();
|
|
|
|
self.inclusive = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_to_inclusive(&mut self, v: &Value) {
|
|
|
|
if self.value.is_none() {
|
|
|
|
self.value = v.clone();
|
|
|
|
self.inclusive = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if self.inclusive {
|
|
|
|
if self.value.lt(v) {
|
|
|
|
self.value = v.clone();
|
|
|
|
}
|
|
|
|
} else if self.value.le(v) {
|
|
|
|
self.value = v.clone();
|
|
|
|
self.inclusive = true;
|
|
|
|
}
|
2023-06-23 20:26:19 +00:00
|
|
|
}
|
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
fn set_from(&mut self, v: &Value) {
|
|
|
|
if self.value.is_none() {
|
|
|
|
self.value = v.clone();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if self.value.gt(v) {
|
|
|
|
self.value = v.clone();
|
|
|
|
self.inclusive = false;
|
|
|
|
}
|
2023-06-19 18:41:13 +00:00
|
|
|
}
|
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
fn set_from_inclusive(&mut self, v: &Value) {
|
|
|
|
if self.value.is_none() {
|
|
|
|
self.value = v.clone();
|
|
|
|
self.inclusive = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if self.inclusive {
|
|
|
|
if self.value.gt(v) {
|
|
|
|
self.value = v.clone();
|
|
|
|
}
|
|
|
|
} else if self.value.ge(v) {
|
|
|
|
self.value = v.clone();
|
|
|
|
self.inclusive = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&RangeValue> for Value {
|
|
|
|
fn from(rv: &RangeValue) -> Self {
|
|
|
|
Value::from(Object::from(HashMap::from([
|
|
|
|
("value", rv.value.to_owned()),
|
|
|
|
("inclusive", Value::from(rv.inclusive)),
|
2023-07-20 12:56:32 +00:00
|
|
|
])))
|
2023-06-19 18:41:13 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-23 20:26:19 +00:00
|
|
|
|
2023-09-12 15:43:32 +00:00
|
|
|
#[derive(Default, Debug)]
|
|
|
|
pub(super) struct RangeQueryBuilder {
|
|
|
|
pub(super) exps: HashSet<Arc<Expression>>,
|
|
|
|
pub(super) from: RangeValue,
|
|
|
|
pub(super) to: RangeValue,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RangeQueryBuilder {
|
|
|
|
fn add(&mut self, exp: Arc<Expression>, op: &Operator, v: &Value) {
|
|
|
|
match op {
|
|
|
|
Operator::LessThan => self.to.set_to(v),
|
|
|
|
Operator::LessThanOrEqual => self.to.set_to_inclusive(v),
|
|
|
|
Operator::MoreThan => self.from.set_from(v),
|
|
|
|
Operator::MoreThanOrEqual => self.from.set_from_inclusive(v),
|
|
|
|
_ => return,
|
|
|
|
}
|
|
|
|
self.exps.insert(exp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-23 20:26:19 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2023-09-12 15:43:32 +00:00
|
|
|
use crate::idx::planner::plan::{IndexOperator, IndexOption, RangeValue};
|
|
|
|
use crate::sql::{Array, Idiom, Value};
|
2023-06-23 20:26:19 +00:00
|
|
|
use std::collections::HashSet;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_hash_index_option() {
|
|
|
|
let mut set = HashSet::new();
|
|
|
|
let io1 = IndexOption::new(
|
2023-09-12 15:43:32 +00:00
|
|
|
1,
|
2023-06-23 20:26:19 +00:00
|
|
|
Idiom::from("a.b".to_string()),
|
2023-09-12 15:43:32 +00:00
|
|
|
IndexOperator::Equality(Array::from(vec!["test"])),
|
2023-06-23 20:26:19 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let io2 = IndexOption::new(
|
2023-09-12 15:43:32 +00:00
|
|
|
1,
|
2023-06-23 20:26:19 +00:00
|
|
|
Idiom::from("a.b".to_string()),
|
2023-09-12 15:43:32 +00:00
|
|
|
IndexOperator::Equality(Array::from(vec!["test"])),
|
2023-06-23 20:26:19 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
set.insert(io1);
|
|
|
|
set.insert(io2.clone());
|
|
|
|
set.insert(io2);
|
|
|
|
|
|
|
|
assert_eq!(set.len(), 1);
|
|
|
|
}
|
2023-09-12 15:43:32 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_range_default_value() {
|
|
|
|
let r = RangeValue::default();
|
|
|
|
assert_eq!(r.value, Value::None);
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_range_value_from_inclusive() {
|
|
|
|
let mut r = RangeValue::default();
|
|
|
|
r.set_from_inclusive(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
r.set_from_inclusive(&10.into());
|
|
|
|
assert_eq!(r.value, 10.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
r.set_from_inclusive(&20.into());
|
|
|
|
assert_eq!(r.value, 10.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_range_value_from() {
|
|
|
|
let mut r = RangeValue::default();
|
|
|
|
r.set_from(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
r.set_from(&10.into());
|
|
|
|
assert_eq!(r.value, 10.into());
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
r.set_from(&20.into());
|
|
|
|
assert_eq!(r.value, 10.into());
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_range_value_to_inclusive() {
|
|
|
|
let mut r = RangeValue::default();
|
|
|
|
r.set_to_inclusive(&10.into());
|
|
|
|
assert_eq!(r.value, 10.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
r.set_to_inclusive(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
r.set_to_inclusive(&10.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_range_value_to() {
|
|
|
|
let mut r = RangeValue::default();
|
|
|
|
r.set_to(&10.into());
|
|
|
|
assert_eq!(r.value, 10.into());
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
r.set_to(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
r.set_to(&10.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_range_value_to_switch_inclusive() {
|
|
|
|
let mut r = RangeValue::default();
|
|
|
|
r.set_to(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
r.set_to_inclusive(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
r.set_to(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_range_value_from_switch_inclusive() {
|
|
|
|
let mut r = RangeValue::default();
|
|
|
|
r.set_from(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, false);
|
|
|
|
r.set_from_inclusive(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
r.set_from(&20.into());
|
|
|
|
assert_eq!(r.value, 20.into());
|
|
|
|
assert_eq!(r.inclusive, true);
|
|
|
|
}
|
2023-06-23 20:26:19 +00:00
|
|
|
}
|