1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rdf_storage_trees.c - RDF Storage in memory using balanced trees
4 *
5 * Copyright (C) 2000-2008, David Beckett http://www.dajobe.org/
6 * Copyright (C) 2000-2004, University of Bristol, UK http://www.bristol.ac.uk/
7 *
8 * This package is Free Software and part of Redland http://librdf.org/
9 *
10 * It is licensed under the following three licenses as alternatives:
11 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
12 * 2. GNU General Public License (GPL) V2 or any newer version
13 * 3. Apache License, V2.0 or any newer version
14 *
15 * You may not use this file except in compliance with at least one of
16 * the above three licenses.
17 *
18 * See LICENSE.html or LICENSE.txt at the top of this package for the
19 * complete terms and further detail along with the license texts for
20 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
21 *
22 *
23 */
24
25
26 #ifdef HAVE_CONFIG_H
27 #include <rdf_config.h>
28 #endif
29
30 #ifdef WIN32
31 #include <win32_rdf_config.h>
32 #endif
33
34 #include <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 /* for ptrdiff_t */
40 #ifdef HAVE_STDDEF_H
41 #include <stddef.h>
42 #endif
43 #include <sys/types.h>
44
45 #include <redland.h>
46
47 /* Not yet fully implemented (namely iteration) */
48 /*#define RDF_STORAGE_TREES_WITH_CONTEXTS 1*/
49
50 typedef struct
51 {
52 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
53 librdf_node* context;
54 #endif
55 raptor_avltree* spo_tree; /* Always present */
56 raptor_avltree* sop_tree; /* Optional */
57 raptor_avltree* ops_tree; /* Optional */
58 raptor_avltree* pso_tree; /* Optional */
59 } librdf_storage_trees_graph;
60
61 typedef struct
62 {
63 librdf_storage_trees_graph* graph; /* Statements without a context */
64 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
65 raptor_avltree* contexts; /* Tree of librdf_storage_trees_graph */
66 #endif
67 int index_sop;
68 int index_ops;
69 int index_pso;
70 } librdf_storage_trees_instance;
71
72 /* prototypes for local functions */
73 static int librdf_storage_trees_init(librdf_storage* storage, const char *name, librdf_hash* options);
74 static int librdf_storage_trees_open(librdf_storage* storage, librdf_model* model);
75 static int librdf_storage_trees_close(librdf_storage* storage);
76 static int librdf_storage_trees_size(librdf_storage* storage);
77 static int librdf_storage_trees_add_statement(librdf_storage* storage, librdf_statement* statement);
78 static int librdf_storage_trees_add_statements(librdf_storage* storage, librdf_stream* statement_stream);
79 static int librdf_storage_trees_remove_statement(librdf_storage* storage, librdf_statement* statement);
80 static int librdf_storage_trees_remove_statement_internal(librdf_storage_trees_graph* graph, librdf_statement* statement);
81 static int librdf_storage_trees_contains_statement(librdf_storage* storage, librdf_statement* statement);
82 static librdf_stream* librdf_storage_trees_serialise(librdf_storage* storage);
83 static librdf_stream* librdf_storage_trees_find_statements(librdf_storage* storage, librdf_statement* statement);
84
85 /* graph functions */
86 static librdf_storage_trees_graph* librdf_storage_trees_graph_new(librdf_storage* storage, librdf_node* context);
87 static void librdf_storage_trees_graph_free(void* data);
88 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
89 static int librdf_storage_trees_graph_compare(const void* data1, const void* data2);
90 #endif
91
92 /* serialising implementing functions */
93 static int librdf_storage_trees_serialise_end_of_stream(void* context);
94 static int librdf_storage_trees_serialise_next_statement(void* context);
95 static void* librdf_storage_trees_serialise_get_statement(void* context, int flags);
96 static void librdf_storage_trees_serialise_finished(void* context);
97
98 /* context functions */
99 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
100 static int librdf_storage_trees_context_add_statement(librdf_storage* storage, librdf_node* context_node, librdf_statement* statement);
101 static int librdf_storage_trees_context_remove_statement(librdf_storage* storage, librdf_node* context_node, librdf_statement* statement);
102 static librdf_stream* librdf_storage_trees_context_serialise(librdf_storage* storage, librdf_node* context_node);
103 #endif
104
105 /* statement tree functions */
106 static int librdf_statement_compare_spo(const void* data1, const void* data2);
107 static int librdf_statement_compare_sop(const void* data1, const void* data2);
108 static int librdf_statement_compare_ops(const void* data1, const void* data2);
109 static int librdf_statement_compare_pso(const void* data1, const void* data2);
110 static void librdf_storage_trees_avl_free(void* data);
111
112
113 static void librdf_storage_trees_register_factory(librdf_storage_factory *factory);
114
115
116 /* functions implementing storage api */
117 static int
librdf_storage_trees_init(librdf_storage * storage,const char * name,librdf_hash * options)118 librdf_storage_trees_init(librdf_storage* storage, const char *name,
119 librdf_hash* options)
120 {
121 const int index_spo_option = librdf_hash_get_as_boolean(options, "index-spo") > 0;
122 const int index_sop_option = librdf_hash_get_as_boolean(options, "index-sop") > 0;
123 const int index_ops_option = librdf_hash_get_as_boolean(options, "index-ops") > 0;
124 const int index_pso_option = librdf_hash_get_as_boolean(options, "index-pso") > 0;
125
126 librdf_storage_trees_instance* context;
127
128 context = LIBRDF_CALLOC(librdf_storage_trees_instance*, 1, sizeof(*context));
129 if(!context) {
130 if(options)
131 librdf_free_hash(options);
132 return 1;
133 }
134
135 librdf_storage_set_instance(storage, context);
136
137 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
138 /* Support contexts if option given */
139 if (librdf_hash_get_as_boolean(options, "contexts") > 0) {
140 context->contexts=librdf_new_avltree(librdf_storage_trees_graph_compare,
141 librdf_storage_trees_graph_free);
142 } else {
143 context->contexts=NULL;
144 }
145 #endif
146
147 /* No indexing options given, index all by default */
148 if (!index_spo_option && !index_sop_option && !index_ops_option && !index_pso_option) {
149 context->index_sop=1;
150 context->index_ops=1;
151 context->index_pso=1;
152 } else {
153 /* spo is always indexed, option just exists so user can
154 * specifically /only/ index spo */
155 context->index_sop=index_sop_option;
156 context->index_ops=index_ops_option;
157 context->index_pso=index_pso_option;
158 }
159
160 context->graph = librdf_storage_trees_graph_new(storage, NULL);
161
162 /* no more options, might as well free them now */
163 if(options)
164 librdf_free_hash(options);
165
166 return 0;
167 }
168
169
170 static void
librdf_storage_trees_terminate(librdf_storage * storage)171 librdf_storage_trees_terminate(librdf_storage* storage)
172 {
173 if (storage->instance != NULL)
174 LIBRDF_FREE(librdf_storage_trees_instance, storage->instance);
175 }
176
177
178 static int
librdf_storage_trees_open(librdf_storage * storage,librdf_model * model)179 librdf_storage_trees_open(librdf_storage* storage, librdf_model* model)
180 {
181 /* nop */
182 return 0;
183 }
184
185
186 /**
187 * librdf_storage_trees_close:
188 * @storage: the storage
189 *
190 * .
191 *
192 * Close the storage, and free all content since there is no persistance.
193 *
194 * Return value: non 0 on failure
195 **/
196 static int
librdf_storage_trees_close(librdf_storage * storage)197 librdf_storage_trees_close(librdf_storage* storage)
198 {
199 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
200
201 librdf_storage_trees_graph_free(context->graph);
202 context->graph=NULL;
203
204 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
205 librdf_free_avltree(context->contexts);
206 context->contexts=NULL;
207 #endif
208
209 return 0;
210 }
211
212
213 static int
librdf_storage_trees_size(librdf_storage * storage)214 librdf_storage_trees_size(librdf_storage* storage)
215 {
216 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
217
218 return raptor_avltree_size(context->graph->spo_tree);
219 }
220
221
222 static int
librdf_storage_trees_add_statement_internal(librdf_storage * storage,librdf_storage_trees_graph * graph,librdf_statement * statement)223 librdf_storage_trees_add_statement_internal(librdf_storage* storage,
224 librdf_storage_trees_graph* graph,
225 librdf_statement* statement)
226 {
227 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
228 int status = 0;
229
230 /* copy statement (store single copy in all trees) */
231 statement = librdf_new_statement_from_statement(statement);
232
233 /* spo_tree owns statement */
234 status = raptor_avltree_add(graph->spo_tree, statement);
235 if (status > 0) /* item already exists; old item remains in tree */
236 return 0;
237 else if (status < 0) /* failure */
238 return status;
239
240 /* others have null deleters */
241 /* (XXX: corrupt model if insertions fail) */
242
243 if (context->index_sop)
244 raptor_avltree_add(graph->sop_tree, statement);
245
246 if (context->index_ops)
247 raptor_avltree_add(graph->ops_tree, statement);
248
249 if (context->index_pso)
250 raptor_avltree_add(graph->pso_tree, statement);
251
252 return status;
253 }
254
255
256 /**
257 * librdf_storage_trees_add_statement:
258 * @storage: #librdf_storage object
259 * @context_node: #librdf_node object
260 * @statement: #librdf_statement statement to add
261 *
262 * Add a statement (with no context) to the storage.
263 *
264 * Return value: non 0 on failure (negative if error, positive if statement
265 * already exists).
266 **/
267 static int
librdf_storage_trees_add_statement(librdf_storage * storage,librdf_statement * statement)268 librdf_storage_trees_add_statement(librdf_storage* storage,
269 librdf_statement* statement)
270 {
271 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
272 return librdf_storage_trees_add_statement_internal(storage, context->graph, statement);
273 }
274
275
276 static int
librdf_storage_trees_add_statements(librdf_storage * storage,librdf_stream * statement_stream)277 librdf_storage_trees_add_statements(librdf_storage* storage,
278 librdf_stream* statement_stream)
279 {
280 int status=0;
281
282 for(; !librdf_stream_end(statement_stream); librdf_stream_next(statement_stream)) {
283 librdf_statement* statement=librdf_stream_get_object(statement_stream);
284
285 if (statement) {
286 status=librdf_storage_trees_add_statement(storage, statement);
287 if (status)
288 break;
289 } else {
290 status=1;
291 break;
292 }
293 }
294
295 return status;
296 }
297
298 static int
librdf_storage_trees_remove_statement_internal(librdf_storage_trees_graph * graph,librdf_statement * statement)299 librdf_storage_trees_remove_statement_internal(librdf_storage_trees_graph* graph,
300 librdf_statement* statement)
301 {
302 if (graph->sop_tree)
303 raptor_avltree_delete(graph->sop_tree, statement);
304
305 if (graph->ops_tree)
306 raptor_avltree_delete(graph->ops_tree, statement);
307
308 if (graph->pso_tree)
309 raptor_avltree_delete(graph->pso_tree, statement);
310
311 raptor_avltree_delete(graph->spo_tree, statement);
312
313 return 0;
314 }
315
316
317 /**
318 * librdf_storage_trees_remove_statement:
319 * @storage: #librdf_storage object
320 * @context_node: #librdf_node object
321 * @statement: #librdf_statement statement to remove
322 *
323 * Remove a statement (without context) from the storage.
324 *
325 * Return value: non 0 on failure
326 **/
327 static int
librdf_storage_trees_remove_statement(librdf_storage * storage,librdf_statement * statement)328 librdf_storage_trees_remove_statement(librdf_storage* storage,
329 librdf_statement* statement)
330 {
331 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
332
333 return librdf_storage_trees_remove_statement_internal(context->graph, statement);
334 }
335
336 static int
librdf_storage_trees_contains_statement(librdf_storage * storage,librdf_statement * statement)337 librdf_storage_trees_contains_statement(librdf_storage* storage, librdf_statement* statement)
338 {
339 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
340
341 return (raptor_avltree_search(context->graph->spo_tree, statement) != NULL);
342 }
343
344
345 typedef struct {
346 librdf_storage *storage;
347 raptor_avltree_iterator *avltree_iterator;
348 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
349 librdf_node *context_node;
350 #endif
351 } librdf_storage_trees_serialise_stream_context;
352
353
354 static librdf_stream*
librdf_storage_trees_serialise_range(librdf_storage * storage,librdf_statement * range)355 librdf_storage_trees_serialise_range(librdf_storage* storage, librdf_statement* range)
356 {
357 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
358 librdf_storage_trees_serialise_stream_context* scontext;
359 librdf_stream* stream;
360 int filter = 0;
361
362 scontext = LIBRDF_CALLOC(librdf_storage_trees_serialise_stream_context*, 1,
363 sizeof(*scontext));
364 if(!scontext)
365 return NULL;
366
367 scontext->avltree_iterator = NULL;
368
369 /* ?s ?p ?o */
370 if (!range || (!range->subject && !range->predicate && !range->object)) {
371 scontext->avltree_iterator = raptor_new_avltree_iterator(context->graph->spo_tree,
372 /* range */ NULL,
373 /* range free */ NULL,
374 1);
375 if (range) {
376 librdf_free_statement(range);
377 range=NULL;
378 }
379 /* s ?p o */
380 } else if (range->subject && !range->predicate && range->object) {
381 if (context->index_sop)
382 scontext->avltree_iterator = raptor_new_avltree_iterator(context->graph->sop_tree,
383 range,
384 librdf_storage_trees_avl_free,
385 1);
386 else
387 filter=1;
388 /* s _ _ */
389 } else if (range->subject) {
390 scontext->avltree_iterator = raptor_new_avltree_iterator(context->graph->spo_tree,
391 range,
392 librdf_storage_trees_avl_free,
393 1);
394 /* ?s _ o */
395 } else if (range->object) {
396 if (context->index_ops)
397 scontext->avltree_iterator = raptor_new_avltree_iterator(context->graph->ops_tree,
398 range,
399 librdf_storage_trees_avl_free,
400 1);
401 else
402 filter=1;
403 /* ?s p ?o */
404 } else { /* range->predicate != NULL */
405 if (context->index_pso)
406 scontext->avltree_iterator = raptor_new_avltree_iterator(context->graph->pso_tree,
407 range,
408 librdf_storage_trees_avl_free,
409 1);
410 else
411 filter=1;
412 }
413
414 /* If filter is set, we're missing the required index.
415 * Iterate over the entire model and filter the stream.
416 * (With a fully indexed store, this will never happen) */
417 if (filter) {
418 scontext->avltree_iterator = raptor_new_avltree_iterator(context->graph->spo_tree,
419 range,
420 librdf_storage_trees_avl_free,
421 1);
422 }
423
424 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
425 scontext->context_node=NULL;
426 #endif
427
428 if(!scontext->avltree_iterator) {
429 LIBRDF_FREE(librdf_storage_trees_serialise_stream_context, scontext);
430 return librdf_new_empty_stream(storage->world);
431 }
432
433 scontext->storage=storage;
434 librdf_storage_add_reference(scontext->storage);
435
436 stream=librdf_new_stream(storage->world,
437 (void*)scontext,
438 &librdf_storage_trees_serialise_end_of_stream,
439 &librdf_storage_trees_serialise_next_statement,
440 &librdf_storage_trees_serialise_get_statement,
441 &librdf_storage_trees_serialise_finished);
442
443 if(!stream) {
444 librdf_storage_trees_serialise_finished((void*)scontext);
445 return NULL;
446 }
447
448 if(filter) {
449 if(librdf_stream_add_map(stream, &librdf_stream_statement_find_map, NULL, (void*)range)) {
450 /* error - stream_add_map failed */
451 librdf_free_stream(stream);
452 stream=NULL;
453 }
454 }
455
456 return stream;
457 }
458
459
460 static librdf_stream*
librdf_storage_trees_serialise(librdf_storage * storage)461 librdf_storage_trees_serialise(librdf_storage* storage)
462 {
463 return librdf_storage_trees_serialise_range(storage, NULL);
464 }
465
466
467 static int
librdf_storage_trees_serialise_end_of_stream(void * context)468 librdf_storage_trees_serialise_end_of_stream(void* context)
469 {
470 librdf_storage_trees_serialise_stream_context* scontext=(librdf_storage_trees_serialise_stream_context*)context;
471
472 return raptor_avltree_iterator_is_end(scontext->avltree_iterator);
473 }
474
475 static int
librdf_storage_trees_serialise_next_statement(void * context)476 librdf_storage_trees_serialise_next_statement(void* context)
477 {
478 librdf_storage_trees_serialise_stream_context* scontext=(librdf_storage_trees_serialise_stream_context*)context;
479
480 return raptor_avltree_iterator_next(scontext->avltree_iterator);
481 }
482
483
484 static void*
librdf_storage_trees_serialise_get_statement(void * context,int flags)485 librdf_storage_trees_serialise_get_statement(void* context, int flags)
486 {
487 librdf_storage_trees_serialise_stream_context* scontext=(librdf_storage_trees_serialise_stream_context*)context;
488
489 if(!scontext->avltree_iterator)
490 return NULL;
491
492 switch(flags) {
493 case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT:
494 return (librdf_statement*)raptor_avltree_iterator_get(scontext->avltree_iterator);
495
496 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
497 case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT:
498 return scontext->context_node;
499 #endif
500
501 default:
502 return NULL;
503 }
504 }
505
506
507 static void
librdf_storage_trees_serialise_finished(void * context)508 librdf_storage_trees_serialise_finished(void* context)
509 {
510 librdf_storage_trees_serialise_stream_context* scontext=(librdf_storage_trees_serialise_stream_context*)context;
511
512 if(scontext->avltree_iterator)
513 raptor_free_avltree_iterator(scontext->avltree_iterator);
514
515 if(scontext->storage)
516 librdf_storage_remove_reference(scontext->storage);
517
518 LIBRDF_FREE(librdf_storage_trees_serialise_stream_context, scontext);
519 }
520
521
522 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
523 /**
524 * librdf_storage_trees_context_add_statement:
525 * @storage: #librdf_storage object
526 * @context_node: #librdf_node object
527 * @statement: #librdf_statement statement to add
528 *
529 * Add a statement to a storage context.
530 *
531 * Return value: non 0 on failure
532 **/
533 static int
librdf_storage_trees_context_add_statement(librdf_storage * storage,librdf_node * context_node,librdf_statement * statement)534 librdf_storage_trees_context_add_statement(librdf_storage* storage,
535 librdf_node* context_node,
536 librdf_statement* statement)
537 {
538 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
539
540 librdf_storage_trees_graph* key=librdf_storage_trees_graph_new(storage, context_node);
541 librdf_storage_trees_graph* graph=(librdf_storage_trees_graph*)
542 raptor_avltree_search(context->contexts, key);
543
544 if(graph) {
545 librdf_storage_trees_graph_free(key);
546 } else {
547 raptor_avltree_add(context->contexts, key);
548 graph=key;
549 }
550
551 return librdf_storage_trees_add_statement_internal(storage, graph, statement);
552 }
553
554
555 /**
556 * librdf_storage_trees_context_remove_statement:
557 * @storage: #librdf_storage object
558 * @context_node: #librdf_node object
559 * @statement: #librdf_statement statement to remove
560 *
561 * Remove a statement from a storage context.
562 *
563 * Return value: non 0 on failure
564 **/
565 static int
librdf_storage_trees_context_remove_statement(librdf_storage * storage,librdf_node * context_node,librdf_statement * statement)566 librdf_storage_trees_context_remove_statement(librdf_storage* storage,
567 librdf_node* context_node,
568 librdf_statement* statement)
569 {
570 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
571 librdf_storage_trees_graph* key=librdf_storage_trees_graph_new(storage, context_node);
572 librdf_storage_trees_graph* graph=(librdf_storage_trees_graph*)
573 raptor_avltree_search(context->contexts, &key);
574 librdf_storage_trees_graph_free(key);
575 if (graph) {
576 return librdf_storage_trees_remove_statement_internal(graph, statement);
577 } else {
578 return -1;
579 }
580 }
581
582
583 /**
584 * librdf_storage_trees_context_serialise:
585 * @storage: #librdf_storage object
586 * @context_node: #librdf_node object
587 *
588 * List all statements in a storage context.
589 *
590 * Return value: #librdf_stream of statements or NULL on failure or context is empty
591 **/
592 static librdf_stream*
librdf_storage_trees_context_serialise(librdf_storage * storage,librdf_node * context_node)593 librdf_storage_trees_context_serialise(librdf_storage* storage,
594 librdf_node* context_node)
595 {
596 return NULL;
597 }
598
599
600 /**
601 * librdf_storage_trees_context_get_contexts:
602 * @storage: #librdf_storage object
603 *
604 * List all context nodes in a storage.
605 *
606 * Return value: #librdf_iterator of context_nodes or NULL on failure or no contexts
607 **/
608 static librdf_iterator*
librdf_storage_trees_get_contexts(librdf_storage * storage)609 librdf_storage_trees_get_contexts(librdf_storage* storage)
610 {
611 return NULL;
612 }
613 #endif
614
615
616 /**
617 * librdf_storage_trees_find_statements:
618 * @storage: the storage
619 * @statement: the statement to match
620 *
621 * .
622 *
623 * Return a stream of statements matching the given statement (or
624 * all statements if NULL). Parts (subject, predicate, object) of the
625 * statement can be empty in which case any statement part will match that.
626 * Uses #librdf_statement_match to do the matching.
627 *
628 * Return value: a #librdf_stream or NULL on failure
629 **/
630 static librdf_stream*
librdf_storage_trees_find_statements(librdf_storage * storage,librdf_statement * statement)631 librdf_storage_trees_find_statements(librdf_storage* storage, librdf_statement* statement)
632 {
633 librdf_stream* stream;
634
635 librdf_statement* range=librdf_new_statement_from_statement(statement);
636 if(!range)
637 return NULL;
638
639 stream=librdf_storage_trees_serialise_range(storage, range);
640
641 return stream;
642 }
643
644 /* statement tree functions */
645
646 static int
librdf_storage_trees_node_compare(librdf_node * n1,librdf_node * n2)647 librdf_storage_trees_node_compare(librdf_node* n1, librdf_node* n2)
648 {
649 if (n1 == n2) {
650 return 0;
651 } else if (n1->type != n2->type) {
652 return LIBRDF_GOOD_CAST(int, n2->type) - LIBRDF_GOOD_CAST(int, n1->type);
653 } else {
654 switch (n1->type) {
655 case RAPTOR_TERM_TYPE_URI:
656 return librdf_uri_compare(n1->value.uri, n2->value.uri);
657
658 case RAPTOR_TERM_TYPE_LITERAL:
659 if(1) {
660 const unsigned char l1 = n1->value.literal.language_len;
661 const unsigned char l2 = n2->value.literal.language_len;
662 const unsigned char l = (l1 < l2) ? l1 : l2;
663
664 /* compare first by data type */
665 int r = raptor_uri_compare(n1->value.literal.datatype,
666 n2->value.literal.datatype);
667 if(r)
668 return r;
669
670 /* if data type is equal, compare by value */
671 r = strcmp((const char*)n1->value.literal.string,
672 (const char*)n2->value.literal.string);
673 if(r)
674 return r;
675
676 /* if both data type and value are equal, compare by language */
677 if(l) {
678 return strncmp((const char*)n1->value.literal.language,
679 (const char*)n2->value.literal.language, (size_t)l);
680 } else {
681 /* if l == 0 strncmp will always return 0; in that case
682 * consider the node with no language to be lesser. */
683 return l1 - l2;
684 }
685 }
686 case RAPTOR_TERM_TYPE_BLANK:
687 return strcmp((char*)n1->value.blank.string,
688 (char*)n2->value.blank.string);
689
690 case RAPTOR_TERM_TYPE_UNKNOWN:
691 default:
692 if(1) {
693 ptrdiff_t d;
694 d = LIBRDF_GOOD_CAST(char*, n2) - LIBRDF_GOOD_CAST(char*, n1);
695 return (d > 0) - (d < 0);
696 }
697 }
698 }
699 }
700
701
702
703 /* Compare two statements in (s, p, o) order.
704 * NULL fields act as wildcards. */
705 static int
librdf_statement_compare_spo(const void * data1,const void * data2)706 librdf_statement_compare_spo(const void* data1, const void* data2)
707 {
708 librdf_statement* a = (librdf_statement*)data1;
709 librdf_statement* b = (librdf_statement*)data2;
710 int cmp = 0;
711
712 /* Subject */
713 if (a->subject == NULL || b->subject == NULL)
714 return 0; /* wildcard subject match */
715 else
716 cmp = librdf_storage_trees_node_compare(a->subject, b->subject);
717
718 if (cmp != 0)
719 return cmp;
720
721 /* Predicate */
722 if (a->predicate == NULL || b->predicate == NULL)
723 return 0; /* wildcard predicate match */
724 else
725 cmp = librdf_storage_trees_node_compare(a->predicate, b->predicate);
726
727 if (cmp != 0)
728 return cmp;
729
730 /* Object */
731 if (a->object == NULL || b->object == NULL)
732 return 0; /* wildcard object match */
733 else
734 cmp = librdf_storage_trees_node_compare(a->object, b->object);
735
736 return cmp;
737 }
738
739
740 /* Compare two statements in (o, s, p) order.
741 * NULL fields act as wildcards. */
742 static int
librdf_statement_compare_sop(const void * data1,const void * data2)743 librdf_statement_compare_sop(const void* data1, const void* data2)
744 {
745 librdf_statement* a = (librdf_statement*)data1;
746 librdf_statement* b = (librdf_statement*)data2;
747 int cmp = 0;
748
749 /* Subject */
750 if (a->subject == NULL || b->subject == NULL)
751 return 0; /* wildcard subject match */
752 else
753 cmp = librdf_storage_trees_node_compare(a->subject, b->subject);
754
755 if (cmp != 0)
756 return cmp;
757
758 /* Object */
759 if (a->object == NULL || b->object == NULL)
760 return 0; /* wildcard object match */
761 else
762 cmp = librdf_storage_trees_node_compare(a->object, b->object);
763
764 if (cmp != 0)
765 return cmp;
766
767 /* Predicate */
768 if (a->predicate == NULL || b->predicate == NULL)
769 return 0; /* wildcard predicate match */
770 else
771 cmp = librdf_storage_trees_node_compare(a->predicate, b->predicate);
772
773 return cmp;
774 }
775
776
777 /* Compare two statements in (o, p, s) order.
778 * NULL fields act as wildcards. */
779 static int
librdf_statement_compare_ops(const void * data1,const void * data2)780 librdf_statement_compare_ops(const void* data1, const void* data2)
781 {
782 librdf_statement* a = (librdf_statement*)data1;
783 librdf_statement* b = (librdf_statement*)data2;
784 int cmp = 0;
785
786 /* Object */
787 if (a->object == NULL || b->object == NULL)
788 return 0; /* wildcard object match */
789 else
790 cmp = librdf_storage_trees_node_compare(a->object, b->object);
791
792 if (cmp != 0)
793 return cmp;
794
795 /* Predicate */
796 if (a->predicate == NULL || b->predicate == NULL)
797 return 0; /* wildcard predicate match */
798 else
799 cmp = librdf_storage_trees_node_compare(a->predicate, b->predicate);
800
801 if (cmp != 0)
802 return cmp;
803
804 /* Subject */
805 if (a->subject == NULL || b->subject == NULL)
806 return 0; /* wildcard subject match */
807 else
808 cmp = librdf_storage_trees_node_compare(a->subject, b->subject);
809
810 return cmp;
811 }
812
813
814 /* Compare two statements in (p, s, o) order.
815 * NULL fields act as wildcards. */
816 static int
librdf_statement_compare_pso(const void * data1,const void * data2)817 librdf_statement_compare_pso(const void* data1, const void* data2)
818 {
819 librdf_statement* a = (librdf_statement*)data1;
820 librdf_statement* b = (librdf_statement*)data2;
821 int cmp = 0;
822
823 /* Predicate */
824 if (a->predicate == NULL || b->predicate == NULL)
825 return 0; /* wildcard predicate match */
826 else
827 cmp = librdf_storage_trees_node_compare(a->predicate, b->predicate);
828
829 if (cmp != 0)
830 return cmp;
831
832 /* Subject */
833 if (a->subject == NULL || b->subject == NULL)
834 return 0; /* wildcard subject match */
835 else
836 cmp = librdf_storage_trees_node_compare(a->subject, b->subject);
837
838 if (cmp != 0)
839 return cmp;
840
841 /* Object */
842 if (a->object == NULL || b->object == NULL)
843 return 0; /* wildcard object match */
844 else
845 cmp = librdf_storage_trees_node_compare(a->object, b->object);
846
847 return cmp;
848 }
849
850
851 static void
librdf_storage_trees_avl_free(void * data)852 librdf_storage_trees_avl_free(void* data)
853 {
854 librdf_statement* stmnt=(librdf_statement*)data;
855 librdf_free_statement(stmnt);
856 }
857
858
859 /* graph functions */
860
861 static librdf_storage_trees_graph*
librdf_storage_trees_graph_new(librdf_storage * storage,librdf_node * context_node)862 librdf_storage_trees_graph_new(librdf_storage* storage, librdf_node* context_node)
863 {
864 librdf_storage_trees_instance* context=(librdf_storage_trees_instance*)storage->instance;
865 librdf_storage_trees_graph* graph;
866
867 graph = LIBRDF_MALLOC(librdf_storage_trees_graph*, sizeof(*graph));
868
869 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
870 graph->context=(context_node ? librdf_new_node_from_node(context_node) : NULL);
871 #endif
872
873 /* Always create SPO index */
874 graph->spo_tree = raptor_new_avltree(librdf_statement_compare_spo,
875 librdf_storage_trees_avl_free,
876 /* flags */ 0);
877 if(!graph->spo_tree) {
878 LIBRDF_FREE(librdf_storage_trees_graph, graph);
879 return NULL;
880 }
881
882 if(context->index_sop)
883 graph->sop_tree = raptor_new_avltree(librdf_statement_compare_sop, NULL,
884 /* flags */ 0);
885 else
886 graph->sop_tree=NULL;
887
888 if(context->index_ops)
889 graph->ops_tree = raptor_new_avltree(librdf_statement_compare_ops, NULL,
890 /* flags */ 0);
891 else
892 graph->ops_tree=NULL;
893
894 if(context->index_pso)
895 graph->pso_tree = raptor_new_avltree(librdf_statement_compare_pso, NULL,
896 /* flags */ 0);
897 else
898 graph->pso_tree=NULL;
899
900 return graph;
901 }
902
903
904 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
905 static int
librdf_storage_trees_graph_compare(const void * data1,const void * data2)906 librdf_storage_trees_graph_compare(const void* data1, const void* data2)
907 {
908 librdf_storage_trees_graph* a = (librdf_storage_trees_graph*)data1;
909 librdf_storage_trees_graph* b = (librdf_storage_trees_graph*)data2;
910 return librdf_storage_trees_node_compare(a->context, b->context);
911 }
912 #endif
913
914
915 static void
librdf_storage_trees_graph_free(void * data)916 librdf_storage_trees_graph_free(void* data)
917 {
918 librdf_storage_trees_graph* graph = (librdf_storage_trees_graph*)data;
919
920 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
921 librdf_free_node(graph->context);
922 #endif
923
924 /* Extra index trees have null deleters (statements are shared) */
925 if (graph->sop_tree)
926 raptor_free_avltree(graph->sop_tree);
927 if (graph->ops_tree)
928 raptor_free_avltree(graph->ops_tree);
929 if (graph->pso_tree)
930 raptor_free_avltree(graph->pso_tree);
931
932 /* Free spo tree and statements */
933 raptor_free_avltree(graph->spo_tree);
934
935 graph->spo_tree = NULL;
936 graph->sop_tree = NULL;
937 graph->ops_tree = NULL;
938 graph->pso_tree = NULL;
939
940 LIBRDF_FREE(librdf_storage_trees_graph, graph);
941 }
942
943
944 /**
945 * librdf_storage_trees_get_feature:
946 * @storage: #librdf_storage object
947 * @feature: #librdf_uri feature property
948 *
949 * Get the value of a storage feature.
950 *
951 * Return value: #librdf_node feature value or NULL if no such feature
952 * exists or the value is empty.
953 **/
954 static librdf_node*
librdf_storage_trees_get_feature(librdf_storage * storage,librdf_uri * feature)955 librdf_storage_trees_get_feature(librdf_storage* storage, librdf_uri* feature)
956 {
957 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
958 librdf_storage_trees_instance* scontext=(librdf_storage_trees_instance*)storage->instance;
959 unsigned char *uri_string;
960
961 if(!feature)
962 return NULL;
963
964 uri_string=librdf_uri_as_string(feature);
965 if(!uri_string)
966 return NULL;
967
968 if(!strcmp((const char*)uri_string, LIBRDF_MODEL_FEATURE_CONTEXTS)) {
969 unsigned char value[2];
970
971 sprintf((char*)value, "%d", (scontext->contexts != NULL));
972 return librdf_new_node_from_typed_literal(storage->world,
973 value, NULL, NULL);
974 }
975 #endif
976
977 return NULL;
978 }
979
980
981 /** Local entry point for dynamically loaded storage module */
982 static void
librdf_storage_trees_register_factory(librdf_storage_factory * factory)983 librdf_storage_trees_register_factory(librdf_storage_factory *factory)
984 {
985 LIBRDF_ASSERT_CONDITION(!strncmp(factory->name, "trees", 5));
986
987 factory->version = LIBRDF_STORAGE_INTERFACE_VERSION;
988 factory->init = librdf_storage_trees_init;
989 factory->clone = NULL;
990 factory->terminate = librdf_storage_trees_terminate;
991 factory->open = librdf_storage_trees_open;
992 factory->close = librdf_storage_trees_close;
993 factory->size = librdf_storage_trees_size;
994 factory->add_statement = librdf_storage_trees_add_statement;
995 factory->add_statements = librdf_storage_trees_add_statements;
996 factory->remove_statement = librdf_storage_trees_remove_statement;
997 factory->contains_statement = librdf_storage_trees_contains_statement;
998 factory->serialise = librdf_storage_trees_serialise;
999
1000 factory->find_statements = librdf_storage_trees_find_statements;
1001 /* These could be implemented, but only if all indexes are available.
1002 * If they returned NULL if the indexes weren't available,
1003 * librdf_storage_find_statements would break, unfortunately.
1004 * Since these are exposed by model methods, the storage interface
1005 * needs to be fixed so these can be exposed but find_statements
1006 * still work */
1007 factory->find_sources = NULL;
1008 factory->find_arcs = NULL;
1009 factory->find_targets = NULL;
1010
1011 #ifdef RDF_STORAGE_TREES_WITH_CONTEXTS
1012 factory->context_add_statement = librdf_storage_trees_context_add_statement;
1013 factory->context_remove_statement = librdf_storage_trees_context_remove_statement;
1014 factory->context_serialise = librdf_storage_trees_context_serialise;
1015 factory->get_contexts = librdf_storage_trees_get_contexts;
1016 #else
1017 factory->context_add_statement = NULL;
1018 factory->context_remove_statement = NULL;
1019 factory->context_serialise = NULL;
1020 factory->get_contexts = NULL;
1021 #endif
1022
1023 factory->sync = NULL;
1024 factory->get_feature = librdf_storage_trees_get_feature;
1025 }
1026
1027
1028 /*
1029 * librdf_init_storage_trees:
1030 * @world: world object
1031 *
1032 * INTERNAL - Initialise the built-in storage_trees module.
1033 */
1034 void
librdf_init_storage_trees(librdf_world * world)1035 librdf_init_storage_trees(librdf_world *world)
1036 {
1037 librdf_storage_register_factory(world, "trees", "Balanced trees",
1038 &librdf_storage_trees_register_factory);
1039 }
1040