[tracker/sam/tracker-resource-delete-nested-resources: 1/3] libtracker-sparql: Generate DELETEs for relations inside arrays



commit 981fcbc79b77bca6a8c01c6a1e5cc55b130dc995
Author: Sam Thursfield <sam afuera me uk>
Date:   Wed Oct 2 23:56:34 2019 +0200

    libtracker-sparql: Generate DELETEs for relations inside arrays
    
    When a TrackerResource is serialized to SPARQL, we generate a series of
    DELETE {} INSERT {} statements. For every single-value properties whose
    value we set, we need to delete its value first. (Otherwise we might see
    "Unable to insert multiple values" errors).
    
    The tracker_resource_print_sparql() function was not generating the
    DELETE statements for relations if there were multiple relations for
    a single property.
    
    This indirectly led to https://gitlab.gnome.org/GNOME/tracker/issues/154
    and https://gitlab.gnome.org/GNOME/tracker/issues/121

 src/libtracker-sparql/tracker-resource.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)
---
diff --git a/src/libtracker-sparql/tracker-resource.c b/src/libtracker-sparql/tracker-resource.c
index 059289b78..8f69be646 100644
--- a/src/libtracker-sparql/tracker-resource.c
+++ b/src/libtracker-sparql/tracker-resource.c
@@ -1308,13 +1308,23 @@ generate_sparql_relation_deletes_foreach (gpointer key,
 {
        const GValue *value = value_ptr;
        GenerateSparqlData *data = user_data;
+       int i;
 
        if (G_VALUE_HOLDS (value, TRACKER_TYPE_RESOURCE)) {
                TrackerResource *relation = g_value_get_object (value);
 
-               if (g_list_find_custom (data->done_list, relation, (GCompareFunc) tracker_resource_compare) 
== NULL) {
-                       data->done_list = g_list_prepend (data->done_list, relation);
-                       generate_sparql_deletes (relation, data);
+               generate_sparql_deletes (relation, data);
+       } else if (G_VALUE_HOLDS (value, G_TYPE_PTR_ARRAY)) {
+               GPtrArray *array = g_value_get_boxed (value);
+
+               for (i = 0; i < array->len; i ++) {
+                       GValue *value = g_ptr_array_index (array, i);
+
+                       if (G_VALUE_HOLDS (value, TRACKER_TYPE_RESOURCE)) {
+                               TrackerResource *relation = g_value_get_object (value);
+
+                               generate_sparql_deletes (relation, data);
+                       }
                }
        }
 }
@@ -1419,6 +1429,12 @@ generate_sparql_deletes (TrackerResource    *resource,
 {
        TrackerResourcePrivate *priv = GET_PRIVATE (resource);
 
+       if (g_list_find_custom (data->done_list, resource, (GCompareFunc) tracker_resource_compare) != NULL)
+               /* We already processed this resource. */
+               return;
+
+       data->done_list = g_list_prepend (data->done_list, resource);
+
        if (! is_blank_node (priv->identifier) && g_hash_table_size (priv->overwrite) > 0) {
                generate_sparql_delete_queries (resource, priv->overwrite, data);
        }
@@ -1520,7 +1536,7 @@ tracker_resource_print_sparql_update (TrackerResource         *resource,
        /* Resources can be recursive, and may have repeated or even cyclic
         * relationships. This list keeps track of what we already processed.
         */
-       context.done_list = g_list_prepend (NULL, resource);
+       context.done_list = NULL;
 
        /* Delete the existing data. If we don't do this, we may get constraint
         * violations due to trying to add a second value to a single-valued


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