summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2021-02-26 20:29:50 +0100
committerCarlos Garnacho <carlosg@gnome.org>2021-02-26 21:07:37 +0100
commit86b0b7258e731a2ade2033b2e57400cd1ed8e750 (patch)
tree9cb1e41b42f198fff0e2942374f614cd6aabaf50
parent79cfcfd5b9e51e670cad13197ce5b16ff8d71469 (diff)
downloadtracker-86b0b7258e731a2ade2033b2e57400cd1ed8e750.tar.gz
libtracker-data: Handle unbound variables in GraphGraphPattern
We currently don't handle correctly the situation of GRAPH ?g { ... } clauses in SELECTs that leave ?g unbound. E.g. situations that the contained GroupGraphPattern does not contain anything that actually requires accessing graphs: SELECT ?g { GRAPH ?g { } } SELECT ?g ?a { GRAPH ?g { BIND (1 AS ?a) } } Check for this specific situation, and union the contained query with a query for all available named graphs. This makes these queries behave as expected (e.g. bind ?g to all available graphs, because the empty pattern { } matches everything).
-rw-r--r--src/libtracker-data/tracker-sparql.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index 6278978ab..a32b4960e 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -790,6 +790,49 @@ tracker_sparql_add_union_graph_subquery_for_class (TrackerSparql *sparql,
tracker_sparql_swap_builder (sparql, old);
}
+static void
+tracker_sparql_add_union_graph_subquery_for_named_graphs (TrackerSparql *sparql)
+{
+ TrackerStringBuilder *old;
+ gpointer graph_id;
+ GHashTable *graphs;
+ GHashTableIter iter;
+ gboolean first = TRUE;
+
+ if (g_hash_table_lookup (sparql->current_state->union_views, "graphs"))
+ return;
+
+ g_hash_table_add (sparql->current_state->union_views, g_strdup ("graphs"));
+ old = tracker_sparql_swap_builder (sparql, sparql->current_state->with_clauses);
+
+ if (tracker_string_builder_is_empty (sparql->current_state->with_clauses))
+ _append_string (sparql, "WITH ");
+ else
+ _append_string (sparql, ", ");
+
+ graphs = tracker_sparql_get_effective_graphs (sparql);
+
+ _append_string (sparql, "\"unionGraph_graphs\"(graph) AS (");
+
+ g_hash_table_iter_init (&iter, graphs);
+ while (g_hash_table_iter_next (&iter, NULL, &graph_id)) {
+ if (first)
+ _append_string (sparql, "VALUES ");
+ else
+ _append_string (sparql, ", ");
+
+ _append_string_printf (sparql, "(%d) ", GPOINTER_TO_INT (graph_id));
+ first = FALSE;
+ }
+
+ if (g_hash_table_size (graphs) == 0)
+ _append_string (sparql, "SELECT NULL WHERE FALSE");
+
+ _append_string (sparql, ") ");
+
+ tracker_sparql_swap_builder (sparql, old);
+}
+
static gint
tracker_sparql_find_graph (TrackerSparql *sparql,
const gchar *name)
@@ -5049,7 +5092,9 @@ static gboolean
translate_GraphGraphPattern (TrackerSparql *sparql,
GError **error)
{
+ TrackerStringBuilder *str, *old;
TrackerToken old_graph;
+ TrackerVariable *graph_var;
gboolean do_join;
/* GraphGraphPattern ::= 'GRAPH' VarOrIri GroupGraphPattern
@@ -5066,10 +5111,37 @@ translate_GraphGraphPattern (TrackerSparql *sparql,
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_GRAPH);
_call_rule (sparql, NAMED_RULE_VarOrIri, error);
+ graph_var = _last_node_variable (sparql);
_init_token (&sparql->current_state->graph,
sparql->current_state->prev_node, sparql);
+
+ str = _append_placeholder (sparql);
+
_call_rule (sparql, NAMED_RULE_GroupGraphPattern, error);
+ if (graph_var && !tracker_variable_has_bindings (graph_var)) {
+ TrackerBinding *binding;
+
+ tracker_sparql_add_union_graph_subquery_for_named_graphs (sparql);
+
+ old = tracker_sparql_swap_builder (sparql, str);
+ _append_string_printf (sparql,
+ "SELECT * FROM ( "
+ "SELECT graph AS %s FROM \"unionGraph_graphs\"),"
+ " (",
+ tracker_variable_get_sql_expression (graph_var));
+
+ tracker_sparql_swap_builder (sparql, old);
+ _append_string (sparql, ") ");
+
+ binding = tracker_variable_binding_new (graph_var, NULL, NULL);
+ tracker_binding_set_data_type (TRACKER_BINDING (binding),
+ TRACKER_PROPERTY_TYPE_RESOURCE);
+ tracker_variable_set_sample_binding (graph_var,
+ TRACKER_VARIABLE_BINDING (binding));
+ g_object_unref (binding);
+ }
+
tracker_token_unset (&sparql->current_state->graph);
sparql->current_state->graph = old_graph;