summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam@afuera.me.uk>2020-11-27 13:35:08 +0000
committerSam Thursfield <sam@afuera.me.uk>2020-11-27 13:35:08 +0000
commitf235199ceb3dc5afcd07270760347faede0a81c0 (patch)
tree30dd0d3b75c03faf39626ba7a457dca7e1218541
parentb909e9fc05b5af5f2433c67b8bd48fae5c7c8ad8 (diff)
parentabbb813542d7e9f906232f2f35e299b43d65703a (diff)
downloadtracker-f235199ceb3dc5afcd07270760347faede0a81c0.tar.gz
Merge branch 'wip/carlosg/batches-and-resources' into 'master'
Batches and resources See merge request GNOME/tracker!345
-rw-r--r--docs/reference/libtracker-sparql/libtracker-sparql-docs.xml33
-rw-r--r--docs/reference/libtracker-sparql/libtracker-sparql-sections.txt37
-rw-r--r--docs/reference/libtracker-sparql/libtracker-sparql.types1
-rw-r--r--src/libtracker-data/tracker-data-manager.c65
-rw-r--r--src/libtracker-data/tracker-data-manager.h6
-rw-r--r--src/libtracker-data/tracker-data-update.c349
-rw-r--r--src/libtracker-data/tracker-data-update.h6
-rw-r--r--src/libtracker-data/tracker-sparql.c62
-rw-r--r--src/libtracker-data/tracker-sparql.h3
-rw-r--r--src/libtracker-sparql/direct/meson.build1
-rw-r--r--src/libtracker-sparql/direct/tracker-direct-batch.c255
-rw-r--r--src/libtracker-sparql/direct/tracker-direct-batch.h45
-rw-r--r--src/libtracker-sparql/direct/tracker-direct.c266
-rw-r--r--src/libtracker-sparql/direct/tracker-direct.h16
-rw-r--r--src/libtracker-sparql/meson.build8
-rw-r--r--src/libtracker-sparql/tracker-batch.c293
-rw-r--r--src/libtracker-sparql/tracker-batch.h70
-rw-r--r--src/libtracker-sparql/tracker-connection.c118
-rw-r--r--src/libtracker-sparql/tracker-connection.h22
-rw-r--r--src/libtracker-sparql/tracker-namespace-manager.c16
-rw-r--r--src/libtracker-sparql/tracker-notifier.c6
-rw-r--r--src/libtracker-sparql/tracker-private.h43
-rw-r--r--src/libtracker-sparql/tracker-resource.c91
-rw-r--r--src/libtracker-sparql/tracker-resource.h3
-rw-r--r--src/libtracker-sparql/tracker-sparql.h2
-rw-r--r--src/libtracker-sparql/tracker-uri.c6
-rw-r--r--src/libtracker-sparql/tracker-version-generated.h.meson.in28
-rw-r--r--src/libtracker-sparql/tracker-version.c2
-rw-r--r--src/libtracker-sparql/tracker-version.h36
29 files changed, 1680 insertions, 209 deletions
diff --git a/docs/reference/libtracker-sparql/libtracker-sparql-docs.xml b/docs/reference/libtracker-sparql/libtracker-sparql-docs.xml
index 792f309e7..2599b0f5a 100644
--- a/docs/reference/libtracker-sparql/libtracker-sparql-docs.xml
+++ b/docs/reference/libtracker-sparql/libtracker-sparql-docs.xml
@@ -36,6 +36,7 @@
<xi:include href="xml/tracker-sparql-cursor.xml"/>
<xi:include href="xml/tracker-notifier.xml"/>
<xi:include href="xml/tracker-endpoint.xml"/>
+ <xi:include href="xml/tracker-batch.xml"/>
<xi:include href="xml/tracker-misc.xml"/>
<xi:include href="xml/tracker-version.xml"/>
<xi:include href="xml/tracker-sparql-error.xml"/>
@@ -67,33 +68,13 @@
<title>Index of deprecated symbols</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
</index>
- <index id="api-index-0-10" role="0.10">
- <title>Index of new symbols in 0.10</title>
- <xi:include href="xml/api-index-0.10.xml"><xi:fallback /></xi:include>
+ <index id="api-index-3-0" role="3.0">
+ <title>Index of new symbols in 3.1</title>
+ <xi:include href="xml/api-index-3.0.xml"><xi:fallback /></xi:include>
</index>
- <index id="api-index-0-12" role="0.12">
- <title>Index of new symbols in 0.12</title>
- <xi:include href="xml/api-index-0.12.xml"><xi:fallback /></xi:include>
- </index>
- <index id="api-index-1-10" role="1.10">
- <title>Index of new symbols in 1.10</title>
- <xi:include href="xml/api-index-1.10.xml"><xi:fallback /></xi:include>
- </index>
- <index id="api-index-1-12" role="1.12">
- <title>Index of new symbols in 1.12</title>
- <xi:include href="xml/api-index-1.12.xml"><xi:fallback /></xi:include>
- </index>
- <index id="api-index-2-0" role="2.0">
- <title>Index of new symbols in 2.0</title>
- <xi:include href="xml/api-index-2.0.xml"><xi:fallback /></xi:include>
- </index>
- <index id="api-index-2-0-5" role="2.0.5">
- <title>Index of new symbols in 2.0.5</title>
- <xi:include href="xml/api-index-2.0.5.xml"><xi:fallback /></xi:include>
- </index>
- <index id="api-index-2-2" role="2.2">
- <title>Index of new symbols in 2.2</title>
- <xi:include href="xml/api-index-2.2.xml"><xi:fallback /></xi:include>
+ <index id="api-index-3-1" role="3.1">
+ <title>Index of new symbols in 3.1</title>
+ <xi:include href="xml/api-index-3.1.xml"><xi:fallback /></xi:include>
</index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
diff --git a/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt b/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
index e78d96b0a..93d73f2b4 100644
--- a/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
+++ b/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
@@ -47,6 +47,7 @@ tracker_resource_get_first_uri
tracker_resource_get_identifier
tracker_resource_get_values
tracker_resource_get_properties
+tracker_resource_get_property_overwrite
tracker_resource_identifier_compare_func
tracker_resource_print_sparql_update
tracker_resource_print_turtle
@@ -117,8 +118,12 @@ tracker_sparql_connection_update_array_finish
tracker_sparql_connection_update_blank
tracker_sparql_connection_update_blank_async
tracker_sparql_connection_update_blank_finish
+tracker_sparql_connection_update_resource
+tracker_sparql_connection_update_resource_async
+tracker_sparql_connection_update_resource_finish
tracker_sparql_connection_get_namespace_manager
tracker_sparql_connection_create_notifier
+tracker_sparql_connection_create_batch
tracker_sparql_connection_close
tracker_sparql_connection_close_async
tracker_sparql_connection_close_finish
@@ -264,6 +269,27 @@ tracker_endpoint_dbus_get_type
</SECTION>
<SECTION>
+<FILE>tracker-batch</FILE>
+<TITLE>TrackerBatch</TITLE>
+TrackerBatch
+tracker_batch_get_connection
+tracker_batch_add_sparql
+tracker_batch_add_resource
+tracker_batch_execute
+tracker_batch_execute_async
+tracker_batch_execute_finish
+<SUBSECTION Standard>
+TrackerBatchClass
+TRACKER_BATCH
+TRACKER_BATCH_CLASS
+TRACKER_BATCH_GET_CLASS
+TRACKER_IS_BATCH
+TRACKER_IS_BATCH_CLASS
+TRACKER_TYPE_BATCH
+tracker_batch_get_type
+</SECTION>
+
+<SECTION>
<TITLE>Version Information</TITLE>
<FILE>tracker-version</FILE>
tracker_major_version
@@ -274,7 +300,18 @@ tracker_interface_age
tracker_check_version
<SUBSECTION>
+TRACKER_MAJOR_VERSION
+TRACKER_MINOR_VERSION
+TRACKER_MICRO_VERSION
TRACKER_CHECK_VERSION
<SUBSECTION Private>
TRACKER_AVAILABLE_IN_ALL
+TRACKER_AVAILABLE_IN_3_1
+TRACKER_DEPRECATED_IN_3_1
+TRACKER_DEPRECATED_IN_3_1_FOR
+TRACKER_VERSION_MAX_ALLOWED
+TRACKER_VERSION_MIN_REQUIRED
+TRACKER_VERSION_CUR
+TRACKER_VERSION_3_0
+TRACKER_VERSION_3_1
</SECTION>
diff --git a/docs/reference/libtracker-sparql/libtracker-sparql.types b/docs/reference/libtracker-sparql/libtracker-sparql.types
index 21681e1ee..4a94c21cc 100644
--- a/docs/reference/libtracker-sparql/libtracker-sparql.types
+++ b/docs/reference/libtracker-sparql/libtracker-sparql.types
@@ -11,3 +11,4 @@ tracker_sparql_connection_get_type
tracker_sparql_connection_flags_get_type
tracker_sparql_cursor_get_type
tracker_sparql_statement_get_type
+tracker_batch_get_type
diff --git a/src/libtracker-data/tracker-data-manager.c b/src/libtracker-data/tracker-data-manager.c
index bbb4d2e0e..bea674b3e 100644
--- a/src/libtracker-data/tracker-data-manager.c
+++ b/src/libtracker-data/tracker-data-manager.c
@@ -5108,3 +5108,68 @@ tracker_data_manager_release_memory (TrackerDataManager *manager)
{
tracker_db_manager_release_memory (manager->db_manager);
}
+
+gboolean
+tracker_data_manager_expand_prefix (TrackerDataManager *manager,
+ const gchar *term,
+ GHashTable *prefix_map,
+ gchar **prefix,
+ gchar **expanded)
+{
+ const gchar *sep, *expanded_ns = NULL;
+ TrackerOntologies *ontologies;
+ TrackerNamespace **namespaces;
+ guint n_namespaces, i;
+ gchar *ns;
+
+ sep = strchr (term, ':');
+
+ if (sep) {
+ ns = g_strndup (term, sep - term);
+ sep++;
+ } else {
+ ns = g_strdup (term);
+ }
+
+ if (prefix_map)
+ expanded_ns = g_hash_table_lookup (prefix_map, ns);
+
+ if (!expanded_ns) {
+ ontologies = tracker_data_manager_get_ontologies (manager);
+ namespaces = tracker_ontologies_get_namespaces (ontologies, &n_namespaces);
+
+ for (i = 0; i < n_namespaces; i++) {
+ if (!g_str_equal (ns, tracker_namespace_get_prefix (namespaces[i])))
+ continue;
+
+ expanded_ns = tracker_namespace_get_uri (namespaces[i]);
+
+ if (prefix_map)
+ g_hash_table_insert (prefix_map, ns, g_strdup (expanded_ns));
+ break;
+ }
+ }
+
+ if (!expanded_ns) {
+ if (prefix)
+ *prefix = NULL;
+ if (expanded)
+ *expanded = g_strdup (term);
+
+ g_free (ns);
+ return FALSE;
+ }
+
+ if (prefix)
+ *prefix = g_strdup (expanded_ns);
+
+ if (expanded) {
+ if (sep) {
+ *expanded = g_strdup_printf ("%s%s", expanded_ns, sep);
+ } else {
+ *expanded = g_strdup (expanded_ns);
+ }
+ }
+
+ return TRUE;
+}
diff --git a/src/libtracker-data/tracker-data-manager.h b/src/libtracker-data/tracker-data-manager.h
index db8b4e509..474e8f815 100644
--- a/src/libtracker-data/tracker-data-manager.h
+++ b/src/libtracker-data/tracker-data-manager.h
@@ -107,6 +107,12 @@ void tracker_data_manager_commit_graphs (TrackerDataManager *man
void tracker_data_manager_release_memory (TrackerDataManager *manager);
+gboolean tracker_data_manager_expand_prefix (TrackerDataManager *manager,
+ const gchar *term,
+ GHashTable *prefix_map,
+ gchar **prefix,
+ gchar **expanded);
+
G_END_DECLS
#endif /* __LIBTRACKER_DATA_MANAGER_H__ */
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 3ce1b7897..378f434bc 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -164,6 +164,12 @@ static gboolean resource_buffer_switch (TrackerData *data,
const gchar *subject,
gint subject_id,
GError **error);
+static gboolean update_resource_single (TrackerData *data,
+ const gchar *graph,
+ TrackerResource *resource,
+ GHashTable *visited,
+ GHashTable *bnodes,
+ GError **error);
void tracker_data_insert_statement_with_uri (TrackerData *data,
const gchar *graph,
@@ -1618,6 +1624,101 @@ bytes_to_gvalue (GBytes *bytes,
}
}
+static const gchar *
+get_bnode_for_resource (GHashTable *bnodes,
+ TrackerData *data,
+ TrackerResource *resource)
+{
+ TrackerDBInterface *iface;
+ const gchar *identifier;
+ gchar *bnode;
+
+ bnode = g_hash_table_lookup (bnodes, resource);
+ if (bnode)
+ return bnode;
+
+ iface = tracker_data_manager_get_writable_db_interface (data->manager);
+ bnode = tracker_data_query_unused_uuid (data->manager,
+ iface);
+ identifier = tracker_resource_get_identifier (resource);
+ g_hash_table_insert (bnodes, g_strdup (identifier), bnode);
+
+ return bnode;
+}
+
+static void
+bytes_from_gvalue (GValue *gvalue,
+ GBytes **bytes,
+ TrackerData *data,
+ GHashTable *bnodes)
+{
+ gchar *str;
+
+ if (G_VALUE_HOLDS_BOOLEAN (gvalue)) {
+ if (g_value_get_boolean (gvalue)) {
+ *bytes = g_bytes_new_static ("true", strlen ("true") + 1);
+ } else {
+ *bytes = g_bytes_new_static ("false", strlen ("false") + 1);
+ }
+ } else if (G_VALUE_HOLDS_INT (gvalue)) {
+ str = g_strdup_printf ("%d", g_value_get_int (gvalue));
+ *bytes = g_bytes_new_take (str, strlen (str) + 1);
+ } else if (G_VALUE_HOLDS_INT64 (gvalue)) {
+ str = g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (gvalue));
+ *bytes = g_bytes_new_take (str, strlen (str) + 1);
+ } else if (G_VALUE_HOLDS_DOUBLE (gvalue)) {
+ gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
+ g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE,
+ g_value_get_double (gvalue));
+ *bytes = g_bytes_new (buffer, strlen (buffer) + 1);
+ } else if (g_strcmp0 (G_VALUE_TYPE_NAME (gvalue), "TrackerUri") == 0) {
+ /* FIXME: We can't access TrackerUri GType here */
+ const gchar *uri;
+ gchar *expanded;
+
+ uri = g_value_get_string (gvalue);
+
+ if (g_str_has_prefix (uri, "_:")) {
+ gchar *bnode;
+
+ bnode = g_hash_table_lookup (bnodes, uri);
+
+ if (!bnode) {
+ TrackerDBInterface *iface;
+
+ iface = tracker_data_manager_get_writable_db_interface (data->manager);
+ bnode = tracker_data_query_unused_uuid (data->manager,
+ iface);
+ g_hash_table_insert (bnodes, g_strdup (uri), bnode);
+ }
+
+ *bytes = g_bytes_new (bnode, strlen (bnode) + 1);
+ } else if (tracker_data_manager_expand_prefix (data->manager,
+ g_value_get_string (gvalue),
+ NULL, NULL,
+ &expanded)) {
+ *bytes = g_bytes_new_take (expanded, strlen (expanded) + 1);
+ } else {
+ *bytes = g_bytes_new (uri, strlen (uri) + 1);
+ }
+ } else if (G_VALUE_HOLDS_STRING (gvalue)) {
+ const gchar *ptr;
+ ptr = g_value_get_string (gvalue);
+ *bytes = g_bytes_new (ptr, strlen (ptr) + 1);
+ } else if (G_VALUE_HOLDS (gvalue, TRACKER_TYPE_RESOURCE)) {
+ TrackerResource *res;
+ const gchar *object;
+
+ res = g_value_get_object (gvalue);
+ object = tracker_resource_get_identifier (res);
+
+ if (!object || g_str_has_prefix (object, "_:"))
+ object = get_bnode_for_resource (bnodes, data, res);
+
+ *bytes = g_bytes_new (object, strlen (object) + 1);
+ }
+}
+
static gboolean
resource_in_domain_index_class (TrackerData *data,
TrackerClass *domain_index_class)
@@ -2169,6 +2270,66 @@ tracker_data_delete_statement (TrackerData *data,
}
}
+static void
+tracker_data_delete_all (TrackerData *data,
+ const gchar *graph,
+ const gchar *subject,
+ const gchar *predicate,
+ GError **error)
+{
+ gint subject_id = 0;
+ TrackerOntologies *ontologies;
+ TrackerProperty *property;
+ GArray *old_values;
+ GError *inner_error = NULL;
+ guint i;
+
+ g_return_if_fail (subject != NULL);
+ g_return_if_fail (predicate != NULL);
+ g_return_if_fail (data->in_transaction);
+
+ subject_id = query_resource_id (data, subject);
+
+ if (subject_id == 0) {
+ /* subject not in database */
+ return;
+ }
+
+ if (!resource_buffer_switch (data, graph, subject, subject_id, error))
+ return;
+
+ ontologies = tracker_data_manager_get_ontologies (data->manager);
+ property = tracker_ontologies_get_property_by_uri (ontologies,
+ predicate);
+ old_values = get_old_property_values (data, property, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return;
+ }
+
+ for (i = 0; i < old_values->len; i++) {
+ GValue *value;
+ GBytes *bytes;
+
+ value = &g_array_index (old_values, GValue, i);
+ bytes_from_gvalue (value,
+ &bytes,
+ data,
+ NULL);
+
+ tracker_data_delete_statement (data, graph, subject,
+ predicate, bytes,
+ &inner_error);
+ g_bytes_unref (bytes);
+
+ if (inner_error)
+ break;
+ }
+
+ if (inner_error)
+ g_propagate_error (error, inner_error);
+}
+
static gboolean
delete_single_valued (TrackerData *data,
const gchar *graph,
@@ -2637,7 +2798,7 @@ update_sparql (TrackerData *data,
}
sparql_query = tracker_sparql_new_update (data->manager, update);
- blank_nodes = tracker_sparql_execute_update (sparql_query, blank, &actual_error);
+ blank_nodes = tracker_sparql_execute_update (sparql_query, blank, NULL, &actual_error);
g_object_unref (sparql_query);
if (actual_error) {
@@ -2776,3 +2937,189 @@ tracker_data_delete_graph (TrackerData *data,
return TRUE;
}
+
+static gboolean
+resource_maybe_reset_property (TrackerData *data,
+ const gchar *graph,
+ TrackerResource *resource,
+ const gchar *subject_uri,
+ const gchar *property_uri,
+ GHashTable *bnodes,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ const gchar *subject;
+
+ /* If the subject is a blank node, this is a whole new insertion.
+ * We don't need deleting anything then.
+ */
+ subject = tracker_resource_get_identifier (resource);
+ if (g_str_has_prefix (subject, "_:"))
+ return TRUE;
+
+ tracker_data_delete_all (data,
+ graph, subject_uri, property_uri,
+ &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+update_resource_property (TrackerData *data,
+ const gchar *graph_uri,
+ TrackerResource *resource,
+ const gchar *subject,
+ const gchar *property,
+ GHashTable *visited,
+ GHashTable *bnodes,
+ GError **error)
+{
+ GList *values, *v;
+ gchar *property_uri;
+ GError *inner_error = NULL;
+
+ values = tracker_resource_get_values (resource, property);
+ tracker_data_manager_expand_prefix (data->manager,
+ property,
+ NULL, NULL,
+ &property_uri);
+
+ if (tracker_resource_get_property_overwrite (resource, property) &&
+ !resource_maybe_reset_property (data, graph_uri, resource,
+ subject, property_uri,
+ bnodes, error)) {
+ g_free (property_uri);
+ return FALSE;
+ }
+
+ for (v = values; v && !inner_error; v = v->next) {
+ GBytes *bytes = NULL;
+
+ if (G_VALUE_HOLDS (v->data, TRACKER_TYPE_RESOURCE)) {
+ update_resource_single (data,
+ graph_uri,
+ g_value_get_object (v->data),
+ visited,
+ bnodes,
+ &inner_error);
+ if (inner_error)
+ break;
+ }
+
+ bytes_from_gvalue (v->data,
+ &bytes,
+ data,
+ bnodes);
+
+ tracker_data_insert_statement (data,
+ graph_uri,
+ subject,
+ property_uri,
+ bytes,
+ &inner_error);
+ g_bytes_unref (bytes);
+ }
+
+ g_list_free (values);
+ g_free (property_uri);
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+update_resource_single (TrackerData *data,
+ const gchar *graph,
+ TrackerResource *resource,
+ GHashTable *visited,
+ GHashTable *bnodes,
+ GError **error)
+{
+ GList *properties, *l;
+ GError *inner_error = NULL;
+ const gchar *subject;
+ gchar *graph_uri = NULL;
+
+ if (g_hash_table_lookup (visited, resource))
+ return TRUE;
+
+ g_hash_table_add (visited, resource);
+
+ properties = tracker_resource_get_properties (resource);
+
+ subject = tracker_resource_get_identifier (resource);
+ if (!subject || g_str_has_prefix (subject, "_:"))
+ subject = get_bnode_for_resource (bnodes, data, resource);
+
+ if (graph) {
+ tracker_data_manager_expand_prefix (data->manager,
+ graph, NULL, NULL,
+ &graph_uri);
+ }
+
+ /* Handle rdf:type first */
+ if (g_list_find_custom (properties, "rdf:type", (GCompareFunc) g_strcmp0)) {
+ update_resource_property (data, graph_uri, resource,
+ subject, "rdf:type",
+ visited, bnodes,
+ &inner_error);
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+ }
+
+ for (l = properties; l; l = l->next) {
+ if (g_str_equal (l->data, "rdf:type"))
+ continue;
+
+ if (!update_resource_property (data, graph_uri, resource,
+ subject, l->data,
+ visited, bnodes,
+ &inner_error))
+ break;
+ }
+
+ g_list_free (properties);
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+tracker_data_update_resource (TrackerData *data,
+ const gchar *graph,
+ TrackerResource *resource,
+ GHashTable *bnodes,
+ GError **error)
+{
+ GHashTable *visited;
+ gboolean retval;
+
+ visited = g_hash_table_new (NULL, NULL);
+
+ if (bnodes)
+ g_hash_table_ref (bnodes);
+ else
+ bnodes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ retval = update_resource_single (data, graph, resource, visited, bnodes, error);
+
+ g_hash_table_unref (visited);
+ g_hash_table_unref (bnodes);
+
+ return retval;
+}
diff --git a/src/libtracker-data/tracker-data-update.h b/src/libtracker-data/tracker-data-update.h
index 00588fa00..26fc3d971 100644
--- a/src/libtracker-data/tracker-data-update.h
+++ b/src/libtracker-data/tracker-data-update.h
@@ -137,6 +137,12 @@ void tracker_data_remove_rollback_statement_callback (TrackerData
TrackerCommitCallback callback,
gpointer user_data);
+gboolean tracker_data_update_resource (TrackerData *data,
+ const gchar *graph,
+ TrackerResource *resource,
+ GHashTable *bnodes,
+ GError **error);
+
GType tracker_data_get_type (void) G_GNUC_CONST;
TrackerData * tracker_data_new (TrackerDataManager *manager);
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index f2b81f695..45caa02df 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -310,58 +310,6 @@ tracker_sparql_expand_base (TrackerSparql *sparql,
return g_strdup (term);
}
-static inline gchar *
-tracker_sparql_expand_prefix (TrackerSparql *sparql,
- const gchar *term)
-{
- const gchar *sep;
- gchar *ns, *expanded_ns;
-
- sep = strchr (term, ':');
-
- if (sep) {
- ns = g_strndup (term, sep - term);
- sep++;
- } else {
- ns = g_strdup (term);
- }
-
- expanded_ns = g_hash_table_lookup (sparql->prefix_map, ns);
-
- if (!expanded_ns && g_strcmp0 (ns, "fn") == 0)
- expanded_ns = FN_NS;
-
- if (!expanded_ns) {
- TrackerOntologies *ontologies;
- TrackerNamespace **namespaces;
- guint n_namespaces, i;
-
- ontologies = tracker_data_manager_get_ontologies (sparql->data_manager);
- namespaces = tracker_ontologies_get_namespaces (ontologies, &n_namespaces);
-
- for (i = 0; i < n_namespaces; i++) {
- if (!g_str_equal (ns, tracker_namespace_get_prefix (namespaces[i])))
- continue;
-
- expanded_ns = g_strdup (tracker_namespace_get_uri (namespaces[i]));
- g_hash_table_insert (sparql->prefix_map, g_strdup (ns), expanded_ns);
- }
-
- if (!expanded_ns) {
- g_free (ns);
- return NULL;
- }
- }
-
- g_free (ns);
-
- if (sep) {
- return g_strdup_printf ("%s%s", expanded_ns, sep);
- } else {
- return g_strdup (expanded_ns);
- }
-}
-
static inline void
tracker_sparql_iter_next (TrackerSparql *sparql)
{
@@ -1117,7 +1065,10 @@ _extract_node_string (TrackerParserNode *node,
unexpanded = g_strndup (terminal_start + add_start,
terminal_end - terminal_start - subtract_end);
- str = tracker_sparql_expand_prefix (sparql, unexpanded);
+ tracker_data_manager_expand_prefix (sparql->data_manager,
+ unexpanded,
+ sparql->prefix_map,
+ NULL, &str);
g_free (unexpanded);
break;
}
@@ -9310,6 +9261,8 @@ tracker_sparql_init (TrackerSparql *sparql)
{
sparql->prefix_map = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
+ g_hash_table_insert (sparql->prefix_map, g_strdup ("fn"), g_strdup (FN_NS));
+
sparql->cached_bindings = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
sparql->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
@@ -9616,6 +9569,7 @@ tracker_sparql_new_update (TrackerDataManager *manager,
GVariant *
tracker_sparql_execute_update (TrackerSparql *sparql,
gboolean blank,
+ GHashTable *bnode_map,
GError **error)
{
TrackerSparqlState state = { 0 };
@@ -9631,6 +9585,8 @@ tracker_sparql_execute_update (TrackerSparql *sparql,
sparql->current_state = &state;
sparql->current_state->node = tracker_node_tree_get_root (sparql->tree);
+ sparql->current_state->blank_node_map =
+ bnode_map ? g_hash_table_ref (bnode_map) : NULL;
tracker_sparql_init_string_builder (sparql);
retval = _call_rule_func (sparql, NAMED_RULE_Update, error);
sparql->current_state = NULL;
diff --git a/src/libtracker-data/tracker-sparql.h b/src/libtracker-data/tracker-sparql.h
index 57651de1a..74297bd0a 100644
--- a/src/libtracker-data/tracker-sparql.h
+++ b/src/libtracker-data/tracker-sparql.h
@@ -40,9 +40,10 @@ TrackerSparqlCursor * tracker_sparql_execute_cursor (TrackerSparql *sparql,
GError **error);
TrackerSparql * tracker_sparql_new_update (TrackerDataManager *manager,
- const gchar *query);
+ const gchar *query);
GVariant * tracker_sparql_execute_update (TrackerSparql *sparql,
gboolean blank,
+ GHashTable *bnode_map,
GError **error);
GBytes * tracker_sparql_make_langstring (const gchar *str,
diff --git a/src/libtracker-sparql/direct/meson.build b/src/libtracker-sparql/direct/meson.build
index c1ec244e9..9f5ed7b95 100644
--- a/src/libtracker-sparql/direct/meson.build
+++ b/src/libtracker-sparql/direct/meson.build
@@ -1,5 +1,6 @@
libtracker_direct = static_library('tracker-direct',
'tracker-direct.c',
+ 'tracker-direct-batch.c',
'tracker-direct-statement.c',
c_args: tracker_c_args + [
'-include', 'libtracker-sparql/tracker-private.h',
diff --git a/src/libtracker-sparql/direct/tracker-direct-batch.c b/src/libtracker-sparql/direct/tracker-direct-batch.c
new file mode 100644
index 000000000..718a1cdc6
--- /dev/null
+++ b/src/libtracker-sparql/direct/tracker-direct-batch.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2020, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include "config.h"
+
+#include <libtracker-data/tracker-data-update.h>
+#include <libtracker-data/tracker-sparql.h>
+
+#include "tracker-direct-batch.h"
+#include "tracker-direct.h"
+#include "tracker-data.h"
+#include "tracker-private.h"
+
+typedef struct _TrackerDirectBatchPrivate TrackerDirectBatchPrivate;
+typedef struct _TrackerBatchElem TrackerBatchElem;
+
+struct _TrackerBatchElem
+{
+ guint type;
+
+ union {
+ gchar *sparql;
+
+ struct {
+ gchar *graph;
+ TrackerResource *resource;
+ } resource;
+ } d;
+};
+
+struct _TrackerDirectBatchPrivate
+{
+ GArray *array;
+};
+
+enum {
+ TRACKER_DIRECT_BATCH_RESOURCE,
+ TRACKER_DIRECT_BATCH_SPARQL,
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (TrackerDirectBatch,
+ tracker_direct_batch,
+ TRACKER_TYPE_BATCH)
+
+static void
+tracker_direct_batch_finalize (GObject *object)
+{
+ TrackerDirectBatchPrivate *priv;
+
+ priv = tracker_direct_batch_get_instance_private (TRACKER_DIRECT_BATCH (object));
+ g_array_unref (priv->array);
+
+ G_OBJECT_CLASS (tracker_direct_batch_parent_class)->finalize (object);
+}
+
+static void
+tracker_direct_batch_add_sparql (TrackerBatch *batch,
+ const gchar *sparql)
+{
+ TrackerDirectBatch *direct = TRACKER_DIRECT_BATCH (batch);
+ TrackerDirectBatchPrivate *priv = tracker_direct_batch_get_instance_private (direct);
+ TrackerBatchElem elem;
+
+ elem.type = TRACKER_DIRECT_BATCH_SPARQL;
+ elem.d.sparql = g_strdup (sparql);
+ g_array_append_val (priv->array, elem);
+}
+
+static void
+tracker_direct_batch_add_resource (TrackerBatch *batch,
+ const gchar *graph,
+ TrackerResource *resource)
+{
+ TrackerDirectBatch *direct = TRACKER_DIRECT_BATCH (batch);
+ TrackerDirectBatchPrivate *priv = tracker_direct_batch_get_instance_private (direct);
+ TrackerBatchElem elem;
+
+ elem.type = TRACKER_DIRECT_BATCH_RESOURCE;
+ elem.d.resource.graph = g_strdup (graph);
+ elem.d.resource.resource = g_object_ref (resource);
+ g_array_append_val (priv->array, elem);
+}
+
+static gboolean
+tracker_direct_batch_execute (TrackerBatch *batch,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerDirectConnection *conn;
+
+ conn = TRACKER_DIRECT_CONNECTION (tracker_batch_get_connection (batch));
+
+ return tracker_direct_connection_update_batch (conn, batch, error);
+}
+
+static void
+tracker_direct_batch_execute_async (TrackerBatch *batch,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TrackerDirectConnection *conn;
+
+ conn = TRACKER_DIRECT_CONNECTION (tracker_batch_get_connection (batch));
+
+ tracker_direct_connection_update_batch_async (conn, batch,
+ cancellable,
+ callback,
+ user_data);
+}
+
+static gboolean
+tracker_direct_batch_execute_finish (TrackerBatch *batch,
+ GAsyncResult *res,
+ GError **error)
+{
+ TrackerDirectConnection *conn;
+
+ conn = TRACKER_DIRECT_CONNECTION (tracker_batch_get_connection (batch));
+
+ return tracker_direct_connection_update_batch_finish (conn, res, error);
+}
+
+static void
+tracker_direct_batch_class_init (TrackerDirectBatchClass *klass)
+{
+ TrackerBatchClass *batch_class = (TrackerBatchClass *) klass;
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ object_class->finalize = tracker_direct_batch_finalize;
+
+ batch_class->add_sparql = tracker_direct_batch_add_sparql;
+ batch_class->add_resource = tracker_direct_batch_add_resource;
+ batch_class->execute = tracker_direct_batch_execute;
+ batch_class->execute_async = tracker_direct_batch_execute_async;
+ batch_class->execute_finish = tracker_direct_batch_execute_finish;
+}
+
+static void
+tracker_batch_elem_clear (TrackerBatchElem *elem)
+{
+ if (elem->type == TRACKER_DIRECT_BATCH_RESOURCE) {
+ g_object_run_dispose (G_OBJECT (elem->d.resource.resource));
+ g_object_unref (elem->d.resource.resource);
+ g_free (elem->d.resource.graph);
+ } else if (elem->type == TRACKER_DIRECT_BATCH_SPARQL) {
+ g_free (elem->d.sparql);
+ }
+}
+
+static void
+tracker_direct_batch_init (TrackerDirectBatch *batch)
+{
+ TrackerDirectBatchPrivate *priv;
+
+ priv = tracker_direct_batch_get_instance_private (batch);
+ priv->array = g_array_new (FALSE, FALSE, sizeof (TrackerBatchElem));
+ g_array_set_clear_func (priv->array, (GDestroyNotify) tracker_batch_elem_clear);
+}
+
+TrackerBatch *
+tracker_direct_batch_new (TrackerSparqlConnection *conn)
+{
+ return g_object_new (TRACKER_TYPE_DIRECT_BATCH,
+ "connection", conn,
+ NULL);
+}
+
+/* Executes with the update lock held */
+gboolean
+tracker_direct_batch_update (TrackerDirectBatch *batch,
+ TrackerDataManager *data_manager,
+ GError **error)
+{
+ TrackerDirectBatchPrivate *priv;
+ GError *inner_error = NULL;
+ GHashTable *bnodes;
+ TrackerData *data;
+ guint i;
+
+ priv = tracker_direct_batch_get_instance_private (batch);
+ data = tracker_data_manager_get_data (data_manager);
+ bnodes = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+ tracker_data_begin_transaction (data, &inner_error);
+ if (inner_error)
+ goto error;
+
+ for (i = 0; i < priv->array->len; i++) {
+ TrackerBatchElem *elem;
+
+ elem = &g_array_index (priv->array, TrackerBatchElem, i);
+
+ if (elem->type == TRACKER_DIRECT_BATCH_RESOURCE) {
+ tracker_data_update_resource (data,
+ elem->d.resource.graph,
+ elem->d.resource.resource,
+ bnodes,
+ &inner_error);
+ } else if (elem->type == TRACKER_DIRECT_BATCH_SPARQL) {
+ TrackerSparql *query;
+
+ query = tracker_sparql_new_update (data_manager,
+ elem->d.sparql);
+ tracker_sparql_execute_update (query, FALSE,
+ bnodes,
+ &inner_error);
+ g_object_unref (query);
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (inner_error)
+ break;
+ }
+
+ if (!inner_error)
+ tracker_data_update_buffer_flush (data, &inner_error);
+
+ if (inner_error) {
+ tracker_data_rollback_transaction (data);
+ goto error;
+ }
+
+ tracker_data_commit_transaction (data, &inner_error);
+ if (inner_error)
+ goto error;
+
+ g_hash_table_unref (bnodes);
+
+ return TRUE;
+
+error:
+ g_hash_table_unref (bnodes);
+ g_propagate_error (error, inner_error);
+ return FALSE;
+}
diff --git a/src/libtracker-sparql/direct/tracker-direct-batch.h b/src/libtracker-sparql/direct/tracker-direct-batch.h
new file mode 100644
index 000000000..685b94fb7
--- /dev/null
+++ b/src/libtracker-sparql/direct/tracker-direct-batch.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __TRACKER_DIRECT_BATCH_H__
+#define __TRACKER_DIRECT_BATCH_H__
+
+#include "tracker-direct.h"
+#include <libtracker-sparql/tracker-sparql.h>
+#include <libtracker-sparql/tracker-private.h>
+
+#define TRACKER_TYPE_DIRECT_BATCH (tracker_direct_batch_get_type ())
+
+G_DECLARE_FINAL_TYPE (TrackerDirectBatch,
+ tracker_direct_batch,
+ TRACKER, DIRECT_BATCH,
+ TrackerBatch)
+
+struct _TrackerDirectBatch
+{
+ TrackerBatch parent_instance;
+};
+
+TrackerBatch * tracker_direct_batch_new (TrackerSparqlConnection *conn);
+
+gboolean tracker_direct_batch_update (TrackerDirectBatch *batch,
+ TrackerDataManager *data_manager,
+ GError **error);
+
+#endif /* __TRACKER_DIRECT_BATCH_H__ */
diff --git a/src/libtracker-sparql/direct/tracker-direct.c b/src/libtracker-sparql/direct/tracker-direct.c
index 3d867283c..4908c75b5 100644
--- a/src/libtracker-sparql/direct/tracker-direct.c
+++ b/src/libtracker-sparql/direct/tracker-direct.c
@@ -21,6 +21,7 @@
#include "config.h"
#include "tracker-direct.h"
+#include "tracker-direct-batch.h"
#include "tracker-direct-statement.h"
#include "libtracker-sparql/tracker-private.h"
#include <libtracker-data/tracker-data.h>
@@ -54,6 +55,11 @@ struct _TrackerDirectConnectionPrivate
guint closing : 1;
};
+typedef struct {
+ gchar *graph;
+ TrackerResource *resource;
+} UpdateResource;
+
enum {
PROP_0,
PROP_FLAGS,
@@ -68,12 +74,15 @@ typedef enum {
TASK_TYPE_QUERY,
TASK_TYPE_UPDATE,
TASK_TYPE_UPDATE_BLANK,
+ TASK_TYPE_UPDATE_RESOURCE,
+ TASK_TYPE_UPDATE_BATCH,
TASK_TYPE_RELEASE_MEMORY,
} TaskType;
typedef struct {
TaskType type;
- gchar *query;
+ gpointer data;
+ GDestroyNotify destroy;
} TaskData;
static void tracker_direct_connection_initable_iface_init (GInitableIface *iface);
@@ -90,22 +99,25 @@ G_DEFINE_TYPE_WITH_CODE (TrackerDirectConnection, tracker_direct_connection,
tracker_direct_connection_async_initable_iface_init))
static TaskData *
-task_data_query_new (TaskType type,
- const gchar *sparql)
+task_data_query_new (TaskType type,
+ gpointer data,
+ GDestroyNotify destroy)
{
- TaskData *data;
+ TaskData *task;
- data = g_new0 (TaskData, 1);
- data->type = type;
- data->query = g_strdup (sparql);
+ task = g_new0 (TaskData, 1);
+ task->type = type;
+ task->data = data;
+ task->destroy = destroy;
- return data;
+ return task;
}
static void
task_data_free (TaskData *task)
{
- g_free (task->query);
+ if (task->destroy && task->data)
+ task->destroy (task->data);
g_free (task);
}
@@ -131,7 +143,7 @@ cleanup_timeout_cb (gpointer user_data)
task = g_task_new (conn, NULL, NULL, NULL);
g_task_set_task_data (task,
- task_data_query_new (TASK_TYPE_RELEASE_MEMORY, NULL),
+ task_data_query_new (TASK_TYPE_RELEASE_MEMORY, NULL, NULL),
(GDestroyNotify) task_data_free);
g_thread_pool_push (priv->update_thread, task, NULL);
@@ -139,6 +151,39 @@ cleanup_timeout_cb (gpointer user_data)
return G_SOURCE_CONTINUE;
}
+gboolean
+update_resource (TrackerData *data,
+ const gchar *graph,
+ TrackerResource *resource,
+ GError **error)
+{
+ GError *inner_error = NULL;
+
+ tracker_data_begin_transaction (data, &inner_error);
+ if (inner_error)
+ goto error;
+
+ tracker_data_update_resource (data,
+ graph,
+ resource,
+ NULL,
+ &inner_error);
+
+ if (inner_error) {
+ tracker_data_rollback_transaction (data);
+ goto error;
+ }
+
+ tracker_data_commit_transaction (data, &inner_error);
+ if (inner_error)
+ goto error;
+
+ return TRUE;
+
+error:
+ g_propagate_error (error, inner_error);
+ return FALSE;
+}
static void
update_thread_func (gpointer data,
@@ -165,12 +210,20 @@ update_thread_func (gpointer data,
g_warning ("Queries don't go through this thread");
break;
case TASK_TYPE_UPDATE:
- tracker_data_update_sparql (tracker_data, task_data->query, &error);
+ tracker_data_update_sparql (tracker_data, task_data->data, &error);
break;
case TASK_TYPE_UPDATE_BLANK:
- retval = tracker_data_update_sparql_blank (tracker_data, task_data->query, &error);
+ retval = tracker_data_update_sparql_blank (tracker_data, task_data->data, &error);
destroy_notify = (GDestroyNotify) g_variant_unref;
break;
+ case TASK_TYPE_UPDATE_RESOURCE: {
+ UpdateResource *data = task_data->data;
+ update_resource (tracker_data, data->graph, data->resource, &error);
+ break;
+ }
+ case TASK_TYPE_UPDATE_BATCH:
+ tracker_direct_batch_update (task_data->data, priv->data_manager, &error);
+ break;
case TASK_TYPE_RELEASE_MEMORY:
tracker_data_manager_release_memory (priv->data_manager);
update_timestamp = FALSE;
@@ -217,7 +270,7 @@ query_thread_pool_func (gpointer data,
}
cursor = tracker_sparql_connection_query (TRACKER_SPARQL_CONNECTION (g_task_get_source_object (task)),
- task_data->query,
+ task_data->data,
g_task_get_cancellable (task),
&error);
if (cursor)
@@ -705,7 +758,9 @@ tracker_direct_connection_query_async (TrackerSparqlConnection *self,
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_task_data (task,
- task_data_query_new (TASK_TYPE_QUERY, sparql),
+ task_data_query_new (TASK_TYPE_QUERY,
+ g_strdup (sparql),
+ g_free),
(GDestroyNotify) task_data_free);
if (!g_thread_pool_push (priv->select_pool, task, &error)) {
@@ -771,7 +826,9 @@ tracker_direct_connection_update_async (TrackerSparqlConnection *self,
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_task_data (task,
- task_data_query_new (TASK_TYPE_UPDATE, sparql),
+ task_data_query_new (TASK_TYPE_UPDATE,
+ g_strdup (sparql),
+ g_free),
(GDestroyNotify) task_data_free);
g_thread_pool_push (priv->update_thread, task, NULL);
@@ -813,8 +870,7 @@ tracker_direct_connection_update_array_async (TrackerSparqlConnection *self,
concatenated = g_strjoinv ("\n", array_copy);
g_free (array_copy);
- task_data = task_data_query_new (TASK_TYPE_UPDATE, NULL);
- task_data->query = concatenated;
+ task_data = task_data_query_new (TASK_TYPE_UPDATE, concatenated, g_free);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_task_data (task, task_data,
@@ -880,7 +936,9 @@ tracker_direct_connection_update_blank_async (TrackerSparqlConnection *self,
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_task_data (task,
- task_data_query_new (TASK_TYPE_UPDATE_BLANK, sparql),
+ task_data_query_new (TASK_TYPE_UPDATE_BLANK,
+ g_strdup (sparql),
+ g_free),
(GDestroyNotify) task_data_free);
g_thread_pool_push (priv->update_thread, task, NULL);
@@ -984,7 +1042,7 @@ tracker_direct_connection_close (TrackerSparqlConnection *self)
}
}
-void
+static void
async_close_thread_func (GTask *task,
gpointer source_object,
gpointer task_data,
@@ -997,7 +1055,7 @@ async_close_thread_func (GTask *task,
g_task_return_boolean (task, TRUE);
}
-void
+static void
tracker_direct_connection_close_async (TrackerSparqlConnection *connection,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -1010,7 +1068,7 @@ tracker_direct_connection_close_async (TrackerSparqlConnection *connection,
g_object_unref (task);
}
-gboolean
+static gboolean
tracker_direct_connection_close_finish (TrackerSparqlConnection *connection,
GAsyncResult *res,
GError **error)
@@ -1018,6 +1076,106 @@ tracker_direct_connection_close_finish (TrackerSparqlConnection *connection,
return g_task_propagate_boolean (G_TASK (res), error);
}
+static UpdateResource *
+update_resource_data_new (const gchar *graph,
+ TrackerResource *resource)
+{
+ UpdateResource *data;
+
+ data = g_new0 (UpdateResource, 1);
+ data->graph = g_strdup (graph);
+ data->resource = g_object_ref (resource);
+
+ return data;
+}
+
+static void
+update_resource_data_free (UpdateResource *data)
+{
+ g_free (data->graph);
+ g_object_unref (data->resource);
+ g_free (data);
+}
+
+static gboolean
+tracker_direct_connection_update_resource (TrackerSparqlConnection *self,
+ const gchar *graph,
+ TrackerResource *resource,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerDirectConnectionPrivate *priv;
+ TrackerDirectConnection *conn;
+ TrackerData *data;
+ GError *inner_error = NULL;
+
+ conn = TRACKER_DIRECT_CONNECTION (self);
+ priv = tracker_direct_connection_get_instance_private (conn);
+
+ g_mutex_lock (&priv->mutex);
+ data = tracker_data_manager_get_data (priv->data_manager);
+ update_resource (data, graph, resource, &inner_error);
+ tracker_direct_connection_update_timestamp (conn);
+ g_mutex_unlock (&priv->mutex);
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+tracker_direct_connection_update_resource_async (TrackerSparqlConnection *self,
+ const gchar *graph,
+ TrackerResource *resource,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TrackerDirectConnectionPrivate *priv;
+ TrackerDirectConnection *conn;
+ TaskData *task_data;
+ GTask *task;
+
+ conn = TRACKER_DIRECT_CONNECTION (self);
+ priv = tracker_direct_connection_get_instance_private (conn);
+
+ task_data = task_data_query_new (TASK_TYPE_UPDATE_RESOURCE,
+ update_resource_data_new (graph, resource),
+ (GDestroyNotify) update_resource_data_free);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_task_data (task, task_data,
+ (GDestroyNotify) task_data_free);
+
+ g_thread_pool_push (priv->update_thread, task, NULL);
+}
+
+static gboolean
+tracker_direct_connection_update_resource_finish (TrackerSparqlConnection *connection,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static TrackerBatch *
+tracker_direct_connection_create_batch (TrackerSparqlConnection *connection)
+{
+ TrackerDirectConnectionPrivate *priv;
+ TrackerDirectConnection *conn;
+
+ conn = TRACKER_DIRECT_CONNECTION (connection);
+ priv = tracker_direct_connection_get_instance_private (conn);
+
+ if (priv->flags & TRACKER_SPARQL_CONNECTION_FLAGS_READONLY)
+ return NULL;
+
+ return tracker_direct_batch_new (connection);
+}
+
static void
tracker_direct_connection_class_init (TrackerDirectConnectionClass *klass)
{
@@ -1048,6 +1206,10 @@ tracker_direct_connection_class_init (TrackerDirectConnectionClass *klass)
sparql_connection_class->close = tracker_direct_connection_close;
sparql_connection_class->close_async = tracker_direct_connection_close_async;
sparql_connection_class->close_finish = tracker_direct_connection_close_finish;
+ sparql_connection_class->update_resource = tracker_direct_connection_update_resource;
+ sparql_connection_class->update_resource_async = tracker_direct_connection_update_resource_async;
+ sparql_connection_class->update_resource_finish = tracker_direct_connection_update_resource_finish;
+ sparql_connection_class->create_batch = tracker_direct_connection_create_batch;
props[PROP_FLAGS] =
g_param_spec_flags ("flags",
@@ -1109,3 +1271,65 @@ tracker_direct_connection_update_timestamp (TrackerDirectConnection *conn)
priv = tracker_direct_connection_get_instance_private (conn);
priv->timestamp = g_get_monotonic_time ();
}
+
+gboolean
+tracker_direct_connection_update_batch (TrackerDirectConnection *conn,
+ TrackerBatch *batch,
+ GError **error)
+{
+ TrackerDirectConnectionPrivate *priv;
+ GError *inner_error = NULL;
+
+ priv = tracker_direct_connection_get_instance_private (conn);
+
+ g_mutex_lock (&priv->mutex);
+ tracker_direct_batch_update (TRACKER_DIRECT_BATCH (batch),
+ priv->data_manager, &inner_error);
+ tracker_direct_connection_update_timestamp (conn);
+ g_mutex_unlock (&priv->mutex);
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+tracker_direct_connection_update_batch_async (TrackerDirectConnection *conn,
+ TrackerBatch *batch,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TrackerDirectConnectionPrivate *priv;
+ GTask *task;
+
+ priv = tracker_direct_connection_get_instance_private (conn);
+
+ task = g_task_new (batch, cancellable, callback, user_data);
+ g_task_set_task_data (task,
+ task_data_query_new (TASK_TYPE_UPDATE_BATCH,
+ g_object_ref (batch),
+ g_object_unref),
+ (GDestroyNotify) task_data_free);
+
+ g_thread_pool_push (priv->update_thread, task, NULL);
+}
+
+gboolean
+tracker_direct_connection_update_batch_finish (TrackerDirectConnection *conn,
+ GAsyncResult *res,
+ GError **error)
+{
+ GError *inner_error = NULL;
+
+ g_task_propagate_boolean (G_TASK (res), &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, _translate_internal_error (inner_error));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/src/libtracker-sparql/direct/tracker-direct.h b/src/libtracker-sparql/direct/tracker-direct.h
index c353b51ca..d914f0fa1 100644
--- a/src/libtracker-sparql/direct/tracker-direct.h
+++ b/src/libtracker-sparql/direct/tracker-direct.h
@@ -24,6 +24,8 @@
#include <libtracker-sparql/tracker-sparql.h>
#include <libtracker-data/tracker-data-manager.h>
+#include "tracker-direct-batch.h"
+
#define TRACKER_TYPE_DIRECT_CONNECTION (tracker_direct_connection_get_type())
#define TRACKER_DIRECT_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_DIRECT_CONNECTION, TrackerDirectConnection))
#define TRACKER_DIRECT_CONNECTION_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_DIRECT_CONNECTION, TrackerDirectConnectionClass))
@@ -55,7 +57,19 @@ TrackerDataManager *tracker_direct_connection_get_data_manager (TrackerDirectCon
void tracker_direct_connection_update_timestamp (TrackerDirectConnection *conn);
-/* Internal helper function */
+/* Internal helper functions */
GError *translate_db_interface_error (GError *error);
+gboolean tracker_direct_connection_update_batch (TrackerDirectConnection *conn,
+ TrackerBatch *batch,
+ GError **error);
+void tracker_direct_connection_update_batch_async (TrackerDirectConnection *conn,
+ TrackerBatch *batch,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean tracker_direct_connection_update_batch_finish (TrackerDirectConnection *conn,
+ GAsyncResult *res,
+ GError **error);
+
#endif /* __TRACKER_LOCAL_CONNECTION_H__ */
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
index 465185753..2bb6ca8a6 100644
--- a/src/libtracker-sparql/meson.build
+++ b/src/libtracker-sparql/meson.build
@@ -1,3 +1,8 @@
+version_header = configure_file(
+ input: 'tracker-version-generated.h.meson.in',
+ output: 'tracker-version-generated.h',
+ configuration: conf)
+
enum_types = gnome.mkenums('tracker-sparql-enum-types',
sources: ['tracker-notifier.h', 'tracker-connection.h'],
c_template: 'tracker-sparql-enum-types.c.template',
@@ -10,6 +15,7 @@ tracker_sparql_vapi = files('tracker-sparql.vapi')
tracker_sparql_vapi_dep = meson.get_compiler('vala').find_library('tracker-sparql', dirs: meson.current_source_dir())
libtracker_sparql_c_sources = files(
+ 'tracker-batch.c',
'tracker-connection.c',
'tracker-cursor.c',
'tracker-endpoint.c',
@@ -25,6 +31,7 @@ libtracker_sparql_c_sources = files(
)
libtracker_sparql_c_public_headers = files(
+ 'tracker-batch.h',
'tracker-connection.h',
'tracker-cursor.h',
'tracker-endpoint.h',
@@ -59,6 +66,7 @@ install_headers(
libtracker_sparql_c_public_headers,
'tracker-ontologies.h',
'tracker-sparql.h',
+ version_header,
subdir: 'tracker-@0@/libtracker-sparql'.format(tracker_api_version))
install_data(
diff --git a/src/libtracker-sparql/tracker-batch.c b/src/libtracker-sparql/tracker-batch.c
new file mode 100644
index 000000000..883d822a7
--- /dev/null
+++ b/src/libtracker-sparql/tracker-batch.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2020, Red Hat Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+/**
+ * SECTION: tracker-batch
+ * @short_description: Update batches
+ * @title: TrackerBatch
+ * @stability: Stable
+ * @include: tracker-sparql.h
+ *
+ * #TrackerBatch is an object containing a series of SPARQL updates,
+ * in either SPARQL string or #TrackerResource form. This object has
+ * a single use, after the batch is executed, it can only be finished
+ * and freed.
+ *
+ * A batch is created with tracker_sparql_connection_create_batch().
+ * To add resources use tracker_batch_add_resource() or
+ * tracker_batch_add_sparql().
+ *
+ * When a batch is ready for execution, use tracker_batch_execute()
+ * or tracker_batch_execute_async(). The batch is executed as a single
+ * transaction, it will succeed or fail entirely.
+ *
+ * The mapping of blank node labels is global in a #TrackerBatch,
+ * referencing the same blank node label in different operations in
+ * a batch will resolve to the same resource.
+ *
+ * This object was added in Tracker 3.1.
+ */
+#include "config.h"
+
+#include "tracker-batch.h"
+#include "tracker-connection.h"
+#include "tracker-private.h"
+
+enum {
+ PROP_0,
+ PROP_CONNECTION,
+ N_PROPS
+};
+
+static GParamSpec *props[N_PROPS];
+
+typedef struct {
+ TrackerSparqlConnection *connection;
+ gchar *sparql;
+ guint already_executed : 1;
+} TrackerBatchPrivate;
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (TrackerBatch,
+ tracker_batch,
+ G_TYPE_OBJECT)
+
+static void
+tracker_batch_init (TrackerBatch *batch)
+{
+}
+
+static void
+tracker_batch_finalize (GObject *object)
+{
+ TrackerBatch *batch = TRACKER_BATCH (object);
+ TrackerBatchPrivate *priv = tracker_batch_get_instance_private (batch);
+
+ g_clear_object (&priv->connection);
+ G_OBJECT_CLASS (tracker_batch_parent_class)->finalize (object);
+}
+
+static void
+tracker_batch_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TrackerBatch *batch = TRACKER_BATCH (object);
+ TrackerBatchPrivate *priv = tracker_batch_get_instance_private (batch);
+
+ switch (prop_id) {
+ case PROP_CONNECTION:
+ priv->connection = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+tracker_batch_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TrackerBatch *batch = TRACKER_BATCH (object);
+ TrackerBatchPrivate *priv = tracker_batch_get_instance_private (batch);
+
+ switch (prop_id) {
+ case PROP_CONNECTION:
+ g_value_set_object (value, priv->connection);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+tracker_batch_class_init (TrackerBatchClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = tracker_batch_finalize;
+ object_class->set_property = tracker_batch_set_property;
+ object_class->get_property = tracker_batch_get_property;
+
+ /**
+ * TrackerBatch:connection:
+ *
+ * The #TrackerSparqlConnection the batch belongs to.
+ */
+ props[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "connection",
+ "connection",
+ TRACKER_TYPE_SPARQL_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE);
+
+ g_object_class_install_properties (object_class, N_PROPS, props);
+}
+
+/**
+ * tracker_batch_get_connection:
+ * @batch: a #TrackerBatch
+ *
+ * Returns the #TrackerSparqlConnection that this batch was created from.
+ *
+ * Returns: (transfer none): The SPARQL connection of this batch.
+ **/
+TrackerSparqlConnection *
+tracker_batch_get_connection (TrackerBatch *batch)
+{
+ TrackerBatchPrivate *priv = tracker_batch_get_instance_private (batch);
+
+ g_return_val_if_fail (TRACKER_IS_BATCH (batch), NULL);
+
+ return priv->connection;
+}
+
+/**
+ * tracker_batch_add_sparql:
+ * @batch: a #TrackerBatch
+ * @sparql: a SPARQL update string
+ *
+ * Adds an SPARQL update string to @batch.
+ *
+ * Since: 3.1
+ **/
+void
+tracker_batch_add_sparql (TrackerBatch *batch,
+ const gchar *sparql)
+{
+ TrackerBatchPrivate *priv = tracker_batch_get_instance_private (batch);
+
+ g_return_if_fail (TRACKER_IS_BATCH (batch));
+ g_return_if_fail (sparql != NULL);
+ g_return_if_fail (!priv->already_executed);
+
+ TRACKER_BATCH_GET_CLASS (batch)->add_sparql (batch, sparql);
+}
+
+/**
+ * tracker_batch_add_resource:
+ * @batch: a #TrackerBatch
+ * @graph: RDF graph to insert the resource to
+ * @resource: a #TrackerResource
+ *
+ * Adds the RDF represented by @resource to @batch.
+ *
+ * Since: 3.1
+ **/
+void
+tracker_batch_add_resource (TrackerBatch *batch,
+ const gchar *graph,
+ TrackerResource *resource)
+{
+ TrackerBatchPrivate *priv = tracker_batch_get_instance_private (batch);
+
+ g_return_if_fail (TRACKER_IS_BATCH (batch));
+ g_return_if_fail (TRACKER_IS_RESOURCE (resource));
+ g_return_if_fail (!priv->already_executed);
+
+ TRACKER_BATCH_GET_CLASS (batch)->add_resource (batch, graph, resource);
+}
+
+/**
+ * tracker_batch_execute:
+ * @batch: a #TrackerBatch
+ * @cancellable: (nullable): a #GCancellable, or %NULL
+ * @error: location for a #GError, or %NULL
+ *
+ * Executes the batch. This operations happens synchronously.
+ *
+ * Returns: %TRUE of there were no errors, %FALSE otherwise
+ *
+ * Since: 3.1
+ **/
+gboolean
+tracker_batch_execute (TrackerBatch *batch,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerBatchPrivate *priv = tracker_batch_get_instance_private (batch);
+
+ g_return_val_if_fail (TRACKER_IS_BATCH (batch), FALSE);
+ g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (!priv->already_executed, FALSE);
+
+ priv->already_executed = TRUE;
+
+ return TRACKER_BATCH_GET_CLASS (batch)->execute (batch, cancellable, error);
+}
+
+/**
+ * tracker_batch_execute_async:
+ * @batch: a #TrackerBatch
+ * @cancellable: (nullable): a #GCancellable, or %NULL
+ * @callback: user-defined #GAsyncReadyCallback to be called when
+ * asynchronous operation is finished.
+ * @user_data: user-defined data to be passed to @callback
+ *
+ * Executes the batch. This operation happens asynchronously, when
+ * finished @callback will be executed.
+ *
+ * Since: 3.1
+ **/
+void
+tracker_batch_execute_async (TrackerBatch *batch,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TrackerBatchPrivate *priv = tracker_batch_get_instance_private (batch);
+
+ g_return_if_fail (TRACKER_IS_BATCH (batch));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (!priv->already_executed);
+
+ priv->already_executed = TRUE;
+ TRACKER_BATCH_GET_CLASS (batch)->execute_async (batch, cancellable, callback, user_data);
+}
+
+/**
+ * tracker_batch_execute_finish:
+ * @batch: a #TrackerBatch
+ * @res: a #GAsyncResult with the result of the operation
+ * @error: location for a #GError, or %NULL
+ *
+ * Finishes the operation started with tracker_batch_execute_async().
+ *
+ * Returns: %TRUE of there were no errors, %FALSE otherwise
+ *
+ * Since: 3.1
+ **/
+gboolean
+tracker_batch_execute_finish (TrackerBatch *batch,
+ GAsyncResult *res,
+ GError **error)
+{
+ g_return_val_if_fail (TRACKER_IS_BATCH (batch), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+
+ return TRACKER_BATCH_GET_CLASS (batch)->execute_finish (batch, res, error);
+}
diff --git a/src/libtracker-sparql/tracker-batch.h b/src/libtracker-sparql/tracker-batch.h
new file mode 100644
index 000000000..16e6a1099
--- /dev/null
+++ b/src/libtracker-sparql/tracker-batch.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 Red Hat Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho
+ */
+#ifndef __TRACKER_BATCH_H__
+#define __TRACKER_BATCH_H__
+
+#if !defined (__LIBTRACKER_SPARQL_INSIDE__) && !defined (TRACKER_COMPILATION)
+#error "only <libtracker-sparql/tracker-sparql.h> must be included directly."
+#endif
+
+#include <libtracker-sparql/tracker-version.h>
+#include <libtracker-sparql/tracker-resource.h>
+#include <gio/gio.h>
+
+#define TRACKER_TYPE_BATCH tracker_batch_get_type ()
+
+TRACKER_AVAILABLE_IN_ALL
+G_DECLARE_DERIVABLE_TYPE (TrackerBatch,
+ tracker_batch,
+ TRACKER, BATCH,
+ GObject)
+
+#include "tracker-connection.h"
+
+TRACKER_AVAILABLE_IN_3_1
+TrackerSparqlConnection * tracker_batch_get_connection (TrackerBatch *batch);
+
+TRACKER_AVAILABLE_IN_3_1
+void tracker_batch_add_sparql (TrackerBatch *batch,
+ const gchar *sparql);
+
+TRACKER_AVAILABLE_IN_3_1
+void tracker_batch_add_resource (TrackerBatch *batch,
+ const gchar *graph,
+ TrackerResource *resource);
+
+TRACKER_AVAILABLE_IN_3_1
+gboolean tracker_batch_execute (TrackerBatch *batch,
+ GCancellable *cancellable,
+ GError **error);
+
+TRACKER_AVAILABLE_IN_3_1
+void tracker_batch_execute_async (TrackerBatch *batch,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+TRACKER_AVAILABLE_IN_3_1
+gboolean tracker_batch_execute_finish (TrackerBatch *batch,
+ GAsyncResult *res,
+ GError **error);
+
+#endif /* __TRACKER_BATCH_H__ */
diff --git a/src/libtracker-sparql/tracker-connection.c b/src/libtracker-sparql/tracker-connection.c
index 8df18b895..5dcc3d226 100644
--- a/src/libtracker-sparql/tracker-connection.c
+++ b/src/libtracker-sparql/tracker-connection.c
@@ -182,8 +182,6 @@ tracker_sparql_connection_class_init (TrackerSparqlConnectionClass *klass)
*
* Returns: (transfer full): a new remote #TrackerSparqlConnection. Call
* g_object_unref() on the object when no longer used.
- *
- * Since: 1.12
*/
/**
@@ -538,6 +536,102 @@ tracker_sparql_connection_update_blank_finish (TrackerSparqlConnection *connect
}
/**
+ * tracker_sparql_connection_update_resource:
+ * @connection: a #TrackerSparqlConnection
+ * @graph: (nullable): RDF graph where the resource should be inserted/updated, or %NULL for the default graph
+ * @resource: a #TrackerResource
+ * @cancellable: (nullable): a #GCancellable, or %NULL
+ * @error: pointer to a #GError, or %NULL
+ *
+ * Inserts a resource as described by @resource, on the graph described by @graph.
+ * This operation blocks until done.
+ *
+ * Returns: #TRUE if there were no errors.
+ *
+ * Since: 3.1
+ **/
+gboolean
+tracker_sparql_connection_update_resource (TrackerSparqlConnection *connection,
+ const gchar *graph,
+ TrackerResource *resource,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (TRACKER_IS_SPARQL_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (TRACKER_IS_RESOURCE (resource), FALSE);
+ g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+
+ return TRACKER_SPARQL_CONNECTION_GET_CLASS (connection)->update_resource (connection,
+ graph,
+ resource,
+ cancellable,
+ error);
+}
+
+/**
+ * tracker_sparql_connection_update_resource_async:
+ * @connection: a #TrackerSparqlConnection
+ * @graph: (nullable): RDF graph where the resource should be inserted/updated, or %NULL for the default graph
+ * @resource: a #TrackerResource
+ * @cancellable: (nullable): a #GCancellable, or %NULL
+ * @callback: the #GAsyncReadyCallback called when the operation completes
+ * @user_data: data passed to @callback
+ *
+ * Inserts a resource as described by @resource, on the graph described by @graph.
+ * This operation is executed asynchronously, when finished @callback will be
+ * executed.
+ *
+ * Since: 3.1
+ **/
+void
+tracker_sparql_connection_update_resource_async (TrackerSparqlConnection *connection,
+ const gchar *graph,
+ TrackerResource *resource,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (TRACKER_IS_SPARQL_CONNECTION (connection));
+ g_return_if_fail (TRACKER_IS_RESOURCE (resource));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (callback != NULL);
+
+ TRACKER_SPARQL_CONNECTION_GET_CLASS (connection)->update_resource_async (connection,
+ graph,
+ resource,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * tracker_sparql_connection_update_resource_finish:
+ * @connection: a #TrackerSparqlConnection
+ * @res: a #GAsyncResult with the result of the operation
+ * @error: pointer to a #GError, or %NULL
+ *
+ * Finishes a tracker_sparql_connection_update_resource_async() operation.
+ *
+ * Returns: #TRUE if there were no errors.
+ *
+ * Since: 3.1
+ **/
+gboolean
+tracker_sparql_connection_update_resource_finish (TrackerSparqlConnection *connection,
+ GAsyncResult *res,
+ GError **error)
+{
+ g_return_val_if_fail (TRACKER_IS_SPARQL_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+
+ return TRACKER_SPARQL_CONNECTION_GET_CLASS (connection)->update_resource_finish (connection,
+ res,
+ error);
+}
+
+/**
* tracker_sparql_connection_get_namespace_manager:
* @connection: a #TrackerSparqlConnection
*
@@ -673,3 +767,23 @@ tracker_sparql_connection_close_finish (TrackerSparqlConnection *connection,
return TRACKER_SPARQL_CONNECTION_GET_CLASS (connection)->close_finish (connection,
res, error);
}
+
+/**
+ * tracker_sparql_connection_create_batch:
+ * @connection: a #TrackerSparqlConnection
+ *
+ * Creates a new batch to store and execute update commands. If the connection
+ * is readonly or cannot issue SPARQL updates, %NULL will be returned.
+ *
+ * Returns: (transfer full): (nullable): A new #TrackerBatch
+ **/
+TrackerBatch *
+tracker_sparql_connection_create_batch (TrackerSparqlConnection *connection)
+{
+ g_return_val_if_fail (TRACKER_IS_SPARQL_CONNECTION (connection), NULL);
+
+ if (!TRACKER_SPARQL_CONNECTION_GET_CLASS (connection)->create_batch)
+ return NULL;
+
+ return TRACKER_SPARQL_CONNECTION_GET_CLASS (connection)->create_batch (connection);
+}
diff --git a/src/libtracker-sparql/tracker-connection.h b/src/libtracker-sparql/tracker-connection.h
index ee92fde22..834f65fb6 100644
--- a/src/libtracker-sparql/tracker-connection.h
+++ b/src/libtracker-sparql/tracker-connection.h
@@ -25,6 +25,7 @@
#include <libtracker-sparql/tracker-error.h>
#include <libtracker-sparql/tracker-notifier.h>
+#include <libtracker-sparql/tracker-resource.h>
#include <libtracker-sparql/tracker-version.h>
#include <gio/gio.h>
@@ -63,6 +64,7 @@ G_DECLARE_DERIVABLE_TYPE (TrackerSparqlConnection,
TRACKER, SPARQL_CONNECTION,
GObject)
+#include "tracker-batch.h"
#include "tracker-cursor.h"
#include "tracker-statement.h"
#include "tracker-namespace-manager.h"
@@ -136,6 +138,26 @@ TRACKER_AVAILABLE_IN_ALL
gboolean tracker_sparql_connection_update_array_finish (TrackerSparqlConnection *connection,
GAsyncResult *res,
GError **error);
+TRACKER_AVAILABLE_IN_3_1
+gboolean tracker_sparql_connection_update_resource (TrackerSparqlConnection *connection,
+ const gchar *graph,
+ TrackerResource *resource,
+ GCancellable *cancellable,
+ GError **error);
+TRACKER_AVAILABLE_IN_3_1
+void tracker_sparql_connection_update_resource_async (TrackerSparqlConnection *connection,
+ const gchar *graph,
+ TrackerResource *resource,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+TRACKER_AVAILABLE_IN_3_1
+gboolean tracker_sparql_connection_update_resource_finish (TrackerSparqlConnection *connection,
+ GAsyncResult *res,
+ GError **error);
+TRACKER_AVAILABLE_IN_3_1
+TrackerBatch * tracker_sparql_connection_create_batch (TrackerSparqlConnection *connection);
+
TRACKER_AVAILABLE_IN_ALL
GVariant * tracker_sparql_connection_update_blank (TrackerSparqlConnection *connection,
const gchar *sparql,
diff --git a/src/libtracker-sparql/tracker-namespace-manager.c b/src/libtracker-sparql/tracker-namespace-manager.c
index c4f4a3003..d8f284ca9 100644
--- a/src/libtracker-sparql/tracker-namespace-manager.c
+++ b/src/libtracker-sparql/tracker-namespace-manager.c
@@ -99,8 +99,6 @@ finalize (GObject *object)
* Creates a new #TrackerNamespaceManager instance.
*
* Returns: a new #TrackerNamespaceManager instance
- *
- * Since: 1.10
*/
TrackerNamespaceManager *
tracker_namespace_manager_new ()
@@ -123,8 +121,6 @@ tracker_namespace_manager_new ()
* ontologies, if they have been modified since they were installed.
*
* Returns: (transfer none): a global, shared #TrackerNamespaceManager instance
- *
- * Since: 1.10
*/
TrackerNamespaceManager *
tracker_namespace_manager_get_default ()
@@ -165,8 +161,6 @@ tracker_namespace_manager_get_default ()
* Returns whether @prefix is known.
*
* Returns: %TRUE if the #TrackerNamespaceManager knows about @prefix, %FALSE otherwise
- *
- * Since: 1.10
*/
gboolean
tracker_namespace_manager_has_prefix (TrackerNamespaceManager *self,
@@ -190,8 +184,6 @@ tracker_namespace_manager_has_prefix (TrackerNamespaceManager *self,
* is not known.
*
* Returns: a string owned by the #TrackerNamespaceManager, or %NULL
- *
- * Since: 1.10
*/
const char *
tracker_namespace_manager_lookup_prefix (TrackerNamespaceManager *self,
@@ -216,8 +208,6 @@ tracker_namespace_manager_lookup_prefix (TrackerNamespaceManager *self,
*
* Only one prefix is allowed for a given namespace, and all prefixes must
* be unique.
- *
- * Since: 1.10
*/
void
tracker_namespace_manager_add_prefix (TrackerNamespaceManager *self,
@@ -264,8 +254,6 @@ tracker_namespace_manager_add_prefix (TrackerNamespaceManager *self,
* expanded URI. Otherwise, a copy of @compact_uri will be returned.
*
* Returns: a newly-allocated string
- *
- * Since: 1.10
*/
char *
tracker_namespace_manager_expand_uri (TrackerNamespaceManager *self,
@@ -307,8 +295,6 @@ tracker_namespace_manager_expand_uri (TrackerNamespaceManager *self,
* Writes out all namespaces as Turtle @prefix statements.
*
* Returns: a newly-allocated string
- *
- * Since: 1.10
*/
char *
tracker_namespace_manager_print_turtle (TrackerNamespaceManager *self)
@@ -338,8 +324,6 @@ tracker_namespace_manager_print_turtle (TrackerNamespaceManager *self)
* @user_data: user data to pass to the function
*
* Calls @func for each known prefix / URI pair.
- *
- * Since: 1.10
*/
void
tracker_namespace_manager_foreach (TrackerNamespaceManager *self,
diff --git a/src/libtracker-sparql/tracker-notifier.c b/src/libtracker-sparql/tracker-notifier.c
index 38e6897fe..cf1c9a9dd 100644
--- a/src/libtracker-sparql/tracker-notifier.c
+++ b/src/libtracker-sparql/tracker-notifier.c
@@ -883,8 +883,6 @@ _tracker_notifier_get_connection (TrackerNotifier *notifier)
* Returns the event type.
*
* Returns: The event type
- *
- * Since: 1.12
**/
TrackerNotifierEventType
tracker_notifier_event_get_event_type (TrackerNotifierEvent *event)
@@ -901,8 +899,6 @@ tracker_notifier_event_get_event_type (TrackerNotifierEvent *event)
* which is used as efficient internal identifier for the resource.
*
* Returns: the resource ID
- *
- * Since: 1.12
**/
gint64
tracker_notifier_event_get_id (TrackerNotifierEvent *event)
@@ -922,8 +918,6 @@ tracker_notifier_event_get_id (TrackerNotifierEvent *event)
* notified upon, typically of the form "urn:uuid:...".
*
* Returns: The element URN
- *
- * Since: 1.12
**/
const gchar *
tracker_notifier_event_get_urn (TrackerNotifierEvent *event)
diff --git a/src/libtracker-sparql/tracker-private.h b/src/libtracker-sparql/tracker-private.h
index d91f6e7f4..6c696d4a7 100644
--- a/src/libtracker-sparql/tracker-private.h
+++ b/src/libtracker-sparql/tracker-private.h
@@ -20,8 +20,9 @@
#ifndef __TRACKER_PRIVATE_H__
#define __TRACKER_PRIVATE_H__
-#include "tracker-cursor.h"
-#include "tracker-endpoint-dbus.h"
+#include <libtracker-sparql/tracker-version-generated.h>
+#include <libtracker-sparql/tracker-cursor.h>
+#include <libtracker-sparql/tracker-endpoint-dbus.h>
typedef struct _TrackerSparqlConnectionClass TrackerSparqlConnectionClass;
@@ -89,6 +90,22 @@ struct _TrackerSparqlConnectionClass
gboolean (* close_finish) (TrackerSparqlConnection *connection,
GAsyncResult *res,
GError **error);
+
+ gboolean (* update_resource) (TrackerSparqlConnection *connection,
+ const gchar *graph,
+ TrackerResource *resource,
+ GCancellable *cancellable,
+ GError **error);
+ void (* update_resource_async) (TrackerSparqlConnection *connection,
+ const gchar *graph,
+ TrackerResource *resource,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* update_resource_finish) (TrackerSparqlConnection *connection,
+ GAsyncResult *res,
+ GError **error);
+ TrackerBatch * (* create_batch) (TrackerSparqlConnection *connection);
};
typedef struct _TrackerSparqlCursorClass TrackerSparqlCursorClass;
@@ -211,6 +228,28 @@ struct _TrackerNotifierClass {
const GPtrArray *events);
};
+typedef struct _TrackerBatchClass TrackerBatchClass;
+
+struct _TrackerBatchClass {
+ GObjectClass parent_class;
+
+ void (* add_sparql) (TrackerBatch *batch,
+ const gchar *sparql);
+ void (* add_resource) (TrackerBatch *batch,
+ const gchar *graph,
+ TrackerResource *resource);
+ gboolean (* execute) (TrackerBatch *batch,
+ GCancellable *cancellable,
+ GError **error);
+ void (* execute_async) (TrackerBatch *batch,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* execute_finish) (TrackerBatch *batch,
+ GAsyncResult *res,
+ GError **error);
+};
+
void tracker_sparql_cursor_set_connection (TrackerSparqlCursor *cursor,
TrackerSparqlConnection *connection);
GError * _translate_internal_error (GError *error);
diff --git a/src/libtracker-sparql/tracker-resource.c b/src/libtracker-sparql/tracker-resource.c
index 4c4c0fc42..5c64e24c5 100644
--- a/src/libtracker-sparql/tracker-resource.c
+++ b/src/libtracker-sparql/tracker-resource.c
@@ -227,8 +227,6 @@ set_property (GObject *object,
* Creates a TrackerResource instance.
*
* Returns: a newly created #TrackerResource. Free with g_object_unref() when done
- *
- * Since: 1.10
*/
TrackerResource *
tracker_resource_new (const char *identifier)
@@ -264,8 +262,6 @@ tracker_resource_new (const char *identifier)
* You can pass any kind of GValue for @value, but serialization functions will
* normally only be able to serialize URIs/relationships and fundamental value
* types (string, int, etc.).
- *
- * Since: 1.10
*/
void
tracker_resource_set_gvalue (TrackerResource *self,
@@ -363,8 +359,6 @@ validate_pointer (const void *pointer,
* @value: the property object
*
* Sets a single-valued boolean object.
- *
- * Since: 1.10
*/
SET_PROPERTY_FOR_GTYPE (tracker_resource_set_boolean, gboolean, G_TYPE_BOOLEAN, g_value_set_boolean, validate_boolean);
@@ -375,8 +369,6 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_boolean, gboolean, G_TYPE_BOOLEAN,
* @value: the property object
*
* Sets a single-valued double object.
- *
- * Since: 1.10
*/
SET_PROPERTY_FOR_GTYPE (tracker_resource_set_double, double, G_TYPE_DOUBLE, g_value_set_double, validate_double);
@@ -387,8 +379,6 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_double, double, G_TYPE_DOUBLE, g_va
* @value: the property object
*
* Sets a single-valued integer object.
- *
- * Since: 1.10
*/
SET_PROPERTY_FOR_GTYPE (tracker_resource_set_int, int, G_TYPE_INT, g_value_set_int, validate_int);
@@ -399,8 +389,6 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_int, int, G_TYPE_INT, g_value_set_i
* @value: the property object
*
* Sets a single-valued integer object.
- *
- * Since: 1.10
*/
SET_PROPERTY_FOR_GTYPE (tracker_resource_set_int64, gint64, G_TYPE_INT64, g_value_set_int64, validate_int64);
@@ -414,8 +402,6 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_int64, gint64, G_TYPE_INT64, g_valu
* function produces similar RDF to tracker_resource_set_uri(),
* although in this function the URI will depend on the identifier
* set on @resource.
- *
- * Since: 1.10
*/
SET_PROPERTY_FOR_GTYPE (tracker_resource_set_relation, TrackerResource *, TRACKER_TYPE_RESOURCE, g_value_set_object, validate_pointer);
@@ -429,8 +415,6 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_relation, TrackerResource *, TRACKE
* function produces similar RDF to tracker_resource_set_uri(),
* although in this function the URI will depend on the identifier
* set on @resource. This function takes ownership of @resource.
- *
- * Since: 2.0
*/
SET_PROPERTY_FOR_GTYPE (tracker_resource_set_take_relation, TrackerResource *, TRACKER_TYPE_RESOURCE, g_value_take_object, validate_pointer);
@@ -441,8 +425,6 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_take_relation, TrackerResource *, T
* @value: the property object
*
* Sets a single-valued string object.
- *
- * Since: 1.10
*/
SET_PROPERTY_FOR_GTYPE (tracker_resource_set_string, const char *, G_TYPE_STRING, g_value_set_string, validate_pointer);
@@ -455,8 +437,6 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_string, const char *, G_TYPE_STRING
* Sets a single-valued resource object as a string URI. This function
* produces similar RDF to tracker_resource_set_relation(), although
* it requires that the URI is previously known.
- *
- * Since: 1.10
*/
SET_PROPERTY_FOR_GTYPE (tracker_resource_set_uri, const char *, TRACKER_TYPE_URI, g_value_set_string, validate_pointer);
@@ -471,8 +451,6 @@ SET_PROPERTY_FOR_GTYPE (tracker_resource_set_uri, const char *, TRACKER_TYPE_URI
* You can pass any kind of GValue for @value, but serialization functions will
* normally only be able to serialize URIs/relationships and fundamental value
* types (string, int, etc.).
- *
- * Since: 1.10
*/
void
tracker_resource_add_gvalue (TrackerResource *self,
@@ -583,8 +561,6 @@ tracker_resource_add_gvalue (TrackerResource *self,
* @value: the property object
*
* Adds a boolean object to a multi-valued property.
- *
- * Since: 1.10
*/
ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_boolean, gboolean, G_TYPE_BOOLEAN, g_value_set_boolean, validate_boolean);
@@ -595,8 +571,6 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_boolean, gboolean, G_TYPE_BOOLEAN,
* @value: the property object
*
* Adds a double object to a multi-valued property.
- *
- * Since: 1.10
*/
ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_double, double, G_TYPE_DOUBLE, g_value_set_double, validate_double);
@@ -607,8 +581,6 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_double, double, G_TYPE_DOUBLE, g_va
* @value: the property object
*
* Adds an integer object to a multi-valued property.
- *
- * Since: 1.10
*/
ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_int, int, G_TYPE_INT, g_value_set_int, validate_int);
@@ -619,8 +591,6 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_int, int, G_TYPE_INT, g_value_set_i
* @value: the property object
*
* Adds an integer object to a multi-valued property.
- *
- * Since: 1.10
*/
ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_int64, gint64, G_TYPE_INT64, g_value_set_int64, validate_int64);
@@ -634,8 +604,6 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_int64, gint64, G_TYPE_INT64, g_valu
* function produces similar RDF to tracker_resource_add_uri(),
* although in this function the URI will depend on the identifier
* set on @resource.
- *
- * Since: 1.10
*/
ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_relation, TrackerResource *, TRACKER_TYPE_RESOURCE, g_value_set_object, validate_pointer);
@@ -649,8 +617,6 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_relation, TrackerResource *, TRACKE
* function produces similar RDF to tracker_resource_add_uri(),
* although in this function the URI will depend on the identifier
* set on @resource. This function takes ownership of @resource.
- *
- * Since: 2.0
*/
ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_take_relation, TrackerResource *, TRACKER_TYPE_RESOURCE, g_value_take_object, validate_pointer);
@@ -662,8 +628,6 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_take_relation, TrackerResource *, T
* @value: the property object
*
* Adds a string object to a multi-valued property.
- *
- * Since: 1.10
*/
ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_string, const char *, G_TYPE_STRING, g_value_set_string, validate_pointer);
@@ -676,8 +640,6 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_string, const char *, G_TYPE_STRING
* Adds a resource object to a multi-valued property. This function
* produces similar RDF to tracker_resource_add_relation(), although
* it requires that the URI is previously known.
- *
- * Since: 1.10
*/
ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_uri, const char *, TRACKER_TYPE_URI, g_value_set_string, validate_pointer);
@@ -691,8 +653,6 @@ ADD_PROPERTY_FOR_GTYPE (tracker_resource_add_uri, const char *, TRACKER_TYPE_URI
*
* Returns: (transfer container) (element-type GValue): a #GList of #GValue
* instances. The list should be freed with g_list_free()
- *
- * Since: 1.10
*/
GList *tracker_resource_get_values (TrackerResource *self,
const char *property_uri)
@@ -768,8 +728,6 @@ GList *tracker_resource_get_values (TrackerResource *self,
* Returns the first boolean object previously assigned to a property.
*
* Returns: the first boolean object
- *
- * Since: 1.10
*/
GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_boolean, gboolean, G_TYPE_BOOLEAN, g_value_get_boolean, FALSE);
@@ -781,8 +739,6 @@ GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_boolean, gboolean, G_TYPE_BOO
* Returns the first double object previously assigned to a property.
*
* Returns: the first double object
- *
- * Since: 1.10
*/
GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_double, double, G_TYPE_DOUBLE, g_value_get_double, 0.0);
@@ -794,8 +750,6 @@ GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_double, double, G_TYPE_DOUBLE
* Returns the first integer object previously assigned to a property.
*
* Returns: the first integer object
- *
- * Since: 1.10
*/
GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_int, int, G_TYPE_INT, g_value_get_int, 0);
@@ -807,8 +761,6 @@ GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_int, int, G_TYPE_INT, g_value
* Returns the first integer object previously assigned to a property.
*
* Returns: the first integer object
- *
- * Since: 1.10
*/
GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_int64, gint64, G_TYPE_INT64, g_value_get_int64, 0);
@@ -820,8 +772,6 @@ GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_int64, gint64, G_TYPE_INT64,
* Returns the first resource object previously assigned to a property.
*
* Returns: (transfer none): the first resource object
- *
- * Since: 1.10
*/
GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_relation, TrackerResource *, TRACKER_TYPE_RESOURCE, g_value_get_object, NULL);
@@ -833,8 +783,6 @@ GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_relation, TrackerResource *,
* Returns the first string object previously assigned to a property.
*
* Returns: the first string object
- *
- * Since: 1.10
*/
GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_string, const char *, G_TYPE_STRING, g_value_get_string, NULL);
@@ -846,8 +794,6 @@ GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_string, const char *, G_TYPE_
* Returns the first resource object previously assigned to a property.
*
* Returns: the first resource object as an URI.
- *
- * Since: 1.10
*/
GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_uri, const char *, TRACKER_TYPE_URI, g_value_get_string, NULL);
@@ -861,8 +807,6 @@ GET_PROPERTY_FOR_GTYPE (tracker_resource_get_first_uri, const char *, TRACKER_TY
* SPARQL blank node identifier, such as "_:123".
*
* Returns: a string owned by the resource
- *
- * Since: 1.10
*/
const char *
tracker_resource_get_identifier (TrackerResource *self)
@@ -888,8 +832,6 @@ tracker_resource_get_identifier (TrackerResource *self)
*
* If the identifier is set to NULL, a SPARQL blank node identifier such as
* "_:123" is assigned to the resource.
- *
- * Since: 1.10
*/
void
tracker_resource_set_identifier (TrackerResource *self,
@@ -953,8 +895,6 @@ tracker_resource_identifier_compare_func (TrackerResource *resource,
* thing.
*
* Returns: 0 if the identifiers are the same, -1 or +1 otherwise
- *
- * Since: 1.10
*/
gint
tracker_resource_compare (TrackerResource *a,
@@ -1284,8 +1224,6 @@ generate_turtle (TrackerResource *resource,
* usual prefixes for all of the ontologies that Tracker ships with by default.
*
* Returns: a newly-allocated string
- *
- * Since: 1.10
*/
char *
tracker_resource_print_turtle (TrackerResource *self,
@@ -1541,8 +1479,6 @@ generate_sparql_insert_pattern (TrackerResource *resource,
* usual prefixes for all of the ontologies that Tracker ships with by default.
*
* Returns: a newly-allocated string containing a SPARQL update command.
- *
- * Since: 1.10
*/
char *
tracker_resource_print_sparql_update (TrackerResource *resource,
@@ -1731,8 +1667,6 @@ generate_jsonld_namespace_mapping_foreach (gpointer key,
* usual prefixes for all of the ontologies that Tracker ships with by default.
*
* Returns: a newly-allocated string containing JSON-LD data.
- *
- * Since: 2.0.5
*/
char *
tracker_resource_print_jsonld (TrackerResource *self,
@@ -1819,8 +1753,6 @@ tracker_serialize_single_value (TrackerResource *resource,
*
* Returns: (transfer full): A variant describing the resource,
* the reference is floating.
- *
- * Since: 3.0
**/
GVariant *
tracker_resource_serialize (TrackerResource *resource)
@@ -1898,8 +1830,6 @@ tracker_resource_serialize (TrackerResource *resource)
*
* Returns: (transfer full): A TrackerResource, or %NULL if
* deserialization fails.
- *
- * Since: 3.0
**/
TrackerResource *
tracker_resource_deserialize (GVariant *variant)
@@ -2010,3 +1940,24 @@ tracker_resource_deserialize (GVariant *variant)
return resource;
}
+
+/**
+ * tracker_resource_get_property_overwrite:
+ * @resource: a #TrackerResource
+ * @property_uri: a string identifying the property to query
+ *
+ * Returns whether the prior values for this property would be deleted
+ * in the SPARQL issued by @resource.
+ *
+ * Returns: #TRUE if the property would be overwritten
+ *
+ * Since: 3.1
+ **/
+gboolean
+tracker_resource_get_property_overwrite (TrackerResource *resource,
+ const gchar *property_uri)
+{
+ TrackerResourcePrivate *priv = GET_PRIVATE (resource);
+
+ return g_hash_table_contains (priv->overwrite, property_uri);
+}
diff --git a/src/libtracker-sparql/tracker-resource.h b/src/libtracker-sparql/tracker-resource.h
index 171834449..f975c757c 100644
--- a/src/libtracker-sparql/tracker-resource.h
+++ b/src/libtracker-sparql/tracker-resource.h
@@ -114,6 +114,9 @@ GVariant * tracker_resource_serialize (TrackerResource *resource);
TRACKER_AVAILABLE_IN_ALL
TrackerResource * tracker_resource_deserialize (GVariant *variant);
+TRACKER_AVAILABLE_IN_3_1
+gboolean tracker_resource_get_property_overwrite (TrackerResource *resource, const gchar *property_uri);
+
G_END_DECLS
#endif /* __LIBTRACKER_RESOURCE_H__ */
diff --git a/src/libtracker-sparql/tracker-sparql.h b/src/libtracker-sparql/tracker-sparql.h
index 60432ff6a..cb6309a0d 100644
--- a/src/libtracker-sparql/tracker-sparql.h
+++ b/src/libtracker-sparql/tracker-sparql.h
@@ -22,9 +22,11 @@
#define __LIBTRACKER_SPARQL_INSIDE__
+#include <libtracker-sparql/tracker-version-generated.h>
#include <libtracker-sparql/tracker-version.h>
#include <libtracker-sparql/tracker-error.h>
#include <libtracker-sparql/tracker-connection.h>
+#include <libtracker-sparql/tracker-batch.h>
#include <libtracker-sparql/tracker-cursor.h>
#include <libtracker-sparql/tracker-endpoint.h>
#include <libtracker-sparql/tracker-endpoint-dbus.h>
diff --git a/src/libtracker-sparql/tracker-uri.c b/src/libtracker-sparql/tracker-uri.c
index b97f84527..3f01256b0 100644
--- a/src/libtracker-sparql/tracker-uri.c
+++ b/src/libtracker-sparql/tracker-uri.c
@@ -161,8 +161,6 @@ find_conversion (const char *format,
*
* Returns: (transfer full): a newly-allocated string holding the result. The returned string
* should be freed with g_free() when no longer needed.
- *
- * Since: 0.10
*/
gchar *
tracker_sparql_escape_uri_vprintf (const gchar *format,
@@ -265,8 +263,6 @@ cleanup:
*
* Returns: (transfer full): a newly-allocated string holding the result.The returned string
* should be freed with g_free() when no longer needed.
- *
- * Since: 0.10
*/
gchar *
tracker_sparql_escape_uri_printf (const gchar *format, ...)
@@ -289,8 +285,6 @@ tracker_sparql_escape_uri_printf (const gchar *format, ...)
*
* Returns: (transfer full): a newly-allocated string holding the result. The returned string
* should be freed with g_free() when no longer needed.
- *
- * Since: 1.12
*/
gchar *
tracker_sparql_escape_uri (const gchar *uri)
diff --git a/src/libtracker-sparql/tracker-version-generated.h.meson.in b/src/libtracker-sparql/tracker-version-generated.h.meson.in
new file mode 100644
index 000000000..6bff961b1
--- /dev/null
+++ b/src/libtracker-sparql/tracker-version-generated.h.meson.in
@@ -0,0 +1,28 @@
+/* Generated by meson */
+
+/**
+ * TRACKER_MAJOR_VERSION:
+ *
+ * The major version of the Tracker library.
+ *
+ * Like #tracker_major_version, but intended to be used at application compile time.
+ */
+#mesondefine TRACKER_MAJOR_VERSION
+
+/**
+ * TRACKER_MINOR_VERSION:
+ *
+ * The minor version of the Tracker library.
+ *
+ * Like #tracker_minor_version, but intended to be used at application compile time.
+ */
+#mesondefine TRACKER_MINOR_VERSION
+
+/**
+ * TRACKER_MICRO_VERSION:
+ *
+ * The micro version of the Tracker library.
+ *
+ * Like #tracker_micro_version, but intended to be used at application compile time.
+ */
+#mesondefine TRACKER_MICRO_VERSION
diff --git a/src/libtracker-sparql/tracker-version.c b/src/libtracker-sparql/tracker-version.c
index 6a71facab..7fd829482 100644
--- a/src/libtracker-sparql/tracker-version.c
+++ b/src/libtracker-sparql/tracker-version.c
@@ -66,8 +66,6 @@ const guint tracker_binary_age = TRACKER_BINARY_AGE;
* given version, or a string describing the version mismatch.
* The returned string is owned by Tracker and must not be modified
* or freed.
- *
- * Since: 0.10
**/
const gchar *
tracker_check_version (guint required_major,
diff --git a/src/libtracker-sparql/tracker-version.h b/src/libtracker-sparql/tracker-version.h
index fe18f24ef..cb730fbc9 100644
--- a/src/libtracker-sparql/tracker-version.h
+++ b/src/libtracker-sparql/tracker-version.h
@@ -33,8 +33,42 @@ G_BEGIN_DECLS
#define _TRACKER_EXTERN __attribute__((visibility("default"))) extern
#endif
+#define _TRACKER_UNAVAILABLE(maj, min) G_UNAVAILABLE(maj, min) _TRACKER_EXTERN
+#define _TRACKER_DEPRECATED G_DEPRECATED _TRACKER_EXTERN
+#define _TRACKER_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _TRACKER_EXTERN
+
+#define TRACKER_VERSION_3_0 G_ENCODE_VERSION (3, 0)
+#define TRACKER_VERSION_3_1 G_ENCODE_VERSION (3, 1)
+#define TRACKER_VERSION_CUR G_ENCODE_VERSION (TRACKER_MAJOR_VERSION, TRACKER_MINOR_VERSION)
+
+#ifndef TRACKER_VERSION_MIN_REQUIRED
+#define TRACKER_VERSION_MIN_REQUIRED TRACKER_VERSION_CUR
+#endif
+
+#ifndef TRACKER_VERSION_MAX_ALLOWED
+#define TRACKER_VERSION_MAX_ALLOWED TRACKER_VERSION_CUR
+#endif
+
+#if TRACKER_VERSION_MIN_REQUIRED > TRACKER_VERSION_MAX_ALLOWED
+#error "TRACKER_VERSION_MAX_ALLOWED must be >= TRACKER_VERSION_MIN_REQUIRED"
+#endif
+
#define TRACKER_AVAILABLE_IN_ALL _TRACKER_EXTERN
+#if TRACKER_VERSION_MIN_REQUIRED >= TRACKER_VERSION_3_1
+#define TRACKER_DEPRECATED_IN_3_1 _TRACKER_DEPRECATED
+#define TRACKER_DEPRECATED_IN_3_1_FOR(f) _TRACKER_DEPRECATED_FOR(f)
+#else
+#define TRACKER_DEPRECATED_IN_3_1 _TRACKER_EXTERN
+#define TRACKER_DEPRECATED_IN_3_1_FOR(f) _TRACKER_EXTERN
+#endif
+
+#if TRACKER_VERSION_MAX_ALLOWED < TRACKER_VERSION_3_1
+#define TRACKER_AVAILABLE_IN_3_1 _TRACKER_UNAVAILABLE(3, 1)
+#else
+#define TRACKER_AVAILABLE_IN_3_1 _TRACKER_EXTERN
+#endif
+
/**
* tracker_major_version:
*
@@ -101,8 +135,6 @@ GLIB_VAR const guint tracker_binary_age;
* }
* </programlisting>
* </example>
- *
- * Since: 0.10
**/
#define TRACKER_CHECK_VERSION(major,minor,micro) \
(TRACKER_MAJOR_VERSION > (major) || \