Updating the Store with Blank Nodes

The majority of the work here is already described in the previous example where we talk about how to write the store.

The difference with this example is that sometimes you want to insert data and have the URNs returned which were created to avoid re-querying for them. This is done using the tracker_sparql_connection_update_blank function (or asynchronously tracker_sparql_connection_update_blank_async). If launched asynchronously, the result of the operation can be obtained with tracker_sparql_connection_update_blank_finish.

The _:foo in the example is how a blank node is represented in SPARQL. The foo part is used to generate the unique ID that is used for the new URN. It is also used in the GVariant that is returned. In the example below, we are creating a new blank node called foo for every class that exists.

The format of the GVariant (in D-Bus terms) is an aaa{ss} (an array of an array of dictionaries). This is rather complex but for a good reason. The first array represents each INSERT that may exist in the SPARQL. The second array represents each new node for a given WHERE clause (the example below illustrates this), you need this to differentiate between two INSERT statments like the one below in the same SPARQL sent to the store. Last, we have a final array to represent each new node's name (in this case foo) and the actual URN which was created. For most updates the first two outer arrays will only have one item in them.

The following program shows how a synchronous blank node update can be done to the store:

#include <tracker-sparql.h>

int main (int argc, const char **argv)
{
  GError *error = NULL;
  GVariant *v;
  TrackerSparqlConnection *connection;
  const gchar *query =
    "INSERT { _:foo a nie:InformationElement } WHERE { ?x a rdfs:Class }";

  /* Do NOT get a direct connection if you're going to do some write
   * operation in the Store. The NULL represents a possible
   * GCancellable.
   */
  connection = tracker_sparql_connection_get (NULL, &error);
  if (!connection) {
    g_printerr ("Couldn't obtain a connection to the Tracker store: %s",
                error ? error->message : "unknown error");
    g_clear_error (&error);

    return 1;
  }

  /* Run a synchronous blank node update query */
  v = tracker_sparql_connection_update_blank (connection,
  				              query,
  				              G_PRIORITY_DEFAULT,
  				              NULL,
  				              &error);

  if (error) {
    /* Some error happened performing the query, not good */
    g_printerr ("Couldn't update the Tracker store: %s",
                error ? error->message : "unknown error");

    g_clear_error (&error);
    g_object_unref (connection);

    return 1;
  }

  if (!v) {
    g_print ("No results were returned\n");
  } else {
    GVariantIter iter1, *iter2, *iter3;
    const gchar *node;
    const gchar *urn;

    g_print ("Results:\n");

    g_variant_iter_init (&iter1, v);
    while (g_variant_iter_loop (&iter1, "aa{ss}", &iter2)) { /* aa{ss} */
      while (g_variant_iter_loop (iter2, "a{ss}", &iter3)) { /* a{ss} */
        while (g_variant_iter_loop (iter3, "{ss}", &node, &urn)) { /* {ss} */
	  g_print ("  Node:'%s', URN:'%s'\n", node, urn);
	}
      }
    }

    g_variant_unref (v);
  }

  g_object_unref (connection);

  return 0;
}