tracker-0.16.2/src/libtracker-data/tracker-data-manager.c

Location Tool Test ID Function Issue
tracker-data-manager.c:2862:2 gcc pointer-sign create_decomposed_metadata_tables pointer targets in passing argument 1 of 'tracker_ontologies_get_properties' differ in signedness
tracker-data-manager.c:3222:2 gcc pointer-sign clean_decomposed_transient_metadata pointer targets in passing argument 1 of 'tracker_ontologies_get_properties' differ in signedness
tracker-data-manager.c:3267:2 gcc pointer-sign tracker_data_ontology_import_finished pointer targets in passing argument 1 of 'tracker_ontologies_get_classes' differ in signedness
tracker-data-manager.c:3294:2 gcc pointer-sign tracker_data_ontology_import_into_db pointer targets in passing argument 1 of 'tracker_ontologies_get_classes' differ in signedness
tracker-data-manager.c:3571:24 gcc maybe-uninitialized ontology_get_fts_properties.isra.1 'table_name' may be used uninitialized in this function

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found tracker-data-manager.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
   1 /*
   2  * Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org>
   3  * Copyright (C) 2007, Jason Kivlighn <jkivlighn@gmail.com>
   4  * Copyright (C) 2007, Creative Commons <http://creativecommons.org>
   5  * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
   6  *
   7  * This library is free software; you can redistribute it and/or
   8  * modify it under the terms of the GNU Lesser General Public
   9  * License as published by the Free Software Foundation; either
  10  * version 2.1 of the License, or (at your option) any later version.
  11  *
  12  * This library is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15  * Lesser General Public License for more details.
  16  *
  17  * You should have received a copy of the GNU Lesser General Public
  18  * License along with this library; if not, write to the
  19  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  20  * Boston, MA  02110-1301, USA.
  21  */
  22 
  23 #include "config.h"
  24 
  25 #include <string.h>
  26 #include <stdlib.h>
  27 #include <fcntl.h>
  28 #include <zlib.h>
  29 #include <inttypes.h>
  30 
  31 #include <glib/gstdio.h>
  32 
  33 #if HAVE_TRACKER_FTS
  34 #include <libtracker-fts/tracker-fts.h>
  35 #endif
  36 
  37 #include <libtracker-common/tracker-locale.h>
  38 
  39 #include "tracker-class.h"
  40 #include "tracker-data-manager.h"
  41 #include "tracker-data-update.h"
  42 #include "tracker-db-interface-sqlite.h"
  43 #include "tracker-db-manager.h"
  44 #include "tracker-db-journal.h"
  45 #include "tracker-namespace.h"
  46 #include "tracker-ontologies.h"
  47 #include "tracker-ontology.h"
  48 #include "tracker-property.h"
  49 #include "tracker-sparql-query.h"
  50 #include "tracker-data-query.h"
  51 
  52 #define XSD_PREFIX TRACKER_XSD_PREFIX
  53 #define RDF_PREFIX TRACKER_RDF_PREFIX
  54 #define RDF_PROPERTY RDF_PREFIX "Property"
  55 #define RDF_TYPE RDF_PREFIX "type"
  56 
  57 #define RDFS_PREFIX TRACKER_RDFS_PREFIX
  58 #define RDFS_CLASS RDFS_PREFIX "Class"
  59 #define RDFS_DOMAIN RDFS_PREFIX "domain"
  60 #define RDFS_RANGE RDFS_PREFIX "range"
  61 #define RDFS_SUB_CLASS_OF RDFS_PREFIX "subClassOf"
  62 #define RDFS_SUB_PROPERTY_OF RDFS_PREFIX "subPropertyOf"
  63 
  64 #define NRL_PREFIX TRACKER_NRL_PREFIX
  65 #define NRL_INVERSE_FUNCTIONAL_PROPERTY TRACKER_NRL_PREFIX "InverseFunctionalProperty"
  66 #define NRL_MAX_CARDINALITY NRL_PREFIX "maxCardinality"
  67 
  68 #define NAO_PREFIX TRACKER_NAO_PREFIX
  69 #define NAO_LAST_MODIFIED NAO_PREFIX "lastModified"
  70 
  71 #define TRACKER_PREFIX TRACKER_TRACKER_PREFIX
  72 
  73 #define ZLIBBUFSIZ 8192
  74 
  75 static gchar    *ontologies_dir;
  76 static gboolean  initialized;
  77 static gboolean  reloading = FALSE;
  78 #ifndef DISABLE_JOURNAL
  79 static gboolean  in_journal_replay;
  80 #endif
  81 
  82 typedef struct {
  83 	const gchar *from;
  84 	const gchar *to;
  85 } Conversion;
  86 
  87 static Conversion allowed_boolean_conversions[] = {
  88 	{ "false", "true" },
  89 	{ "true", "false" },
  90 	{ NULL, NULL }
  91 };
  92 
  93 static Conversion allowed_range_conversions[] = {
  94 	{ XSD_PREFIX "integer", XSD_PREFIX "string" },
  95 	{ XSD_PREFIX "integer", XSD_PREFIX "double" },
  96 	{ XSD_PREFIX "integer", XSD_PREFIX "boolean" },
  97 
  98 	{ XSD_PREFIX "string", XSD_PREFIX "integer" },
  99 	{ XSD_PREFIX "string", XSD_PREFIX "double" },
 100 	{ XSD_PREFIX "string", XSD_PREFIX "boolean" },
 101 
 102 	{ XSD_PREFIX "double", XSD_PREFIX "integer" },
 103 	{ XSD_PREFIX "double", XSD_PREFIX "string" },
 104 	{ XSD_PREFIX "double", XSD_PREFIX "boolean" },
 105 
 106 	{ NULL, NULL }
 107 };
 108 
 109 GQuark
 110 tracker_data_ontology_error_quark (void)
 111 {
 112 	return g_quark_from_static_string ("tracker-data-ontology-error-quark");
 113 }
 114 
 115 static void
 116 handle_unsupported_ontology_change (const gchar  *ontology_path,
 117                                     const gchar  *subject,
 118                                     const gchar  *change,
 119                                     const gchar  *old,
 120                                     const gchar  *attempted_new,
 121                                     GError      **error)
 122 {
 123 #ifndef DISABLE_JOURNAL
 124 	/* force reindex on restart */
 125 	tracker_db_manager_remove_version_file ();
 126 #endif /* DISABLE_JOURNAL */
 127 
 128 	g_set_error (error, TRACKER_DATA_ONTOLOGY_ERROR,
 129 	             TRACKER_DATA_UNSUPPORTED_ONTOLOGY_CHANGE,
 130 	             "%s: Unsupported ontology change for %s: can't change %s (old=%s, attempted new=%s)",
 131 	             ontology_path != NULL ? ontology_path : "Unknown",
 132 	             subject != NULL ? subject : "Unknown",
 133 	             change != NULL ? change : "Unknown",
 134 	             old != NULL ? old : "Unknown",
 135 	             attempted_new != NULL ? attempted_new : "Uknown");
 136 }
 137 
 138 static void
 139 set_secondary_index_for_single_value_property (TrackerDBInterface  *iface,
 140                                                const gchar         *service_name,
 141                                                const gchar         *field_name,
 142                                                const gchar         *second_field_name,
 143                                                gboolean             enabled,
 144                                                GError             **error)
 145 {
 146 	GError *internal_error = NULL;
 147 
 148 	g_debug ("Dropping secondary index (single-value property):  "
 149 	         "DROP INDEX IF EXISTS \"%s_%s\"",
 150 	         service_name, field_name);
 151 
 152 	tracker_db_interface_execute_query (iface, &internal_error,
 153 	                                    "DROP INDEX IF EXISTS \"%s_%s\"",
 154 	                                    service_name,
 155 	                                    field_name);
 156 
 157 	if (internal_error) {
 158 		g_propagate_error (error, internal_error);
 159 		return;
 160 	}
 161 
 162 	if (enabled) {
 163 		g_debug ("Creating secondary index (single-value property): "
 164 		         "CREATE INDEX \"%s_%s\" ON \"%s\" (\"%s\", \"%s\")",
 165 		         service_name, field_name, service_name, field_name, second_field_name);
 166 
 167 		tracker_db_interface_execute_query (iface, &internal_error,
 168 		                                    "CREATE INDEX \"%s_%s\" ON \"%s\" (\"%s\", \"%s\")",
 169 		                                    service_name,
 170 		                                    field_name,
 171 		                                    service_name,
 172 		                                    field_name,
 173 		                                    second_field_name);
 174 
 175 		if (internal_error) {
 176 			g_propagate_error (error, internal_error);
 177 		}
 178 	}
 179 }
 180 
 181 static void
 182 set_index_for_single_value_property (TrackerDBInterface  *iface,
 183                                      const gchar         *service_name,
 184                                      const gchar         *field_name,
 185                                      gboolean             enabled,
 186                                      GError             **error)
 187 {
 188 	GError *internal_error = NULL;
 189 
 190 	g_debug ("Dropping index (single-value property): "
 191 	         "DROP INDEX IF EXISTS \"%s_%s\"",
 192 	         service_name, field_name);
 193 
 194 	tracker_db_interface_execute_query (iface, &internal_error,
 195 	                                    "DROP INDEX IF EXISTS \"%s_%s\"",
 196 	                                    service_name,
 197 	                                    field_name);
 198 
 199 	if (internal_error) {
 200 		g_propagate_error (error, internal_error);
 201 		return;
 202 	}
 203 
 204 	if (enabled) {
 205 		g_debug ("Creating index (single-value property): "
 206 		         "CREATE INDEX \"%s_%s\" ON \"%s\" (\"%s\")",
 207 		         service_name, field_name, service_name, field_name);
 208 
 209 		tracker_db_interface_execute_query (iface, &internal_error,
 210 		                                    "CREATE INDEX \"%s_%s\" ON \"%s\" (\"%s\")",
 211 		                                    service_name,
 212 		                                    field_name,
 213 		                                    service_name,
 214 		                                    field_name);
 215 
 216 		if (internal_error) {
 217 			g_propagate_error (error, internal_error);
 218 		}
 219 	}
 220 }
 221 
 222 static void
 223 set_index_for_multi_value_property (TrackerDBInterface  *iface,
 224                                     const gchar         *service_name,
 225                                     const gchar         *field_name,
 226                                     gboolean             enabled,
 227                                     gboolean             recreate,
 228                                     GError             **error)
 229 {
 230 	GError *internal_error = NULL;
 231 
 232 	g_debug ("Dropping index (multi-value property): "
 233 	         "DROP INDEX IF EXISTS \"%s_%s_ID_ID\"",
 234 	         service_name, field_name);
 235 
 236 	tracker_db_interface_execute_query (iface, &internal_error,
 237 	                                    "DROP INDEX IF EXISTS \"%s_%s_ID_ID\"",
 238 	                                    service_name,
 239 	                                    field_name);
 240 
 241 	if (internal_error) {
 242 		g_propagate_error (error, internal_error);
 243 		return;
 244 	}
 245 
 246 	/* Useful to have this here for the cases where we want to fully
 247 	 * re-create the indexes even without an ontology change (when locale
 248 	 * of the user changes) */
 249 	g_debug ("Dropping index (multi-value property): "
 250 	         "DROP INDEX IF EXISTS \"%s_%s_ID\"",
 251 	         service_name,
 252 	         field_name);
 253 	tracker_db_interface_execute_query (iface, &internal_error,
 254 	                                    "DROP INDEX IF EXISTS \"%s_%s_ID\"",
 255 	                                    service_name,
 256 	                                    field_name);
 257 
 258 	if (internal_error) {
 259 		g_propagate_error (error, internal_error);
 260 		return;
 261 	}
 262 
 263 	if (!recreate) {
 264 		return;
 265 	}
 266 
 267 	if (enabled) {
 268 		g_debug ("Creating index (multi-value property): "
 269 		         "CREATE INDEX \"%s_%s_ID\" ON \"%s_%s\" (ID)",
 270 		         service_name,
 271 		         field_name,
 272 		         service_name,
 273 		         field_name);
 274 
 275 		tracker_db_interface_execute_query (iface, &internal_error,
 276 		                                    "CREATE INDEX \"%s_%s_ID\" ON \"%s_%s\" (ID)",
 277 		                                    service_name,
 278 		                                    field_name,
 279 		                                    service_name,
 280 		                                    field_name);
 281 
 282 		if (internal_error) {
 283 			g_propagate_error (error, internal_error);
 284 			return;
 285 		}
 286 
 287 		g_debug ("Creating index (multi-value property): "
 288 		         "CREATE UNIQUE INDEX \"%s_%s_ID_ID\" ON \"%s_%s\" (\"%s\", ID)",
 289 		         service_name,
 290 		         field_name,
 291 		         service_name,
 292 		         field_name,
 293 		         field_name);
 294 
 295 		tracker_db_interface_execute_query (iface, &internal_error,
 296 		                                    "CREATE UNIQUE INDEX \"%s_%s_ID_ID\" ON \"%s_%s\" (\"%s\", ID)",
 297 		                                    service_name,
 298 		                                    field_name,
 299 		                                    service_name,
 300 		                                    field_name,
 301 		                                    field_name);
 302 
 303 		if (internal_error) {
 304 			g_propagate_error (error, internal_error);
 305 			return;
 306 		}
 307 	} else {
 308 		g_debug ("Creating index (multi-value property): "
 309 		         "CREATE UNIQUE INDEX \"%s_%s_ID_ID\" ON \"%s_%s\" (ID, \"%s\")",
 310 		         service_name,
 311 		         field_name,
 312 		         service_name,
 313 		         field_name,
 314 		         field_name);
 315 
 316 		tracker_db_interface_execute_query (iface, &internal_error,
 317 		                                    "CREATE UNIQUE INDEX \"%s_%s_ID_ID\" ON \"%s_%s\" (ID, \"%s\")",
 318 		                                    service_name,
 319 		                                    field_name,
 320 		                                    service_name,
 321 		                                    field_name,
 322 		                                    field_name);
 323 
 324 		if (internal_error) {
 325 			g_propagate_error (error, internal_error);
 326 		}
 327 	}
 328 }
 329 
 330 static gboolean
 331 is_allowed_conversion (const gchar *oldv,
 332                        const gchar *newv,
 333                        Conversion   allowed[])
 334 {
 335 	guint i;
 336 
 337 	for (i = 0; allowed[i].from != NULL; i++) {
 338 		if (g_strcmp0 (allowed[i].from, oldv) == 0) {
 339 			if (g_strcmp0 (allowed[i].to, newv) == 0) {
 340 				return TRUE;
 341 			}
 342 		}
 343 	}
 344 
 345 	return FALSE;
 346 }
 347 
 348 static gboolean
 349 check_unsupported_property_value_change (const gchar     *ontology_path,
 350                                          const gchar     *kind,
 351                                          const gchar     *subject,
 352                                          const gchar     *predicate,
 353                                          const gchar     *object)
 354 {
 355 	GError *error = NULL;
 356 	gboolean needed = TRUE;
 357 	gchar *query = NULL;
 358 	TrackerDBCursor *cursor;
 359 
 360 	query = g_strdup_printf ("SELECT ?old_value WHERE { "
 361 	                           "<%s> %s ?old_value "
 362 	                         "}", subject, kind);
 363 
 364 	cursor = tracker_data_query_sparql_cursor (query, &error);
 365 
 366 	if (cursor && tracker_db_cursor_iter_next (cursor, NULL, NULL)) {
 367 		if (g_strcmp0 (object, tracker_db_cursor_get_string (cursor, 0, NULL)) == 0) {
 368 			needed = FALSE;
 369 		} else {
 370 			needed = TRUE;
 371 		}
 372 
 373 	} else {
 374 		if (object && (g_strcmp0 (object, "false") == 0)) {
 375 			needed = FALSE;
 376 		} else {
 377 			needed = (object != NULL);
 378 		}
 379 	}
 380 
 381 	g_free (query);
 382 	if (cursor) {
 383 		g_object_unref (cursor);
 384 	}
 385 
 386 	if (error) {
 387 		g_critical ("Ontology change, %s", error->message);
 388 		g_clear_error (&error);
 389 	}
 390 
 391 	return needed;
 392 }
 393 
 394 static gboolean
 395 update_property_value (const gchar      *ontology_path,
 396                        const gchar      *kind,
 397                        const gchar      *subject,
 398                        const gchar      *predicate,
 399                        const gchar      *object,
 400                        Conversion        allowed[],
 401                        TrackerClass     *class,
 402                        TrackerProperty  *property,
 403                        GError          **error_in)
 404 {
 405 	GError *error = NULL;
 406 	gboolean needed = TRUE;
 407 	gboolean is_new = FALSE;
 408 
 409 	if (class) {
 410 		is_new = tracker_class_get_is_new (class);
 411 	} else if (property) {
 412 		is_new = tracker_property_get_is_new (property);
 413 	}
 414 
 415 	if (!is_new) {
 416 		gchar *query = NULL;
 417 		TrackerDBCursor *cursor;
 418 
 419 		query = g_strdup_printf ("SELECT ?old_value WHERE { "
 420 		                           "<%s> %s ?old_value "
 421 		                         "}", subject, kind);
 422 
 423 		cursor = tracker_data_query_sparql_cursor (query, &error);
 424 
 425 		if (cursor && tracker_db_cursor_iter_next (cursor, NULL, NULL)) {
 426 			const gchar *str = NULL;
 427 
 428 			str = tracker_db_cursor_get_string (cursor, 0, NULL);
 429 
 430 			if (g_strcmp0 (object, str) == 0) {
 431 				needed = FALSE;
 432 			} else {
 433 				gboolean unsup_onto_err = FALSE;
 434 
 435 				if (allowed && !is_allowed_conversion (str, object, allowed)) {
 436 					handle_unsupported_ontology_change (ontology_path,
 437 					                                    subject,
 438 					                                    kind,
 439 					                                    str,
 440 					                                    object,
 441 					                                    error_in);
 442 					needed = FALSE;
 443 					unsup_onto_err = TRUE;
 444 				}
 445 
 446 				if (!unsup_onto_err) {
 447 					tracker_data_delete_statement (NULL, subject, predicate, str, &error);
 448 					if (!error)
 449 						tracker_data_update_buffer_flush (&error);
 450 				}
 451 			}
 452 
 453 		} else {
 454 			if (object && (g_strcmp0 (object, "false") == 0)) {
 455 				needed = FALSE;
 456 			} else {
 457 				needed = (object != NULL);
 458 			}
 459 		}
 460 		g_free (query);
 461 		if (cursor) {
 462 			g_object_unref (cursor);
 463 		}
 464 	} else {
 465 		needed = FALSE;
 466 	}
 467 
 468 
 469 	if (!error && needed && object) {
 470 		tracker_data_insert_statement (NULL, subject,
 471 		                               predicate, object,
 472 		                               &error);
 473 		if (!error)
 474 			tracker_data_update_buffer_flush (&error);
 475 	}
 476 
 477 	if (error) {
 478 		g_critical ("Ontology change, %s", error->message);
 479 		g_clear_error (&error);
 480 	}
 481 
 482 	return needed;
 483 }
 484 
 485 static void
 486 check_range_conversion_is_allowed (const gchar  *ontology_path,
 487                                    const gchar  *subject,
 488                                    const gchar  *predicate,
 489                                    const gchar  *object,
 490                                    GError      **error)
 491 {
 492 	TrackerDBCursor *cursor;
 493 	gchar *query;
 494 
 495 	query = g_strdup_printf ("SELECT ?old_value WHERE { "
 496 	                           "<%s> rdfs:range ?old_value "
 497 	                         "}", subject);
 498 
 499 	cursor = tracker_data_query_sparql_cursor (query, NULL);
 500 
 501 	g_free (query);
 502 
 503 	if (cursor && tracker_db_cursor_iter_next (cursor, NULL, NULL)) {
 504 		const gchar *str;
 505 
 506 		str = tracker_db_cursor_get_string (cursor, 0, NULL);
 507 
 508 		if (g_strcmp0 (object, str) != 0) {
 509 			if (!is_allowed_conversion (str, object, allowed_range_conversions)) {
 510 				handle_unsupported_ontology_change (ontology_path,
 511 				                                    subject,
 512 				                                    "rdfs:range",
 513 				                                    str,
 514 				                                    object,
 515 				                                    error);
 516 			}
 517 		}
 518 	}
 519 
 520 	if (cursor) {
 521 		g_object_unref (cursor);
 522 	}
 523 }
 524 
 525 static void
 526 fix_indexed (TrackerProperty  *property,
 527              gboolean          recreate,
 528              GError          **error)
 529 {
 530 	GError *internal_error = NULL;
 531 	TrackerDBInterface *iface;
 532 	TrackerClass *class;
 533 	const gchar *service_name;
 534 	const gchar *field_name;
 535 
 536 	iface = tracker_db_manager_get_db_interface ();
 537 
 538 	class = tracker_property_get_domain (property);
 539 	field_name = tracker_property_get_name (property);
 540 	service_name = tracker_class_get_name (class);
 541 
 542 	if (tracker_property_get_multiple_values (property)) {
 543 		set_index_for_multi_value_property (iface, service_name, field_name,
 544 		                                    tracker_property_get_indexed (property),
 545 		                                    recreate,
 546 		                                    &internal_error);
 547 	} else {
 548 		TrackerProperty *secondary_index;
 549 		TrackerClass **domain_index_classes;
 550 
 551 		secondary_index = tracker_property_get_secondary_index (property);
 552 		if (secondary_index == NULL) {
 553 			set_index_for_single_value_property (iface, service_name, field_name,
 554 			                                     recreate && tracker_property_get_indexed (property),
 555 			                                     &internal_error);
 556 		} else {
 557 			set_secondary_index_for_single_value_property (iface, service_name, field_name,
 558 			                                               tracker_property_get_name (secondary_index),
 559 			                                               recreate && tracker_property_get_indexed (property),
 560 			                                               &internal_error);
 561 		}
 562 
 563 		/* single-valued properties may also have domain-specific indexes */
 564 		domain_index_classes = tracker_property_get_domain_indexes (property);
 565 		while (!internal_error && domain_index_classes && *domain_index_classes) {
 566 			set_index_for_single_value_property (iface,
 567 			                                     tracker_class_get_name (*domain_index_classes),
 568 			                                     field_name,
 569 			                                     recreate,
 570 			                                     &internal_error);
 571 			domain_index_classes++;
 572 		}
 573 	}
 574 
 575 	if (internal_error) {
 576 		g_propagate_error (error, internal_error);
 577 	}
 578 }
 579 
 580 static void
 581 tracker_data_ontology_load_statement (const gchar *ontology_path,
 582                                       gint         subject_id,
 583                                       const gchar *subject,
 584                                       const gchar *predicate,
 585                                       const gchar *object,
 586                                       gint        *max_id,
 587                                       gboolean     in_update,
 588                                       GHashTable  *classes,
 589                                       GHashTable  *properties,
 590                                       GPtrArray   *seen_classes,
 591                                       GPtrArray   *seen_properties,
 592                                       GError     **error)
 593 {
 594 	if (g_strcmp0 (predicate, RDF_TYPE) == 0) {
 595 		if (g_strcmp0 (object, RDFS_CLASS) == 0) {
 596 			TrackerClass *class;
 597 			class = tracker_ontologies_get_class_by_uri (subject);
 598 
 599 			if (class != NULL) {
 600 				if (seen_classes)
 601 					g_ptr_array_add (seen_classes, g_object_ref (class));
 602 				if (!in_update) {
 603 					g_critical ("%s: Duplicate definition of class %s", ontology_path, subject);
 604 				} else {
 605 					/* Reset for a correct post-check */
 606 					tracker_class_reset_domain_indexes (class);
 607 					tracker_class_reset_super_classes (class);
 608 					tracker_class_set_notify (class, FALSE);
 609 				}
 610 				return;
 611 			}
 612 
 613 			if (subject_id == 0) {
 614 				subject_id = ++(*max_id);
 615 			}
 616 
 617 			class = tracker_class_new (FALSE);
 618 			tracker_class_set_is_new (class, in_update);
 619 			tracker_class_set_uri (class, subject);
 620 			tracker_class_set_id (class, subject_id);
 621 			tracker_ontologies_add_class (class);
 622 			tracker_ontologies_add_id_uri_pair (subject_id, subject);
 623 
 624 			if (seen_classes)
 625 				g_ptr_array_add (seen_classes, g_object_ref (class));
 626 
 627 			if (classes) {
 628 				g_hash_table_insert (classes, GINT_TO_POINTER (subject_id), class);
 629 			} else {
 630 				g_object_unref (class);
 631 			}
 632 
 633 		} else if (g_strcmp0 (object, RDF_PROPERTY) == 0) {
 634 			TrackerProperty *property;
 635 
 636 			property = tracker_ontologies_get_property_by_uri (subject);
 637 			if (property != NULL) {
 638 				if (seen_properties)
 639 					g_ptr_array_add (seen_properties, g_object_ref (property));
 640 				if (!in_update) {
 641 					g_critical ("%s: Duplicate definition of property %s", ontology_path, subject);
 642 				} else {
 643 					/* Reset for a correct post and pre-check */
 644 					tracker_property_set_last_multiple_values (property, TRUE);
 645 					tracker_property_reset_domain_indexes (property);
 646 					tracker_property_reset_super_properties (property);
 647 					tracker_property_set_indexed (property, FALSE);
 648 					tracker_property_set_secondary_index (property, NULL);
 649 					tracker_property_set_writeback (property, FALSE);
 650 					tracker_property_set_is_inverse_functional_property (property, FALSE);
 651 					tracker_property_set_default_value (property, NULL);
 652 				}
 653 				return;
 654 			}
 655 
 656 			if (subject_id == 0) {
 657 				subject_id = ++(*max_id);
 658 			}
 659 
 660 			property = tracker_property_new (FALSE);
 661 			tracker_property_set_is_new (property, in_update);
 662 			tracker_property_set_uri (property, subject);
 663 			tracker_property_set_id (property, subject_id);
 664 			tracker_ontologies_add_property (property);
 665 			tracker_ontologies_add_id_uri_pair (subject_id, subject);
 666 
 667 			if (seen_properties)
 668 				g_ptr_array_add (seen_properties, g_object_ref (property));
 669 
 670 			if (properties) {
 671 				g_hash_table_insert (properties, GINT_TO_POINTER (subject_id), property);
 672 			} else {
 673 				g_object_unref (property);
 674 			}
 675 
 676 		} else if (g_strcmp0 (object, NRL_INVERSE_FUNCTIONAL_PROPERTY) == 0) {
 677 			TrackerProperty *property;
 678 
 679 			property = tracker_ontologies_get_property_by_uri (subject);
 680 			if (property == NULL) {
 681 				g_critical ("%s: Unknown property %s", ontology_path, subject);
 682 				return;
 683 			}
 684 
 685 			tracker_property_set_is_inverse_functional_property (property, TRUE);
 686 		} else if (g_strcmp0 (object, TRACKER_PREFIX "Namespace") == 0) {
 687 			TrackerNamespace *namespace;
 688 
 689 			if (tracker_ontologies_get_namespace_by_uri (subject) != NULL) {
 690 				if (!in_update)
 691 					g_critical ("%s: Duplicate definition of namespace %s", ontology_path, subject);
 692 				return;
 693 			}
 694 
 695 			namespace = tracker_namespace_new (FALSE);
 696 			tracker_namespace_set_is_new (namespace, in_update);
 697 			tracker_namespace_set_uri (namespace, subject);
 698 			tracker_ontologies_add_namespace (namespace);
 699 			g_object_unref (namespace);
 700 
 701 		} else if (g_strcmp0 (object, TRACKER_PREFIX "Ontology") == 0) {
 702 			TrackerOntology *ontology;
 703 
 704 			if (tracker_ontologies_get_ontology_by_uri (subject) != NULL) {
 705 				if (!in_update)
 706 					g_critical ("%s: Duplicate definition of ontology %s", ontology_path, subject);
 707 				return;
 708 			}
 709 
 710 			ontology = tracker_ontology_new ();
 711 			tracker_ontology_set_is_new (ontology, in_update);
 712 			tracker_ontology_set_uri (ontology, subject);
 713 			tracker_ontologies_add_ontology (ontology);
 714 			g_object_unref (ontology);
 715 
 716 		}
 717 	} else if (g_strcmp0 (predicate, RDFS_SUB_CLASS_OF) == 0) {
 718 		TrackerClass *class, *super_class;
 719 		gboolean is_new;
 720 
 721 		class = tracker_ontologies_get_class_by_uri (subject);
 722 		if (class == NULL) {
 723 			g_critical ("%s: Unknown class %s", ontology_path, subject);
 724 			return;
 725 		}
 726 
 727 		is_new = tracker_class_get_is_new (class);
 728 		if (is_new != in_update) {
 729 			gboolean ignore = FALSE;
 730 			/* Detect unsupported ontology change (this needs a journal replay) */
 731 			if (in_update == TRUE && is_new == FALSE && g_strcmp0 (object, RDFS_PREFIX "Resource") != 0) {
 732 				TrackerClass **super_classes = tracker_class_get_super_classes (class);
 733 				gboolean had = FALSE;
 734 
 735 				super_class = tracker_ontologies_get_class_by_uri (object);
 736 				if (super_class == NULL) {
 737 					g_critical ("%s: Unknown class %s", ontology_path, object);
 738 					return;
 739 				}
 740 
 741 				while (*super_classes) {
 742 					if (*super_classes == super_class) {
 743 						ignore = TRUE;
 744 						g_debug ("%s: Class %s already has rdfs:subClassOf in %s",
 745 						         ontology_path, object, subject);
 746 						break;
 747 					}
 748 					super_classes++;
 749 				}
 750 
 751 				super_classes = tracker_class_get_last_super_classes (class);
 752 				if (super_classes) {
 753 					while (*super_classes) {
 754 						if (super_class == *super_classes) {
 755 							had = TRUE;
 756 						}
 757 						super_classes++;
 758 					}
 759 				}
 760 
 761 				/* This doesn't detect removed rdfs:subClassOf situations, it
 762 				 * only checks whether no new ones are being added. For
 763 				 * detecting the removal of a rdfs:subClassOf, please check the
 764 				 * tracker_data_ontology_process_changes_pre_db stuff */
 765 
 766 
 767 				if (!ignore && !had) {
 768 					handle_unsupported_ontology_change (ontology_path,
 769 					                                    tracker_class_get_name (class),
 770 					                                    "rdfs:subClassOf",
 771 					                                    "-",
 772 					                                    tracker_class_get_name (super_class),
 773 					                                    error);
 774 				}
 775 			}
 776 
 777 			if (!ignore) {
 778 				super_class = tracker_ontologies_get_class_by_uri (object);
 779 				tracker_class_add_super_class (class, super_class);
 780 			}
 781 
 782 			return;
 783 		}
 784 
 785 		super_class = tracker_ontologies_get_class_by_uri (object);
 786 		if (super_class == NULL) {
 787 			g_critical ("%s: Unknown class %s", ontology_path, object);
 788 			return;
 789 		}
 790 
 791 		tracker_class_add_super_class (class, super_class);
 792 
 793 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "notify") == 0) {
 794 		TrackerClass *class;
 795 
 796 		class = tracker_ontologies_get_class_by_uri (subject);
 797 
 798 		if (class == NULL) {
 799 			g_critical ("%s: Unknown class %s", ontology_path, subject);
 800 			return;
 801 		}
 802 
 803 		tracker_class_set_notify (class, (strcmp (object, "true") == 0));
 804 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "domainIndex") == 0) {
 805 		TrackerClass *class;
 806 		TrackerProperty *property;
 807 		TrackerProperty **properties;
 808 		gboolean ignore = FALSE;
 809 		gboolean had = FALSE;
 810 		guint n_props, i;
 811 
 812 		class = tracker_ontologies_get_class_by_uri (subject);
 813 
 814 		if (class == NULL) {
 815 			g_critical ("%s: Unknown class %s", ontology_path, subject);
 816 			return;
 817 		}
 818 
 819 		property = tracker_ontologies_get_property_by_uri (object);
 820 
 821 		if (property == NULL) {
 822 
 823 			/* In this case the import of the TTL will still make the introspection
 824 			 * have the URI set as a tracker:domainIndex for class. The critical
 825 			 * will have happened, but future operations might not cope with this
 826 			 * situation. TODO: add error handling so that the entire ontology
 827 			 * change operation is discarded, for example ignore the entire
 828 			 * .ontology file and rollback all changes that happened. I would
 829 			 * prefer a hard abort() here over a g_critical(), to be honest.
 830 			 *
 831 			 * Of course don't we yet allow just anybody to alter the ontology
 832 			 * files. So very serious is this lack of thorough error handling
 833 			 * not. Let's just not make mistakes when changing the .ontology
 834 			 * files for now. */
 835 
 836 			g_critical ("%s: Unknown property %s for tracker:domainIndex in %s."
 837 			            "Don't release this .ontology change!",
 838 			            ontology_path, object, subject);
 839 			return;
 840 		}
 841 
 842 		if (tracker_property_get_multiple_values (property)) {
 843 			g_critical ("%s: Property %s has multiple values while trying to add it as tracker:domainIndex in %s, this isn't supported",
 844 			            ontology_path, object, subject);
 845 			return;
 846 		}
 847 
 848 		properties = tracker_ontologies_get_properties (&n_props);
 849 		for (i = 0; i < n_props; i++) {
 850 			if (tracker_property_get_domain (properties[i]) == class &&
 851 			    properties[i] == property) {
 852 				g_critical ("%s: Property %s is already a first-class property of %s while trying to add it as tracker:domainIndex",
 853 				            ontology_path, object, subject);
 854 			}
 855 		}
 856 
 857 		properties = tracker_class_get_domain_indexes (class);
 858 		while (*properties) {
 859 			if (property == *properties) {
 860 				g_debug ("%s: Property %s already a tracker:domainIndex in %s",
 861 				         ontology_path, object, subject);
 862 				ignore = TRUE;
 863 			}
 864 			properties++;
 865 		}
 866 
 867 		properties = tracker_class_get_last_domain_indexes (class);
 868 		if (properties) {
 869 			while (*properties) {
 870 				if (property == *properties) {
 871 					had = TRUE;
 872 				}
 873 				properties++;
 874 			}
 875 		}
 876 
 877 		/* This doesn't detect removed tracker:domainIndex situations, it
 878 		 * only checks whether no new ones are being added. For
 879 		 * detecting the removal of a tracker:domainIndex, please check the
 880 		 * tracker_data_ontology_process_changes_pre_db stuff */
 881 
 882 		if (!ignore) {
 883 			if (!had) {
 884 				tracker_property_set_is_new_domain_index (property, class, in_update);
 885 			}
 886 			tracker_class_add_domain_index (class, property);
 887 			tracker_property_add_domain_index (property, class);
 888 		}
 889 
 890 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "writeback") == 0) {
 891 		TrackerProperty *property;
 892 
 893 		property = tracker_ontologies_get_property_by_uri (subject);
 894 
 895 		if (property == NULL) {
 896 			g_critical ("%s: Unknown property %s", ontology_path, subject);
 897 			return;
 898 		}
 899 
 900 		tracker_property_set_writeback (property, (strcmp (object, "true") == 0));
 901 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "forceJournal") == 0) {
 902 		TrackerProperty *property;
 903 
 904 		property = tracker_ontologies_get_property_by_uri (subject);
 905 
 906 		if (property == NULL) {
 907 			g_critical ("%s: Unknown property %s", ontology_path, subject);
 908 			return;
 909 		}
 910 
 911 		tracker_property_set_force_journal (property, (strcmp (object, "true") == 0));
 912 	} else if (g_strcmp0 (predicate, RDFS_SUB_PROPERTY_OF) == 0) {
 913 		TrackerProperty *property, *super_property;
 914 		gboolean is_new;
 915 
 916 		property = tracker_ontologies_get_property_by_uri (subject);
 917 		if (property == NULL) {
 918 			g_critical ("%s: Unknown property %s", ontology_path, subject);
 919 			return;
 920 		}
 921 
 922 		is_new = tracker_property_get_is_new (property);
 923 		if (is_new != in_update) {
 924 			gboolean ignore = FALSE;
 925 			/* Detect unsupported ontology change (this needs a journal replay) */
 926 			if (in_update == TRUE && is_new == FALSE) {
 927 				TrackerProperty **super_properties = tracker_property_get_super_properties (property);
 928 				gboolean had = FALSE;
 929 
 930 				super_property = tracker_ontologies_get_property_by_uri (object);
 931 				if (super_property == NULL) {
 932 					g_critical ("%s: Unknown property %s", ontology_path, object);
 933 					return;
 934 				}
 935 
 936 				while (*super_properties) {
 937 					if (*super_properties == super_property) {
 938 						ignore = TRUE;
 939 						g_debug ("%s: Property %s already has rdfs:subPropertyOf in %s",
 940 						         ontology_path, object, subject);
 941 						break;
 942 					}
 943 					super_properties++;
 944 				}
 945 
 946 				super_properties = tracker_property_get_last_super_properties (property);
 947 				if (super_properties) {
 948 					while (*super_properties) {
 949 						if (super_property == *super_properties) {
 950 							had = TRUE;
 951 						}
 952 						super_properties++;
 953 					}
 954 				}
 955 
 956 				/* This doesn't detect removed rdfs:subPropertyOf situations, it
 957 				 * only checks whether no new ones are being added. For
 958 				 * detecting the removal of a rdfs:subPropertyOf, please check the
 959 				 * tracker_data_ontology_process_changes_pre_db stuff */
 960 
 961 				if (!ignore && !had) {
 962 					handle_unsupported_ontology_change (ontology_path,
 963 					                                    tracker_property_get_name (property),
 964 					                                    "rdfs:subPropertyOf",
 965 					                                    "-",
 966 					                                    tracker_property_get_name (super_property),
 967 					                                    error);
 968 				}
 969 			}
 970 
 971 			if (!ignore) {
 972 				super_property = tracker_ontologies_get_property_by_uri (object);
 973 				tracker_property_add_super_property (property, super_property);
 974 			}
 975 
 976 			return;
 977 		}
 978 
 979 		super_property = tracker_ontologies_get_property_by_uri (object);
 980 		if (super_property == NULL) {
 981 			g_critical ("%s: Unknown property %s", ontology_path, object);
 982 			return;
 983 		}
 984 
 985 		tracker_property_add_super_property (property, super_property);
 986 	} else if (g_strcmp0 (predicate, RDFS_DOMAIN) == 0) {
 987 		TrackerProperty *property;
 988 		TrackerClass *domain;
 989 		gboolean is_new;
 990 
 991 		property = tracker_ontologies_get_property_by_uri (subject);
 992 		if (property == NULL) {
 993 			g_critical ("%s: Unknown property %s", ontology_path, subject);
 994 			return;
 995 		}
 996 
 997 		domain = tracker_ontologies_get_class_by_uri (object);
 998 		if (domain == NULL) {
 999 			g_critical ("%s: Unknown class %s", ontology_path, object);
1000 			return;
1001 		}
1002 
1003 		is_new = tracker_property_get_is_new (property);
1004 		if (is_new != in_update) {
1005 			/* Detect unsupported ontology change (this needs a journal replay) */
1006 			if (in_update == TRUE && is_new == FALSE) {
1007 				TrackerClass *old_domain = tracker_property_get_domain (property);
1008 				if (old_domain != domain) {
1009 					handle_unsupported_ontology_change (ontology_path,
1010 					                                    tracker_property_get_name (property),
1011 					                                    "rdfs:domain",
1012 					                                    tracker_class_get_name (old_domain),
1013 					                                    tracker_class_get_name (domain),
1014 					                                    error);
1015 				}
1016 			}
1017 			return;
1018 		}
1019 
1020 		tracker_property_set_domain (property, domain);
1021 	} else if (g_strcmp0 (predicate, RDFS_RANGE) == 0) {
1022 		TrackerProperty *property;
1023 		TrackerClass *range;
1024 
1025 		property = tracker_ontologies_get_property_by_uri (subject);
1026 		if (property == NULL) {
1027 			g_critical ("%s: Unknown property %s", ontology_path, subject);
1028 			return;
1029 		}
1030 
1031 		if (tracker_property_get_is_new (property) != in_update) {
1032 			GError *err = NULL;
1033 			check_range_conversion_is_allowed (ontology_path,
1034 			                                   subject,
1035 			                                   predicate,
1036 			                                   object,
1037 			                                   &err);
1038 			if (err) {
1039 				g_propagate_error (error, err);
1040 				return;
1041 			}
1042 		}
1043 
1044 		range = tracker_ontologies_get_class_by_uri (object);
1045 		if (range == NULL) {
1046 			g_critical ("%s: Unknown class %s", ontology_path, object);
1047 			return;
1048 		}
1049 
1050 		tracker_property_set_range (property, range);
1051 	} else if (g_strcmp0 (predicate, NRL_MAX_CARDINALITY) == 0) {
1052 		TrackerProperty *property;
1053 		gboolean is_new;
1054 
1055 		property = tracker_ontologies_get_property_by_uri (subject);
1056 		if (property == NULL) {
1057 			g_critical ("%s: Unknown property %s", ontology_path, subject);
1058 			return;
1059 		}
1060 
1061 		/* This doesn't detect removed nrl:maxCardinality situations, it
1062 		 * only checks whether the existing one got changed. For
1063 		 * detecting the removal of a nrl:maxCardinality, please check the
1064 		 * tracker_data_ontology_process_changes_pre_db stuff */
1065 
1066 		is_new = tracker_property_get_is_new (property);
1067 		if (is_new != in_update) {
1068 			/* Detect unsupported ontology change (this needs a journal replay) */
1069 			if (in_update == TRUE && is_new == FALSE) {
1070 				if (check_unsupported_property_value_change (ontology_path,
1071 				                                             "nrl:maxCardinality",
1072 				                                             subject,
1073 				                                             predicate,
1074 				                                             object)) {
1075 					handle_unsupported_ontology_change (ontology_path,
1076 					                                    tracker_property_get_name (property),
1077 					                                    "nrl:maxCardinality",
1078 					                                    tracker_property_get_multiple_values (property) ? "1" : "0",
1079 					                                    (atoi (object) == 1)  ? "1" : "0",
1080 					                                    error);
1081 					return;
1082 				}
1083 			}
1084 		}
1085 
1086 		if (atoi (object) == 1) {
1087 			tracker_property_set_multiple_values (property, FALSE);
1088 			tracker_property_set_last_multiple_values (property, FALSE);
1089 		} else {
1090 			tracker_property_set_multiple_values (property, TRUE);
1091 			tracker_property_set_last_multiple_values (property, TRUE);
1092 		}
1093 
1094 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "indexed") == 0) {
1095 		TrackerProperty *property;
1096 
1097 		property = tracker_ontologies_get_property_by_uri (subject);
1098 		if (property == NULL) {
1099 			g_critical ("%s: Unknown property %s", ontology_path, subject);
1100 			return;
1101 		}
1102 
1103 		tracker_property_set_indexed (property, (strcmp (object, "true") == 0));
1104 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "secondaryIndex") == 0) {
1105 		TrackerProperty *property, *secondary_index;
1106 
1107 		property = tracker_ontologies_get_property_by_uri (subject);
1108 		if (property == NULL) {
1109 			g_critical ("%s: Unknown property %s", ontology_path, subject);
1110 			return;
1111 		}
1112 
1113 		secondary_index = tracker_ontologies_get_property_by_uri (object);
1114 		if (secondary_index == NULL) {
1115 			g_critical ("%s: Unknown property %s", ontology_path, object);
1116 			return;
1117 		}
1118 
1119 		tracker_property_set_secondary_index (property, secondary_index);
1120 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "transient") == 0) {
1121 		TrackerProperty *property;
1122 		gboolean is_new;
1123 
1124 		property = tracker_ontologies_get_property_by_uri (subject);
1125 		if (property == NULL) {
1126 			g_critical ("%s: Unknown property %s", ontology_path, subject);
1127 			return;
1128 		}
1129 
1130 		is_new = tracker_property_get_is_new (property);
1131 		if (is_new != in_update) {
1132 			/* Detect unsupported ontology change (this needs a journal replay).
1133 			 * Wouldn't be very hard to support this, just dropping the tabtle
1134 			 * or creating the table in the-non memdisk db file, but afaik this
1135 			 * isn't supported right now */
1136 			if (in_update == TRUE && is_new == FALSE) {
1137 				if (check_unsupported_property_value_change (ontology_path,
1138 				                                             "tracker:transient",
1139 				                                             subject,
1140 				                                             predicate,
1141 				                                             object)) {
1142 					handle_unsupported_ontology_change (ontology_path,
1143 					                                    tracker_property_get_name (property),
1144 					                                    "tracker:transient",
1145 					                                    tracker_property_get_transient (property) ? "true" : "false",
1146 					                                    g_strcmp0 (object, "true") ==0 ? "true" : "false",
1147 					                                    error);
1148 				}
1149 			}
1150 			return;
1151 		}
1152 
1153 		if (g_strcmp0 (object, "true") == 0) {
1154 			tracker_property_set_transient (property, TRUE);
1155 		}
1156 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "fulltextIndexed") == 0) {
1157 		TrackerProperty *property;
1158 		gboolean is_new;
1159 
1160 		property = tracker_ontologies_get_property_by_uri (subject);
1161 		if (property == NULL) {
1162 			g_critical ("%s: Unknown property %s", ontology_path, subject);
1163 			return;
1164 		}
1165 
1166 		is_new = tracker_property_get_is_new (property);
1167 		if (is_new != in_update) {
1168 			/* Detect unsupported ontology change (this needs a journal replay) */
1169 			if (in_update == TRUE && is_new == FALSE) {
1170 				if (check_unsupported_property_value_change (ontology_path,
1171 				                                             "tracker:fulltextIndexed",
1172 				                                             subject,
1173 				                                             predicate,
1174 				                                             object)) {
1175 					handle_unsupported_ontology_change (ontology_path,
1176 					                                    tracker_property_get_name (property),
1177 					                                    "tracker:fulltextIndexed",
1178 					                                    tracker_property_get_fulltext_indexed (property) ? "true" : "false",
1179 					                                    g_strcmp0 (object, "true") == 0 ? "true" : "false",
1180 					                                    error);
1181 				}
1182 			}
1183 			return;
1184 		}
1185 
1186 		if (strcmp (object, "true") == 0) {
1187 			tracker_property_set_fulltext_indexed (property, TRUE);
1188 		}
1189 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "defaultValue") == 0) {
1190 		TrackerProperty *property;
1191 
1192 		property = tracker_ontologies_get_property_by_uri (subject);
1193 		if (property == NULL) {
1194 			g_critical ("%s: Unknown property %s", ontology_path, subject);
1195 			return;
1196 		}
1197 
1198 		tracker_property_set_default_value (property, object);
1199 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "prefix") == 0) {
1200 		TrackerNamespace *namespace;
1201 
1202 		namespace = tracker_ontologies_get_namespace_by_uri (subject);
1203 		if (namespace == NULL) {
1204 			g_critical ("%s: Unknown namespace %s", ontology_path, subject);
1205 			return;
1206 		}
1207 
1208 		if (tracker_namespace_get_is_new (namespace) != in_update) {
1209 			return;
1210 		}
1211 
1212 		tracker_namespace_set_prefix (namespace, object);
1213 	} else if (g_strcmp0 (predicate, NAO_LAST_MODIFIED) == 0) {
1214 		TrackerOntology *ontology;
1215 
1216 		ontology = tracker_ontologies_get_ontology_by_uri (subject);
1217 		if (ontology == NULL) {
1218 			g_critical ("%s: Unknown ontology %s", ontology_path, subject);
1219 			return;
1220 		}
1221 
1222 		if (tracker_ontology_get_is_new (ontology) != in_update) {
1223 			return;
1224 		}
1225 
1226 		tracker_ontology_set_last_modified (ontology, tracker_string_to_date (object, NULL, NULL));
1227 	}
1228 }
1229 
1230 
1231 static void
1232 check_for_deleted_domain_index (TrackerClass *class)
1233 {
1234 	TrackerProperty **last_domain_indexes;
1235 	GSList *hfound = NULL, *deleted = NULL;
1236 
1237 	last_domain_indexes = tracker_class_get_last_domain_indexes (class);
1238 
1239 	if (!last_domain_indexes) {
1240 		return;
1241 	}
1242 
1243 	while (*last_domain_indexes) {
1244 		TrackerProperty *last_domain_index = *last_domain_indexes;
1245 		gboolean found = FALSE;
1246 		TrackerProperty **domain_indexes;
1247 
1248 		domain_indexes = tracker_class_get_domain_indexes (class);
1249 
1250 		while (*domain_indexes) {
1251 			TrackerProperty *domain_index = *domain_indexes;
1252 			if (last_domain_index == domain_index) {
1253 				found = TRUE;
1254 				hfound = g_slist_prepend (hfound, domain_index);
1255 				break;
1256 			}
1257 			domain_indexes++;
1258 		}
1259 
1260 		if (!found) {
1261 			deleted = g_slist_prepend (deleted, last_domain_index);
1262 		}
1263 
1264 		last_domain_indexes++;
1265 	}
1266 
1267 
1268 	if (deleted) {
1269 		GSList *l;
1270 		TrackerProperty **properties;
1271 		guint n_props, i;
1272 
1273 		tracker_class_set_db_schema_changed (class, TRUE);
1274 
1275 		properties = tracker_ontologies_get_properties (&n_props);
1276 		for (i = 0; i < n_props; i++) {
1277 			if (tracker_property_get_domain (properties[i]) == class &&
1278 			    !tracker_property_get_multiple_values (properties[i])) {
1279 
1280 				/* These aren't domain-indexes, but it's just a flag for the
1281 				 * functionality that'll recreate the table to know that the
1282 				 * property must be involved in the recreation and copy */
1283 
1284 				tracker_property_set_is_new_domain_index (properties[i], class, TRUE);
1285 			}
1286 		}
1287 
1288 		for (l = hfound; l != NULL; l = l->next) {
1289 			TrackerProperty *prop = l->data;
1290 			g_debug ("Ontology change: keeping tracker:domainIndex: %s",
1291 			         tracker_property_get_name (prop));
1292 			tracker_property_set_is_new_domain_index (prop, class, TRUE);
1293 		}
1294 
1295 		for (l = deleted; l != NULL; l = l->next) {
1296 			GError *error = NULL;
1297 			TrackerProperty *prop = l->data;
1298 
1299 			g_debug ("Ontology change: deleting tracker:domainIndex: %s",
1300 			         tracker_property_get_name (prop));
1301 			tracker_property_del_domain_index (prop, class);
1302 			tracker_class_del_domain_index (class, prop);
1303 
1304 			tracker_data_delete_statement (NULL, tracker_class_get_uri (class),
1305 			                               TRACKER_PREFIX "domainIndex",
1306 			                               tracker_property_get_uri (prop),
1307 			                               &error);
1308 
1309 			if (error) {
1310 				g_critical ("Ontology change, %s", error->message);
1311 				g_clear_error (&error);
1312 			} else {
1313 				tracker_data_update_buffer_flush (&error);
1314 				if (error) {
1315 					g_critical ("Ontology change, %s", error->message);
1316 					g_clear_error (&error);
1317 				}
1318 			}
1319 		}
1320 
1321 		g_slist_free (deleted);
1322 	}
1323 
1324 	g_slist_free (hfound);
1325 }
1326 
1327 static void
1328 check_for_deleted_super_classes (TrackerClass  *class,
1329                                  GError       **error)
1330 {
1331 	TrackerClass **last_super_classes;
1332 
1333 	last_super_classes = tracker_class_get_last_super_classes (class);
1334 
1335 	if (!last_super_classes) {
1336 		return;
1337 	}
1338 
1339 	while (*last_super_classes) {
1340 		TrackerClass *last_super_class = *last_super_classes;
1341 		gboolean found = FALSE;
1342 		TrackerClass **super_classes;
1343 
1344 		if (g_strcmp0 (tracker_class_get_uri (last_super_class), RDFS_PREFIX "Resource") == 0) {
1345 			last_super_classes++;
1346 			continue;
1347 		}
1348 
1349 		super_classes = tracker_class_get_super_classes (class);
1350 
1351 		while (*super_classes) {
1352 			TrackerClass *super_class = *super_classes;
1353 
1354 			if (last_super_class == super_class) {
1355 				found = TRUE;
1356 				break;
1357 			}
1358 			super_classes++;
1359 		}
1360 
1361 		if (!found) {
1362 			const gchar *ontology_path = "Unknown";
1363 			const gchar *subject = tracker_class_get_uri (class);
1364 
1365 			handle_unsupported_ontology_change (ontology_path,
1366 			                                    subject,
1367 			                                    "rdfs:subClassOf", "-", "-",
1368 			                                    error);
1369 			return;
1370 		}
1371 
1372 		last_super_classes++;
1373 	}
1374 }
1375 
1376 
1377 static void
1378 check_for_deleted_super_properties (TrackerProperty  *property,
1379                                     GError          **error)
1380 {
1381 	TrackerProperty **last_super_properties;
1382 	GList *to_remove = NULL;
1383 
1384 	last_super_properties = tracker_property_get_last_super_properties (property);
1385 
1386 	if (!last_super_properties) {
1387 		return;
1388 	}
1389 
1390 	while (*last_super_properties) {
1391 		TrackerProperty *last_super_property = *last_super_properties;
1392 		gboolean found = FALSE;
1393 		TrackerProperty **super_properties;
1394 
1395 		super_properties = tracker_property_get_super_properties (property);
1396 
1397 		while (*super_properties) {
1398 			TrackerProperty *super_property = *super_properties;
1399 
1400 			if (last_super_property == super_property) {
1401 				found = TRUE;
1402 				break;
1403 			}
1404 			super_properties++;
1405 		}
1406 
1407 		if (!found) {
1408 			to_remove = g_list_prepend (to_remove, last_super_property);
1409 		}
1410 
1411 		last_super_properties++;
1412 	}
1413 
1414 	if (to_remove) {
1415 		GList *copy = to_remove;
1416 
1417 		while (copy) {
1418 			GError *n_error = NULL;
1419 			TrackerProperty *prop_to_remove = copy->data;
1420 			const gchar *object = tracker_property_get_uri (prop_to_remove);
1421 			const gchar *subject = tracker_property_get_uri (property);
1422 
1423 			tracker_property_del_super_property (property, prop_to_remove);
1424 
1425 			tracker_data_delete_statement (NULL, subject,
1426 			                               RDFS_PREFIX "subPropertyOf",
1427 			                               object, &n_error);
1428 
1429 			if (!n_error) {
1430 				tracker_data_update_buffer_flush (&n_error);
1431 			}
1432 
1433 			if (n_error) {
1434 				g_propagate_error (error, n_error);
1435 				return;
1436 			}
1437 
1438 			copy = copy->next;
1439 		}
1440 		g_list_free (to_remove);
1441 	}
1442 }
1443 
1444 static void
1445 tracker_data_ontology_process_changes_pre_db (GPtrArray  *seen_classes,
1446                                               GPtrArray  *seen_properties,
1447                                               GError    **error)
1448 {
1449 	gint i;
1450 	if (seen_classes) {
1451 		for (i = 0; i < seen_classes->len; i++) {
1452 			GError *n_error = NULL;
1453 			TrackerClass *class = g_ptr_array_index (seen_classes, i);
1454 
1455 			check_for_deleted_domain_index (class);
1456 			check_for_deleted_super_classes (class, &n_error);
1457 
1458 			if (n_error) {
1459 				g_propagate_error (error, n_error);
1460 				return;
1461 			}
1462 		}
1463 	}
1464 
1465 	if (seen_properties) {
1466 		for (i = 0; i < seen_properties->len; i++) {
1467 			GError *n_error = NULL;
1468 
1469 			TrackerProperty *property = g_ptr_array_index (seen_properties, i);
1470 			gboolean last_multiple_values = tracker_property_get_last_multiple_values (property);
1471 
1472 			check_for_deleted_super_properties (property, &n_error);
1473 
1474 			if (n_error) {
1475 				g_propagate_error (error, n_error);
1476 				return;
1477 			}
1478 
1479 			if (tracker_property_get_is_new (property) == FALSE &&
1480 			    last_multiple_values != tracker_property_get_multiple_values (property)) {
1481 				const gchar *ontology_path = "Unknown";
1482 				const gchar *subject = tracker_property_get_uri (property);
1483 
1484 				handle_unsupported_ontology_change (ontology_path,
1485 				                                    subject,
1486 				                                    "nrl:maxCardinality", "1", "0",
1487 				                                    error);
1488 				return;
1489 			}
1490 		}
1491 	}
1492 }
1493 
1494 static void
1495 tracker_data_ontology_process_changes_post_db (GPtrArray  *seen_classes,
1496                                                GPtrArray  *seen_properties,
1497                                                GError    **error)
1498 {
1499 	gint i;
1500 	/* TODO: Collect the ontology-paths of the seen events for proper error reporting */
1501 	const gchar *ontology_path = "Unknown";
1502 
1503 	/* This updates property-property changes and marks classes for necessity
1504 	 * of having their tables recreated later. There's support for
1505 	 * tracker:notify, tracker:writeback and tracker:indexed */
1506 
1507 	if (seen_classes) {
1508 		for (i = 0; i < seen_classes->len; i++) {
1509 			TrackerClass *class = g_ptr_array_index (seen_classes, i);
1510 			const gchar *subject;
1511 			GError *n_error = NULL;
1512 
1513 			subject = tracker_class_get_uri (class);
1514 
1515 			if (tracker_class_get_notify (class)) {
1516 				update_property_value (ontology_path,
1517 				                       "tracker:notify",
1518 				                       subject,
1519 				                       TRACKER_PREFIX "notify",
1520 				                       "true", allowed_boolean_conversions,
1521 				                       class, NULL, &n_error);
1522 			} else {
1523 				update_property_value (ontology_path,
1524 				                       "tracker:notify",
1525 				                       subject,
1526 				                       TRACKER_PREFIX "notify",
1527 				                       "false", allowed_boolean_conversions,
1528 				                       class, NULL, &n_error);
1529 			}
1530 
1531 			if (n_error) {
1532 				g_propagate_error (error, n_error);
1533 				return;
1534 			}
1535 		}
1536 	}
1537 
1538 	if (seen_properties) {
1539 		for (i = 0; i < seen_properties->len; i++) {
1540 			TrackerProperty *property = g_ptr_array_index (seen_properties, i);
1541 			const gchar *subject;
1542 			gchar *query;
1543 			TrackerProperty *secondary_index;
1544 			gboolean indexed_set = FALSE, in_onto;
1545 			GError *n_error = NULL;
1546 			TrackerSparqlCursor *cursor;
1547 
1548 			subject = tracker_property_get_uri (property);
1549 
1550 			/* Check for nrl:InverseFunctionalProperty changes (not supported) */
1551 			in_onto = tracker_property_get_is_inverse_functional_property (property);
1552 
1553 			query = g_strdup_printf ("ASK { <%s> a nrl:InverseFunctionalProperty }", subject);
1554 			cursor = TRACKER_SPARQL_CURSOR (tracker_data_query_sparql_cursor (query, &n_error));
1555 			g_free (query);
1556 
1557 			if (n_error) {
1558 				g_propagate_error (error, n_error);
1559 				return;
1560 			}
1561 
1562 			if (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
1563 				if (tracker_sparql_cursor_get_boolean (cursor, 0) != in_onto) {
1564 					handle_unsupported_ontology_change (ontology_path,
1565 					                                    subject,
1566 					                                    "nrl:InverseFunctionalProperty", "-", "-",
1567 					                                    &n_error);
1568 
1569 					if (n_error) {
1570 						g_object_unref (cursor);
1571 						g_propagate_error (error, n_error);
1572 						return;
1573 					}
1574 				}
1575 			}
1576 
1577 			if (cursor) {
1578 				g_object_unref (cursor);
1579 			}
1580 
1581 			/* Check for possibly supported changes */
1582 			if (tracker_property_get_writeback (property)) {
1583 				update_property_value (ontology_path,
1584 				                       "tracker:writeback",
1585 				                       subject,
1586 				                       TRACKER_PREFIX "writeback",
1587 				                       "true", allowed_boolean_conversions,
1588 				                       NULL, property, &n_error);
1589 			} else {
1590 				update_property_value (ontology_path,
1591 				                       "tracker:writeback",
1592 				                       subject,
1593 				                       TRACKER_PREFIX "writeback",
1594 				                       "false", allowed_boolean_conversions,
1595 				                       NULL, property, &n_error);
1596 			}
1597 
1598 			if (n_error) {
1599 				g_propagate_error (error, n_error);
1600 				return;
1601 			}
1602 
1603 			if (tracker_property_get_indexed (property)) {
1604 				if (update_property_value (ontology_path,
1605 				                           "tracker:indexed",
1606 				                           subject,
1607 				                           TRACKER_PREFIX "indexed",
1608 				                           "true", allowed_boolean_conversions,
1609 				                           NULL, property, &n_error)) {
1610 					fix_indexed (property, TRUE, &n_error);
1611 					indexed_set = TRUE;
1612 				}
1613 			} else {
1614 				if (update_property_value (ontology_path,
1615 				                           "tracker:indexed",
1616 				                           subject,
1617 				                           TRACKER_PREFIX "indexed",
1618 				                           "false", allowed_boolean_conversions,
1619 				                           NULL, property, &n_error)) {
1620 					fix_indexed (property, TRUE, &n_error);
1621 					indexed_set = TRUE;
1622 				}
1623 			}
1624 
1625 			if (n_error) {
1626 				g_propagate_error (error, n_error);
1627 				return;
1628 			}
1629 
1630 			secondary_index = tracker_property_get_secondary_index (property);
1631 
1632 			if (secondary_index) {
1633 				if (update_property_value (ontology_path,
1634 				                           "tracker:secondaryIndex",
1635 				                           subject,
1636 				                           TRACKER_PREFIX "secondaryIndex",
1637 				                           tracker_property_get_uri (secondary_index), NULL,
1638 				                           NULL, property, &n_error)) {
1639 					if (!indexed_set) {
1640 						fix_indexed (property, TRUE, &n_error);
1641 					}
1642 				}
1643 			} else {
1644 				if (update_property_value (ontology_path,
1645 				                           "tracker:secondaryIndex",
1646 				                           subject,
1647 				                           TRACKER_PREFIX "secondaryIndex",
1648 				                           NULL, NULL,
1649 				                           NULL, property, &n_error)) {
1650 					if (!indexed_set) {
1651 						fix_indexed (property, TRUE, &n_error);
1652 					}
1653 				}
1654 			}
1655 
1656 			if (n_error) {
1657 				g_propagate_error (error, n_error);
1658 				return;
1659 			}
1660 
1661 			if (update_property_value (ontology_path,
1662 			                           "rdfs:range", subject, RDFS_PREFIX "range",
1663 			                           tracker_class_get_uri (tracker_property_get_range (property)),
1664 			                           allowed_range_conversions,
1665 			                           NULL, property, &n_error)) {
1666 				TrackerClass *class;
1667 
1668 				class = tracker_property_get_domain (property);
1669 				tracker_class_set_db_schema_changed (class, TRUE);
1670 				tracker_property_set_db_schema_changed (property, TRUE);
1671 			}
1672 
1673 			if (n_error) {
1674 				g_propagate_error (error, n_error);
1675 				return;
1676 			}
1677 
1678 			if (update_property_value (ontology_path,
1679 			                           "tracker:defaultValue", subject, TRACKER_PREFIX "defaultValue",
1680 			                           tracker_property_get_default_value (property),
1681 			                           NULL, NULL, property, &n_error)) {
1682 				TrackerClass *class;
1683 
1684 				class = tracker_property_get_domain (property);
1685 				tracker_class_set_db_schema_changed (class, TRUE);
1686 				tracker_property_set_db_schema_changed (property, TRUE);
1687 			}
1688 
1689 			if (n_error) {
1690 				g_propagate_error (error, n_error);
1691 			}
1692 		}
1693 	}
1694 }
1695 
1696 static void
1697 tracker_data_ontology_process_changes_post_import (GPtrArray *seen_classes,
1698                                                    GPtrArray *seen_properties)
1699 {
1700 	return;
1701 }
1702 
1703 static void
1704 tracker_data_ontology_free_seen (GPtrArray *seen)
1705 {
1706 	if (seen) {
1707 		g_ptr_array_foreach (seen, (GFunc) g_object_unref, NULL);
1708 		g_ptr_array_free (seen, TRUE);
1709 	}
1710 }
1711 
1712 static void
1713 load_ontology_file_from_path (const gchar        *ontology_path,
1714                               gint               *max_id,
1715                               gboolean            in_update,
1716                               GPtrArray          *seen_classes,
1717                               GPtrArray          *seen_properties,
1718                               GHashTable         *uri_id_map,
1719                               GError            **error)
1720 {
1721 	TrackerTurtleReader *reader;
1722 	GError              *ttl_error = NULL;
1723 
1724 	reader = tracker_turtle_reader_new (ontology_path, &ttl_error);
1725 
1726 	if (ttl_error) {
1727 		g_propagate_error (error, ttl_error);
1728 		return;
1729 	}
1730 
1731 	/* Post checks are only needed for ontology updates, not the initial
1732 	 * ontology */
1733 
1734 	while (ttl_error == NULL && tracker_turtle_reader_next (reader, &ttl_error)) {
1735 		const gchar *subject, *predicate, *object;
1736 		gint subject_id = 0;
1737 		GError *ontology_error = NULL;
1738 
1739 		subject = tracker_turtle_reader_get_subject (reader);
1740 		predicate = tracker_turtle_reader_get_predicate (reader);
1741 		object = tracker_turtle_reader_get_object (reader);
1742 
1743 		if (uri_id_map) {
1744 			subject_id = GPOINTER_TO_INT (g_hash_table_lookup (uri_id_map, subject));
1745 		}
1746 
1747 		tracker_data_ontology_load_statement (ontology_path, subject_id, subject, predicate, object,
1748 		                                      max_id, in_update, NULL, NULL,
1749 		                                      seen_classes, seen_properties, &ontology_error);
1750 
1751 		if (ontology_error) {
1752 			g_propagate_error (error, ontology_error);
1753 			break;
1754 		}
1755 	}
1756 
1757 	g_object_unref (reader);
1758 
1759 	if (ttl_error) {
1760 		g_propagate_error (error, ttl_error);
1761 	}
1762 }
1763 
1764 
1765 static TrackerOntology*
1766 get_ontology_from_path (const gchar *ontology_path)
1767 {
1768 	TrackerTurtleReader *reader;
1769 	GError *error = NULL;
1770 	GHashTable *ontology_uris;
1771 	TrackerOntology *ret = NULL;
1772 
1773 	reader = tracker_turtle_reader_new (ontology_path, &error);
1774 
1775 	if (error) {
1776 		g_critical ("Turtle parse error: %s", error->message);
1777 		g_error_free (error);
1778 		return NULL;
1779 	}
1780 
1781 	ontology_uris = g_hash_table_new_full (g_str_hash,
1782 	                                       g_str_equal,
1783 	                                       g_free,
1784 	                                       g_object_unref);
1785 
1786 	while (error == NULL && tracker_turtle_reader_next (reader, &error)) {
1787 		const gchar *subject, *predicate, *object;
1788 
1789 		subject = tracker_turtle_reader_get_subject (reader);
1790 		predicate = tracker_turtle_reader_get_predicate (reader);
1791 		object = tracker_turtle_reader_get_object (reader);
1792 
1793 		if (g_strcmp0 (predicate, RDF_TYPE) == 0) {
1794 			if (g_strcmp0 (object, TRACKER_PREFIX "Ontology") == 0) {
1795 				TrackerOntology *ontology;
1796 
1797 				ontology = tracker_ontology_new ();
1798 				tracker_ontology_set_uri (ontology, subject);
1799 
1800 				/* Passes ownership */
1801 				g_hash_table_insert (ontology_uris,
1802 				                     g_strdup (subject),
1803 				                     ontology);
1804 			}
1805 		} else if (g_strcmp0 (predicate, NAO_LAST_MODIFIED) == 0) {
1806 			TrackerOntology *ontology;
1807 
1808 			ontology = g_hash_table_lookup (ontology_uris, subject);
1809 			if (ontology == NULL) {
1810 				g_critical ("%s: Unknown ontology %s", ontology_path, subject);
1811 				return NULL;
1812 			}
1813 
1814 			tracker_ontology_set_last_modified (ontology, tracker_string_to_date (object, NULL, NULL));
1815 
1816 			/* This one is here because lower ontology_uris is destroyed, and
1817 			 * else would this one's reference also be destroyed with it */
1818 			ret = g_object_ref (ontology);
1819 
1820 			break;
1821 		}
1822 	}
1823 
1824 	g_hash_table_unref (ontology_uris);
1825 	g_object_unref (reader);
1826 
1827 	if (error) {
1828 		g_critical ("Turtle parse error: %s", error->message);
1829 		g_error_free (error);
1830 	}
1831 
1832 	if (ret == NULL) {
1833 		g_critical ("Ontology file has no nao:lastModified header: %s", ontology_path);
1834 	}
1835 
1836 	return ret;
1837 }
1838 
1839 #ifndef DISABLE_JOURNAL
1840 static void
1841 load_ontology_ids_from_journal (GHashTable **uri_id_map_out,
1842                                 gint        *max_id)
1843 {
1844 	GHashTable *uri_id_map;
1845 
1846 	uri_id_map = g_hash_table_new_full (g_str_hash, g_str_equal,
1847 	                                    g_free, NULL);
1848 
1849 	while (tracker_db_journal_reader_next (NULL)) {
1850 		TrackerDBJournalEntryType type;
1851 
1852 		type = tracker_db_journal_reader_get_type ();
1853 		if (type == TRACKER_DB_JOURNAL_RESOURCE) {
1854 			gint id;
1855 			const gchar *uri;
1856 
1857 			tracker_db_journal_reader_get_resource (&id, &uri);
1858 			g_hash_table_insert (uri_id_map, g_strdup (uri), GINT_TO_POINTER (id));
1859 			if (id > *max_id) {
1860 				*max_id = id;
1861 			}
1862 		}
1863 	}
1864 
1865 	*uri_id_map_out = uri_id_map;
1866 }
1867 #endif /* DISABLE_JOURNAL */
1868 
1869 static void
1870 tracker_data_ontology_process_statement (const gchar *graph,
1871                                          const gchar *subject,
1872                                          const gchar *predicate,
1873                                          const gchar *object,
1874                                          gboolean     is_uri,
1875                                          gboolean     in_update,
1876                                          gboolean     ignore_nao_last_modified)
1877 {
1878 	GError *error = NULL;
1879 
1880 	if (g_strcmp0 (predicate, RDF_TYPE) == 0) {
1881 		if (g_strcmp0 (object, RDFS_CLASS) == 0) {
1882 			TrackerClass *class;
1883 
1884 			class = tracker_ontologies_get_class_by_uri (subject);
1885 
1886 			if (class && tracker_class_get_is_new (class) != in_update) {
1887 				return;
1888 			}
1889 		} else if (g_strcmp0 (object, RDF_PROPERTY) == 0) {
1890 			TrackerProperty *prop;
1891 
1892 			prop = tracker_ontologies_get_property_by_uri (subject);
1893 
1894 			if (prop && tracker_property_get_is_new (prop) != in_update) {
1895 				return;
1896 			}
1897 		} else if (g_strcmp0 (object, TRACKER_PREFIX "Namespace") == 0) {
1898 			TrackerNamespace *namespace;
1899 
1900 			namespace = tracker_ontologies_get_namespace_by_uri (subject);
1901 
1902 			if (namespace && tracker_namespace_get_is_new (namespace) != in_update) {
1903 				return;
1904 			}
1905 		} else if (g_strcmp0 (object, TRACKER_PREFIX "Ontology") == 0) {
1906 			TrackerOntology *ontology;
1907 
1908 			ontology = tracker_ontologies_get_ontology_by_uri (subject);
1909 
1910 			if (ontology && tracker_ontology_get_is_new (ontology) != in_update) {
1911 				return;
1912 			}
1913 		}
1914 	} else if (g_strcmp0 (predicate, RDFS_SUB_CLASS_OF) == 0) {
1915 		TrackerClass *class;
1916 
1917 		class = tracker_ontologies_get_class_by_uri (subject);
1918 
1919 		if (class && tracker_class_get_is_new (class) != in_update) {
1920 			return;
1921 		}
1922 	} else if (g_strcmp0 (predicate, RDFS_SUB_PROPERTY_OF) == 0          ||
1923 	           g_strcmp0 (predicate, RDFS_DOMAIN) == 0                   ||
1924 	           g_strcmp0 (predicate, RDFS_RANGE) == 0                    ||
1925 	           g_strcmp0 (predicate, NRL_MAX_CARDINALITY) == 0           ||
1926 	           g_strcmp0 (predicate, TRACKER_PREFIX "indexed") == 0      ||
1927 	           g_strcmp0 (predicate, TRACKER_PREFIX "transient") == 0    ||
1928 	           g_strcmp0 (predicate, TRACKER_PREFIX "fulltextIndexed") == 0) {
1929 		TrackerProperty *prop;
1930 
1931 		prop = tracker_ontologies_get_property_by_uri (subject);
1932 
1933 		if (prop && tracker_property_get_is_new (prop) != in_update) {
1934 			return;
1935 		}
1936 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "prefix") == 0) {
1937 		TrackerNamespace *namespace;
1938 
1939 		namespace = tracker_ontologies_get_namespace_by_uri (subject);
1940 
1941 		if (namespace && tracker_namespace_get_is_new (namespace) != in_update) {
1942 			return;
1943 		}
1944 	} else if (g_strcmp0 (predicate, NAO_LAST_MODIFIED) == 0) {
1945 		TrackerOntology *ontology;
1946 
1947 		ontology = tracker_ontologies_get_ontology_by_uri (subject);
1948 
1949 		if (ontology && tracker_ontology_get_is_new (ontology) != in_update) {
1950 			return;
1951 		}
1952 
1953 		if (ignore_nao_last_modified) {
1954 			return;
1955 		}
1956 	}
1957 
1958 	if (is_uri) {
1959 		tracker_data_insert_statement_with_uri (graph, subject,
1960 		                                        predicate, object,
1961 		                                        &error);
1962 
1963 		if (error != NULL) {
1964 			g_critical ("%s", error->message);
1965 			g_error_free (error);
1966 			return;
1967 		}
1968 
1969 	} else {
1970 		tracker_data_insert_statement_with_string (graph, subject,
1971 		                                           predicate, object,
1972 		                                           &error);
1973 
1974 		if (error != NULL) {
1975 			g_critical ("%s", error->message);
1976 			g_error_free (error);
1977 			return;
1978 		}
1979 	}
1980 }
1981 
1982 static void
1983 import_ontology_path (const gchar *ontology_path,
1984                       gboolean in_update,
1985                       gboolean ignore_nao_last_modified)
1986 {
1987 	GError          *error = NULL;
1988 
1989 	TrackerTurtleReader* reader;
1990 
1991 	reader = tracker_turtle_reader_new (ontology_path, &error);
1992 
1993 	if (error != NULL) {
1994 		g_critical ("%s", error->message);
1995 		g_error_free (error);
1996 		return;
1997 	}
1998 
1999 	while (tracker_turtle_reader_next (reader, &error)) {
2000 
2001 		const gchar *graph = tracker_turtle_reader_get_graph (reader);
2002 		const gchar *subject = tracker_turtle_reader_get_subject (reader);
2003 		const gchar *predicate = tracker_turtle_reader_get_predicate (reader);
2004 		const gchar *object  = tracker_turtle_reader_get_object (reader);
2005 
2006 		tracker_data_ontology_process_statement (graph, subject, predicate, object,
2007 		                                         tracker_turtle_reader_get_object_is_uri (reader),
2008 		                                         in_update, ignore_nao_last_modified);
2009 
2010 	}
2011 
2012 	g_object_unref (reader);
2013 
2014 	if (error) {
2015 		g_critical ("%s", error->message);
2016 		g_error_free (error);
2017 	}
2018 }
2019 
2020 static void
2021 class_add_super_classes_from_db (TrackerDBInterface *iface,
2022                                  TrackerClass       *class)
2023 {
2024 	TrackerDBStatement *stmt;
2025 	TrackerDBCursor *cursor;
2026 	GError *error = NULL;
2027 
2028 	stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &error,
2029 	                                              "SELECT (SELECT Uri FROM Resource WHERE ID = \"rdfs:subClassOf\") "
2030 	                                              "FROM \"rdfs:Class_rdfs:subClassOf\" "
2031 	                                              "WHERE ID = (SELECT ID FROM Resource WHERE Uri = ?)");
2032 
2033 	if (!stmt) {
2034 		g_critical ("%s", error->message);
2035 		g_error_free (error);
2036 		return;
2037 	}
2038 
2039 	tracker_db_statement_bind_text (stmt, 0, tracker_class_get_uri (class));
2040 	cursor = tracker_db_statement_start_cursor (stmt, NULL);
2041 	g_object_unref (stmt);
2042 
2043 	if (cursor) {
2044 		while (tracker_db_cursor_iter_next (cursor, NULL, NULL)) {
2045 			TrackerClass *super_class;
2046 			const gchar *super_class_uri;
2047 
2048 			super_class_uri = tracker_db_cursor_get_string (cursor, 0, NULL);
2049 			super_class = tracker_ontologies_get_class_by_uri (super_class_uri);
2050 			tracker_class_add_super_class (class, super_class);
2051 		}
2052 
2053 		g_object_unref (cursor);
2054 	}
2055 }
2056 
2057 
2058 static void
2059 class_add_domain_indexes_from_db (TrackerDBInterface *iface,
2060                                   TrackerClass       *class)
2061 {
2062 	TrackerDBStatement *stmt;
2063 	TrackerDBCursor *cursor;
2064 	GError *error = NULL;
2065 
2066 	stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &error,
2067 	                                              "SELECT (SELECT Uri FROM Resource WHERE ID = \"tracker:domainIndex\") "
2068 	                                              "FROM \"rdfs:Class_tracker:domainIndex\" "
2069 	                                              "WHERE ID = (SELECT ID FROM Resource WHERE Uri = ?)");
2070 
2071 	if (!stmt) {
2072 		g_critical ("%s", error->message);
2073 		g_error_free (error);
2074 		return;
2075 	}
2076 
2077 	tracker_db_statement_bind_text (stmt, 0, tracker_class_get_uri (class));
2078 	cursor = tracker_db_statement_start_cursor (stmt, NULL);
2079 	g_object_unref (stmt);
2080 
2081 	if (cursor) {
2082 		while (tracker_db_cursor_iter_next (cursor, NULL, NULL)) {
2083 			TrackerProperty *domain_index;
2084 			const gchar *domain_index_uri;
2085 
2086 			domain_index_uri = tracker_db_cursor_get_string (cursor, 0, NULL);
2087 			domain_index = tracker_ontologies_get_property_by_uri (domain_index_uri);
2088 			tracker_class_add_domain_index (class, domain_index);
2089 			tracker_property_add_domain_index (domain_index, class);
2090 		}
2091 
2092 		g_object_unref (cursor);
2093 	}
2094 }
2095 
2096 static void
2097 property_add_super_properties_from_db (TrackerDBInterface *iface,
2098                                        TrackerProperty *property)
2099 {
2100 	TrackerDBStatement *stmt;
2101 	TrackerDBCursor *cursor;
2102 	GError *error = NULL;
2103 
2104 	stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &error,
2105 	                                              "SELECT (SELECT Uri FROM Resource WHERE ID = \"rdfs:subPropertyOf\") "
2106 	                                              "FROM \"rdf:Property_rdfs:subPropertyOf\" "
2107 	                                              "WHERE ID = (SELECT ID FROM Resource WHERE Uri = ?)");
2108 
2109 	if (!stmt) {
2110 		g_critical ("%s", error->message);
2111 		g_error_free (error);
2112 		return;
2113 	}
2114 
2115 	tracker_db_statement_bind_text (stmt, 0, tracker_property_get_uri (property));
2116 	cursor = tracker_db_statement_start_cursor (stmt, NULL);
2117 	g_object_unref (stmt);
2118 
2119 	if (cursor) {
2120 		while (tracker_db_cursor_iter_next (cursor, NULL, NULL)) {
2121 			TrackerProperty *super_property;
2122 			const gchar *super_property_uri;
2123 
2124 			super_property_uri = tracker_db_cursor_get_string (cursor, 0, NULL);
2125 			super_property = tracker_ontologies_get_property_by_uri (super_property_uri);
2126 			tracker_property_add_super_property (property, super_property);
2127 		}
2128 
2129 		g_object_unref (cursor);
2130 	}
2131 }
2132 
2133 static void
2134 db_get_static_data (TrackerDBInterface  *iface,
2135                     GError             **error)
2136 {
2137 	TrackerDBStatement *stmt;
2138 	TrackerDBCursor *cursor = NULL;
2139 	TrackerClass **classes;
2140 	guint n_classes, i;
2141 	GError *internal_error = NULL;
2142 
2143 	stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &internal_error,
2144 	                                              "SELECT (SELECT Uri FROM Resource WHERE ID = \"tracker:Ontology\".ID), "
2145 	                                              "\"nao:lastModified\" "
2146 	                                              "FROM \"tracker:Ontology\"");
2147 
2148 	if (stmt) {
2149 		cursor = tracker_db_statement_start_cursor (stmt, &internal_error);
2150 		g_object_unref (stmt);
2151 	}
2152 
2153 	if (cursor) {
2154 		while (tracker_db_cursor_iter_next (cursor, NULL, &internal_error)) {
2155 			TrackerOntology *ontology;
2156 			const gchar     *uri;
2157 			time_t           last_mod;
2158 
2159 			ontology = tracker_ontology_new ();
2160 
2161 			uri = tracker_db_cursor_get_string (cursor, 0, NULL);
2162 			last_mod = (time_t) tracker_db_cursor_get_int (cursor, 1);
2163 
2164 			tracker_ontology_set_is_new (ontology, FALSE);
2165 			tracker_ontology_set_uri (ontology, uri);
2166 			tracker_ontology_set_last_modified (ontology, last_mod);
2167 			tracker_ontologies_add_ontology (ontology);
2168 
2169 			g_object_unref (ontology);
2170 		}
2171 
2172 		g_object_unref (cursor);
2173 		cursor = NULL;
2174 	}
2175 
2176 	if (internal_error) {
2177 		g_propagate_error (error, internal_error);
2178 		return;
2179 	}
2180 
2181 	stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &internal_error,
2182 	                                              "SELECT (SELECT Uri FROM Resource WHERE ID = \"tracker:Namespace\".ID), "
2183 	                                              "\"tracker:prefix\" "
2184 	                                              "FROM \"tracker:Namespace\"");
2185 
2186 	if (stmt) {
2187 		cursor = tracker_db_statement_start_cursor (stmt, &internal_error);
2188 		g_object_unref (stmt);
2189 	}
2190 
2191 	if (cursor) {
2192 		while (tracker_db_cursor_iter_next (cursor, NULL, &internal_error)) {
2193 			TrackerNamespace *namespace;
2194 			const gchar      *uri, *prefix;
2195 
2196 			namespace = tracker_namespace_new (FALSE);
2197 
2198 			uri = tracker_db_cursor_get_string (cursor, 0, NULL);
2199 			prefix = tracker_db_cursor_get_string (cursor, 1, NULL);
2200 
2201 			tracker_namespace_set_is_new (namespace, FALSE);
2202 			tracker_namespace_set_uri (namespace, uri);
2203 			tracker_namespace_set_prefix (namespace, prefix);
2204 			tracker_ontologies_add_namespace (namespace);
2205 
2206 			g_object_unref (namespace);
2207 
2208 		}
2209 
2210 		g_object_unref (cursor);
2211 		cursor = NULL;
2212 	}
2213 
2214 	if (internal_error) {
2215 		g_propagate_error (error, internal_error);
2216 		return;
2217 	}
2218 
2219 	stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &internal_error,
2220 	                                              "SELECT \"rdfs:Class\".ID, "
2221 	                                              "(SELECT Uri FROM Resource WHERE ID = \"rdfs:Class\".ID), "
2222 	                                              "\"tracker:notify\" "
2223 	                                              "FROM \"rdfs:Class\" ORDER BY ID");
2224 
2225 	if (stmt) {
2226 		cursor = tracker_db_statement_start_cursor (stmt, &internal_error);
2227 		g_object_unref (stmt);
2228 	}
2229 
2230 	if (cursor) {
2231 		while (tracker_db_cursor_iter_next (cursor, NULL, &internal_error)) {
2232 			TrackerClass *class;
2233 			const gchar  *uri;
2234 			gint          id;
2235 			GValue        value = { 0 };
2236 			gboolean      notify;
2237 
2238 			class = tracker_class_new (FALSE);
2239 
2240 			id = tracker_db_cursor_get_int (cursor, 0);
2241 			uri = tracker_db_cursor_get_string (cursor, 1, NULL);
2242 
2243 			tracker_db_cursor_get_value (cursor, 2, &value);
2244 
2245 			if (G_VALUE_TYPE (&value) != 0) {
2246 				notify = (g_value_get_int64 (&value) == 1);
2247 				g_value_unset (&value);
2248 			} else {
2249 				/* NULL */
2250 				notify = FALSE;
2251 			}
2252 
2253 			tracker_class_set_db_schema_changed (class, FALSE);
2254 			tracker_class_set_is_new (class, FALSE);
2255 			tracker_class_set_uri (class, uri);
2256 			tracker_class_set_notify (class, notify);
2257 
2258 			class_add_super_classes_from_db (iface, class);
2259 
2260 			/* We do this later, we first need to load the properties too
2261 			   class_add_domain_indexes_from_db (iface, class); */
2262 
2263 			tracker_ontologies_add_class (class);
2264 			tracker_ontologies_add_id_uri_pair (id, uri);
2265 			tracker_class_set_id (class, id);
2266 
2267 			g_object_unref (class);
2268 		}
2269 
2270 		g_object_unref (cursor);
2271 		cursor = NULL;
2272 	}
2273 
2274 	if (internal_error) {
2275 		g_propagate_error (error, internal_error);
2276 		return;
2277 	}
2278 
2279 	stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &internal_error,
2280 	                                              "SELECT \"rdf:Property\".ID, (SELECT Uri FROM Resource WHERE ID = \"rdf:Property\".ID), "
2281 	                                              "(SELECT Uri FROM Resource WHERE ID = \"rdfs:domain\"), "
2282 	                                              "(SELECT Uri FROM Resource WHERE ID = \"rdfs:range\"), "
2283 	                                              "\"nrl:maxCardinality\", "
2284 	                                              "\"tracker:indexed\", "
2285 	                                              "(SELECT Uri FROM Resource WHERE ID = \"tracker:secondaryIndex\"), "
2286 	                                              "\"tracker:fulltextIndexed\", "
2287 	                                              "\"tracker:transient\", "
2288 	                                              "\"tracker:writeback\", "
2289 	                                              "(SELECT 1 FROM \"rdfs:Resource_rdf:type\" WHERE ID = \"rdf:Property\".ID AND "
2290 	                                              "\"rdf:type\" = (SELECT ID FROM Resource WHERE Uri = '" NRL_INVERSE_FUNCTIONAL_PROPERTY "')), "
2291 	                                              "\"tracker:forceJournal\", "
2292 	                                              "\"tracker:defaultValue\" "
2293 	                                              "FROM \"rdf:Property\" ORDER BY ID");
2294 
2295 	if (stmt) {
2296 		cursor = tracker_db_statement_start_cursor (stmt, &internal_error);
2297 		g_object_unref (stmt);
2298 	}
2299 
2300 	if (cursor) {
2301 		while (tracker_db_cursor_iter_next (cursor, NULL, &internal_error)) {
2302 			GValue value = { 0 };
2303 			TrackerProperty *property;
2304 			const gchar     *uri, *domain_uri, *range_uri, *secondary_index_uri, *default_value;
2305 			gboolean         multi_valued, indexed, fulltext_indexed;
2306 			gboolean         transient, is_inverse_functional_property;
2307 			gboolean         writeback, force_journal;
2308 			gint             id;
2309 
2310 			property = tracker_property_new (FALSE);
2311 
2312 			id = tracker_db_cursor_get_int (cursor, 0);
2313 			uri = tracker_db_cursor_get_string (cursor, 1, NULL);
2314 			domain_uri = tracker_db_cursor_get_string (cursor, 2, NULL);
2315 			range_uri = tracker_db_cursor_get_string (cursor, 3, NULL);
2316 
2317 			tracker_db_cursor_get_value (cursor, 4, &value);
2318 
2319 			if (G_VALUE_TYPE (&value) != 0) {
2320 				multi_valued = (g_value_get_int64 (&value) > 1);
2321 				g_value_unset (&value);
2322 			} else {
2323 				/* nrl:maxCardinality not set
2324 				   not limited to single value */
2325 				multi_valued = TRUE;
2326 			}
2327 
2328 			tracker_db_cursor_get_value (cursor, 5, &value);
2329 
2330 			if (G_VALUE_TYPE (&value) != 0) {
2331 				indexed = (g_value_get_int64 (&value) == 1);
2332 				g_value_unset (&value);
2333 			} else {
2334 				/* NULL */
2335 				indexed = FALSE;
2336 			}
2337 
2338 			secondary_index_uri = tracker_db_cursor_get_string (cursor, 6, NULL);
2339 
2340 			tracker_db_cursor_get_value (cursor, 7, &value);
2341 
2342 			if (G_VALUE_TYPE (&value) != 0) {
2343 				fulltext_indexed = (g_value_get_int64 (&value) == 1);
2344 				g_value_unset (&value);
2345 			} else {
2346 				/* NULL */
2347 				fulltext_indexed = FALSE;
2348 			}
2349 
2350 			tracker_db_cursor_get_value (cursor, 8, &value);
2351 
2352 			if (G_VALUE_TYPE (&value) != 0) {
2353 				transient = (g_value_get_int64 (&value) == 1);
2354 				g_value_unset (&value);
2355 			} else {
2356 				/* NULL */
2357 				transient = FALSE;
2358 			}
2359 
2360 			/* tracker:writeback column */
2361 			tracker_db_cursor_get_value (cursor, 9, &value);
2362 
2363 			if (G_VALUE_TYPE (&value) != 0) {
2364 				writeback = (g_value_get_int64 (&value) == 1);
2365 				g_value_unset (&value);
2366 			} else {
2367 				/* NULL */
2368 				writeback = FALSE;
2369 			}
2370 
2371 			/* NRL_INVERSE_FUNCTIONAL_PROPERTY column */
2372 			tracker_db_cursor_get_value (cursor, 10, &value);
2373 
2374 			if (G_VALUE_TYPE (&value) != 0) {
2375 				is_inverse_functional_property = TRUE;
2376 				g_value_unset (&value);
2377 			} else {
2378 				/* NULL */
2379 				is_inverse_functional_property = FALSE;
2380 			}
2381 
2382 			/* tracker:forceJournal column */
2383 			tracker_db_cursor_get_value (cursor, 11, &value);
2384 
2385 			if (G_VALUE_TYPE (&value) != 0) {
2386 				force_journal = (g_value_get_int64 (&value) == 1);
2387 				g_value_unset (&value);
2388 			} else {
2389 				/* NULL */
2390 				force_journal = TRUE;
2391 			}
2392 
2393 			default_value = tracker_db_cursor_get_string (cursor, 12, NULL);
2394 
2395 			tracker_property_set_is_new_domain_index (property, tracker_ontologies_get_class_by_uri (domain_uri), FALSE);
2396 			tracker_property_set_is_new (property, FALSE);
2397 			tracker_property_set_transient (property, transient);
2398 			tracker_property_set_uri (property, uri);
2399 			tracker_property_set_id (property, id);
2400 			tracker_property_set_domain (property, tracker_ontologies_get_class_by_uri (domain_uri));
2401 			tracker_property_set_range (property, tracker_ontologies_get_class_by_uri (range_uri));
2402 			tracker_property_set_multiple_values (property, multi_valued);
2403 			tracker_property_set_indexed (property, indexed);
2404 			tracker_property_set_default_value (property, default_value);
2405 			tracker_property_set_force_journal (property, force_journal);
2406 
2407 			tracker_property_set_db_schema_changed (property, FALSE);
2408 			tracker_property_set_writeback (property, writeback);
2409 
2410 			if (secondary_index_uri) {
2411 				tracker_property_set_secondary_index (property, tracker_ontologies_get_property_by_uri (secondary_index_uri));
2412 			}
2413 
2414 			tracker_property_set_fulltext_indexed (property, fulltext_indexed);
2415 			tracker_property_set_is_inverse_functional_property (property, is_inverse_functional_property);
2416 
2417 			/* super properties are only used in updates, never for queries */
2418 			if ((tracker_db_manager_get_flags (NULL, NULL) & TRACKER_DB_MANAGER_READONLY) == 0) {
2419 				property_add_super_properties_from_db (iface, property);
2420 			}
2421 
2422 			tracker_ontologies_add_property (property);
2423 			tracker_ontologies_add_id_uri_pair (id, uri);
2424 
2425 			g_object_unref (property);
2426 
2427 		}
2428 
2429 		g_object_unref (cursor);
2430 		cursor = NULL;
2431 	}
2432 
2433 	/* Now that the properties are loaded we can do this foreach class */
2434 	classes = tracker_ontologies_get_classes (&n_classes);
2435 	for (i = 0; i < n_classes; i++) {
2436 		class_add_domain_indexes_from_db (iface, classes[i]);
2437 	}
2438 
2439 	if (internal_error) {
2440 		g_propagate_error (error, internal_error);
2441 		return;
2442 	}
2443 }
2444 
2445 static void
2446 insert_uri_in_resource_table (TrackerDBInterface  *iface,
2447                               const gchar         *uri,
2448                               gint                 id,
2449                               GError             **error)
2450 {
2451 	TrackerDBStatement *stmt;
2452 	GError *internal_error = NULL;
2453 
2454 	stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE,
2455 	                                              &internal_error,
2456 	                                              "INSERT OR IGNORE "
2457 	                                              "INTO Resource "
2458 	                                              "(ID, Uri) "
2459 	                                              "VALUES (?, ?)");
2460 	if (internal_error) {
2461 		g_propagate_error (error, internal_error);
2462 		return;
2463 	}
2464 
2465 	tracker_db_statement_bind_int (stmt, 0, id);
2466 	tracker_db_statement_bind_text (stmt, 1, uri);
2467 	tracker_db_statement_execute (stmt, &internal_error);
2468 
2469 	if (internal_error) {
2470 		g_object_unref (stmt);
2471 		g_propagate_error (error, internal_error);
2472 		return;
2473 	}
2474 
2475 #ifndef DISABLE_JOURNAL
2476 	if (!in_journal_replay) {
2477 		tracker_db_journal_append_resource (id, uri);
2478 	}
2479 #endif /* DISABLE_JOURNAL */
2480 
2481 	g_object_unref (stmt);
2482 
2483 }
2484 
2485 static void
2486 range_change_for (TrackerProperty *property,
2487                   GString         *in_col_sql,
2488                   GString         *sel_col_sql,
2489                   const gchar     *field_name)
2490 {
2491 	/* TODO: TYPE_RESOURCE and TYPE_DATETIME are completely unhandled atm, we
2492 	 * should forbid conversion from anything to resource or datetime in error
2493 	 * handling earlier */
2494 
2495 	g_string_append_printf (in_col_sql, ", \"%s\", \"%s:graph\"",
2496 	                        field_name, field_name);
2497 
2498 	if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_INTEGER ||
2499 	    tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DOUBLE) {
2500 			g_string_append_printf (sel_col_sql, ", \"%s\" + 0, \"%s:graph\"",
2501 			                        field_name, field_name);
2502 	} else if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME) {
2503 
2504 		/* TODO (see above) */
2505 
2506 		g_string_append_printf (sel_col_sql, ", \"%s\", \"%s:graph\"",
2507 		                        field_name, field_name);
2508 
2509 		g_string_append_printf (in_col_sql, ", \"%s:localDate\", \"%s:localTime\"",
2510 		                        tracker_property_get_name (property),
2511 		                        tracker_property_get_name (property));
2512 
2513 		g_string_append_printf (sel_col_sql, ", \"%s:localDate\", \"%s:localTime\"",
2514 		                        tracker_property_get_name (property),
2515 		                        tracker_property_get_name (property));
2516 
2517 	} else if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_BOOLEAN) {
2518 		g_string_append_printf (sel_col_sql, ", \"%s\" != 0, \"%s:graph\"",
2519 		                        field_name, field_name);
2520 	} else {
2521 		g_string_append_printf (sel_col_sql, ", \"%s\", \"%s:graph\"",
2522 		                        field_name, field_name);
2523 	}
2524 }
2525 
2526 static void
2527 create_decomposed_metadata_property_table (TrackerDBInterface *iface,
2528                                            TrackerProperty    *property,
2529                                            const gchar        *service_name,
2530                                            TrackerClass       *service,
2531                                            const gchar       **sql_type_for_single_value,
2532                                            gboolean            in_update,
2533                                            gboolean            in_change,
2534                                            GError            **error)
2535 {
2536 	GError *internal_error = NULL;
2537 	const char *field_name;
2538 	const char *sql_type;
2539 	gboolean    not_single;
2540 
2541 	field_name = tracker_property_get_name (property);
2542 
2543 	not_single = !sql_type_for_single_value;
2544 
2545 	switch (tracker_property_get_data_type (property)) {
2546 	case TRACKER_PROPERTY_TYPE_STRING:
2547 		sql_type = "TEXT";
2548 		break;
2549 	case TRACKER_PROPERTY_TYPE_INTEGER:
2550 	case TRACKER_PROPERTY_TYPE_BOOLEAN:
2551 	case TRACKER_PROPERTY_TYPE_DATE:
2552 	case TRACKER_PROPERTY_TYPE_DATETIME:
2553 	case TRACKER_PROPERTY_TYPE_RESOURCE:
2554 		sql_type = "INTEGER";
2555 		break;
2556 	case TRACKER_PROPERTY_TYPE_DOUBLE:
2557 		sql_type = "REAL";
2558 		break;
2559 	default:
2560 		sql_type = "";
2561 		break;
2562 	}
2563 
2564 	if (!in_update || (in_update && (tracker_property_get_is_new (property) ||
2565 	                                 tracker_property_get_is_new_domain_index (property, service) ||
2566 	                                 tracker_property_get_db_schema_changed (property)))) {
2567 		if (not_single || tracker_property_get_multiple_values (property)) {
2568 			GString *sql = NULL;
2569 			GString *in_col_sql = NULL;
2570 			GString *sel_col_sql = NULL;
2571 
2572 			/* multiple values */
2573 
2574 			if (in_update) {
2575 				g_debug ("Altering database for class '%s' property '%s': multi value",
2576 				         service_name, field_name);
2577 			}
2578 
2579 			if (in_change && !tracker_property_get_is_new (property)) {
2580 				g_debug ("Drop index: DROP INDEX IF EXISTS \"%s_%s_ID\"\nRename: ALTER TABLE \"%s_%s\" RENAME TO \"%s_%s_TEMP\"",
2581 				         service_name, field_name, service_name, field_name,
2582 				         service_name, field_name);
2583 
2584 				tracker_db_interface_execute_query (iface, &internal_error,
2585 				                                    "DROP INDEX IF EXISTS \"%s_%s_ID\"",
2586 				                                    service_name,
2587 				                                    field_name);
2588 
2589 				if (internal_error) {
2590 					g_propagate_error (error, internal_error);
2591 					goto error_out;
2592 				}
2593 
2594 				tracker_db_interface_execute_query (iface, &internal_error,
2595 				                                    "ALTER TABLE \"%s_%s\" RENAME TO \"%s_%s_TEMP\"",
2596 				                                    service_name, field_name, service_name, field_name);
2597 
2598 				if (internal_error) {
2599 					g_propagate_error (error, internal_error);
2600 					goto error_out;
2601 				}
2602 			}
2603 
2604 			sql = g_string_new ("");
2605 			g_string_append_printf (sql, "CREATE TABLE \"%s_%s\" ("
2606 			                             "ID INTEGER NOT NULL, "
2607 			                             "\"%s\" %s NOT NULL, "
2608 			                             "\"%s:graph\" INTEGER",
2609 			                             service_name,
2610 			                             field_name,
2611 			                             field_name,
2612 			                             sql_type,
2613 			                             field_name);
2614 
2615 			if (in_change && !tracker_property_get_is_new (property)) {
2616 				in_col_sql = g_string_new ("ID");
2617 				sel_col_sql = g_string_new ("ID");
2618 
2619 				range_change_for (property, in_col_sql, sel_col_sql, field_name);
2620 			}
2621 
2622 			if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME) {
2623 				/* xsd:dateTime is stored in three columns:
2624 				 * universal time, local date, local time of day */
2625 				g_string_append_printf (sql,
2626 				                        ", \"%s:localDate\" INTEGER NOT NULL"
2627 				                        ", \"%s:localTime\" INTEGER NOT NULL",
2628 				                        tracker_property_get_name (property),
2629 				                        tracker_property_get_name (property));
2630 			}
2631 
2632 			tracker_db_interface_execute_query (iface, &internal_error,
2633 			                                    "%s)", sql->str);
2634 
2635 			if (internal_error) {
2636 				g_propagate_error (error, internal_error);
2637 				goto error_out;
2638 			}
2639 
2640 			/* multiple values */
2641 			if (tracker_property_get_indexed (property)) {
2642 				/* use different UNIQUE index for properties whose
2643 				 * value should be indexed to minimize index size */
2644 				set_index_for_multi_value_property (iface, service_name, field_name, TRUE, TRUE,
2645 				                                    &internal_error);
2646 				if (internal_error) {
2647 					g_propagate_error (error, internal_error);
2648 					goto error_out;
2649 				}
2650 			} else {
2651 				set_index_for_multi_value_property (iface, service_name, field_name, FALSE, TRUE,
2652 				                                    &internal_error);
2653 				/* we still have to include the property value in
2654 				 * the unique index for proper constraints */
2655 				if (internal_error) {
2656 					g_propagate_error (error, internal_error);
2657 					goto error_out;
2658 				}
2659 			}
2660 
2661 			if (in_change && !tracker_property_get_is_new (property) && in_col_sql && sel_col_sql) {
2662 				gchar *query;
2663 
2664 				query = g_strdup_printf ("INSERT INTO \"%s_%s\"(%s) "
2665 				                         "SELECT %s FROM \"%s_%s_TEMP\"",
2666 				                         service_name, field_name, in_col_sql->str,
2667 				                         sel_col_sql->str, service_name, field_name);
2668 
2669 				tracker_db_interface_execute_query (iface, &internal_error, "%s", query);
2670 
2671 				if (internal_error) {
2672 					g_free (query);
2673 					g_propagate_error (error, internal_error);
2674 					goto error_out;
2675 				}
2676 
2677 				g_free (query);
2678 				tracker_db_interface_execute_query (iface, &internal_error, "DROP TABLE \"%s_%s_TEMP\"",
2679 				                                    service_name, field_name);
2680 
2681 				if (internal_error) {
2682 					g_propagate_error (error, internal_error);
2683 					goto error_out;
2684 				}
2685 			}
2686 
2687 			/* multiple values */
2688 			if (tracker_property_get_indexed (property)) {
2689 				/* use different UNIQUE index for properties whose
2690 				 * value should be indexed to minimize index size */
2691 				set_index_for_multi_value_property (iface, service_name, field_name, TRUE, TRUE,
2692 				                                    &internal_error);
2693 				if (internal_error) {
2694 					g_propagate_error (error, internal_error);
2695 					goto error_out;
2696 				}
2697 			} else {
2698 				set_index_for_multi_value_property (iface, service_name, field_name, FALSE, TRUE,
2699 				                                    &internal_error);
2700 				if (internal_error) {
2701 					g_propagate_error (error, internal_error);
2702 					goto error_out;
2703 				}
2704 				/* we still have to include the property value in
2705 				 * the unique index for proper constraints */
2706 			}
2707 
2708 			error_out:
2709 
2710 			if (sql) {
2711 				g_string_free (sql, TRUE);
2712 			}
2713 
2714 			if (sel_col_sql) {
2715 				g_string_free (sel_col_sql, TRUE);
2716 			}
2717 
2718 			if (in_col_sql) {
2719 				g_string_free (in_col_sql, TRUE);
2720 			}
2721 		} else if (sql_type_for_single_value) {
2722 			*sql_type_for_single_value = sql_type;
2723 		}
2724 	}
2725 }
2726 
2727 static gboolean
2728 is_a_domain_index (TrackerProperty **domain_indexes, TrackerProperty *property)
2729 {
2730 	while (*domain_indexes) {
2731 
2732 		if (*domain_indexes == property) {
2733 			return TRUE;
2734 		}
2735 
2736 		domain_indexes++;
2737 	}
2738 
2739 	return FALSE;
2740 }
2741 
2742 static void
2743 copy_from_domain_to_domain_index (TrackerDBInterface  *iface,
2744                                   TrackerProperty     *domain_index,
2745                                   const gchar         *column_name,
2746                                   const gchar         *column_suffix,
2747                                   TrackerClass        *dest_domain,
2748                                   GError             **error)
2749 {
2750 	GError *internal_error = NULL;
2751 	TrackerClass *source_domain;
2752 	const gchar *source_name, *dest_name;
2753 	gchar *query;
2754 
2755 	source_domain = tracker_property_get_domain (domain_index);
2756 	source_name = tracker_class_get_name (source_domain);
2757 	dest_name = tracker_class_get_name (dest_domain);
2758 
2759 	query = g_strdup_printf ("UPDATE \"%s\" SET \"%s%s\"=("
2760 	                         "SELECT \"%s%s\" FROM \"%s\" "
2761 	                         "WHERE \"%s\".ID = \"%s\".ID)",
2762 	                         dest_name,
2763 	                         column_name,
2764 	                         column_suffix ? column_suffix : "",
2765 	                         column_name,
2766 	                         column_suffix ? column_suffix : "",
2767 	                         source_name,
2768 	                         source_name,
2769 	                         dest_name);
2770 
2771 	g_debug ("Copying: '%s'", query);
2772 
2773 	tracker_db_interface_execute_query (iface, &internal_error, "%s", query);
2774 
2775 	if (internal_error) {
2776 		g_propagate_error (error, internal_error);
2777 	}
2778 
2779 	g_free (query);
2780 }
2781 
2782 typedef struct {
2783 	TrackerProperty *prop;
2784 	const gchar *field_name;
2785 	const gchar *suffix;
2786 } ScheduleCopy;
2787 
2788 static void
2789 schedule_copy (GPtrArray *schedule,
2790                TrackerProperty *prop,
2791                const gchar *field_name,
2792                const gchar *suffix)
2793 {
2794 	ScheduleCopy *sched = g_new0 (ScheduleCopy, 1);
2795 	sched->prop = prop;
2796 	sched->field_name = field_name,
2797 	sched->suffix = suffix;
2798 	g_ptr_array_add (schedule, sched);
2799 }
2800 
2801 static void
2802 create_decomposed_metadata_tables (TrackerDBInterface  *iface,
2803                                    TrackerClass        *service,
2804                                    gboolean             in_update,
2805                                    gboolean             in_change,
2806                                    GError             **error)
2807 {
2808 	const char       *service_name;
2809 	GString          *create_sql = NULL;
2810 	GString          *in_col_sql = NULL;
2811 	GString          *sel_col_sql = NULL;
2812 	TrackerProperty **properties, *property, **domain_indexes;
2813 	GSList           *class_properties = NULL, *field_it;
2814 	gboolean          main_class;
2815 	gint              i, n_props;
2816 	gboolean          in_alter = in_update;
2817 	GError           *internal_error = NULL;
2818 	GPtrArray        *copy_schedule = NULL;
2819 
2820 	g_return_if_fail (TRACKER_IS_CLASS (service));
2821 
2822 	service_name = tracker_class_get_name (service);
2823 
2824 	g_return_if_fail (service_name != NULL);
2825 
2826 	main_class = (strcmp (service_name, "rdfs:Resource") == 0);
2827 
2828 	if (g_str_has_prefix (service_name, "xsd:")) {
2829 		/* xsd classes do not derive from rdfs:Resource and do not need separate tables */
2830 		return;
2831 	}
2832 
2833 	if (in_change) {
2834 		g_debug ("Rename: ALTER TABLE \"%s\" RENAME TO \"%s_TEMP\"", service_name, service_name);
2835 		tracker_db_interface_execute_query (iface, &internal_error,
2836 		                                    "ALTER TABLE \"%s\" RENAME TO \"%s_TEMP\"",
2837 		                                    service_name, service_name);
2838 		in_col_sql = g_string_new ("ID");
2839 		sel_col_sql = g_string_new ("ID");
2840 		if (internal_error) {
2841 			g_propagate_error (error, internal_error);
2842 			goto error_out;
2843 		}
2844 	}
2845 
2846 	if (in_change || !in_update || (in_update && tracker_class_get_is_new (service))) {
2847 		if (in_update)
2848 			g_debug ("Altering database with new class '%s' (create)", service_name);
2849 		in_alter = FALSE;
2850 		create_sql = g_string_new ("");
2851 		g_string_append_printf (create_sql, "CREATE TABLE \"%s\" (ID INTEGER NOT NULL PRIMARY KEY", service_name);
2852 		if (main_class) {
2853 			tracker_db_interface_execute_query (iface, &internal_error, "CREATE TABLE Resource (ID INTEGER NOT NULL PRIMARY KEY, Uri TEXT NOT NULL, UNIQUE (Uri))");
2854 			if (internal_error) {
2855 				g_propagate_error (error, internal_error);
2856 				goto error_out;
2857 			}
2858 			g_string_append (create_sql, ", Available INTEGER NOT NULL");
2859 		}
2860 	}
2861 
2862 	properties = tracker_ontologies_get_properties (&n_props);
pointer targets in passing argument 1 of 'tracker_ontologies_get_properties' differ in signedness
(emitted by gcc)
2863 domain_indexes = tracker_class_get_domain_indexes (service); 2864 2865 for (i = 0; i < n_props; i++) { 2866 gboolean is_domain_index; 2867 2868 property = properties[i]; 2869 is_domain_index = is_a_domain_index (domain_indexes, property); 2870 2871 if (tracker_property_get_domain (property) == service || is_domain_index) { 2872 gboolean put_change; 2873 const gchar *sql_type_for_single_value = NULL; 2874 const gchar *field_name; 2875 2876 create_decomposed_metadata_property_table (iface, property, 2877 service_name, 2878 service, 2879 &sql_type_for_single_value, 2880 in_update, 2881 in_change, 2882 &internal_error); 2883 2884 if (internal_error) { 2885 g_propagate_error (error, internal_error); 2886 goto error_out; 2887 } 2888 2889 field_name = tracker_property_get_name (property); 2890 2891 if (sql_type_for_single_value) { 2892 const gchar *default_value; 2893 2894 /* single value */ 2895 2896 default_value = tracker_property_get_default_value (property); 2897 2898 if (in_update) { 2899 g_debug ("%sAltering database for class '%s' property '%s': single value (%s)", 2900 in_alter ? "" : " ", 2901 service_name, 2902 field_name, 2903 in_alter ? "alter" : "create"); 2904 } 2905 2906 if (!in_alter) { 2907 put_change = TRUE; 2908 class_properties = g_slist_prepend (class_properties, property); 2909 2910 g_string_append_printf (create_sql, ", \"%s\" %s", 2911 field_name, 2912 sql_type_for_single_value); 2913 2914 if (!copy_schedule) { 2915 copy_schedule = g_ptr_array_new_with_free_func (g_free); 2916 } 2917 2918 if (is_domain_index && tracker_property_get_is_new_domain_index (property, service)) { 2919 schedule_copy (copy_schedule, property, field_name, NULL); 2920 } 2921 2922 if (g_ascii_strcasecmp (sql_type_for_single_value, "TEXT") == 0) { 2923 g_string_append (create_sql, " COLLATE " TRACKER_COLLATION_NAME); 2924 } 2925 2926 /* add DEFAULT in case that the ontology specifies a default value, 2927 assumes that default values never contain quotes */ 2928 if (default_value != NULL) { 2929 g_string_append_printf (create_sql, " DEFAULT '%s'", default_value); 2930 } 2931 2932 if (tracker_property_get_is_inverse_functional_property (property)) { 2933 g_string_append (create_sql, " UNIQUE"); 2934 } 2935 2936 g_string_append_printf (create_sql, ", \"%s:graph\" INTEGER", 2937 field_name); 2938 2939 if (is_domain_index && tracker_property_get_is_new_domain_index (property, service)) { 2940 schedule_copy (copy_schedule, property, field_name, ":graph"); 2941 } 2942 2943 if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME) { 2944 /* xsd:dateTime is stored in three columns: 2945 * universal time, local date, local time of day */ 2946 g_string_append_printf (create_sql, ", \"%s:localDate\" INTEGER, \"%s:localTime\" INTEGER", 2947 tracker_property_get_name (property), 2948 tracker_property_get_name (property)); 2949 2950 if (is_domain_index && tracker_property_get_is_new_domain_index (property, service)) { 2951 schedule_copy (copy_schedule, property, field_name, ":localTime"); 2952 schedule_copy (copy_schedule, property, field_name, ":localDate"); 2953 } 2954 2955 } 2956 2957 } else if ((!is_domain_index && tracker_property_get_is_new (property)) || 2958 (is_domain_index && tracker_property_get_is_new_domain_index (property, service))) { 2959 GString *alter_sql = NULL; 2960 2961 put_change = FALSE; 2962 class_properties = g_slist_prepend (class_properties, property); 2963 2964 alter_sql = g_string_new ("ALTER TABLE "); 2965 g_string_append_printf (alter_sql, "\"%s\" ADD COLUMN \"%s\" %s", 2966 service_name, 2967 field_name, 2968 sql_type_for_single_value); 2969 2970 if (g_ascii_strcasecmp (sql_type_for_single_value, "TEXT") == 0) { 2971 g_string_append (alter_sql, " COLLATE " TRACKER_COLLATION_NAME); 2972 } 2973 2974 /* add DEFAULT in case that the ontology specifies a default value, 2975 assumes that default values never contain quotes */ 2976 if (default_value != NULL) { 2977 g_string_append_printf (alter_sql, " DEFAULT '%s'", default_value); 2978 } 2979 2980 if (tracker_property_get_is_inverse_functional_property (property)) { 2981 g_string_append (alter_sql, " UNIQUE"); 2982 } 2983 2984 g_debug ("Altering: '%s'", alter_sql->str); 2985 tracker_db_interface_execute_query (iface, &internal_error, "%s", alter_sql->str); 2986 if (internal_error) { 2987 g_string_free (alter_sql, TRUE); 2988 g_propagate_error (error, internal_error); 2989 goto error_out; 2990 } else if (is_domain_index) { 2991 copy_from_domain_to_domain_index (iface, property, 2992 field_name, NULL, 2993 service, 2994 &internal_error); 2995 if (internal_error) { 2996 g_string_free (alter_sql, TRUE); 2997 g_propagate_error (error, internal_error); 2998 goto error_out; 2999 } 3000 3001 /* This is implicit for all domain-specific-indices */ 3002 set_index_for_single_value_property (iface, service_name, 3003 field_name, TRUE, 3004 &internal_error); 3005 if (internal_error) { 3006 g_string_free (alter_sql, TRUE); 3007 g_propagate_error (error, internal_error); 3008 goto error_out; 3009 } 3010 } 3011 3012 g_string_free (alter_sql, TRUE); 3013 3014 alter_sql = g_string_new ("ALTER TABLE "); 3015 g_string_append_printf (alter_sql, "\"%s\" ADD COLUMN \"%s:graph\" INTEGER", 3016 service_name, 3017 field_name); 3018 g_debug ("Altering: '%s'", alter_sql->str); 3019 tracker_db_interface_execute_query (iface, &internal_error, 3020 "%s", alter_sql->str); 3021 if (internal_error) { 3022 g_string_free (alter_sql, TRUE); 3023 g_propagate_error (error, internal_error); 3024 goto error_out; 3025 } else if (is_domain_index) { 3026 copy_from_domain_to_domain_index (iface, property, 3027 field_name, ":graph", 3028 service, 3029 &internal_error); 3030 if (internal_error) { 3031 g_string_free (alter_sql, TRUE); 3032 g_propagate_error (error, internal_error); 3033 goto error_out; 3034 } 3035 } 3036 3037 g_string_free (alter_sql, TRUE); 3038 3039 if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME) { 3040 alter_sql = g_string_new ("ALTER TABLE "); 3041 g_string_append_printf (alter_sql, "\"%s\" ADD COLUMN \"%s:localDate\" INTEGER", 3042 service_name, 3043 field_name); 3044 g_debug ("Altering: '%s'", alter_sql->str); 3045 tracker_db_interface_execute_query (iface, &internal_error, 3046 "%s", alter_sql->str); 3047 3048 if (internal_error) { 3049 g_string_free (alter_sql, TRUE); 3050 g_propagate_error (error, internal_error); 3051 goto error_out; 3052 } else if (is_domain_index) { 3053 copy_from_domain_to_domain_index (iface, property, 3054 field_name, ":localDate", 3055 service, 3056 &internal_error); 3057 if (internal_error) { 3058 g_string_free (alter_sql, TRUE); 3059 g_propagate_error (error, internal_error); 3060 goto error_out; 3061 } 3062 } 3063 3064 g_string_free (alter_sql, TRUE); 3065 3066 alter_sql = g_string_new ("ALTER TABLE "); 3067 g_string_append_printf (alter_sql, "\"%s\" ADD COLUMN \"%s:localTime\" INTEGER", 3068 service_name, 3069 field_name); 3070 g_debug ("Altering: '%s'", alter_sql->str); 3071 tracker_db_interface_execute_query (iface, &internal_error, 3072 "%s", alter_sql->str); 3073 if (internal_error) { 3074 g_string_free (alter_sql, TRUE); 3075 g_propagate_error (error, internal_error); 3076 goto error_out; 3077 } else if (is_domain_index) { 3078 copy_from_domain_to_domain_index (iface, property, 3079 field_name, ":localTime", 3080 service, 3081 &internal_error); 3082 if (internal_error) { 3083 g_string_free (alter_sql, TRUE); 3084 g_propagate_error (error, internal_error); 3085 goto error_out; 3086 } 3087 } 3088 g_string_free (alter_sql, TRUE); 3089 } 3090 } else { 3091 put_change = TRUE; 3092 } 3093 3094 if (in_change && put_change) { 3095 range_change_for (property, in_col_sql, sel_col_sql, field_name); 3096 } 3097 } 3098 } 3099 } 3100 3101 if (create_sql) { 3102 g_string_append (create_sql, ")"); 3103 g_debug ("Creating: '%s'", create_sql->str); 3104 tracker_db_interface_execute_query (iface, &internal_error, 3105 "%s", create_sql->str); 3106 3107 if (internal_error) { 3108 g_propagate_error (error, internal_error); 3109 goto error_out; 3110 } 3111 } 3112 3113 /* create index for single-valued fields */ 3114 for (field_it = class_properties; field_it != NULL; field_it = field_it->next) { 3115 TrackerProperty *field, *secondary_index; 3116 const char *field_name; 3117 gboolean is_domain_index; 3118 3119 field = field_it->data; 3120 3121 /* This is implicit for all domain-specific-indices */ 3122 is_domain_index = is_a_domain_index (domain_indexes, field); 3123 3124 if (!tracker_property_get_multiple_values (field) 3125 && (tracker_property_get_indexed (field) || is_domain_index)) { 3126 3127 field_name = tracker_property_get_name (field); 3128 3129 secondary_index = tracker_property_get_secondary_index (field); 3130 if (secondary_index == NULL) { 3131 set_index_for_single_value_property (iface, service_name, 3132 field_name, TRUE, 3133 &internal_error); 3134 if (internal_error) { 3135 g_propagate_error (error, internal_error); 3136 goto error_out; 3137 } 3138 } else { 3139 set_secondary_index_for_single_value_property (iface, service_name, field_name, 3140 tracker_property_get_name (secondary_index), 3141 TRUE, &internal_error); 3142 if (internal_error) { 3143 g_propagate_error (error, internal_error); 3144 goto error_out; 3145 } 3146 } 3147 } 3148 } 3149 3150 if (in_change && sel_col_sql && in_col_sql) { 3151 gchar *query; 3152 3153 query = g_strdup_printf ("INSERT INTO \"%s\"(%s) " 3154 "SELECT %s FROM \"%s_TEMP\"", 3155 service_name, in_col_sql->str, 3156 sel_col_sql->str, service_name); 3157 3158 g_debug ("Copy: %s", query); 3159 3160 tracker_db_interface_execute_query (iface, &internal_error, "%s", query); 3161 3162 if (internal_error) { 3163 g_propagate_error (error, internal_error); 3164 goto error_out; 3165 } 3166 3167 g_free (query); 3168 g_debug ("Rename (drop): DROP TABLE \"%s_TEMP\"", service_name); 3169 tracker_db_interface_execute_query (iface, &internal_error, 3170 "DROP TABLE \"%s_TEMP\"", service_name); 3171 3172 if (internal_error) { 3173 g_propagate_error (error, internal_error); 3174 goto error_out; 3175 } 3176 } 3177 3178 if (copy_schedule) { 3179 guint i; 3180 for (i = 0; i < copy_schedule->len; i++) { 3181 ScheduleCopy *sched = g_ptr_array_index (copy_schedule, i); 3182 copy_from_domain_to_domain_index (iface, sched->prop, 3183 sched->field_name, sched->suffix, 3184 service, 3185 &internal_error); 3186 3187 if (internal_error) { 3188 g_propagate_error (error, internal_error); 3189 break; 3190 } 3191 } 3192 } 3193 3194 error_out: 3195 3196 if (copy_schedule) { 3197 g_ptr_array_free (copy_schedule, TRUE); 3198 } 3199 3200 if (create_sql) { 3201 g_string_free (create_sql, TRUE); 3202 } 3203 3204 g_slist_free (class_properties); 3205 3206 if (in_col_sql) { 3207 g_string_free (in_col_sql, TRUE); 3208 } 3209 3210 if (sel_col_sql) { 3211 g_string_free (sel_col_sql, TRUE); 3212 } 3213 } 3214 3215 static void 3216 clean_decomposed_transient_metadata (TrackerDBInterface *iface) 3217 { 3218 TrackerProperty **properties; 3219 TrackerProperty *property; 3220 gint i, n_props; 3221 3222 properties = tracker_ontologies_get_properties (&n_props);
pointer targets in passing argument 1 of 'tracker_ontologies_get_properties' differ in signedness
(emitted by gcc)
3223 3224 for (i = 0; i < n_props; i++) { 3225 property = properties[i]; 3226 3227 if (tracker_property_get_transient (property)) { 3228 TrackerClass *domain; 3229 const gchar *service_name; 3230 const gchar *prop_name; 3231 GError *error = NULL; 3232 3233 domain = tracker_property_get_domain (property); 3234 service_name = tracker_class_get_name (domain); 3235 prop_name = tracker_property_get_name (property); 3236 3237 if (tracker_property_get_multiple_values (property)) { 3238 /* create the disposable table */ 3239 tracker_db_interface_execute_query (iface, &error, "DELETE FROM \"%s_%s\"", 3240 service_name, 3241 prop_name); 3242 } else { 3243 /* create the disposable table */ 3244 tracker_db_interface_execute_query (iface, &error, "UPDATE \"%s\" SET \"%s\" = NULL", 3245 service_name, 3246 prop_name); 3247 } 3248 3249 if (error) { 3250 g_critical ("Cleaning transient propery '%s:%s' failed: %s", 3251 service_name, 3252 prop_name, 3253 error->message); 3254 g_error_free (error); 3255 } 3256 } 3257 } 3258 } 3259 3260 static void 3261 tracker_data_ontology_import_finished (void) 3262 { 3263 TrackerClass **classes; 3264 TrackerProperty **properties; 3265 gint i, n_props, n_classes; 3266 3267 classes = tracker_ontologies_get_classes (&n_classes);
pointer targets in passing argument 1 of 'tracker_ontologies_get_classes' differ in signedness
(emitted by gcc)
3268 properties = tracker_ontologies_get_properties (&n_props); 3269 3270 for (i = 0; i < n_classes; i++) { 3271 tracker_class_set_is_new (classes[i], FALSE); 3272 tracker_class_set_db_schema_changed (classes[i], FALSE); 3273 } 3274 3275 for (i = 0; i < n_props; i++) { 3276 tracker_property_set_is_new_domain_index (properties[i], NULL, FALSE); 3277 tracker_property_set_is_new (properties[i], FALSE); 3278 tracker_property_set_db_schema_changed (properties[i], FALSE); 3279 } 3280 } 3281 3282 static void 3283 tracker_data_ontology_import_into_db (gboolean in_update, 3284 GError **error) 3285 { 3286 TrackerDBInterface *iface; 3287 3288 TrackerClass **classes; 3289 TrackerProperty **properties; 3290 gint i, n_props, n_classes; 3291 3292 iface = tracker_db_manager_get_db_interface (); 3293 3294 classes = tracker_ontologies_get_classes (&n_classes);
pointer targets in passing argument 1 of 'tracker_ontologies_get_classes' differ in signedness
(emitted by gcc)
3295 properties = tracker_ontologies_get_properties (&n_props); 3296 3297 /* create tables */ 3298 for (i = 0; i < n_classes; i++) { 3299 GError *internal_error = NULL; 3300 3301 /* Also !is_new classes are processed, they might have new properties */ 3302 create_decomposed_metadata_tables (iface, classes[i], in_update, 3303 tracker_class_get_db_schema_changed (classes[i]), 3304 &internal_error); 3305 3306 if (internal_error) { 3307 g_propagate_error (error, internal_error); 3308 return; 3309 } 3310 } 3311 3312 /* insert classes into rdfs:Resource table */ 3313 for (i = 0; i < n_classes; i++) { 3314 if (tracker_class_get_is_new (classes[i]) == in_update) { 3315 GError *internal_error = NULL; 3316 3317 insert_uri_in_resource_table (iface, tracker_class_get_uri (classes[i]), 3318 tracker_class_get_id (classes[i]), 3319 &internal_error); 3320 3321 if (internal_error) { 3322 g_propagate_error (error, internal_error); 3323 return; 3324 } 3325 } 3326 } 3327 3328 /* insert properties into rdfs:Resource table */ 3329 for (i = 0; i < n_props; i++) { 3330 if (tracker_property_get_is_new (properties[i]) == in_update) { 3331 GError *internal_error = NULL; 3332 3333 insert_uri_in_resource_table (iface, tracker_property_get_uri (properties[i]), 3334 tracker_property_get_id (properties[i]), 3335 &internal_error); 3336 3337 if (internal_error) { 3338 g_propagate_error (error, internal_error); 3339 return; 3340 } 3341 } 3342 } 3343 } 3344 3345 static GList* 3346 get_ontologies (gboolean test_schema, 3347 const gchar *ontologies_dir) 3348 { 3349 GList *sorted = NULL; 3350 3351 if (test_schema) { 3352 sorted = g_list_prepend (sorted, g_strdup ("12-nrl.ontology")); 3353 sorted = g_list_prepend (sorted, g_strdup ("11-rdf.ontology")); 3354 sorted = g_list_prepend (sorted, g_strdup ("10-xsd.ontology")); 3355 } else { 3356 GDir *ontologies; 3357 const gchar *conf_file; 3358 3359 ontologies = g_dir_open (ontologies_dir, 0, NULL); 3360 3361 conf_file = g_dir_read_name (ontologies); 3362 3363 /* .ontology files */ 3364 while (conf_file) { 3365 if (g_str_has_suffix (conf_file, ".ontology")) { 3366 sorted = g_list_insert_sorted (sorted, 3367 g_strdup (conf_file), 3368 (GCompareFunc) strcmp); 3369 } 3370 conf_file = g_dir_read_name (ontologies); 3371 } 3372 3373 g_dir_close (ontologies); 3374 } 3375 3376 return sorted; 3377 } 3378 3379 3380 static gint 3381 get_new_service_id (TrackerDBInterface *iface) 3382 { 3383 TrackerDBCursor *cursor = NULL; 3384 TrackerDBStatement *stmt; 3385 gint max_service_id = 0; 3386 GError *error = NULL; 3387 3388 /* Don't intermix this thing with tracker_data_update_get_new_service_id, 3389 * if you use this, know what you are doing! */ 3390 3391 iface = tracker_db_manager_get_db_interface (); 3392 3393 stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &error, 3394 "SELECT MAX(ID) AS A FROM Resource WHERE ID <= %d", TRACKER_ONTOLOGIES_MAX_ID); 3395 3396 if (stmt) { 3397 cursor = tracker_db_statement_start_cursor (stmt, &error); 3398 g_object_unref (stmt); 3399 } 3400 3401 if (cursor) { 3402 if (tracker_db_cursor_iter_next (cursor, NULL, &error)) { 3403 max_service_id = tracker_db_cursor_get_int (cursor, 0); 3404 } 3405 g_object_unref (cursor); 3406 } 3407 3408 if (error) { 3409 g_error ("Unable to get max ID, aborting: %s", error->message); 3410 } 3411 3412 return ++max_service_id; 3413 } 3414 3415 static void 3416 tracker_data_manager_recreate_indexes (TrackerBusyCallback busy_callback, 3417 gpointer busy_user_data, 3418 const gchar *busy_status, 3419 GError **error) 3420 { 3421 GError *internal_error = NULL; 3422 TrackerProperty **properties; 3423 guint n_properties; 3424 guint i; 3425 3426 properties = tracker_ontologies_get_properties (&n_properties); 3427 if (!properties) { 3428 g_critical ("Couldn't get all properties to recreate indexes"); 3429 return; 3430 } 3431 3432 g_debug ("Dropping all indexes..."); 3433 for (i = 0; i < n_properties; i++) { 3434 fix_indexed (properties [i], FALSE, &internal_error); 3435 3436 if (internal_error) { 3437 g_propagate_error (error, internal_error); 3438 return; 3439 } 3440 } 3441 3442 g_debug ("Starting index re-creation..."); 3443 for (i = 0; i < n_properties; i++) { 3444 fix_indexed (properties [i], TRUE, &internal_error); 3445 3446 if (internal_error) { 3447 g_critical ("Unable to create index for %s: %s", 3448 tracker_property_get_name (properties[i]), 3449 internal_error->message); 3450 g_clear_error (&internal_error); 3451 } 3452 3453 if (busy_callback) { 3454 busy_callback (busy_status, 3455 (gdouble) ((gdouble) i / (gdouble) n_properties), 3456 busy_user_data); 3457 } 3458 } 3459 g_debug (" Finished index re-creation..."); 3460 } 3461 3462 gboolean 3463 tracker_data_manager_reload (TrackerBusyCallback busy_callback, 3464 gpointer busy_user_data, 3465 const gchar *busy_operation, 3466 GError **error) 3467 { 3468 TrackerDBManagerFlags flags; 3469 guint select_cache_size; 3470 guint update_cache_size; 3471 gboolean is_first; 3472 gboolean status; 3473 GError *internal_error = NULL; 3474 3475 g_message ("Reloading data manager..."); 3476 /* Shutdown data manager... */ 3477 flags = tracker_db_manager_get_flags (&select_cache_size, &update_cache_size); 3478 reloading = TRUE; 3479 tracker_data_manager_shutdown (); 3480 3481 g_message (" Data manager shut down, now initializing again..."); 3482 3483 /* And initialize it again, this actually triggers index recreation. */ 3484 status = tracker_data_manager_init (flags, 3485 NULL, 3486 &is_first, 3487 TRUE, 3488 FALSE, 3489 select_cache_size, 3490 update_cache_size, 3491 busy_callback, 3492 busy_user_data, 3493 busy_operation, 3494 &internal_error); 3495 reloading = FALSE; 3496 3497 if (internal_error) { 3498 g_propagate_error (error, internal_error); 3499 } 3500 3501 g_message (" %s reloading data manager", 3502 status ? "Succeeded" : "Failed"); 3503 3504 return status; 3505 } 3506 3507 static void 3508 write_ontologies_gvdb (gboolean overwrite, 3509 GError **error) 3510 { 3511 gchar *filename; 3512 3513 filename = g_build_filename (g_get_user_cache_dir (), 3514 "tracker", 3515 "ontologies.gvdb", 3516 NULL); 3517 3518 if (overwrite || !g_file_test (filename, G_FILE_TEST_EXISTS)) { 3519 tracker_ontologies_write_gvdb (filename, error); 3520 } 3521 3522 g_free (filename); 3523 } 3524 3525 static void 3526 load_ontologies_gvdb (GError **error) 3527 { 3528 gchar *filename; 3529 3530 filename = g_build_filename (g_get_user_cache_dir (), 3531 "tracker", 3532 "ontologies.gvdb", 3533 NULL); 3534 3535 tracker_ontologies_load_gvdb (filename, error); 3536 3537 g_free (filename); 3538 } 3539 3540 #if HAVE_TRACKER_FTS 3541 static gboolean 3542 ontology_get_fts_properties (gboolean only_new, 3543 GHashTable **fts_properties, 3544 GHashTable **multivalued) 3545 { 3546 TrackerProperty **properties; 3547 gboolean has_new = FALSE; 3548 GHashTable *hashtable; 3549 guint i, len; 3550 3551 properties = tracker_ontologies_get_properties (&len); 3552 hashtable = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, 3553 (GDestroyNotify) g_list_free); 3554 3555 if (multivalued) { 3556 *multivalued = g_hash_table_new (g_str_hash, g_str_equal); 3557 } 3558 3559 for (i = 0; i < len; i++) { 3560 const gchar *name, *table_name; 3561 GList *list; 3562 3563 if (!tracker_property_get_fulltext_indexed (properties[i])) { 3564 continue; 3565 } 3566 3567 has_new |= tracker_property_get_is_new (properties[i]); 3568 3569 if (multivalued && 3570 tracker_property_get_multiple_values (properties[i])) { 3571 g_hash_table_insert (*multivalued, (gpointer) table_name,
'table_name' may be used uninitialized in this function
(emitted by gcc)
3572 GUINT_TO_POINTER (TRUE)); 3573 } 3574 3575 table_name = tracker_property_get_table_name (properties[i]); 3576 name = tracker_property_get_name (properties[i]); 3577 list = g_hash_table_lookup (hashtable, table_name); 3578 3579 if (!list) { 3580 list = g_list_prepend (NULL, (gpointer) name); 3581 g_hash_table_insert (hashtable, (gpointer) table_name, list); 3582 } else { 3583 list = g_list_append (list, (gpointer) name); 3584 } 3585 } 3586 3587 if (fts_properties) { 3588 *fts_properties = hashtable; 3589 } 3590 3591 return has_new; 3592 } 3593 #endif 3594 3595 gboolean 3596 tracker_data_manager_init_fts (TrackerDBInterface *iface, 3597 gboolean create) 3598 { 3599 #if HAVE_TRACKER_FTS 3600 GHashTable *fts_props, *multivalued; 3601 3602 ontology_get_fts_properties (FALSE, &fts_props, &multivalued); 3603 tracker_db_interface_sqlite_fts_init (iface, fts_props, 3604 multivalued, create); 3605 g_hash_table_unref (fts_props); 3606 g_hash_table_unref (multivalued); 3607 return TRUE; 3608 #else 3609 g_message ("FTS support is disabled"); 3610 return FALSE; 3611 #endif 3612 } 3613 3614 gboolean 3615 tracker_data_manager_init (TrackerDBManagerFlags flags, 3616 const gchar **test_schemas, 3617 gboolean *first_time, 3618 gboolean journal_check, 3619 gboolean restoring_backup, 3620 guint select_cache_size, 3621 guint update_cache_size, 3622 TrackerBusyCallback busy_callback, 3623 gpointer busy_user_data, 3624 const gchar *busy_operation, 3625 GError **error) 3626 { 3627 TrackerDBInterface *iface; 3628 gboolean is_first_time_index, check_ontology; 3629 TrackerDBCursor *cursor; 3630 TrackerDBStatement *stmt; 3631 GHashTable *ontos_table; 3632 GList *sorted = NULL, *l; 3633 const gchar *env_path; 3634 gint max_id = 0; 3635 gboolean read_only; 3636 GHashTable *uri_id_map = NULL; 3637 gchar *busy_status; 3638 GError *internal_error = NULL; 3639 #ifndef DISABLE_JOURNAL 3640 gboolean read_journal; 3641 #endif 3642 3643 read_only = (flags & TRACKER_DB_MANAGER_READONLY) ? TRUE : FALSE; 3644 3645 tracker_data_update_init (); 3646 3647 #ifdef HAVE_TRACKER_FTS 3648 if (!tracker_fts_init ()) { 3649 g_warning ("FTS module loading failed"); 3650 } 3651 #endif 3652 3653 /* First set defaults for return values */ 3654 if (first_time) { 3655 *first_time = FALSE; 3656 } 3657 3658 if (initialized) { 3659 return TRUE; 3660 } 3661 3662 /* Make sure we initialize all other modules we depend on */ 3663 tracker_ontologies_init (); 3664 3665 if (!reloading) { 3666 tracker_locale_init (); 3667 } 3668 3669 #ifndef DISABLE_JOURNAL 3670 read_journal = FALSE; 3671 #endif 3672 3673 if (!tracker_db_manager_init (flags, 3674 &is_first_time_index, 3675 restoring_backup, 3676 FALSE, 3677 select_cache_size, 3678 update_cache_size, 3679 busy_callback, 3680 busy_user_data, 3681 busy_operation, 3682 &internal_error)) { 3683 g_propagate_error (error, internal_error); 3684 3685 tracker_ontologies_shutdown (); 3686 if (!reloading) { 3687 tracker_locale_shutdown (); 3688 } 3689 tracker_data_update_shutdown (); 3690 3691 return FALSE; 3692 } 3693 3694 /* Report OPERATION - STATUS */ 3695 if (busy_callback) { 3696 busy_status = g_strdup_printf ("%s - %s", 3697 busy_operation, 3698 "Initializing data manager"); 3699 busy_callback (busy_status, 0, busy_user_data); 3700 g_free (busy_status); 3701 } 3702 3703 3704 if (first_time != NULL) { 3705 *first_time = is_first_time_index; 3706 } 3707 3708 iface = tracker_db_manager_get_db_interface (); 3709 3710 #ifndef DISABLE_JOURNAL 3711 if (journal_check && is_first_time_index) { 3712 /* Call may fail without notice (it's handled) */ 3713 if (tracker_db_journal_reader_init (NULL, &internal_error)) { 3714 if (tracker_db_journal_reader_next (NULL)) { 3715 /* journal with at least one valid transaction 3716 is required to trigger journal replay */ 3717 read_journal = TRUE; 3718 } 3719 tracker_db_journal_reader_shutdown (); 3720 } else if (internal_error) { 3721 if (!g_error_matches (internal_error, 3722 TRACKER_DB_JOURNAL_ERROR, 3723 TRACKER_DB_JOURNAL_ERROR_BEGIN_OF_JOURNAL)) { 3724 g_propagate_error (error, internal_error); 3725 3726 tracker_db_manager_shutdown (); 3727 tracker_ontologies_shutdown (); 3728 if (!reloading) { 3729 tracker_locale_shutdown (); 3730 } 3731 tracker_data_update_shutdown (); 3732 3733 return FALSE; 3734 } else { 3735 g_clear_error (&internal_error); 3736 } 3737 } 3738 } 3739 #endif /* DISABLE_JOURNAL */ 3740 3741 env_path = g_getenv ("TRACKER_DB_ONTOLOGIES_DIR"); 3742 3743 if (G_LIKELY (!env_path)) { 3744 ontologies_dir = g_build_filename (SHAREDIR, 3745 "tracker", 3746 "ontologies", 3747 NULL); 3748 } else { 3749 ontologies_dir = g_strdup (env_path); 3750 } 3751 3752 #ifndef DISABLE_JOURNAL 3753 if (read_journal) { 3754 in_journal_replay = TRUE; 3755 3756 if (tracker_db_journal_reader_ontology_init (NULL, &internal_error)) { 3757 /* Load ontology IDs from journal into memory */ 3758 load_ontology_ids_from_journal (&uri_id_map, &max_id); 3759 3760 tracker_db_journal_reader_shutdown (); 3761 } else { 3762 if (internal_error) { 3763 if (!g_error_matches (internal_error, 3764 TRACKER_DB_JOURNAL_ERROR, 3765 TRACKER_DB_JOURNAL_ERROR_BEGIN_OF_JOURNAL)) { 3766 g_propagate_error (error, internal_error); 3767 3768 tracker_db_manager_shutdown (); 3769 tracker_ontologies_shutdown (); 3770 if (!reloading) { 3771 tracker_locale_shutdown (); 3772 } 3773 tracker_data_update_shutdown (); 3774 3775 return FALSE; 3776 } else { 3777 g_clear_error (&internal_error); 3778 } 3779 } 3780 3781 /* do not trigger journal replay if ontology journal 3782 does not exist or is not valid, 3783 same as with regular journal further above */ 3784 in_journal_replay = FALSE; 3785 read_journal = FALSE; 3786 } 3787 } 3788 #endif /* DISABLE_JOURNAL */ 3789 3790 if (is_first_time_index && !read_only) { 3791 sorted = get_ontologies (test_schemas != NULL, ontologies_dir); 3792 3793 #ifndef DISABLE_JOURNAL 3794 if (!read_journal) { 3795 /* Truncate journal as it does not even contain a single valid transaction 3796 * or is explicitly ignored (journal_check == FALSE, only for test cases) */ 3797 tracker_db_journal_init (NULL, TRUE, &internal_error); 3798 3799 if (internal_error) { 3800 g_propagate_error (error, internal_error); 3801 3802 tracker_db_manager_shutdown (); 3803 tracker_ontologies_shutdown (); 3804 if (!reloading) { 3805 tracker_locale_shutdown (); 3806 } 3807 tracker_data_update_shutdown (); 3808 3809 return FALSE; 3810 } 3811 } 3812 #endif /* DISABLE_JOURNAL */ 3813 3814 /* load ontology from files into memory (max_id starts at zero: first-time) */ 3815 3816 for (l = sorted; l; l = l->next) { 3817 GError *ontology_error = NULL; 3818 gchar *ontology_path; 3819 g_debug ("Loading ontology %s", (char *) l->data); 3820 ontology_path = g_build_filename (ontologies_dir, l->data, NULL); 3821 load_ontology_file_from_path (ontology_path, 3822 &max_id, 3823 FALSE, 3824 NULL, 3825 NULL, 3826 uri_id_map, 3827 &ontology_error); 3828 if (ontology_error) { 3829 g_error ("Error loading ontology (%s): %s", 3830 ontology_path, 3831 ontology_error->message); 3832 } 3833 g_free (ontology_path); 3834 3835 } 3836 3837 if (test_schemas) { 3838 guint p; 3839 for (p = 0; test_schemas[p] != NULL; p++) { 3840 GError *ontology_error = NULL; 3841 gchar *test_schema_path; 3842 test_schema_path = g_strconcat (test_schemas[p], ".ontology", NULL); 3843 3844 g_debug ("Loading ontology:'%s' (TEST ONTOLOGY)", test_schema_path); 3845 3846 load_ontology_file_from_path (test_schema_path, 3847 &max_id, 3848 FALSE, 3849 NULL, 3850 NULL, 3851 uri_id_map, 3852 &ontology_error); 3853 if (ontology_error) { 3854 g_error ("Error loading ontology (%s): %s", 3855 test_schema_path, 3856 ontology_error->message); 3857 } 3858 g_free (test_schema_path); 3859 } 3860 } 3861 3862 tracker_data_begin_ontology_transaction (&internal_error); 3863 if (internal_error) { 3864 g_propagate_error (error, internal_error); 3865 3866 #ifndef DISABLE_JOURNAL 3867 tracker_db_journal_shutdown (NULL); 3868 #endif /* DISABLE_JOURNAL */ 3869 tracker_db_manager_shutdown (); 3870 tracker_ontologies_shutdown (); 3871 if (!reloading) { 3872 tracker_locale_shutdown (); 3873 } 3874 tracker_data_update_shutdown (); 3875 3876 return FALSE; 3877 } 3878 3879 tracker_data_ontology_import_into_db (FALSE, 3880 &internal_error); 3881 3882 tracker_data_manager_init_fts (iface, TRUE); 3883 3884 if (internal_error) { 3885 g_propagate_error (error, internal_error); 3886 3887 #ifndef DISABLE_JOURNAL 3888 tracker_db_journal_shutdown (NULL); 3889 #endif /* DISABLE_JOURNAL */ 3890 tracker_db_manager_shutdown (); 3891 tracker_ontologies_shutdown (); 3892 if (!reloading) { 3893 tracker_locale_shutdown (); 3894 } 3895 tracker_data_update_shutdown (); 3896 3897 return FALSE; 3898 } 3899 3900 #ifndef DISABLE_JOURNAL 3901 if (uri_id_map) { 3902 /* restore all IDs from ontology journal */ 3903 GHashTableIter iter; 3904 gpointer key, value; 3905 3906 g_hash_table_iter_init (&iter, uri_id_map); 3907 while (g_hash_table_iter_next (&iter, &key, &value)) { 3908 insert_uri_in_resource_table (iface, 3909 key, 3910 GPOINTER_TO_INT (value), 3911 &internal_error); 3912 if (internal_error) { 3913 g_propagate_error (error, internal_error); 3914 3915 tracker_db_journal_shutdown (NULL); 3916 tracker_db_manager_shutdown (); 3917 tracker_ontologies_shutdown (); 3918 if (!reloading) { 3919 tracker_locale_shutdown (); 3920 } 3921 tracker_data_update_shutdown (); 3922 3923 return FALSE; 3924 } 3925 } 3926 } 3927 #endif /* DISABLE_JOURNAL */ 3928 3929 /* store ontology in database */ 3930 for (l = sorted; l; l = l->next) { 3931 gchar *ontology_path = g_build_filename (ontologies_dir, l->data, NULL); 3932 import_ontology_path (ontology_path, FALSE, !journal_check); 3933 g_free (ontology_path); 3934 } 3935 3936 if (test_schemas) { 3937 guint p; 3938 for (p = 0; test_schemas[p] != NULL; p++) { 3939 gchar *test_schema_path; 3940 3941 test_schema_path = g_strconcat (test_schemas[p], ".ontology", NULL); 3942 import_ontology_path (test_schema_path, FALSE, TRUE); 3943 g_free (test_schema_path); 3944 } 3945 } 3946 3947 tracker_data_commit_transaction (&internal_error); 3948 if (internal_error) { 3949 g_propagate_error (error, internal_error); 3950 3951 #ifndef DISABLE_JOURNAL 3952 tracker_db_journal_shutdown (NULL); 3953 #endif /* DISABLE_JOURNAL */ 3954 tracker_db_manager_shutdown (); 3955 tracker_ontologies_shutdown (); 3956 if (!reloading) { 3957 tracker_locale_shutdown (); 3958 } 3959 tracker_data_update_shutdown (); 3960 3961 return FALSE; 3962 } 3963 3964 write_ontologies_gvdb (TRUE /* overwrite */, NULL); 3965 3966 g_list_foreach (sorted, (GFunc) g_free, NULL); 3967 g_list_free (sorted); 3968 sorted = NULL; 3969 3970 /* First time, no need to check ontology */ 3971 check_ontology = FALSE; 3972 } else { 3973 if (!read_only) { 3974 3975 #ifndef DISABLE_JOURNAL 3976 tracker_db_journal_init (NULL, FALSE, &internal_error); 3977 3978 if (internal_error) { 3979 g_propagate_error (error, internal_error); 3980 3981 tracker_db_manager_shutdown (); 3982 tracker_ontologies_shutdown (); 3983 if (!reloading) { 3984 tracker_locale_shutdown (); 3985 } 3986 tracker_data_update_shutdown (); 3987 3988 return FALSE; 3989 } 3990 #endif /* DISABLE_JOURNAL */ 3991 3992 /* Load ontology from database into memory */ 3993 db_get_static_data (iface, &internal_error); 3994 check_ontology = (flags & TRACKER_DB_MANAGER_DO_NOT_CHECK_ONTOLOGY) == 0; 3995 3996 if (internal_error) { 3997 g_propagate_error (error, internal_error); 3998 return FALSE; 3999 } 4000 4001 write_ontologies_gvdb (FALSE /* overwrite */, NULL); 4002 4003 /* Skipped in the read-only case as it can't work with direct access and 4004 it reduces initialization time */ 4005 clean_decomposed_transient_metadata (iface); 4006 } else { 4007 GError *gvdb_error = NULL; 4008 4009 load_ontologies_gvdb (&gvdb_error); 4010 check_ontology = FALSE; 4011 4012 if (gvdb_error) { 4013 g_critical ("Error loading ontology cache: %s", 4014 gvdb_error->message); 4015 g_clear_error (&gvdb_error); 4016 4017 /* fall back to loading ontology from database into memory */ 4018 db_get_static_data (iface, &internal_error); 4019 if (internal_error) { 4020 g_propagate_error (error, internal_error); 4021 return FALSE; 4022 } 4023 } 4024 } 4025 4026 tracker_data_manager_init_fts (iface, FALSE); 4027 } 4028 4029 if (check_ontology) { 4030 GList *to_reload = NULL; 4031 GList *ontos = NULL; 4032 guint p; 4033 GPtrArray *seen_classes; 4034 GPtrArray *seen_properties; 4035 GError *n_error = NULL; 4036 gboolean transaction_started = FALSE; 4037 4038 seen_classes = g_ptr_array_new (); 4039 seen_properties = g_ptr_array_new (); 4040 4041 /* Get all the ontology files from ontologies_dir */ 4042 sorted = get_ontologies (test_schemas != NULL, ontologies_dir); 4043 4044 for (l = sorted; l; l = l->next) { 4045 gchar *ontology_path; 4046 ontology_path = g_build_filename (ontologies_dir, l->data, NULL); 4047 ontos = g_list_append (ontos, ontology_path); 4048 } 4049 4050 g_list_foreach (sorted, (GFunc) g_free, NULL); 4051 g_list_free (sorted); 4052 4053 if (test_schemas) { 4054 for (p = 0; test_schemas[p] != NULL; p++) { 4055 gchar *test_schema_path; 4056 test_schema_path = g_strconcat (test_schemas[p], ".ontology", NULL); 4057 ontos = g_list_append (ontos, test_schema_path); 4058 } 4059 } 4060 4061 /* check ontology against database */ 4062 4063 /* Get a map of tracker:Ontology v. nao:lastModified so that we can test 4064 * for all the ontology files in ontologies_dir whether the last-modified 4065 * has changed since we dealt with the file last time. */ 4066 4067 stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &n_error, 4068 "SELECT Resource.Uri, \"rdfs:Resource\".\"nao:lastModified\" FROM \"tracker:Ontology\" " 4069 "INNER JOIN Resource ON Resource.ID = \"tracker:Ontology\".ID " 4070 "INNER JOIN \"rdfs:Resource\" ON \"tracker:Ontology\".ID = \"rdfs:Resource\".ID"); 4071 4072 if (stmt) { 4073 cursor = tracker_db_statement_start_cursor (stmt, &n_error); 4074 g_object_unref (stmt); 4075 } else { 4076 cursor = NULL; 4077 } 4078 4079 ontos_table = g_hash_table_new_full (g_str_hash, 4080 g_str_equal, 4081 g_free, 4082 NULL); 4083 4084 if (cursor) { 4085 while (tracker_db_cursor_iter_next (cursor, NULL, &n_error)) { 4086 const gchar *onto_uri = tracker_db_cursor_get_string (cursor, 0, NULL); 4087 /* It's stored as an int in the db anyway. This is caused by 4088 * string_to_gvalue in tracker-data-update.c */ 4089 gint value = tracker_db_cursor_get_int (cursor, 1); 4090 4091 g_hash_table_insert (ontos_table, g_strdup (onto_uri), 4092 GINT_TO_POINTER (value)); 4093 } 4094 4095 g_object_unref (cursor); 4096 } 4097 4098 if (n_error) { 4099 g_warning ("%s", n_error->message); 4100 g_clear_error (&n_error); 4101 } 4102 4103 for (l = ontos; l; l = l->next) { 4104 TrackerOntology *ontology; 4105 const gchar *ontology_path = l->data; 4106 const gchar *ontology_uri; 4107 gboolean found, update_nao = FALSE; 4108 gpointer value; 4109 gint last_mod; 4110 4111 /* Parse a TrackerOntology from ontology_file */ 4112 ontology = get_ontology_from_path (ontology_path); 4113 4114 if (!ontology) { 4115 /* TODO: cope with full custom .ontology files: deal with this 4116 * error gracefully. App devs might install wrong ontology files 4117 * and we shouldn't critical() due to this. */ 4118 g_critical ("Can't get ontology from file: %s", ontology_path); 4119 continue; 4120 } 4121 4122 ontology_uri = tracker_ontology_get_uri (ontology); 4123 /* We can't do better than this cast, it's stored as an int in the 4124 * db. See above comment for more info. */ 4125 last_mod = (gint) tracker_ontology_get_last_modified (ontology); 4126 4127 found = g_hash_table_lookup_extended (ontos_table, 4128 ontology_uri, 4129 NULL, &value); 4130 4131 if (found) { 4132 GError *ontology_error = NULL; 4133 gint val = GPOINTER_TO_INT (value); 4134 4135 /* When the last-modified in our database isn't the same as the last 4136 * modified in the latest version of the file, deal with changes. */ 4137 if (val != last_mod) { 4138 g_debug ("Ontology file '%s' needs update", ontology_path); 4139 4140 if (!transaction_started) { 4141 tracker_data_begin_ontology_transaction (&internal_error); 4142 if (internal_error) { 4143 g_propagate_error (error, internal_error); 4144 4145 #ifndef DISABLE_JOURNAL 4146 tracker_db_journal_shutdown (NULL); 4147 #endif /* DISABLE_JOURNAL */ 4148 tracker_db_manager_shutdown (); 4149 tracker_ontologies_shutdown (); 4150 if (!reloading) { 4151 tracker_locale_shutdown (); 4152 } 4153 tracker_data_update_shutdown (); 4154 4155 return FALSE; 4156 } 4157 transaction_started = TRUE; 4158 } 4159 4160 if (max_id == 0) { 4161 /* In case of first-time, this wont start at zero */ 4162 max_id = get_new_service_id (iface); 4163 } 4164 /* load ontology from files into memory, set all new's 4165 * is_new to TRUE */ 4166 load_ontology_file_from_path (ontology_path, 4167 &max_id, 4168 TRUE, 4169 seen_classes, 4170 seen_properties, 4171 uri_id_map, 4172 &ontology_error); 4173 4174 if (g_error_matches (ontology_error, 4175 TRACKER_DATA_ONTOLOGY_ERROR, 4176 TRACKER_DATA_UNSUPPORTED_ONTOLOGY_CHANGE)) { 4177 g_warning ("%s", ontology_error->message); 4178 g_error_free (ontology_error); 4179 4180 tracker_data_ontology_free_seen (seen_classes); 4181 tracker_data_ontology_free_seen (seen_properties); 4182 tracker_data_ontology_import_finished (); 4183 4184 /* as we're processing an ontology change, 4185 transaction is guaranteed to be started */ 4186 tracker_data_rollback_transaction (); 4187 4188 if (ontos_table) { 4189 g_hash_table_unref (ontos_table); 4190 } 4191 if (ontos) { 4192 g_list_foreach (ontos, (GFunc) g_free, NULL); 4193 g_list_free (ontos); 4194 } 4195 g_free (ontologies_dir); 4196 if (uri_id_map) { 4197 g_hash_table_unref (uri_id_map); 4198 } 4199 initialized = TRUE; 4200 4201 /* This also does tracker_locale_shutdown */ 4202 tracker_data_manager_shutdown (); 4203 4204 return tracker_data_manager_init (flags | TRACKER_DB_MANAGER_DO_NOT_CHECK_ONTOLOGY, 4205 test_schemas, 4206 first_time, 4207 journal_check, 4208 restoring_backup, 4209 select_cache_size, 4210 update_cache_size, 4211 busy_callback, 4212 busy_user_data, 4213 busy_operation, 4214 error); 4215 } 4216 4217 if (ontology_error) { 4218 g_critical ("Fatal error dealing with ontology changes: %s", ontology_error->message); 4219 g_error_free (ontology_error); 4220 } 4221 4222 to_reload = g_list_prepend (to_reload, l->data); 4223 update_nao = TRUE; 4224 } 4225 } else { 4226 GError *ontology_error = NULL; 4227 4228 g_debug ("Ontology file '%s' got added", ontology_path); 4229 4230 if (!transaction_started) { 4231 tracker_data_begin_ontology_transaction (&internal_error); 4232 if (internal_error) { 4233 g_propagate_error (error, internal_error); 4234 4235 #ifndef DISABLE_JOURNAL 4236 tracker_db_journal_shutdown (NULL); 4237 #endif /* DISABLE_JOURNAL */ 4238 tracker_db_manager_shutdown (); 4239 tracker_ontologies_shutdown (); 4240 if (!reloading) { 4241 tracker_locale_shutdown (); 4242 } 4243 tracker_data_update_shutdown (); 4244 4245 return FALSE; 4246 } 4247 transaction_started = TRUE; 4248 } 4249 4250 if (max_id == 0) { 4251 /* In case of first-time, this wont start at zero */ 4252 max_id = get_new_service_id (iface); 4253 } 4254 /* load ontology from files into memory, set all new's 4255 * is_new to TRUE */ 4256 load_ontology_file_from_path (ontology_path, 4257 &max_id, 4258 TRUE, 4259 seen_classes, 4260 seen_properties, 4261 uri_id_map,