diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2021-01-26 10:07:32 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2021-01-26 10:46:36 +0100 |
commit | 9c84dce97b085949dc895b60d3fdc9419eb45edf (patch) | |
tree | c2388f176e20112ba549e6cb823da808c86096ad | |
parent | 1d9aa84c2f999e07fd8e975939e2bfc30e48da86 (diff) | |
download | tracker-9c84dce97b085949dc895b60d3fdc9419eb45edf.tar.gz |
libtracker-data: Handle variables for SERVICE clauses correctly
The sparql1.1 spec allows the use of variables in SERVICE clauses,
e.g.:
... SERVICE ?s { ... } ...
Where ?s is a variable resolved in other parts of the graph pattern.
https://www.w3.org/TR/2013/REC-sparql11-federated-query-20130321/#variableService
precisely advocates that query execution order should resolve the
possible values for the queried services before attempting to access
those.
Let Tracker do this somersault, if the service is a variable instead
of a literal propagate it up as a variable in the subselect so it is
matched together with all other variables when JOINed with the other
bits of the graph pattern, and let the services virtual table enforce
the execution order that resolves the service variable by returning
SQLITE_CONSTRAINT if the service column is missing. This makes SQLite
try the alternative execution orders, and eventually find one that
resolves the service variable when executing the remote service(s).
This allows delegating service queries to a variable, which may be
useful if e.g. we want to propagate a same query to multiple services:
SELECT ?u {
SERVICE ?s {
?u a nfo:Document
}
}
VALUES ?s { 'dbus:...', 'dbus:...' }
-rw-r--r-- | src/libtracker-data/tracker-sparql.c | 17 | ||||
-rw-r--r-- | src/libtracker-data/tracker-vtab-service.c | 7 |
2 files changed, 22 insertions, 2 deletions
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c index 2a3e8c17b..9b0f5701f 100644 --- a/src/libtracker-data/tracker-sparql.c +++ b/src/libtracker-data/tracker-sparql.c @@ -5214,6 +5214,15 @@ translate_ServiceGraphPattern (TrackerSparql *sparql, i++; } + if (tracker_token_get_variable (&service)) { + if (variable_rules != NULL) + _append_string (sparql, ", "); + + _append_string_printf (sparql, "service AS %s ", + tracker_token_get_idstring (&service)); + join_vars = g_list_prepend (join_vars, tracker_token_get_variable (&service)); + } + tracker_parser_node_get_extents (pattern, &pattern_start, &pattern_end); pattern_str = g_strndup (&sparql->sparql[pattern_start], pattern_end - pattern_start); escaped_str = _escape_sql_string (pattern_str, '"'); @@ -5222,11 +5231,15 @@ translate_ServiceGraphPattern (TrackerSparql *sparql, g_free (pattern_str); g_free (escaped_str); - _append_string_printf (sparql, "FROM tracker_service WHERE service=\"%s\" AND query=\"%s\" AND silent=%d ", - tracker_token_get_idstring (&service), + _append_string_printf (sparql, "FROM tracker_service WHERE query=\"%s\" AND silent=%d ", service_sparql->str, silent); + if (!tracker_token_get_variable (&service)) { + _append_string_printf (sparql, "AND service=\"%s\" ", + tracker_token_get_idstring (&service)); + } + i = 0; /* Proxy parameters to the virtual table */ diff --git a/src/libtracker-data/tracker-vtab-service.c b/src/libtracker-data/tracker-vtab-service.c index a14d50509..628ecada1 100644 --- a/src/libtracker-data/tracker-vtab-service.c +++ b/src/libtracker-data/tracker-vtab-service.c @@ -158,6 +158,7 @@ service_best_index (sqlite3_vtab *vtab, { int i, argv_idx = 1; ConstraintData *data; + gboolean has_service = FALSE; data = sqlite3_malloc (sizeof (ConstraintData) * info->nConstraint); bzero (data, sizeof (ConstraintData) * info->nConstraint); @@ -174,6 +175,9 @@ service_best_index (sqlite3_vtab *vtab, if (info->aConstraint[i].op != SQLITE_INDEX_CONSTRAINT_EQ) goto error; + if (info->aConstraint[i].iColumn == COL_SERVICE) + has_service = TRUE; + data[i].column = info->aConstraint[i].iColumn; data[i].op = info->aConstraint[i].op; @@ -186,6 +190,9 @@ service_best_index (sqlite3_vtab *vtab, info->idxStr = (char *) data; info->needToFreeIdxStr = TRUE; + if (!has_service) + return SQLITE_CONSTRAINT; + return SQLITE_OK; error: |