Fixes blank node support in SPARQL UPDATE

pull/51/head
Tpt 4 years ago
parent ac61ce38f4
commit 2c60150205
  1. 6
      lib/src/sparql/parser.rs
  2. 54
      lib/src/sparql/update.rs

@ -1040,7 +1040,7 @@ parser! {
} }
//[41] //[41]
rule Modify() -> Vec<GraphUpdateOperation> = with:Modify_with()? _ c:Modify_clauses() _ using:(UsingClause() ** (_)) _ i("WHERE") _ algebra:GroupGraphPattern() { rule Modify() -> Vec<GraphUpdateOperation> = with:Modify_with()? _ Modify_clear() c:Modify_clauses() _ using:(UsingClause() ** (_)) _ i("WHERE") _ algebra:GroupGraphPattern() {
let (delete, insert) = c; let (delete, insert) = c;
let mut delete = delete.unwrap_or_else(Vec::new); let mut delete = delete.unwrap_or_else(Vec::new);
let mut insert = insert.unwrap_or_else(Vec::new); let mut insert = insert.unwrap_or_else(Vec::new);
@ -1074,6 +1074,10 @@ parser! {
} / i:InsertClause() { } / i:InsertClause() {
(None, Some(i)) (None, Some(i))
} }
rule Modify_clear() -> () = {
state.used_bnodes.clear();
state.currently_used_bnodes.clear();
}
//[42] //[42]
rule DeleteClause() -> Vec<QuadPattern> = i("DELETE") _ q:QuadPattern() { q } rule DeleteClause() -> Vec<QuadPattern> = i("DELETE") _ q:QuadPattern() { q }

@ -1,3 +1,4 @@
use crate::model::{BlankNode, Term};
use crate::sparql::algebra::{ use crate::sparql::algebra::{
DatasetSpec, GraphPattern, GraphTarget, GraphUpdateOperation, NamedNodeOrVariable, QuadPattern, DatasetSpec, GraphPattern, GraphTarget, GraphUpdateOperation, NamedNodeOrVariable, QuadPattern,
TermOrVariable, TermOrVariable,
@ -12,6 +13,7 @@ use crate::store::numeric_encoder::{
}; };
use crate::store::{ReadableEncodedStore, WritableEncodedStore}; use crate::store::{ReadableEncodedStore, WritableEncodedStore};
use oxiri::Iri; use oxiri::Iri;
use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
pub(crate) struct SimpleUpdateEvaluator<'a, R, W> { pub(crate) struct SimpleUpdateEvaluator<'a, R, W> {
@ -68,8 +70,9 @@ impl<
} }
fn eval_insert_data(&mut self, data: &[QuadPattern]) -> Result<(), EvaluationError> { fn eval_insert_data(&mut self, data: &[QuadPattern]) -> Result<(), EvaluationError> {
let mut bnodes = HashMap::new();
for quad in data { 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)?; self.write.insert_encoded(&quad).map_err(to_eval_error)?;
} }
} }
@ -99,6 +102,7 @@ impl<
self.base_iri.clone(), self.base_iri.clone(),
self.service_handler.clone(), self.service_handler.clone(),
); );
let mut bnodes = HashMap::new();
for tuple in evaluator.eval_plan(&plan, EncodedTuple::with_capacity(variables.len())) { for tuple in evaluator.eval_plan(&plan, EncodedTuple::with_capacity(variables.len())) {
// We map the tuple to only get store strings // We map the tuple to only get store strings
let tuple = tuple? let tuple = tuple?
@ -139,10 +143,13 @@ impl<
} }
} }
for quad in insert { 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)?; self.write.insert_encoded(&quad).map_err(to_eval_error)?;
} }
} }
bnodes.clear();
} }
Ok(()) Ok(())
} }
@ -203,10 +210,11 @@ impl<
quad: &QuadPattern, quad: &QuadPattern,
variables: &[Variable], variables: &[Variable],
values: &[Option<EncodedTerm<R::StrId>>], values: &[Option<EncodedTerm<R::StrId>>],
bnodes: &mut HashMap<BlankNode, BlankNode>,
) -> Result<Option<EncodedQuad<R::StrId>>, EvaluationError> { ) -> Result<Option<EncodedQuad<R::StrId>>, EvaluationError> {
Ok(Some(EncodedQuad { Ok(Some(EncodedQuad {
subject: if let Some(subject) = 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() t.is_named_node() || t.is_blank_node()
})? { })? {
subject subject
@ -221,7 +229,7 @@ impl<
return Ok(None); return Ok(None);
}, },
object: if let Some(object) = 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() !t.is_default_graph()
})? { })? {
object object
@ -247,12 +255,19 @@ impl<
term: &TermOrVariable, term: &TermOrVariable,
variables: &[Variable], variables: &[Variable],
values: &[Option<EncodedTerm<R::StrId>>], values: &[Option<EncodedTerm<R::StrId>>],
bnodes: &mut HashMap<BlankNode, BlankNode>,
validate: impl FnOnce(&EncodedTerm<R::StrId>) -> bool, validate: impl FnOnce(&EncodedTerm<R::StrId>) -> bool,
) -> Result<Option<EncodedTerm<R::StrId>>, EvaluationError> { ) -> Result<Option<EncodedTerm<R::StrId>>, EvaluationError> {
Ok(match term { Ok(match term {
TermOrVariable::Term(term) => { TermOrVariable::Term(term) => Some(
Some(self.write.encode_term(term.into()).map_err(to_eval_error)?) 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) => { TermOrVariable::Variable(v) => {
if let Some(Some(term)) = variables if let Some(Some(term)) = variables
.iter() .iter()
@ -349,12 +364,19 @@ impl<
variables: &[Variable], variables: &[Variable],
values: &[Option<EncodedTerm<R::StrId>>], values: &[Option<EncodedTerm<R::StrId>>],
) -> Result<Option<EncodedTerm<R::StrId>>, EvaluationError> { ) -> Result<Option<EncodedTerm<R::StrId>>, EvaluationError> {
Ok(match term { match term {
TermOrVariable::Term(term) => self TermOrVariable::Term(term) => {
.read if term.is_blank_node() {
.get_encoded_term(term.into()) Err(EvaluationError::msg(
.map_err(to_eval_error)?, "Blank node are not allowed in deletion patterns",
TermOrVariable::Variable(v) => { ))
} else {
self.read
.get_encoded_term(term.into())
.map_err(to_eval_error)
}
}
TermOrVariable::Variable(v) => Ok(
if let Some(Some(term)) = variables if let Some(Some(term)) = variables
.iter() .iter()
.position(|v2| v == v2) .position(|v2| v == v2)
@ -363,9 +385,9 @@ impl<
Some(*term) Some(*term)
} else { } else {
None None
} },
} ),
}) }
} }
fn encode_named_node_for_deletion( fn encode_named_node_for_deletion(

Loading…
Cancel
Save