[tracker/wip/carlosg/sparql-corners: 3/12] libtracker-data: Handle unbound variables in GraphGraphPattern




commit 86b0b7258e731a2ade2033b2e57400cd1ed8e750
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Feb 26 20:29:50 2021 +0100

    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;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]