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