summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2021-01-26 10:07:32 +0100
committerCarlos Garnacho <carlosg@gnome.org>2021-01-26 10:46:36 +0100
commit9c84dce97b085949dc895b60d3fdc9419eb45edf (patch)
treec2388f176e20112ba549e6cb823da808c86096ad
parent1d9aa84c2f999e07fd8e975939e2bfc30e48da86 (diff)
downloadtracker-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.c17
-rw-r--r--src/libtracker-data/tracker-vtab-service.c7
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: