Makes nested PlanNode easy to clone

pull/470/head
Tpt 2 years ago committed by Thomas Tanon
parent 9dc1106b9a
commit 81793bc221
  1. 55
      lib/src/sparql/eval.rs
  2. 8
      lib/src/sparql/mod.rs
  3. 44
      lib/src/sparql/plan.rs
  4. 126
      lib/src/sparql/plan_builder.rs
  5. 3
      lib/src/sparql/update.rs

@ -60,14 +60,14 @@ impl SimpleEvaluator {
pub fn evaluate_select_plan( pub fn evaluate_select_plan(
&self, &self,
plan: &PlanNode, plan: Rc<PlanNode>,
variables: Rc<Vec<Variable>>, variables: Rc<Vec<Variable>>,
) -> QueryResults { ) -> QueryResults {
let iter = self.plan_evaluator(plan)(EncodedTuple::with_capacity(variables.len())); let iter = self.plan_evaluator(plan)(EncodedTuple::with_capacity(variables.len()));
QueryResults::Solutions(decode_bindings(self.dataset.clone(), iter, variables)) QueryResults::Solutions(decode_bindings(self.dataset.clone(), iter, variables))
} }
pub fn evaluate_ask_plan(&self, plan: &PlanNode) -> Result<QueryResults, EvaluationError> { pub fn evaluate_ask_plan(&self, plan: Rc<PlanNode>) -> Result<QueryResults, EvaluationError> {
let from = EncodedTuple::with_capacity(plan.used_variables().len()); let from = EncodedTuple::with_capacity(plan.used_variables().len());
match self.plan_evaluator(plan)(from).next() { match self.plan_evaluator(plan)(from).next() {
Some(Ok(_)) => Ok(QueryResults::Boolean(true)), Some(Ok(_)) => Ok(QueryResults::Boolean(true)),
@ -78,7 +78,7 @@ impl SimpleEvaluator {
pub fn evaluate_construct_plan( pub fn evaluate_construct_plan(
&self, &self,
plan: &PlanNode, plan: Rc<PlanNode>,
template: Vec<TripleTemplate>, template: Vec<TripleTemplate>,
) -> QueryResults { ) -> QueryResults {
let from = EncodedTuple::with_capacity(plan.used_variables().len()); let from = EncodedTuple::with_capacity(plan.used_variables().len());
@ -93,7 +93,7 @@ impl SimpleEvaluator {
}) })
} }
pub fn evaluate_describe_plan(&self, plan: &PlanNode) -> QueryResults { pub fn evaluate_describe_plan(&self, plan: Rc<PlanNode>) -> QueryResults {
let from = EncodedTuple::with_capacity(plan.used_variables().len()); let from = EncodedTuple::with_capacity(plan.used_variables().len());
QueryResults::Graph(QueryTripleIter { QueryResults::Graph(QueryTripleIter {
iter: Box::new(DescribeIterator { iter: Box::new(DescribeIterator {
@ -106,9 +106,9 @@ impl SimpleEvaluator {
pub fn plan_evaluator( pub fn plan_evaluator(
&self, &self,
node: &PlanNode, node: Rc<PlanNode>,
) -> Rc<dyn Fn(EncodedTuple) -> EncodedTuplesIterator> { ) -> Rc<dyn Fn(EncodedTuple) -> EncodedTuplesIterator> {
match node { match node.as_ref() {
PlanNode::StaticBindings { encoded_tuples, .. } => { PlanNode::StaticBindings { encoded_tuples, .. } => {
let tuples = encoded_tuples.clone(); let tuples = encoded_tuples.clone();
Rc::new(move |from| { Rc::new(move |from| {
@ -348,8 +348,8 @@ impl SimpleEvaluator {
.intersection(&right.always_bound_variables()) .intersection(&right.always_bound_variables())
.copied() .copied()
.collect(); .collect();
let left = self.plan_evaluator(left); let left = self.plan_evaluator(left.clone());
let right = self.plan_evaluator(right); let right = self.plan_evaluator(right.clone());
if join_keys.is_empty() { if join_keys.is_empty() {
// Cartesian product // Cartesian product
Rc::new(move |from| { Rc::new(move |from| {
@ -392,8 +392,8 @@ impl SimpleEvaluator {
} }
} }
PlanNode::ForLoopJoin { left, right } => { PlanNode::ForLoopJoin { left, right } => {
let left = self.plan_evaluator(left); let left = self.plan_evaluator(left.clone());
let right = self.plan_evaluator(right); let right = self.plan_evaluator(right.clone());
Rc::new(move |from| { Rc::new(move |from| {
let right = right.clone(); let right = right.clone();
Box::new(left(from).flat_map(move |t| match t { Box::new(left(from).flat_map(move |t| match t {
@ -408,8 +408,8 @@ impl SimpleEvaluator {
.intersection(&right.always_bound_variables()) .intersection(&right.always_bound_variables())
.copied() .copied()
.collect(); .collect();
let left = self.plan_evaluator(left); let left = self.plan_evaluator(left.clone());
let right = self.plan_evaluator(right); let right = self.plan_evaluator(right.clone());
if join_keys.is_empty() { if join_keys.is_empty() {
Rc::new(move |from| { Rc::new(move |from| {
let right: Vec<_> = right(from.clone()).filter_map(Result::ok).collect(); let right: Vec<_> = right(from.clone()).filter_map(Result::ok).collect();
@ -449,8 +449,8 @@ impl SimpleEvaluator {
.intersection(&right.always_bound_variables()) .intersection(&right.always_bound_variables())
.copied() .copied()
.collect(); .collect();
let left = self.plan_evaluator(left); let left = self.plan_evaluator(left.clone());
let right = self.plan_evaluator(right); let right = self.plan_evaluator(right.clone());
let expression = self.expression_evaluator(expression); let expression = self.expression_evaluator(expression);
// Real hash join // Real hash join
Rc::new(move |from| { Rc::new(move |from| {
@ -476,8 +476,8 @@ impl SimpleEvaluator {
right, right,
possible_problem_vars, possible_problem_vars,
} => { } => {
let left = self.plan_evaluator(left); let left = self.plan_evaluator(left.clone());
let right = self.plan_evaluator(right); let right = self.plan_evaluator(right.clone());
let possible_problem_vars = possible_problem_vars.clone(); let possible_problem_vars = possible_problem_vars.clone();
Rc::new(move |from| { Rc::new(move |from| {
if possible_problem_vars.is_empty() { if possible_problem_vars.is_empty() {
@ -499,7 +499,7 @@ impl SimpleEvaluator {
}) })
} }
PlanNode::Filter { child, expression } => { PlanNode::Filter { child, expression } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
let expression = self.expression_evaluator(expression); let expression = self.expression_evaluator(expression);
Rc::new(move |from| { Rc::new(move |from| {
let expression = expression.clone(); let expression = expression.clone();
@ -516,7 +516,7 @@ impl SimpleEvaluator {
PlanNode::Union { children } => { PlanNode::Union { children } => {
let children: Vec<_> = children let children: Vec<_> = children
.iter() .iter()
.map(|child| self.plan_evaluator(child)) .map(|child| self.plan_evaluator(child.clone()))
.collect(); .collect();
Rc::new(move |from| { Rc::new(move |from| {
Box::new(UnionIterator { Box::new(UnionIterator {
@ -532,7 +532,7 @@ impl SimpleEvaluator {
variable, variable,
expression, expression,
} => { } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
let position = variable.encoded; let position = variable.encoded;
let expression = self.expression_evaluator(expression); let expression = self.expression_evaluator(expression);
Rc::new(move |from| { Rc::new(move |from| {
@ -547,7 +547,7 @@ impl SimpleEvaluator {
}) })
} }
PlanNode::Sort { child, by } => { PlanNode::Sort { child, by } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
let by: Vec<_> = by let by: Vec<_> = by
.iter() .iter()
.map(|comp| match comp { .map(|comp| match comp {
@ -604,11 +604,11 @@ impl SimpleEvaluator {
}) })
} }
PlanNode::HashDeduplicate { child } => { PlanNode::HashDeduplicate { child } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
Rc::new(move |from| Box::new(hash_deduplicate(child(from)))) Rc::new(move |from| Box::new(hash_deduplicate(child(from))))
} }
PlanNode::Reduced { child } => { PlanNode::Reduced { child } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
Rc::new(move |from| { Rc::new(move |from| {
Box::new(ConsecutiveDeduplication { Box::new(ConsecutiveDeduplication {
inner: child(from), inner: child(from),
@ -617,17 +617,17 @@ impl SimpleEvaluator {
}) })
} }
PlanNode::Skip { child, count } => { PlanNode::Skip { child, count } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
let count = *count; let count = *count;
Rc::new(move |from| Box::new(child(from).skip(count))) Rc::new(move |from| Box::new(child(from).skip(count)))
} }
PlanNode::Limit { child, count } => { PlanNode::Limit { child, count } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
let count = *count; let count = *count;
Rc::new(move |from| Box::new(child(from).take(count))) Rc::new(move |from| Box::new(child(from).take(count)))
} }
PlanNode::Project { child, mapping } => { PlanNode::Project { child, mapping } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
let mapping = mapping.clone(); let mapping = mapping.clone();
Rc::new(move |from| { Rc::new(move |from| {
let mapping = mapping.clone(); let mapping = mapping.clone();
@ -666,7 +666,7 @@ impl SimpleEvaluator {
key_variables, key_variables,
aggregates, aggregates,
} => { } => {
let child = self.plan_evaluator(child); let child = self.plan_evaluator(child.clone());
let key_variables = key_variables.clone(); let key_variables = key_variables.clone();
let aggregate_input_expressions: Vec<_> = aggregates let aggregate_input_expressions: Vec<_> = aggregates
.iter() .iter()
@ -864,8 +864,7 @@ impl SimpleEvaluator {
Rc::new(move |tuple| tuple.get(v).cloned()) Rc::new(move |tuple| tuple.get(v).cloned())
} }
PlanExpression::Exists(plan) => { PlanExpression::Exists(plan) => {
let plan = plan.clone(); let eval = self.plan_evaluator(plan.clone());
let eval = self.plan_evaluator(&plan);
Rc::new(move |tuple| Some(eval(tuple.clone()).next().is_some().into())) Rc::new(move |tuple| Some(eval(tuple.clone()).next().is_some().into()))
} }
PlanExpression::Or(a, b) => { PlanExpression::Or(a, b) => {

@ -56,7 +56,7 @@ pub(crate) fn evaluate_query(
options.service_handler(), options.service_handler(),
Rc::new(options.custom_functions), Rc::new(options.custom_functions),
) )
.evaluate_select_plan(&plan, Rc::new(variables))) .evaluate_select_plan(Rc::new(plan), Rc::new(variables)))
} }
spargebra::Query::Ask { spargebra::Query::Ask {
pattern, base_iri, .. pattern, base_iri, ..
@ -74,7 +74,7 @@ pub(crate) fn evaluate_query(
options.service_handler(), options.service_handler(),
Rc::new(options.custom_functions), Rc::new(options.custom_functions),
) )
.evaluate_ask_plan(&plan) .evaluate_ask_plan(Rc::new(plan))
} }
spargebra::Query::Construct { spargebra::Query::Construct {
template, template,
@ -102,7 +102,7 @@ pub(crate) fn evaluate_query(
options.service_handler(), options.service_handler(),
Rc::new(options.custom_functions), Rc::new(options.custom_functions),
) )
.evaluate_construct_plan(&plan, construct)) .evaluate_construct_plan(Rc::new(plan), construct))
} }
spargebra::Query::Describe { spargebra::Query::Describe {
pattern, base_iri, .. pattern, base_iri, ..
@ -120,7 +120,7 @@ pub(crate) fn evaluate_query(
options.service_handler(), options.service_handler(),
Rc::new(options.custom_functions), Rc::new(options.custom_functions),
) )
.evaluate_describe_plan(&plan)) .evaluate_describe_plan(Rc::new(plan)))
} }
} }
} }

@ -9,7 +9,7 @@ use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum PlanNode { pub enum PlanNode {
StaticBindings { StaticBindings {
encoded_tuples: Vec<EncodedTuple>, encoded_tuples: Vec<EncodedTuple>,
@ -19,7 +19,7 @@ pub enum PlanNode {
Service { Service {
service_name: PatternValue, service_name: PatternValue,
variables: Rc<Vec<Variable>>, variables: Rc<Vec<Variable>>,
child: Box<Self>, child: Rc<Self>,
graph_pattern: Rc<GraphPattern>, graph_pattern: Rc<GraphPattern>,
silent: bool, silent: bool,
}, },
@ -37,69 +37,69 @@ pub enum PlanNode {
}, },
/// Streams left and materializes right join /// Streams left and materializes right join
HashJoin { HashJoin {
left: Box<Self>, left: Rc<Self>,
right: Box<Self>, right: Rc<Self>,
}, },
/// Right nested in left loop /// Right nested in left loop
ForLoopJoin { ForLoopJoin {
left: Box<Self>, left: Rc<Self>,
right: Box<Self>, right: Rc<Self>,
}, },
/// Streams left and materializes right anti join /// Streams left and materializes right anti join
AntiJoin { AntiJoin {
left: Box<Self>, left: Rc<Self>,
right: Box<Self>, right: Rc<Self>,
}, },
Filter { Filter {
child: Box<Self>, child: Rc<Self>,
expression: Box<PlanExpression>, expression: Box<PlanExpression>,
}, },
Union { Union {
children: Vec<Self>, children: Vec<Rc<Self>>,
}, },
/// hash left join /// hash left join
HashLeftJoin { HashLeftJoin {
left: Box<Self>, left: Rc<Self>,
right: Box<Self>, right: Rc<Self>,
expression: Box<PlanExpression>, expression: Box<PlanExpression>,
}, },
/// right nested in left loop /// right nested in left loop
ForLoopLeftJoin { ForLoopLeftJoin {
left: Box<Self>, left: Rc<Self>,
right: Box<Self>, right: Rc<Self>,
possible_problem_vars: Rc<Vec<usize>>, //Variables that should not be part of the entry of the left join possible_problem_vars: Rc<Vec<usize>>, //Variables that should not be part of the entry of the left join
}, },
Extend { Extend {
child: Box<Self>, child: Rc<Self>,
variable: PlanVariable, variable: PlanVariable,
expression: Box<PlanExpression>, expression: Box<PlanExpression>,
}, },
Sort { Sort {
child: Box<Self>, child: Rc<Self>,
by: Vec<Comparator>, by: Vec<Comparator>,
}, },
HashDeduplicate { HashDeduplicate {
child: Box<Self>, child: Rc<Self>,
}, },
/// Removes duplicated consecutive elements /// Removes duplicated consecutive elements
Reduced { Reduced {
child: Box<Self>, child: Rc<Self>,
}, },
Skip { Skip {
child: Box<Self>, child: Rc<Self>,
count: usize, count: usize,
}, },
Limit { Limit {
child: Box<Self>, child: Rc<Self>,
count: usize, count: usize,
}, },
Project { Project {
child: Box<Self>, child: Rc<Self>,
mapping: Rc<Vec<(PlanVariable, PlanVariable)>>, // pairs of (variable key in child, variable key in output) mapping: Rc<Vec<(PlanVariable, PlanVariable)>>, // pairs of (variable key in child, variable key in output)
}, },
Aggregate { Aggregate {
// By definition the group by key are the range 0..key_mapping.len() // By definition the group by key are the range 0..key_mapping.len()
child: Box<Self>, child: Rc<Self>,
key_variables: Rc<Vec<PlanVariable>>, key_variables: Rc<Vec<PlanVariable>>,
aggregates: Rc<Vec<(PlanAggregation, PlanVariable)>>, aggregates: Rc<Vec<(PlanAggregation, PlanVariable)>>,
}, },

@ -46,7 +46,7 @@ impl<'a> PlanBuilder<'a> {
// let's reduce downstream task. // let's reduce downstream task.
// TODO: avoid if already REDUCED or DISTINCT // TODO: avoid if already REDUCED or DISTINCT
PlanNode::Reduced { PlanNode::Reduced {
child: Box::new(plan), child: Rc::new(plan),
} }
} else { } else {
plan plan
@ -113,21 +113,21 @@ impl<'a> PlanBuilder<'a> {
//We add the extra filter if needed //We add the extra filter if needed
let right = if let Some(expr) = expression { let right = if let Some(expr) = expression {
self.push_filter( self.push_filter(
Box::new(right), Rc::new(right),
Box::new(self.build_for_expression(expr, variables, graph_name)?), Box::new(self.build_for_expression(expr, variables, graph_name)?),
) )
} else { } else {
right right
}; };
PlanNode::ForLoopLeftJoin { PlanNode::ForLoopLeftJoin {
left: Box::new(left), left: Rc::new(left),
right: Box::new(right), right: Rc::new(right),
possible_problem_vars: Rc::new(possible_problem_vars.into_iter().collect()), possible_problem_vars: Rc::new(possible_problem_vars.into_iter().collect()),
} }
} else { } else {
PlanNode::HashLeftJoin { PlanNode::HashLeftJoin {
left: Box::new(left), left: Rc::new(left),
right: Box::new(right), right: Rc::new(right),
expression: Box::new(expression.as_ref().map_or( expression: Box::new(expression.as_ref().map_or(
Ok(PlanExpression::Literal(PlanTerm { Ok(PlanExpression::Literal(PlanTerm {
encoded: true.into(), encoded: true.into(),
@ -139,11 +139,11 @@ impl<'a> PlanBuilder<'a> {
} }
} }
GraphPattern::Lateral { left, right } => PlanNode::ForLoopJoin { GraphPattern::Lateral { left, right } => PlanNode::ForLoopJoin {
left: Box::new(self.build_for_graph_pattern(left, variables, graph_name)?), left: Rc::new(self.build_for_graph_pattern(left, variables, graph_name)?),
right: Box::new(self.build_for_graph_pattern(right, variables, graph_name)?), right: Rc::new(self.build_for_graph_pattern(right, variables, graph_name)?),
}, },
GraphPattern::Filter { expr, inner } => self.push_filter( GraphPattern::Filter { expr, inner } => self.push_filter(
Box::new(self.build_for_graph_pattern(inner, variables, graph_name)?), Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?),
Box::new(self.build_for_expression(expr, variables, graph_name)?), Box::new(self.build_for_expression(expr, variables, graph_name)?),
), ),
GraphPattern::Union { left, right } => { GraphPattern::Union { left, right } => {
@ -157,9 +157,9 @@ impl<'a> PlanBuilder<'a> {
stack.push(left); stack.push(left);
stack.push(right); stack.push(right);
} }
Some(p) => { Some(p) => children.push(Rc::new(
children.push(self.build_for_graph_pattern(p, variables, graph_name)?) self.build_for_graph_pattern(p, variables, graph_name)?,
} )),
} }
} }
PlanNode::Union { children } PlanNode::Union { children }
@ -173,13 +173,13 @@ impl<'a> PlanBuilder<'a> {
variable, variable,
expression, expression,
} => PlanNode::Extend { } => PlanNode::Extend {
child: Box::new(self.build_for_graph_pattern(inner, variables, graph_name)?), child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?),
variable: build_plan_variable(variables, variable), variable: build_plan_variable(variables, variable),
expression: Box::new(self.build_for_expression(expression, variables, graph_name)?), expression: Box::new(self.build_for_expression(expression, variables, graph_name)?),
}, },
GraphPattern::Minus { left, right } => PlanNode::AntiJoin { GraphPattern::Minus { left, right } => PlanNode::AntiJoin {
left: Box::new(self.build_for_graph_pattern(left, variables, graph_name)?), left: Rc::new(self.build_for_graph_pattern(left, variables, graph_name)?),
right: Box::new(self.build_for_graph_pattern(right, variables, graph_name)?), right: Rc::new(self.build_for_graph_pattern(right, variables, graph_name)?),
}, },
GraphPattern::Service { GraphPattern::Service {
name, name,
@ -192,7 +192,7 @@ impl<'a> PlanBuilder<'a> {
PlanNode::Service { PlanNode::Service {
service_name, service_name,
variables: Rc::new(variables.clone()), variables: Rc::new(variables.clone()),
child: Box::new(child), child: Rc::new(child),
graph_pattern: Rc::new(inner.as_ref().clone()), graph_pattern: Rc::new(inner.as_ref().clone()),
silent: *silent, silent: *silent,
} }
@ -202,7 +202,7 @@ impl<'a> PlanBuilder<'a> {
variables: by, variables: by,
aggregates, aggregates,
} => PlanNode::Aggregate { } => PlanNode::Aggregate {
child: Box::new(self.build_for_graph_pattern(inner, variables, graph_name)?), child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?),
key_variables: Rc::new( key_variables: Rc::new(
by.iter() by.iter()
.map(|k| build_plan_variable(variables, k)) .map(|k| build_plan_variable(variables, k))
@ -266,7 +266,7 @@ impl<'a> PlanBuilder<'a> {
}) })
.collect(); .collect();
PlanNode::Sort { PlanNode::Sort {
child: Box::new(self.build_for_graph_pattern(inner, variables, graph_name)?), child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?),
by: condition?, by: condition?,
} }
} }
@ -278,7 +278,7 @@ impl<'a> PlanBuilder<'a> {
let inner_graph_name = let inner_graph_name =
Self::convert_pattern_value_id(graph_name, &mut inner_variables); Self::convert_pattern_value_id(graph_name, &mut inner_variables);
PlanNode::Project { PlanNode::Project {
child: Box::new(self.build_for_graph_pattern( child: Rc::new(self.build_for_graph_pattern(
inner, inner,
&mut inner_variables, &mut inner_variables,
&inner_graph_name, &inner_graph_name,
@ -301,10 +301,10 @@ impl<'a> PlanBuilder<'a> {
} }
} }
GraphPattern::Distinct { inner } => PlanNode::HashDeduplicate { GraphPattern::Distinct { inner } => PlanNode::HashDeduplicate {
child: Box::new(self.build_for_graph_pattern(inner, variables, graph_name)?), child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?),
}, },
GraphPattern::Reduced { inner } => PlanNode::Reduced { GraphPattern::Reduced { inner } => PlanNode::Reduced {
child: Box::new(self.build_for_graph_pattern(inner, variables, graph_name)?), child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?),
}, },
GraphPattern::Slice { GraphPattern::Slice {
inner, inner,
@ -314,13 +314,13 @@ impl<'a> PlanBuilder<'a> {
let mut plan = self.build_for_graph_pattern(inner, variables, graph_name)?; let mut plan = self.build_for_graph_pattern(inner, variables, graph_name)?;
if *start > 0 { if *start > 0 {
plan = PlanNode::Skip { plan = PlanNode::Skip {
child: Box::new(plan), child: Rc::new(plan),
count: *start, count: *start,
}; };
} }
if let Some(length) = length { if let Some(length) = length {
plan = PlanNode::Limit { plan = PlanNode::Limit {
child: Box::new(plan), child: Rc::new(plan),
count: *length, count: *length,
}; };
} }
@ -1351,8 +1351,8 @@ impl<'a> PlanBuilder<'a> {
swap(&mut left, &mut right); swap(&mut left, &mut right);
} }
PlanNode::ForLoopJoin { PlanNode::ForLoopJoin {
left: Box::new(left), left: Rc::new(left),
right: Box::new(right), right: Rc::new(right),
} }
} else { } else {
// Let's avoid materializing right if left is already materialized // Let's avoid materializing right if left is already materialized
@ -1361,8 +1361,8 @@ impl<'a> PlanBuilder<'a> {
swap(&mut left, &mut right); swap(&mut left, &mut right);
} }
PlanNode::HashJoin { PlanNode::HashJoin {
left: Box::new(left), left: Rc::new(left),
right: Box::new(right), right: Rc::new(right),
} }
} }
} }
@ -1387,7 +1387,9 @@ impl<'a> PlanBuilder<'a> {
PlanNode::Filter { child, .. } | PlanNode::Extend { child, .. } => { PlanNode::Filter { child, .. } | PlanNode::Extend { child, .. } => {
Self::is_fit_for_for_loop_join(child) Self::is_fit_for_for_loop_join(child)
} }
PlanNode::Union { children } => children.iter().all(Self::is_fit_for_for_loop_join), PlanNode::Union { children } => {
children.iter().all(|c| Self::is_fit_for_for_loop_join(c))
}
PlanNode::AntiJoin { .. } PlanNode::AntiJoin { .. }
| PlanNode::HashLeftJoin { .. } | PlanNode::HashLeftJoin { .. }
| PlanNode::ForLoopLeftJoin { .. } | PlanNode::ForLoopLeftJoin { .. }
@ -1402,7 +1404,7 @@ impl<'a> PlanBuilder<'a> {
} }
} }
fn push_filter(&self, node: Box<PlanNode>, filter: Box<PlanExpression>) -> PlanNode { fn push_filter(&self, node: Rc<PlanNode>, filter: Box<PlanExpression>) -> PlanNode {
if !self.with_optimizations { if !self.with_optimizations {
return PlanNode::Filter { return PlanNode::Filter {
child: node, child: node,
@ -1410,34 +1412,37 @@ impl<'a> PlanBuilder<'a> {
}; };
} }
if let PlanExpression::And(f1, f2) = *filter { if let PlanExpression::And(f1, f2) = *filter {
return self.push_filter(Box::new(self.push_filter(node, f1)), f2); return self.push_filter(Rc::new(self.push_filter(node, f1)), f2);
} }
let mut filter_variables = BTreeSet::new(); let mut filter_variables = BTreeSet::new();
filter.lookup_used_variables(&mut |v| { filter.lookup_used_variables(&mut |v| {
filter_variables.insert(v); filter_variables.insert(v);
}); });
match *node { match node.as_ref() {
PlanNode::HashJoin { left, right } => { PlanNode::HashJoin { left, right } => {
if filter_variables.iter().all(|v| left.is_variable_bound(*v)) { if filter_variables.iter().all(|v| left.is_variable_bound(*v)) {
if filter_variables.iter().all(|v| right.is_variable_bound(*v)) { if filter_variables.iter().all(|v| right.is_variable_bound(*v)) {
PlanNode::HashJoin { PlanNode::HashJoin {
left: Box::new(self.push_filter(left, filter.clone())), left: Rc::new(self.push_filter(left.clone(), filter.clone())),
right: Box::new(self.push_filter(right, filter)), right: Rc::new(self.push_filter(right.clone(), filter)),
} }
} else { } else {
PlanNode::HashJoin { PlanNode::HashJoin {
left: Box::new(self.push_filter(left, filter)), left: Rc::new(self.push_filter(left.clone(), filter)),
right, right: right.clone(),
} }
} }
} else if filter_variables.iter().all(|v| right.is_variable_bound(*v)) { } else if filter_variables.iter().all(|v| right.is_variable_bound(*v)) {
PlanNode::HashJoin { PlanNode::HashJoin {
left, left: left.clone(),
right: Box::new(self.push_filter(right, filter)), right: Rc::new(self.push_filter(right.clone(), filter)),
} }
} else { } else {
PlanNode::Filter { PlanNode::Filter {
child: Box::new(PlanNode::HashJoin { left, right }), child: Rc::new(PlanNode::HashJoin {
left: left.clone(),
right: right.clone(),
}),
expression: filter, expression: filter,
} }
} }
@ -1445,18 +1450,21 @@ impl<'a> PlanBuilder<'a> {
PlanNode::ForLoopJoin { left, right } => { PlanNode::ForLoopJoin { left, right } => {
if filter_variables.iter().all(|v| left.is_variable_bound(*v)) { if filter_variables.iter().all(|v| left.is_variable_bound(*v)) {
PlanNode::ForLoopJoin { PlanNode::ForLoopJoin {
left: Box::new(self.push_filter(left, filter)), left: Rc::new(self.push_filter(left.clone(), filter)),
right, right: right.clone(),
} }
} else if filter_variables.iter().all(|v| right.is_variable_bound(*v)) { } else if filter_variables.iter().all(|v| right.is_variable_bound(*v)) {
PlanNode::ForLoopJoin { PlanNode::ForLoopJoin {
//TODO: should we do that always? //TODO: should we do that always?
left, left: left.clone(),
right: Box::new(self.push_filter(right, filter)), right: Rc::new(self.push_filter(right.clone(), filter)),
} }
} else { } else {
PlanNode::Filter { PlanNode::Filter {
child: Box::new(PlanNode::HashJoin { left, right }), child: Rc::new(PlanNode::HashJoin {
left: left.clone(),
right: right.clone(),
}),
expression: filter, expression: filter,
} }
} }
@ -1464,21 +1472,21 @@ impl<'a> PlanBuilder<'a> {
PlanNode::Extend { PlanNode::Extend {
child, child,
expression, expression,
variable: position, variable,
} => { } => {
//TODO: handle the case where the filter generates an expression variable //TODO: handle the case where the filter generates an expression variable
if filter_variables.iter().all(|v| child.is_variable_bound(*v)) { if filter_variables.iter().all(|v| child.is_variable_bound(*v)) {
PlanNode::Extend { PlanNode::Extend {
child: Box::new(self.push_filter(child, filter)), child: Rc::new(self.push_filter(child.clone(), filter)),
expression, expression: expression.clone(),
variable: position, variable: variable.clone(),
} }
} else { } else {
PlanNode::Filter { PlanNode::Filter {
child: Box::new(PlanNode::Extend { child: Rc::new(PlanNode::Extend {
child, child: child.clone(),
expression, expression: expression.clone(),
variable: position, variable: variable.clone(),
}), }),
expression: filter, expression: filter,
} }
@ -1487,25 +1495,25 @@ impl<'a> PlanBuilder<'a> {
PlanNode::Filter { child, expression } => { PlanNode::Filter { child, expression } => {
if filter_variables.iter().all(|v| child.is_variable_bound(*v)) { if filter_variables.iter().all(|v| child.is_variable_bound(*v)) {
PlanNode::Filter { PlanNode::Filter {
child: Box::new(self.push_filter(child, filter)), child: Rc::new(self.push_filter(child.clone(), filter)),
expression, expression: expression.clone(),
} }
} else { } else {
PlanNode::Filter { PlanNode::Filter {
child, child: child.clone(),
expression: Box::new(PlanExpression::And(expression, filter)), expression: Box::new(PlanExpression::And(expression.clone(), filter)),
} }
} }
} }
PlanNode::Union { children } => PlanNode::Union { PlanNode::Union { children } => PlanNode::Union {
children: children children: children
.into_iter() .iter()
.map(|c| self.push_filter(Box::new(c), filter.clone())) .map(|c| Rc::new(self.push_filter(c.clone(), filter.clone())))
.collect(), .collect(),
}, },
node => PlanNode::Filter { _ => PlanNode::Filter {
//TODO: more? //TODO: more?
child: Box::new(node), child: node,
expression: filter, expression: filter,
}, },
} }

@ -132,7 +132,8 @@ impl<'a, 'b: 'a> SimpleUpdateEvaluator<'a, 'b> {
Rc::new(self.options.query_options.custom_functions.clone()), Rc::new(self.options.query_options.custom_functions.clone()),
); );
let mut bnodes = HashMap::new(); let mut bnodes = HashMap::new();
let tuples = evaluator.plan_evaluator(&plan)(EncodedTuple::with_capacity(variables.len())) let tuples =
evaluator.plan_evaluator(Rc::new(plan))(EncodedTuple::with_capacity(variables.len()))
.collect::<Result<Vec<_>, _>>()?; //TODO: would be much better to stream .collect::<Result<Vec<_>, _>>()?; //TODO: would be much better to stream
for tuple in tuples { for tuple in tuples {
for quad in delete { for quad in delete {

Loading…
Cancel
Save