blob: 7f1bdcc67359e2a7c23e2a9276529eba63450344 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Apache Jena - Parameterized SPARQL String</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/css/bootstrap-icons.css" rel="stylesheet" media="screen"><link rel="stylesheet" type="text/css" href="https://jena.apache.org/sass/jena.1b17c39a117e22b46db4c66f6395dc27c134a60377d87d2d5745b8600eb69722.css" integrity="sha256-GxfDmhF&#43;IrRttMZvY5XcJ8E0pgN32H0tV0W4YA62lyI=">
<link rel="shortcut icon" href="/images/favicon.ico" />
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary" role="navigation">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="/index.html">
<img class="logo-menu" src="/images/jena-logo/jena-logo-notext-small.png" alt="jena logo">Apache Jena</a>
</div>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li id="homepage" class="nav-item"><a class="nav-link" href="/index.html"><span class="bi-house"></span> Home</a></li>
<li id="download" class="nav-item"><a class="nav-link" href="/download/index.cgi"><span class="bi-download"></span> Download</a></li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal"></span> Learn <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Tutorials</li>
<li><a class="dropdown-item" href="/tutorials/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/fuseki2/index.html">Fuseki Triplestore</a></li>
<li><a class="dropdown-item" href="/documentation/notes/index.html">How-To's</a></li>
<li><a class="dropdown-item" href="/documentation/query/manipulating_sparql_using_arq.html">Manipulating SPARQL using ARQ</a></li>
<li><a class="dropdown-item" href="/tutorials/rdf_api.html">RDF core API tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/sparql.html">SPARQL tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/using_jena_with_eclipse.html">Using Jena with Eclipse</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">References</li>
<li><a class="dropdown-item" href="/documentation/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/query/index.html">ARQ (SPARQL)</a></li>
<li><a class="dropdown-item" href="/documentation/io/">RDF I/O</a></li>
<li><a class="dropdown-item" href="/documentation/assembler/index.html">Assembler</a></li>
<li><a class="dropdown-item" href="/documentation/tools/index.html">Command-line tools</a></li>
<li><a class="dropdown-item" href="/documentation/rdfs/">Data with RDFS Inferencing</a></li>
<li><a class="dropdown-item" href="/documentation/geosparql/index.html">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/inference/index.html">Inference API</a></li>
<li><a class="dropdown-item" href="/documentation/ontology/">Ontology API</a></li>
<li><a class="dropdown-item" href="/documentation/permissions/index.html">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/extras/querybuilder/index.html">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/rdf/index.html">RDF API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfconnection/">RDF Connection - SPARQL API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfstar/index.html">RDF-star</a></li>
<li><a class="dropdown-item" href="/documentation/shacl/index.html">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/shex/index.html">ShEx</a></li>
<li><a class="dropdown-item" href="/documentation/tdb/index.html">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/tdb2/index.html">TDB2</a></li>
<li><a class="dropdown-item" href="/documentation/query/text-query.html">Text Search</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal-code"></span> Javadoc <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/documentation/javadoc.html">All Javadoc</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/arq/">ARQ</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/fuseki2/">Fuseki</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/geosparql/">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/jena/">Jena Core</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/permissions/">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/extras/querybuilder/">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/shacl/">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/tdb/">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/text/">Text Search</a></li>
</ul>
</li>
</ul>
<form class="d-flex" role="search" action="/search" method="GET">
<div class="input-group">
<input class="form-control border-end-0 border m-0" type="search" name="q" id="search-query" placeholder="Search...." aria-label="Search" style="width: 10rem;">
<button class="btn btn-outline-secondary border-start-0 border" type="submit">
<i class="bi-search"></i>
</button>
</div>
</form>
<ul class="navbar-nav">
<li id="ask" class="nav-item"><a class="nav-link" href="/help_and_support/index.html" title="Ask"><span class="bi-patch-question"></span><span class="text-body d-none d-xxl-inline"> Ask</span></a></li>
<li class="nav-item dropdown">
<a href="#" title="Get involved" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-megaphone"></span><span class="text-body d-none d-xxl-inline"> Get involved </span><b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/getting_involved/index.html">Contribute</a></li>
<li><a class="dropdown-item" href="/help_and_support/bugs_and_suggestions.html">Report a bug</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">Project</li>
<li><a class="dropdown-item" href="/about_jena/about.html">About Jena</a></li>
<li><a class="dropdown-item" href="/about_jena/architecture.html">Architecture</a></li>
<li><a class="dropdown-item" href="/about_jena/citing.html">Citing</a></li>
<li><a class="dropdown-item" href="/about_jena/team.html">Project team</a></li>
<li><a class="dropdown-item" href="/about_jena/contributions.html">Related projects</a></li>
<li><a class="dropdown-item" href="/about_jena/roadmap.html">Roadmap</a></li>
<li><a class="dropdown-item" href="/about_jena/security-advisories.html">Security Advisories</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">ASF</li>
<li><a class="dropdown-item" href="https://www.apache.org/">Apache Software Foundation</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Become a Sponsor</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/licenses/LICENSE-2.0">License</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/security/">Security</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
</ul>
</li>
<li class="nav-item" id="edit"><a class="nav-link" href="https://github.com/apache/jena-site/edit/main/source/documentation/query/parameterized-sparql-strings.md" title="Edit this page on GitHub"><span class="bi-pencil-square"></span><span class="text-body d-none d-xxl-inline"> Edit this page</span></a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="breadcrumbs">
<ol class="breadcrumb mt-4 p-2 bg-body-tertiary">
<li class="breadcrumb-item"><a href='/documentation'>DOCUMENTATION</a></li>
<li class="breadcrumb-item"><a href='/documentation/query'>QUERY</a></li>
<li class="breadcrumb-item active">PARAMETERIZED SPARQL STRINGS</li>
</ol>
</div>
<h1 class="title">Parameterized SPARQL String</h1>
<main class="d-flex flex-xl-row flex-column">
<aside class="text-muted align-self-start mb-3 p-0 d-xl-none d-block">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#building-parameterised-commands">Building parameterised commands</a>
<ul>
<li><a href="#injecting-values">Injecting Values</a>
<ul>
<li><a href="#variable-parameters">Variable Parameters</a></li>
<li><a href="#positional-parameters">Positional Parameters</a></li>
<li><a href="#non-existent-parameters">Non-existent parameters</a></li>
<li><a href="#buffer-usage">Buffer Usage</a></li>
<li><a href="#getting-a-queryupdate">Getting a Query/Update</a></li>
</ul>
</li>
<li><a href="#sparql-injection-notes">SPARQL Injection Notes</a></li>
</ul>
</li>
</ul>
</nav>
</aside>
<article class="flex-column me-lg-4">
<p>A Parameterized SPARQL String is a SPARQL query/update into which values
may be injected.</p>
<p>The intended usage of this is where using a <code>QuerySolutionMap</code> as
initial bindings is either inappropriate or not possible e.g.</p>
<ul>
<li>Generating query/update strings in code without lots of error prone
and messy string concatenation</li>
<li>Preparing a query/update for remote execution</li>
<li>Where you do not want to simply say some variable should have a
certain value but rather wish to insert constants into the
query/update in place of variables</li>
<li>Defending against SPARQL injection when creating a query/update
using some external input, see SPARQL Injection notes for
limitations.</li>
<li>Provide a more convenient way to prepend common prefixes to your
query</li>
</ul>
<p>This class is useful for preparing both queries and updates hence the
generic name as it provides programmatic ways to replace variables in
the query with constants and to add prefix and base declarations. A
<code>Query</code> or <code>UpdateRequest</code> can be created using
the <code>asQuery()</code> and <code>asUpdate()</code> methods assuming the command an
instance represents is actually valid as a query/update.</p>
<h2 id="building-parameterised-commands">Building parameterised commands</h2>
<p>A <a href="/documentation/javadoc/arq/org.apache.jena.arq/org/apache/jena/query/ParameterizedSparqlString.html">ParameterizedSparqlString</a> is created as follows:</p>
<pre><code>ParameterizedSparqlString pss = new ParameterizedSparqlString();
</code></pre>
<p>There are also constructor overloads that take in an initial command text, parameter values, namespace prefixes etc.
which may allow you to simplify some code.</p>
<p>Once you have an instance you first set your template command with the <code>setCommandText()</code> method like so:</p>
<pre><code>pss.setCommandText(&quot;SELECT * WHERE {\n&quot; +
&quot; ?s a ?type .\n&quot; +
&quot; OPTIONAL { ?s rdfs:label ?label . }\n&quot; +
&quot;}&quot;);
</code></pre>
<p>Note that in the above example we did not define the <code>rdfs:</code> prefix so as it stands the query is invalid. However
you can automatically populate <code>BASE</code> and <code>PREFIX</code> declarations for your command without having to explicitly
declare them in your command text by using the <code>setBaseUri()</code> and <code>setNsPrefix()</code> method e.g.</p>
<pre><code>// Add a Base URI and define the rdfs prefix
pss.setBaseUri(&quot;http://example.org/base#&quot;);
pss.setNsPrefix(&quot;rdfs&quot;, &quot;http://www.w3.org/2000/01/rdf-schema#&quot;);
</code></pre>
<p>You can always call <code>toString()</code> to see the current state of your instance e.g.</p>
<pre><code>// Print current state to stdout
System.out.println(pss.toString());
</code></pre>
<p>Which based on the calls so far would print the following:</p>
<pre><code>BASE &lt;http://example.org/base#&gt;
PREFIX rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#&gt;
SELECT * WHERE {
?s a ?type .
OPTIONAL { ?s rdfs:label ?label . }
}
</code></pre>
<p>Note that the state of the instance returned by <code>toString()</code> will include any injected values. Part of what the <code>toString()</code> method
does is check that your command is not subject to SPARQL injection attacks so in some cases where a possible
injection is detected an <code>ARQException</code> will be thrown.</p>
<h3 id="injecting-values">Injecting Values</h3>
<p>Once you have a command text prepared then you want to actually inject values into it, values may be injected in several ways:</p>
<ul>
<li>By treating a variable in the SPARQL string as a parameter</li>
<li>Using JDBC style positional parameters</li>
<li>Appending values directly to the command text being built</li>
</ul>
<p>See the <a href="/documentation/javadoc/arq/org.apache.jena.arq/org/apache/jena/query/ParameterizedSparqlString.html">ParameterizedSparqlString</a> javadocs for a comprehensive reference of available methods for setting values,
the following sections shows some basic examples of this.</p>
<h4 id="variable-parameters">Variable Parameters</h4>
<p>Any SPARQL variable in the command text may have a value injected to it, injecting a value replaces all usages of
that variable in the command i.e. substitutes the variable for a constant. Importantly injection is done by textual
substitution so in some cases may cause unexpected side effects.</p>
<p>Variables parameters are set via the various <code>setX()</code> methods which take a <code>String</code> as their first argument e.g.</p>
<pre><code>// Set an IRI
pss.setIri(&quot;x&quot;, &quot;http://example.org&quot;);
// Set a Literal
pss.setLiteral(&quot;x&quot;, 1234);
pss.setLiteral(&quot;x&quot;, true);
pss.setLiteral(&quot;x&quot;, &quot;value&quot;);
</code></pre>
<p>Where you set a value for a variable you have already set the existing value is overwritten. Setting any value
to <code>null</code> has the same effect as calling the <code>clearParam(&quot;x&quot;)</code> method</p>
<p>If you have the value already as a <code>RDFNode</code> or <code>Node</code> instance you can call the <code>setParam()</code> method instead e.g.</p>
<pre><code>// Set a Node
Node n = NodeFactory.createIRI(&quot;http://example.org&quot;);
pas.setParam(&quot;x&quot;, n);
</code></pre>
<h4 id="positional-parameters">Positional Parameters</h4>
<p>You can use JDBC style positional parameters if you prefer, a JDBC style parameter is a single <code>?</code> followed by
whitespace or certain punctuation characters (currently <code>; , .</code>). Positional parameters have a unique index which
reflects the order in which they appear in the string. Note that positional parameters use a zero based index.</p>
<p>Positional parameters are set via the various <code>setX()</code> methods which take an <code>int</code> as their first argument e.g.</p>
<pre><code>// Set an IRI
pss.setIri(0, &quot;http://example.org&quot;);
// Set a Literal
pss.setLiteral(0, 1234);
pss.setLiteral(0, true);
pss.setLiteral(0, &quot;value&quot;);
</code></pre>
<p>Where you set a value for a variable you have already set the existing value is overwritten. Setting any value
to <code>null</code> has the same effect as calling the <code>clearParam(0)</code> method</p>
<p>If you have the value already as a <code>RDFNode</code> or <code>Node</code> instance you can call the <code>setParam()</code> method instead e.g.</p>
<pre><code>// Set a Node
Node n = NodeFactory.createIRI(&quot;http://example.org&quot;);
pas.setParam(0, n);
</code></pre>
<h4 id="non-existent-parameters">Non-existent parameters</h4>
<p>Where you try to set a variable/positional parameter that does not exist there will be no feedback that the parameter
does not exist, however the value set will not be included in the string produced when calling the <code>toString()</code> method.</p>
<h4 id="buffer-usage">Buffer Usage</h4>
<p>Additionally you may use this purely as a <code>StringBuffer</code> replacement for creating commands since it provides a
large variety of convenience methods for appending things either as-is or as nodes (which causes appropriate
formatting to be applied).</p>
<p>For example we could add an <code>ORDER BY</code> clause to our earlier example like so:</p>
<pre><code>// Add ORDER BY clause
pss.append(&quot;ORDER BY ?s&quot;);
</code></pre>
<p>Be aware that the basic <code>append()</code> methods append the given value as-is without any special formatting applied, if you
wanted to use the value being appended as a constant in the SPARQL query then you should use the appropriate <code>appendLiteral()</code>,
<code>appendIri()</code> or <code>appendNode()</code> method e.g.</p>
<pre><code>// Add a LIMIT clause
pss.append(&quot;LIMIT &quot;);
pss.appendLiteral(50);
</code></pre>
<h4 id="getting-a-queryupdate">Getting a Query/Update</h4>
<p>Once you&rsquo;ve prepared your command you should then call the <code>asQuery()</code> or <code>asUpdate()</code> method to get it as a <code>Query</code>
or <code>UpdateRequest</code> object as appropriate. Doing this calls <code>toString()</code> to produce the final version of your command with
all values injected and runs it through the appropriate parser (either <code>QueryFactory</code> or <code>UpdateFactory</code>).</p>
<p>You can then use the returned <code>Query</code> or <code>UpdateRequest</code> object as you would normally to make a query/update.</p>
<h3 id="sparql-injection-notes">SPARQL Injection Notes</h3>
<p>First a couple of warnings:</p>
<ol>
<li>This class does not in any way check that your command is syntactically correct until such time as you try and parse
it as a <code>Query</code> or <code>UpdateRequest</code>.</li>
<li>Injection is done purely based on textual replacement, it does not understand or respect variable scope in any
way. For example if your command text contains sub queries you should ensure that variables within the sub query
which you don&rsquo;t want replaced have distinct names from those in the outer query you do want replaced (or vice versa)</li>
</ol>
<p>While this class was in part designed to prevent SPARQL injection it is by no means foolproof because it works purely
at the textual level. The current version of the code addresses some possible attack vectors that the developers have
identified but we do not claim to be sufficiently devious to have thought of and prevented every possible attack vector.</p>
<p>Therefore we <strong>strongly</strong> recommend that users concerned about SPARQL Injection attacks perform
their own validation on provided parameters and test their use of this class themselves prior to its use in any security
conscious deployment. We also recommend that users do not use easily guess-able variable names for their parameters
as these can allow a chained injection attack though generally speaking the code should prevent these.</p>
</article>
<aside class="text-muted align-self-start mb-3 mb-xl-5 p-0 d-none d-xl-flex flex-column sticky-top">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#building-parameterised-commands">Building parameterised commands</a>
<ul>
<li><a href="#injecting-values">Injecting Values</a>
<ul>
<li><a href="#variable-parameters">Variable Parameters</a></li>
<li><a href="#positional-parameters">Positional Parameters</a></li>
<li><a href="#non-existent-parameters">Non-existent parameters</a></li>
<li><a href="#buffer-usage">Buffer Usage</a></li>
<li><a href="#getting-a-queryupdate">Getting a Query/Update</a></li>
</ul>
</li>
<li><a href="#sparql-injection-notes">SPARQL Injection Notes</a></li>
</ul>
</li>
</ul>
</nav>
</aside>
</main>
</div>
</div>
</div>
<footer class="bd-footer py-4 py-md-5 mt-4 mt-lg-5 bg-body-tertiary">
<div class="container" style="font-size:80%" >
<p>
Copyright &copy; 2011&ndash;2024 The Apache Software Foundation, Licensed under the
<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
</p>
<p>
Apache Jena, Jena, the Apache Jena project logo, Apache and the Apache feather logos are trademarks of
The Apache Software Foundation.
<br/>
<a href="https://privacy.apache.org/policies/privacy-policy-public.html"
>Apache Software Foundation Privacy Policy</a>.
</p>
</div>
</footer>
<script src="/js/popper.min.js.js" type="text/javascript"></script>
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<script src="/js/improve.js" type="text/javascript"></script>
<script type="text/javascript">
(function() {
'use strict'
const links = document.querySelectorAll(`a[href="${window.location.pathname}"]`)
if (links !== undefined && links !== null) {
for (const link of links) {
link.classList.add('active')
let parentElement = link.parentElement
let count = 0
const levelsLimit = 4
while (['UL', 'LI'].includes(parentElement.tagName) && count <= levelsLimit) {
if (parentElement.tagName === 'LI') {
parentElement.querySelector('a:first-child').classList.add('active')
}
parentElement = parentElement.parentElement
count++
}
}
}
})()
</script>
</body>
</html>