1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-02 16:49:41 +02:00
audacity/lib-src/redland/librdf/rdf_storage_hashes.c
2010-01-24 09:19:39 +00:00

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);
}