diff --git a/lib/src/sparql/parser.rs b/lib/src/sparql/parser.rs index a29d5e4e..14dda52c 100644 --- a/lib/src/sparql/parser.rs +++ b/lib/src/sparql/parser.rs @@ -1040,7 +1040,7 @@ parser! { } //[41] - rule Modify() -> Vec = with:Modify_with()? _ c:Modify_clauses() _ using:(UsingClause() ** (_)) _ i("WHERE") _ algebra:GroupGraphPattern() { + rule Modify() -> Vec = with:Modify_with()? _ Modify_clear() c:Modify_clauses() _ using:(UsingClause() ** (_)) _ i("WHERE") _ algebra:GroupGraphPattern() { let (delete, insert) = c; let mut delete = delete.unwrap_or_else(Vec::new); let mut insert = insert.unwrap_or_else(Vec::new); @@ -1074,6 +1074,10 @@ parser! { } / i:InsertClause() { (None, Some(i)) } + rule Modify_clear() -> () = { + state.used_bnodes.clear(); + state.currently_used_bnodes.clear(); + } //[42] rule DeleteClause() -> Vec = i("DELETE") _ q:QuadPattern() { q } diff --git a/lib/src/sparql/update.rs b/lib/src/sparql/update.rs index f6dfe19f..63079f9c 100644 --- a/lib/src/sparql/update.rs +++ b/lib/src/sparql/update.rs @@ -1,3 +1,4 @@ +use crate::model::{BlankNode, Term}; use crate::sparql::algebra::{ DatasetSpec, GraphPattern, GraphTarget, GraphUpdateOperation, NamedNodeOrVariable, QuadPattern, TermOrVariable, @@ -12,6 +13,7 @@ use crate::store::numeric_encoder::{ }; use crate::store::{ReadableEncodedStore, WritableEncodedStore}; use oxiri::Iri; +use std::collections::HashMap; use std::rc::Rc; pub(crate) struct SimpleUpdateEvaluator<'a, R, W> { @@ -68,8 +70,9 @@ impl< } fn eval_insert_data(&mut self, data: &[QuadPattern]) -> Result<(), EvaluationError> { + let mut bnodes = HashMap::new(); for quad in data { - if let Some(quad) = self.encode_quad_for_insertion(quad, &[], &[])? { + if let Some(quad) = self.encode_quad_for_insertion(quad, &[], &[], &mut bnodes)? { self.write.insert_encoded(&quad).map_err(to_eval_error)?; } } @@ -99,6 +102,7 @@ impl< self.base_iri.clone(), self.service_handler.clone(), ); + let mut bnodes = HashMap::new(); for tuple in evaluator.eval_plan(&plan, EncodedTuple::with_capacity(variables.len())) { // We map the tuple to only get store strings let tuple = tuple? @@ -139,10 +143,13 @@ impl< } } for quad in insert { - if let Some(quad) = self.encode_quad_for_insertion(quad, &variables, &tuple)? { + if let Some(quad) = + self.encode_quad_for_insertion(quad, &variables, &tuple, &mut bnodes)? + { self.write.insert_encoded(&quad).map_err(to_eval_error)?; } } + bnodes.clear(); } Ok(()) } @@ -203,10 +210,11 @@ impl< quad: &QuadPattern, variables: &[Variable], values: &[Option>], + bnodes: &mut HashMap, ) -> Result>, EvaluationError> { Ok(Some(EncodedQuad { subject: if let Some(subject) = - self.encode_term_for_insertion(&quad.subject, variables, values, |t| { + self.encode_term_for_insertion(&quad.subject, variables, values, bnodes, |t| { t.is_named_node() || t.is_blank_node() })? { subject @@ -221,7 +229,7 @@ impl< return Ok(None); }, object: if let Some(object) = - self.encode_term_for_insertion(&quad.object, variables, values, |t| { + self.encode_term_for_insertion(&quad.object, variables, values, bnodes, |t| { !t.is_default_graph() })? { object @@ -247,12 +255,19 @@ impl< term: &TermOrVariable, variables: &[Variable], values: &[Option>], + bnodes: &mut HashMap, validate: impl FnOnce(&EncodedTerm) -> bool, ) -> Result>, EvaluationError> { Ok(match term { - TermOrVariable::Term(term) => { - Some(self.write.encode_term(term.into()).map_err(to_eval_error)?) - } + TermOrVariable::Term(term) => Some( + self.write + .encode_term(if let Term::BlankNode(bnode) = term { + bnodes.entry(bnode.clone()).or_default().as_ref().into() + } else { + term.as_ref() + }) + .map_err(to_eval_error)?, + ), TermOrVariable::Variable(v) => { if let Some(Some(term)) = variables .iter() @@ -349,12 +364,19 @@ impl< variables: &[Variable], values: &[Option>], ) -> Result>, EvaluationError> { - Ok(match term { - TermOrVariable::Term(term) => self - .read - .get_encoded_term(term.into()) - .map_err(to_eval_error)?, - TermOrVariable::Variable(v) => { + match term { + TermOrVariable::Term(term) => { + if term.is_blank_node() { + Err(EvaluationError::msg( + "Blank node are not allowed in deletion patterns", + )) + } else { + self.read + .get_encoded_term(term.into()) + .map_err(to_eval_error) + } + } + TermOrVariable::Variable(v) => Ok( if let Some(Some(term)) = variables .iter() .position(|v2| v == v2) @@ -363,9 +385,9 @@ impl< Some(*term) } else { None - } - } - }) + }, + ), + } } fn encode_named_node_for_deletion(