SPARQL plan: allows AND and OR to have more than 2 children

Adds tests on VALUES cardinality validation
pull/490/head
Tpt 2 years ago committed by Thomas Tanon
parent cfe52db3a3
commit e96672a2a8
  1. 52
      lib/src/sparql/eval.rs
  2. 38
      lib/src/sparql/plan.rs
  3. 47
      lib/src/sparql/plan_builder.rs

@ -954,23 +954,45 @@ impl SimpleEvaluator {
stat_children.push(stats); stat_children.push(stats);
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(inner) => {
let a = self.expression_evaluator(a, stat_children); let children = inner
let b = self.expression_evaluator(b, stat_children); .iter()
Rc::new(move |tuple| match a(tuple).and_then(|v| to_bool(&v)) { .map(|i| self.expression_evaluator(i, stat_children))
Some(true) => Some(true.into()), .collect::<Rc<[_]>>();
Some(false) => b(tuple), Rc::new(move |tuple| {
None => (Some(true) == a(tuple).and_then(|v| to_bool(&v))).then(|| true.into()), let mut error = true;
for child in children.iter() {
match child(tuple).and_then(|v| to_bool(&v)) {
Some(true) => return Some(true.into()),
Some(false) => continue,
None => error = true,
}
}
if error {
None
} else {
Some(false.into())
}
}) })
} }
PlanExpression::And(a, b) => { PlanExpression::And(inner) => {
let a = self.expression_evaluator(a, stat_children); let children = inner
let b = self.expression_evaluator(b, stat_children); .iter()
Rc::new(move |tuple| match a(tuple).and_then(|v| to_bool(&v)) { .map(|i| self.expression_evaluator(i, stat_children))
Some(true) => b(tuple), .collect::<Rc<[_]>>();
Some(false) => Some(false.into()), Rc::new(move |tuple| {
None => { let mut error = false;
(Some(false) == b(tuple).and_then(|v| to_bool(&v))).then(|| false.into()) for child in children.iter() {
match child(tuple).and_then(|v| to_bool(&v)) {
Some(true) => continue,
Some(false) => return Some(false.into()),
None => error = true,
}
}
if error {
None
} else {
Some(true.into())
} }
}) })
} }

