[tracker/blank] SPARQL: Return generated URIs for inserted blank nodes
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [tracker/blank] SPARQL: Return generated URIs for inserted blank nodes
- Date: Mon, 23 Nov 2009 15:38:32 +0000 (UTC)
commit 9259b002b210a129e6c3c9d9af5ec81c548b1c69
Author: Jürg Billeter <j bitron ch>
Date: Fri Nov 20 12:02:13 2009 +0100
SPARQL: Return generated URIs for inserted blank nodes
data/dbus/tracker-resources.xml | 7 +
src/libtracker-client/tracker.c | 43 +++++++
src/libtracker-client/tracker.h | 7 +
src/libtracker-data/tracker-data-update.c | 42 +++++++-
src/libtracker-data/tracker-data-update.h | 3 +
src/libtracker-data/tracker-sparql-query.vala | 158 +++++++++++++++++--------
src/tracker-store/tracker-resources.c | 38 ++++++
src/tracker-store/tracker-resources.h | 4 +
src/tracker-store/tracker-store.c | 30 +++++
src/tracker-store/tracker-store.h | 2 +
src/tracker-utils/tracker-sparql.c | 26 ++++-
11 files changed, 311 insertions(+), 49 deletions(-)
---
diff --git a/data/dbus/tracker-resources.xml b/data/dbus/tracker-resources.xml
index 7b28ac5..7f7ac1f 100644
--- a/data/dbus/tracker-resources.xml
+++ b/data/dbus/tracker-resources.xml
@@ -24,6 +24,13 @@
<arg type="s" name="query" direction="in" />
</method>
+ <!-- SPARQL Update extensions, insert and delete -->
+ <method name="SparqlUpdateBlank">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+ <arg type="s" name="query" direction="in" />
+ <arg type="aaa{ss}" name="result" direction="out" />
+ </method>
+
<!-- SPARQL Update as part of a batch, use this method when sending a
possibly large amount of updates to improve performance, may delay
database commit until receiving BatchCommit -->
diff --git a/src/libtracker-client/tracker.c b/src/libtracker-client/tracker.c
index 3280e5f..051ff2a 100644
--- a/src/libtracker-client/tracker.c
+++ b/src/libtracker-client/tracker.c
@@ -365,6 +365,23 @@ tracker_resources_sparql_update (TrackerClient *client,
&*error);
}
+GPtrArray *
+tracker_resources_sparql_update_blank (TrackerClient *client,
+ const gchar *query,
+ GError **error)
+{
+ GPtrArray *result;
+
+ if (!org_freedesktop_Tracker1_Resources_sparql_update_blank (client->proxy_resources,
+ query,
+ &result,
+ &*error)) {
+ return NULL;
+ }
+
+ return result;
+}
+
void
tracker_resources_batch_sparql_update (TrackerClient *client,
const gchar *query,
@@ -486,6 +503,32 @@ tracker_resources_sparql_update_async (TrackerClient *client,
}
guint
+tracker_resources_sparql_update_blank_async (TrackerClient *client,
+ const gchar *query,
+ TrackerReplyGPtrArray callback,
+ gpointer user_data)
+{
+ CallbackGPtrArray *s;
+ DBusGProxyCall *call;
+ guint id;
+
+ s = g_new0 (CallbackGPtrArray, 1);
+ s->callback = callback;
+ s->data = user_data;
+ s->client = client;
+
+ call = org_freedesktop_Tracker1_Resources_sparql_update_blank_async (client->proxy_resources,
+ query,
+ tracker_GPtrArray_reply,
+ s);
+
+ id = pending_call_new (client, client->proxy_resources, call);
+ s->id = id;
+
+ return id;
+}
+
+guint
tracker_resources_batch_sparql_update_async (TrackerClient *client,
const gchar *query,
TrackerReplyVoid callback,
diff --git a/src/libtracker-client/tracker.h b/src/libtracker-client/tracker.h
index a69674a..b05445e 100644
--- a/src/libtracker-client/tracker.h
+++ b/src/libtracker-client/tracker.h
@@ -63,6 +63,9 @@ GPtrArray * tracker_resources_sparql_query (TrackerClient
void tracker_resources_sparql_update (TrackerClient *client,
const gchar *query,
GError **error);
+GPtrArray * tracker_resources_sparql_update_blank (TrackerClient *client,
+ const gchar *query,
+ GError **error);
void tracker_resources_batch_sparql_update (TrackerClient *client,
const gchar *query,
GError **error);
@@ -84,6 +87,10 @@ guint tracker_resources_sparql_update_async (TrackerClient
const gchar *query,
TrackerReplyVoid callback,
gpointer user_data);
+guint tracker_resources_sparql_update_blank_async (TrackerClient *client,
+ const gchar *query,
+ TrackerReplyGPtrArray callback,
+ gpointer user_data);
guint tracker_resources_batch_sparql_update_async (TrackerClient *client,
const gchar *query,
TrackerReplyVoid callback,
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 77a32b4..01cb9ea 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -2003,7 +2003,7 @@ tracker_data_update_sparql (const gchar *update,
tracker_db_interface_execute_query (iface, NULL, "SAVEPOINT sparql");
- tracker_sparql_query_execute (sparql_query, error);
+ tracker_sparql_query_execute_update (sparql_query, FALSE, error);
if (*error) {
tracker_data_update_buffer_clear ();
@@ -2024,3 +2024,43 @@ tracker_data_update_sparql (const gchar *update,
g_object_unref (sparql_query);
}
+
+GPtrArray *
+tracker_data_update_sparql_blank (const gchar *update,
+ GError **error)
+{
+ TrackerDBInterface *iface;
+ TrackerSparqlQuery *sparql_query;
+ GPtrArray *blank_nodes;
+
+ g_return_val_if_fail (update != NULL, NULL);
+
+ iface = tracker_db_manager_get_db_interface ();
+
+ sparql_query = tracker_sparql_query_new_update (update);
+
+ tracker_db_interface_execute_query (iface, NULL, "SAVEPOINT sparql");
+
+ blank_nodes = tracker_sparql_query_execute_update (sparql_query, TRUE, error);
+
+ if (*error) {
+ tracker_data_update_buffer_clear ();
+ tracker_db_interface_execute_query (iface, NULL, "ROLLBACK TO sparql");
+
+ if (rollback_callbacks) {
+ guint n;
+ for (n = 0; n < rollback_callbacks->len; n++) {
+ TrackerCommitDelegate *delegate;
+ delegate = g_ptr_array_index (rollback_callbacks, n);
+ delegate->callback (delegate->user_data);
+ }
+ }
+ }
+
+ tracker_db_interface_execute_query (iface, NULL, "RELEASE sparql");
+
+ g_object_unref (sparql_query);
+
+ return blank_nodes;
+}
+
diff --git a/src/libtracker-data/tracker-data-update.h b/src/libtracker-data/tracker-data-update.h
index 1298cd9..00839cf 100644
--- a/src/libtracker-data/tracker-data-update.h
+++ b/src/libtracker-data/tracker-data-update.h
@@ -81,6 +81,9 @@ void tracker_data_begin_transaction (void);
void tracker_data_commit_transaction (void);
void tracker_data_update_sparql (const gchar *update,
GError **error);
+GPtrArray *
+ tracker_data_update_sparql_blank (const gchar *update,
+ GError **error);
void tracker_data_update_buffer_flush (GError **error);
/* Volume handling */
diff --git a/src/libtracker-data/tracker-sparql-query.vala b/src/libtracker-data/tracker-sparql-query.vala
index 69bf488..99b25c2 100644
--- a/src/libtracker-data/tracker-sparql-query.vala
+++ b/src/libtracker-data/tracker-sparql-query.vala
@@ -272,6 +272,7 @@ public class Tracker.SparqlQuery : Object {
int bnodeid = 0;
// base UUID used for blank nodes
uchar[] base_uuid;
+ HashTable<string,string> blank_nodes;
public SparqlQuery (string query) {
tokens = new TokenInfo[BUFFER_SIZE];
@@ -294,17 +295,40 @@ public class Tracker.SparqlQuery : Object {
if (user_bnodeid == null) {
return ":%d".printf (++bnodeid);
} else {
+ string uri = null;
+
+ if (blank_nodes != null) {
+ uri = blank_nodes.lookup (user_bnodeid);
+ if (uri != null) {
+ return uri;
+ }
+ }
+
var checksum = new Checksum (ChecksumType.SHA1);
// base UUID, unique per file
checksum.update (base_uuid, 16);
- // node ID
- checksum.update ((uchar[]) user_bnodeid, -1);
- string sha1 = checksum.get_string ();
+ while (uri == null) {
+ // node ID
+ checksum.update ((uchar[]) user_bnodeid, -1);
+
+ string sha1 = checksum.get_string ();
- // generate name based uuid
- return "urn:uuid:%.8s-%.4s-%.4s-%.4s-%.12s".printf (
- sha1, sha1.offset (8), sha1.offset (12), sha1.offset (16), sha1.offset (20));
+ // generate name based uuid
+ uri = "urn:uuid:%.8s-%.4s-%.4s-%.4s-%.12s".printf (
+ sha1, sha1.offset (8), sha1.offset (12), sha1.offset (16), sha1.offset (20));
+
+ if (blank_nodes != null) {
+ if (Data.query_resource_id (uri) > 0) {
+ blank_nodes.insert (user_bnodeid, uri);
+ } else {
+ // uri collision
+ uri = null;
+ }
+ }
+ }
+
+ return uri;
}
}
@@ -418,6 +442,8 @@ public class Tracker.SparqlQuery : Object {
}
public DBResultSet? execute () throws Error {
+ assert (!update_extensions);
+
scanner = new SparqlScanner ((char*) query_string, (long) query_string.size ());
next ();
@@ -430,49 +456,71 @@ public class Tracker.SparqlQuery : Object {
parse_prologue ();
- if (!update_extensions) {
+ switch (current ()) {
+ case SparqlTokenType.SELECT:
+ return execute_select ();
+ case SparqlTokenType.CONSTRUCT:
+ throw get_internal_error ("CONSTRUCT is not supported");
+ case SparqlTokenType.DESCRIBE:
+ throw get_internal_error ("DESCRIBE is not supported");
+ case SparqlTokenType.ASK:
+ return execute_ask ();
+ case SparqlTokenType.INSERT:
+ case SparqlTokenType.DELETE:
+ case SparqlTokenType.DROP:
+ throw get_error ("INSERT and DELETE are not supported in query mode");
+ default:
+ throw get_error ("expected SELECT or ASK");
+ }
+ }
+
+ public PtrArray? execute_update (bool blank) throws Error {
+ assert (update_extensions);
+
+ scanner = new SparqlScanner ((char*) query_string, (long) query_string.size ());
+ next ();
+
+ // declare fn prefix for XPath functions
+ prefix_map.insert ("fn", FN_NS);
+
+ foreach (Namespace ns in Ontology.get_namespaces ()) {
+ prefix_map.insert (ns.prefix, ns.uri);
+ }
+
+ parse_prologue ();
+
+ PtrArray blank_nodes = null;
+ if (blank) {
+ blank_nodes = new PtrArray ();
+ }
+
+ // SPARQL update supports multiple operations in a single query
+
+ while (current () != SparqlTokenType.EOF) {
switch (current ()) {
+ case SparqlTokenType.INSERT:
+ PtrArray* ptr = execute_insert (blank);
+ if (blank) {
+ blank_nodes.add (ptr);
+ }
+ break;
+ case SparqlTokenType.DELETE:
+ execute_delete ();
+ break;
+ case SparqlTokenType.DROP:
+ execute_drop_graph ();
+ break;
case SparqlTokenType.SELECT:
- return execute_select ();
case SparqlTokenType.CONSTRUCT:
- throw get_internal_error ("CONSTRUCT is not supported");
case SparqlTokenType.DESCRIBE:
- throw get_internal_error ("DESCRIBE is not supported");
case SparqlTokenType.ASK:
- return execute_ask ();
- case SparqlTokenType.INSERT:
- case SparqlTokenType.DELETE:
- case SparqlTokenType.DROP:
- throw get_error ("INSERT and DELETE are not supported in query mode");
+ throw get_error ("SELECT, CONSTRUCT, DESCRIBE, and ASK are not supported in update mode");
default:
- throw get_error ("expected SELECT or ASK");
- }
- } else {
- // SPARQL update supports multiple operations in a single query
-
- while (current () != SparqlTokenType.EOF) {
- switch (current ()) {
- case SparqlTokenType.INSERT:
- execute_insert ();
- break;
- case SparqlTokenType.DELETE:
- execute_delete ();
- break;
- case SparqlTokenType.DROP:
- execute_drop_graph ();
- break;
- case SparqlTokenType.SELECT:
- case SparqlTokenType.CONSTRUCT:
- case SparqlTokenType.DESCRIBE:
- case SparqlTokenType.ASK:
- throw get_error ("SELECT, CONSTRUCT, DESCRIBE, and ASK are not supported in update mode");
- default:
- throw get_error ("expected INSERT or DELETE");
- }
+ throw get_error ("expected INSERT or DELETE");
}
-
- return null;
}
+
+ return blank_nodes;
}
DBResultSet? exec_sql (string sql) throws Error {
@@ -798,25 +846,27 @@ public class Tracker.SparqlQuery : Object {
}
}
- void execute_insert () throws Error {
+ PtrArray? execute_insert (bool blank) throws Error {
expect (SparqlTokenType.INSERT);
if (accept (SparqlTokenType.INTO)) {
parse_from_or_into_param ();
- } else
+ } else {
current_graph = null;
- execute_update (false);
+ }
+ return execute_insert_or_delete (false, blank);
}
void execute_delete () throws Error {
expect (SparqlTokenType.DELETE);
if (accept (SparqlTokenType.FROM)) {
parse_from_or_into_param ();
- } else
+ } else {
current_graph = null;
- execute_update (true);
+ }
+ execute_insert_or_delete (true, false);
}
- void execute_update (bool delete_statements) throws Error {
+ PtrArray? execute_insert_or_delete (bool delete_statements, bool blank) throws Error {
// INSERT or DELETE
var pattern_sql = new StringBuilder ();
@@ -859,12 +909,19 @@ public class Tracker.SparqlQuery : Object {
this.delete_statements = delete_statements;
+ PtrArray update_blank_nodes = null;
+
+ if (blank) {
+ update_blank_nodes = new PtrArray ();
+ }
+
// iterate over all solutions
if (result_set != null) {
do {
// blank nodes in construct templates are per solution
uuid_generate (base_uuid);
+ blank_nodes = new HashTable<string,string>.full (str_hash, str_equal, g_free, g_free);
// get values of all variables to be bound
var var_value_map = new HashTable<string,string>.full (str_hash, str_equal, g_free, g_free);
@@ -879,6 +936,11 @@ public class Tracker.SparqlQuery : Object {
// iterate over each triple in the template
parse_construct_triples_block (var_value_map);
+
+ if (blank) {
+ HashTable<string,string>* ptr = (owned) blank_nodes;
+ update_blank_nodes.add (ptr);
+ }
} while (result_set.iter_next ());
}
@@ -888,6 +950,8 @@ public class Tracker.SparqlQuery : Object {
// ensure possible WHERE clause in next part gets the correct results
Data.update_buffer_flush ();
bindings = null;
+
+ return update_blank_nodes;
}
void execute_drop_graph () throws Error {
diff --git a/src/tracker-store/tracker-resources.c b/src/tracker-store/tracker-resources.c
index 57833b1..caa8d2c 100644
--- a/src/tracker-store/tracker-resources.c
+++ b/src/tracker-store/tracker-resources.c
@@ -250,6 +250,44 @@ tracker_resources_sparql_update (TrackerResources *self,
tracker_dbus_request_success (request_id);
}
+void
+tracker_resources_sparql_update_blank (TrackerResources *self,
+ const gchar *update,
+ DBusGMethodInvocation *context,
+ GError **error)
+{
+ TrackerResourcesPrivate *priv;
+ GError *actual_error = NULL;
+ guint request_id;
+ GPtrArray *blank_nodes;
+
+ priv = TRACKER_RESOURCES_GET_PRIVATE (self);
+
+ request_id = tracker_dbus_get_next_request_id ();
+
+ tracker_dbus_async_return_if_fail (update != NULL, context);
+
+ tracker_dbus_request_new (request_id,
+ "D-Bus request for SPARQL Update, "
+ "update:'%s'",
+ update);
+
+ blank_nodes = tracker_store_sparql_update_blank (update, &actual_error);
+
+ if (actual_error) {
+ tracker_dbus_request_failed (request_id,
+ &actual_error,
+ NULL);
+ dbus_g_method_return_error (context, actual_error);
+ g_error_free (actual_error);
+ return;
+ }
+
+ dbus_g_method_return (context, blank_nodes);
+
+ tracker_dbus_request_success (request_id);
+}
+
static void
batch_update_callback (GError *error, gpointer user_data)
{
diff --git a/src/tracker-store/tracker-resources.h b/src/tracker-store/tracker-resources.h
index aa135d7..8368e48 100644
--- a/src/tracker-store/tracker-resources.h
+++ b/src/tracker-store/tracker-resources.h
@@ -68,6 +68,10 @@ void tracker_resources_sparql_update (TrackerResources
const gchar *update,
DBusGMethodInvocation *context,
GError **error);
+void tracker_resources_sparql_update_blank (TrackerResources *object,
+ const gchar *update,
+ DBusGMethodInvocation *context,
+ GError **error);
void tracker_resources_batch_sparql_update (TrackerResources *object,
const gchar *update,
DBusGMethodInvocation *context,
diff --git a/src/tracker-store/tracker-store.c b/src/tracker-store/tracker-store.c
index 0daca68..72e530e 100644
--- a/src/tracker-store/tracker-store.c
+++ b/src/tracker-store/tracker-store.c
@@ -536,6 +536,36 @@ tracker_store_sparql_update (const gchar *sparql,
}
+GPtrArray *
+tracker_store_sparql_update_blank (const gchar *sparql,
+ GError **error)
+{
+ TrackerStorePrivate *private;
+ GPtrArray *blank_nodes;
+
+ g_return_val_if_fail (sparql != NULL, NULL);
+
+ private = g_static_private_get (&private_key);
+ g_return_val_if_fail (private != NULL, NULL);
+
+ if (private->batch_mode) {
+ /* commit pending batch items */
+ tracker_data_commit_transaction ();
+ private->batch_mode = FALSE;
+ private->batch_count = 0;
+ }
+
+ tracker_data_begin_transaction ();
+ blank_nodes = tracker_data_update_sparql_blank (sparql, error);
+ tracker_data_commit_transaction ();
+
+ if (private->start_log) {
+ log_to_journal (private, sparql);
+ }
+
+ return blank_nodes;
+}
+
TrackerDBResultSet*
tracker_store_sparql_query (const gchar *sparql,
GError **error)
diff --git a/src/tracker-store/tracker-store.h b/src/tracker-store/tracker-store.h
index a495800..da2b0c0 100644
--- a/src/tracker-store/tracker-store.h
+++ b/src/tracker-store/tracker-store.h
@@ -53,6 +53,8 @@ void tracker_store_queue_turtle_import (GFile *file,
GDestroyNotify destroy);
void tracker_store_sparql_update (const gchar *sparql,
GError **error);
+GPtrArray * tracker_store_sparql_update_blank (const gchar *sparql,
+ GError **error);
TrackerDBResultSet*
tracker_store_sparql_query (const gchar *sparql,
GError **error);
diff --git a/src/tracker-utils/tracker-sparql.c b/src/tracker-utils/tracker-sparql.c
index c4491bb..1c70ea5 100644
--- a/src/tracker-utils/tracker-sparql.c
+++ b/src/tracker-utils/tracker-sparql.c
@@ -393,7 +393,7 @@ main (int argc, char **argv)
if (query) {
if (G_UNLIKELY (update)) {
- tracker_resources_sparql_update (client, query, &error);
+ results = tracker_resources_sparql_update_blank (client, query, &error);
if (error) {
g_printerr ("%s, %s\n",
@@ -403,6 +403,30 @@ main (int argc, char **argv)
return FALSE;
}
+
+ if (results) {
+ GPtrArray *insert;
+ GHashTable *solution;
+ GHashTableIter iter;
+ gpointer key, value;
+ gint i, s, n;
+
+ for (i = 0; i < results->len; i++) {
+ insert = results->pdata[i];
+
+ for (s = 0; s < insert->len; s++) {
+ solution = insert->pdata[s];
+
+ g_hash_table_iter_init (&iter, solution);
+ n = 0;
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ g_print ("%s%s: %s", n > 0 ? ", " : "", (const gchar *) key, (const gchar *) value);
+ n++;
+ }
+ g_print ("\n");
+ }
+ }
+ }
} else {
results = tracker_resources_sparql_query (client, query, &error);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]