mirror of
				https://github.com/cookiengineer/audacity
				synced 2025-11-04 08:04:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1905 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1905 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* -*- Mode: c; c-basic-offset: 2 -*-
 | 
						|
 *
 | 
						|
 * rdf_storage_hashes.c - RDF Storage as Hashes Implementation
 | 
						|
 *
 | 
						|
 * Copyright (C) 2000-2008, David Beckett http://www.dajobe.org/
 | 
						|
 * Copyright (C) 2000-2004, University of Bristol, UK http://www.bristol.ac.uk/
 | 
						|
 * 
 | 
						|
 * This package is Free Software and part of Redland http://librdf.org/
 | 
						|
 * 
 | 
						|
 * It is licensed under the following three licenses as alternatives:
 | 
						|
 *   1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
 | 
						|
 *   2. GNU General Public License (GPL) V2 or any newer version
 | 
						|
 *   3. Apache License, V2.0 or any newer version
 | 
						|
 * 
 | 
						|
 * You may not use this file except in compliance with at least one of
 | 
						|
 * the above three licenses.
 | 
						|
 * 
 | 
						|
 * See LICENSE.html or LICENSE.txt at the top of this package for the
 | 
						|
 * complete terms and further detail along with the license texts for
 | 
						|
 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
 | 
						|
 * 
 | 
						|
 * 
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#ifdef HAVE_CONFIG_H
 | 
						|
#include <rdf_config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef WIN32
 | 
						|
#include <win32_rdf_config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#ifdef HAVE_STDLIB_H
 | 
						|
#include <stdlib.h> /* for abort() as used in errors */
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#include <redland.h>
 | 
						|
#include <rdf_storage.h>
 | 
						|
 | 
						|
 | 
						|
typedef struct 
 | 
						|
{
 | 
						|
  const char *name;
 | 
						|
  int key_fields; /* OR of LIBRDF_STATEMENT_* fields defined in rdf_statement.h */
 | 
						|
  int value_fields; /* ditto */
 | 
						|
} librdf_hash_descriptor;
 | 
						|
 | 
						|
 | 
						|
static const librdf_hash_descriptor librdf_storage_hashes_descriptions[]= {
 | 
						|
  {"sp2o",
 | 
						|
   LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_PREDICATE,
 | 
						|
   LIBRDF_STATEMENT_OBJECT},  /* For 'get targets' */
 | 
						|
  {"po2s",
 | 
						|
   LIBRDF_STATEMENT_PREDICATE|LIBRDF_STATEMENT_OBJECT,
 | 
						|
   LIBRDF_STATEMENT_SUBJECT},  /* For 'get sources' */
 | 
						|
  {"so2p", 
 | 
						|
   LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_OBJECT,
 | 
						|
   LIBRDF_STATEMENT_PREDICATE},  /* For 'get arcs' */
 | 
						|
  {"p2so", 
 | 
						|
   LIBRDF_STATEMENT_PREDICATE,
 | 
						|
   LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_OBJECT},  /* For '(?, p, ?)' */
 | 
						|
  {"contexts",
 | 
						|
   0L, /* for contexts - do not touch when storing statements! */
 | 
						|
   0L},
 | 
						|
  {NULL,0L,0L}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
static const librdf_hash_descriptor*
 | 
						|
librdf_storage_get_hash_description_by_name(const char *name) 
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  const librdf_hash_descriptor *d;
 | 
						|
  
 | 
						|
  for(i=0; (d=&librdf_storage_hashes_descriptions[i]); i++) {
 | 
						|
    if(!d->name)
 | 
						|
      return NULL;
 | 
						|
    
 | 
						|
    if(!strcmp(d->name, name))
 | 
						|
      return d;
 | 
						|
  }
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
  /* from init() argument */
 | 
						|
  char         *name;
 | 
						|
  /* from options decoded from options hash during init() */
 | 
						|
  char         *hash_type;
 | 
						|
  char         *db_dir;
 | 
						|
  char         *indexes;
 | 
						|
  int           mode;
 | 
						|
  int           is_writable;
 | 
						|
  int           is_new;
 | 
						|
  librdf_hash  *options;     /* remaining options for hash open method */
 | 
						|
 | 
						|
  /* internals */
 | 
						|
  int                      hash_count; /* how many hashes are present? */
 | 
						|
  /* The following are allocated arrays of size hash_count */
 | 
						|
  librdf_hash**            hashes;
 | 
						|
  librdf_hash_descriptor** hash_descriptions;
 | 
						|
  char**                   names;       /* hash names for hash open method */
 | 
						|
 | 
						|
  int sources_index;
 | 
						|
  int arcs_index;
 | 
						|
  int targets_index;
 | 
						|
 | 
						|
  int p2so_index;
 | 
						|
 | 
						|
  /* If this is non-0, contexts are being used */
 | 
						|
  int index_contexts;
 | 
						|
  int contexts_index;
 | 
						|
 | 
						|
  int all_statements_hash_index;
 | 
						|
 | 
						|
  /* growing buffers used to en/decode keys/values */
 | 
						|
  unsigned char *key_buffer;
 | 
						|
  size_t key_buffer_len;
 | 
						|
  unsigned char *value_buffer;
 | 
						|
  size_t value_buffer_len;
 | 
						|
} librdf_storage_hashes_context;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* helper function for implementing init and clone methods */
 | 
						|
static int librdf_storage_hashes_register(librdf_storage *storage, const char *name, const librdf_hash_descriptor *source_desc);
 | 
						|
static int librdf_storage_hashes_init_common(librdf_storage* storage, const char *name, char *hash_type, char *db_dir, char *indexes, int mode, int is_writable, int is_new, librdf_hash* options);
 | 
						|
 | 
						|
 | 
						|
/* prototypes for local functions */
 | 
						|
static int librdf_storage_hashes_init(librdf_storage* storage, const char *name, librdf_hash* options);
 | 
						|
static void librdf_storage_hashes_terminate(librdf_storage* storage);
 | 
						|
static int librdf_storage_hashes_clone(librdf_storage* new_storage, librdf_storage* old_storage);
 | 
						|
static int librdf_storage_hashes_open(librdf_storage* storage, librdf_model* model);
 | 
						|
static int librdf_storage_hashes_close(librdf_storage* storage);
 | 
						|
static int librdf_storage_hashes_size(librdf_storage* storage);
 | 
						|
static int librdf_storage_hashes_add_statement(librdf_storage* storage, librdf_statement* statement);
 | 
						|
static int librdf_storage_hashes_add_statements(librdf_storage* storage, librdf_stream* statement_stream);
 | 
						|
static int librdf_storage_hashes_remove_statement(librdf_storage* storage, librdf_statement* statement);
 | 
						|
static int librdf_storage_hashes_contains_statement(librdf_storage* storage, librdf_statement* statement);
 | 
						|
static librdf_stream* librdf_storage_hashes_serialise(librdf_storage* storage);
 | 
						|
static librdf_stream* librdf_storage_hashes_find_statements(librdf_storage* storage, librdf_statement* statement);
 | 
						|
static librdf_iterator* librdf_storage_hashes_find_sources(librdf_storage* storage, librdf_node* arc, librdf_node *target);
 | 
						|
static librdf_iterator* librdf_storage_hashes_find_arcs(librdf_storage* storage, librdf_node* source, librdf_node *target);
 | 
						|
static librdf_iterator* librdf_storage_hashes_find_targets(librdf_storage* storage, librdf_node* source, librdf_node *arc);
 | 
						|
 | 
						|
/* serialising implementing functions */
 | 
						|
static int librdf_storage_hashes_serialise_end_of_stream(void* context);
 | 
						|
static int librdf_storage_hashes_serialise_next_statement(void* context);
 | 
						|
static void* librdf_storage_hashes_serialise_get_statement(void* context, int flags);
 | 
						|
static void librdf_storage_hashes_serialise_finished(void* context);
 | 
						|
 | 
						|
/* context functions */
 | 
						|
static int librdf_storage_hashes_context_add_statement(librdf_storage* storage, librdf_node* context_node, librdf_statement* statement);
 | 
						|
static int librdf_storage_hashes_context_remove_statement(librdf_storage* storage, librdf_node* context_node, librdf_statement* statement);
 | 
						|
static librdf_stream* librdf_storage_hashes_context_serialise(librdf_storage* storage, librdf_node* context_node);
 | 
						|
 | 
						|
/* context list statement stream methods */
 | 
						|
static int librdf_storage_hashes_context_serialise_end_of_stream(void* context);
 | 
						|
static int librdf_storage_hashes_context_serialise_next_statement(void* context);
 | 
						|
static void* librdf_storage_hashes_context_serialise_get_statement(void* context, int flags);
 | 
						|
static void librdf_storage_hashes_context_serialise_finished(void* context);
 | 
						|
 | 
						|
static void librdf_storage_hashes_register_factory(librdf_storage_factory *factory);
 | 
						|
 | 
						|
 | 
						|
/* node iterator implementing functions for get sources, targets, arcs methods */
 | 
						|
static int librdf_storage_hashes_node_iterator_is_end(void* iterator);
 | 
						|
static int librdf_storage_hashes_node_iterator_next_method(void* iterator);
 | 
						|
static void* librdf_storage_hashes_node_iterator_get_method(void* iterator, int flags);
 | 
						|
static void librdf_storage_hashes_node_iterator_finished(void* iterator);
 | 
						|
/* common initialisation code for creating get sources, targets, arcs iterators */
 | 
						|
