diff --git a/lib/src/sparql/algebra.rs b/lib/src/sparql/algebra.rs index 3e12ecf8..874a7a61 100644 --- a/lib/src/sparql/algebra.rs +++ b/lib/src/sparql/algebra.rs @@ -167,7 +167,7 @@ impl StaticBindings { self.values.iter() } - pub fn into_iterator(self) -> BindingsIterator { + pub fn into_iterator(self) -> BindingsIterator<'static> { BindingsIterator { variables: self.variables, iter: Box::new(self.values.into_iter().map(Ok)), @@ -188,15 +188,15 @@ impl Default for StaticBindings { } } -pub struct BindingsIterator { +pub struct BindingsIterator<'a> { variables: Vec, - iter: Box>>>>, + iter: Box>>> + 'a>, } -impl BindingsIterator { +impl<'a> BindingsIterator<'a> { pub fn new( variables: Vec, - iter: Box>>>>, + iter: Box>>> + 'a>, ) -> Self { Self { variables, iter } } @@ -205,7 +205,7 @@ impl BindingsIterator { &*self.variables } - pub fn into_values_iter(self) -> Box>>>> { + pub fn into_values_iter(self) -> Box>>> + 'a> { self.iter } @@ -213,7 +213,7 @@ impl BindingsIterator { self, ) -> ( Vec, - Box>>>>, + Box>>> + 'a>, ) { (self.variables, self.iter) } @@ -1574,8 +1574,8 @@ impl fmt::Display for Query { } } -pub enum QueryResult { - Bindings(BindingsIterator), +pub enum QueryResult<'a> { + Bindings(BindingsIterator<'a>), Boolean(bool), Graph(MemoryGraph), } diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index 5d558daf..5b208420 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -21,7 +21,7 @@ use store::encoded::EncodedQuadsStore; use store::numeric_encoder::*; use Result; -type EncodedTuplesIterator = Box>>; +type EncodedTuplesIterator<'a> = Box> + 'a>; pub struct SimpleEvaluator { store: Arc, @@ -40,18 +40,18 @@ impl SimpleEvaluator { Self { store } } - pub fn evaluate(&self, query: &Query) -> Result { - match query { - Query::Select { algebra, dataset } => { - let (plan, variables) = PlanBuilder::build(&*self.store, algebra)?; - let iter = self.eval_plan(plan, vec![None; variables.len()]); - Ok(QueryResult::Bindings(self.decode_bindings(iter, variables))) - } - _ => unimplemented!(), - } + pub fn evaluate_select_plan<'a>( + &'a self, + plan: &PlanNode, + variables: &[Variable], + ) -> Result> { + let iter = self.eval_plan(plan.clone(), vec![None; variables.len()]); + Ok(QueryResult::Bindings( + self.decode_bindings(iter, variables.to_vec()), + )) } - fn eval_plan(&self, node: PlanNode, from: EncodedTuple) -> EncodedTuplesIterator { + fn eval_plan<'a>(&self, node: PlanNode, from: EncodedTuple) -> EncodedTuplesIterator<'a> { match node { PlanNode::Init => Box::new(once(Ok(from))), PlanNode::StaticBindings { tuples } => Box::new(tuples.into_iter().map(Ok)), @@ -648,11 +648,11 @@ impl SimpleEvaluator { } } - fn decode_bindings( + fn decode_bindings<'a>( &self, - iter: EncodedTuplesIterator, + iter: EncodedTuplesIterator<'a>, variables: Vec, - ) -> BindingsIterator { + ) -> BindingsIterator<'a> { let store = self.store.clone(); BindingsIterator::new( variables, @@ -807,13 +807,13 @@ fn combine_tuples(a: &[Option], b: &[Option]) -> Optio } } -struct JoinIterator { +struct JoinIterator<'a> { left: Vec, - right_iter: EncodedTuplesIterator, + right_iter: EncodedTuplesIterator<'a>, buffered_results: Vec>, } -impl Iterator for JoinIterator { +impl<'a> Iterator for JoinIterator<'a> { type Item = Result; fn next(&mut self) -> Option> { @@ -833,14 +833,14 @@ impl Iterator for JoinIterator { } } -struct LeftJoinIterator { +struct LeftJoinIterator<'a, S: EncodedQuadsStore> { eval: SimpleEvaluator, right_plan: PlanNode, - left_iter: EncodedTuplesIterator, - current_right_iter: Option, + left_iter: EncodedTuplesIterator<'a>, + current_right_iter: Option>, } -impl Iterator for LeftJoinIterator { +impl<'a, S: EncodedQuadsStore> Iterator for LeftJoinIterator<'a, S> { type Item = Result; fn next(&mut self) -> Option> { @@ -867,13 +867,13 @@ impl Iterator for LeftJoinIterator { } } -struct BadLeftJoinIterator { +struct BadLeftJoinIterator<'a, S: EncodedQuadsStore> { input: EncodedTuple, - iter: LeftJoinIterator, + iter: LeftJoinIterator<'a, S>, problem_vars: Vec, } -impl Iterator for BadLeftJoinIterator { +impl<'a, S: EncodedQuadsStore> Iterator for BadLeftJoinIterator<'a, S> { type Item = Result; fn next(&mut self) -> Option> { @@ -903,14 +903,14 @@ impl Iterator for BadLeftJoinIterator { } } -struct UnionIterator { +struct UnionIterator<'a, S: EncodedQuadsStore> { eval: SimpleEvaluator, children_plan: Vec, - input_iter: EncodedTuplesIterator, - current_iters: Vec, + input_iter: EncodedTuplesIterator<'a>, + current_iters: Vec>, } -impl Iterator for UnionIterator { +impl<'a, S: EncodedQuadsStore> Iterator for UnionIterator<'a, S> { type Item = Result; fn next(&mut self) -> Option> { diff --git a/lib/src/sparql/mod.rs b/lib/src/sparql/mod.rs index 4ff9587d..819bb6d8 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -4,10 +4,12 @@ use model::Dataset; use sparql::algebra::Query; use sparql::algebra::QueryResult; +use sparql::algebra::Variable; use sparql::eval::SimpleEvaluator; use sparql::parser::read_sparql_query; +use sparql::plan::PlanBuilder; +use sparql::plan::PlanNode; use std::io::Read; -use std::sync::Arc; use store::encoded::EncodedQuadsStore; use store::encoded::StoreDataset; use Result; @@ -31,20 +33,37 @@ impl SparqlDataset for StoreDataset { type PreparedQuery = SimplePreparedQuery; fn prepare_query(&self, query: impl Read) -> Result> { - Ok(SimplePreparedQuery { - query: read_sparql_query(query, None)?, - store: self.encoded(), + Ok(match read_sparql_query(query, None)? { + Query::Select { algebra, dataset } => { + let store = self.encoded(); + let (plan, variables) = PlanBuilder::build(&*store, &algebra)?; + SimplePreparedQuery::Select { + plan, + variables, + evaluator: SimpleEvaluator::new(store), + } + } + _ => unimplemented!(), }) } } -pub struct SimplePreparedQuery { - query: Query, - store: Arc, +pub enum SimplePreparedQuery { + Select { + plan: PlanNode, + variables: Vec, + evaluator: SimpleEvaluator, + }, } impl PreparedQuery for SimplePreparedQuery { fn exec(&self) -> Result { - SimpleEvaluator::new(self.store.clone()).evaluate(&self.query) + match self { + SimplePreparedQuery::Select { + plan, + variables, + evaluator, + } => evaluator.evaluate_select_plan(&plan, &variables), + } } } diff --git a/lib/src/sparql/xml_results.rs b/lib/src/sparql/xml_results.rs index fa370254..cf9fffc9 100644 --- a/lib/src/sparql/xml_results.rs +++ b/lib/src/sparql/xml_results.rs @@ -10,7 +10,7 @@ use std::iter::empty; use std::str::FromStr; use Result; -pub fn read_xml_results(source: impl BufRead + 'static) -> Result { +pub fn read_xml_results(source: impl BufRead + 'static) -> Result> { enum State { Start, Sparql, diff --git a/lib/tests/sparql_test_cases.rs b/lib/tests/sparql_test_cases.rs index 347c49ef..5951fd1b 100644 --- a/lib/tests/sparql_test_cases.rs +++ b/lib/tests/sparql_test_cases.rs @@ -211,30 +211,34 @@ fn sparql_w3c_query_evaluation_testsuite() { .unwrap() .for_each(|triple| named_graph.insert(&triple.unwrap()).unwrap()); } - match data - .prepare_query(client.get(&test.query).unwrap()) - .and_then(|p| p.exec()) - { + match data.prepare_query(client.get(&test.query).unwrap()) { Err(error) => assert!( false, "Failure to parse query of {} with error: {}", test, error ), - Ok(result) => { - let actual_graph = to_graph(result).unwrap(); - let expected_graph = client - .load_sparql_query_result_graph(test.result.clone().unwrap()) - .unwrap(); - assert!( - actual_graph.is_isomorphic(&expected_graph).unwrap(), - "Failure on {}.\nExpected file:\n{}\nOutput file:\n{}\nParsed query:\n{}\nData:\n{}\n", - test, - expected_graph, - actual_graph, - client.load_sparql_query(test.query.clone()).unwrap(), - data - ) - } + Ok(query) => match query.exec() { + Err(error) => assert!( + false, + "Failure to execute query of {} with error: {}", + test, error + ), + Ok(result) => { + let actual_graph = to_graph(result).unwrap(); + let expected_graph = client + .load_sparql_query_result_graph(test.result.clone().unwrap()) + .unwrap(); + assert!( + actual_graph.is_isomorphic(&expected_graph).unwrap(), + "Failure on {}.\nExpected file:\n{}\nOutput file:\n{}\nParsed query:\n{}\nData:\n{}\n", + test, + expected_graph, + actual_graph, + client.load_sparql_query(test.query.clone()).unwrap(), + data + ) + } + }, } } else { assert!(false, "Not supported test: {}", test);