[tracker/sparql-update: 2/2] libtracker-data:REPLACE, adding building blocks in the storage
- From: Philip Van Hoof <pvanhoof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/sparql-update: 2/2] libtracker-data:REPLACE, adding building blocks in the storage
- Date: Tue, 8 Mar 2011 14:50:29 +0000 (UTC)
commit 3cafcaf50e2bb2e45a19c2bf608b13f5e0c176ed
Author: Philip Van Hoof <philip codeminded be>
Date: Tue Mar 8 15:48:54 2011 +0100
libtracker-data:REPLACE, adding building blocks in the storage
src/libtracker-data/tracker-data-update.c | 465 ++++++++++++++++++++++++++++-
src/libtracker-data/tracker-data-update.h | 5 +
2 files changed, 454 insertions(+), 16 deletions(-)
---
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 9aab5a5..275db01 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -112,6 +112,7 @@ struct _TrackerDataUpdateBufferTable {
TrackerClass *class;
/* TrackerDataUpdateBufferProperty */
GArray *properties;
+ gboolean update_value;
};
/* buffer for anonymous blank nodes
@@ -173,6 +174,14 @@ static void cache_insert_value (const gchar *table_name,
gboolean multiple_values,
gboolean fts,
gboolean date_time);
+static void cache_update_value (const gchar *table_name,
+ const gchar *field_name,
+ gboolean transient,
+ GValue *value,
+ gint graph,
+ gboolean multiple_values,
+ gboolean fts,
+ gboolean date_time);
static GValueArray *get_old_property_values (TrackerProperty *property,
GError **error);
@@ -543,6 +552,35 @@ cache_insert_row (TrackerClass *class)
}
static void
+cache_update_value (const gchar *table_name,
+ const gchar *field_name,
+ gboolean transient,
+ GValue *value,
+ gint graph,
+ gboolean multiple_values,
+ gboolean fts,
+ gboolean date_time)
+{
+ TrackerDataUpdateBufferTable *table;
+ TrackerDataUpdateBufferProperty property;
+
+ /* No need to strdup here, the incoming string is either always static, or
+ * long-standing as tracker_property_get_name return value. */
+ property.name = field_name;
+
+ property.value = *value;
+ property.graph = graph;
+#if HAVE_TRACKER_FTS
+ property.fts = fts;
+#endif
+ property.date_time = date_time;
+
+ table = cache_ensure_table (table_name, multiple_values, transient);
+ table->update_value = TRUE;
+ g_array_append_val (table->properties, property);
+}
+
+static void
cache_insert_value (const gchar *table_name,
const gchar *field_name,
gboolean transient,
@@ -735,7 +773,15 @@ tracker_data_resource_buffer_flush (GError **error)
for (i = 0; i < table->properties->len; i++) {
property = &g_array_index (table->properties, TrackerDataUpdateBufferProperty, i);
- if (table->delete_value) {
+ if (table->update_value) {
+ g_critical ("Unimplemented SPARQL Update UPDATE feature called");
+
+ g_set_error_literal (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNSUPPORTED,
+ "Unimplemented SPARQL Update UPDATE feature called");
+
+ continue;
+
+ } else if (table->delete_value) {
/* delete rows for multiple value properties */
stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error,
"DELETE FROM \"%s\" WHERE ID = ? AND \"%s\" = ?",
@@ -784,6 +830,15 @@ tracker_data_resource_buffer_flush (GError **error)
} else {
GString *sql, *values_sql;
+ if (table->update_value) {
+ g_critical ("Unimplemented SPARQL Update UPDATE feature called");
+
+ g_set_error_literal (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNSUPPORTED,
+ "Unimplemented SPARQL Update UPDATE feature called");
+
+ continue;
+ }
+
if (table->delete_row) {
/* remove entry from rdf:type table */
stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error,
@@ -1525,12 +1580,12 @@ resource_in_domain_index_class (TrackerClass *domain_index_class)
}
static gboolean
-cache_set_metadata_decomposed (TrackerProperty *property,
- const gchar *value,
- gint value_id,
- const gchar *graph,
- gint graph_id,
- GError **error)
+cache_insert_metadata_decomposed (TrackerProperty *property,
+ const gchar *value,
+ gint value_id,
+ const gchar *graph,
+ gint graph_id,
+ GError **error)
{
gboolean multiple_values;
const gchar *table_name;
@@ -1544,8 +1599,8 @@ cache_set_metadata_decomposed (TrackerProperty *property,
/* also insert super property values */
super_properties = tracker_property_get_super_properties (property);
while (*super_properties) {
- change |= cache_set_metadata_decomposed (*super_properties, value, value_id,
- graph, graph_id, &new_error);
+ change |= cache_insert_metadata_decomposed (*super_properties, value, value_id,
+ graph, graph_id, &new_error);
if (new_error) {
g_propagate_error (error, new_error);
return FALSE;
@@ -1648,6 +1703,85 @@ cache_set_metadata_decomposed (TrackerProperty *property,
return change;
}
+
+static gboolean
+cache_update_metadata_decomposed (TrackerProperty *property,
+ const gchar *value,
+ gint value_id,
+ const gchar *graph,
+ gint graph_id,
+ GError **error)
+{
+ gboolean multiple_values;
+ const gchar *table_name;
+ const gchar *field_name;
+ TrackerProperty **super_properties;
+ GValue gvalue = { 0 };
+ GError *new_error = NULL;
+ gboolean change = FALSE;
+
+ /* also insert super property values */
+ super_properties = tracker_property_get_super_properties (property);
+ while (*super_properties) {
+ change |= cache_update_metadata_decomposed (*super_properties, value, value_id,
+ graph, graph_id, &new_error);
+ if (new_error) {
+ g_propagate_error (error, new_error);
+ return FALSE;
+ }
+ super_properties++;
+ }
+
+ multiple_values = tracker_property_get_multiple_values (property);
+ table_name = tracker_property_get_table_name (property);
+ field_name = tracker_property_get_name (property);
+
+ if (value) {
+ string_to_gvalue (value, tracker_property_get_data_type (property), &gvalue, &new_error);
+ if (new_error) {
+ g_propagate_error (error, new_error);
+ return FALSE;
+ }
+ } else {
+ g_value_init (&gvalue, G_TYPE_INT64);
+ g_value_set_int64 (&gvalue, value_id);
+ }
+
+ cache_update_value (table_name, field_name,
+ tracker_property_get_transient (property),
+ &gvalue,
+ graph != NULL ? ensure_resource_id (graph, NULL) : graph_id,
+ multiple_values,
+ tracker_property_get_fulltext_indexed (property),
+ tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME);
+
+ if (!multiple_values) {
+ TrackerClass **domain_index_classes;
+
+ domain_index_classes = tracker_property_get_domain_indexes (property);
+ while (*domain_index_classes) {
+ if (resource_in_domain_index_class (*domain_index_classes)) {
+ GValue gvalue_copy = { 0 };
+
+ g_value_init (&gvalue_copy, G_VALUE_TYPE (&gvalue));
+ g_value_copy (&gvalue, &gvalue_copy);
+
+ cache_update_value (tracker_class_get_name (*domain_index_classes),
+ field_name,
+ tracker_property_get_transient (property),
+ &gvalue_copy,
+ graph != NULL ? ensure_resource_id (graph, NULL) : graph_id,
+ multiple_values,
+ tracker_property_get_fulltext_indexed (property),
+ tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME);
+ }
+ domain_index_classes++;
+ }
+ }
+
+ return TRUE;
+}
+
static gboolean
delete_metadata_decomposed (TrackerProperty *property,
const gchar *value,
@@ -2301,7 +2435,7 @@ tracker_data_insert_statement_with_uri (const gchar *graph,
change = TRUE;
} else {
/* add value to metadata database */
- change = cache_set_metadata_decomposed (property, object, 0, graph, 0, &actual_error);
+ change = cache_insert_metadata_decomposed (property, object, 0, graph, 0, &actual_error);
if (actual_error) {
g_propagate_error (error, actual_error);
return;
@@ -2383,7 +2517,7 @@ tracker_data_insert_statement_with_string (const gchar *graph,
}
/* add value to metadata database */
- change = cache_set_metadata_decomposed (property, object, 0, graph, 0, &actual_error);
+ change = cache_insert_metadata_decomposed (property, object, 0, graph, 0, &actual_error);
if (actual_error) {
g_propagate_error (error, actual_error);
return;
@@ -2432,6 +2566,296 @@ tracker_data_insert_statement_with_string (const gchar *graph,
}
}
+static void
+tracker_data_update_statement_with_uri (const gchar *graph,
+ const gchar *subject,
+ const gchar *predicate,
+ const gchar *object,
+ GError **error)
+{
+ GError *actual_error = NULL;
+ TrackerClass *class;
+ TrackerProperty *property;
+ gint prop_id = 0, graph_id = 0;
+ gint final_prop_id = 0, object_id = 0;
+ gboolean change = FALSE;
+
+ g_return_if_fail (subject != NULL);
+ g_return_if_fail (predicate != NULL);
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (in_transaction);
+
+ property = tracker_ontologies_get_property_by_uri (predicate);
+ if (property == NULL) {
+ g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
+ "Property '%s' not found in the ontology", predicate);
+ return;
+ } else {
+ if (tracker_property_get_data_type (property) != TRACKER_PROPERTY_TYPE_RESOURCE) {
+ g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_TYPE,
+ "Property '%s' does not accept URIs", predicate);
+ return;
+ }
+ prop_id = tracker_property_get_id (property);
+ }
+
+ if (!tracker_property_get_transient (property)) {
+ has_persistent = TRUE;
+ }
+
+ /* subjects and objects starting with `:' are anonymous blank nodes */
+ if (g_str_has_prefix (object, ":")) {
+ /* anonymous blank node used as object in a statement */
+ const gchar *blank_uri;
+
+ if (blank_buffer.subject != NULL) {
+ if (strcmp (blank_buffer.subject, object) == 0) {
+ /* object still in blank buffer, need to flush buffer */
+ tracker_data_blank_buffer_flush (&actual_error);
+
+ if (actual_error) {
+ g_propagate_error (error, actual_error);
+ return;
+ }
+ }
+ }
+
+ blank_uri = g_hash_table_lookup (blank_buffer.table, object);
+
+ if (blank_uri != NULL) {
+ /* now insert statement referring to blank node */
+ tracker_data_update_statement (graph, subject, predicate, blank_uri, &actual_error);
+
+ g_hash_table_remove (blank_buffer.table, object);
+
+ if (actual_error) {
+ g_propagate_error (error, actual_error);
+ return;
+ }
+
+ return;
+ } else {
+ g_critical ("Blank node '%s' not found", object);
+ }
+ }
+
+ /* Update and insert share the exact same code here */
+ if (!tracker_data_insert_statement_common (graph, subject, predicate, object, &actual_error)) {
+ if (actual_error) {
+ g_propagate_error (error, actual_error);
+ return;
+ }
+
+ return;
+ }
+
+ if (strcmp (predicate, RDF_PREFIX "type") == 0) {
+ /* handle rdf:type statements specially to
+ cope with inference and insert blank rows */
+ class = tracker_ontologies_get_class_by_uri (object);
+ if (class != NULL) {
+ /* Create here is fine for Update too */
+ cache_create_service_decomposed (class, graph, 0);
+ } else {
+ g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNKNOWN_CLASS,
+ "Class '%s' not found in the ontology", object);
+ return;
+ }
+
+ if (!in_journal_replay && !tracker_property_get_transient (property)) {
+ graph_id = (graph != NULL ? query_resource_id (graph) : 0);
+ final_prop_id = (prop_id != 0) ? prop_id : tracker_data_query_resource_id (predicate);
+ object_id = query_resource_id (object);
+ }
+
+ change = TRUE;
+ } else {
+ /* update or add value to metadata database */
+ change = cache_update_metadata_decomposed (property, object, 0, graph, 0, &actual_error);
+ if (actual_error) {
+ g_propagate_error (error, actual_error);
+ return;
+ }
+
+ if (change) {
+ graph_id = (graph != NULL ? query_resource_id (graph) : 0);
+ final_prop_id = (prop_id != 0) ? prop_id : tracker_data_query_resource_id (predicate);
+ object_id = query_resource_id (object);
+
+ if (insert_callbacks) {
+ guint n;
+ for (n = 0; n < delete_callbacks->len; n++) {
+ TrackerStatementDelegate *delegate;
+
+ /* Don't pass object to the delete, it's not correct */
+ delegate = g_ptr_array_index (delete_callbacks, n);
+ delegate->callback (graph_id, graph, resource_buffer->id, subject,
+ final_prop_id, 0,
+ NULL,
+ resource_buffer->types,
+ delegate->user_data);
+ }
+ for (n = 0; n < insert_callbacks->len; n++) {
+ TrackerStatementDelegate *delegate;
+
+ delegate = g_ptr_array_index (insert_callbacks, n);
+ delegate->callback (graph_id, graph, resource_buffer->id, subject,
+ final_prop_id, object_id,
+ object,
+ resource_buffer->types,
+ delegate->user_data);
+ }
+ }
+ }
+ }
+
+ if (!in_journal_replay && change && !tracker_property_get_transient (property)) {
+ tracker_db_journal_append_update_statement_id (
+ (graph != NULL ? query_resource_id (graph) : 0),
+ resource_buffer->id,
+ final_prop_id,
+ object_id);
+ }
+}
+
+static void
+tracker_data_update_statement_with_string (const gchar *graph,
+ const gchar *subject,
+ const gchar *predicate,
+ const gchar *object,
+ GError **error)
+{
+ GError *actual_error = NULL;
+ TrackerProperty *property;
+ gboolean change, tried = FALSE;
+ gint graph_id = 0, pred_id = 0;
+
+
+ g_return_if_fail (subject != NULL);
+ g_return_if_fail (predicate != NULL);
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (in_transaction);
+
+ property = tracker_ontologies_get_property_by_uri (predicate);
+ if (property == NULL) {
+ g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
+ "Property '%s' not found in the ontology", predicate);
+ return;
+ } else {
+ if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) {
+ g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_TYPE,
+ "Property '%s' only accepts URIs", predicate);
+ return;
+ }
+ pred_id = tracker_property_get_id (property);
+ }
+
+ if (!tracker_property_get_transient (property)) {
+ has_persistent = TRUE;
+ }
+
+ /* Update and insert share the exact same code here */
+ if (!tracker_data_insert_statement_common (graph, subject, predicate, object, &actual_error)) {
+ if (actual_error) {
+ g_propagate_error (error, actual_error);
+ return;
+ }
+
+ return;
+ }
+
+ /* add or update value to metadata database */
+ change = cache_update_metadata_decomposed (property, object, 0, graph, 0, &actual_error);
+ if (actual_error) {
+ g_propagate_error (error, actual_error);
+ return;
+ }
+
+ if (insert_callbacks && change) {
+ guint n;
+
+ graph_id = (graph != NULL ? query_resource_id (graph) : 0);
+ pred_id = (pred_id != 0) ? pred_id : tracker_data_query_resource_id (predicate);
+ tried = TRUE;
+
+ for (n = 0; n < delete_callbacks->len; n++) {
+ TrackerStatementDelegate *delegate;
+
+ /* Don't pass object to the delete, it's not correct */
+ delegate = g_ptr_array_index (delete_callbacks, n);
+ delegate->callback (graph_id, graph, resource_buffer->id, subject,
+ pred_id, 0 /* Always a literal */,
+ NULL,
+ resource_buffer->types,
+ delegate->user_data);
+ }
+
+ for (n = 0; n < insert_callbacks->len; n++) {
+ TrackerStatementDelegate *delegate;
+
+ delegate = g_ptr_array_index (insert_callbacks, n);
+ delegate->callback (graph_id, graph, resource_buffer->id, subject,
+ pred_id, 0 /* Always a literal */,
+ object,
+ resource_buffer->types,
+ delegate->user_data);
+ }
+ }
+
+ if (!in_journal_replay && change && !tracker_property_get_transient (property)) {
+ if (!tried) {
+ graph_id = (graph != NULL ? query_resource_id (graph) : 0);
+ pred_id = (pred_id != 0) ? pred_id : tracker_data_query_resource_id (predicate);
+ }
+ if (!tracker_property_get_force_journal (property) &&
+ 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_update_statement (graph_id,
+ resource_buffer->id,
+ tracker_property_get_id (damaged),
+ "true");
+ } else {
+ tracker_db_journal_append_update_statement (graph_id,
+ resource_buffer->id,
+ pred_id,
+ object);
+ }
+ }
+}
+
+void
+tracker_data_update_statement (const gchar *graph,
+ const gchar *subject,
+ const gchar *predicate,
+ const gchar *object,
+ GError **error)
+{
+ TrackerProperty *property;
+
+ g_return_if_fail (subject != NULL);
+ g_return_if_fail (predicate != NULL);
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (in_transaction);
+
+ 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);
+ } 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,
+ "Property '%s' not found in the ontology", predicate);
+ }
+}
+
+/* --------------- */
+
+
void
tracker_data_begin_transaction (GError **error)
{
@@ -2746,7 +3170,8 @@ tracker_data_replay_journal (TrackerBusyCallback busy_callback,
g_clear_error (&new_error);
}
}
- } else if (type == TRACKER_DB_JOURNAL_INSERT_STATEMENT) {
+ } else if (type == TRACKER_DB_JOURNAL_INSERT_STATEMENT ||
+ type == TRACKER_DB_JOURNAL_UPDATE_STATEMENT) {
GError *new_error = NULL;
TrackerProperty *property = NULL;
@@ -2769,8 +3194,11 @@ tracker_data_replay_journal (TrackerBusyCallback busy_callback,
if (property) {
resource_buffer_switch (NULL, graph_id, NULL, subject_id);
- cache_set_metadata_decomposed (property, object, 0, NULL, graph_id, &new_error);
-
+ if (type == TRACKER_DB_JOURNAL_UPDATE_STATEMENT) {
+ cache_update_metadata_decomposed (property, object, 0, NULL, graph_id, &new_error);
+ } else {
+ cache_insert_metadata_decomposed (property, object, 0, NULL, graph_id, &new_error);
+ }
if (new_error) {
g_warning ("Journal replay error: '%s'", new_error->message);
g_clear_error (&new_error);
@@ -2780,7 +3208,8 @@ tracker_data_replay_journal (TrackerBusyCallback busy_callback,
g_warning ("Journal replay error: 'property with ID %d doesn't exist'", predicate_id);
}
- } else if (type == TRACKER_DB_JOURNAL_INSERT_STATEMENT_ID) {
+ } else if (type == TRACKER_DB_JOURNAL_INSERT_STATEMENT_ID ||
+ type == TRACKER_DB_JOURNAL_UPDATE_STATEMENT_ID) {
GError *new_error = NULL;
TrackerClass *class = NULL;
TrackerProperty *property = NULL;
@@ -2821,7 +3250,11 @@ tracker_data_replay_journal (TrackerBusyCallback busy_callback,
GError *new_error = NULL;
/* add value to metadata database */
- cache_set_metadata_decomposed (property, NULL, object_id, NULL, graph_id, &new_error);
+ if (type == TRACKER_DB_JOURNAL_UPDATE_STATEMENT_ID) {
+ cache_update_metadata_decomposed (property, NULL, object_id, NULL, graph_id, &new_error);
+ } else {
+ cache_insert_metadata_decomposed (property, NULL, object_id, NULL, graph_id, &new_error);
+ }
if (new_error) {
g_warning ("Journal replay error: '%s'", new_error->message);
diff --git a/src/libtracker-data/tracker-data-update.h b/src/libtracker-data/tracker-data-update.h
index 92b1045..1bed0d9 100644
--- a/src/libtracker-data/tracker-data-update.h
+++ b/src/libtracker-data/tracker-data-update.h
@@ -69,6 +69,11 @@ void tracker_data_insert_statement_with_string (const gchar *
const gchar *predicate,
const gchar *object,
GError **error);
+void tracker_data_update_statement (const gchar *graph,
+ const gchar *subject,
+ const gchar *predicate,
+ const gchar *object,
+ GError **error);
void tracker_data_begin_transaction (GError **error);
void tracker_data_begin_ontology_transaction (GError **error);
void tracker_data_begin_transaction_for_replay (time_t time,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]