summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2020-04-08 23:34:14 +0200
committerCarlos Garnacho <carlosg@gnome.org>2020-04-27 19:08:13 +0200
commitd8e8903546cdd04f8b01ebd28e1682b75a633da1 (patch)
tree23142eedc444689cbfcc53e124c73e43c8fb5d75 /src
parent77662eae30af129b294c4644c53474df65e289d5 (diff)
downloadtracker-d8e8903546cdd04f8b01ebd28e1682b75a633da1.tar.gz
libtracker-data: Simplify tracker_data_update_statement()
The SPARQL specs don't define "update" operations, we only have this for our INSERT OR REPLACE syntax extension. Make it less of a full blown operation, and more ad-hoc to fit its single usecase.
Diffstat (limited to 'src')
-rw-r--r--src/libtracker-data/tracker-data-update.c440
1 files changed, 78 insertions, 362 deletions
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index dd7fcceac..fd70a07d8 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -1566,10 +1566,16 @@ cache_insert_metadata_decomposed (TrackerData *data,
while (*super_properties) {
gboolean super_is_multi;
+ GArray *super_old_values;
super_is_multi = tracker_property_get_multiple_values (*super_properties);
+ super_old_values = get_old_property_values (data, *super_properties, &new_error);
+ if (new_error) {
+ g_propagate_error (error, new_error);
+ return FALSE;
+ }
- if (super_is_multi || old_values->len == 0) {
+ if (super_is_multi || super_old_values->len == 0) {
change |= cache_insert_metadata_decomposed (data, *super_properties, value,
&new_error);
if (new_error) {
@@ -1708,97 +1714,6 @@ delete_first_object (TrackerData *data,
}
static gboolean
-cache_update_metadata_decomposed (TrackerData *data,
- TrackerProperty *property,
- GValue *value,
- const gchar *graph,
- GError **error)
-{
- gboolean multiple_values;
- const gchar *table_name;
- const gchar *field_name;
- TrackerProperty **super_properties;
- GError *new_error = NULL;
- gboolean change = FALSE;
-
- multiple_values = tracker_property_get_multiple_values (property);
-
- /* also insert super property values */
- super_properties = tracker_property_get_super_properties (property);
- while (*super_properties) {
- gboolean super_is_multi;
- super_is_multi = tracker_property_get_multiple_values (*super_properties);
-
- if (!multiple_values && super_is_multi) {
- gint subject_id;
- gchar *subject;
-
- GArray *old_values;
-
- /* read existing property values */
- old_values = get_old_property_values (data, property, &new_error);
- if (new_error) {
- g_propagate_error (error, new_error);
- return FALSE;
- }
-
- /* Delete old values from super */
- change |= delete_first_object (data, *super_properties,
- old_values,
- &new_error);
-
- if (new_error) {
- g_propagate_error (error, new_error);
- return FALSE;
- }
-
- subject_id = data->resource_buffer->id;
- subject = g_strdup (data->resource_buffer->subject);
-
- /* We need to flush to apply the delete */
- tracker_data_update_buffer_flush (data, &new_error);
- if (new_error) {
- g_propagate_error (error, new_error);
- g_free (subject);
- return FALSE;
- }
-
- /* After flush we need to switch the resource_buffer */
- if (!resource_buffer_switch (data, graph, subject, subject_id, &new_error)) {
- g_propagate_error (error, new_error);
- g_free (subject);
- return FALSE;
- }
-
- g_free (subject);
- }
-
- change |= cache_update_metadata_decomposed (data, *super_properties, value,
- graph, &new_error);
- if (new_error) {
- g_propagate_error (error, new_error);
- return FALSE;
- }
- super_properties++;
- }
-
- table_name = tracker_property_get_table_name (property);
- field_name = tracker_property_get_name (property);
-
- cache_insert_value (data, table_name, field_name,
- value,
- multiple_values,
- tracker_property_get_fulltext_indexed (property),
- tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME);
-
- if (!multiple_values) {
- process_domain_indexes (data, property, value, field_name);
- }
-
- return TRUE;
-}
-
-static gboolean
delete_metadata_decomposed (TrackerData *data,
TrackerProperty *property,
GValue *value,
@@ -2338,6 +2253,58 @@ delete_all_objects (TrackerData *data,
}
}
+static gboolean
+delete_single_valued (TrackerData *data,
+ const gchar *graph,
+ const gchar *subject,
+ const gchar *predicate,
+ gboolean super_is_single_valued,
+ GError **error)
+{
+ TrackerProperty *field, **super_properties;
+ TrackerOntologies *ontologies;
+ gboolean multiple_values;
+
+ ontologies = tracker_data_manager_get_ontologies (data->manager);
+ field = tracker_ontologies_get_property_by_uri (ontologies, predicate);
+ super_properties = tracker_property_get_super_properties (field);
+ multiple_values = tracker_property_get_multiple_values (field);
+
+ if (super_is_single_valued && multiple_values) {
+ delete_all_objects (data, graph, subject, predicate, error);
+ } else if (!multiple_values) {
+ GError *inner_error = NULL;
+ GArray *old_values;
+
+ old_values = get_old_property_values (data, field, &inner_error);
+
+ if (old_values && old_values->len == 1) {
+ cache_delete_value (data,
+ tracker_property_get_table_name (field),
+ tracker_property_get_name (field),
+ &g_array_index (old_values, GValue, 0),
+ FALSE,
+ tracker_property_get_fulltext_indexed (field),
+ tracker_property_get_data_type (field) == TRACKER_PROPERTY_TYPE_DATETIME);
+ } else {
+ /* no need to error out if statement does not exist for any reason */
+ g_clear_error (&inner_error);
+ }
+ }
+
+ while (*super_properties) {
+ if (!delete_single_valued (data, graph, subject,
+ tracker_property_get_uri (*super_properties),
+ super_is_single_valued,
+ error))
+ return FALSE;
+
+ super_properties++;
+ }
+
+ return TRUE;
+}
+
void
tracker_data_insert_statement (TrackerData *data,
const gchar *graph,
@@ -2555,270 +2522,6 @@ tracker_data_insert_statement_with_string (TrackerData *data,
}
}
-static void
-tracker_data_update_statement_with_uri (TrackerData *data,
- const gchar *graph,
- const gchar *subject,
- const gchar *predicate,
- GBytes *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;
- TrackerOntologies *ontologies;
- TrackerDBInterface *iface;
- const gchar *object_str;
-
- g_return_if_fail (subject != NULL);
- g_return_if_fail (predicate != NULL);
- g_return_if_fail (data->in_transaction);
-
- ontologies = tracker_data_manager_get_ontologies (data->manager);
- iface = tracker_data_manager_get_writable_db_interface (data->manager);
-
- property = tracker_ontologies_get_property_by_uri (ontologies, 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);
- }
-
- data->has_persistent = TRUE;
-
- if (!resource_buffer_switch (data, graph, subject, 0, error))
- return;
-
- if (graph)
- graph_id = tracker_data_manager_find_graph (data->manager, graph);
-
- object_str = g_bytes_get_data (object, NULL);
-
- if (property == tracker_ontologies_get_rdf_type (ontologies)) {
- /* handle rdf:type statements specially to
- cope with inference and insert blank rows */
- class = tracker_ontologies_get_class_by_uri (ontologies, object_str);
- if (class != NULL) {
- /* Create here is fine for Update too */
- cache_create_service_decomposed (data, class);
- } else {
- g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNKNOWN_CLASS,
- "Class '%s' not found in the ontology", object_str);
- return;
- }
-
- final_prop_id = (prop_id != 0) ? prop_id : tracker_data_query_resource_id (data->manager, iface, predicate);
- object_id = query_resource_id (data, object_str);
-
- change = TRUE;
- } else {
- gint old_object_id = 0;
- GArray *old_values;
- gboolean multiple_values;
- GError *new_error = NULL;
- gboolean domain_unchecked = TRUE;
- GValue object_value = G_VALUE_INIT;
-
- multiple_values = tracker_property_get_multiple_values (property);
-
- /* This is unavoidable with FTS */
- /* This does a check_property_domain too */
- old_values = get_old_property_values (data, property, &new_error);
- domain_unchecked = FALSE;
- if (!new_error) {
- if (old_values->len > 0) {
- /* evel knievel cast */
- GValue *v;
-
- v = &g_array_index (old_values, GValue, 0);
- old_object_id = (gint) g_value_get_int64 (v);
- }
- } else {
- g_propagate_error (error, new_error);
- return;
- }
-
- if (domain_unchecked && !check_property_domain (data, property)) {
- g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_CONSTRAINT,
- "Subject `%s' is not in domain `%s' of property `%s'",
- data->resource_buffer->subject,
- tracker_class_get_name (tracker_property_get_domain (property)),
- tracker_property_get_name (property));
- return;
- }
-
- bytes_to_gvalue (object, tracker_property_get_data_type (property), &object_value, data, &new_error);
- if (new_error) {
- g_propagate_error (error, new_error);
- return;
- }
-
- /* update or add value to metadata database */
- change = cache_update_metadata_decomposed (data, property, &object_value, graph, &actual_error);
- g_value_unset (&object_value);
-
- if (actual_error) {
- g_propagate_error (error, actual_error);
- return;
- }
-
- if (change) {
- final_prop_id = (prop_id != 0) ? prop_id : tracker_data_query_resource_id (data->manager, iface, predicate);
- object_id = query_resource_id (data, object_str);
-
- if (!multiple_values && data->delete_callbacks) {
- guint n;
-
- for (n = 0; n < data->delete_callbacks->len; n++) {
- TrackerStatementDelegate *delegate;
-
- /* Don't pass object to the delete, it's not correct */
- delegate = g_ptr_array_index (data->delete_callbacks, n);
- delegate->callback (graph_id, graph, data->resource_buffer->id, subject,
- final_prop_id, old_object_id,
- NULL,
- data->resource_buffer->types,
- delegate->user_data);
- }
- }
-
- if (data->insert_callbacks) {
- guint n;
-
- for (n = 0; n < data->insert_callbacks->len; n++) {
- TrackerStatementDelegate *delegate;
-
- delegate = g_ptr_array_index (data->insert_callbacks, n);
- delegate->callback (graph_id, graph, data->resource_buffer->id, subject,
- final_prop_id, object_id,
- object_str,
- data->resource_buffer->types,
- delegate->user_data);
- }
- }
- }
- }
-}
-
-static void
-tracker_data_update_statement_with_string (TrackerData *data,
- const gchar *graph,
- const gchar *subject,
- const gchar *predicate,
- GBytes *object,
- GError **error)
-{
- GError *actual_error = NULL;
- TrackerProperty *property;
- gboolean change;
- gint graph_id = 0, pred_id = 0;
- gboolean multiple_values;
- TrackerOntologies *ontologies;
- TrackerDBInterface *iface;
- GValue object_value = G_VALUE_INIT;
- const gchar *object_str;
- GError *new_error = NULL;
-
- g_return_if_fail (subject != NULL);
- g_return_if_fail (predicate != NULL);
- g_return_if_fail (data->in_transaction);
-
- ontologies = tracker_data_manager_get_ontologies (data->manager);
- iface = tracker_data_manager_get_writable_db_interface (data->manager);
-
- property = tracker_ontologies_get_property_by_uri (ontologies, 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);
- }
-
- multiple_values = tracker_property_get_multiple_values (property);
-
- data->has_persistent = TRUE;
-
- if (!resource_buffer_switch (data, graph, subject, 0, error))
- return;
-
- /* This is unavoidable with FTS */
- get_old_property_values (data, property, &new_error);
- if (new_error) {
- g_propagate_error (error, new_error);
- return;
- }
-
- bytes_to_gvalue (object, tracker_property_get_data_type (property), &object_value, data, &new_error);
- if (new_error) {
- g_propagate_error (error, new_error);
- return;
- }
-
- /* add or update value to metadata database */
- change = cache_update_metadata_decomposed (data, property, &object_value, graph, &actual_error);
- g_value_unset (&object_value);
-
- if (actual_error) {
- g_propagate_error (error, actual_error);
- return;
- }
-
- if (graph)
- graph_id = tracker_data_manager_find_graph (data->manager, graph);
-
- object_str = g_bytes_get_data (object, NULL);
-
- if (((!multiple_values && data->delete_callbacks) || data->insert_callbacks) && change) {
- pred_id = (pred_id != 0) ? pred_id : tracker_data_query_resource_id (data->manager, iface, predicate);
- }
-
- if ((!multiple_values && data->delete_callbacks) && change) {
- guint n;
-
- for (n = 0; n < data->delete_callbacks->len; n++) {
- TrackerStatementDelegate *delegate;
-
- /* Don't pass object to the delete, it's not correct */
- delegate = g_ptr_array_index (data->delete_callbacks, n);
- delegate->callback (graph_id, graph, data->resource_buffer->id, subject,
- pred_id, 0 /* Always a literal */,
- NULL,
- data->resource_buffer->types,
- delegate->user_data);
- }
- }
-
- if (data->insert_callbacks && change) {
- guint n;
- for (n = 0; n < data->insert_callbacks->len; n++) {
- TrackerStatementDelegate *delegate;
-
- delegate = g_ptr_array_index (data->insert_callbacks, n);
- delegate->callback (graph_id, graph, data->resource_buffer->id, subject,
- pred_id, 0 /* Always a literal */,
- object_str,
- data->resource_buffer->types,
- delegate->user_data);
- }
- }
-}
-
void
tracker_data_update_statement (TrackerData *data,
const gchar *graph,
@@ -2829,6 +2532,7 @@ tracker_data_update_statement (TrackerData *data,
{
TrackerProperty *property;
TrackerOntologies *ontologies;
+ GError *new_error = NULL;
g_return_if_fail (subject != NULL);
g_return_if_fail (predicate != NULL);
@@ -2839,7 +2543,6 @@ tracker_data_update_statement (TrackerData *data,
if (property != NULL) {
if (object == NULL) {
- GError *new_error = NULL;
if (property == tracker_ontologies_get_rdf_type (ontologies)) {
g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNSUPPORTED,
"Using 'null' with '%s' is not supported", predicate);
@@ -2856,21 +2559,34 @@ tracker_data_update_statement (TrackerData *data,
}
delete_all_objects (data, graph, subject, predicate, error);
+ } else {
+ if (!resource_buffer_switch (data, graph, subject,
+ ensure_resource_id (data, subject, NULL),
+ error))
+ return;
- /* Flush at the end to make null, x work. When x arrives the null
- * (delete all values of the multivalue) must be flushed */
+ if (!delete_single_valued (data, graph, subject, predicate,
+ !tracker_property_get_multiple_values (property),
+ error))
+ return;
tracker_data_update_buffer_flush (data, &new_error);
if (new_error) {
g_propagate_error (error, new_error);
+ return;
}
- } else {
+
if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) {
- tracker_data_update_statement_with_uri (data, graph, subject, predicate, object, error);
+ tracker_data_insert_statement_with_uri (data, graph, subject, predicate, object, error);
} else {
- tracker_data_update_statement_with_string (data, graph, subject, predicate, object, error);
+ tracker_data_insert_statement_with_string (data, graph, subject, predicate, object, error);
}
}
+
+ tracker_data_update_buffer_flush (data, &new_error);
+ if (new_error) {
+ g_propagate_error (error, new_error);
+ }
} else {
g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
"Property '%s' not found in the ontology", predicate);