<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
               "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2001/XInclude'">
]>

<part id="sparql-and-tracker">
  <title>SPARQL as understood by Tracker</title>
  <partintro>
    This section describes the choices made by Tracker in its interpretation
    of the SPARQL documents, as well as its extensions and divergences.
  </partintro>

  <chapter id="graphs">
    <title>The default graph</title>
    <para>
      The <ulink url="https://www.w3.org/TR/sparql11-update/#graphStore">SPARQL
      documentation</ulink> says:
    </para>
    <para>
      <quote>
	Operations may specify graphs to be modified, or they may rely on a
	default graph for that operation. […] The unnamed graph for the store
	will be the default graph for any operations on that store. Depending
	on implementation, the unnamed graph may refer to a separate graph, a
	graph describing the named graphs, a representation of a union of
	other graphs, etc.
      </quote>
    </para>
    <para>
      Tracker defines the default graph to be the union of the unnamed graph
      and all known named graphs. Updates without specified graph are still
      performed only on the unnamed graph.
    </para>
  </chapter>

  <chapter id="blank-nodes">
    <title>Blank nodes</title>
    <para>
      The <ulink url="https://www.w3.org/TR/2004/REC-rdf-concepts-20040210/#section-URI-Vocabulary">
      RDF documentation</ulink> says:
    </para>
    <para>
      <quote>
	A blank node is a node that is not a URI reference or a literal. In
	the RDF abstract syntax, a blank node is just a unique node that can
	be used in one or more RDF statements, but has no intrinsic name.
      </quote>
    </para>
    <para>
      Tracker treats blank nodes as an URI generator instead. The string
      referencing a blank node (e.g. as returned by cursors) permanently
      identifies that blank node and can be used as an URI reference in
      future queries.
    </para>
  </chapter>

  <chapter id="property-functions">
    <title>Property functions</title>
    <para>
      The <ulink url="https://www.w3.org/TR/sparql11-query/#expressions">SPARQL
      documentation</ulink> says:
    </para>
    <para>
      <quote>
	In addition, SPARQL provides the ability to invoke arbitrary functions
	[…]. These functions are invoked by name (an IRI) within a SPARQL query.
      </quote>
    </para>
    <para>
      Tracker allows using all defined <systemitem>rdf:Property</systemitem>
      instances as functions. If the property has multiple values, it will
      propagate to the cursor as the <systemitem>GROUP_CONCAT</systemitem>
      (with comma separator) of the multiple values.
    </para>
  </chapter>

  <chapter id="syntax">
    <title>Syntax extensions</title>
    <para>
      Tracker offers some SPARQL syntax extensions. These predate the
      existence of SPARQL 1.1 and stay for legacy reasons. These
      extensions should be used sparingly, if at all.
    </para>
    <sect3 id="syntax-group-concat">
      <para>
	The SPARQL specifications define the following syntax to use
	a specific separator for the GROUP_CONCAT operation:
      </para>
      <programlisting>
GROUP_CONCAT (?var, separator=;)
      </programlisting>
      <para>
	Tracker additionally accepts a simplified syntax:
      </para>
      <programlisting>
GROUP_CONCAT (?u, ';')
      </programlisting>
    </sect3>
    <sect3 id="syntax-bound">
      <para>
	The BOUND function, as defined in the SPARQL specification,
	only accepts variables as its single argument. Tracker additionally
	allows this function to deal with expressions, mainly allowing the
	nesting of other functions, e.g. functional properties:
      </para>
      <programlisting>
SELECT BOUND (nfo:fileName (?u)) { ?u a nfo:FileDataObject }
      </programlisting>
    </sect3>
    <sect3 id="syntax-subselects-in-expressions">
      <para>
	Tracker accepts subselects in place of expressions, these subselects
	should return a single variable in order to act as a expression.
	E.g. this query:
      </para>
      <programlisting>
SELECT (SELECT ?ret { ?u nie:hasPart ?elem }) { ?elem a nfo:Folder }
      </programlisting>
      <para>
	Would be equivalent to this:
      </para>
      <programlisting>
SELECT nie:hasPart(?elem) { ?elem a nfo:Folder }
      </programlisting>
    </sect3>
    <sect3 id="syntax-insert-delete-silent">
      <para>
	Tracker allows the use of SILENT after INSERT and DELETE
	keywords. Errors will be consequently silenced.
      </para>
    </sect3>
    <sect3 id="syntax-insert-or-replace">
      <para>
	Tracker adds a special <systemitem>INSERT OR REPLACE</systemitem>
	operation. This form of update will overwrite any existing values.
      </para>
      <programlisting>
