Volksdata 1.0b7
RDF library
Loading...
Searching...
No Matches
graph.c
Go to the documentation of this file.
1#include "volksdata/graph.h"
2
3/*
4 * Data types.
5 */
6
11
13 const VOLK_Graph * graph;
14 void * data;
15 size_t ct;
21};
22
23
24/*
25 * Static prototypes.
26 */
27
28inline static VOLK_rc
29graph_iter_next_buffer (VOLK_GraphIterator *it);
30
31
32#define ENTRY(a, b) (be) == (VOLK_STORE_##a) ||
33static inline bool
34check_backend (VOLK_StoreType be)
35{ return (BACKEND_TBL false); }
36#undef ENTRY
37
38
39/*
40 * Graph API.
41 */
42
43VOLK_Graph *
44VOLK_graph_new (VOLK_Store *store, const char *uri_str)
45{
46 // Create a HTable graph by default.
47 VOLK_Graph *gr;
48 MALLOC_GUARD (gr, NULL);
49
50 gr->store = (store) ? store : VOLK_store_new (
51 VOLK_STORE_HTABLE, NULL, 0, false);
52
53 gr->uri =
54 uri_str? VOLK_iriref_new (uri_str) :
55 VOLK_iriref_new (NULL);
56
57 LOG_DEBUG ("Graph created.");
58 return gr;
59}
60
61
62VOLK_Graph *
64 void *txn, VOLK_Store *store, const VOLK_Term *uri, size_t *ct)
65{
67 void *it = store->sif->lookup_fn (
68 store->data, NULL, NULL, NULL, sc, NULL, NULL);
69
70 VOLK_Graph *gr = VOLK_graph_new (NULL, uri->data);
72 void *add_it = VOLK_graph_add_init_txn (txn, gr);
73
74 size_t _ct = 0;
75 while (store->sif->lu_next_fn (it, sspo, NULL) == VOLK_OK) {
76 // This is deserializing a buffer triple that will be re-serialized by
77 // VOLK_graph_add_iter. But it's necessary to relativize URIs.
79 VOLK_graph_add_iter (add_it, spo);
80 VOLK_triple_free (spo);
81 _ct++;
82 }
83 VOLK_graph_iter_free (add_it);
84 store->sif->lu_free_fn(it);
86 VOLK_btriple_free (sspo);
87
88 // Do not create a new graph if no results were found.
89 if (_ct == 0) {
90 VOLK_graph_free (gr);
91 gr = NULL;
92 }
93 if (ct) *ct = _ct;
94
95 return gr;
96}
97
98
101 void *txn, const VOLK_bool_op op,
102 const VOLK_Graph *gr1, const VOLK_Graph *gr2, VOLK_Graph *res)
103{
105 if (UNLIKELY (
106 op != VOLK_BOOL_UNION
107 && op != VOLK_BOOL_SUBTRACTION
109 && op != VOLK_BOOL_XOR)) {
110 log_error ("Invalid boolean operation: %d.", op);
111
112 return VOLK_VALUE_ERR;
113 }
114
115 /* BEGIN union block. */
116
117 if (op == VOLK_BOOL_UNION) {
118 // No need to use a transaction here: the graph is freed on failure.
119 rc = VOLK_graph_copy_contents (gr1, res, NULL, NULL, NULL);
120 PCHECK (rc, fail);
121 rc = VOLK_graph_copy_contents (gr2, res, NULL, NULL, NULL);
122 PCHECK (rc, fail);
123
124 return VOLK_OK;
125 }
126
127 /* END union block. */
128
130 *res_sc = VOLK_term_serialize (res->uri),
131 *gr1_sc = VOLK_term_serialize (gr1->uri),
132 *gr2_sc = VOLK_term_serialize (gr2->uri);
133 void *lu1_it, *lu2_it, *add_it;
135 size_t ct;
136
137 // Handle transactions for graphs possibly in different storage back ends.
138 void
139 *lu1_txn = NULL,
140 *lu2_txn = NULL,
141 *res_txn = NULL;
142 // Whether gr1 or gr2 txn will be open independently from res txn.
143 bool
144 open_txn1 = false,
145 open_txn2 = false;
146
147 add_it = res->store->sif->add_init_fn (res->store->data, res_sc, txn);
148
149 if (res->store->sif->features & VOLK_STORE_TXN)
150 res_txn = res->store->sif->iter_txn_fn (add_it);
151
152 /* If either source graph is in the same store as the destination and has
153 * an open transaction, reuse that transaction. A new reader cannot be
154 * opened in LMDB while a writer is open already.
155 */
156 // Handle gr1 transaction.
157 if (gr1->store->sif->features & VOLK_STORE_TXN) {
158 if (gr1->store == res->store) lu1_txn = res_txn;
159 // FIXME: MDB_RDONLY is implementation-specific and doesn't belong here.
160 else {
161 CHECK (gr1->store->sif->txn_begin_fn (
162 gr1->store->data, MDB_RDONLY, &lu1_txn), fail);
163 open_txn1 = true;
164 }
165 }
166
167 // Handle gr2 transaction.
168 if (gr2->store->sif->features & VOLK_STORE_TXN) {
169 if (gr2->store == res->store) lu2_txn = res_txn;
170 else if (gr2->store == gr1->store) lu2_txn = lu1_txn;
171 // FIXME: see above.
172 else {
173 CHECK (gr2->store->sif->txn_begin_fn (
174 gr2->store->data, MDB_RDONLY, &lu2_txn), fail);
175 open_txn2 = true;
176 }
177 }
178 LOG_TRACE (
179 "lu1_txn: %p ; lu2_txn: %p ; res_txn: %p",
180 lu1_txn, lu2_txn, res_txn);
181
182 /* BEGIN XOR block. */
183
184 if (op == VOLK_BOOL_XOR) {
185 // Add triples from gr2 if not found in gr1.
186 lu2_it = gr2->store->sif->lookup_fn (
187 gr2->store->data, NULL, NULL, NULL, gr2_sc, lu2_txn, NULL);
188 while (gr2->store->sif->lu_next_fn (lu2_it, sspo, NULL) == VOLK_OK) {
189 lu1_it = gr1->store->sif->lookup_fn (
190 gr1->store->data, sspo->s, sspo->p, sspo->o, gr1_sc,
191 lu1_txn, &ct);
192 if (ct == 0) {
193 res->store->sif->add_iter_fn (add_it, sspo);
194 rc = VOLK_OK;
195 }
196 gr1->store->sif->lu_free_fn (lu1_it);
197 }
198 gr2->store->sif->lu_free_fn (lu2_it);
199 }
200
201 /* BEGIN subtraction and intersection block. */
202
203 lu1_it = gr1->store->sif->lookup_fn (
204 gr1->store->data, NULL, NULL, NULL, gr1_sc, lu1_txn, NULL);
205 while (gr1->store->sif->lu_next_fn (lu1_it, sspo, NULL) == VOLK_OK) {
206 lu2_it = gr2->store->sif->lookup_fn (
207 gr2->store->data, sspo->s, sspo->p, sspo->o, gr2_sc,
208 lu2_txn, &ct);
209 if (UNLIKELY (!lu2_it)) {
210 rc = VOLK_DB_ERR;
211 gr1->store->sif->lu_free_fn (lu1_it);
212 goto fail;
213 }
214 // For XOR and subtraction, add if not found.
215 // For intersection, add if found.
216 if ((ct == 0) ^ (op == VOLK_BOOL_INTERSECTION)) {
217 res->store->sif->add_iter_fn (add_it, sspo);
218 rc = VOLK_OK;
219 }
220 gr2->store->sif->lu_free_fn (lu2_it);
221 }
222 gr1->store->sif->lu_free_fn (lu1_it);
223
224 if (open_txn1) gr1->store->sif->txn_commit_fn (lu1_txn);
225 if (open_txn2) gr2->store->sif->txn_commit_fn (lu2_txn);
226
227 res->store->sif->add_done_fn (add_it);
228 VOLK_btriple_free (sspo);
229 VOLK_buffer_free (res_sc);
230 VOLK_buffer_free (gr1_sc);
231 VOLK_buffer_free (gr2_sc);
232
233 /* END subtraction, intersection, XOR block. */
234
235 return rc;
236
237fail:
238 if (lu1_txn) gr1->store->sif->txn_abort_fn (lu1_txn);
239 if (lu2_txn) gr2->store->sif->txn_abort_fn (lu2_txn);
240 VOLK_graph_free (res);
241 return rc;
242}
243
244
245void
246VOLK_graph_free (VOLK_Graph *gr)
247{
248 if (UNLIKELY (!gr)) return;
249
250 VOLK_term_free (gr->uri);
251 // If the store is embedded, it goes away with the associated graph.
252 if (gr->store->sif->features & VOLK_STORE_EMBED) {
253 gr->store->sif->free_fn (gr->store->data);
254 free (gr->store->id);
255 free (gr->store);
256 }
257
258 free (gr);
259}
260
261
262const VOLK_Term *
263VOLK_graph_uri (const VOLK_Graph *gr) { return gr->uri; }
264
265
267VOLK_graph_store (const VOLK_Graph *gr)
268{ return gr->store; }
269
270
272VOLK_graph_set_uri (VOLK_Graph *gr, const char *uri_str)
273{
274 VOLK_rc rc = VOLK_OK;
275 VOLK_Buffer *old_sc = NULL, *new_sc = NULL;
276
277 VOLK_Term *uri = VOLK_iriref_new (uri_str);
278 if (UNLIKELY (!uri)) {
279 rc = VOLK_MEM_ERR;
280 goto finally;
281 }
282
283 // Update context for triples in the graph.
284 if (gr->store->sif->features & VOLK_STORE_CTX) {
285 old_sc = VOLK_term_serialize (gr->uri);
286 new_sc = VOLK_term_serialize (uri);
287 if (UNLIKELY (!old_sc || !new_sc)) {
288 rc = VOLK_MEM_ERR;
289 goto finally;
290 }
291
292 PCHECK (rc = gr->store->sif->update_ctx_fn (
293 gr->store->data, old_sc, new_sc, NULL), finally);
294
295 // Overall success even if rc of underlying fn was VOLK_NOACTION.
296 if (rc == VOLK_NOACTION) rc = VOLK_OK;
297 }
298
299 VOLK_term_free (gr->uri);
300 gr->uri = uri;
301
302finally:
303 if (old_sc) VOLK_buffer_free (old_sc);
304 if (new_sc) VOLK_buffer_free (new_sc);
305
306 return rc;
307}
308
309
310size_t
311VOLK_graph_size (const VOLK_Graph *gr)
312{
313 size_t ct = 0;
314 VOLK_Buffer *sc = VOLK_term_serialize (gr->uri);
315 void *it = gr->store->sif->lookup_fn (
316 gr->store->data, NULL, NULL, NULL, sc, NULL, &ct);
317 if (!it) {
318 log_error ("Error initializing lookup.");
319 ct = -1;
320 }
321 gr->store->sif->lu_free_fn (it);
322
323 VOLK_buffer_free (sc);
324
325 return ct;
326}
327
328
329bool
330VOLK_graph_equals (const VOLK_Graph *gr1, const VOLK_Graph *gr2)
331{
332 VOLK_Graph *res = VOLK_graph_new (NULL, NULL);
333 VOLK_graph_bool_op (VOLK_BOOL_XOR, gr1, gr2, res);
334 bool ret = (VOLK_graph_size (res) == 0);
335
336 VOLK_graph_free (res);
337
338 return ret;
339}
340
341
342VOLK_GraphIterator *
343VOLK_graph_add_init_txn (void *txn, VOLK_Graph *gr)
344{
345 VOLK_GraphIterator *it;
346 CALLOC_GUARD (it, NULL);
347
348 VOLK_Buffer *sc = VOLK_term_serialize (gr->uri);
349
350 it->data = gr->store->sif->add_init_fn (gr->store->data, sc, txn);
351 VOLK_buffer_free (sc);
352
353 it->graph = gr;
354
355 return it;
356}
357
358
360VOLK_graph_add_iter (VOLK_GraphIterator *it, const VOLK_Triple *spo)
361{
362 LOG_TRACE(
363 "Adding triple {%s, %s, %s} to %s",
364 spo->s->data, spo->p->data, spo->o->data,
365 VOLK_graph_uri(it->graph)->data);
366
367 // Make relative s and o.
368 VOLK_Term *rel_s, *rel_o;
369 if (spo->s->type == VOLK_TERM_IRIREF)
370 rel_s = VOLK_iriref_new_rel (it->graph->uri, spo->s);
371 else rel_s = spo->s;
372 if (spo->o->type == VOLK_TERM_IRIREF)
373 rel_o = VOLK_iriref_new_rel (it->graph->uri, spo->o);
374 else rel_o = spo->o;
375
376 VOLK_Triple *rel_spo = VOLK_triple_new (rel_s, spo->p, rel_o);
377 LOG_TRACE (
378 "Adding relative triple: {%s, %s, %s}",
379 rel_s->data, spo->p->data, rel_o->data);
380
381 // Serialize relative triple.
383 if (UNLIKELY (!sspo)) return VOLK_MEM_ERR;
384
385 // Selectively free triple members and structure.
386 if (rel_s != spo->s) VOLK_term_free (rel_s);
387 if (rel_o != spo->o) VOLK_term_free (rel_o);
388 free (rel_spo);
389
390 const VOLK_StoreInt *sif = it->graph->store->sif;
391
392 VOLK_rc rc;
393
394 PCHECK (rc = sif->add_iter_fn (it->data, sspo), finally);
395
396 // Store datatype term permanently.
397 if (rc == VOLK_OK && sif->add_term_fn) {
398 for (int i = 0; i < 3; i++) {
399 VOLK_Term *term = VOLK_triple_pos (spo, i);
400 if (term->type == VOLK_TERM_LITERAL) {
401 VOLK_Buffer *ser_dtype = VOLK_term_serialize (term->datatype);
402 void *txn =
403 sif->features & VOLK_STORE_TXN ?
404 sif->iter_txn_fn (it->data) : NULL;
405 VOLK_rc term_rc = sif->add_term_fn (
406 it->graph->store->data, ser_dtype, txn);
407 PCHECK (term_rc, finally);
408 VOLK_buffer_free (ser_dtype);
409 }
410 }
411 }
412
413
414finally:
415 VOLK_btriple_free (sspo);
416
417 return rc;
418}
419
420
423 void *txn, VOLK_Graph *gr, VOLK_Triple *const *trp, size_t *ct)
424{
426
427 // Initialize iterator.
428 VOLK_GraphIterator *it = VOLK_graph_add_init_txn (txn, gr);
429
430 if (ct) *ct = 0;
431 // Serialize and insert RDF triples.
432 for (size_t i = 0; trp[i] != NULL; i++) {
433 LOG_TRACE("Inserting triple #%lu", i);
434
435 VOLK_rc db_rc = VOLK_graph_add_iter (it, trp[i]);
436
437 if (db_rc == VOLK_OK) {
438 rc = VOLK_OK;
439 if (ct) (*ct)++;
440 // A duplicate will return VOLK_NOACTION and not increment ct.
441 }
442 if (UNLIKELY (db_rc < 0)) {
443 rc = db_rc;
444 goto finally;
445 }
446 }
447
448finally:
450
451 return rc;
452}
453
454
457 void *txn, VOLK_Graph *gr,
458 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o,
459 size_t *ct)
460{
462 *ss = VOLK_term_serialize (s),
463 *sp = VOLK_term_serialize (p),
464 *so = VOLK_term_serialize (o),
465 *sc = VOLK_term_serialize (gr->uri);
466
467 VOLK_rc rc = gr->store->sif->remove_fn (
468 gr->store->data, ss, sp, so, sc, txn, ct);
469
470 VOLK_buffer_free (ss);
471 VOLK_buffer_free (sp);
472 VOLK_buffer_free (so);
473 VOLK_buffer_free (sc);
474
475 return rc;
476}
477
478
481 void *txn, const VOLK_Graph *src, VOLK_Graph *dest,
482 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o)
483{
485
486 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (txn, src, s, p, o, NULL);
487
488 VOLK_Triple *spo = NULL;
489 VOLK_GraphIterator *add_it = VOLK_graph_add_init_txn (txn, dest);
490 while (VOLK_graph_iter_next (it, &spo) != VOLK_END) {
491 VOLK_rc add_rc = VOLK_graph_add_iter (add_it, spo);
492 VOLK_triple_free (spo);
493 if (LIKELY (add_rc == VOLK_OK)) rc = VOLK_OK;
494 else if (add_rc < 0) {
495 rc = add_rc;
496 break;
497 }
498 }
499
500 VOLK_graph_iter_free (add_it);
502
503 return rc;
504}
505
506
507VOLK_GraphIterator *
509 void *txn, const VOLK_Graph *gr,
510 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o,
511 size_t *ct)
512{
513 VOLK_GraphIterator *it;
514 MALLOC_GUARD (it, NULL);
515
516 // Make relative s and o.
517 VOLK_Term *rel_s, *rel_o;
518 if (s && s->type == VOLK_TERM_IRIREF) {
519 rel_s = VOLK_iriref_new_rel (gr->uri, s);
520 LOG_DEBUG ("Relative S lookup: %s", rel_s->data);
521 } else rel_s = (VOLK_Term *)s;
522 if (o && o->type == VOLK_TERM_IRIREF) {
523 rel_o = VOLK_iriref_new_rel (gr->uri, o);
524 LOG_DEBUG ("Relative O lookup: %s", rel_o->data);
525 } else rel_o = (VOLK_Term *)o;
526
528 *ss = VOLK_term_serialize (rel_s),
529 *sp = VOLK_term_serialize (p),
530 *so = VOLK_term_serialize (rel_o),
531 *sc = VOLK_term_serialize (gr->uri);
532
533 // Selectively free triple members and structure.
534 if (rel_s != s) VOLK_term_free (rel_s);
535 if (rel_o != o) VOLK_term_free (rel_o);
536
537 it->data = gr->store->sif->lookup_fn (
538 gr->store->data, ss, sp, so, sc, txn, ct);
539
540 VOLK_buffer_free (ss);
541 VOLK_buffer_free (sp);
542 VOLK_buffer_free (so);
543 VOLK_buffer_free (sc);
544
545 if (UNLIKELY (!it->data)) {
546 free (it);
547 return NULL;
548 }
549
550 it->graph = gr;
551
552 if (it->graph->store->sif->features & VOLK_STORE_COW) {
553 // Copy-on-write store.
554 it->sspo = BTRP_DUMMY;
555 if (UNLIKELY (it->sspo == NULL)) return NULL;
556 it->sspo->s->flags |= VOLK_BUF_BORROWED;
557 it->sspo->p->flags |= VOLK_BUF_BORROWED;
558 it->sspo->o->flags |= VOLK_BUF_BORROWED;
559 } else {
560 // TODO copy-on-retrieval store. No implementations yet.
561 }
562
563 return it;
564}
565
566
568VOLK_graph_iter_next (VOLK_GraphIterator *it, VOLK_Triple **spo_p)
569{
570 VOLK_rc rc = graph_iter_next_buffer (it);
571 PRCCK (rc);
572 if (rc != VOLK_OK) return rc;
573
575 VOLK_term_new_from_buffer (it->sspo->s),
576 VOLK_term_new_from_buffer (it->sspo->p),
577 VOLK_term_new_from_buffer (it->sspo->o)
578 );
579 if (UNLIKELY (!spo)) return VOLK_MEM_ERR;
580
581 *spo_p = spo;
582
583 return VOLK_OK;
584}
585
586
587const VOLK_Graph *
588VOLK_graph_iter_graph (VOLK_GraphIterator *it)
589{ return it->graph; }
590
591
592bool
593VOLK_graph_iter_is_add (VOLK_GraphIterator *it)
594{ return it->sspo == NULL; }
595
596
597void
598VOLK_graph_iter_free (VOLK_GraphIterator *it)
599{
600 if (UNLIKELY (!it)) return;
601
602 if (it->sspo) {
603 // Free lookup iterator.
604 it->graph->store->sif->lu_free_fn (it->data);
605
606 /*
607 * This deallocates resources properly by preserving borrowed pointers
608 * from the store in case of VOLK_STORE_COW stores.
609 */
610 if (it->graph->store->sif->features & VOLK_STORE_COW) {
611 VOLK_btriple_free (it->sspo);
612 LOG_DEBUG("Freeing dummy triple @ %p", it->sspo);
613 } else {
614 // TODO copy-on-retrieval stores. None yet.
615 }
616
617 } else {
618 // Add iterator has sspo == NULL. Use add_done_fn for that.
619 it->graph->store->sif->add_done_fn (it->data);
620 }
621
622 free (it);
623}
624
625
628{
629 VOLK_Buffer **tdata = VOLK_store_ctx_list_txn (store, txn);
630 if (UNLIKELY (!tdata)) return NULL;
631
633
634 size_t i = 0;
635 while (tdata[i]) {
636 VOLK_Term *t = VOLK_term_new_from_buffer (tdata[i]);
637 VOLK_rc rc = VOLK_term_set_add (ts, t, NULL);
638 VOLK_buffer_free (tdata[i]);
639 if (UNLIKELY (rc != VOLK_OK)) {
640 VOLK_term_free (t);
642
643 return NULL;
644 }
645 i++;
646 }
647 free (tdata);
648
649 return ts;
650}
651
652
653bool
654VOLK_graph_contains (const VOLK_Graph *gr, const VOLK_Triple *spo)
655{
656 VOLK_GraphIterator *it = VOLK_graph_lookup (
657 gr, spo->s, spo->p, spo->o, NULL);
658 VOLK_Triple *tmp_spo = NULL;
659 bool rc = VOLK_graph_iter_next (it, &tmp_spo) != VOLK_END;
660
661 VOLK_triple_free (tmp_spo);
663
664 return rc;
665}
666
667
668void
669VOLK_graph_print (const VOLK_Graph *gr)
670{
671 size_t ct;
672 VOLK_GraphIterator *it = VOLK_graph_lookup (gr, NULL, NULL, NULL, &ct);
673 if (UNLIKELY (!it)) {
674 log_error ("Could not inspect graph for printing.");
675 return;
676 }
677
678 printf ("*** Graph %s (%zu triples):\n\n", gr->uri->data, ct);
679
680 VOLK_Triple *spo = NULL;
681 ct = 0;
683 while ((rc = VOLK_graph_iter_next (it, &spo)) == VOLK_OK) {
684 printf (
685 "#%-6zu {%s %s %s}\n",
686 ct, spo->s->data, spo->p->data, spo->o->data);
687 ct++;
688 }
689 if (rc != VOLK_END)
690 log_error (
691 "Output truncated due to abnormal return: %s",
692 VOLK_strerror (rc));
693}
694
695
698 const VOLK_Graph *gr, const VOLK_Term *t, const VOLK_LinkType type)
699{
700 const VOLK_Term
701 *s = NULL,
702 *p = NULL,
703 *o = NULL;
704
705 // Position of passed term and link terms, respectively.
706 VOLK_TriplePos pos1, pos2;
707
708 if (type == VOLK_LINK_INBOUND) {
709 o = t;
710 pos1 = TRP_POS_O;
711 pos2 = TRP_POS_P;
712 } else if (type == VOLK_LINK_OUTBOUND) {
713 s = t;
714 pos1 = TRP_POS_S;
715 pos2 = TRP_POS_P;
716 } else if (type == VOLK_LINK_EDGE) {
717 p = t;
718 pos1 = TRP_POS_P;
719 pos2 = TRP_POS_S;
720 } else {
721 log_error ("Invalid connection type: %d", type);
722 return NULL;
723 }
724
725 // Gather all linking terms in a set first.
726 VOLK_GraphIterator *it = VOLK_graph_lookup (gr, s, p, o, NULL);
727 if (!it) return NULL;
728
730 while (graph_iter_next_buffer (it) != VOLK_END) {
732 *ex = NULL,
734 VOLK_btriple_pos (it->sspo, pos2));
735 VOLK_term_set_add (lts, ins, &ex);
736
737 if (ex) VOLK_term_free (ins);
738 }
740
741 VOLK_LinkMap *ret = VOLK_link_map_new (t, type);
742 if (!ret) return NULL;
743 size_t i = 0;
744 VOLK_Term *lt;
745 while (VOLK_term_set_next (lts, &i, &lt) != VOLK_END) {
747 ret, VOLK_term_copy (lt),
748 VOLK_graph_term_set (gr, t, pos1, lt, pos2));
749 }
750 VOLK_term_set_free (lts);
751
752 return ret;
753}
754
755
758 const VOLK_Graph *gr, const VOLK_Term *t1, const VOLK_TriplePos t1_pos,
759 const VOLK_Term *t2, const VOLK_TriplePos t2_pos)
760{
761 if (t1_pos == t2_pos) {
762 log_error ("Term 1 and 2 positions cannot be the same!");
763 return NULL;
764 }
765
766 const VOLK_Term *spo_l[3] = {NULL};
767 spo_l[t1_pos] = t1;
768 spo_l[t2_pos] = t2;
769 VOLK_TriplePos rpos = 0; // Position of term to be added to results.
770 for (unsigned i = 0; i < 3; i++)
771 if (t1_pos != i && t2_pos != i) rpos = i;
772
773 VOLK_GraphIterator *it = VOLK_graph_lookup (
774 gr, spo_l[0], spo_l[1], spo_l[2], NULL);
775
777 while (graph_iter_next_buffer (it) != VOLK_END) {
778 // There cannot be duplicates in a 2-bound lookup.
780 ts,
782 NULL);
783 }
785
786 return ts;
787}
788
789
791VOLK_graph_unique_terms (const VOLK_Graph *gr, VOLK_TriplePos pos)
792{
793 // TODO We should use spo indices for stores that have them...
794 VOLK_GraphIterator *it = VOLK_graph_lookup (gr, NULL, NULL, NULL, NULL);
795
797 while (graph_iter_next_buffer (it) != VOLK_END) {
799 *ex = NULL,
800 *ins = VOLK_term_new_from_buffer (VOLK_btriple_pos (it->sspo, pos));
801 VOLK_term_set_add (ts, ins, &ex);
802
803 if (ex) VOLK_term_free (ins);
804 }
806
807 return ts;
808}
809
810
811size_t
812VOLK_graph_add_link_map (VOLK_GraphIterator *it, VOLK_LinkMap *lm)
813{
814 VOLK_Triple *spo = TRP_DUMMY;
815 size_t ct = 0;
816 VOLK_LinkMapIterator *lmit = VOLK_link_map_iter_new (lm);
817
818 while (VOLK_link_map_triples (lmit, spo) != VOLK_END) {
819 VOLK_rc rc = VOLK_graph_add_iter (it, spo);
820 if (rc >= 0) ct++;
821 PRCCK (rc);
822 }
824 free (spo);
825
826 return ct;
827}
828
829
830VOLK_Term *
831VOLK_bnode_add_collection (VOLK_GraphIterator *it, VOLK_TermSet *ts)
832{
834 *s = VOLK_term_new (VOLK_TERM_BNODE, NULL, NULL),
835 *rdf_first = VOLK_iriref_new ("rdf:first"),
836 *rdf_rest = VOLK_iriref_new ("rdf:rest"),
837 *rdf_nil = VOLK_iriref_new ("rdf:nil"),
838 *link;
839
840 VOLK_Triple *spo = TRP_DUMMY;
841 link = s;
842 size_t i = 0;
843 VOLK_Term *t;
844 while (VOLK_term_set_next (ts, &i, &t) != VOLK_END) {
845 spo->s = link;
846 spo->p = rdf_first;
847 spo->o = t;
848 PRCNL (VOLK_graph_add_iter (it, spo));
849
850 spo->p = rdf_rest;
851 size_t save_i = i; // Save iterator position to restore it after peek.
852 spo->o = (
853 // Peek into the next result.
854 VOLK_term_set_next (ts, &i, NULL) != VOLK_END ?
855 VOLK_term_new (VOLK_TERM_BNODE, NULL, NULL)
856 : rdf_nil);
857 i = save_i; // Restore the iterator that advanced when peeking.
858
859 PRCNL (VOLK_graph_add_iter (it, spo));
860
861 if (link != s) VOLK_term_free (link);
862 // Current object becomes next subject. Irrelevant for last item.
863 link = spo->o;
864 }
865
866 VOLK_term_free (rdf_first);
867 VOLK_term_free (rdf_rest);
868 VOLK_term_free (rdf_nil);
869 free (spo);
870
871 return s;
872}
873
874
875/*
876 * Static functions.
877 */
878
886inline static VOLK_rc
887graph_iter_next_buffer (VOLK_GraphIterator *it)
888{ return it->graph->store->sif->lu_next_fn (it->data, it->sspo, NULL); }
889
890
894
895size_t VOLK_graph_size (const VOLK_Graph *gr);
896VOLK_Graph * VOLK_graph_new_ns (VOLK_Store *store, const char *ns_str);
#define UNLIKELY(x)
Definition core.h:39
#define LIKELY(x)
Definition core.h:38
bool VOLK_graph_iter_is_add(VOLK_GraphIterator *it)
Definition graph.c:593
VOLK_Buffer * VOLK_btriple_pos(const VOLK_BufferTriple *trp, VOLK_TriplePos n)
Get serialized triple by term position.
Definition buffer.h:297
#define BTRP_DUMMY
Dummy buffer triple.
Definition buffer.h:336
void VOLK_btriple_free(VOLK_BufferTriple *sspo)
Free a buffer triple and all its internal pointers.
Definition buffer.c:147
VOLK_TriplePos
Triple position of s, p, o.
Definition buffer.h:19
void VOLK_buffer_free(VOLK_Buffer *buf)
Free a buffer.
Definition buffer.c:97
@ VOLK_BUF_BORROWED
Definition buffer.h:28
@ TRP_POS_O
Definition buffer.h:22
@ TRP_POS_S
Definition buffer.h:20
@ TRP_POS_P
Definition buffer.h:21
#define VOLK_graph_lookup(...)
Non-transactional version of VOLK_graph_lookup_txn.
Definition graph.h:364
VOLK_Graph * VOLK_graph_new_ns(VOLK_Store *store, const char *ns_str)
Create an empty graph using a namespace-prefixed string for its URI.
Definition graph.h:54
const VOLK_Graph * VOLK_graph_iter_graph(VOLK_GraphIterator *it)
Return the graph related to an iterator.
Definition graph.c:588
VOLK_TermSet * VOLK_graph_list_txn(void *txn, VOLK_Store *store)
List all graph URIs in a store.
Definition graph.c:627
void VOLK_graph_print(const VOLK_Graph *gr)
Print graph information and triples to stdout.
Definition graph.c:669
VOLK_LinkMap * VOLK_graph_connections(const VOLK_Graph *gr, const VOLK_Term *t, const VOLK_LinkType type)
Get term pairs connected to a term in a graph.
Definition graph.c:697
VOLK_Graph * VOLK_graph_get_txn(void *txn, VOLK_Store *store, const VOLK_Term *uri, size_t *ct)
Create a temp graph from stored triples.
Definition graph.c:63
size_t VOLK_graph_add_link_map(VOLK_GraphIterator *it, VOLK_LinkMap *lm)
Add triples for a term and related link map to a graph.
Definition graph.c:812
bool VOLK_graph_contains(const VOLK_Graph *gr, const VOLK_Triple *spo)
Whether a graph contains a triple.
Definition graph.c:654
bool VOLK_graph_equals(const VOLK_Graph *gr1, const VOLK_Graph *gr2)
Compare two graphs.
Definition graph.c:330
VOLK_rc VOLK_graph_remove_txn(void *txn, VOLK_Graph *gr, const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o, size_t *ct)
Delete triples by a matching pattern.
Definition graph.c:456
VOLK_rc VOLK_graph_copy_contents_txn(void *txn, const VOLK_Graph *src, VOLK_Graph *dest, const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o)
Copy triples from a source graph into a destination one.
Definition graph.c:480
void VOLK_graph_free(VOLK_Graph *gr)
Free a graph.
Definition graph.c:246
VOLK_rc VOLK_graph_add_txn(void *txn, VOLK_Graph *gr, VOLK_Triple *const *trp, size_t *ct)
Add triples to a graph.
Definition graph.c:422
VOLK_GraphIterator * VOLK_graph_lookup_txn(void *txn, const VOLK_Graph *gr, const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o, size_t *ct)
Look up triples by a matching pattern and yield an iterator.
Definition graph.c:508
#define VOLK_graph_copy_contents(...)
Definition graph.h:134
VOLK_rc VOLK_graph_bool_op_txn(void *txn, const VOLK_bool_op op, const VOLK_Graph *gr1, const VOLK_Graph *gr2, VOLK_Graph *res)
Definition graph.c:100
VOLK_TermSet * VOLK_graph_unique_terms(const VOLK_Graph *gr, VOLK_TriplePos pos)
Get all unique subjcts, predicates, or objects in a graph.
Definition graph.c:791
#define VOLK_graph_bool_op(...)
Non-transactional version of VOLK_graph_bool_op_txn.
Definition graph.h:184
VOLK_Store * VOLK_graph_store(const VOLK_Graph *gr)
Underlying graph store handle.
Definition graph.c:267
VOLK_GraphIterator * VOLK_graph_add_init_txn(void *txn, VOLK_Graph *gr)
Initialize an iterator to add triples.
Definition graph.c:343
VOLK_rc VOLK_graph_iter_next(VOLK_GraphIterator *it, VOLK_Triple **spo_p)
Advance a cursor obtained by a lookup and return a matching triple.
Definition graph.c:568
VOLK_rc VOLK_graph_set_uri(VOLK_Graph *gr, const char *uri_str)
Definition graph.c:272
VOLK_Term * VOLK_bnode_add_collection(VOLK_GraphIterator *it, VOLK_TermSet *ts)
Add triples for an anonymous collection to a graph.
Definition graph.c:831
VOLK_rc VOLK_graph_add_iter(VOLK_GraphIterator *it, const VOLK_Triple *spo)
Add a single triple to the store.
Definition graph.c:360
void VOLK_graph_iter_free(VOLK_GraphIterator *it)
Free a graph iterator.
Definition graph.c:598
VOLK_TermSet * VOLK_graph_term_set(const VOLK_Graph *gr, const VOLK_Term *t1, const VOLK_TriplePos t1_pos, const VOLK_Term *t2, const VOLK_TriplePos t2_pos)
Get a list of terms related to a term pair in a graph.
Definition graph.c:757
VOLK_Graph * VOLK_graph_new(VOLK_Store *store, const char *uri_str)
Create new graph.
Definition graph.c:44
const VOLK_Term * VOLK_graph_uri(const VOLK_Graph *gr)
Read-only graph URI.
Definition graph.c:263
size_t VOLK_graph_size(const VOLK_Graph *gr)
Number of triples in a graph.
Definition graph.c:311
#define MALLOC_GUARD(var, rc)
Allocate one pointer with malloc and return rc if it fails.
Definition core.h:375
#define PCHECK(exp, marker)
Jump to marker if exp returns a negative value (skip warnings).
Definition core.h:303
#define LOG_TRACE(...)
Definition core.h:276
#define PRCNL(exp)
Return NULL if exp returns a negative value (=error).
Definition core.h:356
#define CHECK(exp, marker)
Jump to marker if exp does not return VOLK_OK.
Definition core.h:291
#define LOG_DEBUG(...)
Definition core.h:275
#define CALLOC_GUARD(var, rc)
Allocate one pointer with calloc and return rc if it fails.
Definition core.h:381
#define PRCCK(exp)
Return exp return value if it is of VOLK_rc type and negative (=error).
Definition core.h:334
VOLK_bool_op
Boolean operations that can be performed on a graph.
Definition core.h:221
@ VOLK_BOOL_XOR
Boolean XOR.
Definition core.h:225
@ VOLK_BOOL_UNION
Boolean union.
Definition core.h:222
@ VOLK_BOOL_SUBTRACTION
Boolean subtraction.
Definition core.h:223
@ VOLK_BOOL_INTERSECTION
Boolean intersection.
Definition core.h:224
#define VOLK_VALUE_ERR
An invalid input value was provided.
Definition core.h:129
#define VOLK_MEM_ERR
Memory allocation error.
Definition core.h:144
#define VOLK_NORESULT
No result yielded.
Definition core.h:100
#define VOLK_DB_ERR
Low-level database error.
Definition core.h:135
#define VOLK_END
Loop end.
Definition core.h:107
#define VOLK_OK
Generic success return code.
Definition core.h:83
#define VOLK_NOACTION
No action taken.
Definition core.h:93
int VOLK_rc
Definition core.h:79
const char * VOLK_strerror(VOLK_rc rc)
Return an error message for a return code.
Definition core.c:195
@ VOLK_STORE_TXN
Supports transaction handling.
@ VOLK_STORE_EMBED
@ VOLK_STORE_COW
Copy on write.
@ VOLK_STORE_CTX
VOLK_Buffer ** VOLK_store_ctx_list_txn(VOLK_Store *store, void *txn)
get index of all graph (context) URIs in a store.
Definition store.c:226
VOLK_StoreType
Store types. All prefixed with VOLK_STORE_.
Definition store.h:39
VOLK_Store * VOLK_store_new(const VOLK_StoreType store_type, const char *store_id, size_t size, bool clear)
Create a new store.
Definition store.c:28
#define BACKEND_TBL
Definition store.h:32
VOLK_rc VOLK_term_set_add(VOLK_TermSet *ts, VOLK_Term *term, VOLK_Term **existing)
Add term to a term set.
Definition term.c:562
VOLK_Triple * VOLK_triple_new_from_btriple(const VOLK_BufferTriple *sspo)
Definition term.c:471
struct hashmap VOLK_TermSet
a set of unique terms.
Definition term.h:124
VOLK_rc VOLK_term_set_next(VOLK_TermSet *ts, size_t *i, VOLK_Term **term)
Iterate trough a term set.
Definition term.c:592
VOLK_Triple * VOLK_triple_new(VOLK_Term *s, VOLK_Term *p, VOLK_Term *o)
Create a new triple from three terms.
Definition term.c:456
VOLK_Term * VOLK_iriref_new_rel(const VOLK_Term *root, const VOLK_Term *iri)
Create a new relative IRI from an absolute IRI and a web root IRI.
Definition term.c:273
void VOLK_link_map_iter_free(VOLK_LinkMapIterator *it)
Free a link map iterator.
Definition term.c:707
VOLK_LinkType
Link type.
Definition term.h:94
VOLK_Term * VOLK_iriref_new(const char *data)
Create an IRI reference.
Definition term.h:192
VOLK_LinkMapIterator * VOLK_link_map_iter_new(const VOLK_LinkMap *lmap)
Create a new iterator to loop through a link map.
Definition term.c:695
VOLK_LinkMap * VOLK_link_map_new(const VOLK_Term *linked_term, VOLK_LinkType type)
New link map.
Definition term.c:617
VOLK_rc VOLK_link_map_triples(VOLK_LinkMapIterator *it, VOLK_Triple *spo)
Iterate over a link map and generate triples.
Definition term.c:726
VOLK_TermSet * VOLK_term_set_new()
Create a new term set.
Definition term.c:549
void VOLK_term_set_free(VOLK_TermSet *ts)
Free a term set.
Definition term.c:604
#define TRP_DUMMY
Dummy triple with NULL slots. It is not a valid triple.
Definition term.h:442
void VOLK_term_free(VOLK_Term *term)
Definition term.c:387
VOLK_Term * VOLK_triple_pos(const VOLK_Triple *trp, VOLK_TriplePos n)
Get triple by term position.
Definition term.h:499
VOLK_Buffer * VOLK_term_serialize(const VOLK_Term *term)
Serialize a term into a buffer.
Definition term.c:293
VOLK_Term * VOLK_term_new_from_buffer(const VOLK_Buffer *sterm)
See notes in VOLK_term_serialize function body for format info.
Definition term.c:189
VOLK_rc VOLK_link_map_add(VOLK_LinkMap *lmap, VOLK_Term *term, VOLK_TermSet *tset)
Add a term - term set pair to a link map.
Definition term.c:652
VOLK_BufferTriple * VOLK_triple_serialize(const VOLK_Triple *spo)
Definition term.c:485
VOLK_Term * VOLK_term_new(VOLK_TermType type, const char *data, void *metadata)
Create a new term.
Definition term.c:157
void VOLK_triple_free(VOLK_Triple *spo)
Free a triple and all its internal pointers.
Definition term.c:532
VOLK_Term * VOLK_term_copy(const VOLK_Term *src)
Copy a term.
Definition term.c:174
@ VOLK_LINK_EDGE
Edge link (so).
Definition term.h:97
@ VOLK_LINK_INBOUND
Inbound link (sp).
Definition term.h:95
@ VOLK_LINK_OUTBOUND
Outbound link (po).
Definition term.h:96
@ VOLK_TERM_IRIREF
IRI reference.
Definition term.h:35
@ VOLK_TERM_LITERAL
Literal without language tag.
Definition term.h:36
@ VOLK_TERM_BNODE
Blank node.
Definition term.h:38
Triple of byte buffers.
Definition buffer.h:60
VOLK_Buffer * o
Definition buffer.h:63
VOLK_Buffer * s
Definition buffer.h:61
VOLK_Buffer * p
Definition buffer.h:62
General-purpose data buffer.
Definition buffer.h:47
Store interface.
VOLK_StoreFeature features
Feature flags.
iter_free_fn_t lu_free_fn
Free the lookup iterator.
store_add_iter_fn_t add_iter_fn
Add one triple.
store_add_term_fn_t add_term_fn
iter_txn_fn_t iter_txn_fn
Get iterator's transaction.
iter_next_fn_t lu_next_fn
Advance the lookup iterator.
store_lookup_fn_t lookup_fn
Look up triples by pattern. 
Store structure.
Definition store.h:59
void * data
Store back end data.
Definition store.h:67
const VOLK_StoreInt * sif
Store interface.
Definition store.h:66
RDF term.
Definition term.h:62
char * data
URI, literal value, or BNode label.
Definition term.h:63
struct term_t * datatype
Data type IRI for VOLK_TERM_LITERAL.
Definition term.h:65
VOLK_TermType type
Term type.
Definition term.h:70
RDF triple.
Definition term.h:86
VOLK_Term * p
Predicate.
Definition term.h:88
VOLK_Term * s
Subject.
Definition term.h:87
VOLK_Term * o
Object.
Definition term.h:89
Graph iterator.
Definition graph.c:12
const VOLK_Graph * graph
Parent graph.
Definition graph.c:13
size_t ct
Total lookup matches.
Definition graph.c:15
void * data
Iterator state.
Definition graph.c:14
VOLK_BufferTriple * sspo
Definition graph.c:16
Graph object.
Definition graph.c:7
VOLK_Store * store
Store handle.
Definition graph.c:9
VOLK_Term * uri
Graph "name" (URI).
Definition graph.c:8