OK, I realized only now that the ParameterizedSparqlString is safe in
terms of injection attacks but not in terms of SPARQL scoping... Since
it's just a wrapper for string replacement. I had mistaken this.

So I actually should be looking at the QueryTransformOps
implementation probably.

And my question from the previous email should have been:
Can there be differences in query semantics after a value was injected
using *QueryTransformOps* vs. Substitute?

On Wed, Feb 26, 2025 at 9:08 PM Martynas Jusevičius
<marty...@atomgraph.com> wrote:
>
> On Fri, Feb 21, 2025 at 1:01 PM Andy Seaborne <a...@apache.org> wrote:
> >
> >
> >
> > On 12/02/2025 21:03, Martynas Jusevičius wrote:
> > > Hi Andy,
> > >
> > > I understand the differences of how they are implemented.
> > >
> > > I think what I'm missing is a sort of overview of when those different
> > > approaches should be used, and also examples of when they produce
> > > semantically different queries.
> >
> > string template substitution can alter or break queries.
> >
> > Replace ?X in {?s :p ?X} with the  '"text" . FILTER (?s != :hideMe )'
>
> I understand that simple string replacement is not safe.
>
> But can there be differences in query semantics after a value was
> injected using ParameterizedSparqlString vs. Substitute?
>
> >
> > https://xkcd.com/327/
> >
> >      Andy
> >
> > >
> > >
> > > Martynas
> > >
> > > On Thu, Feb 6, 2025 at 5:59 PM Andy Seaborne <a...@apache.org> wrote:
> > >>
> > >>
> > >>
> > >> On 06/02/2025 03:24, Nicholas Car wrote:
> > >>> You could try running that with RDFlib and see what it does….
> > >>>
> > >>> How is substitute() different to just string template substitution? Is 
> > >>> it just a convenience function so substitution can be done on a Jena 
> > >>> SPARQL object (perhaps algebra) rather than a string?
> > >>
> > >>
> > >> It does not work on a string - when working with Query objects (e.g.
> > >> service enhancer), manipulate is on Query objects.
> > >> It does does not have injection attacks.
> > >>
> > >> There some places where you can't replace a variable by a value
> > >>
> > >> BIND(123  AS ?X)
> > >>
> > >> for example. QueryTransforOps checks.
> > >>
> > >> Substitute.substitue is a collect of algebra to algebra changes - some
> > >> of which are used in execution.
> > >>
> > >>>
> > >>> Is that your goal for an RDFLib equivalent?
> > >>
> > >> See also ParameterizedSparqlString in Jena which is injection-safe.
> > >> That's closer to string replacement.
> > >>
> > >> Under the general concept of "substitute" there are different uses cases
> > >> on different objects.
> > >>
> > >>       Andy
> > >>
> > >>> SPARQL string to/from SPARQL grammar object is handles in RDFLib fine 
> > >>> so I guess as I think the code says, an RDFLib substitute() could work 
> > >>> on either or both.
> > >>>
> > >>> Nick
> > >>>
> > >>> On Thu, Feb 6, 2025 at 10:05 am, Martynas Jusevičius 
> > >>> <[marty...@atomgraph.com](mailto:On Thu, Feb 6, 2025 at 10:05 am, 
> > >>> Martynas Jusevičius <<a href=)> wrote:
> > >>>
> > >>>> OK I simply fed Jena's source to ChatGPT and asked it to produce an
> > >>>> RDFLIb version :)
> > >>>> No idea if it's correct but I'll find out I guess.
> > >>>>
> > >>>> from rdflib import Variable, BNode, Literal
> > >>>> from rdflib.plugins.sparql.algebra import BGP, Filter, Join, LeftJoin,
> > >>>> Union, Graph, Extend, Minus, OrderBy, Project
> > >>>>
> > >>>> def substitute(algebra, binding):
> > >>>> if isinstance(algebra, BGP):
> > >>>> new_triples = []
> > >>>> for s, p, o in algebra.triples:
> > >>>> s = binding.get(s, s)
> > >>>> p = binding.get(p, p)
> > >>>> o = binding.get(o, o)
> > >>>> new_triples.append((s, p, o))
> > >>>> return BGP(new_triples)
> > >>>> elif isinstance(algebra, Filter):
> > >>>> new_p = substitute(algebra.p, binding)
> > >>>> new_expr = algebra.expr
> > >>>> for var, val in binding.items():
> > >>>> new_expr = new_expr.substitute(var, val)
> > >>>> return Filter(new_expr, new_p)
> > >>>> elif isinstance(algebra, Join):
> > >>>> return Join(substitute(algebra.p1, binding),
> > >>>> substitute(algebra.p2, binding))
> > >>>> elif isinstance(algebra, LeftJoin):
> > >>>> return LeftJoin(substitute(algebra.p1, binding),
> > >>>> substitute(algebra.p2, binding), algebra.expr)
> > >>>> elif isinstance(algebra, Union):
> > >>>> return Union(substitute(algebra.p1, binding),
> > >>>> substitute(algebra.p2, binding))
> > >>>> elif isinstance(algebra, Graph):
> > >>>> return Graph(algebra.term, substitute(algebra.p, binding))
> > >>>> elif isinstance(algebra, Extend):
> > >>>> new_p = substitute(algebra.p, binding)
> > >>>> new_expr = algebra.expr
> > >>>> for var, val in binding.items():
> > >>>> new_expr = new_expr.substitute(var, val)
> > >>>> return Extend(new_p, new_expr, algebra.var)
> > >>>> elif isinstance(algebra, Minus):
> > >>>> return Minus(substitute(algebra.p1, binding),
> > >>>> substitute(algebra.p2, binding))
> > >>>> elif isinstance(algebra, OrderBy):
> > >>>> return OrderBy(substitute(algebra.p, binding), algebra.expr)
> > >>>> elif isinstance(algebra, Project):
> > >>>> return Project(substitute(algebra.p, binding), algebra.PV)
> > >>>> else:
> > >>>> return algebra
> > >>>>
> > >>>> On Thu, Feb 6, 2025 at 12:54 AM Martynas Jusevičius
> > >>>> <marty...@atomgraph.com> wrote:
> > >>>>>
> > >>>>> Hi,
> > >>>>>
> > >>>>> I was looking to implement something like substitute() using RDFLib.
> > >>>>>
> > >>>>> I checked the note:
> > >>>>> https://afs.github.io/substitute.htm
> > >>>>> But I couldn't find a clear example.
> > >>>>>
> > >>>>> For example, how would this query string (the template)
> > >>>>>
> > >>>>> PREFIX dbo: <http://dbpedia.org/ontology/>
> > >>>>> CONSTRUCT
> > >>>>> WHERE { ?city dbo:populationTotal ?population }
> > >>>>>
> > >>>>> would look like after substituting (?city,
> > >>>>> <http://dbpedia.org/resource/Copenhagen>)?
> > >>>>>
> > >>>>>
> > >>>>> Martynas
> > >>
> >

Reply via email to