[tracker/IorR-null-support] libtracker-data: Experimental commit, insert or replace null support



commit ea00af9ece5e09c6cb312ef683694605f1283604
Author: Philip Van Hoof <philip codeminded be>
Date:   Fri Jul 29 16:36:55 2011 +0200

    libtracker-data: Experimental commit, insert or replace null support
    
    For deleting a resource-property's objects during insert or replace
    using null

 src/libtracker-data/libtracker-data.vapi        |    2 +-
 src/libtracker-data/tracker-data-update.c       |  137 ++++++++++++++++++++++-
 src/libtracker-data/tracker-data-update.h       |    1 +
 src/libtracker-data/tracker-sparql-query.vala   |   26 ++++-
 src/libtracker-data/tracker-sparql-scanner.vala |    5 +
 5 files changed, 160 insertions(+), 11 deletions(-)
---
diff --git a/src/libtracker-data/libtracker-data.vapi b/src/libtracker-data/libtracker-data.vapi
index 491cf9e..acec2eb 100644
--- a/src/libtracker-data/libtracker-data.vapi
+++ b/src/libtracker-data/libtracker-data.vapi
@@ -200,7 +200,7 @@ namespace Tracker {
 		public void load_turtle_file (GLib.File file) throws Sparql.Error;
 		public void notify_transaction (CommitType commit_type);
 		public void delete_statement (string? graph, string subject, string predicate, string object) throws Sparql.Error, DateError;
-		public void update_statement (string? graph, string subject, string predicate, string object) throws Sparql.Error, DateError;
+		public void update_statement (string? graph, string subject, string predicate, string object, bool object_is_null) throws Sparql.Error, DateError;
 		public void insert_statement (string? graph, string subject, string predicate, string object) throws Sparql.Error, DateError;
 		public void insert_statement_with_uri (string? graph, string subject, string predicate, string object) throws Sparql.Error;
 		public void insert_statement_with_string (string? graph, string subject, string predicate, string object) throws Sparql.Error, DateError;
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index dbf1043..3e6bd70 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -2247,6 +2247,130 @@ tracker_data_delete_statement (const gchar  *graph,
 	}
 }
 