static librdf_iterator* librdf_storage_hashes_node_iterator_create(librdf_storage* storage, librdf_node* node1, librdf_node *node2, int hash_index, int want);
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_register(librdf_storage *storage,
 | 
						|
                               const char *name,
 | 
						|
                               const librdf_hash_descriptor *source_desc) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  int len;
 | 
						|
  char *full_name=NULL;
 | 
						|
  int hash_index;
 | 
						|
  librdf_hash_descriptor *desc=(librdf_hash_descriptor*)LIBRDF_MALLOC(librdf_hash_descriptor, sizeof(librdf_hash_descriptor));
 | 
						|
  
 | 
						|
  if(!desc)
 | 
						|
    return 1;
 | 
						|
    
 | 
						|
  memcpy(desc, source_desc, sizeof(librdf_hash_descriptor));
 | 
						|
 | 
						|
  hash_index=context->hash_count++;
 | 
						|
  
 | 
						|
  context->hash_descriptions[hash_index]=desc;
 | 
						|
    
 | 
						|
  if(name) {
 | 
						|
    len=strlen(desc->name) + 1 + strlen(name) + 1; /* "%s-%s\0" */
 | 
						|
    if(context->db_dir)
 | 
						|
      len+=strlen(context->db_dir) +1;
 | 
						|
    
 | 
						|
    full_name=(char*)LIBRDF_MALLOC(cstring, len);
 | 
						|
    if(!full_name)
 | 
						|
      return 1;
 | 
						|
 | 
						|
    /* FIXME: Implies Unix filenames */
 | 
						|
    if(context->db_dir)
 | 
						|
      sprintf(full_name, "%s/%s-%s", context->db_dir, name, desc->name);
 | 
						|
    else
 | 
						|
      sprintf(full_name, "%s-%s", name, desc->name);
 | 
						|
  }
 | 
						|
  
 | 
						|
  context->hashes[hash_index]=librdf_new_hash(storage->world, 
 | 
						|
                                              context->hash_type);
 | 
						|
  context->names[hash_index]=full_name;
 | 
						|
 | 
						|
  return (context->hashes[hash_index] == NULL);
 | 
						|
}
 | 
						|
 | 
						|
