From f017a829d999f2237a83b25221446a7d9de0cb90 Mon Sep 17 00:00:00 2001 From: Gunnar Aastrand Grimnes Date: Thu, 19 Jan 2017 20:25:28 +0100 Subject: [PATCH] Fix initBindings in SPARQL initBindings are now special fixed bindings, they are always in scope in all parts of the query. Fixes #294 (once and for all) --- rdflib/plugins/sparql/evaluate.py | 36 ++++--------------------------- rdflib/plugins/sparql/sparql.py | 13 +++++------ rdflib/plugins/sparql/update.py | 12 ++++------- test/test_initbindings.py | 3 +++ 4 files changed, 18 insertions(+), 46 deletions(-) diff --git a/rdflib/plugins/sparql/evaluate.py b/rdflib/plugins/sparql/evaluate.py index e79e51493..8d22c2d92 100644 --- a/rdflib/plugins/sparql/evaluate.py +++ b/rdflib/plugins/sparql/evaluate.py @@ -446,41 +446,13 @@ def evalConstructQuery(ctx, query): def evalQuery(graph, query, initBindings, base=None): - ctx = QueryContext(graph) - ctx.prologue = query.prologue + initBindings = dict( ( Variable(k),v ) for k,v in initBindings.iteritems() ) - main = query.algebra + ctx = QueryContext(graph, initBindings=initBindings) - if initBindings: - # add initBindings as a values clause - - values = {} # no dict comprehension in 2.6 :( - for k,v in initBindings.iteritems(): - if not isinstance(k, Variable): - k = Variable(k) - values[k] = v - - main = main.clone() # clone to not change prepared q - main['p'] = main.p.clone() - # Find the right place to insert MultiSet join - repl = main.p - if repl.name == 'Slice': - repl['p'] = repl.p.clone() - repl = repl.p - if repl.name == 'Distinct': - repl['p'] = repl.p.clone() - repl = repl.p - if repl.p.name == 'OrderBy': - repl['p'] = repl.p.clone() - repl = repl.p - if repl.p.name == 'Extend': - repl['p'] = repl.p.clone() - repl = repl.p - - repl['p'] = Join(repl.p, ToMultiSet(Values([values]))) - - # TODO: Vars? + ctx.prologue = query.prologue + main = query.algebra if main.datasetClause: if ctx.dataset is None: diff --git a/rdflib/plugins/sparql/sparql.py b/rdflib/plugins/sparql/sparql.py index 695055618..c012a8fc7 100644 --- a/rdflib/plugins/sparql/sparql.py +++ b/rdflib/plugins/sparql/sparql.py @@ -197,8 +197,8 @@ def forget(self, before, _except=None): since before """ if not _except : _except = [] - - return FrozenBindings(self.ctx, (x for x in self.iteritems() if x[0] in _except or before[x[0]] is None)) + # bindings from initBindings are newer forgotten + return FrozenBindings(self.ctx, (x for x in self.iteritems() if x[0] in _except or x[0] in self.ctx.initBindings or before[x[0]] is None)) def remember(self, these): """ @@ -213,8 +213,10 @@ class QueryContext(object): Query context - passed along when evaluating the query """ - def __init__(self, graph=None, bindings=None): - self.bindings = bindings or Bindings() + def __init__(self, graph=None, bindings=None, initBindings=None): + self.initBindings = initBindings + self.bindings = Bindings(d=bindings or []) + if initBindings: self.bindings.update(initBindings) if isinstance(graph, ConjunctiveGraph): self._dataset = graph @@ -233,9 +235,8 @@ def __init__(self, graph=None, bindings=None): def clone(self, bindings=None): r = QueryContext( - self._dataset if self._dataset is not None else self.graph) + self._dataset if self._dataset is not None else self.graph, bindings or self.bindings, initBindings=self.initBindings) r.prologue = self.prologue - r.bindings.update(bindings or self.bindings) r.graph = self.graph r.bnodes = self.bnodes return r diff --git a/rdflib/plugins/sparql/update.py b/rdflib/plugins/sparql/update.py index 57c5bf461..f5a5f2eb1 100644 --- a/rdflib/plugins/sparql/update.py +++ b/rdflib/plugins/sparql/update.py @@ -252,7 +252,7 @@ def evalCopy(ctx, u): dstg += srcg -def evalUpdate(graph, update, initBindings=None): +def evalUpdate(graph, update, initBindings={}): """ http://www.w3.org/TR/sparql11-update/#updateLanguage @@ -274,15 +274,11 @@ def evalUpdate(graph, update, initBindings=None): for u in update: - ctx = QueryContext(graph) + initBindings = dict( ( Variable(k),v ) for k,v in initBindings.iteritems() ) + + ctx = QueryContext(graph, initBindings=initBindings) ctx.prologue = u.prologue - if initBindings: - for k, v in initBindings.iteritems(): - if not isinstance(k, Variable): - k = Variable(k) - ctx[k] = v - # ctx.push() # nescessary? try: if u.name == 'Load': diff --git a/test/test_initbindings.py b/test/test_initbindings.py index ad94db4f2..e44f9fff5 100644 --- a/test/test_initbindings.py +++ b/test/test_initbindings.py @@ -150,6 +150,9 @@ def testVariableKeyWithQuestionMark(): results = list(g2.query("SELECT ?o WHERE { ?s :p ?o }", initBindings={Variable("?s"): EX['s1']})) assert len(results) == 1, results +def testFilter(): + results = list(g2.query("SELECT ?o WHERE { ?s :p ?o FILTER (?s = ?x)}", initBindings={Variable("?x"): EX['s1']})) + assert len(results) == 1, results if __name__ == "__main__":