+static void
+delete_all_objects (const gchar  *graph,
+                    const gchar  *subject,
+                    const gchar  *predicate,
+                    GError      **error)
+{
+	gint subject_id = 0;
+	gboolean change = FALSE;
+	guint i;
+	GError *new_error = NULL;
+	TrackerProperty *field;
+
+	g_return_if_fail (subject != NULL);
+	g_return_if_fail (predicate != NULL);
+	g_return_if_fail (in_transaction);
+
+	subject_id = query_resource_id (subject);
+
+	if (subject_id == 0) {
+		/* subject not in database */
+		return;
+	}
+
+	resource_buffer_switch (graph, 0, subject, subject_id);
+
+	field = tracker_ontologies_get_property_by_uri (predicate);
+	if (field != NULL) {
+		GValueArray *old_values;
+
+		if (!tracker_property_get_transient (field)) {
+			has_persistent = TRUE;
+		}
+
+		old_values = get_old_property_values (field, &new_error);
+		if (new_error) {
+			g_propagate_error (error, new_error);
+			return;
+		}
+
+		for (i = 0; i < old_values->n_values; i++) {
+			gint pred_id = 0, graph_id = 0;
+			gboolean tried = FALSE;
+			const gchar *object = NULL;
+			gint object_id = 0;
+
+			if (tracker_property_get_data_type (field) == TRACKER_PROPERTY_TYPE_RESOURCE) {
+
+				graph_id = (graph != NULL ? query_resource_id (graph) : 0);
+				pred_id = tracker_property_get_id (field);
+				object_id = (gint) g_value_get_int64 (g_value_array_get_nth (old_values, i));
+				tried = TRUE;
+
+				change = delete_metadata_decomposed (field, NULL, object_id, error);
+
+#ifndef DISABLE_JOURNAL
+				if (!in_journal_replay && change && !tracker_property_get_transient (field)) {
+					tracker_db_journal_append_delete_statement_id (graph_id,
+					                                               resource_buffer->id,
+					                                               pred_id,
+					                                               object_id);
+				}
+#endif /* DISABLE_JOURNAL */
+			} else {
+				object = g_value_get_string (g_value_array_get_nth (old_values, i));
+				pred_id = tracker_property_get_id (field);
+				graph_id = (graph != NULL ? query_resource_id (graph) : 0);
+				object_id = 0;
+				tried = TRUE;
+
+				change = delete_metadata_decomposed (field, object, 0, error);
+
+#ifndef DISABLE_JOURNAL
+				if (!in_journal_replay && change && !tracker_property_get_transient (field)) {
+					if (!tracker_property_get_force_journal (field) &&
+						g_strcmp0 (graph, TRACKER_MINER_FS_GRAPH_URN) == 0) {
+						/* do not journal this statement extracted from filesystem */
+						TrackerProperty *damaged;
+
+						damaged = tracker_ontologies_get_property_by_uri (TRACKER_TRACKER_PREFIX "damaged");
+
+						tracker_db_journal_append_insert_statement (graph_id,
+						                                            resource_buffer->id,
+						                                            tracker_property_get_id (damaged),
+						                                            "true");
+					} else {
+						tracker_db_journal_append_delete_statement (graph_id,
+						                                            resource_buffer->id,
+						                                            pred_id,
+						                                            object);
+					}
+				}
+#endif /* DISABLE_JOURNAL */
+
+				if (!tried) {
+					graph_id = (graph != NULL ? query_resource_id (graph) : 0);
+					if (field == NULL) {
+						pred_id = tracker_data_query_resource_id (predicate);
+					} else {
+						pred_id = tracker_property_get_id (field);
+					}
+				}
+
+				if (delete_callbacks && change) {
+					guint n;
+					for (n = 0; n < delete_callbacks->len; n++) {
+						TrackerStatementDelegate *delegate;
+
+						delegate = g_ptr_array_index (delete_callbacks, n);
+						delegate->callback (graph_id, graph, subject_id, subject,
+						                    pred_id, object_id,
+						                    object,
+						                    resource_buffer->types,
+						                    delegate->user_data);
+					}
+				}
+			}
+		}
+	} else {
+		/* I wonder why in case of error the delete_callbacks are still executed */
+		g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
+		             "Property '%s' not found in the ontology", predicate);
+	}
+}
+
 static gboolean
 tracker_data_insert_statement_common (const gchar            *graph,
                                       const gchar            *subject,
@@ -2352,7 +2476,7 @@ handle_blank_node (const gchar  *subject,
 
 	if (blank_uri != NULL) {
 		/* now insert statement referring to blank node */
-		tracker_data_update_statement (graph, subject, predicate, blank_uri, &actual_error);
+		tracker_data_update_statement (graph, subject, predicate, blank_uri, FALSE, &actual_error);
 
 		g_hash_table_remove (blank_buffer.table, object);
 
@@ -2937,6 +3061,7 @@ tracker_data_update_statement (const gchar            *graph,
                                const gchar            *subject,
                                const gchar            *predicate,
                                const gchar            *object,
+                               gboolean                object_is_null,
                                GError                **error)
 {
 	TrackerProperty *property;
@@ -2948,10 +3073,14 @@ tracker_data_update_statement (const gchar            *graph,
 
 	property = tracker_ontologies_get_property_by_uri (predicate);
 	if (property != NULL) {
-		if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) {
-			tracker_data_update_statement_with_uri (graph, subject, predicate, object, error);
+		if (object_is_null) {
+			delete_all_objects (graph, subject, predicate, error);
 		} else {
-			tracker_data_update_statement_with_string (graph, subject, predicate, object, error);
+			if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) {
+				tracker_data_update_statement_with_uri (graph, subject, predicate, object, error);
+			} else {
+				tracker_data_update_statement_with_string (graph, subject, predicate, object, error);
+			}
 		}
 	} else {
 		g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
diff --git a/src/libtracker-data/tracker-data-update.h b/src/libtracker-data/tracker-data-update.h
index 9921333..245e894 100644
--- a/src/libtracker-data/tracker-data-update.h
+++ b/src/libtracker-data/tracker-data-update.h
@@ -79,6 +79,7 @@ void     tracker_data_update_statement              (const gchar               *
                                                      const gchar               *subject,
                                                      const gchar               *predicate,
                                                      const gchar               *object,
+                                                     gboolean                   object_is_null,
                                                      GError                   **error);
 void     tracker_data_begin_transaction             (GError                   **error);
 void     tracker_data_begin_ontology_transaction    (GError                   **error);
diff --git a/src/libtracker-data/tracker-sparql-query.vala b/src/libtracker-data/tracker-sparql-query.vala
index 0c9f453..79b6e24 100644
--- a/src/libtracker-data/tracker-sparql-query.vala
+++ b/src/libtracker-data/tracker-sparql-query.vala
@@ -755,14 +755,16 @@ public class Tracker.Sparql.Query : Object {
 		expect (SparqlTokenType.OPEN_BRACE);
 
 		while (current () != SparqlTokenType.CLOSE_BRACE) {
+			bool is_null; // ignored
+
 			if (accept (SparqlTokenType.GRAPH)) {
 				var old_graph = current_graph;
-				current_graph = parse_construct_var_or_term (var_value_map);
+				current_graph = parse_construct_var_or_term (var_value_map, out is_null);
 
 				expect (SparqlTokenType.OPEN_BRACE);
 
 				while (current () != SparqlTokenType.CLOSE_BRACE) {
-					current_subject = parse_construct_var_or_term (var_value_map);
+					current_subject = parse_construct_var_or_term (var_value_map, out is_null);
 					parse_construct_property_list_not_empty (var_value_map);
 					if (!accept (SparqlTokenType.DOT)) {
 						// no triples following
@@ -776,7 +778,7 @@ public class Tracker.Sparql.Query : Object {
 
 				accept (SparqlTokenType.DOT);
 			} else {
-				current_subject = parse_construct_var_or_term (var_value_map);
+				current_subject = parse_construct_var_or_term (var_value_map, out is_null);
 				parse_construct_property_list_not_empty (var_value_map);
 				if (!accept (SparqlTokenType.DOT) && current () != SparqlTokenType.GRAPH) {
 					// neither GRAPH nor triples following
@@ -790,8 +792,9 @@ public class Tracker.Sparql.Query : Object {
 
 	bool anon_blank_node_open = false;
 
-	string? parse_construct_var_or_term (HashTable<string,string> var_value_map) throws Sparql.Error, DateError {
+	string? parse_construct_var_or_term (HashTable<string,string> var_value_map, out bool is_null) throws Sparql.Error, DateError {
 		string result = "";
+		is_null = false;
 		if (current () == SparqlTokenType.VAR) {
 			next ();
 			result = var_value_map.lookup (get_last_string ().substring (1));
@@ -825,6 +828,10 @@ public class Tracker.Sparql.Query : Object {
 		} else if (current () == SparqlTokenType.INTEGER) {
 			next ();
 			result = get_last_string ();
+		} else if (current () == SparqlTokenType.NULL) {
+			next ();
+			result = "null";
+			is_null = true;
 		} else if (current () == SparqlTokenType.DECIMAL) {
 			next ();
 			result = get_last_string ();
@@ -920,7 +927,8 @@ public class Tracker.Sparql.Query : Object {
 	}
 
 	void parse_construct_object (HashTable<string,string> var_value_map) throws Sparql.Error, DateError {
-		string object = parse_construct_var_or_term (var_value_map);
+		bool is_null = false;
+		string object = parse_construct_var_or_term (var_value_map, out is_null);
 		if (current_subject == null || current_predicate == null || object == null) {
 			// the SPARQL specification says that triples containing unbound variables
 			// should be excluded from the output RDF graph of CONSTRUCT
@@ -929,12 +937,18 @@ public class Tracker.Sparql.Query : Object {
 		try {
 			if (update_statements) {
 				// update triple in database
-				Data.update_statement (current_graph, current_subject, current_predicate, object);
+				Data.update_statement (current_graph, current_subject, current_predicate, object, is_null);
 			} else if (delete_statements) {
 				// delete triple from database
+				if (is_null) {
+					throw get_error ("'null' not supported in this mode");
+				}
 				Data.delete_statement (current_graph, current_subject, current_predicate, object);
 			} else {
 				// insert triple into database
+				if (is_null) {
+					throw get_error ("'null' not supported in this mode");
+				}
 				Data.insert_statement (current_graph, current_subject, current_predicate, object);
 			}
 		} catch (Sparql.Error e) {
diff --git a/src/libtracker-data/tracker-sparql-scanner.vala b/src/libtracker-data/tracker-sparql-scanner.vala
index dda1343..aed826d 100644
--- a/src/libtracker-data/tracker-sparql-scanner.vala
+++ b/src/libtracker-data/tracker-sparql-scanner.vala
@@ -169,6 +169,10 @@ public class Tracker.SparqlScanner : Object {
 			case 'l':
 				if (matches (begin, "LANG")) return SparqlTokenType.LANG;
 				break;
+			case 'N':
+			case 'n':
+				if (matches (begin, "NULL")) return SparqlTokenType.NULL;
+				break;
 			case 'T':
 			case 't':
 				if (matches (begin, "TRUE")) return SparqlTokenType.TRUE;
@@ -907,6 +911,7 @@ public enum Tracker.SparqlTokenType {
 	MINUS,
 	NAMED,
 	NOT,
+	NULL, /* Non-standard in SPARQL spec */
 	OFFSET,
 	OP_AND,
 	OP_EQ,



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