Cleans up the Variable structure to only represent actual variables

There should be now a sane blank node support in the SPARQL algebra.
They are now allowed only in places where they are allowed by the SPARQL syntax
pull/35/head
Tpt 5 years ago
parent f4f542ce00
commit 98a4d40a7e
  1. 6
      js/src/store.rs
  2. 44
      lib/src/sparql/algebra.rs
  3. 4
      lib/src/sparql/json_results.rs
  4. 63
      lib/src/sparql/model.rs
  5. 22
      lib/src/sparql/parser.rs
  6. 80
      lib/src/sparql/plan_builder.rs
  7. 4
      lib/src/sparql/xml_results.rs
  8. 4
      lib/tests/sparql_test_cases.rs

@ -118,10 +118,8 @@ impl JsMemoryStore {
let output = match results { let output = match results {
QueryResult::Bindings(bindings) => { QueryResult::Bindings(bindings) => {
let (variables, iter) = bindings.destruct(); let (variables, iter) = bindings.destruct();
let variables: Vec<JsValue> = variables let variables: Vec<JsValue> =
.into_iter() variables.into_iter().map(|v| v.as_str().into()).collect();
.map(|v| v.name().unwrap().into())
.collect();
let results = Array::new(); let results = Array::new();
for values in iter { for values in iter {
let values = values.map_err(to_err)?; let values = values.map_err(to_err)?;

@ -244,7 +244,9 @@ impl<'a> fmt::Display for SparqlTripleOrPathPattern<'a> {
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub enum Expression { pub enum Expression {
Constant(TermOrVariable), NamedNode(NamedNode),
Literal(Literal),
Variable(Variable),
Or(Box<Expression>, Box<Expression>), Or(Box<Expression>, Box<Expression>),
And(Box<Expression>, Box<Expression>), And(Box<Expression>, Box<Expression>),
Equal(Box<Expression>, Box<Expression>), Equal(Box<Expression>, Box<Expression>),
@ -270,7 +272,9 @@ pub enum Expression {
impl fmt::Display for Expression { impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Expression::Constant(t) => write!(f, "{}", t), Expression::NamedNode(node) => node.fmt(f),
Expression::Literal(l) => l.fmt(f),
Expression::Variable(var) => var.fmt(f),
Expression::Or(a, b) => write!(f, "({} || {})", a, b), Expression::Or(a, b) => write!(f, "({} || {})", a, b),
Expression::And(a, b) => write!(f, "({} && {})", a, b), Expression::And(a, b) => write!(f, "({} && {})", a, b),
Expression::Equal(a, b) => write!(f, "({} = {})", a, b), Expression::Equal(a, b) => write!(f, "({} = {})", a, b),
@ -324,19 +328,19 @@ impl fmt::Display for Expression {
impl From<NamedNode> for Expression { impl From<NamedNode> for Expression {
fn from(p: NamedNode) -> Self { fn from(p: NamedNode) -> Self {
Expression::Constant(p.into()) Expression::NamedNode(p)
} }
} }
impl From<Literal> for Expression { impl From<Literal> for Expression {
fn from(p: Literal) -> Self { fn from(p: Literal) -> Self {
Expression::Constant(p.into()) Expression::Literal(p)
} }
} }
impl From<Variable> for Expression { impl From<Variable> for Expression {
fn from(v: Variable) -> Self { fn from(v: Variable) -> Self {
Expression::Constant(v.into()) Expression::Variable(v)
} }
} }
@ -345,7 +349,9 @@ struct SparqlExpression<'a>(&'a Expression);
impl<'a> fmt::Display for SparqlExpression<'a> { impl<'a> fmt::Display for SparqlExpression<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 { match self.0 {
Expression::Constant(t) => write!(f, "{}", t), Expression::NamedNode(node) => node.fmt(f),
Expression::Literal(l) => l.fmt(f),
Expression::Variable(var) => var.fmt(f),
Expression::Or(a, b) => write!( Expression::Or(a, b) => write!(
f, f,
"({} || {})", "({} || {})",
@ -677,21 +683,21 @@ impl GraphPattern {
match pattern { match pattern {
TripleOrPathPattern::Triple(tp) => { TripleOrPathPattern::Triple(tp) => {
if let TermOrVariable::Variable(ref s) = tp.subject { if let TermOrVariable::Variable(ref s) = tp.subject {
adds_if_has_name(vars, s); vars.insert(s);
} }
if let NamedNodeOrVariable::Variable(ref p) = tp.predicate { if let NamedNodeOrVariable::Variable(ref p) = tp.predicate {
adds_if_has_name(vars, p); vars.insert(p);
} }
if let TermOrVariable::Variable(ref o) = tp.object { if let TermOrVariable::Variable(ref o) = tp.object {
adds_if_has_name(vars, o); vars.insert(o);
} }
} }
TripleOrPathPattern::Path(ppp) => { TripleOrPathPattern::Path(ppp) => {
if let TermOrVariable::Variable(ref s) = ppp.subject { if let TermOrVariable::Variable(ref s) = ppp.subject {
adds_if_has_name(vars, s); vars.insert(s);
} }
if let TermOrVariable::Variable(ref o) = ppp.object { if let TermOrVariable::Variable(ref o) = ppp.object {
adds_if_has_name(vars, o); vars.insert(o);
} }
} }
} }
@ -712,17 +718,21 @@ impl GraphPattern {
} }
GraphPattern::Graph(g, p) => { GraphPattern::Graph(g, p) => {
if let NamedNodeOrVariable::Variable(ref g) = g { if let NamedNodeOrVariable::Variable(ref g) = g {
adds_if_has_name(vars, g); vars.insert(g);
} }
p.add_visible_variables(vars); p.add_visible_variables(vars);
} }
GraphPattern::Extend(p, v, _) => { GraphPattern::Extend(p, v, _) => {
vars.insert(v);
p.add_visible_variables(vars); p.add_visible_variables(vars);
adds_if_has_name(vars, v);
} }
GraphPattern::Minus(a, _) => a.add_visible_variables(vars), GraphPattern::Minus(a, _) => a.add_visible_variables(vars),
GraphPattern::Service(_, p, _) => p.add_visible_variables(vars), GraphPattern::Service(_, p, _) => p.add_visible_variables(vars),
GraphPattern::AggregateJoin(_, a) => vars.extend(a.iter().map(|(_, v)| v)), GraphPattern::AggregateJoin(_, a) => {
for v in a.values() {
vars.insert(v);
}
}
GraphPattern::Data(b) => vars.extend(b.variables_iter()), GraphPattern::Data(b) => vars.extend(b.variables_iter()),
GraphPattern::OrderBy(l, _) => l.add_visible_variables(vars), GraphPattern::OrderBy(l, _) => l.add_visible_variables(vars),
GraphPattern::Project(_, pv) => vars.extend(pv.iter()), GraphPattern::Project(_, pv) => vars.extend(pv.iter()),
@ -733,12 +743,6 @@ impl GraphPattern {
} }
} }
fn adds_if_has_name<'a>(vars: &mut BTreeSet<&'a Variable>, var: &'a Variable) {
if var.has_name() {
vars.insert(var);
}
}
struct SparqlGraphPattern<'a>(&'a GraphPattern); struct SparqlGraphPattern<'a>(&'a GraphPattern);
impl<'a> fmt::Display for SparqlGraphPattern<'a> { impl<'a> fmt::Display for SparqlGraphPattern<'a> {

@ -23,7 +23,7 @@ pub fn write_json_results<W: Write>(results: QueryResult<'_>, mut sink: W) -> Re
} else { } else {
sink.write_all(b",")?; sink.write_all(b",")?;
} }
write_escaped_json_string(variable.name()?, &mut sink)?; write_escaped_json_string(variable.as_str(), &mut sink)?;
} }
sink.write_all(b"]},\"results\":{\"bindings\":[")?; sink.write_all(b"]},\"results\":{\"bindings\":[")?;
let mut start_bindings = true; let mut start_bindings = true;
@ -44,7 +44,7 @@ pub fn write_json_results<W: Write>(results: QueryResult<'_>, mut sink: W) -> Re
} else { } else {
sink.write_all(b",")?; sink.write_all(b",")?;
} }
write_escaped_json_string(variables[i].name()?, &mut sink)?; write_escaped_json_string(variables[i].as_str(), &mut sink)?;
match term { match term {
Term::NamedNode(uri) => { Term::NamedNode(uri) => {
sink.write_all(b":{\"type\":\"uri\",\"value\":")?; sink.write_all(b":{\"type\":\"uri\",\"value\":")?;

@ -153,55 +153,36 @@ impl<'a> BindingsIterator<'a> {
/// A SPARQL query variable /// A SPARQL query variable
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub enum Variable { pub struct Variable {
Variable { name: String }, name: String,
BlankNode { id: u128 },
Internal { id: u128 },
} }
impl Variable { impl Variable {
pub fn new(name: impl Into<String>) -> Self { pub fn new(name: impl Into<String>) -> Self {
Variable::Variable { name: name.into() } Variable { name: name.into() }
} }
pub fn has_name(&self) -> bool { pub fn as_str(&self) -> &str {
match self { &self.name
Variable::Variable { .. } => true,
_ => false,
}
} }
#[deprecated]
pub fn name(&self) -> Result<&str> { pub fn name(&self) -> Result<&str> {
match self { Ok(self.as_str())
Variable::Variable { name } => Ok(name),
_ => Err(Error::msg(format!("The variable {} has no name", self))),
}
}
} }
impl fmt::Display for Variable { pub fn into_string(self) -> String {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.name
match self {
Variable::Variable { name } => write!(f, "?{}", name),
Variable::BlankNode { id } => write!(f, "_:{:x}", id),
Variable::Internal { id } => write!(f, "?{:x}", id),
}
}
} }
impl Default for Variable { pub(crate) fn new_random() -> Self {
fn default() -> Self { Self::new(format!("{:x}", random::<u128>()))
Variable::Internal {
id: random::<u128>(),
}
} }
} }
impl From<BlankNode> for Variable { impl fmt::Display for Variable {
fn from(blank_node: BlankNode) -> Self { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Variable::BlankNode { write!(f, "?{}", self.name)
id: blank_node.id(),
}
} }
} }
@ -214,8 +195,8 @@ pub enum NamedNodeOrVariable {
impl fmt::Display for NamedNodeOrVariable { impl fmt::Display for NamedNodeOrVariable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
NamedNodeOrVariable::NamedNode(node) => write!(f, "{}", node), NamedNodeOrVariable::NamedNode(node) => node.fmt(f),
NamedNodeOrVariable::Variable(var) => write!(f, "{}", var), NamedNodeOrVariable::Variable(var) => var.fmt(f),
} }
} }
} }
@ -241,8 +222,8 @@ pub enum TermOrVariable {
impl fmt::Display for TermOrVariable { impl fmt::Display for TermOrVariable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
TermOrVariable::Term(term) => write!(f, "{}", term), TermOrVariable::Term(term) => term.fmt(f),
TermOrVariable::Variable(var) => write!(f, "{}", var), TermOrVariable::Variable(var) => var.fmt(f),
} }
} }
} }
@ -255,7 +236,7 @@ impl From<NamedNode> for TermOrVariable {
impl From<BlankNode> for TermOrVariable { impl From<BlankNode> for TermOrVariable {
fn from(node: BlankNode) -> Self { fn from(node: BlankNode) -> Self {
TermOrVariable::Variable(node.into()) TermOrVariable::Term(node.into())
} }
} }
@ -273,11 +254,7 @@ impl From<Variable> for TermOrVariable {
impl From<Term> for TermOrVariable { impl From<Term> for TermOrVariable {
fn from(term: Term) -> Self { fn from(term: Term) -> Self {
match term { TermOrVariable::Term(term)
Term::NamedNode(node) => TermOrVariable::Term(node.into()),
Term::BlankNode(node) => TermOrVariable::Variable(node.into()),
Term::Literal(literal) => TermOrVariable::Term(literal.into()),
}
} }
} }

@ -80,7 +80,7 @@ fn add_to_triple_or_path_patterns(
add_to_triple_or_path_patterns(object, *p, subject, patterns) add_to_triple_or_path_patterns(object, *p, subject, patterns)
} }
PropertyPath::SequencePath(a, b) => { PropertyPath::SequencePath(a, b) => {
let middle = Variable::default(); let middle = BlankNode::default();
add_to_triple_or_path_patterns(subject, *a, middle.clone().into(), patterns); add_to_triple_or_path_patterns(subject, *a, middle.clone().into(), patterns);
add_to_triple_or_path_patterns(middle.into(), *b, object, patterns); add_to_triple_or_path_patterns(middle.into(), *b, object, patterns);
} }
@ -213,7 +213,7 @@ fn build_select(
//GROUP BY //GROUP BY
let aggregations = state.aggregations.pop().unwrap_or_else(BTreeMap::default); let aggregations = state.aggregations.pop().unwrap_or_else(BTreeMap::default);
if group.is_none() && !aggregations.is_empty() { if group.is_none() && !aggregations.is_empty() {
let const_variable = Variable::default(); let const_variable = Variable::new_random();
group = Some(( group = Some((
vec![const_variable.clone()], vec![const_variable.clone()],
vec![(Literal::from(1).into(), const_variable)], vec![(Literal::from(1).into(), const_variable)],
@ -310,7 +310,7 @@ impl ParserState {
.last_mut() .last_mut()
.ok_or_else(|| "Unexpected aggregate")?; .ok_or_else(|| "Unexpected aggregate")?;
Ok(aggregations.get(&agg).cloned().unwrap_or_else(|| { Ok(aggregations.get(&agg).cloned().unwrap_or_else(|| {
let new_var = Variable::default(); let new_var = Variable::new_random();
aggregations.insert(agg, new_var.clone()); aggregations.insert(agg, new_var.clone());
new_var new_var
})) }))
@ -644,7 +644,7 @@ parser! {
algebra: build_select(Selection { algebra: build_select(Selection {
option: SelectionOption::Default, option: SelectionOption::Default,
variables: Some(p.into_iter().map(|var_or_iri| match var_or_iri { variables: Some(p.into_iter().map(|var_or_iri| match var_or_iri {
NamedNodeOrVariable::NamedNode(n) => SelectionMember::Expression(n.into(), Variable::default()), NamedNodeOrVariable::NamedNode(n) => SelectionMember::Expression(n.into(), Variable::new_random()),
NamedNodeOrVariable::Variable(v) => SelectionMember::Variable(v) NamedNodeOrVariable::Variable(v) => SelectionMember::Variable(v)
}).collect()) }).collect())
}, w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state), }, w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state),
@ -690,10 +690,10 @@ parser! {
rule GroupClause() -> (Vec<Variable>, Vec<(Expression,Variable)>) = i("GROUP") _ i("BY") _ c:GroupCondition_item()+ { rule GroupClause() -> (Vec<Variable>, Vec<(Expression,Variable)>) = i("GROUP") _ i("BY") _ c:GroupCondition_item()+ {
let mut projections: Vec<(Expression,Variable)> = Vec::default(); let mut projections: Vec<(Expression,Variable)> = Vec::default();
let clauses = c.into_iter().map(|(e, vo)| { let clauses = c.into_iter().map(|(e, vo)| {
if let Expression::Constant(TermOrVariable::Variable(v)) = e { if let Expression::Variable(v) = e {
v v
} else { } else {
let v = vo.unwrap_or_else(Variable::default); let v = vo.unwrap_or_else(Variable::new_random);
projections.push((e, v.clone())); projections.push((e, v.clone()));
v v
} }
@ -1310,10 +1310,10 @@ parser! {
rule PrimaryExpression() -> Expression = rule PrimaryExpression() -> Expression =
BrackettedExpression() / BrackettedExpression() /
iriOrFunction() / iriOrFunction() /
v:Var() { Expression::Constant(v.into()) } / v:Var() { v.into() } /
l:RDFLiteral() { Expression::Constant(l.into()) } / l:RDFLiteral() { l.into() } /
l:NumericLiteral() { Expression::Constant(l.into()) } / l:NumericLiteral() { l.into() } /
l:BooleanLiteral() { Expression::Constant(l.into()) } / l:BooleanLiteral() { l.into() } /
BuiltInCall() BuiltInCall()
//[120] //[120]
@ -1423,7 +1423,7 @@ parser! {
rule iriOrFunction() -> Expression = i: iri() _ a: ArgList()? { rule iriOrFunction() -> Expression = i: iri() _ a: ArgList()? {
match a { match a {
Some(a) => Expression::FunctionCall(Function::Custom(i), a), Some(a) => Expression::FunctionCall(Function::Custom(i), a),
None => Expression::Constant(i.into()) None => i.into()
} }
} }

@ -1,6 +1,6 @@
use crate::model::{BlankNode, Term};
use crate::sparql::algebra::*; use crate::sparql::algebra::*;
use crate::sparql::model::*; use crate::sparql::model::*;
use crate::sparql::plan::PlanPropertyPath;
use crate::sparql::plan::*; use crate::sparql::plan::*;
use crate::store::numeric_encoder::{Encoder, ENCODED_DEFAULT_GRAPH}; use crate::store::numeric_encoder::{Encoder, ENCODED_DEFAULT_GRAPH};
use crate::Error; use crate::Error;
@ -276,10 +276,11 @@ impl<E: Encoder> PlanBuilder<E> {
graph_name: PatternValue, graph_name: PatternValue,
) -> Result<PlanExpression> { ) -> Result<PlanExpression> {
Ok(match expression { Ok(match expression {
Expression::Constant(t) => match t { Expression::NamedNode(node) => {
TermOrVariable::Term(t) => PlanExpression::Constant(self.encoder.encode_term(t)?), PlanExpression::Constant(self.encoder.encode_named_node(node)?)
TermOrVariable::Variable(v) => PlanExpression::Variable(variable_key(variables, v)), }
}, Expression::Literal(l) => PlanExpression::Constant(self.encoder.encode_literal(l)?),
Expression::Variable(v) => PlanExpression::Variable(variable_key(variables, v)),
Expression::Or(a, b) => PlanExpression::Or( Expression::Or(a, b) => PlanExpression::Or(
Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(a, variables, graph_name)?),
Box::new(self.build_for_expression(b, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?),
@ -704,10 +705,14 @@ impl<E: Encoder> PlanBuilder<E> {
variables: &mut Vec<Variable>, variables: &mut Vec<Variable>,
) -> Result<PatternValue> { ) -> Result<PatternValue> {
Ok(match term_or_variable { Ok(match term_or_variable {
TermOrVariable::Term(term) => PatternValue::Constant(self.encoder.encode_term(term)?),
TermOrVariable::Variable(variable) => { TermOrVariable::Variable(variable) => {
PatternValue::Variable(variable_key(variables, variable)) PatternValue::Variable(variable_key(variables, variable))
} }
TermOrVariable::Term(Term::BlankNode(bnode)) => {
PatternValue::Variable(variable_key(variables, &Variable::new(bnode.as_str())))
//TODO: very bad hack to convert bnode to variable
}
TermOrVariable::Term(term) => PatternValue::Constant(self.encoder.encode_term(term)?),
}) })
} }
@ -818,11 +823,8 @@ impl<E: Encoder> PlanBuilder<E> {
variables, variables,
&mut bnodes, &mut bnodes,
)?, )?,
predicate: self.template_value_from_named_node_or_variable( predicate: self
&triple.predicate, .template_value_from_named_node_or_variable(&triple.predicate, variables)?,
variables,
&mut bnodes,
)?,
object: self.template_value_from_term_or_variable( object: self.template_value_from_term_or_variable(
&triple.object, &triple.object,
variables, variables,
@ -837,18 +839,17 @@ impl<E: Encoder> PlanBuilder<E> {
&mut self, &mut self,
term_or_variable: &TermOrVariable, term_or_variable: &TermOrVariable,
variables: &mut Vec<Variable>, variables: &mut Vec<Variable>,
bnodes: &mut Vec<Variable>, bnodes: &mut Vec<BlankNode>,
) -> Result<TripleTemplateValue> { ) -> Result<TripleTemplateValue> {
Ok(match term_or_variable { Ok(match term_or_variable {
TermOrVariable::Term(term) => {
TripleTemplateValue::Constant(self.encoder.encode_term(term)?)
}
TermOrVariable::Variable(variable) => { TermOrVariable::Variable(variable) => {
if variable.has_name() {
TripleTemplateValue::Variable(variable_key(variables, variable)) TripleTemplateValue::Variable(variable_key(variables, variable))
} else {
TripleTemplateValue::BlankNode(variable_key(bnodes, variable))
} }
TermOrVariable::Term(Term::BlankNode(bnode)) => {
TripleTemplateValue::BlankNode(bnode_key(bnodes, bnode))
}
TermOrVariable::Term(term) => {
TripleTemplateValue::Constant(self.encoder.encode_term(term)?)
} }
}) })
} }
@ -857,18 +858,13 @@ impl<E: Encoder> PlanBuilder<E> {
&mut self, &mut self,
named_node_or_variable: &NamedNodeOrVariable, named_node_or_variable: &NamedNodeOrVariable,
variables: &mut Vec<Variable>, variables: &mut Vec<Variable>,
bnodes: &mut Vec<Variable>,
) -> Result<TripleTemplateValue> { ) -> Result<TripleTemplateValue> {
Ok(match named_node_or_variable { Ok(match named_node_or_variable {
NamedNodeOrVariable::NamedNode(term) => {
TripleTemplateValue::Constant(self.encoder.encode_named_node(term)?)
}
NamedNodeOrVariable::Variable(variable) => { NamedNodeOrVariable::Variable(variable) => {
if variable.has_name() {
TripleTemplateValue::Variable(variable_key(variables, variable)) TripleTemplateValue::Variable(variable_key(variables, variable))
} else {
TripleTemplateValue::BlankNode(variable_key(bnodes, variable))
} }
NamedNodeOrVariable::NamedNode(term) => {
TripleTemplateValue::Constant(self.encoder.encode_named_node(term)?)
} }
}) })
} }
@ -902,7 +898,7 @@ impl<E: Encoder> PlanBuilder<E> {
}) { }) {
to_id to_id
} else { } else {
to.push(Variable::default()); to.push(Variable::new_random());
to.len() - 1 to.len() - 1
} }
} }
@ -981,6 +977,16 @@ fn variable_key(variables: &mut Vec<Variable>, variable: &Variable) -> usize {
} }
} }
fn bnode_key(blank_nodes: &mut Vec<BlankNode>, blank_node: &BlankNode) -> usize {
match slice_key(blank_nodes, blank_node) {
Some(key) => key,
None => {
blank_nodes.push(blank_node.clone());
blank_nodes.len() - 1
}
}
}
fn slice_key<T: Eq>(slice: &[T], element: &T) -> Option<usize> { fn slice_key<T: Eq>(slice: &[T], element: &T) -> Option<usize> {
for (i, item) in slice.iter().enumerate() { for (i, item) in slice.iter().enumerate() {
if item == element { if item == element {
@ -992,14 +998,16 @@ fn slice_key<T: Eq>(slice: &[T], element: &T) -> Option<usize> {
fn sort_bgp(p: &[TripleOrPathPattern]) -> Vec<&TripleOrPathPattern> { fn sort_bgp(p: &[TripleOrPathPattern]) -> Vec<&TripleOrPathPattern> {
let mut assigned_variables = BTreeSet::default(); let mut assigned_variables = BTreeSet::default();
let mut assigned_blank_nodes = BTreeSet::default();
let mut new_p: Vec<_> = p.iter().collect(); let mut new_p: Vec<_> = p.iter().collect();
for i in 0..new_p.len() { for i in 0..new_p.len() {
(&mut new_p[i..]).sort_by(|p1, p2| { (&mut new_p[i..]).sort_by(|p1, p2| {
count_pattern_binds(p2, &assigned_variables) count_pattern_binds(p2, &assigned_variables, &assigned_blank_nodes).cmp(
.cmp(&count_pattern_binds(p1, &assigned_variables)) &count_pattern_binds(p1, &assigned_variables, &assigned_blank_nodes),
)
}); });
add_pattern_variables(new_p[i], &mut assigned_variables); add_pattern_variables(new_p[i], &mut assigned_variables, &mut assigned_blank_nodes);
} }
new_p new_p
@ -1008,12 +1016,17 @@ fn sort_bgp(p: &[TripleOrPathPattern]) -> Vec<&TripleOrPathPattern> {
fn count_pattern_binds( fn count_pattern_binds(
pattern: &TripleOrPathPattern, pattern: &TripleOrPathPattern,
assigned_variables: &BTreeSet<&Variable>, assigned_variables: &BTreeSet<&Variable>,
assigned_blank_nodes: &BTreeSet<&BlankNode>,
) -> u8 { ) -> u8 {
let mut count = 12; let mut count = 12;
if let TermOrVariable::Variable(v) = pattern.subject() { if let TermOrVariable::Variable(v) = pattern.subject() {
if !assigned_variables.contains(v) { if !assigned_variables.contains(v) {
count -= 4; count -= 4;
} }
} else if let TermOrVariable::Term(Term::BlankNode(bnode)) = pattern.subject() {
if !assigned_blank_nodes.contains(bnode) {
count -= 4;
}
} else { } else {
count -= 1; count -= 1;
} }
@ -1032,6 +1045,10 @@ fn count_pattern_binds(
if !assigned_variables.contains(v) { if !assigned_variables.contains(v) {
count -= 4; count -= 4;
} }
} else if let TermOrVariable::Term(Term::BlankNode(bnode)) = pattern.object() {
if !assigned_blank_nodes.contains(bnode) {
count -= 4;
}
} else { } else {
count -= 1; count -= 1;
} }
@ -1041,9 +1058,12 @@ fn count_pattern_binds(
fn add_pattern_variables<'a>( fn add_pattern_variables<'a>(
pattern: &'a TripleOrPathPattern, pattern: &'a TripleOrPathPattern,
variables: &mut BTreeSet<&'a Variable>, variables: &mut BTreeSet<&'a Variable>,
blank_nodes: &mut BTreeSet<&'a BlankNode>,
) { ) {
if let TermOrVariable::Variable(v) = pattern.subject() { if let TermOrVariable::Variable(v) = pattern.subject() {
variables.insert(v); variables.insert(v);
} else if let TermOrVariable::Term(Term::BlankNode(bnode)) = pattern.subject() {
blank_nodes.insert(bnode);
} }
if let TripleOrPathPattern::Triple(t) = pattern { if let TripleOrPathPattern::Triple(t) = pattern {
if let NamedNodeOrVariable::Variable(v) = &t.predicate { if let NamedNodeOrVariable::Variable(v) = &t.predicate {
@ -1052,5 +1072,7 @@ fn add_pattern_variables<'a>(
} }
if let TermOrVariable::Variable(v) = pattern.object() { if let TermOrVariable::Variable(v) = pattern.object() {
variables.insert(v); variables.insert(v);
} else if let TermOrVariable::Term(Term::BlankNode(bnode)) = pattern.object() {
blank_nodes.insert(bnode);
} }
} }

@ -44,7 +44,7 @@ pub fn write_xml_results<W: Write>(results: QueryResult<'_>, sink: W) -> Result<
writer.write_event(Event::Start(BytesStart::borrowed_name(b"head")))?; writer.write_event(Event::Start(BytesStart::borrowed_name(b"head")))?;
for variable in &variables { for variable in &variables {
let mut variable_tag = BytesStart::borrowed_name(b"variable"); let mut variable_tag = BytesStart::borrowed_name(b"variable");
variable_tag.push_attribute(("name", variable.name()?)); variable_tag.push_attribute(("name", variable.as_str()));
writer.write_event(Event::Empty(variable_tag))?; writer.write_event(Event::Empty(variable_tag))?;
} }
writer.write_event(Event::End(BytesEnd::borrowed(b"head")))?; writer.write_event(Event::End(BytesEnd::borrowed(b"head")))?;
@ -55,7 +55,7 @@ pub fn write_xml_results<W: Write>(results: QueryResult<'_>, sink: W) -> Result<
for (i, value) in result.into_iter().enumerate() { for (i, value) in result.into_iter().enumerate() {
if let Some(term) = value { if let Some(term) = value {
let mut binding_tag = BytesStart::borrowed_name(b"binding"); let mut binding_tag = BytesStart::borrowed_name(b"binding");
binding_tag.push_attribute(("name", variables[i].name()?)); binding_tag.push_attribute(("name", variables[i].as_str()));
writer.write_event(Event::Start(binding_tag))?; writer.write_event(Event::Start(binding_tag))?;
match term { match term {
Term::NamedNode(uri) => { Term::NamedNode(uri) => {

@ -361,7 +361,7 @@ fn to_graph(result: QueryResult<'_>, with_order: bool) -> Result<SimpleGraph> {
graph.insert(Triple::new( graph.insert(Triple::new(
result_set, result_set,
rs::RESULT_VARIABLE.clone(), rs::RESULT_VARIABLE.clone(),
Literal::new_simple_literal(variable.name()?), Literal::new_simple_literal(variable.as_str()),
)); ));
} }
for (i, binding_values) in iter.enumerate() { for (i, binding_values) in iter.enumerate() {
@ -376,7 +376,7 @@ fn to_graph(result: QueryResult<'_>, with_order: bool) -> Result<SimpleGraph> {
graph.insert(Triple::new( graph.insert(Triple::new(
binding, binding,
rs::VARIABLE.clone(), rs::VARIABLE.clone(),
Literal::new_simple_literal(variables[i].name()?), Literal::new_simple_literal(variables[i].as_str()),
)); ));
} }
} }

Loading…
Cancel
Save