so, it seems that librdf_storage_FOO_context_add_statement functions do not check for duplicates; methinks they should.
how about the following patch for "memory" and "hashes" storages?
(currently i don't care about others; maybe someone else wants to fix those, or check if they actually don't have the same problem?)

also, attached a test case to reproduce the problem.

michael


--
"The use of four-letter words like goto can occasionally be justified
 even in the best of company." -- Donald E. Knuth
diff -ru redland-1.0.7/librdf/rdf_storage_hashes.c redland-1.0.7-contextdup/librdf/rdf_storage_hashes.c
--- redland-1.0.7/librdf/rdf_storage_hashes.c	Thu Dec 20 22:39:42 2007
+++ redland-1.0.7-contextdup/librdf/rdf_storage_hashes.c	Mon Apr 28 13:13:18 2008
@@ -1389,6 +1389,66 @@
                                                     LIBRDF_STATEMENT_OBJECT);
 }
 
+
+/* return -1 on failure, 1 if context contains stmt, 0 if not */
+static int
+librdf_storage_hashes_context_contains_statement(librdf_storage* storage,
+    librdf_node* context_node,
+    librdf_statement* statement)
+{
+  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
+  librdf_hash_datum key, value; /* on stack - not allocated */
+  size_t size;
+  int status;
+
+  if(context->contexts_index < 0) {
+    librdf_log(storage->world, 0, LIBRDF_LOG_WARN, LIBRDF_FROM_STORAGE, NULL,
+               "Storage was created without context support");
+    return -1;
+  }
+
+  /* ENCODE KEY */
+  size=librdf_node_encode(context_node, NULL, 0);
+  if (!size)
+    return -1;
+  key.data=(char*)LIBRDF_MALLOC(cstring, size);
+  if (!key.data)
+    return -1;
+  key.size=librdf_node_encode(context_node,
+                               (unsigned char*)key.data, size);
+  if (!key.size) {
+    LIBRDF_FREE(data, key.data);
+    return -1;
+  }
+
+  /* ENCODE VALUE */
+  size=librdf_statement_encode(statement, NULL, 0);
+  if (!size) {
+    LIBRDF_FREE(data, key.data);
+    return -1;
+  }
+  value.data=(char*)LIBRDF_MALLOC(cstring, size);
+  if (!value.data) {
+    LIBRDF_FREE(data, key.data);
+    return -1;
+  }
+  value.size=librdf_statement_encode(statement, (unsigned char*)value.data, size);
+  if (!value.size) {
+    LIBRDF_FREE(data, value.data);
+    LIBRDF_FREE(data, key.data);
+    return -1;
+  }
+
+  status=librdf_hash_exists(context->hashes[context->contexts_index], &key, &value);
+  LIBRDF_FREE(data, value.data);
+  LIBRDF_FREE(data, key.data);
+
+  /* DO NOT free statement, ownership was not passed in */
+  return status;
+}
+
+
+
 /**
  * librdf_storage_hashes_context_add_statement:
  * @storage: #librdf_storage object
@@ -1414,7 +1474,15 @@
                "Storage was created without context support");
     return 1;
   }
-  
+
+  /* Do not add duplicate statements */
+  status=librdf_storage_hashes_context_contains_statement(storage, context_node, statement);
+  if(status)
+    if(status < 0)
+      return 1;
+    else
+      return 0;
+
   if(librdf_storage_hashes_add_remove_statement(storage, 
                                                 statement, context_node, 1))
     return 1;
diff -ru redland-1.0.7/librdf/rdf_storage_list.c redland-1.0.7-contextdup/librdf/rdf_storage_list.c
--- redland-1.0.7/librdf/rdf_storage_list.c	Thu Dec 20 22:39:42 2007
+++ redland-1.0.7-contextdup/librdf/rdf_storage_list.c	Mon Apr 28 13:13:10 2008
@@ -459,6 +459,64 @@
 }
 
 