@ -13,7 +13,7 @@ use std::rc::Rc;
use std::time::Duration; use std::time::Duration;
use std::{fmt, io}; use std::{fmt, io};
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum PlanNode { pub enum PlanNode {
StaticBindings { StaticBindings {
encoded_tuples: Vec<EncodedTuple>, encoded_tuples: Vec<EncodedTuple>,
@ -447,8 +447,8 @@ pub enum PlanExpression {
Literal(PlanTerm<Literal>), Literal(PlanTerm<Literal>),
Variable(PlanVariable), Variable(PlanVariable),
Exists(Rc<PlanNode>), Exists(Rc<PlanNode>),
Or(Box<Self>, Box<Self>), Or(Vec<Self>),
And(Box<Self>, Box<Self>), And(Vec<Self>),
Equal(Box<Self>, Box<Self>), Equal(Box<Self>, Box<Self>),
Greater(Box<Self>, Box<Self>), Greater(Box<Self>, Box<Self>),
GreaterOrEqual(Box<Self>, Box<Self>), GreaterOrEqual(Box<Self>, Box<Self>),
@ -597,9 +597,7 @@ impl PlanExpression {
| Self::YearMonthDurationCast(e) | Self::YearMonthDurationCast(e)
| Self::DayTimeDurationCast(e) | Self::DayTimeDurationCast(e)
| Self::StringCast(e) => e.lookup_used_variables(callback), | Self::StringCast(e) => e.lookup_used_variables(callback),
Self::Or(a, b) Self::Equal(a, b)
| Self::And(a, b)
| Self::Equal(a, b)
| Self::Greater(a, b) | Self::Greater(a, b)
| Self::GreaterOrEqual(a, b) | Self::GreaterOrEqual(a, b)
| Self::Less(a, b) | Self::Less(a, b)
@ -639,7 +637,11 @@ impl PlanExpression {
c.lookup_used_variables(callback); c.lookup_used_variables(callback);
d.lookup_used_variables(callback); d.lookup_used_variables(callback);
} }
Self::Concat(es) | Self::Coalesce(es) | Self::CustomFunction(_, es) => { Self::Or(es)
| Self::And(es)
| Self::Concat(es)
| Self::Coalesce(es)
| Self::CustomFunction(_, es) => {
for e in es { for e in es {
e.lookup_used_variables(callback); e.lookup_used_variables(callback);
} }
@ -723,8 +725,26 @@ impl fmt::Display for PlanExpression {
Self::YearMonthDurationCast(e) => write!(f, "YearMonthDurationCast({e})"), Self::YearMonthDurationCast(e) => write!(f, "YearMonthDurationCast({e})"),
Self::DayTimeDurationCast(e) => write!(f, "DayTimeDurationCast({e})"), Self::DayTimeDurationCast(e) => write!(f, "DayTimeDurationCast({e})"),
Self::StringCast(e) => write!(f, "StringCast({e})"), Self::StringCast(e) => write!(f, "StringCast({e})"),
Self::Or(a, b) => write!(f, "Or({a}, {b})"), Self::Or(es) => {
Self::And(a, b) => write!(f, "And({a}, {b})"), write!(f, "Or(")?;
for (i, e) in es.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{e}")?;
}
write!(f, ")")
}
Self::And(es) => {
write!(f, "And(")?;
for (i, e) in es.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{e}")?;
}
write!(f, ")")
}
Self::Equal(a, b) => write!(f, "Equal({a}, {b})"), Self::Equal(a, b) => write!(f, "Equal({a}, {b})"),
Self::Greater(a, b) => write!(f, "Greater({a}, {b})"), Self::Greater(a, b) => write!(f, "Greater({a}, {b})"),
Self::GreaterOrEqual(a, b) => write!(f, "GreaterOrEqual({a}, {b})"), Self::GreaterOrEqual(a, b) => write!(f, "GreaterOrEqual({a}, {b})"),

@ -400,14 +400,14 @@ impl<'a> PlanBuilder<'a> {
plain: l.clone(), plain: l.clone(),
}), }),
Expression::Variable(v) => PlanExpression::Variable(build_plan_variable(variables, v)), Expression::Variable(v) => PlanExpression::Variable(build_plan_variable(variables, v)),
Expression::Or(a, b) => PlanExpression::Or( Expression::Or(a, b) => PlanExpression::Or(vec![
Box::new(self.build_for_expression(a, variables, graph_name)?), self.build_for_expression(a, variables, graph_name)?,
Box::new(self.build_for_expression(b, variables, graph_name)?), self.build_for_expression(b, variables, graph_name)?,
), ]),
Expression::And(a, b) => PlanExpression::And( Expression::And(a, b) => PlanExpression::And(vec![
Box::new(self.build_for_expression(a, variables, graph_name)?), self.build_for_expression(a, variables, graph_name)?,
Box::new(self.build_for_expression(b, variables, graph_name)?), self.build_for_expression(b, variables, graph_name)?,
), ]),
Expression::Equal(a, b) => PlanExpression::Equal( Expression::Equal(a, b) => PlanExpression::Equal(
Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(a, variables, graph_name)?),
Box::new(self.build_for_expression(b, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?),
@ -433,7 +433,14 @@ impl<'a> PlanBuilder<'a> {
Box::new(self.build_for_expression(b, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?),
), ),
Expression::In(e, l) => { Expression::In(e, l) => {
if l.is_empty() {
return Ok(PlanExpression::Literal(PlanTerm {
encoded: false.into(),
plain: false.into(),
}));
}
let e = self.build_for_expression(e, variables, graph_name)?; let e = self.build_for_expression(e, variables, graph_name)?;
PlanExpression::Or(
l.iter() l.iter()
.map(|v| { .map(|v| {
Ok(PlanExpression::Equal( Ok(PlanExpression::Equal(
@ -441,15 +448,8 @@ impl<'a> PlanBuilder<'a> {
Box::new(self.build_for_expression(v, variables, graph_name)?), Box::new(self.build_for_expression(v, variables, graph_name)?),
)) ))
}) })
.reduce(|a: Result<_, EvaluationError>, b| { .collect::<Result<_, EvaluationError>>()?,
Ok(PlanExpression::Or(Box::new(a?), Box::new(b?))) )
})
.unwrap_or_else(|| {
Ok(PlanExpression::Literal(PlanTerm {
encoded: false.into(),
plain: false.into(),
}))
})?
} }
Expression::Add(a, b) => PlanExpression::Add( Expression::Add(a, b) => PlanExpression::Add(
Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(a, variables, graph_name)?),
@ -1402,8 +1402,12 @@ impl<'a> PlanBuilder<'a> {
expression: filter, expression: filter,
}; };
} }
if let PlanExpression::And(f1, f2) = *filter { if let PlanExpression::And(filters) = *filter {
return self.push_filter(Rc::new(self.push_filter(node, f1)), f2); return filters
.into_iter()
.fold((*node.as_ref()).clone(), |acc, f| {
self.push_filter(Rc::new(acc), Box::new(f))
});
} }
let mut filter_variables = BTreeSet::new(); let mut filter_variables = BTreeSet::new();
filter.lookup_used_variables(&mut |v| { filter.lookup_used_variables(&mut |v| {
@ -1492,7 +1496,10 @@ impl<'a> PlanBuilder<'a> {
} else { } else {
PlanNode::Filter { PlanNode::Filter {
child: Rc::clone(child), child: Rc::clone(child),
expression: Box::new(PlanExpression::And(expression.clone(), filter)), expression: Box::new(PlanExpression::And(vec![
*expression.clone(),
*filter,
])),
} }
} }
} }

Loading…
Cancel
Save