From 29d3bab2ef1d826c29bc5b54e9558a5521bf6bcd Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 8 Nov 2018 12:40:36 +0100 Subject: [PATCH] libtracker-data: Drop FTS table/view before ontology updates Sqlite >= 3.25.0 got stricter 'alter table ... rename ...' behavior where the renaming affects all references to the table across the database. This is at odds with our fts_view view on schema updates due to ontology changes, as we first migrate (rename current table, create new one, insert previous content, drop old table) all resource tables before doing the FTS table/view updates. This causes rename failures due to the fts_view referencing the renamed and dropped tables. Change the ontology update code so we delete the FTS table/view before changing resource tables in case of FTS updates. This makes the behavior correct both before and after the Sqlite change. https://gitlab.gnome.org/GNOME/tracker/issues/40 --- src/libtracker-data/tracker-data-manager.c | 105 +++++++++++++----- .../tracker-db-interface-sqlite.c | 8 ++ .../tracker-db-interface-sqlite.h | 2 + src/libtracker-fts/tracker-fts.c | 32 ++++-- src/libtracker-fts/tracker-fts.h | 2 + 5 files changed, 107 insertions(+), 42 deletions(-) Index: tracker-2.1.6/src/libtracker-data/tracker-data-manager.c =================================================================== --- tracker-2.1.6.orig/src/libtracker-data/tracker-data-manager.c +++ tracker-2.1.6/src/libtracker-data/tracker-data-manager.c @@ -135,6 +135,12 @@ enum { N_PROPS }; +#if HAVE_TRACKER_FTS +static gboolean tracker_data_manager_fts_changed (TrackerDataManager *manager); +static void tracker_data_manager_update_fts (TrackerDataManager *manager, + TrackerDBInterface *iface); +#endif + static void tracker_data_manager_initable_iface_init (GInitableIface *iface); G_DEFINE_TYPE_WITH_CODE (TrackerDataManager, tracker_data_manager, G_TYPE_OBJECT, @@ -3681,6 +3687,9 @@ tracker_data_ontology_import_into_db (Tr TrackerProperty **properties; guint i, n_props, n_classes; gboolean base_tables_altered = FALSE; +#if HAVE_TRACKER_FTS + gboolean update_fts = FALSE; +#endif iface = tracker_db_manager_get_writable_db_interface (manager->db_manager); @@ -3691,6 +3700,15 @@ tracker_data_ontology_import_into_db (Tr return; } +#if HAVE_TRACKER_FTS + if (base_tables_altered || in_update) { + update_fts = base_tables_altered | tracker_data_manager_fts_changed (manager); + + if (update_fts) + tracker_db_interface_sqlite_fts_delete_table (iface); + } +#endif + /* create tables */ for (i = 0; i < n_classes; i++) { GError *internal_error = NULL; @@ -3740,6 +3758,14 @@ tracker_data_ontology_import_into_db (Tr } } } + +#if HAVE_TRACKER_FTS + if (update_fts) { + tracker_data_manager_update_fts (manager, iface); + } else { + tracker_data_manager_init_fts (iface, !in_update); + } +#endif } static gint @@ -3942,13 +3968,44 @@ load_ontologies_gvdb (TrackerDataManager #if HAVE_TRACKER_FTS static gboolean +tracker_data_manager_fts_changed (TrackerDataManager *manager) +{ + TrackerProperty **properties; + gboolean has_changed = FALSE; + guint i, len; + + properties = tracker_ontologies_get_properties (manager->ontologies, &len); + + for (i = 0; i < len; i++) { + TrackerClass *class; + + if (tracker_property_get_fulltext_indexed (properties[i]) != + tracker_property_get_orig_fulltext_indexed (properties[i])) { + has_changed |= TRUE; + } + + if (!tracker_property_get_fulltext_indexed (properties[i])) { + continue; + } + + has_changed |= tracker_property_get_is_new (properties[i]); + + /* We must also regenerate FTS if any table in the view + * updated its schema. + */ + class = tracker_property_get_domain (properties[i]); + has_changed |= tracker_class_get_db_schema_changed (class); + } + + return has_changed; +} + +static void ontology_get_fts_properties (TrackerDataManager *manager, - gboolean only_new, GHashTable **fts_properties, GHashTable **multivalued) { TrackerProperty **properties; - gboolean has_changed = FALSE; guint i, len; properties = tracker_ontologies_get_properties (manager->ontologies, &len); @@ -3960,16 +4017,10 @@ ontology_get_fts_properties (TrackerData const gchar *name, *table_name; GList *list; - if (tracker_property_get_fulltext_indexed (properties[i]) != - tracker_property_get_orig_fulltext_indexed (properties[i])) { - has_changed |= TRUE; - } - if (!tracker_property_get_fulltext_indexed (properties[i])) { continue; } - has_changed |= tracker_property_get_is_new (properties[i]); table_name = tracker_property_get_table_name (properties[i]); name = tracker_property_get_name (properties[i]); list = g_hash_table_lookup (*fts_properties, table_name); @@ -3986,8 +4037,6 @@ ontology_get_fts_properties (TrackerData list = g_list_append (list, (gpointer) name); } } - - return has_changed; } static void @@ -4001,29 +4050,36 @@ rebuild_fts_tokens (TrackerDataManager * /* Update the stamp file */ tracker_db_manager_tokenizer_update (manager->db_manager); } -#endif gboolean tracker_data_manager_init_fts (TrackerDBInterface *iface, gboolean create) { -#if HAVE_TRACKER_FTS GHashTable *fts_props, *multivalued; TrackerDataManager *manager; manager = tracker_db_interface_get_user_data (iface); - ontology_get_fts_properties (manager, FALSE, &fts_props, &multivalued); + ontology_get_fts_properties (manager, &fts_props, &multivalued); tracker_db_interface_sqlite_fts_init (iface, fts_props, multivalued, create); g_hash_table_unref (fts_props); g_hash_table_unref (multivalued); return TRUE; -#else - g_info ("FTS support is disabled"); - return FALSE; -#endif } +static void +tracker_data_manager_update_fts (TrackerDataManager *manager, + TrackerDBInterface *iface) +{ + GHashTable *fts_properties, *multivalued; + + ontology_get_fts_properties (manager, &fts_properties, &multivalued); + tracker_db_interface_sqlite_fts_alter_table (iface, fts_properties, multivalued); + g_hash_table_unref (fts_properties); + g_hash_table_unref (multivalued); +} +#endif + GFile * tracker_data_manager_get_cache_location (TrackerDataManager *manager) { @@ -4279,8 +4335,6 @@ tracker_data_manager_initable_init (GIni tracker_data_ontology_import_into_db (manager, FALSE, &internal_error); - tracker_data_manager_init_fts (iface, TRUE); - if (internal_error) { g_propagate_error (error, internal_error); return FALSE; @@ -4371,7 +4425,9 @@ tracker_data_manager_initable_init (GIni } } +#if HAVE_TRACKER_FTS tracker_data_manager_init_fts (iface, FALSE); +#endif } if (!read_only) { @@ -4630,17 +4686,6 @@ tracker_data_manager_initable_init (GIni } if (update_nao) { -#if HAVE_TRACKER_FTS - GHashTable *fts_properties, *multivalued; - - if (ontology_get_fts_properties (manager, TRUE, &fts_properties, &multivalued)) { - tracker_db_interface_sqlite_fts_alter_table (iface, fts_properties, multivalued); - } - - g_hash_table_unref (fts_properties); - g_hash_table_unref (multivalued); -#endif - update_ontology_last_modified (manager, iface, ontology, &n_error); if (n_error) { Index: tracker-2.1.6/src/libtracker-data/tracker-db-interface-sqlite.c =================================================================== --- tracker-2.1.6.orig/src/libtracker-data/tracker-db-interface-sqlite.c +++ tracker-2.1.6/src/libtracker-data/tracker-db-interface-sqlite.c @@ -1648,6 +1648,14 @@ tracker_db_interface_sqlite_fts_init (Tr #if HAVE_TRACKER_FTS void +tracker_db_interface_sqlite_fts_delete_table (TrackerDBInterface *db_interface) +{ + if (!tracker_fts_delete_table (db_interface->db, "fts5")) { + g_critical ("Failed to delete FTS table"); + } +} + +void tracker_db_interface_sqlite_fts_alter_table (TrackerDBInterface *db_interface, GHashTable *properties, GHashTable *multivalued) Index: tracker-2.1.6/src/libtracker-data/tracker-db-interface-sqlite.h =================================================================== --- tracker-2.1.6.orig/src/libtracker-data/tracker-db-interface-sqlite.h +++ tracker-2.1.6/src/libtracker-data/tracker-db-interface-sqlite.h @@ -59,6 +59,8 @@ gboolean tracker_db_interface #if HAVE_TRACKER_FTS +void tracker_db_interface_sqlite_fts_delete_table (TrackerDBInterface *interface); + void tracker_db_interface_sqlite_fts_alter_table (TrackerDBInterface *interface, GHashTable *properties, GHashTable *multivalued); Index: tracker-2.1.6/src/libtracker-fts/tracker-fts.c =================================================================== --- tracker-2.1.6.orig/src/libtracker-fts/tracker-fts.c +++ tracker-2.1.6/src/libtracker-fts/tracker-fts.c @@ -158,6 +158,26 @@ tracker_fts_create_table (sqlite3 *db } gboolean +tracker_fts_delete_table (sqlite3 *db, + gchar *table_name) +{ + gchar *query; + int rc; + + query = g_strdup_printf ("DROP VIEW fts_view"); + rc = sqlite3_exec (db, query, NULL, NULL, NULL); + g_free (query); + + if (rc == SQLITE_OK) { + query = g_strdup_printf ("DROP TABLE %s", table_name); + sqlite3_exec (db, query, NULL, NULL, NULL); + g_free (query); + } + + return rc == SQLITE_OK; +} + +gboolean tracker_fts_alter_table (sqlite3 *db, gchar *table_name, GHashTable *tables, @@ -168,18 +188,6 @@ tracker_fts_alter_table (sqlite3 *db, tmp_name = g_strdup_printf ("%s_TMP", table_name); - query = g_strdup_printf ("DROP VIEW fts_view"); - rc = sqlite3_exec (db, query, NULL, NULL, NULL); - g_free (query); - - query = g_strdup_printf ("DROP TABLE %s", tmp_name); - rc = sqlite3_exec (db, query, NULL, NULL, NULL); - g_free (query); - - query = g_strdup_printf ("DROP TABLE %s", table_name); - rc = sqlite3_exec (db, query, NULL, NULL, NULL); - g_free (query); - if (!tracker_fts_create_table (db, tmp_name, tables, grouped_columns)) { g_free (tmp_name); return FALSE; Index: tracker-2.1.6/src/libtracker-fts/tracker-fts.h =================================================================== --- tracker-2.1.6.orig/src/libtracker-fts/tracker-fts.h +++ tracker-2.1.6/src/libtracker-fts/tracker-fts.h @@ -36,6 +36,8 @@ gboolean tracker_fts_create_table gchar *table_name, GHashTable *tables, GHashTable *grouped_columns); +gboolean tracker_fts_delete_table (sqlite3 *db, + gchar *table_name); gboolean tracker_fts_alter_table (sqlite3 *db, gchar *table_name, GHashTable *tables, Index: tracker-2.1.6/src/libtracker-data/tracker-property.c =================================================================== --- tracker-2.1.6.orig/src/libtracker-data/tracker-property.c +++ tracker-2.1.6/src/libtracker-data/tracker-property.c @@ -1050,6 +1050,7 @@ tracker_property_set_multiple_values (Tr priv = GET_PRIV (property); priv->multiple_values = value; + g_clear_pointer (&priv->table_name, g_free); } void