+/* return -1 on failure, 1 if context contains stmt, 0 if not */
+static int
+librdf_storage_list_context_contains_statement(librdf_storage* storage,
+    librdf_node* context_node,
+    librdf_statement* statement)
+{
+  librdf_storage_list_context* context=(librdf_storage_list_context*)storage->context;
+  librdf_hash_datum key, value; /* on stack - not allocated */
+  size_t size;
+  int status;
+
+  if(!context->index_contexts) {
+    librdf_log(storage->world, 0, LIBRDF_LOG_WARN, LIBRDF_FROM_STORAGE, NULL,
+               "Storage was created without context support");
+    return -1;
+  }
+
+  /* ENCODE KEY */
+  size=librdf_node_encode(context_node, NULL, 0);
+  if (!size)
+    return -1;
+  key.data=(char*)LIBRDF_MALLOC(cstring, size);
+  if (!key.data)
+    return -1;
+  key.size=librdf_node_encode(context_node,
+                               (unsigned char*)key.data, size);
+  if (!key.size) {
+    LIBRDF_FREE(data, key.data);
+    return -1;
+  }
+
+  /* ENCODE VALUE */
+  size=librdf_statement_encode(statement, NULL, 0);
+  if (!size) {
+    LIBRDF_FREE(data, key.data);
+    return -1;
+  }
+  value.data=(char*)LIBRDF_MALLOC(cstring, size);
+  if (!value.data) {
+    LIBRDF_FREE(data, key.data);
+    return -1;
+  }
+  value.size=librdf_statement_encode(statement, (unsigned char*)value.data, size);
+  if (!value.size) {
+    LIBRDF_FREE(data, value.data);
+    LIBRDF_FREE(data, key.data);
+    return -1;
+  }
+
+  status=librdf_hash_exists(context->contexts, &key, &value);
+  LIBRDF_FREE(data, value.data);
+  LIBRDF_FREE(data, key.data);
+
+  /* DO NOT free statement, ownership was not passed in */
+  return status;
+}
+
+
 /**
  * librdf_storage_list_context_add_statement:
  * @storage: #librdf_storage object
@@ -485,7 +543,15 @@
                "Storage was created without context support");
     return 1;
   }
-  
+
+  /* Do not add duplicate statements */
+  status=librdf_storage_list_context_contains_statement(storage, context_node, statement);
+  if(status)
+    if(status < 0)
+      return 1;
+    else
+      return 0;
+
   /* Store statement + node in the storage_list */
   sln=(librdf_storage_list_node*)LIBRDF_MALLOC(librdf_storage_list_node, sizeof(librdf_storage_list_node));
   if(!sln)

#include <librdf.h>

int main()
{
    librdf_world *pWorld = librdf_new_world();
    librdf_world_open(pWorld);
    librdf_storage *pStorage = librdf_new_storage(pWorld,
//        "memory", NULL, "contexts='yes'");
        "hashes", NULL, "contexts='yes',hash-type='memory'");
    librdf_model *pModel = librdf_new_model(pWorld, pStorage, NULL);
    librdf_node *pContext = librdf_new_node_from_uri_string(pWorld,
        (const unsigned char*) ("uri:context"));
    librdf_node *pFoo = librdf_new_node_from_uri_string(pWorld,
        (const unsigned char*) ("uri:foo"));
    librdf_node *pBar = librdf_new_node_from_uri_string(pWorld,
        (const unsigned char*) ("uri:bar"));
    librdf_node *pBaz = librdf_new_node_from_uri_string(pWorld,
        (const unsigned char*) ("uri:baz"));

    librdf_statement *pStatement =
        librdf_new_statement_from_nodes(pWorld, pFoo, pBar, pBaz);
    librdf_model_context_add_statement(pModel, pContext, pStatement);
    librdf_model_context_add_statement(pModel, pContext, pStatement);
    librdf_model_context_add_statement(pModel, pContext, pStatement);

    librdf_stream *pStream = librdf_model_context_as_stream(pModel, pContext);
    librdf_serializer *pSerializer =
        librdf_new_serializer(pWorld, "rdfxml", NULL, NULL);
    librdf_serializer_serialize_stream_to_file_handle(pSerializer,
        stdout, NULL, pStream);

    return 0;
}

_______________________________________________
redland-dev mailing list
[email protected]
http://lists.librdf.org/mailman/listinfo/redland-dev

Reply via email to