diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index c75d12cc..ce8256d2 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -1,6 +1,7 @@ use crate::model::BlankNode; use crate::model::Triple; use crate::sparql::model::*; +use crate::sparql::QueryOptions; use crate::sparql::plan::*; use crate::store::numeric_encoder::*; use crate::store::StoreConnection; @@ -58,21 +59,26 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { &'b self, plan: &'b PlanNode, variables: &[Variable], + options: &'b QueryOptions<'b> ) -> Result> where 'a: 'b, { - let iter = self.eval_plan(plan, vec![None; variables.len()]); + let iter = self.eval_plan(plan, vec![None; variables.len()], &options); Ok(QueryResult::Bindings( self.decode_bindings(iter, variables.to_vec()), )) } - pub fn evaluate_ask_plan<'b>(&'b self, plan: &'b PlanNode) -> Result> + pub fn evaluate_ask_plan<'b>( + &'b self, + plan: &'b PlanNode, + options: &'b QueryOptions<'b> + ) -> Result> where 'a: 'b, { - match self.eval_plan(plan, vec![]).next() { + match self.eval_plan(plan, vec![], &options).next() { Some(Ok(_)) => Ok(QueryResult::Boolean(true)), Some(Err(error)) => Err(error), None => Ok(QueryResult::Boolean(false)), @@ -83,31 +89,41 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { &'b self, plan: &'b PlanNode, construct: &'b [TripleTemplate], + options: &'b QueryOptions<'b> ) -> Result> where 'a: 'b, { Ok(QueryResult::Graph(Box::new(ConstructIterator { eval: self, - iter: self.eval_plan(plan, vec![]), + iter: self.eval_plan(plan, vec![], options), template: construct, buffered_results: Vec::default(), bnodes: Vec::default(), }))) } - pub fn evaluate_describe_plan<'b>(&'b self, plan: &'b PlanNode) -> Result> + pub fn evaluate_describe_plan<'b>( + &'b self, + plan: &'b PlanNode, + options: &'b QueryOptions<'b> + ) -> Result> where 'a: 'b, { Ok(QueryResult::Graph(Box::new(DescribeIterator { eval: self, - iter: self.eval_plan(plan, vec![]), + iter: self.eval_plan(plan, vec![], options), quads: Box::new(empty()), }))) } - fn eval_plan<'b>(&'b self, node: &'b PlanNode, from: EncodedTuple) -> EncodedTuplesIterator<'b> + fn eval_plan<'b>( + &'b self, + node: &'b PlanNode, + from: EncodedTuple, + options: &'b QueryOptions<'b> + ) -> EncodedTuplesIterator<'b> where 'a: 'b, { @@ -120,7 +136,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { predicate, object, graph_name, - } => Box::new(self.eval_plan(&*child, from).flat_map_ok(move |tuple| { + } => Box::new(self.eval_plan(&*child, from, options).flat_map_ok(move |tuple| { let mut iter = self.dataset.quads_for_pattern( get_pattern_value(&subject, &tuple), get_pattern_value(&predicate, &tuple), @@ -186,7 +202,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { path, object, graph_name, - } => Box::new(self.eval_plan(&*child, from).flat_map_ok(move |tuple| { + } => Box::new(self.eval_plan(&*child, from, options).flat_map_ok(move |tuple| { let input_subject = get_pattern_value(&subject, &tuple); let input_object = get_pattern_value(&object, &tuple); let input_graph_name = @@ -244,7 +260,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { //TODO: very dumb implementation let mut errors = Vec::default(); let left_values = self - .eval_plan(&*left, from.clone()) + .eval_plan(&*left, from.clone(), options) .filter_map(|result| match result { Ok(result) => Some(result), Err(error) => { @@ -255,18 +271,18 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .collect::>(); Box::new(JoinIterator { left: left_values, - right_iter: self.eval_plan(&*right, from), + right_iter: self.eval_plan(&*right, from, options), buffered_results: errors, }) } PlanNode::AntiJoin { left, right } => { //TODO: dumb implementation let right: Vec<_> = self - .eval_plan(&*right, from.clone()) + .eval_plan(&*right, from.clone(), options) .filter_map(|result| result.ok()) .collect(); Box::new(AntiJoinIterator { - left_iter: self.eval_plan(&*left, from), + left_iter: self.eval_plan(&*left, from, options), right, }) } @@ -281,8 +297,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { let iter = LeftJoinIterator { eval: self, right_plan: &*right, - left_iter: self.eval_plan(&*left, filtered_from), + left_iter: self.eval_plan(&*left, filtered_from, options), current_right: Box::new(empty()), + options, }; if problem_vars.is_empty() { Box::new(iter) @@ -296,10 +313,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanNode::Filter { child, expression } => { let eval = self; - Box::new(self.eval_plan(&*child, from).filter(move |tuple| { + Box::new(self.eval_plan(&*child, from, options).filter(move |tuple| { match tuple { Ok(tuple) => eval - .eval_expression(&expression, tuple) + .eval_expression(&expression, tuple, options) .and_then(|term| eval.to_bool(term)) .unwrap_or(false), Err(_) => true, @@ -312,6 +329,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { input: from, current_iterator: Box::new(empty()), current_plan: 0, + options, }), PlanNode::Extend { child, @@ -319,9 +337,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { expression, } => { let eval = self; - Box::new(self.eval_plan(&*child, from).map(move |tuple| { + Box::new(self.eval_plan(&*child, from, options).map(move |tuple| { let mut tuple = tuple?; - if let Some(value) = eval.eval_expression(&expression, &tuple) { + if let Some(value) = eval.eval_expression(&expression, &tuple, options) { put_value(*position, value, &mut tuple) } Ok(tuple) @@ -330,7 +348,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { PlanNode::Sort { child, by } => { let mut errors = Vec::default(); let mut values = self - .eval_plan(&*child, from) + .eval_plan(&*child, from, options) .filter_map(|result| match result { Ok(result) => Some(result), Err(error) => { @@ -343,14 +361,14 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { for comp in by { match comp { Comparator::Asc(expression) => { - match self.cmp_according_to_expression(a, b, &expression) { + match self.cmp_according_to_expression(a, b, &expression, options) { Ordering::Greater => return Ordering::Greater, Ordering::Less => return Ordering::Less, Ordering::Equal => (), } } Comparator::Desc(expression) => { - match self.cmp_according_to_expression(a, b, &expression) { + match self.cmp_according_to_expression(a, b, &expression, options) { Ordering::Greater => return Ordering::Less, Ordering::Less => return Ordering::Greater, Ordering::Equal => (), @@ -363,16 +381,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { Box::new(errors.into_iter().chain(values.into_iter().map(Ok))) } PlanNode::HashDeduplicate { child } => { - Box::new(hash_deduplicate(self.eval_plan(&*child, from))) + Box::new(hash_deduplicate(self.eval_plan(&*child, from, options))) } - PlanNode::Skip { child, count } => Box::new(self.eval_plan(&*child, from).skip(*count)), + PlanNode::Skip { child, count } => Box::new(self.eval_plan(&*child, from, options).skip(*count)), PlanNode::Limit { child, count } => { - Box::new(self.eval_plan(&*child, from).take(*count)) + Box::new(self.eval_plan(&*child, from, options).take(*count)) } PlanNode::Project { child, mapping } => { //TODO: use from somewhere? Box::new( - self.eval_plan(&*child, vec![None; mapping.len()]) + self.eval_plan(&*child, vec![None; mapping.len()], options) .map(move |tuple| { let tuple = tuple?; let mut output_tuple = vec![None; from.len()]; @@ -394,7 +412,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { let mut errors = Vec::default(); let mut accumulators_for_group = HashMap::>, Vec>>::default(); - self.eval_plan(child, from) + self.eval_plan(child, from, options) .filter_map(|result| match result { Ok(result) => Some(result), Err(error) => { @@ -426,7 +444,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { aggregate .parameter .as_ref() - .and_then(|parameter| self.eval_expression(¶meter, &tuple)), + .and_then(|parameter| self.eval_expression(¶meter, &tuple, options)), ); } }); @@ -666,24 +684,25 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .map(|e| e.map(|e| (e, e))) } - fn eval_expression( - &self, + fn eval_expression<'b>( + &'b self, expression: &PlanExpression, tuple: &[Option], + options: &QueryOptions<'b> ) -> Option { match expression { PlanExpression::Constant(t) => Some(*t), PlanExpression::Variable(v) => get_tuple_value(*v, tuple), PlanExpression::Exists(node) => { - Some(self.eval_plan(node, tuple.to_vec()).next().is_some().into()) + Some(self.eval_plan(node, tuple.to_vec(), options).next().is_some().into()) } PlanExpression::Or(a, b) => { - match self.eval_expression(a, tuple).and_then(|v| self.to_bool(v)) { + match self.eval_expression(a, tuple, options).and_then(|v| self.to_bool(v)) { Some(true) => Some(true.into()), - Some(false) => self.eval_expression(b, tuple), + Some(false) => self.eval_expression(b, tuple, options), None => { if Some(true) - == self.eval_expression(b, tuple).and_then(|v| self.to_bool(v)) + == self.eval_expression(b, tuple, options).and_then(|v| self.to_bool(v)) { Some(true.into()) } else { @@ -693,13 +712,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } } PlanExpression::And(a, b) => match self - .eval_expression(a, tuple) + .eval_expression(a, tuple, options) .and_then(|v| self.to_bool(v)) { - Some(true) => self.eval_expression(b, tuple), + Some(true) => self.eval_expression(b, tuple, options), Some(false) => Some(false.into()), None => { - if Some(false) == self.eval_expression(b, tuple).and_then(|v| self.to_bool(v)) { + if Some(false) == self.eval_expression(b, tuple, options).and_then(|v| self.to_bool(v)) { Some(false.into()) } else { None @@ -707,26 +726,26 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } }, PlanExpression::Equal(a, b) => { - let a = self.eval_expression(a, tuple)?; - let b = self.eval_expression(b, tuple)?; + let a = self.eval_expression(a, tuple, options)?; + let b = self.eval_expression(b, tuple, options)?; self.equals(a, b).map(|v| v.into()) } PlanExpression::NotEqual(a, b) => { - let a = self.eval_expression(a, tuple)?; - let b = self.eval_expression(b, tuple)?; + let a = self.eval_expression(a, tuple, options)?; + let b = self.eval_expression(b, tuple, options)?; self.equals(a, b).map(|v| (!v).into()) } PlanExpression::Greater(a, b) => Some( (self.partial_cmp_literals( - self.eval_expression(a, tuple)?, - self.eval_expression(b, tuple)?, + self.eval_expression(a, tuple, options)?, + self.eval_expression(b, tuple, options)?, )? == Ordering::Greater) .into(), ), PlanExpression::GreaterOrEq(a, b) => Some( match self.partial_cmp_literals( - self.eval_expression(a, tuple)?, - self.eval_expression(b, tuple)?, + self.eval_expression(a, tuple, options)?, + self.eval_expression(b, tuple, options)?, )? { Ordering::Greater | Ordering::Equal => true, Ordering::Less => false, @@ -735,15 +754,15 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { ), PlanExpression::Lower(a, b) => Some( (self.partial_cmp_literals( - self.eval_expression(a, tuple)?, - self.eval_expression(b, tuple)?, + self.eval_expression(a, tuple, options)?, + self.eval_expression(b, tuple, options)?, )? == Ordering::Less) .into(), ), PlanExpression::LowerOrEq(a, b) => Some( match self.partial_cmp_literals( - self.eval_expression(a, tuple)?, - self.eval_expression(b, tuple)?, + self.eval_expression(a, tuple, options)?, + self.eval_expression(b, tuple, options)?, )? { Ordering::Less | Ordering::Equal => true, Ordering::Greater => false, @@ -751,10 +770,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .into(), ), PlanExpression::In(e, l) => { - let needed = self.eval_expression(e, tuple)?; + let needed = self.eval_expression(e, tuple, options)?; let mut error = false; for possible in l { - if let Some(possible) = self.eval_expression(possible, tuple) { + if let Some(possible) = self.eval_expression(possible, tuple, options) { if Some(true) == self.equals(needed, possible) { return Some(true.into()); } @@ -768,25 +787,25 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { Some(false.into()) } } - PlanExpression::Add(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { + PlanExpression::Add(a, b) => Some(match self.parse_numeric_operands(a, b, tuple, options)? { NumericBinaryOperands::Float(v1, v2) => (v1 + v2).into(), NumericBinaryOperands::Double(v1, v2) => (v1 + v2).into(), NumericBinaryOperands::Integer(v1, v2) => v1.checked_add(v2)?.into(), NumericBinaryOperands::Decimal(v1, v2) => v1.checked_add(v2)?.into(), }), - PlanExpression::Sub(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { + PlanExpression::Sub(a, b) => Some(match self.parse_numeric_operands(a, b, tuple, options)? { NumericBinaryOperands::Float(v1, v2) => (v1 - v2).into(), NumericBinaryOperands::Double(v1, v2) => (v1 - v2).into(), NumericBinaryOperands::Integer(v1, v2) => v1.checked_sub(v2)?.into(), NumericBinaryOperands::Decimal(v1, v2) => v1.checked_sub(v2)?.into(), }), - PlanExpression::Mul(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { + PlanExpression::Mul(a, b) => Some(match self.parse_numeric_operands(a, b, tuple, options)? { NumericBinaryOperands::Float(v1, v2) => (v1 * v2).into(), NumericBinaryOperands::Double(v1, v2) => (v1 * v2).into(), NumericBinaryOperands::Integer(v1, v2) => v1.checked_mul(v2)?.into(), NumericBinaryOperands::Decimal(v1, v2) => v1.checked_mul(v2)?.into(), }), - PlanExpression::Div(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { + PlanExpression::Div(a, b) => Some(match self.parse_numeric_operands(a, b, tuple, options)? { NumericBinaryOperands::Float(v1, v2) => (v1 / v2).into(), NumericBinaryOperands::Double(v1, v2) => (v1 / v2).into(), NumericBinaryOperands::Integer(v1, v2) => Decimal::from_i128(v1)? @@ -794,14 +813,14 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .into(), NumericBinaryOperands::Decimal(v1, v2) => v1.checked_div(v2)?.into(), }), - PlanExpression::UnaryPlus(e) => match self.eval_expression(e, tuple)? { + PlanExpression::UnaryPlus(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::FloatLiteral(value) => Some((*value).into()), EncodedTerm::DoubleLiteral(value) => Some((*value).into()), EncodedTerm::IntegerLiteral(value) => Some((value).into()), EncodedTerm::DecimalLiteral(value) => Some((value).into()), _ => None, }, - PlanExpression::UnaryMinus(e) => match self.eval_expression(e, tuple)? { + PlanExpression::UnaryMinus(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::FloatLiteral(value) => Some((-*value).into()), EncodedTerm::DoubleLiteral(value) => Some((-*value).into()), EncodedTerm::IntegerLiteral(value) => Some((-value).into()), @@ -809,12 +828,12 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { _ => None, }, PlanExpression::UnaryNot(e) => self - .to_bool(self.eval_expression(e, tuple)?) + .to_bool(self.eval_expression(e, tuple, options)?) .map(|v| (!v).into()), PlanExpression::Str(e) => Some(EncodedTerm::StringLiteral { - value_id: self.to_string_id(self.eval_expression(e, tuple)?)?, + value_id: self.to_string_id(self.eval_expression(e, tuple, options)?)?, }), - PlanExpression::Lang(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Lang(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::LangStringLiteral { language_id, .. } => { Some(EncodedTerm::StringLiteral { value_id: language_id, @@ -825,9 +844,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { }, PlanExpression::LangMatches(language_tag, language_range) => { let language_tag = - self.to_simple_string(self.eval_expression(language_tag, tuple)?)?; + self.to_simple_string(self.eval_expression(language_tag, tuple, options)?)?; let language_range = - self.to_simple_string(self.eval_expression(language_range, tuple)?)?; + self.to_simple_string(self.eval_expression(language_range, tuple, options)?)?; Some( if &*language_range == "*" { !language_tag.is_empty() @@ -845,10 +864,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .into(), ) } - PlanExpression::Datatype(e) => self.eval_expression(e, tuple)?.datatype(), + PlanExpression::Datatype(e) => self.eval_expression(e, tuple, options)?.datatype(), PlanExpression::Bound(v) => Some(has_tuple_value(*v, tuple).into()), PlanExpression::IRI(e) => { - let iri_id = match self.eval_expression(e, tuple)? { + let iri_id = match self.eval_expression(e, tuple, options)? { EncodedTerm::NamedNode { iri_id } => Some(iri_id), EncodedTerm::StringLiteral { value_id } => Some(value_id), _ => None, @@ -864,7 +883,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { PlanExpression::BNode(id) => match id { Some(id) => { if let EncodedTerm::StringLiteral { value_id } = - self.eval_expression(id, tuple)? + self.eval_expression(id, tuple, options)? { Some(EncodedTerm::BlankNode { id: *self @@ -883,28 +902,28 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { }), }, PlanExpression::Rand => Some(random::().into()), - PlanExpression::Abs(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Abs(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::IntegerLiteral(value) => Some(value.checked_abs()?.into()), EncodedTerm::DecimalLiteral(value) => Some(value.abs().into()), EncodedTerm::FloatLiteral(value) => Some(value.abs().into()), EncodedTerm::DoubleLiteral(value) => Some(value.abs().into()), _ => None, }, - PlanExpression::Ceil(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Ceil(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::IntegerLiteral(value) => Some(value.into()), EncodedTerm::DecimalLiteral(value) => Some(value.ceil().into()), EncodedTerm::FloatLiteral(value) => Some(value.ceil().into()), EncodedTerm::DoubleLiteral(value) => Some(value.ceil().into()), _ => None, }, - PlanExpression::Floor(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Floor(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::IntegerLiteral(value) => Some(value.into()), EncodedTerm::DecimalLiteral(value) => Some(value.floor().into()), EncodedTerm::FloatLiteral(value) => Some(value.floor().into()), EncodedTerm::DoubleLiteral(value) => Some(value.floor().into()), _ => None, }, - PlanExpression::Round(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Round(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::IntegerLiteral(value) => Some(value.into()), EncodedTerm::DecimalLiteral(value) => Some( value @@ -920,7 +939,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { let mut language = None; for e in l { let (value, e_language) = - self.to_string_and_language(self.eval_expression(e, tuple)?)?; + self.to_string_and_language(self.eval_expression(e, tuple, options)?)?; if let Some(lang) = language { if lang != e_language { language = Some(None) @@ -934,17 +953,17 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanExpression::SubStr(source, starting_loc, length) => { let (source, language) = - self.to_string_and_language(self.eval_expression(source, tuple)?)?; + self.to_string_and_language(self.eval_expression(source, tuple, options)?)?; let starting_location: usize = if let EncodedTerm::IntegerLiteral(v) = - self.eval_expression(starting_loc, tuple)? + self.eval_expression(starting_loc, tuple, options)? { v.try_into().ok()? } else { return None; }; let length: Option = if let Some(length) = length { - if let EncodedTerm::IntegerLiteral(v) = self.eval_expression(length, tuple)? { + if let EncodedTerm::IntegerLiteral(v) = self.eval_expression(length, tuple, options)? { Some(v.try_into().ok()?) } else { return None; @@ -976,45 +995,45 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanExpression::StrLen(arg) => Some( (self - .to_string(self.eval_expression(arg, tuple)?)? + .to_string(self.eval_expression(arg, tuple, options)?)? .chars() .count() as i128) .into(), ), PlanExpression::Replace(arg, pattern, replacement, flags) => { let regex = self.compile_pattern( - self.eval_expression(pattern, tuple)?, + self.eval_expression(pattern, tuple, options)?, if let Some(flags) = flags { - Some(self.eval_expression(flags, tuple)?) + Some(self.eval_expression(flags, tuple, options)?) } else { None }, )?; let (text, language) = - self.to_string_and_language(self.eval_expression(arg, tuple)?)?; + self.to_string_and_language(self.eval_expression(arg, tuple, options)?)?; let replacement = - self.to_simple_string(self.eval_expression(replacement, tuple)?)?; + self.to_simple_string(self.eval_expression(replacement, tuple, options)?)?; self.build_plain_literal(®ex.replace_all(&text, &replacement as &str), language) } PlanExpression::UCase(e) => { let (value, language) = - self.to_string_and_language(self.eval_expression(e, tuple)?)?; + self.to_string_and_language(self.eval_expression(e, tuple, options)?)?; self.build_plain_literal(&value.to_uppercase(), language) } PlanExpression::LCase(e) => { let (value, language) = - self.to_string_and_language(self.eval_expression(e, tuple)?)?; + self.to_string_and_language(self.eval_expression(e, tuple, options)?)?; self.build_plain_literal(&value.to_lowercase(), language) } PlanExpression::StrStarts(arg1, arg2) => { let (arg1, arg2, _) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple)?, - self.eval_expression(arg2, tuple)?, + self.eval_expression(arg1, tuple, options)?, + self.eval_expression(arg2, tuple, options)?, )?; Some((&arg1).starts_with(&arg2 as &str).into()) } PlanExpression::EncodeForURI(ltrl) => { - let ltlr = self.to_string(self.eval_expression(ltrl, tuple)?)?; + let ltlr = self.to_string(self.eval_expression(ltrl, tuple, options)?)?; let mut result = Vec::with_capacity(ltlr.len()); for c in ltlr.bytes() { match c { @@ -1042,22 +1061,22 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanExpression::StrEnds(arg1, arg2) => { let (arg1, arg2, _) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple)?, - self.eval_expression(arg2, tuple)?, + self.eval_expression(arg1, tuple, options)?, + self.eval_expression(arg2, tuple, options)?, )?; Some((&arg1).ends_with(&arg2 as &str).into()) } PlanExpression::Contains(arg1, arg2) => { let (arg1, arg2, _) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple)?, - self.eval_expression(arg2, tuple)?, + self.eval_expression(arg1, tuple, options)?, + self.eval_expression(arg2, tuple, options)?, )?; Some((&arg1).contains(&arg2 as &str).into()) } PlanExpression::StrBefore(arg1, arg2) => { let (arg1, arg2, language) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple)?, - self.eval_expression(arg2, tuple)?, + self.eval_expression(arg1, tuple, options)?, + self.eval_expression(arg2, tuple, options)?, )?; if let Some(position) = (&arg1).find(&arg2 as &str) { self.build_plain_literal(&arg1[..position], language) @@ -1067,8 +1086,8 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanExpression::StrAfter(arg1, arg2) => { let (arg1, arg2, language) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple)?, - self.eval_expression(arg2, tuple)?, + self.eval_expression(arg1, tuple, options)?, + self.eval_expression(arg2, tuple, options)?, )?; if let Some(position) = (&arg1).find(&arg2 as &str) { self.build_plain_literal(&arg1[position + arg2.len()..], language) @@ -1076,40 +1095,40 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { Some(ENCODED_EMPTY_STRING_LITERAL) } } - PlanExpression::Year(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Year(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::DateLiteral(date) => Some(date.year().into()), EncodedTerm::NaiveDateLiteral(date) => Some(date.year().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.year().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.year().into()), _ => None, }, - PlanExpression::Month(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Month(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::DateLiteral(date) => Some(date.year().into()), EncodedTerm::NaiveDateLiteral(date) => Some(date.month().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.month().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.month().into()), _ => None, }, - PlanExpression::Day(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Day(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::DateLiteral(date) => Some(date.year().into()), EncodedTerm::NaiveDateLiteral(date) => Some(date.day().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.day().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.day().into()), _ => None, }, - PlanExpression::Hours(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Hours(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::NaiveTimeLiteral(time) => Some(time.hour().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.hour().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.hour().into()), _ => None, }, - PlanExpression::Minutes(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Minutes(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::NaiveTimeLiteral(time) => Some(time.minute().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.minute().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.minute().into()), _ => None, }, - PlanExpression::Seconds(e) => match self.eval_expression(e, tuple)? { + PlanExpression::Seconds(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::NaiveTimeLiteral(time) => Some( (Decimal::new(time.nanosecond().into(), 9) + Decimal::from(time.second())) .into(), @@ -1127,7 +1146,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { _ => None, }, PlanExpression::Timezone(e) => { - let timezone = match self.eval_expression(e, tuple)? { + let timezone = match self.eval_expression(e, tuple, options)? { EncodedTerm::DateLiteral(date) => date.timezone(), EncodedTerm::DateTimeLiteral(date_time) => date_time.timezone(), _ => return None, @@ -1161,7 +1180,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { }) } PlanExpression::Tz(e) => { - let timezone = match self.eval_expression(e, tuple)? { + let timezone = match self.eval_expression(e, tuple, options)? { EncodedTerm::DateLiteral(date) => Some(date.timezone()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.timezone()), EncodedTerm::NaiveDateLiteral(_) @@ -1192,38 +1211,38 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .to_hyphenated() .encode_lower(&mut Uuid::encode_buffer()), ), - PlanExpression::MD5(arg) => self.hash::(arg, tuple), - PlanExpression::SHA1(arg) => self.hash::(arg, tuple), - PlanExpression::SHA256(arg) => self.hash::(arg, tuple), - PlanExpression::SHA384(arg) => self.hash::(arg, tuple), - PlanExpression::SHA512(arg) => self.hash::(arg, tuple), + PlanExpression::MD5(arg) => self.hash::(arg, tuple, options), + PlanExpression::SHA1(arg) => self.hash::(arg, tuple, options), + PlanExpression::SHA256(arg) => self.hash::(arg, tuple, options), + PlanExpression::SHA384(arg) => self.hash::(arg, tuple, options), + PlanExpression::SHA512(arg) => self.hash::(arg, tuple, options), PlanExpression::Coalesce(l) => { for e in l { - if let Some(result) = self.eval_expression(e, tuple) { + if let Some(result) = self.eval_expression(e, tuple, options) { return Some(result); } } None } PlanExpression::If(a, b, c) => { - if self.to_bool(self.eval_expression(a, tuple)?)? { - self.eval_expression(b, tuple) + if self.to_bool(self.eval_expression(a, tuple, options)?)? { + self.eval_expression(b, tuple, options) } else { - self.eval_expression(c, tuple) + self.eval_expression(c, tuple, options) } } PlanExpression::StrLang(lexical_form, lang_tag) => { Some(EncodedTerm::LangStringLiteral { value_id: self - .to_simple_string_id(self.eval_expression(lexical_form, tuple)?)?, + .to_simple_string_id(self.eval_expression(lexical_form, tuple, options)?)?, language_id: self - .to_simple_string_id(self.eval_expression(lang_tag, tuple)?)?, + .to_simple_string_id(self.eval_expression(lang_tag, tuple, options)?)?, }) } PlanExpression::StrDT(lexical_form, datatype) => { - let value = self.to_simple_string(self.eval_expression(lexical_form, tuple)?)?; + let value = self.to_simple_string(self.eval_expression(lexical_form, tuple, options)?)?; let datatype = if let EncodedTerm::NamedNode { iri_id } = - self.eval_expression(datatype, tuple)? + self.eval_expression(datatype, tuple, options)? { self.dataset.get_str(iri_id).ok()? } else { @@ -1238,19 +1257,19 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .ok() } PlanExpression::SameTerm(a, b) => { - Some((self.eval_expression(a, tuple)? == self.eval_expression(b, tuple)?).into()) + Some((self.eval_expression(a, tuple, options)? == self.eval_expression(b, tuple, options)?).into()) } PlanExpression::IsIRI(e) => { - Some(self.eval_expression(e, tuple)?.is_named_node().into()) + Some(self.eval_expression(e, tuple, options)?.is_named_node().into()) } PlanExpression::IsBlank(e) => { - Some(self.eval_expression(e, tuple)?.is_blank_node().into()) + Some(self.eval_expression(e, tuple, options)?.is_blank_node().into()) } PlanExpression::IsLiteral(e) => { - Some(self.eval_expression(e, tuple)?.is_literal().into()) + Some(self.eval_expression(e, tuple, options)?.is_literal().into()) } PlanExpression::IsNumeric(e) => Some( - match self.eval_expression(e, tuple)? { + match self.eval_expression(e, tuple, options)? { EncodedTerm::FloatLiteral(_) | EncodedTerm::DoubleLiteral(_) | EncodedTerm::IntegerLiteral(_) @@ -1261,24 +1280,24 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { ), PlanExpression::Regex(text, pattern, flags) => { let regex = self.compile_pattern( - self.eval_expression(pattern, tuple)?, + self.eval_expression(pattern, tuple, options)?, if let Some(flags) = flags { - Some(self.eval_expression(flags, tuple)?) + Some(self.eval_expression(flags, tuple, options)?) } else { None }, )?; - let text = self.to_string(self.eval_expression(text, tuple)?)?; + let text = self.to_string(self.eval_expression(text, tuple, options)?)?; Some(regex.is_match(&text).into()) } - PlanExpression::BooleanCast(e) => match self.eval_expression(e, tuple)? { + PlanExpression::BooleanCast(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::BooleanLiteral(value) => Some(value.into()), EncodedTerm::StringLiteral { value_id } => { parse_boolean_str(&*self.dataset.get_str(value_id).ok()??) } _ => None, }, - PlanExpression::DoubleCast(e) => match self.eval_expression(e, tuple)? { + PlanExpression::DoubleCast(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::FloatLiteral(value) => Some(value.to_f64()?.into()), EncodedTerm::DoubleLiteral(value) => Some(value.to_f64()?.into()), EncodedTerm::IntegerLiteral(value) => Some(value.to_f64()?.into()), @@ -1291,7 +1310,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::FloatCast(e) => match self.eval_expression(e, tuple)? { + PlanExpression::FloatCast(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::FloatLiteral(value) => Some(value.to_f32()?.into()), EncodedTerm::DoubleLiteral(value) => Some(value.to_f32()?.into()), EncodedTerm::IntegerLiteral(value) => Some(value.to_f32()?.into()), @@ -1304,7 +1323,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::IntegerCast(e) => match self.eval_expression(e, tuple)? { + PlanExpression::IntegerCast(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::FloatLiteral(value) => Some(value.to_i128()?.into()), EncodedTerm::DoubleLiteral(value) => Some(value.to_i128()?.into()), EncodedTerm::IntegerLiteral(value) => Some(value.to_i128()?.into()), @@ -1315,7 +1334,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::DecimalCast(e) => match self.eval_expression(e, tuple)? { + PlanExpression::DecimalCast(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::FloatLiteral(value) => Some(Decimal::from_f32(*value)?.into()), EncodedTerm::DoubleLiteral(value) => Some(Decimal::from_f64(*value)?.into()), EncodedTerm::IntegerLiteral(value) => Some(Decimal::from_i128(value)?.into()), @@ -1333,7 +1352,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::DateCast(e) => match self.eval_expression(e, tuple)? { + PlanExpression::DateCast(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::DateLiteral(value) => Some(value.into()), EncodedTerm::NaiveDateLiteral(value) => Some(value.into()), EncodedTerm::DateTimeLiteral(value) => Some(value.date().into()), @@ -1343,7 +1362,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::TimeCast(e) => match self.eval_expression(e, tuple)? { + PlanExpression::TimeCast(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::NaiveTimeLiteral(value) => Some(value.into()), EncodedTerm::DateTimeLiteral(value) => Some(value.time().into()), EncodedTerm::NaiveDateTimeLiteral(value) => Some(value.time().into()), @@ -1352,7 +1371,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::DateTimeCast(e) => match self.eval_expression(e, tuple)? { + PlanExpression::DateTimeCast(e) => match self.eval_expression(e, tuple, options)? { EncodedTerm::DateTimeLiteral(value) => Some(value.into()), EncodedTerm::NaiveDateTimeLiteral(value) => Some(value.into()), EncodedTerm::StringLiteral { value_id } => { @@ -1361,7 +1380,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { _ => None, }, PlanExpression::StringCast(e) => Some(EncodedTerm::StringLiteral { - value_id: self.to_string_id(self.eval_expression(e, tuple)?)?, + value_id: self.to_string_id(self.eval_expression(e, tuple, options)?)?, }), } } @@ -1526,15 +1545,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { regex_builder.build().ok() } - fn parse_numeric_operands( - &self, + fn parse_numeric_operands<'b>( + &'b self, e1: &PlanExpression, e2: &PlanExpression, tuple: &[Option], + options: &QueryOptions<'b> ) -> Option { NumericBinaryOperands::new( - self.eval_expression(&e1, tuple)?, - self.eval_expression(&e2, tuple)?, + self.eval_expression(&e1, tuple, options)?, + self.eval_expression(&e2, tuple, options)?, ) } @@ -1674,15 +1694,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } } - fn cmp_according_to_expression( - &self, + fn cmp_according_to_expression<'b>( + &'b self, tuple_a: &[Option], tuple_b: &[Option], expression: &PlanExpression, + options: &QueryOptions<'b> ) -> Ordering { self.cmp_terms( - self.eval_expression(expression, tuple_a), - self.eval_expression(expression, tuple_b), + self.eval_expression(expression, tuple_a, options), + self.eval_expression(expression, tuple_b, options), ) } @@ -1793,12 +1814,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { ) } - fn hash( - &self, + fn hash<'b, H: Digest>( + &'b self, arg: &PlanExpression, tuple: &[Option], + options: &QueryOptions<'b> ) -> Option { - let input = self.to_simple_string(self.eval_expression(arg, tuple)?)?; + let input = self.to_simple_string(self.eval_expression(arg, tuple, options)?)?; let hash = hex::encode(H::new().chain(&input as &str).result()); self.build_string_literal(&hash) } @@ -2067,6 +2089,7 @@ struct LeftJoinIterator<'a, S: StoreConnection + 'a> { right_plan: &'a PlanNode, left_iter: EncodedTuplesIterator<'a>, current_right: EncodedTuplesIterator<'a>, + options: &'a QueryOptions<'a>, } impl<'a, S: StoreConnection> Iterator for LeftJoinIterator<'a, S> { @@ -2078,7 +2101,7 @@ impl<'a, S: StoreConnection> Iterator for LeftJoinIterator<'a, S> { } match self.left_iter.next()? { Ok(left_tuple) => { - self.current_right = self.eval.eval_plan(self.right_plan, left_tuple.clone()); + self.current_right = self.eval.eval_plan(self.right_plan, left_tuple.clone(), self.options); if let Some(right_tuple) = self.current_right.next() { Some(right_tuple) } else { @@ -2132,6 +2155,7 @@ struct UnionIterator<'a, S: StoreConnection + 'a> { input: EncodedTuple, current_iterator: EncodedTuplesIterator<'a>, current_plan: usize, + options: &'a QueryOptions<'a>, } impl<'a, S: StoreConnection> Iterator for UnionIterator<'a, S> { @@ -2147,13 +2171,13 @@ impl<'a, S: StoreConnection> Iterator for UnionIterator<'a, S> { } self.current_iterator = self .eval - .eval_plan(&self.plans[self.current_plan], self.input.clone()); + .eval_plan(&self.plans[self.current_plan], self.input.clone(), self.options); self.current_plan += 1; } } } -struct ConstructIterator<'a, S: StoreConnection> { +struct ConstructIterator<'a, S: StoreConnection + 'a> { eval: &'a SimpleEvaluator, iter: EncodedTuplesIterator<'a>, template: &'a [TripleTemplate], @@ -2161,7 +2185,7 @@ struct ConstructIterator<'a, S: StoreConnection> { bnodes: Vec, } -impl<'a, S: StoreConnection> Iterator for ConstructIterator<'a, S> { +impl<'a, S: StoreConnection + 'a> Iterator for ConstructIterator<'a, S> { type Item = Result; fn next(&mut self) -> Option> { @@ -2230,7 +2254,7 @@ struct DescribeIterator<'a, S: StoreConnection + 'a> { quads: Box> + 'a>, } -impl<'a, S: StoreConnection> Iterator for DescribeIterator<'a, S> { +impl<'a, S: StoreConnection + 'a> Iterator for DescribeIterator<'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 dbbbdb6c..be6b0506 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -9,6 +9,7 @@ mod plan; mod plan_builder; mod xml_results; +use crate::model::NamedNode; use crate::sparql::algebra::QueryVariants; use crate::sparql::eval::SimpleEvaluator; use crate::sparql::parser::read_sparql_query; @@ -19,6 +20,7 @@ use crate::store::StoreConnection; use crate::Result; use std::fmt; +pub use crate::sparql::algebra::GraphPattern; pub use crate::sparql::model::BindingsIterator; pub use crate::sparql::model::QueryResult; pub use crate::sparql::model::QueryResultSyntax; @@ -27,7 +29,7 @@ pub use crate::sparql::model::Variable; /// A prepared [SPARQL query](https://www.w3.org/TR/sparql11-query/) pub trait PreparedQuery { /// Evaluates the query and returns its results - fn exec(&self) -> Result; + fn exec<'a>(&'a self, options: &'a QueryOptions<'a>) -> Result>; } /// An implementation of `PreparedQuery` for internal use @@ -115,32 +117,37 @@ impl SimplePreparedQuery { } impl PreparedQuery for SimplePreparedQuery { - fn exec(&self) -> Result> { + fn exec<'a>(&'a self, options: &'a QueryOptions<'a>) -> Result> { match &self.0 { SimplePreparedQueryAction::Select { plan, variables, evaluator, - } => evaluator.evaluate_select_plan(&plan, &variables), + } => evaluator.evaluate_select_plan(&plan, &variables, options), SimplePreparedQueryAction::Ask { plan, evaluator } => { - evaluator.evaluate_ask_plan(&plan) + evaluator.evaluate_ask_plan(&plan, options) } SimplePreparedQueryAction::Construct { plan, construct, evaluator, - } => evaluator.evaluate_construct_plan(&plan, &construct), + } => evaluator.evaluate_construct_plan(&plan, &construct, &options), SimplePreparedQueryAction::Describe { plan, evaluator } => { - evaluator.evaluate_describe_plan(&plan) + evaluator.evaluate_describe_plan(&plan, &options) } } } } +pub trait ServiceHandler { + fn handle<'a>(&'a self, node: NamedNode) -> Option<(fn(GraphPattern) -> Result>)>; +} + /// Options for SPARQL query parsing and evaluation like the query base IRI pub struct QueryOptions<'a> { pub(crate) base_iri: Option<&'a str>, pub(crate) default_graph_as_union: bool, + pub(crate) service_handler: Option>, } impl<'a> Default for QueryOptions<'a> { @@ -148,6 +155,7 @@ impl<'a> Default for QueryOptions<'a> { Self { base_iri: None, default_graph_as_union: false, + service_handler: None as Option>, } } }