/* helper function for implementing init and clone methods */
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_init_common(librdf_storage* storage, const char *name,
 | 
						|
                                  char *hash_type, char *db_dir,
 | 
						|
                                  char *indexes,
 | 
						|
                                  int mode, int is_writable, int is_new,
 | 
						|
                                  librdf_hash* options)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  int i;
 | 
						|
  int status=0;
 | 
						|
  int index_predicates=0;
 | 
						|
  int index_contexts=0;
 | 
						|
  int hash_count=0;
 | 
						|
  
 | 
						|
  context->name=(char*)name;
 | 
						|
  
 | 
						|
  context->hash_type=hash_type;
 | 
						|
  context->db_dir=db_dir;
 | 
						|
  context->indexes=indexes;
 | 
						|
 | 
						|
  context->mode=mode;
 | 
						|
  context->is_writable=is_writable;
 | 
						|
  context->is_new=is_new;
 | 
						|
  context->options=options;
 | 
						|
 | 
						|
  /* Work out the number of hashes for allocating stuff below */
 | 
						|
  hash_count=3;
 | 
						|
 | 
						|
  if((index_contexts=librdf_hash_get_as_boolean(options, "contexts"))<0)
 | 
						|
    index_contexts=0; /* default is no contexts */
 | 
						|
  context->index_contexts=index_contexts;
 | 
						|
 | 
						|
  if(index_contexts)
 | 
						|
    hash_count++;
 | 
						|
 | 
						|
  if((index_predicates=librdf_hash_get_as_boolean(options, "index-predicates"))<0)
 | 
						|
    index_predicates=0; /* default is NO index on properties */
 | 
						|
  
 | 
						|
  if(index_predicates)
 | 
						|
    hash_count++;
 | 
						|
 | 
						|
 | 
						|
  /* Start allocating the arrays */
 | 
						|
  context->hashes=(librdf_hash**)LIBRDF_CALLOC(librdf_hash, hash_count, sizeof(librdf_hash*));
 | 
						|
  if(!context->hashes) {
 | 
						|
    if(context->name)
 | 
						|
      LIBRDF_FREE(cstring, context->name);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  context->hash_descriptions=(librdf_hash_descriptor**)LIBRDF_CALLOC(librdf_hash_descriptor, hash_count, sizeof(librdf_hash_descriptor*));
 | 
						|
  if(!context->hash_descriptions) {
 | 
						|
    LIBRDF_FREE(librdf_hash, context->hashes);
 | 
						|
    if(context->name)
 | 
						|
      LIBRDF_FREE(cstring, context->name);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
  
 | 
						|
  context->names=(char**)LIBRDF_CALLOC(cstring, hash_count, sizeof(char*));
 | 
						|
  if(!context->names) {
 | 
						|
    LIBRDF_FREE(librdf_hash, context->hashes);
 | 
						|
    LIBRDF_FREE(librdf_hash_descriptor, context->hash_descriptions);
 | 
						|
    if(context->name)
 | 
						|
      LIBRDF_FREE(cstring, context->name);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
  
 | 
						|
  for(i=0; i<3; i++) {
 | 
						|
    status=librdf_storage_hashes_register(storage, name,
 | 
						|
                                          &librdf_storage_hashes_descriptions[i]);
 | 
						|
    if(status)
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if(index_predicates && !status)
 | 
						|
    status=librdf_storage_hashes_register(storage, name,
 | 
						|
                                          librdf_storage_get_hash_description_by_name("p2so"));
 | 
						|
 | 
						|
  if(index_contexts && !status)
 | 
						|
    librdf_storage_hashes_register(storage, name,
 | 
						|
                                   librdf_storage_get_hash_description_by_name("contexts"));
 | 
						|
 | 
						|
 | 
						|
  /* find indexes for get targets, sources and arcs */
 | 
						|
  context->sources_index= -1;
 | 
						|
  context->arcs_index= -1;
 | 
						|
  context->targets_index= -1;
 | 
						|
  context->p2so_index= -1;
 | 
						|
  /* and index for contexts (no key or value fields) */
 | 
						|
  context->contexts_index= -1;
 | 
						|
 | 
						|
  context->all_statements_hash_index= -1;
 | 
						|
 | 
						|
  for(i=0; i<context->hash_count; i++) {
 | 
						|
    int key_fields=context->hash_descriptions[i]->key_fields;
 | 
						|
    int value_fields=context->hash_descriptions[i]->value_fields;
 | 
						|
 | 
						|
    if(context->all_statements_hash_index <0 &&
 | 
						|
       ((key_fields|value_fields)==(LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_PREDICATE|LIBRDF_STATEMENT_OBJECT))) {
 | 
						|
      context->all_statements_hash_index=i;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if(key_fields == (LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_PREDICATE) &&
 | 
						|
       value_fields == LIBRDF_STATEMENT_OBJECT) {
 | 
						|
      context->targets_index=i;
 | 
						|
    } else if(key_fields == (LIBRDF_STATEMENT_PREDICATE|LIBRDF_STATEMENT_OBJECT) &&
 | 
						|
              value_fields == LIBRDF_STATEMENT_SUBJECT) {
 | 
						|
      context->sources_index=i;
 | 
						|
    } else if(key_fields == (LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_OBJECT) &&
 | 
						|
              value_fields == LIBRDF_STATEMENT_PREDICATE) {
 | 
						|
      context->arcs_index=i;
 | 
						|
    } else if(key_fields == LIBRDF_STATEMENT_PREDICATE &&
 | 
						|
              value_fields == (LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_OBJECT)) {
 | 
						|
      context->p2so_index=i;
 | 
						|
    } else if(!key_fields || !value_fields) {
 | 
						|
       context->contexts_index=i;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* functions implementing storage api */
 | 
						|
static int
 | 
						|
librdf_storage_hashes_init(librdf_storage* storage, const char *name,
 | 
						|
                           librdf_hash* options)
 | 
						|
{
 | 
						|
  char *hash_type, *db_dir, *indexes;
 | 
						|
  int mode, is_writable, is_new;
 | 
						|
  char *name_copy=NULL;
 | 
						|
  
 | 
						|
  if(!options)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  hash_type=librdf_hash_get_del(options, "hash-type");
 | 
						|
  if(!hash_type)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  db_dir=librdf_hash_get_del(options, "dir");
 | 
						|
  
 | 
						|
  indexes=librdf_hash_get_del(options, "indexes");
 | 
						|
  
 | 
						|
  if((mode=librdf_hash_get_as_long(options, "mode"))<0)
 | 
						|
    mode=0644; /* default mode */
 | 
						|
  
 | 
						|
  if((is_writable=librdf_hash_get_as_boolean(options, "write"))<0)
 | 
						|
    is_writable=1; /* default is WRITABLE */
 | 
						|
  
 | 
						|
  if((is_new=librdf_hash_get_as_boolean(options, "new"))<0)
 | 
						|
    is_new=0; /* default is NOT NEW */
 | 
						|
 | 
						|
  if(name) {
 | 
						|
    name_copy = (char *)LIBRDF_MALLOC(cstring, strlen(name)+1);
 | 
						|
    if(!name_copy)
 | 
						|
      return 1;
 | 
						|
    strcpy(name_copy, name);
 | 
						|
  }
 | 
						|
 | 
						|
  return librdf_storage_hashes_init_common(storage, name_copy, 
 | 
						|
                                           hash_type, db_dir, indexes,
 | 
						|
                                           mode, is_writable, is_new, 
 | 
						|
                                           options);
 | 
						|
}
 | 
						|
 | 
						|
  
 | 
						|
 | 
						|
static void
 | 
						|
librdf_storage_hashes_terminate(librdf_storage* storage)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  int i;
 | 
						|
  
 | 
						|
  for(i=0; i<context->hash_count; i++) {
 | 
						|
    if(context->hash_descriptions && context->hash_descriptions[i])
 | 
						|
      LIBRDF_FREE(librdf_hash_descriptor, context->hash_descriptions[i]);
 | 
						|
    if(context->hashes && context->hashes[i])
 | 
						|
      librdf_free_hash(context->hashes[i]);
 | 
						|
    if(context->names && context->names[i])
 | 
						|
      LIBRDF_FREE(cstring,context->names[i]);
 | 
						|
  }
 | 
						|
 | 
						|
  if(context->hash_descriptions)
 | 
						|
    LIBRDF_FREE(librdf_hash_descriptor, context->hash_descriptions);
 | 
						|
 | 
						|
  if(context->hashes)
 | 
						|
    LIBRDF_FREE(librdf_hash_descriptor, context->hashes);
 | 
						|
 | 
						|
  if(context->names)
 | 
						|
    LIBRDF_FREE(cstring, context->names);
 | 
						|
 | 
						|
  if(context->options)
 | 
						|
    librdf_free_hash(context->options);
 | 
						|
 | 
						|
  if(context->hash_type)
 | 
						|
    LIBRDF_FREE(cstring, context->hash_type);
 | 
						|
 | 
						|
  if(context->db_dir)
 | 
						|
    LIBRDF_FREE(cstring, context->db_dir);
 | 
						|
 | 
						|
  if(context->indexes)
 | 
						|
    LIBRDF_FREE(cstring, context->indexes);
 | 
						|
 | 
						|
  if(context->key_buffer)
 | 
						|
    LIBRDF_FREE(data, context->key_buffer);
 | 
						|
  if(context->value_buffer)
 | 
						|
    LIBRDF_FREE(data, context->value_buffer);
 | 
						|
 | 
						|
  if(context->name)
 | 
						|
    LIBRDF_FREE(cstring, context->name);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_clone(librdf_storage* new_storage, librdf_storage* old_storage)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *old_context=(librdf_storage_hashes_context*)old_storage->context;
 | 
						|
  librdf_storage_hashes_context *new_context=(librdf_storage_hashes_context*)new_storage->context;
 | 
						|
 | 
						|
  /* Bump up old context name if any */
 | 
						|
  if(old_context->name) {  
 | 
						|
    new_context->name=librdf_heuristic_gen_name(old_context->name);
 | 
						|
    if(!new_context->name)
 | 
						|
      return 1;
 | 
						|
  }
 | 
						|
  
 | 
						|
  /* This is always a copy of an in-memory hash */
 | 
						|
  new_context->options=librdf_new_hash_from_hash(old_context->options);
 | 
						|
  if(!new_context->options) {
 | 
						|
    if(new_context->name)
 | 
						|
      LIBRDF_FREE(cstring, new_context->name);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if(librdf_storage_hashes_init_common(new_storage, new_context->name,
 | 
						|
                                       old_context->hash_type,
 | 
						|
                                       old_context->db_dir,
 | 
						|
                                       old_context->indexes,
 | 
						|
                                       old_context->mode,
 | 
						|
                                       old_context->is_writable,
 | 
						|
                                       old_context->is_new,
 | 
						|
                                       new_context->options)) {
 | 
						|
    librdf_free_hash(new_context->options);
 | 
						|
    if(new_context->name)
 | 
						|
      LIBRDF_FREE(cstring, new_context->name);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_open(librdf_storage* storage, librdf_model* model)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  int i;
 | 
						|
  int result=0;
 | 
						|
  
 | 
						|
  for(i=0; i<context->hash_count; i++) {
 | 
						|
    librdf_hash *hash=context->hashes[i];
 | 
						|
 | 
						|
    if(!hash ||
 | 
						|
       librdf_hash_open(hash, context->names[i], 
 | 
						|
                        context->mode, context->is_writable, context->is_new,
 | 
						|
                        context->options)) {
 | 
						|
      /* I still have my "Structured Fortran" book */
 | 
						|
      int j;
 | 
						|
      for (j=0; j<i; j++) {
 | 
						|
        librdf_hash_close(context->hashes[j]);
 | 
						|
        context->hashes[j]=NULL;
 | 
						|
      }
 | 
						|
      
 | 
						|
      result=1;
 | 
						|
    }
 | 
						|
 | 
						|
    if(result)
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * librdf_storage_hashes_close:
 | 
						|
 * @storage: 
 | 
						|
 *
 | 
						|
 * .
 | 
						|
 * 
 | 
						|
 * Close the storage hashes storage, and free all content since there is no 
 | 
						|
 * persistance.
 | 
						|
 * 
 | 
						|
 * Return value: non 0 on failure
 | 
						|
 **/
 | 
						|
static int
 | 
						|
librdf_storage_hashes_close(librdf_storage* storage)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  int i;
 | 
						|
  
 | 
						|
  for(i=0; i<context->hash_count; i++) {
 | 
						|
    if(context->hashes[i])
 | 
						|
      librdf_hash_close(context->hashes[i]);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_size(librdf_storage* storage)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  librdf_hash* any_hash=context->hashes[context->all_statements_hash_index];
 | 
						|
 | 
						|
  if(!any_hash)
 | 
						|
    return -1;
 | 
						|
 | 
						|
  return librdf_hash_values_count(any_hash);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_grow_buffer(unsigned char **buffer, size_t *len,
 | 
						|
                                  size_t required_len) 
 | 
						|
{
 | 
						|
  if(required_len <= *len)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  if(*buffer)
 | 
						|
    LIBRDF_FREE(data, *buffer);
 | 
						|
  *len=required_len+8;
 | 
						|
  *buffer=(unsigned char*)LIBRDF_MALLOC(data, *len);
 | 
						|
  if(!*buffer)
 | 
						|
    *len=0;
 | 
						|
  return (*len < required_len);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_add_remove_statement(librdf_storage* storage, 
 | 
						|
                                           librdf_statement* statement,
 | 
						|
                                           librdf_node* context_node,
 | 
						|
                                           int is_addition)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  int i;
 | 
						|
  int status=0;
 | 
						|
 | 
						|
#if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
 | 
						|
  if(is_addition)
 | 
						|
    LIBRDF_DEBUG1("Adding statement: ");
 | 
						|
  else
 | 
						|
    LIBRDF_DEBUG1("Removing statement: ");
 | 
						|
  librdf_statement_print(statement, stderr);
 | 
						|
  fputc('\n', stderr);
 | 
						|
#endif  
 | 
						|
 | 
						|
  for(i=0; i<context->hash_count; i++) {
 | 
						|
    librdf_hash_datum hd_key, hd_value; /* on stack */
 | 
						|
    int key_len, value_len;
 | 
						|
 | 
						|
    /* ENCODE KEY */
 | 
						|
 | 
						|
    librdf_statement_part fields=(librdf_statement_part)context->hash_descriptions[i]->key_fields;
 | 
						|
    if(!fields)
 | 
						|
      continue;
 | 
						|
    
 | 
						|
    key_len=librdf_statement_encode_parts(statement, NULL, NULL, 0, fields);
 | 
						|
    if(!key_len)
 | 
						|
      return 1;
 | 
						|
    if(librdf_storage_hashes_grow_buffer(&context->key_buffer, 
 | 
						|
                                         &context->key_buffer_len, key_len)) {
 | 
						|
      status=1;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
       
 | 
						|
    if(!librdf_statement_encode_parts(statement, NULL,
 | 
						|
                                      context->key_buffer,
 | 
						|
                                      context->key_buffer_len, fields)) {
 | 
						|
      status=1;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    
 | 
						|
    /* ENCODE VALUE */
 | 
						|
    
 | 
						|
    fields=(librdf_statement_part)context->hash_descriptions[i]->value_fields;
 | 
						|
    if(!fields)
 | 
						|
      continue;
 | 
						|
    
 | 
						|
    value_len=librdf_statement_encode_parts(statement, context_node,
 | 
						|
                                            NULL, 0, fields);
 | 
						|
    if(!value_len) {
 | 
						|
      status=1;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if(librdf_storage_hashes_grow_buffer(&context->value_buffer, 
 | 
						|
                                         &context->value_buffer_len, value_len)) {
 | 
						|
      status=1;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
       
 | 
						|
    if(!librdf_statement_encode_parts(statement, context_node,
 | 
						|
                                      context->value_buffer,
 | 
						|
                                      context->value_buffer_len, fields)) {
 | 
						|
      status=1;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
#if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
 | 
						|
    LIBRDF_DEBUG4("Using %s hash key %d bytes -> value %d bytes\n", context->hash_descriptions[i]->name, key_len, value_len);
 | 
						|
#endif
 | 
						|
 | 
						|
    /* Finally, store / remove the sucker */
 | 
						|
    hd_key.data=context->key_buffer; hd_key.size=key_len;
 | 
						|
    hd_value.data=context->value_buffer; hd_value.size=value_len;
 | 
						|
    
 | 
						|
    if(is_addition)
 | 
						|
      status=librdf_hash_put(context->hashes[i], &hd_key, &hd_value);
 | 
						|
    else
 | 
						|
      status=librdf_hash_delete(context->hashes[i], &hd_key, &hd_value);
 | 
						|
    
 | 
						|
    if(status)
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_add_statement(librdf_storage* storage, librdf_statement* statement)
 | 
						|
{
 | 
						|
  /* Do not add duplicate statements */
 | 
						|
  if(librdf_storage_hashes_contains_statement(storage, statement))
 | 
						|
    return 0;
 | 
						|
 | 
						|
  return librdf_storage_hashes_add_remove_statement(storage, statement, NULL, 1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_add_statements(librdf_storage* storage,
 | 
						|
                                     librdf_stream* statement_stream)
 | 
						|
{
 | 
						|
  int status=0;
 | 
						|
 | 
						|
  while(!librdf_stream_end(statement_stream)) {
 | 
						|
    librdf_statement* statement=librdf_stream_get_object(statement_stream);
 | 
						|
 | 
						|
    if(statement) {
 | 
						|
      status=librdf_storage_hashes_add_statement(storage, statement);
 | 
						|
    } else
 | 
						|
      status=1;
 | 
						|
 | 
						|
    if(status)
 | 
						|
      break;
 | 
						|
 | 
						|
    librdf_stream_next(statement_stream);
 | 
						|
  }
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_remove_statement(librdf_storage* storage, librdf_statement* statement)
 | 
						|
{
 | 
						|
  return librdf_storage_hashes_add_remove_statement(storage, statement, NULL, 0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_contains_statement(librdf_storage* storage, librdf_statement* statement)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  librdf_hash_datum hd_key, hd_value; /* on stack */
 | 
						|
  unsigned char *key_buffer, *value_buffer;
 | 
						|
  int key_len, value_len;
 | 
						|
  int hash_index=context->all_statements_hash_index;
 | 
						|
  librdf_statement_part fields;
 | 
						|
  int status;
 | 
						|
  
 | 
						|
  if(storage->index_contexts) {
 | 
						|
    /* When we have contexts, we have to use find_statements for contains
 | 
						|
     * since a statement is encoded in KEY/VALUE and the VALUE may
 | 
						|
     * contain some context node.
 | 
						|
     */
 | 
						|
    librdf_stream *stream=librdf_storage_hashes_find_statements(storage, statement);
 | 
						|
    
 | 
						|
    if(!stream)
 | 
						|
      return 0;
 | 
						|
    /* librdf_stream_end returns 0 if have more, non-0 at end */
 | 
						|
    status=!librdf_stream_end(stream);
 | 
						|
    /* convert to 0 if at end (not found) and non-zero otherwise (found) */
 | 
						|
    librdf_free_stream(stream);
 | 
						|
    return status;
 | 
						|
  }
 | 
						|
 | 
						|
  /* ENCODE KEY */
 | 
						|
  fields=(librdf_statement_part)context->hash_descriptions[hash_index]->key_fields;
 | 
						|
  key_len=librdf_statement_encode_parts(statement, NULL,
 | 
						|
                                        NULL, 0, fields);
 | 
						|
  if(!key_len)
 | 
						|
    return 1;
 | 
						|
  if(!(key_buffer=(unsigned char*)LIBRDF_MALLOC(data, key_len)))
 | 
						|
    return 1;
 | 
						|
       
 | 
						|
  if(!librdf_statement_encode_parts(statement, NULL,
 | 
						|
                                    key_buffer, key_len, fields)) {
 | 
						|
    LIBRDF_FREE(data, key_buffer);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  /* ENCODE VALUE */
 | 
						|
  fields=(librdf_statement_part)context->hash_descriptions[hash_index]->value_fields;
 | 
						|
  value_len=librdf_statement_encode_parts(statement, NULL,
 | 
						|
                                          NULL, 0, fields);
 | 
						|
  if(!value_len) {
 | 
						|
    LIBRDF_FREE(data, key_buffer);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
    
 | 
						|
  if(!(value_buffer=(unsigned char*)LIBRDF_MALLOC(data, value_len))) {
 | 
						|
    LIBRDF_FREE(data, key_buffer);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
       
 | 
						|
  if(!librdf_statement_encode_parts(statement, NULL,
 | 
						|
                                    value_buffer, value_len, fields)) {
 | 
						|
    LIBRDF_FREE(data, key_buffer);
 | 
						|
    LIBRDF_FREE(data, value_buffer);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
#if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
 | 
						|
  LIBRDF_DEBUG4("Using %s hash key %d bytes -> value %d bytes\n", context->hash_descriptions[hash_index]->name, key_len, value_len);
 | 
						|
#endif
 | 
						|
 | 
						|
  hd_key.data=key_buffer; hd_key.size=key_len;
 | 
						|
  hd_value.data=value_buffer; hd_value.size=value_len;
 | 
						|
  status=librdf_hash_exists(context->hashes[hash_index], &hd_key, &hd_value);
 | 
						|
  
 | 
						|
  LIBRDF_FREE(data, key_buffer);
 | 
						|
  LIBRDF_FREE(data, value_buffer);
 | 
						|
 | 
						|
  /* DO NOT free statement, ownership was not passed in */
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  librdf_storage *storage;
 | 
						|
  librdf_storage_hashes_context *hash_context;
 | 
						|
  int index;
 | 
						|
  librdf_iterator* iterator;
 | 
						|
  librdf_hash_datum *key;
 | 
						|
  librdf_hash_datum *value;
 | 
						|
  librdf_node *search_node;
 | 
						|
  librdf_statement current; /* static, shared when search_node not used */
 | 
						|
  int index_contexts; /* true if this storage indexes contexts */
 | 
						|
  librdf_node *context_node;
 | 
						|
  int current_is_ok; /* true when current statement and context_node fresh */
 | 
						|
} librdf_storage_hashes_serialise_stream_context;
 | 
						|
 | 
						|
 | 
						|
static librdf_stream*
 | 
						|
librdf_storage_hashes_serialise_common(librdf_storage* storage, int hash_index,
 | 
						|
                                       librdf_node* search_node, int want)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  librdf_storage_hashes_serialise_stream_context *scontext;
 | 
						|
  librdf_hash *hash;
 | 
						|
  librdf_stream *stream;
 | 
						|
  
 | 
						|
  scontext=(librdf_storage_hashes_serialise_stream_context*)LIBRDF_CALLOC(librdf_storage_hashes_serialise_stream_context, 1, sizeof(librdf_storage_hashes_serialise_stream_context));
 | 
						|
  if(!scontext)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  scontext->hash_context=context;
 | 
						|
 | 
						|
  librdf_statement_init(storage->world, &scontext->current);
 | 
						|
 | 
						|
  hash=context->hashes[scontext->index];
 | 
						|
 | 
						|
  scontext->key=librdf_new_hash_datum(storage->world, NULL, 0);
 | 
						|
  if(!scontext->key)
 | 
						|
    return NULL;
 | 
						|
  
 | 
						|
  scontext->value=librdf_new_hash_datum(storage->world, NULL, 0);
 | 
						|
  if(!scontext->value) {
 | 
						|
    librdf_free_hash_datum(scontext->key);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  /* scurrent->current_is_ok=0; */
 | 
						|
  scontext->index_contexts=context->index_contexts;
 | 
						|
  
 | 
						|
  if(search_node) {
 | 
						|
    scontext->search_node=search_node;
 | 
						|
    scontext->iterator=librdf_storage_hashes_node_iterator_create(storage,
 | 
						|
                                                                  search_node,
 | 
						|
                                                                  NULL,
 | 
						|
                                                                  hash_index,
 | 
						|
                                                                  want);
 | 
						|
  } else {
 | 
						|
    scontext->iterator=librdf_hash_get_all(hash,
 | 
						|
                                           scontext->key, scontext->value);
 | 
						|
  }
 | 
						|
  if(!scontext->iterator) {
 | 
						|
    librdf_storage_hashes_serialise_finished((void*)scontext);
 | 
						|
    return librdf_new_empty_stream(storage->world);
 | 
						|
  }
 | 
						|
 | 
						|
  scontext->storage=storage;
 | 
						|
  librdf_storage_add_reference(scontext->storage);
 | 
						|
 | 
						|
  stream=librdf_new_stream(storage->world,
 | 
						|
                           (void*)scontext,
 | 
						|
                           &librdf_storage_hashes_serialise_end_of_stream,
 | 
						|
                           &librdf_storage_hashes_serialise_next_statement,
 | 
						|
                           &librdf_storage_hashes_serialise_get_statement,
 | 
						|
                           &librdf_storage_hashes_serialise_finished);
 | 
						|
  if(!stream) {
 | 
						|
    librdf_storage_hashes_serialise_finished((void*)scontext);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  
 | 
						|
  return stream;  
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static librdf_stream*
 | 
						|
librdf_storage_hashes_serialise(librdf_storage* storage)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  return librdf_storage_hashes_serialise_common(storage, 
 | 
						|
                                                context->all_statements_hash_index,
 | 
						|
                                                NULL, 0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_serialise_end_of_stream(void* context)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_serialise_stream_context* scontext=(librdf_storage_hashes_serialise_stream_context*)context;
 | 
						|
 | 
						|
  return librdf_iterator_end(scontext->iterator);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_serialise_next_statement(void* context)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_serialise_stream_context* scontext=(librdf_storage_hashes_serialise_stream_context*)context;
 | 
						|
 | 
						|
  scontext->current_is_ok=0;
 | 
						|
  return librdf_iterator_next(scontext->iterator);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void*
 | 
						|
librdf_storage_hashes_serialise_get_statement(void* context, int flags)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_serialise_stream_context* scontext=(librdf_storage_hashes_serialise_stream_context*)context;
 | 
						|
  librdf_hash_datum* hd;
 | 
						|
  librdf_node** cnp=NULL;
 | 
						|
 | 
						|
  if(scontext->search_node) {
 | 
						|
    switch(flags) {
 | 
						|
      case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT:
 | 
						|
        return librdf_iterator_get_object(scontext->iterator);
 | 
						|
      case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT:
 | 
						|
        return librdf_iterator_get_context(scontext->iterator);
 | 
						|
      default:
 | 
						|
        librdf_log(scontext->iterator->world,
 | 
						|
                   0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
                   "Unimplemented flags %d seen", flags);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
    
 | 
						|
  switch(flags) {
 | 
						|
    case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT:
 | 
						|
    case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT:
 | 
						|
 | 
						|
      if(scontext->current_is_ok) {
 | 
						|
        if(flags==LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT)
 | 
						|
          return &scontext->current;
 | 
						|
        else
 | 
						|
          return scontext->context_node;
 | 
						|
      }
 | 
						|
      
 | 
						|
      /* current stuff is out of date - get new cached answers */
 | 
						|
      if(scontext->index_contexts) {
 | 
						|
        if(scontext->context_node)
 | 
						|
          librdf_free_node(scontext->context_node);
 | 
						|
        scontext->context_node=NULL;
 | 
						|
        cnp=&scontext->context_node;
 | 
						|
      }
 | 
						|
      
 | 
						|
      librdf_statement_clear(&scontext->current);
 | 
						|
      
 | 
						|
      hd=(librdf_hash_datum*)librdf_iterator_get_key(scontext->iterator);
 | 
						|
      
 | 
						|
      /* decode key content */
 | 
						|
      if(!librdf_statement_decode_parts(&scontext->current, NULL,
 | 
						|
                                        (unsigned char*)hd->data, hd->size)) {
 | 
						|
        return NULL;
 | 
						|
      }
 | 
						|
      
 | 
						|
      hd=(librdf_hash_datum*)librdf_iterator_get_value(scontext->iterator);
 | 
						|
      
 | 
						|
      /* decode value content and optional context */
 | 
						|
      if(!librdf_statement_decode_parts(&scontext->current, cnp,
 | 
						|
                                        (unsigned char*)hd->data, hd->size)) {
 | 
						|
        return NULL;
 | 
						|
      }
 | 
						|
 | 
						|
      scontext->current_is_ok=1;
 | 
						|
 | 
						|
      if(flags==LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT)
 | 
						|
        return &scontext->current;
 | 
						|
      else
 | 
						|
        return scontext->context_node;
 | 
						|
        
 | 
						|
    default:
 | 
						|
      librdf_log(scontext->iterator->world,
 | 
						|
                 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
                 "Unimplemented flags %d seen", flags);
 | 
						|
      return NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
librdf_storage_hashes_serialise_finished(void* context)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_serialise_stream_context* scontext=(librdf_storage_hashes_serialise_stream_context*)context;
 | 
						|
 | 
						|
  if(scontext->iterator)
 | 
						|
    librdf_free_iterator(scontext->iterator);
 | 
						|
 | 
						|
  if(scontext->context_node)
 | 
						|
    librdf_free_node(scontext->context_node);
 | 
						|
      
 | 
						|
  if(scontext->key) {
 | 
						|
    scontext->key->data=NULL;
 | 
						|
    librdf_free_hash_datum(scontext->key);
 | 
						|
  }
 | 
						|
  if(scontext->value) {
 | 
						|
    scontext->value->data=NULL;
 | 
						|
    librdf_free_hash_datum(scontext->value);
 | 
						|
  }
 | 
						|
 | 
						|
  librdf_statement_clear(&scontext->current);
 | 
						|
 | 
						|
  if(scontext->storage)
 | 
						|
    librdf_storage_remove_reference(scontext->storage);
 | 
						|
 | 
						|
  LIBRDF_FREE(librdf_storage_hashes_serialise_stream_context, scontext);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * librdf_storage_hashes_find_statements:
 | 
						|
 * @storage: the storage
 | 
						|
 * @statement: the statement to match
 | 
						|
 *
 | 
						|
 * .
 | 
						|
 * 
 | 
						|
 * Return a stream of statements matching the given statement (or
 | 
						|
 * all statements if NULL).  Parts (subject, predicate, object) of the
 | 
						|
 * statement can be empty in which case any statement part will match that.
 | 
						|
 * Uses #librdf_statement_match to do the matching.
 | 
						|
 * 
 | 
						|
 * Return value: a #librdf_stream or NULL on failure
 | 
						|
 **/
 | 
						|
static librdf_stream*
 | 
						|
librdf_storage_hashes_find_statements(librdf_storage* storage, librdf_statement* statement)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  librdf_stream* stream;
 | 
						|
 | 
						|
  if(!librdf_statement_get_subject(statement) &&
 | 
						|
     librdf_statement_get_predicate(statement) &&
 | 
						|
     !librdf_statement_get_object(statement) &&
 | 
						|
     context->p2so_index >= 0) {
 | 
						|
    /* (? p ?) -> (s p o) wanted */
 | 
						|
    stream=librdf_storage_hashes_serialise_common(storage,
 | 
						|
                                                  context->p2so_index,
 | 
						|
                                                  librdf_statement_get_predicate(statement),
 | 
						|
                                                  LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_OBJECT);
 | 
						|
  } else {
 | 
						|
    statement=librdf_new_statement_from_statement(statement);
 | 
						|
    if(!statement)
 | 
						|
      return NULL;
 | 
						|
 | 
						|
    stream=librdf_storage_hashes_serialise(storage);
 | 
						|
    if(stream)
 | 
						|
      librdf_stream_add_map(stream, 
 | 
						|
                            &librdf_stream_statement_find_map,
 | 
						|
                            (librdf_stream_map_free_context_handler)&librdf_free_statement, (void*)statement);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return stream;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  librdf_storage* storage;   /* (shared) pointer to storage */
 | 
						|
  int hash_index;            /* index of hash in storage list of hashes */
 | 
						|
  librdf_iterator* iterator; /* owned iterator over above hash */
 | 
						|
  int want;                  /* part of decoded statement to return */
 | 
						|
  librdf_statement statement; /* NOTE: stored here, never allocated */
 | 
						|
  librdf_statement statement2; /* NOTE: stored here, never allocated */
 | 
						|
  librdf_hash_datum key;
 | 
						|
  librdf_hash_datum value;
 | 
						|
  librdf_node *search_node;
 | 
						|
  int index_contexts;
 | 
						|
  librdf_node *context_node;
 | 
						|
} librdf_storage_hashes_node_iterator_context;
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_node_iterator_is_end(void* iterator)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_node_iterator_context* context=(librdf_storage_hashes_node_iterator_context*)iterator;
 | 
						|
 | 
						|
  return librdf_iterator_end(context->iterator);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_node_iterator_next_method(void* iterator) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_node_iterator_context* context=(librdf_storage_hashes_node_iterator_context*)iterator;
 | 
						|
 | 
						|
  if(librdf_iterator_end(context->iterator))
 | 
						|
    return 1;
 | 
						|
 | 
						|
  return librdf_iterator_next(context->iterator);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void*
 | 
						|
librdf_storage_hashes_node_iterator_get_method(void* iterator, int flags) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_node_iterator_context* context=(librdf_storage_hashes_node_iterator_context*)iterator;
 | 
						|
  librdf_node* node;
 | 
						|
  librdf_hash_datum* value;
 | 
						|
  
 | 
						|
  if(librdf_iterator_end(context->iterator))
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  if(flags == LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT) {
 | 
						|
    /* current stuff is out of date - get new cached answers */
 | 
						|
    if(!context->index_contexts)
 | 
						|
      return NULL;
 | 
						|
 | 
						|
    value=(librdf_hash_datum*)librdf_iterator_get_value(context->iterator);
 | 
						|
      
 | 
						|
    if(context->context_node)
 | 
						|
      librdf_free_node(context->context_node);
 | 
						|
    context->context_node=NULL;
 | 
						|
      
 | 
						|
    /* decode value content and optional context */
 | 
						|
    if(!librdf_statement_decode_parts(&context->statement,
 | 
						|
                                      &context->context_node,
 | 
						|
                                      (unsigned char*)value->data, value->size))
 | 
						|
      return NULL;
 | 
						|
    librdf_statement_clear(&context->statement);
 | 
						|
    
 | 
						|
    return context->context_node;
 | 
						|
  }
 | 
						|
  
 | 
						|
  
 | 
						|
  if(flags != LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT) {
 | 
						|
    librdf_log(context->iterator->world,
 | 
						|
               0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
               "Unimplemented iterator method %d", flags);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /* get object */
 | 
						|
  switch(context->want) {
 | 
						|
    case LIBRDF_STATEMENT_SUBJECT: /* SOURCES (subjects) */
 | 
						|
      if((node=librdf_statement_get_subject(&context->statement)))
 | 
						|
         librdf_free_node(node);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case LIBRDF_STATEMENT_PREDICATE: /* ARCS (predicates) */
 | 
						|
      if((node=librdf_statement_get_predicate(&context->statement)))
 | 
						|
         librdf_free_node(node);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case LIBRDF_STATEMENT_OBJECT: /* TARGETS (objects) */
 | 
						|
      if((node=librdf_statement_get_object(&context->statement)))
 | 
						|
         librdf_free_node(node);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case (LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_OBJECT): /* p2so */
 | 
						|
      if((node=librdf_statement_get_subject(&context->statement)))
 | 
						|
         librdf_free_node(node);
 | 
						|
      if((node=librdf_statement_get_object(&context->statement)))
 | 
						|
         librdf_free_node(node);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    default: /* error */
 | 
						|
      librdf_log(context->iterator->world,
 | 
						|
                 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
                 "Illegal statement part %d seen", context->want);
 | 
						|
      return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  value=(librdf_hash_datum*)librdf_iterator_get_value(context->iterator);
 | 
						|
  if(!value)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  if(!librdf_statement_decode(&context->statement, 
 | 
						|
                              (unsigned char*)value->data,
 | 
						|
                              value->size))
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  switch(context->want) {
 | 
						|
    case LIBRDF_STATEMENT_SUBJECT: /* SOURCES (subjects) */
 | 
						|
      node=librdf_statement_get_subject(&context->statement);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case LIBRDF_STATEMENT_PREDICATE: /* ARCS (predicates) */
 | 
						|
      node=librdf_statement_get_predicate(&context->statement);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case LIBRDF_STATEMENT_OBJECT: /* TARGETS (objects) */
 | 
						|
      node=librdf_statement_get_object(&context->statement);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case (LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_OBJECT): /* p2so */
 | 
						|
      librdf_statement_set_subject(&context->statement2, librdf_statement_get_subject(&context->statement));
 | 
						|
      /* fill in the only blank from the node stored in our context */
 | 
						|
      node=librdf_new_node_from_node(context->search_node);
 | 
						|
      if(!node)
 | 
						|
        return NULL;
 | 
						|
      librdf_statement_set_predicate(&context->statement2, node);
 | 
						|
      librdf_statement_set_object(&context->statement2, librdf_statement_get_object(&context->statement));
 | 
						|
      return (void*)&context->statement2;
 | 
						|
      break;
 | 
						|
      
 | 
						|
    default: /* error */
 | 
						|
      librdf_log(context->iterator->world,
 | 
						|
                 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
                 "Illegal statement part %d seen", context->want);
 | 
						|
      return NULL;
 | 
						|
  }
 | 
						|
  
 | 
						|
  return (void*)node;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
librdf_storage_hashes_node_iterator_finished(void* iterator) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_node_iterator_context* icontext=(librdf_storage_hashes_node_iterator_context*)iterator;
 | 
						|
  librdf_node* node;
 | 
						|
  
 | 
						|
  if(icontext->search_node)
 | 
						|
    librdf_free_node(icontext->search_node);
 | 
						|
 | 
						|
  if(icontext->context_node)
 | 
						|
    librdf_free_node(icontext->context_node);
 | 
						|
 | 
						|
  if(icontext->iterator)
 | 
						|
    librdf_free_iterator(icontext->iterator);
 | 
						|
 | 
						|
  librdf_statement_clear(&icontext->statement);
 | 
						|
  if((node=librdf_statement_get_predicate(&icontext->statement2)))
 | 
						|
     librdf_free_node(node);
 | 
						|
 | 
						|
  if(icontext->storage)
 | 
						|
    librdf_storage_remove_reference(icontext->storage);
 | 
						|
  
 | 
						|
  LIBRDF_FREE(librdf_storage_hashes_node_iterator_context, icontext);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * librdf_storage_hashes_node_iterator_create - Create a node iterator for get sources, targets or arcs methods
 | 
						|
 * @storage: the storage hashes object to iterate
 | 
						|
 * @node1: the first node to encode in the key
 | 
						|
 * @node2: the second node to encode in the key
 | 
						|
 * @hash_index: the index of the hash to iterate over
 | 
						|
 * @want: the field required from the hash value
 | 
						|
 * 
 | 
						|
 * Return value: a new #librdf_iterator or NULL on failure
 | 
						|
 **/
 | 
						|
static librdf_iterator*
 | 
						|
librdf_storage_hashes_node_iterator_create(librdf_storage* storage, 
 | 
						|
                                           librdf_node* node1,
 | 
						|
                                           librdf_node *node2,
 | 
						|
                                           int hash_index,
 | 
						|
                                           int want) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *scontext=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  librdf_storage_hashes_node_iterator_context* icontext;
 | 
						|
  librdf_hash *hash;
 | 
						|
  librdf_statement_part fields;
 | 
						|
  unsigned char *key_buffer;
 | 
						|
  librdf_iterator* iterator;
 | 
						|
  
 | 
						|
  icontext=(librdf_storage_hashes_node_iterator_context*)LIBRDF_CALLOC(librdf_storage_hashes_node_iterator_context, 1, sizeof(librdf_storage_hashes_node_iterator_context));
 | 
						|
  if(!icontext)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  icontext->storage=storage;
 | 
						|
 | 
						|
  icontext->hash_index=hash_index;
 | 
						|
  icontext->want=want;
 | 
						|
 | 
						|
  icontext->index_contexts=scontext->index_contexts;
 | 
						|
 | 
						|
  node1=librdf_new_node_from_node(node1);
 | 
						|
  if(!node1) {
 | 
						|
    LIBRDF_FREE(librdf_storage_hashes_node_iterator_context, icontext);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  if(node2) {
 | 
						|
    node2=librdf_new_node_from_node(node2);
 | 
						|
    if(!node2) {
 | 
						|
      librdf_free_node(node2);
 | 
						|
      LIBRDF_FREE(librdf_storage_hashes_node_iterator_context, icontext);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  librdf_statement_init(storage->world, &icontext->statement);
 | 
						|
  librdf_statement_init(storage->world, &icontext->statement2);
 | 
						|
 | 
						|
  hash=scontext->hashes[icontext->hash_index];
 | 
						|
 | 
						|
  /* set the fields in the static statement contained in the context */
 | 
						|
  switch(icontext->want) {
 | 
						|
    case LIBRDF_STATEMENT_SUBJECT: /* SOURCES (subjects) */
 | 
						|
      librdf_statement_set_predicate(&icontext->statement, node1);
 | 
						|
      librdf_statement_set_object(&icontext->statement, node2);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case LIBRDF_STATEMENT_PREDICATE: /* PREDICATES (arcs) */
 | 
						|
      librdf_statement_set_subject(&icontext->statement, node1);
 | 
						|
      librdf_statement_set_object(&icontext->statement, node2);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case LIBRDF_STATEMENT_OBJECT: /* OBJECTS (targets) */
 | 
						|
      librdf_statement_set_subject(&icontext->statement, node1);
 | 
						|
      librdf_statement_set_predicate(&icontext->statement, node2);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case (LIBRDF_STATEMENT_SUBJECT|LIBRDF_STATEMENT_OBJECT): /* p2so */
 | 
						|
      icontext->search_node=librdf_new_node_from_node(node1);
 | 
						|
      librdf_statement_set_predicate(&icontext->statement, node1);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    default: /* error */
 | 
						|
      LIBRDF_FREE(librdf_storage_hashes_node_iterator_context, icontext);
 | 
						|
      librdf_log(storage->world,
 | 
						|
                 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
                 "Illegal statement part %d seen", want);
 | 
						|
      return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /* ENCODE KEY */
 | 
						|
  fields=(librdf_statement_part)scontext->hash_descriptions[hash_index]->key_fields;
 | 
						|
  icontext->key.size=librdf_statement_encode_parts(&icontext->statement, NULL,
 | 
						|
                                                   NULL, 0, fields);
 | 
						|
  if(!icontext->key.size) {
 | 
						|
    LIBRDF_FREE(librdf_storage_hashes_node_iterator_context, icontext);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  if(!(key_buffer=(unsigned char*)LIBRDF_MALLOC(data, icontext->key.size))) {
 | 
						|
    LIBRDF_FREE(librdf_storage_hashes_node_iterator_context, icontext);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
       
 | 
						|
  /* after this point the finished method is called on errors
 | 
						|
   * so must bump the reference count
 | 
						|
   */
 | 
						|
  librdf_storage_add_reference(icontext->storage);
 | 
						|
 | 
						|
  if(!librdf_statement_encode_parts(&icontext->statement, NULL,
 | 
						|
                                    key_buffer, icontext->key.size, fields)) {
 | 
						|
    LIBRDF_FREE(data, key_buffer);
 | 
						|
    librdf_storage_hashes_node_iterator_finished(icontext);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
    
 | 
						|
  icontext->key.data=key_buffer;
 | 
						|
 | 
						|
  icontext->iterator=librdf_hash_get_all(hash, &icontext->key, &icontext->value);
 | 
						|
  if(!icontext->iterator) {
 | 
						|
    LIBRDF_FREE(data, key_buffer);
 | 
						|
    librdf_storage_hashes_node_iterator_finished(icontext);
 | 
						|
    return librdf_new_empty_iterator(storage->world);
 | 
						|
  }
 | 
						|
 | 
						|
  LIBRDF_FREE(data, key_buffer);
 | 
						|
 | 
						|
  iterator=librdf_new_iterator(storage->world,
 | 
						|
                               (void*)icontext,
 | 
						|
                               librdf_storage_hashes_node_iterator_is_end,
 | 
						|
                               librdf_storage_hashes_node_iterator_next_method,
 | 
						|
                               librdf_storage_hashes_node_iterator_get_method,
 | 
						|
                               librdf_storage_hashes_node_iterator_finished);
 | 
						|
  if(!iterator)
 | 
						|
    librdf_storage_hashes_node_iterator_finished(icontext);
 | 
						|
  return iterator;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static librdf_iterator*
 | 
						|
librdf_storage_hashes_find_sources(librdf_storage* storage, 
 | 
						|
                                   librdf_node* arc, librdf_node *target) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *scontext=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  return librdf_storage_hashes_node_iterator_create(storage, arc, target,
 | 
						|
                                                    scontext->sources_index,
 | 
						|
                                                    LIBRDF_STATEMENT_SUBJECT);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static librdf_iterator*
 | 
						|
librdf_storage_hashes_find_arcs(librdf_storage* storage,
 | 
						|
                                librdf_node* source, librdf_node *target) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *scontext=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  return librdf_storage_hashes_node_iterator_create(storage, source, target,
 | 
						|
                                                    scontext->arcs_index,
 | 
						|
                                                    LIBRDF_STATEMENT_PREDICATE);
 | 
						|
}
 | 
						|
 | 
						|
static librdf_iterator*
 | 
						|
librdf_storage_hashes_find_targets(librdf_storage* storage,
 | 
						|
                                   librdf_node* source, librdf_node *arc) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context *scontext=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  return librdf_storage_hashes_node_iterator_create(storage, source, arc,
 | 
						|
                                                    scontext->targets_index,
 | 
						|
                                                    LIBRDF_STATEMENT_OBJECT);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * librdf_storage_hashes_context_add_statement:
 | 
						|
 * @storage: #librdf_storage object
 | 
						|
 * @context_node: #librdf_node object
 | 
						|
 * @statement: #librdf_statement statement to add
 | 
						|
 *
 | 
						|
 * Add a statement to a storage context.
 | 
						|
 * 
 | 
						|
 * Return value: non 0 on failure
 | 
						|
 **/
 | 
						|
static int
 | 
						|
librdf_storage_hashes_context_add_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 */
 | 
						|
  int 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;
 | 
						|
  }
 | 
						|
  
 | 
						|
  if(librdf_storage_hashes_add_remove_statement(storage, 
 | 
						|
                                                statement, context_node, 1))
 | 
						|
    return 1;
 | 
						|
 | 
						|
  size=librdf_node_encode(context_node, NULL, 0);
 | 
						|
  key.data=(char*)LIBRDF_MALLOC(cstring, size);
 | 
						|
  key.size=librdf_node_encode(context_node, 
 | 
						|
                               (unsigned char*)key.data, size);
 | 
						|
 | 
						|
  size=librdf_statement_encode(statement, NULL, 0);
 | 
						|
 | 
						|
  value.data=(char*)LIBRDF_MALLOC(cstring, size);
 | 
						|
  value.size=librdf_statement_encode(statement, (unsigned char*)value.data, size);
 | 
						|
 | 
						|
  status=librdf_hash_put(context->hashes[context->contexts_index], &key, &value);
 | 
						|
  LIBRDF_FREE(data, key.data);
 | 
						|
  LIBRDF_FREE(data, value.data);
 | 
						|
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * librdf_storage_hashes_context_remove_statement:
 | 
						|
 * @storage: #librdf_storage object
 | 
						|
 * @context_node: #librdf_node object
 | 
						|
 * @statement: #librdf_statement statement to remove
 | 
						|
 *
 | 
						|
 * Remove a statement from a storage context.
 | 
						|
 * 
 | 
						|
 * Return value: non 0 on failure
 | 
						|
 **/
 | 
						|
static int
 | 
						|
librdf_storage_hashes_context_remove_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 */
 | 
						|
  int size;
 | 
						|
  int status;
 | 
						|
  
 | 
						|
  if(context_node && context->contexts_index <0) {
 | 
						|
    librdf_log(storage->world, 0, LIBRDF_LOG_WARN, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
               "Storage was created without context support");
 | 
						|
  }
 | 
						|
  
 | 
						|
  if(librdf_storage_hashes_add_remove_statement(storage, 
 | 
						|
                                                statement, context_node, 0))
 | 
						|
    return 1;
 | 
						|
  
 | 
						|
  size=librdf_node_encode(context_node, NULL, 0);
 | 
						|
  key.data=(char*)LIBRDF_MALLOC(cstring, size);
 | 
						|
  key.size=librdf_node_encode(context_node,
 | 
						|
                               (unsigned char*)key.data, size);
 | 
						|
 | 
						|
  size=librdf_statement_encode(statement, NULL, 0);
 | 
						|
 | 
						|
  value.data=(char*)LIBRDF_MALLOC(cstring, size);
 | 
						|
  value.size=librdf_statement_encode(statement, (unsigned char*)value.data, size);
 | 
						|
 | 
						|
  status=librdf_hash_delete(context->hashes[context->contexts_index], &key, &value);
 | 
						|
  LIBRDF_FREE(data, key.data);
 | 
						|
  LIBRDF_FREE(data, value.data);
 | 
						|
  
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  librdf_storage *storage;
 | 
						|
  librdf_iterator* iterator;
 | 
						|
  librdf_hash_datum *key;
 | 
						|
  librdf_hash_datum *value;
 | 
						|
  librdf_statement current; /* static, shared statement */
 | 
						|
  int index_contexts; /* true if this storage indexes contexts */
 | 
						|
  librdf_node *context_node;
 | 
						|
  char *context_node_data;
 | 
						|
  int current_is_ok; /* true when current statement and context_node fresh */
 | 
						|
} librdf_storage_hashes_context_serialise_stream_context;
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * librdf_storage_hashes_context_serialise:
 | 
						|
 * @storage: #librdf_storage object
 | 
						|
 * @context_node: #librdf_node object
 | 
						|
 *
 | 
						|
 * List all statements in a storage context.
 | 
						|
 * 
 | 
						|
 * Return value: #librdf_stream of statements or NULL on failure or context is empty
 | 
						|
 **/
 | 
						|
static librdf_stream*
 | 
						|
librdf_storage_hashes_context_serialise(librdf_storage* storage,
 | 
						|
                                        librdf_node* context_node) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  librdf_storage_hashes_context_serialise_stream_context* scontext;
 | 
						|
  librdf_stream* stream;
 | 
						|
  size_t size;
 | 
						|
 | 
						|
  if(context->contexts_index <0) {
 | 
						|
    librdf_log(storage->world, 0, LIBRDF_LOG_WARN, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
               "Storage was created without context support");
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  
 | 
						|
  scontext=(librdf_storage_hashes_context_serialise_stream_context*)LIBRDF_CALLOC(librdf_storage_hashes_context_serialise_stream_context, 1, sizeof(librdf_storage_hashes_context_serialise_stream_context));
 | 
						|
  if(!scontext)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  librdf_statement_init(storage->world, &scontext->current);
 | 
						|
 | 
						|
  scontext->key=librdf_new_hash_datum(storage->world, NULL, 0);
 | 
						|
  if(!scontext->key)
 | 
						|
    return NULL;
 | 
						|
  
 | 
						|
  scontext->value=librdf_new_hash_datum(storage->world, NULL, 0);
 | 
						|
  if(!scontext->value) {
 | 
						|
    librdf_free_hash_datum(scontext->key);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  /* scurrent->current_is_ok=0; */
 | 
						|
  scontext->index_contexts=context->index_contexts;
 | 
						|
  scontext->context_node=librdf_new_node_from_node(context_node);
 | 
						|
 | 
						|
  size=librdf_node_encode(context_node, NULL, 0);
 | 
						|
  scontext->key->data=scontext->context_node_data=(char*)LIBRDF_MALLOC(cstring, size);
 | 
						|
  scontext->key->size=librdf_node_encode(context_node,
 | 
						|
                                         (unsigned char*)scontext->key->data,
 | 
						|
                                         size);
 | 
						|
 | 
						|
  scontext->iterator=librdf_hash_get_all(context->hashes[context->contexts_index], 
 | 
						|
                                         scontext->key, scontext->value);
 | 
						|
  if(!scontext->iterator)
 | 
						|
    return librdf_new_empty_stream(storage->world);
 | 
						|
 | 
						|
 | 
						|
  scontext->storage=storage;
 | 
						|
  librdf_storage_add_reference(scontext->storage);
 | 
						|
 | 
						|
  stream=librdf_new_stream(storage->world,
 | 
						|
                           (void*)scontext,
 | 
						|
                           &librdf_storage_hashes_context_serialise_end_of_stream,
 | 
						|
                           &librdf_storage_hashes_context_serialise_next_statement,
 | 
						|
                           &librdf_storage_hashes_context_serialise_get_statement,
 | 
						|
                           &librdf_storage_hashes_context_serialise_finished);
 | 
						|
  if(!stream) {
 | 
						|
    librdf_storage_hashes_context_serialise_finished((void*)scontext);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  
 | 
						|
  return stream;  
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_context_serialise_end_of_stream(void* context)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context_serialise_stream_context* scontext=(librdf_storage_hashes_context_serialise_stream_context*)context;
 | 
						|
 | 
						|
  return librdf_iterator_end(scontext->iterator);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_context_serialise_next_statement(void* context)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context_serialise_stream_context* scontext=(librdf_storage_hashes_context_serialise_stream_context*)context;
 | 
						|
 | 
						|
  scontext->current_is_ok=0;
 | 
						|
  return librdf_iterator_next(scontext->iterator);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void*
 | 
						|
librdf_storage_hashes_context_serialise_get_statement(void* context, int flags)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context_serialise_stream_context* scontext=(librdf_storage_hashes_context_serialise_stream_context*)context;
 | 
						|
  librdf_hash_datum* v;
 | 
						|
  librdf_node** cnp=NULL;
 | 
						|
 | 
						|
  switch(flags) {
 | 
						|
    case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT:
 | 
						|
    case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT:
 | 
						|
 | 
						|
      if(scontext->current_is_ok) {
 | 
						|
        if(flags==LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT)
 | 
						|
          return &scontext->current;
 | 
						|
        else
 | 
						|
          return scontext->context_node;
 | 
						|
      }
 | 
						|
 | 
						|
      /* current stuff is out of date - get new cached answers */
 | 
						|
      if(scontext->index_contexts) {
 | 
						|
        if(scontext->context_node)
 | 
						|
          librdf_free_node(scontext->context_node);
 | 
						|
        scontext->context_node=NULL;
 | 
						|
        cnp=&scontext->context_node;
 | 
						|
      }
 | 
						|
      
 | 
						|
      librdf_statement_clear(&scontext->current);
 | 
						|
 | 
						|
      v=(librdf_hash_datum*)librdf_iterator_get_value(scontext->iterator);
 | 
						|
      
 | 
						|
      /* decode value content and optional context */
 | 
						|
      if(!librdf_statement_decode_parts(&scontext->current, cnp,
 | 
						|
                                        (unsigned char*)v->data, v->size)) {
 | 
						|
        return NULL;
 | 
						|
      }
 | 
						|
      
 | 
						|
      scontext->current_is_ok=1;
 | 
						|
 | 
						|
      if(flags==LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT)
 | 
						|
        return &scontext->current;
 | 
						|
      else
 | 
						|
        return scontext->context_node;
 | 
						|
 | 
						|
    default:
 | 
						|
      librdf_log(scontext->iterator->world,
 | 
						|
                 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
                 "Unimplemented flags %d seen", flags);
 | 
						|
      return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
librdf_storage_hashes_context_serialise_finished(void* context)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context_serialise_stream_context* scontext=(librdf_storage_hashes_context_serialise_stream_context*)context;
 | 
						|
  
 | 
						|
  if(scontext->context_node)
 | 
						|
    librdf_free_node(scontext->context_node);
 | 
						|
  
 | 
						|
  if(scontext->iterator)
 | 
						|
    librdf_free_iterator(scontext->iterator);
 | 
						|
 | 
						|
  if(scontext->key) {
 | 
						|
    librdf_free_hash_datum(scontext->key);
 | 
						|
  }
 | 
						|
  if(scontext->value) {
 | 
						|
    scontext->value->data=NULL;
 | 
						|
    librdf_free_hash_datum(scontext->value);
 | 
						|
  }
 | 
						|
 | 
						|
  librdf_statement_clear(&scontext->current);
 | 
						|
 | 
						|
  if(scontext->context_node_data)
 | 
						|
    LIBRDF_FREE(cstring, scontext->context_node_data);
 | 
						|
 | 
						|
  if(scontext->storage)
 | 
						|
    librdf_storage_remove_reference(scontext->storage);
 | 
						|
  
 | 
						|
  LIBRDF_FREE(librdf_storage_hashes_context_serialise_stream_context, scontext);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_sync(librdf_storage *storage)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  int i;
 | 
						|
  
 | 
						|
  for(i=0; i<context->hash_count; i++)
 | 
						|
    librdf_hash_sync(context->hashes[i]);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  librdf_storage *storage;
 | 
						|
  librdf_iterator *iterator;
 | 
						|
  librdf_hash_datum *key;
 | 
						|
  librdf_node *current;
 | 
						|
} librdf_storage_hashes_get_contexts_iterator_context;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_get_contexts_is_end(void* iterator)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_get_contexts_iterator_context* icontext=(librdf_storage_hashes_get_contexts_iterator_context*)iterator;
 | 
						|
 | 
						|
  return librdf_iterator_end(icontext->iterator);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
librdf_storage_hashes_get_contexts_next_method(void* iterator) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_get_contexts_iterator_context* icontext=(librdf_storage_hashes_get_contexts_iterator_context*)iterator;
 | 
						|
 | 
						|
  return librdf_iterator_next(icontext->iterator);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void*
 | 
						|
librdf_storage_hashes_get_contexts_get_method(void* iterator, int flags) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_get_contexts_iterator_context* icontext=(librdf_storage_hashes_get_contexts_iterator_context*)iterator;
 | 
						|
  void *result=NULL;
 | 
						|
  librdf_hash_datum* k;
 | 
						|
  
 | 
						|
  switch(flags) {
 | 
						|
    case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT:
 | 
						|
      if(!(k=(librdf_hash_datum*)librdf_iterator_get_key(icontext->iterator)))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
      if(icontext->current)
 | 
						|
        librdf_free_node(icontext->current);
 | 
						|
 | 
						|
      /* decode value content */
 | 
						|
      icontext->current=librdf_node_decode(icontext->storage->world, NULL,
 | 
						|
                                           (unsigned char*)k->data, k->size);
 | 
						|
      result=icontext->current;
 | 
						|
      break;
 | 
						|
 | 
						|
    case LIBRDF_ITERATOR_GET_METHOD_GET_KEY:
 | 
						|
    case LIBRDF_ITERATOR_GET_METHOD_GET_VALUE:
 | 
						|
      result=NULL;
 | 
						|
      break;
 | 
						|
      
 | 
						|
    default:
 | 
						|
      librdf_log(icontext->iterator->world,
 | 
						|
                 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
                 "Unknown iterator method flag %d", flags);
 | 
						|
      result=NULL;
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
librdf_storage_hashes_get_contexts_finished(void* iterator) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_get_contexts_iterator_context* icontext=(librdf_storage_hashes_get_contexts_iterator_context*)iterator;
 | 
						|
 | 
						|
  if(icontext->iterator)
 | 
						|
    librdf_free_iterator(icontext->iterator);
 | 
						|
 | 
						|
  librdf_free_hash_datum(icontext->key);
 | 
						|
  
 | 
						|
  if(icontext->current)
 | 
						|
    librdf_free_node(icontext->current);
 | 
						|
 | 
						|
  if(icontext->storage)
 | 
						|
    librdf_storage_remove_reference(icontext->storage);
 | 
						|
  
 | 
						|
  LIBRDF_FREE(librdf_storage_hashes_get_contexts_iterator_context, icontext);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * librdf_storage_hashes_context_get_contexts:
 | 
						|
 * @storage: #librdf_storage object
 | 
						|
 *
 | 
						|
 * List all context nodes in a storage.
 | 
						|
 * 
 | 
						|
 * Return value: #librdf_iterator of context_nodes or NULL on failure or no contexts
 | 
						|
 **/
 | 
						|
static librdf_iterator*
 | 
						|
librdf_storage_hashes_get_contexts(librdf_storage* storage) 
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* context=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  librdf_storage_hashes_get_contexts_iterator_context* icontext;
 | 
						|
  librdf_iterator* iterator;
 | 
						|
 | 
						|
  if(context->index_contexts <0) {
 | 
						|
    librdf_log(storage->world, 0, LIBRDF_LOG_WARN, LIBRDF_FROM_STORAGE, NULL,
 | 
						|
               "Storage was created without context support");
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  
 | 
						|
  icontext=(librdf_storage_hashes_get_contexts_iterator_context*)LIBRDF_CALLOC(librdf_storage_hashes_get_contexts_iterator_context, 1, sizeof(librdf_storage_hashes_get_contexts_iterator_context));
 | 
						|
  if(!icontext)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  icontext->key=librdf_new_hash_datum(storage->world, NULL, 0);
 | 
						|
  if(!icontext->key)
 | 
						|
    return NULL;
 | 
						|
  
 | 
						|
  icontext->iterator=librdf_hash_keys(context->hashes[context->contexts_index],
 | 
						|
                                      icontext->key);
 | 
						|
  if(!icontext->iterator) {
 | 
						|
    librdf_storage_hashes_get_contexts_finished(icontext);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  icontext->storage=storage;
 | 
						|
  librdf_storage_add_reference(icontext->storage);
 | 
						|
 | 
						|
  iterator=librdf_new_iterator(storage->world,
 | 
						|
                               (void*)icontext,
 | 
						|
                               &librdf_storage_hashes_get_contexts_is_end,
 | 
						|
                               &librdf_storage_hashes_get_contexts_next_method,
 | 
						|
                               &librdf_storage_hashes_get_contexts_get_method,
 | 
						|
                               &librdf_storage_hashes_get_contexts_finished);
 | 
						|
  if(!iterator)
 | 
						|
    librdf_storage_hashes_get_contexts_finished(icontext);
 | 
						|
  return iterator;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * librdf_storage_hashes_get_feature:
 | 
						|
 * @storage: #librdf_storage object
 | 
						|
 * @feature: #librdf_uri feature property
 | 
						|
 *
 | 
						|
 * Get the value of a storage feature.
 | 
						|
 * 
 | 
						|
 * Return value: new #librdf_node feature value or NULL if no such feature
 | 
						|
 * exists or the value is empty.
 | 
						|
 **/
 | 
						|
static librdf_node*
 | 
						|
librdf_storage_hashes_get_feature(librdf_storage* storage, librdf_uri* feature)
 | 
						|
{
 | 
						|
  librdf_storage_hashes_context* scontext=(librdf_storage_hashes_context*)storage->context;
 | 
						|
  unsigned char *uri_string;
 | 
						|
 | 
						|
  if(!feature)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  uri_string=librdf_uri_as_string(feature);
 | 
						|
  if(!uri_string)
 | 
						|
    return NULL;
 | 
						|
  
 | 
						|
  if(!strcmp((const char*)uri_string, LIBRDF_MODEL_FEATURE_CONTEXTS)) {
 | 
						|
    unsigned char value[2];
 | 
						|
 | 
						|
    sprintf((char*)value, "%d", (scontext->index_contexts != 0));
 | 
						|
    return librdf_new_node_from_typed_literal(storage->world, 
 | 
						|
                                              value, NULL, NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* local function to register hashes storage functions */
 | 
						|
 | 
						|
static void
 | 
						|
librdf_storage_hashes_register_factory(librdf_storage_factory *factory) 
 | 
						|
{
 | 
						|
  factory->context_length     = sizeof(librdf_storage_hashes_context);
 | 
						|
  
 | 
						|
  factory->init               = librdf_storage_hashes_init;
 | 
						|
  factory->clone              = librdf_storage_hashes_clone;
 | 
						|
  factory->terminate          = librdf_storage_hashes_terminate;
 | 
						|
  factory->open               = librdf_storage_hashes_open;
 | 
						|
  factory->close              = librdf_storage_hashes_close;
 | 
						|
  factory->size               = librdf_storage_hashes_size;
 | 
						|
  factory->add_statement      = librdf_storage_hashes_add_statement;
 | 
						|
  factory->add_statements     = librdf_storage_hashes_add_statements;
 | 
						|
  factory->remove_statement   = librdf_storage_hashes_remove_statement;
 | 
						|
  factory->contains_statement = librdf_storage_hashes_contains_statement;
 | 
						|
  factory->serialise          = librdf_storage_hashes_serialise;
 | 
						|
 | 
						|
  factory->find_statements    = librdf_storage_hashes_find_statements;
 | 
						|
  factory->find_sources       = librdf_storage_hashes_find_sources;
 | 
						|
  factory->find_arcs          = librdf_storage_hashes_find_arcs;
 | 
						|
  factory->find_targets       = librdf_storage_hashes_find_targets;
 | 
						|
 | 
						|
  factory->context_add_statement    = librdf_storage_hashes_context_add_statement;
 | 
						|
  factory->context_remove_statement = librdf_storage_hashes_context_remove_statement;
 | 
						|
  factory->context_serialise        = librdf_storage_hashes_context_serialise;
 | 
						|
  factory->sync                     = librdf_storage_hashes_sync;
 | 
						|
  factory->get_contexts             = librdf_storage_hashes_get_contexts;
 | 
						|
  factory->get_feature              = librdf_storage_hashes_get_feature;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * librdf_init_storage_hashes:
 | 
						|
 * @world: world object
 | 
						|
 * 
 | 
						|
 * INTERNAL - initialise the storage_hashes module.
 | 
						|
 **/
 | 
						|
void
 | 
						|
librdf_init_storage_hashes(librdf_world *world)
 | 
						|
{
 | 
						|
  librdf_storage_register_factory(world, "hashes", "Indexed hashes",
 | 
						|
                                  &librdf_storage_hashes_register_factory);
 | 
						|
}
 |