summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2021-07-13 12:23:40 +0200
committerCarlos Garnacho <carlosg@gnome.org>2021-07-13 12:36:28 +0200
commit0f2b8b66f820da677f1cdb73ad1bf44b90246f4c (patch)
tree9d2bdae41abba4a6fb806c4ec96598c68d81cf37
parentf25c376433da1c9bfa8f869ea7d35ea46ca5f57c (diff)
downloadtracker-0f2b8b66f820da677f1cdb73ad1bf44b90246f4c.tar.gz
libtracker-data: Check for already visited properties during flush
Due to TrackerResource insertion trying to avoid too frequent flushing, we might end up with a single batch containing multiple single-valued property delete+insert changes for the same resource/property. These currently fail with "multiple values for single-valued property" errors but that will be fixed in a followup commit. If these got through, we would want to avoid telling SQLite about these properties several times, e.g.: INSERT OR REPLACE INTO ... (ID, "nfo:fileSize", "nfo:fileSize") Since what happens then is unspecified (SQLite chooses to honor the first value and ignore the second). To fix this, check the already visited properties when generating the INSERT/UPDATE statement for single-valued properties in a class table, and ensure we stick to the last given value. This avoids having to prematurely flush just to keep these two changes separate, and coalesces things the right way (i.e. we end up with the good, last value).
-rw-r--r--src/libtracker-data/tracker-data-update.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index cbd2fc46a..2103271b0 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -874,6 +874,8 @@ tracker_data_resource_buffer_flush (TrackerData *data,
}
} else {
GString *sql, *values_sql;
+ GHashTable *visited_properties;
+ gint n;
if (table->delete_row) {
/* remove row from class table */
@@ -917,19 +919,28 @@ tracker_data_resource_buffer_flush (TrackerData *data,
g_string_append (sql, " SET ");
}
- for (i = 0; i < table->properties->len; i++) {
- property = &g_array_index (table->properties, TrackerDataUpdateBufferProperty, i);
+ visited_properties = g_hash_table_new (g_str_hash, g_str_equal);
+
+ for (n = table->properties->len - 1; n >= 0; n--) {
+ property = &g_array_index (table->properties, TrackerDataUpdateBufferProperty, n);
+ if (g_hash_table_contains (visited_properties, property->name))
+ continue;
+
if (table->insert) {
g_string_append_printf (sql, ", \"%s\"", property->name);
g_string_append (values_sql, ", ?");
} else {
- if (i > 0) {
+ if (n < (int) table->properties->len - 1) {
g_string_append (sql, ", ");
}
g_string_append_printf (sql, "\"%s\" = ?", property->name);
}
+
+ g_hash_table_add (visited_properties, (gpointer) property->name);
}
+ g_hash_table_unref (visited_properties);
+
if (table->insert) {
g_string_append (sql, ")");
g_string_append (values_sql, ")");
@@ -966,16 +977,25 @@ tracker_data_resource_buffer_flush (TrackerData *data,
param = 0;
}
- for (i = 0; i < table->properties->len; i++) {
- property = &g_array_index (table->properties, TrackerDataUpdateBufferProperty, i);
+ visited_properties = g_hash_table_new (g_str_hash, g_str_equal);
+
+ for (n = table->properties->len - 1; n >= 0; n--) {
+ property = &g_array_index (table->properties, TrackerDataUpdateBufferProperty, n);
+ if (g_hash_table_contains (visited_properties, property->name))
+ continue;
+
if (property->delete_value) {
/* just set value to NULL for single value properties */
tracker_db_statement_bind_null (stmt, param++);
} else {
statement_bind_gvalue (stmt, &param, &property->value);
}
+
+ g_hash_table_add (visited_properties, (gpointer) property->name);
}
+ g_hash_table_unref (visited_properties);
+
if (!table->insert) {
tracker_db_statement_bind_int (stmt, param++, resource->id);
}