parent
2ba00cd8b5
commit
654ee215d5
@ -0,0 +1,446 @@ |
|||||||
|
use sparql::algebra::*; |
||||||
|
use store::numeric_encoder::EncodedTerm; |
||||||
|
use store::store::EncodedQuadsStore; |
||||||
|
use Result; |
||||||
|
|
||||||
|
pub type EncodedTuple = Vec<Option<EncodedTerm>>; |
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)] |
||||||
|
pub enum PlanNode { |
||||||
|
Init, |
||||||
|
StaticBindings { |
||||||
|
tuples: Vec<EncodedTuple>, |
||||||
|
}, |
||||||
|
TriplePatternJoin { |
||||||
|
child: Box<PlanNode>, |
||||||
|
subject: PatternValue, |
||||||
|
predicate: PatternValue, |
||||||
|
object: PatternValue, |
||||||
|
}, |
||||||
|
Filter { |
||||||
|
child: Box<PlanNode>, |
||||||
|
expression: PlanExpression, |
||||||
|
}, |
||||||
|
Union { |
||||||
|
entry: Box<PlanNode>, |
||||||
|
children: Vec<PlanNode>, |
||||||
|
}, |
||||||
|
HashDeduplicate { |
||||||
|
child: Box<PlanNode>, |
||||||
|
}, |
||||||
|
Skip { |
||||||
|
child: Box<PlanNode>, |
||||||
|
count: usize, |
||||||
|
}, |
||||||
|
Limit { |
||||||
|
child: Box<PlanNode>, |
||||||
|
count: usize, |
||||||
|
}, |
||||||
|
Project { |
||||||
|
child: Box<PlanNode>, |
||||||
|
mapping: Vec<usize>, // for each key in children the key of the returned vector (children is sliced at the vector length)
|
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)] |
||||||
|
pub enum PatternValue { |
||||||
|
Constant(EncodedTerm), |
||||||
|
Variable(usize), |
||||||
|
} |
||||||
|
|
||||||
|
impl PatternValue { |
||||||
|
pub fn is_var(&self) -> bool { |
||||||
|
match self { |
||||||
|
PatternValue::Constant(_) => false, |
||||||
|
PatternValue::Variable(_) => true, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)] |
||||||
|
pub enum PlanExpression { |
||||||
|
Constant(EncodedTerm), |
||||||
|
Variable(usize), |
||||||
|
Or(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
And(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
Equal(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
NotEqual(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
Greater(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
GreaterOrEq(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
Lower(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
LowerOrEq(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
//In(Box<PlanExpression>, Vec<PlanExpression>),
|
||||||
|
//NotIn(Box<PlanExpression>, Vec<PlanExpression>),
|
||||||
|
Add(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
Sub(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
Mul(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
Div(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
UnaryPlus(Box<PlanExpression>), |
||||||
|
UnaryMinus(Box<PlanExpression>), |
||||||
|
UnaryNot(Box<PlanExpression>), |
||||||
|
Str(Box<PlanExpression>), |
||||||
|
Lang(Box<PlanExpression>), |
||||||
|
LangMatches(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
Datatype(Box<PlanExpression>), |
||||||
|
Bound(usize), |
||||||
|
IRI(Box<PlanExpression>), |
||||||
|
BNode(Option<Box<PlanExpression>>), |
||||||
|
/*Rand(),
|
||||||
|
Abs(Box<PlanExpression>), |
||||||
|
Ceil(Box<PlanExpression>), |
||||||
|
Floor(Box<PlanExpression>), |
||||||
|
Round(Box<PlanExpression>), |
||||||
|
Concat(Vec<PlanExpression>), |
||||||
|
SubStr(Box<PlanExpression>, Box<PlanExpression>, Option<Box<PlanExpression>>), |
||||||
|
StrLen(Box<PlanExpression>), |
||||||
|
Replace( |
||||||
|
Box<PlanExpression>, |
||||||
|
Box<PlanExpression>, |
||||||
|
Box<PlanExpression>, |
||||||
|
Option<Box<PlanExpression>>, |
||||||
|
), |
||||||
|
UCase(Box<PlanExpression>), |
||||||
|
LCase(Box<PlanExpression>), |
||||||
|
EncodeForURI(Box<PlanExpression>), |
||||||
|
Contains(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
StrStarts(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
StrEnds(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
StrBefore(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
StrAfter(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
Year(Box<PlanExpression>), |
||||||
|
Month(Box<PlanExpression>), |
||||||
|
Day(Box<PlanExpression>), |
||||||
|
Hours(Box<PlanExpression>), |
||||||
|
Minutes(Box<PlanExpression>), |
||||||
|
Seconds(Box<PlanExpression>), |
||||||
|
Timezone(Box<PlanExpression>), |
||||||
|
Now(), |
||||||
|
UUID(), |
||||||
|
StrUUID(), |
||||||
|
MD5(Box<PlanExpression>), |
||||||
|
SHA1(Box<PlanExpression>), |
||||||
|
SHA256(Box<PlanExpression>), |
||||||
|
SHA384(Box<PlanExpression>), |
||||||
|
SHA512(Box<PlanExpression>), |
||||||
|
Coalesce(Vec<PlanExpression>), |
||||||
|
If(Box<PlanExpression>, Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
StrLang(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
StrDT(Box<PlanExpression>, Box<PlanExpression>),*/ |
||||||
|
SameTerm(Box<PlanExpression>, Box<PlanExpression>), |
||||||
|
IsIRI(Box<PlanExpression>), |
||||||
|
IsBlank(Box<PlanExpression>), |
||||||
|
IsLiteral(Box<PlanExpression>), |
||||||
|
IsNumeric(Box<PlanExpression>), |
||||||
|
Regex( |
||||||
|
Box<PlanExpression>, |
||||||
|
Box<PlanExpression>, |
||||||
|
Option<Box<PlanExpression>>, |
||||||
|
), |
||||||
|
} |
||||||
|
|
||||||
|
pub struct PlanBuilder<'a, S: EncodedQuadsStore> { |
||||||
|
store: &'a S, |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> { |
||||||
|
pub fn build(store: &S, pattern: &GraphPattern) -> Result<(PlanNode, Vec<Variable>)> { |
||||||
|
let mut variables = Vec::default(); |
||||||
|
let plan = PlanBuilder { store }.build_for_graph_pattern( |
||||||
|
pattern, |
||||||
|
PlanNode::Init, |
||||||
|
&mut variables, |
||||||
|
)?; |
||||||
|
Ok((plan, variables)) |
||||||
|
} |
||||||
|
|
||||||
|
fn build_for_graph_pattern( |
||||||
|
&self, |
||||||
|
pattern: &GraphPattern, |
||||||
|
input: PlanNode, |
||||||
|
variables: &mut Vec<Variable>, |
||||||
|
) -> Result<PlanNode> { |
||||||
|
Ok(match pattern { |
||||||
|
GraphPattern::BGP(p) => { |
||||||
|
let mut plan = input; |
||||||
|
for pattern in p { |
||||||
|
plan = match pattern { |
||||||
|
TripleOrPathPattern::Triple(pattern) => PlanNode::TriplePatternJoin { |
||||||
|
child: Box::new(plan), |
||||||
|
subject: self |
||||||
|
.pattern_value_from_term_or_variable(&pattern.subject, variables)?, |
||||||
|
predicate: self.pattern_value_from_named_node_or_variable( |
||||||
|
&pattern.predicate, |
||||||
|
variables, |
||||||
|
)?, |
||||||
|
object: self |
||||||
|
.pattern_value_from_term_or_variable(&pattern.object, variables)?, |
||||||
|
}, |
||||||
|
TripleOrPathPattern::Path(pattern) => unimplemented!(), |
||||||
|
} |
||||||
|
} |
||||||
|
plan |
||||||
|
} |
||||||
|
GraphPattern::Join(a, b) => self.build_for_graph_pattern( |
||||||
|
b, |
||||||
|
self.build_for_graph_pattern(a, input, variables)?, |
||||||
|
variables, |
||||||
|
)?, |
||||||
|
GraphPattern::LeftJoin(a, b, e) => unimplemented!(), |
||||||
|
GraphPattern::Filter(e, p) => PlanNode::Filter { |
||||||
|
child: Box::new(self.build_for_graph_pattern(p, input, variables)?), |
||||||
|
expression: self.build_for_expression(e, variables)?, |
||||||
|
}, |
||||||
|
GraphPattern::Union(a, b) => { |
||||||
|
//We flatten the UNIONs
|
||||||
|
let mut stack: Vec<&GraphPattern> = vec![a, b]; |
||||||
|
let mut children = vec![]; |
||||||
|
loop { |
||||||
|
match stack.pop() { |
||||||
|
None => break, |
||||||
|
Some(GraphPattern::Union(a, b)) => { |
||||||
|
stack.push(a); |
||||||
|
stack.push(b); |
||||||
|
} |
||||||
|
Some(p) => children.push(self.build_for_graph_pattern( |
||||||
|
a, |
||||||
|
PlanNode::Init, |
||||||
|
variables, |
||||||
|
)?), |
||||||
|
} |
||||||
|
} |
||||||
|
PlanNode::Union { |
||||||
|
entry: Box::new(input), |
||||||
|
children, |
||||||
|
} |
||||||
|
} |
||||||
|
GraphPattern::Graph(g, p) => unimplemented!(), |
||||||
|
GraphPattern::Extend(p, v, e) => unimplemented!(), |
||||||
|
GraphPattern::Minus(a, b) => unimplemented!(), |
||||||
|
GraphPattern::Service(n, p, s) => unimplemented!(), |
||||||
|
GraphPattern::AggregateJoin(g, a) => unimplemented!(), |
||||||
|
GraphPattern::Data(bs) => PlanNode::StaticBindings { |
||||||
|
tuples: self.encode_bindings(bs, variables)?, |
||||||
|
}, |
||||||
|
GraphPattern::OrderBy(l, o) => self.build_for_graph_pattern(l, input, variables)?, //TODO
|
||||||
|
GraphPattern::Project(l, new_variables) => PlanNode::Project { |
||||||
|
child: Box::new(self.build_for_graph_pattern( |
||||||
|
l, |
||||||
|
input, |
||||||
|
&mut new_variables.clone(), |
||||||
|
)?), |
||||||
|
mapping: new_variables |
||||||
|
.iter() |
||||||
|
.map(|variable| variable_key(variables, variable)) |
||||||
|
.collect(), |
||||||
|
}, |
||||||
|
GraphPattern::Distinct(l) => PlanNode::HashDeduplicate { |
||||||
|
child: Box::new(self.build_for_graph_pattern(l, input, variables)?), |
||||||
|
}, |
||||||
|
GraphPattern::Reduced(l) => self.build_for_graph_pattern(l, input, variables)?, |
||||||
|
GraphPattern::Slice(l, start, length) => { |
||||||
|
let mut plan = self.build_for_graph_pattern(l, input, variables)?; |
||||||
|
if *start > 0 { |
||||||
|
plan = PlanNode::Skip { |
||||||
|
child: Box::new(plan), |
||||||
|
count: *start, |
||||||
|
}; |
||||||
|
} |
||||||
|
if let Some(length) = length { |
||||||
|
plan = PlanNode::Limit { |
||||||
|
child: Box::new(plan), |
||||||
|
count: *length, |
||||||
|
}; |
||||||
|
} |
||||||
|
plan |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn build_for_expression( |
||||||
|
&self, |
||||||
|
expression: &Expression, |
||||||
|
variables: &mut Vec<Variable>, |
||||||
|
) -> Result<PlanExpression> { |
||||||
|
Ok(match expression { |
||||||
|
Expression::ConstantExpression(t) => match t { |
||||||
|
TermOrVariable::Term(t) => { |
||||||
|
PlanExpression::Constant(self.store.encoder().encode_term(t)?) |
||||||
|
} |
||||||
|
TermOrVariable::Variable(v) => PlanExpression::Variable(variable_key(variables, v)), |
||||||
|
}, |
||||||
|
Expression::OrExpression(a, b) => PlanExpression::Or( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::AndExpression(a, b) => PlanExpression::And( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::EqualExpression(a, b) => PlanExpression::Equal( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::NotEqualExpression(a, b) => PlanExpression::NotEqual( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::GreaterExpression(a, b) => PlanExpression::Greater( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::GreaterOrEqExpression(a, b) => PlanExpression::GreaterOrEq( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::LowerExpression(a, b) => PlanExpression::Lower( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::LowerOrEqExpression(a, b) => PlanExpression::LowerOrEq( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::AddExpression(a, b) => PlanExpression::Add( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::SubExpression(a, b) => PlanExpression::Sub( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::MulExpression(a, b) => PlanExpression::Mul( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::DivExpression(a, b) => PlanExpression::Div( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::UnaryPlusExpression(e) => { |
||||||
|
PlanExpression::UnaryPlus(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::UnaryMinusExpression(e) => { |
||||||
|
PlanExpression::UnaryMinus(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::UnaryNotExpression(e) => { |
||||||
|
PlanExpression::UnaryNot(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::StrFunctionCall(e) => { |
||||||
|
PlanExpression::Str(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::LangFunctionCall(e) => { |
||||||
|
PlanExpression::Lang(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::LangMatchesFunctionCall(a, b) => PlanExpression::LangMatches( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::DatatypeFunctionCall(e) => { |
||||||
|
PlanExpression::Datatype(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::BoundFunctionCall(v) => PlanExpression::Bound(variable_key(variables, v)), |
||||||
|
Expression::IRIFunctionCall(e) => { |
||||||
|
PlanExpression::IRI(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::BNodeFunctionCall(e) => PlanExpression::BNode(match e { |
||||||
|
Some(e) => Some(Box::new(self.build_for_expression(e, variables)?)), |
||||||
|
None => None, |
||||||
|
}), |
||||||
|
Expression::SameTermFunctionCall(a, b) => PlanExpression::SameTerm( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
), |
||||||
|
Expression::IsIRIFunctionCall(e) => { |
||||||
|
PlanExpression::IsIRI(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::IsBlankFunctionCall(e) => { |
||||||
|
PlanExpression::IsBlank(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::IsLiteralFunctionCall(e) => { |
||||||
|
PlanExpression::IsLiteral(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::IsNumericFunctionCall(e) => { |
||||||
|
PlanExpression::IsNumeric(Box::new(self.build_for_expression(e, variables)?)) |
||||||
|
} |
||||||
|
Expression::RegexFunctionCall(a, b, c) => PlanExpression::Regex( |
||||||
|
Box::new(self.build_for_expression(a, variables)?), |
||||||
|
Box::new(self.build_for_expression(b, variables)?), |
||||||
|
match c { |
||||||
|
Some(c) => Some(Box::new(self.build_for_expression(c, variables)?)), |
||||||
|
None => None, |
||||||
|
}, |
||||||
|
), |
||||||
|
_ => unimplemented!(), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn pattern_value_from_term_or_variable( |
||||||
|
&self, |
||||||
|
term_or_variable: &TermOrVariable, |
||||||
|
variables: &mut Vec<Variable>, |
||||||
|
) -> Result<PatternValue> { |
||||||
|
Ok(match term_or_variable { |
||||||
|
TermOrVariable::Term(term) => { |
||||||
|
PatternValue::Constant(self.store.encoder().encode_term(term)?) |
||||||
|
} |
||||||
|
TermOrVariable::Variable(variable) => { |
||||||
|
PatternValue::Variable(variable_key(variables, variable)) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn pattern_value_from_named_node_or_variable( |
||||||
|
&self, |
||||||
|
named_node_or_variable: &NamedNodeOrVariable, |
||||||
|
variables: &mut Vec<Variable>, |
||||||
|
) -> Result<PatternValue> { |
||||||
|
Ok(match named_node_or_variable { |
||||||
|
NamedNodeOrVariable::NamedNode(named_node) => { |
||||||
|
PatternValue::Constant(self.store.encoder().encode_named_node(named_node)?) |
||||||
|
} |
||||||
|
NamedNodeOrVariable::Variable(variable) => { |
||||||
|
PatternValue::Variable(variable_key(variables, variable)) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn encode_bindings( |
||||||
|
&self, |
||||||
|
bindings: &StaticBindings, |
||||||
|
variables: &mut Vec<Variable>, |
||||||
|
) -> Result<Vec<EncodedTuple>> { |
||||||
|
let encoder = self.store.encoder(); |
||||||
|
let bindings_variables = bindings.variables(); |
||||||
|
bindings |
||||||
|
.values_iter() |
||||||
|
.map(move |values| { |
||||||
|
let mut result = vec![None; variables.len()]; |
||||||
|
for (key, value) in values.iter().enumerate() { |
||||||
|
if let Some(term) = value { |
||||||
|
result[variable_key(variables, &bindings_variables[key])] = |
||||||
|
Some(encoder.encode_term(term)?); |
||||||
|
} |
||||||
|
} |
||||||
|
Ok(result) |
||||||
|
}).collect() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn variable_key(variables: &mut Vec<Variable>, variable: &Variable) -> usize { |
||||||
|
match slice_key(variables, variable) { |
||||||
|
Some(key) => key, |
||||||
|
None => { |
||||||
|
variables.push(variable.clone()); |
||||||
|
variables.len() - 1 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn slice_key<T: Eq>(slice: &[T], element: &T) -> Option<usize> { |
||||||
|
for (i, item) in slice.iter().enumerate() { |
||||||
|
if item == element { |
||||||
|
return Some(i); |
||||||
|
} |
||||||
|
} |
||||||
|
None |
||||||
|
} |
Loading…
Reference in new issue