From c7cd43217b6d2ef59e02166dffd8482561f32698 Mon Sep 17 00:00:00 2001 From: Tpt Date: Mon, 26 Nov 2018 22:24:55 +0100 Subject: [PATCH] Implements some SPARQL 1.1 functions --- lib/src/sparql/eval.rs | 72 ++++++++++++++++++++++++++++++++++++++++-- lib/src/sparql/plan.rs | 71 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 133 insertions(+), 10 deletions(-) diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index 71731576..8b9f4d32 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -22,6 +22,7 @@ use std::sync::Arc; use std::sync::Mutex; use store::encoded::EncodedQuadsStore; use store::numeric_encoder::*; +use uuid::Uuid; use Result; const REGEX_SIZE_LIMIT: usize = 1_000_000; @@ -351,12 +352,12 @@ impl SimpleEvaluator { PlanExpression::Equal(a, b) => { let a = self.eval_expression(a, tuple)?; let b = self.eval_expression(b, tuple)?; - Some((a == b || self.partial_cmp_literals(a, b) == Some(Ordering::Equal)).into()) + Some(self.equals(a, b).into()) } PlanExpression::NotEqual(a, b) => { let a = self.eval_expression(a, tuple)?; let b = self.eval_expression(b, tuple)?; - Some((a != b && self.partial_cmp_literals(a, b) != Some(Ordering::Equal)).into()) + Some(self.not_equals(a, b).into()) } PlanExpression::Greater(a, b) => Some( (self.partial_cmp_literals( @@ -390,6 +391,24 @@ impl SimpleEvaluator { Ordering::Greater => false, }.into(), ), + PlanExpression::In(e, l) => { + let needed = self.eval_expression(e, tuple)?; + let mut error = false; + for possible in l { + if let Some(possible) = self.eval_expression(possible, tuple) { + if self.equals(needed, possible) { + return Some(true.into()); + } + } else { + error = true; + } + } + if error { + None + } else { + Some(false.into()) + } + } PlanExpression::Add(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { NumericBinaryOperands::Float(v1, v2) => (v1 + v2).into(), NumericBinaryOperands::Double(v1, v2) => (v1 + v2).into(), @@ -469,6 +488,39 @@ impl SimpleEvaluator { }, None => Some(BlankNode::default().into()), }, + PlanExpression::UUID() => Some(EncodedTerm::NamedNode { + iri_id: self + .store + .insert_str(&Uuid::new_v4().to_urn().to_string()) + .ok()?, + }), + PlanExpression::StrUUID() => Some(EncodedTerm::SimpleLiteral { + value_id: self + .store + .insert_str(&Uuid::new_v4().to_simple().to_string()) + .ok()?, + }), + PlanExpression::Coalesce(l) => { + for e in l { + if let Some(result) = self.eval_expression(e, tuple) { + return Some(result); + } + } + None + } + PlanExpression::If(a, b, c) => if self.to_bool(self.eval_expression(a, tuple)?)? { + self.eval_expression(b, tuple) + } else { + self.eval_expression(c, tuple) + }, + PlanExpression::StrLang(lexical_form, lang_tag) => { + Some(EncodedTerm::LangStringLiteral { + value_id: self + .to_simple_string_id(self.eval_expression(lexical_form, tuple)?)?, + language_id: self + .to_simple_string_id(self.eval_expression(lang_tag, tuple)?)?, + }) + } PlanExpression::SameTerm(a, b) => { Some((self.eval_expression(a, tuple)? == self.eval_expression(b, tuple)?).into()) } @@ -669,6 +721,14 @@ impl SimpleEvaluator { } } + fn to_simple_string_id(&self, term: EncodedTerm) -> Option { + if let EncodedTerm::SimpleLiteral { value_id } = term { + Some(value_id) + } else { + None + } + } + fn to_string(&self, term: EncodedTerm) -> Option { match term { EncodedTerm::SimpleLiteral { value_id } @@ -762,6 +822,14 @@ impl SimpleEvaluator { ) } + fn equals(&self, a: EncodedTerm, b: EncodedTerm) -> bool { + (a == b || self.partial_cmp_literals(a, b) == Some(Ordering::Equal)) + } + + fn not_equals(&self, a: EncodedTerm, b: EncodedTerm) -> bool { + (a != b && self.partial_cmp_literals(a, b) != Some(Ordering::Equal)) + } + fn cmp_according_to_expression( &self, tuple_a: &[Option], diff --git a/lib/src/sparql/plan.rs b/lib/src/sparql/plan.rs index a2bb3d4b..cb29732f 100644 --- a/lib/src/sparql/plan.rs +++ b/lib/src/sparql/plan.rs @@ -168,8 +168,7 @@ pub enum PlanExpression { GreaterOrEq(Box, Box), Lower(Box, Box), LowerOrEq(Box, Box), - //In(Box, Vec), - //NotIn(Box, Vec), + In(Box, Vec), Add(Box, Box), Sub(Box, Box), Mul(Box, Box), @@ -213,18 +212,22 @@ pub enum PlanExpression { Minutes(Box), Seconds(Box), Timezone(Box), - Now(), + Now(),*/ UUID(), StrUUID(), - MD5(Box), + /*MD5(Box), SHA1(Box), SHA256(Box), SHA384(Box), - SHA512(Box), + SHA512(Box),*/ Coalesce(Vec), - If(Box, Box, Box), + If( + Box, + Box, + Box, + ), StrLang(Box, Box), - StrDT(Box, Box),*/ + //StrDT(Box, Box), SameTerm(Box, Box), IsIRI(Box), IsBlank(Box), @@ -247,7 +250,10 @@ pub enum PlanExpression { impl PlanExpression { fn add_variables(&self, set: &mut BTreeSet) { match self { - PlanExpression::Constant(_) | PlanExpression::BNode(None) => (), + PlanExpression::Constant(_) + | PlanExpression::BNode(None) + | PlanExpression::UUID() + | PlanExpression::StrUUID() => (), PlanExpression::Variable(v) | PlanExpression::Bound(v) => { set.insert(*v); } @@ -265,6 +271,7 @@ impl PlanExpression { | PlanExpression::Div(a, b) | PlanExpression::SameTerm(a, b) | PlanExpression::LangMatches(a, b) + | PlanExpression::StrLang(a, b) | PlanExpression::Regex(a, b, None) => { a.add_variables(set); b.add_variables(set); @@ -290,11 +297,27 @@ impl PlanExpression { | PlanExpression::StringCast(e) => { e.add_variables(set); } + PlanExpression::Coalesce(l) => { + for e in l { + e.add_variables(set); + } + } + PlanExpression::If(a, b, c) => { + a.add_variables(set); + b.add_variables(set); + c.add_variables(set); + } PlanExpression::Regex(a, b, Some(c)) => { a.add_variables(set); b.add_variables(set); c.add_variables(set); } + PlanExpression::In(e, l) => { + e.add_variables(set); + for e in l { + e.add_variables(set); + } + } } } } @@ -546,6 +569,14 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> { Box::new(self.build_for_expression(a, variables)?), Box::new(self.build_for_expression(b, variables)?), ), + Expression::In(e, l) => PlanExpression::In( + Box::new(self.build_for_expression(e, variables)?), + self.expression_list(l, variables)?, + ), + Expression::NotIn(e, l) => PlanExpression::UnaryNot(Box::new(PlanExpression::In( + Box::new(self.build_for_expression(e, variables)?), + self.expression_list(l, variables)?, + ))), Expression::Add(a, b) => PlanExpression::Add( Box::new(self.build_for_expression(a, variables)?), Box::new(self.build_for_expression(b, variables)?), @@ -592,6 +623,20 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> { Some(e) => Some(Box::new(self.build_for_expression(e, variables)?)), None => None, }), + Expression::UUIDFunctionCall() => PlanExpression::UUID(), + Expression::StrUUIDFunctionCall() => PlanExpression::StrUUID(), + Expression::CoalesceFunctionCall(l) => { + PlanExpression::Coalesce(self.expression_list(l, variables)?) + } + Expression::IfFunctionCall(a, b, c) => PlanExpression::If( + Box::new(self.build_for_expression(a, variables)?), + Box::new(self.build_for_expression(b, variables)?), + Box::new(self.build_for_expression(c, variables)?), + ), + Expression::StrLangFunctionCall(a, b) => PlanExpression::StrLang( + Box::new(self.build_for_expression(a, variables)?), + Box::new(self.build_for_expression(b, variables)?), + ), Expression::SameTermFunctionCall(a, b) => PlanExpression::SameTerm( Box::new(self.build_for_expression(a, variables)?), Box::new(self.build_for_expression(b, variables)?), @@ -676,6 +721,16 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> { } } + fn expression_list( + &self, + l: &[Expression], + variables: &mut Vec, + ) -> Result> { + l.iter() + .map(|e| self.build_for_expression(e, variables)) + .collect() + } + fn pattern_value_from_term_or_variable( &self, term_or_variable: &TermOrVariable,