INSERT OR REPLACE { &lt;file:///&gt; nfo:fileName 'root' }
      </programlisting>
      <para>
	This operation works the same independently of the cardinality,
	multi-valued properties are cleared before the insertion.
      </para>
      <para>
	If clearing a property is desired within the operation, the
	value list may also contain the NULL keyword, e.g.:
      </para>
      <programlisting>
INSERT OR REPLACE { &lt;file:///&gt; nie:hasPart &lt;a&gt;, &lt;b&gt;, NULL, &lt;c&gt; }
      </programlisting>
      <para>
	Note that the
	<systemitem>DELETE { … } INSERT { … } WHERE { … }</systemitem>
	syntax available in SPARQL 1.1 is a more versatile replacement.
      </para>
    </sect3>
    <sect3 id="syntax-order-by-expressions">
      <para>
	Tracker allows the use of expressions in
	<systemitem>ORDER BY</systemitem> clauses, e.g.:
      </para>
      <programlisting>
SELECT { … } ORDER BY (?a - ?b)
      </programlisting>
    </sect3>
    <sect3 id="syntax-select-expressions">
      <para>
	The SPARQL 1.1 specifications enforce that all expressions
	returned in a <systemitem>SELECT</systemitem> clause are set
	a variable name, e.g.:
      </para>
      <programlisting>
SELECT ((?a - ?b) AS ?sub) { … }
      </programlisting>
      <para>
	Tracker relaxes this restriction, and does not enforce that
	expressions are surrounded by parentheses, e.g.:
      </para>
      <programlisting>
SELECT ?a + ?b ?a - ?b AS ?sub { … }
      </programlisting>
      <para>
	Note that this hinders query readability (e.g. the example above
	returns 2 values, an unnamed sum expression, and a named subtraction),
	so its use is not recommended.
      </para>
    </sect3>
    <sect3 id="syntax-update-separator">
      <para>
	Tracker makes the use of the <systemitem>;</systemitem> separator
	between update clauses optional. Its use is still recommended for
	readability.
      </para>
    </sect3>
    <sect3 id="syntax-constraint">
      <para>
	Tracker supports <systemitem>CONSTRAINT GRAPH</systemitem> and
	<systemitem>CONSTRAINT SERVICE</systemitem> clauses in the query
	prologue. These clauses limit the access outside of the specified
	graphs and services.
      </para>
      <programlisting>
# Only triples in the tracker:Audio graph will be returned
CONSTRAINT GRAPH tracker:Audio
SELECT * { ?s ?p ?o }
      </programlisting>
      <para>
	If a graph is specified within the query, but not allowed by a
	<systemitem>CONSTRAINT GRAPH</systemitem> clause, it will be
	effectively interpreted as an empty graph.
      </para>
      <para>
	If a service is accessed within the query, but not allowed by a
	<systemitem>CONSTRAINT SERVICE</systemitem> clause, it will be
	interpreted as an error, unless
	<systemitem>SERVICE SILENT</systemitem> syntax is used. In that
	case it will be interpreted as an empty graph.
      </para>
      <para>
	The <systemitem>CONSTRAINT</systemitem> clauses cannot be
	contradicted, multiple <systemitem>CONSTRAINT</systemitem> clauses
	effectively intersect the set of allowed graphs/services with
	previous clauses.
      </para>
      <programlisting>
CONSTRAINT GRAPH tracker:Video, tracker:Audio
CONSTRAINT GRAPH tracker:Video
# Only tracker:Video graph can be accessed
SELECT * { ?s ?p ?o }
      </programlisting>
      <programlisting>
CONSTRAINT GRAPH tracker:Video
CONSTRAINT GRAPH tracker:Video, tracker:Audio
# Only tracker:Video graph can be accessed
SELECT * { ?s ?p ?o }
      </programlisting>
      <para>
	Disjoint sets result in an empty set of accessible graphs and services.
      </para>
      <programlisting>
CONSTRAINT GRAPH tracker:Video
CONSTRAINT GRAPH tracker:Audio
# There are no accessible graphs, this query returns no results
SELECT * { ?s ?p ?o }
      </programlisting>
    </sect3>
  </chapter>

  <chapter id="ids-and-iris">
    <title>Mapping IDs and IRIs</title>
    <para>
      Tracker provides the <systemitem>tracker:id</systemitem> and
      <systemitem>tracker:uri</systemitem> SPARQL functions, that allow
      converting an URI reference to a numeric identifier, and back.
    </para>
    <para>
      These identifiers are expected to be valid a long as the URI is
      referenced in the store. The existence of these SPARQL functions
      mostly obey legacy reasons and its use is not recommended.
    </para>
  </chapter>

  <chapter id="parameters">
    <title>Parameters and prepared statements</title>
    <para>
      Tracker accepts “~” prefixed variables in place of literals
      throughout most of the SPARQL select syntax. These variables
      are treated as parameters at query time, so it is possible
      to prepare a query statement once and reuse it many times
      assigning different values to those parameters at query time.
    </para>
    <para>
      See the <link linkend="TrackerSparqlStatement">TrackerSparqlStatement</link>
      documentation for more information.
    </para>
  </chapter>

  <chapter id="full-text-search">
    <title>Full-text search</title>
    <para>
      Tracker provides full-text search capabilities, these are exposed
      as a <systemitem>fts:match</systemitem> pseudo-property that will
      match the resources matching the given text string.
    </para>
    <para>
      To complement this pseudo property, Tracker provides the
      <systemitem>fts:snippet</systemitem>, <systemitem>fts:offsets</systemitem>
      and <systemitem>fts:rank</systemitem> SPARQL functions that can be used
      on the matches.
    </para>
    <para>
      The ontology needs to define the properties that are matched via
      this full-text search mechanism, by toggling the
      <systemitem>tracker:fulltextIndexed</systemitem> property on in the
      text <systemitem>rdf:Property</systemitem> instances. See the documentation
      on <link linkend="tracker-ontologies">defining ontologies</link>.
    </para>
  </chapter>
</part>
