Makes SPARQL UPDATE parser more strict

Does not allow variables in INSERT/DELETE DATA and blank nodes in DELETE
pull/71/head
Tpt 4 years ago
parent 700e47af1e
commit 43d8260acf
  1. 27
      lib/src/sparql/algebra.rs
  2. 75
      lib/src/sparql/parser.rs
  3. 94
      lib/src/sparql/update.rs

@ -1705,9 +1705,9 @@ impl fmt::Display for QueryDataset {
#[derive(Eq, PartialEq, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GraphUpdateOperation { pub enum GraphUpdateOperation {
/// [insert data](https://www.w3.org/TR/sparql11-update/#def_insertdataoperation) /// [insert data](https://www.w3.org/TR/sparql11-update/#def_insertdataoperation)
InsertData { data: Vec<QuadPattern> }, InsertData { data: Vec<Quad> },
/// [delete data](https://www.w3.org/TR/sparql11-update/#def_deletedataoperation) /// [delete data](https://www.w3.org/TR/sparql11-update/#def_deletedataoperation)
DeleteData { data: Vec<QuadPattern> }, DeleteData { data: Vec<Quad> },
/// [delete insert](https://www.w3.org/TR/sparql11-update/#def_deleteinsertoperation) /// [delete insert](https://www.w3.org/TR/sparql11-update/#def_deleteinsertoperation)
DeleteInsert { DeleteInsert {
delete: Vec<QuadPattern>, delete: Vec<QuadPattern>,
@ -1734,16 +1734,12 @@ impl fmt::Display for GraphUpdateOperation {
match self { match self {
GraphUpdateOperation::InsertData { data } => { GraphUpdateOperation::InsertData { data } => {
writeln!(f, "INSERT DATA {{")?; writeln!(f, "INSERT DATA {{")?;
for quad in data { write_quads(data, f)?;
writeln!(f, "\t{}", SparqlQuadPattern(quad))?;
}
write!(f, "}}") write!(f, "}}")
} }
GraphUpdateOperation::DeleteData { data } => { GraphUpdateOperation::DeleteData { data } => {
writeln!(f, "DELETE DATA {{")?; writeln!(f, "DELETE DATA {{")?;
for quad in data { write_quads(data, f)?;
writeln!(f, "\t{}", SparqlQuadPattern(quad))?;
}
write!(f, "}}") write!(f, "}}")
} }
GraphUpdateOperation::DeleteInsert { GraphUpdateOperation::DeleteInsert {
@ -1823,6 +1819,21 @@ impl fmt::Display for GraphUpdateOperation {
} }
} }
fn write_quads(quads: &[Quad], f: &mut fmt::Formatter<'_>) -> fmt::Result {
for quad in quads {
if quad.graph_name == GraphName::DefaultGraph {
writeln!(f, "\t{} {} {} .", quad.subject, quad.predicate, quad.object)?;
} else {
writeln!(
f,
"\tGRAPH {} {{ {} {} {} }}",
quad.graph_name, quad.subject, quad.predicate, quad.object
)?;
}
}
Ok(())
}
/// A target RDF graph for update operations /// A target RDF graph for update operations
/// ///
/// Could be a specific graph, all named graphs or the complete dataset. /// Could be a specific graph, all named graphs or the complete dataset.

@ -1007,26 +1007,34 @@ parser! {
} }
//[39] //[39]
rule DeleteData() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("DATA") _ data:QuadData() { rule DeleteData() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("DATA") _ data:QuadData() {?
vec![GraphUpdateOperation::DeleteData { data }] if data.iter().any(|quad| quad.subject.is_blank_node() || quad.object.is_blank_node() || quad.graph_name.is_blank_node()) {
Err("Blank nodes are not allowed in DELETE DATA")
} else {
Ok(vec![GraphUpdateOperation::DeleteData { data }])
}
} }
//[40] //[40]
rule DeleteWhere() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("WHERE") _ d:QuadData() { rule DeleteWhere() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("WHERE") _ d:QuadPattern() {?
let pattern = d.iter().map(|q| { if d.iter().any(|quad| matches!(quad.subject, TermOrVariable::Term(Term::BlankNode(_))) || matches!(quad.object, TermOrVariable::Term(Term::BlankNode(_)))) {
let bgp = GraphPattern::BGP(vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())]); Err("Blank nodes are not allowed in DELETE WHERE")
if let Some(graph_name) = &q.graph_name { } else {
GraphPattern::Graph { graph_name: graph_name.clone(), inner: Box::new(bgp) } let pattern = d.iter().map(|q| {
} else { let bgp = GraphPattern::BGP(vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())]);
bgp if let Some(graph_name) = &q.graph_name {
} GraphPattern::Graph { graph_name: graph_name.clone(), inner: Box::new(bgp) }
}).fold(GraphPattern::BGP(Vec::new()), new_join); } else {
vec![GraphUpdateOperation::DeleteInsert { bgp
delete: d, }
insert: Vec::new(), }).fold(GraphPattern::BGP(Vec::new()), new_join);
using: QueryDataset::default(), Ok(vec![GraphUpdateOperation::DeleteInsert {
pattern: Box::new(pattern) delete: d,
}] insert: Vec::new(),
using: QueryDataset::default(),
pattern: Box::new(pattern)
}])
}
} }
//[41] //[41]
@ -1088,7 +1096,13 @@ parser! {
} }
//[42] //[42]
rule DeleteClause() -> Vec<QuadPattern> = i("DELETE") _ q:QuadPattern() { q } rule DeleteClause() -> Vec<QuadPattern> = i("DELETE") _ q:QuadPattern() {?
if q.iter().any(|quad| matches!(quad.subject, TermOrVariable::Term(Term::BlankNode(_))) || matches!(quad.object, TermOrVariable::Term(Term::BlankNode(_)))) {
Err("Blank nodes are not allowed in DELETE")
} else {
Ok(q)
}
}
//[43] //[43]
rule InsertClause() -> Vec<QuadPattern> = i("INSERT") _ q:QuadPattern() { q } rule InsertClause() -> Vec<QuadPattern> = i("INSERT") _ q:QuadPattern() { q }
@ -1122,7 +1136,30 @@ parser! {
rule QuadPattern() -> Vec<QuadPattern> = "{" _ q:Quads() _ "}" { q } rule QuadPattern() -> Vec<QuadPattern> = "{" _ q:Quads() _ "}" { q }
//[49] //[49]
rule QuadData() -> Vec<QuadPattern> = "{" _ q:Quads() _ "}" { q } rule QuadData() -> Vec<Quad> = "{" _ q:Quads() _ "}" {?
q.into_iter().map(|q| Ok(Quad {
subject: match q.subject {
TermOrVariable::Term(Term::NamedNode(t)) => t.into(),
TermOrVariable::Term(Term::BlankNode(t)) => t.into(),
_ => return Err(())
},
predicate: if let NamedNodeOrVariable::NamedNode(t) = q.predicate {
t
} else {
return Err(())
},
object: if let TermOrVariable::Term(t) = q.object {
t
} else {
return Err(())
},
graph_name: match q.graph_name {
Some(NamedNodeOrVariable::NamedNode(t)) => t.into(),
None => GraphName::DefaultGraph,
_ => return Err(())
}
})).collect::<Result<Vec<_>, ()>>().map_err(|_| "Variables are not allowed in INSERT DATA and DELETE DATA")
}
//[50] //[50]
rule Quads() -> Vec<QuadPattern> = q:(Quads_TriplesTemplate() / Quads_QuadsNotTriples()) ** (_) { rule Quads() -> Vec<QuadPattern> = q:(Quads_TriplesTemplate() / Quads_QuadsNotTriples()) ** (_) {

@ -1,6 +1,6 @@
use crate::error::{invalid_data_error, invalid_input_error}; use crate::error::{invalid_data_error, invalid_input_error};
use crate::io::GraphFormat; use crate::io::GraphFormat;
use crate::model::{BlankNode, GraphNameRef, NamedNode, Term}; use crate::model::{BlankNode, GraphNameRef, NamedNode, NamedOrBlankNode, Quad, Term};
use crate::sparql::algebra::{ use crate::sparql::algebra::{
GraphPattern, GraphTarget, GraphUpdateOperation, NamedNodeOrVariable, QuadPattern, GraphPattern, GraphTarget, GraphUpdateOperation, NamedNodeOrVariable, QuadPattern,
QueryDataset, TermOrVariable, QueryDataset, TermOrVariable,
@ -87,19 +87,19 @@ where
} }
} }
fn eval_insert_data(&mut self, data: &[QuadPattern]) -> Result<(), EvaluationError> { fn eval_insert_data(&mut self, data: &[Quad]) -> Result<(), EvaluationError> {
let mut bnodes = HashMap::new(); let mut bnodes = HashMap::new();
for quad in data { for quad in data {
if let Some(quad) = self.encode_quad_for_insertion(quad, &[], &[], &mut bnodes)? { 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)?;
} }
} }
Ok(()) Ok(())
} }
fn eval_delete_data(&mut self, data: &[QuadPattern]) -> Result<(), EvaluationError> { fn eval_delete_data(&mut self, data: &[Quad]) -> Result<(), EvaluationError> {
for quad in data { for quad in data {
if let Some(quad) = self.encode_quad_for_deletion(quad, &[], &[])? { if let Some(quad) = self.encode_quad_for_deletion(quad)? {
self.write.remove_encoded(&quad).map_err(to_eval_error)?; self.write.remove_encoded(&quad).map_err(to_eval_error)?;
} }
} }
@ -156,13 +156,15 @@ where
.collect::<Result<Vec<_>, EvaluationError>>()?; .collect::<Result<Vec<_>, EvaluationError>>()?;
for quad in delete { for quad in delete {
if let Some(quad) = self.encode_quad_for_deletion(quad, &variables, &tuple)? { if let Some(quad) =
self.encode_quad_pattern_for_deletion(quad, &variables, &tuple)?
{
self.write.remove_encoded(&quad).map_err(to_eval_error)?; self.write.remove_encoded(&quad).map_err(to_eval_error)?;
} }
} }
for quad in insert { for quad in insert {
if let Some(quad) = if let Some(quad) =
self.encode_quad_for_insertion(quad, &variables, &tuple, &mut bnodes)? self.encode_quad_pattern_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)?;
} }
@ -277,6 +279,40 @@ where
} }
fn encode_quad_for_insertion( fn encode_quad_for_insertion(
&mut self,
quad: &Quad,
bnodes: &mut HashMap<BlankNode, BlankNode>,
) -> Result<Option<EncodedQuad<R::StrId>>, EvaluationError> {
Ok(Some(EncodedQuad {
subject: match &quad.subject {
NamedOrBlankNode::NamedNode(subject) => {
self.write.encode_named_node(subject.as_ref())
}
NamedOrBlankNode::BlankNode(subject) => self
.write
.encode_blank_node(bnodes.entry(subject.clone()).or_default().as_ref()),
}
.map_err(to_eval_error)?,
predicate: self
.write
.encode_named_node(quad.predicate.as_ref())
.map_err(to_eval_error)?,
object: match &quad.object {
Term::NamedNode(object) => self.write.encode_named_node(object.as_ref()),
Term::BlankNode(object) => self
.write
.encode_blank_node(bnodes.entry(object.clone()).or_default().as_ref()),
Term::Literal(object) => self.write.encode_literal(object.as_ref()),
}
.map_err(to_eval_error)?,
graph_name: self
.write
.encode_graph_name(quad.graph_name.as_ref())
.map_err(to_eval_error)?,
}))
}
fn encode_quad_pattern_for_insertion(
&mut self, &mut self,
quad: &QuadPattern, quad: &QuadPattern,
variables: &[Variable], variables: &[Variable],
@ -388,6 +424,50 @@ where
} }
fn encode_quad_for_deletion( fn encode_quad_for_deletion(
&mut self,
quad: &Quad,
) -> Result<Option<EncodedQuad<R::StrId>>, EvaluationError> {
Ok(Some(EncodedQuad {
subject: if let Some(subject) = self
.read
.get_encoded_named_or_blank_node(quad.subject.as_ref())
.map_err(to_eval_error)?
{
subject
} else {
return Ok(None);
},
predicate: if let Some(predicate) = self
.read
.get_encoded_named_node(quad.predicate.as_ref())
.map_err(to_eval_error)?
{
predicate
} else {
return Ok(None);
},
object: if let Some(object) = self
.read
.get_encoded_term(quad.object.as_ref())
.map_err(to_eval_error)?
{
object
} else {
return Ok(None);
},
graph_name: if let Some(graph_name) = self
.read
.get_encoded_graph_name(quad.graph_name.as_ref())
.map_err(to_eval_error)?
{
graph_name
} else {
return Ok(None);
},
}))
}
fn encode_quad_pattern_for_deletion(
&self, &self,
quad: &QuadPattern, quad: &QuadPattern,
variables: &[Variable], variables: &[Variable],

Loading…
Cancel
Save