From 86b0b7258e731a2ade2033b2e57400cd1ed8e750 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 26 Feb 2021 20:29:50 +0100 Subject: 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). --- src/libtracker-data/tracker-sparql.c | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) 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; -- cgit v1.2.1