1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rasqal_graph_pattern.c - Rasqal graph pattern class
4 *
5 * Copyright (C) 2004-2010, David Beckett http://www.dajobe.org/
6 * Copyright (C) 2004-2005, 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 #ifdef HAVE_CONFIG_H
26 #include <rasqal_config.h>
27 #endif
28
29 #ifdef WIN32
30 #include <win32_rasqal_config.h>
31 #endif
32
33 #include <stdio.h>
34 #include <string.h>
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 #include <stdarg.h>
39
40 #include "rasqal.h"
41 #include "rasqal_internal.h"
42
43
44 /*
45 * rasqal_new_graph_pattern:
46 * @query: #rasqal_graph_pattern query object
47 * @op: enum #rasqal_graph_pattern_operator operator
48 *
49 * INTERNAL - Create a new graph pattern object.
50 *
51 * NOTE: This does not initialise the graph pattern completely
52 * but relies on other operations. The empty graph pattern
53 * has no triples and no sub-graphs.
54 *
55 * Return value: a new #rasqal_graph_pattern object or NULL on failure
56 **/
57 static rasqal_graph_pattern*
rasqal_new_graph_pattern(rasqal_query * query,rasqal_graph_pattern_operator op)58 rasqal_new_graph_pattern(rasqal_query* query,
59 rasqal_graph_pattern_operator op)
60 {
61 rasqal_graph_pattern* gp;
62
63 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
64
65 gp = RASQAL_CALLOC(rasqal_graph_pattern*, 1, sizeof(*gp));
66 if(!gp)
67 return NULL;
68
69 gp->op = op;
70
71 gp->query = query;
72 gp->triples = NULL;
73 gp->start_column = -1;
74 gp->end_column = -1;
75
76 /* This is initialised by
77 * rasqal_query_prepare_count_graph_patterns() inside
78 * rasqal_query_prepare()
79 */
80 gp->gp_index = -1;
81
82 return gp;
83 }
84
85
86 /*
87 * rasqal_new_basic_graph_pattern:
88 * @query: #rasqal_graph_pattern query object
89 * @triples: triples sequence containing the graph pattern
90 * @start_column: first triple in the pattern
91 * @end_column: last triple in the pattern
92 *
93 * INTERNAL - Create a new graph pattern object over triples.
94 *
95 * Return value: a new #rasqal_graph_pattern object or NULL on failure
96 **/
97 rasqal_graph_pattern*
rasqal_new_basic_graph_pattern(rasqal_query * query,raptor_sequence * triples,int start_column,int end_column)98 rasqal_new_basic_graph_pattern(rasqal_query* query,
99 raptor_sequence *triples,
100 int start_column, int end_column)
101 {
102 rasqal_graph_pattern* gp;
103
104 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
105 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(triples, raptor_sequence, NULL);
106
107 gp = rasqal_new_graph_pattern(query, RASQAL_GRAPH_PATTERN_OPERATOR_BASIC);
108 if(!gp)
109 return NULL;
110
111 gp->triples = triples;
112 gp->start_column = start_column;
113 gp->end_column = end_column;
114
115 return gp;
116 }
117
118
119 /*
120 * rasqal_new_graph_pattern_from_sequence:
121 * @query: #rasqal_graph_pattern query object
122 * @graph_patterns: sequence containing the graph patterns (or NULL)
123 * @operator: enum #rasqal_graph_pattern_operator such as
124 * RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL
125 *
126 * INTERNAL - Create a new graph pattern from a sequence of graph_patterns.
127 *
128 * Return value: a new #rasqal_graph_pattern object or NULL on failure
129 **/
130 rasqal_graph_pattern*
rasqal_new_graph_pattern_from_sequence(rasqal_query * query,raptor_sequence * graph_patterns,rasqal_graph_pattern_operator op)131 rasqal_new_graph_pattern_from_sequence(rasqal_query* query,
132 raptor_sequence *graph_patterns,
133 rasqal_graph_pattern_operator op)
134 {
135 rasqal_graph_pattern* gp;
136
137 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
138
139 gp = rasqal_new_graph_pattern(query, op);
140 if(!gp) {
141 if(graph_patterns)
142 raptor_free_sequence(graph_patterns);
143 return NULL;
144 }
145
146 gp->graph_patterns = graph_patterns;
147 return gp;
148 }
149
150
151 /*
152 * rasqal_new_filter_graph_pattern:
153 * @query: #rasqal_graph_pattern query object
154 * @expr: expression
155 *
156 * INTERNAL - Create a new graph pattern from a sequence of graph_patterns.
157 *
158 * Return value: a new #rasqal_graph_pattern object or NULL on failure
159 **/
160 rasqal_graph_pattern*
rasqal_new_filter_graph_pattern(rasqal_query * query,rasqal_expression * expr)161 rasqal_new_filter_graph_pattern(rasqal_query* query,
162 rasqal_expression* expr)
163 {
164 rasqal_graph_pattern* gp;
165
166 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
167 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(expr, rasqal_expression, NULL);
168
169 gp = rasqal_new_graph_pattern(query, RASQAL_GRAPH_PATTERN_OPERATOR_FILTER);
170 if(!gp) {
171 rasqal_free_expression(expr);
172 return NULL;
173 }
174
175 if(rasqal_graph_pattern_set_filter_expression(gp, expr)) {
176 rasqal_free_graph_pattern(gp);
177 gp = NULL;
178 }
179
180 return gp;
181 }
182
183
184 /*
185 * rasqal_new_let_graph_pattern:
186 * @query: #rasqal_graph_pattern query object
187 * @var: variable to assign
188 * @expr: expression
189 *
190 * INTERNAL - Create a new assignment graph pattern
191 *
192 * Return value: a new #rasqal_graph_pattern object or NULL on failure
193 **/
194 rasqal_graph_pattern*
rasqal_new_let_graph_pattern(rasqal_query * query,rasqal_variable * var,rasqal_expression * expr)195 rasqal_new_let_graph_pattern(rasqal_query *query,
196 rasqal_variable *var,
197 rasqal_expression *expr)
198 {
199 rasqal_graph_pattern* gp;
200
201 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
202 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(var, rasqal_variable, NULL);
203 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(expr, rasqal_expression, NULL);
204
205 gp = rasqal_new_graph_pattern(query, RASQAL_GRAPH_PATTERN_OPERATOR_LET);
206 if(!gp) {
207 rasqal_free_expression(expr);
208 return NULL;
209 }
210
211 gp->var = var;
212 gp->filter_expression = expr;
213
214 return gp;
215 }
216
217
218 /*
219 * rasqal_new_select_graph_pattern:
220 * @query: #rasqal_graph_pattern query object
221 * @projection: projection object
222 * @data_graphs: sequence of #rasqal_data_graph (or NULL)
223 * @where: WHERE graph pattern
224 * @modifier: solution modifier
225 * @bindings: binding VALUES (or NULL)
226 *
227 * INTERNAL - Create a new SELECT graph pattern
228 *
229 * The @projection, @data_graphs, @where and @modifier all become owned
230 * by the new graph pattern object.
231 *
232 * Roughly corresponds to:
233 * SELECT DISTINCT [in @projection] {@projection}
234 * FROM @data_graphs
235 * WHERE @where
236 * GROUP BY (HAVING)/ORDER BY [in @modifier]
237 *
238 * Return value: a new #rasqal_graph_pattern object or NULL on failure
239 **/
240 rasqal_graph_pattern*
rasqal_new_select_graph_pattern(rasqal_query * query,rasqal_projection * projection,raptor_sequence * data_graphs,rasqal_graph_pattern * where,rasqal_solution_modifier * modifier,rasqal_bindings * bindings)241 rasqal_new_select_graph_pattern(rasqal_query *query,
242 rasqal_projection* projection,
243 raptor_sequence* data_graphs,
244 rasqal_graph_pattern* where,
245 rasqal_solution_modifier* modifier,
246 rasqal_bindings* bindings)
247 {
248 rasqal_graph_pattern* gp;
249
250 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
251 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(projection, rasqal_projeciton, NULL);
252 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(where, rasqal_graph_pattern, NULL);
253
254 gp = rasqal_new_graph_pattern(query, RASQAL_GRAPH_PATTERN_OPERATOR_SELECT);
255 if(!gp) {
256 rasqal_free_projection(projection);
257 if(where)
258 rasqal_free_graph_pattern(where);
259
260 if(modifier)
261 rasqal_free_solution_modifier(modifier);
262
263 if(bindings)
264 rasqal_free_bindings(bindings);
265
266 return NULL;
267 }
268
269 gp->projection = projection;
270 gp->data_graphs = data_graphs;
271 gp->modifier = modifier;
272 gp->bindings = bindings;
273
274 if(rasqal_graph_pattern_add_sub_graph_pattern(gp, where)) {
275 rasqal_free_graph_pattern(gp);
276 return NULL;
277 }
278
279 return gp;
280 }
281
282
283 /*
284 * rasqal_new_single_graph_pattern:
285 * @query: #rasqal_graph_pattern query object
286 * @op: enum #rasqal_graph_pattern_operator operator
287 * @single: single inner graph grattern
288 *
289 * INTERNAL - Create a new graph pattern object over a single graph pattern.
290 *
291 * Return value: a new #rasqal_graph_pattern object or NULL on failure
292 **/
293 rasqal_graph_pattern*
rasqal_new_single_graph_pattern(rasqal_query * query,rasqal_graph_pattern_operator op,rasqal_graph_pattern * single)294 rasqal_new_single_graph_pattern(rasqal_query* query,
295 rasqal_graph_pattern_operator op,
296 rasqal_graph_pattern* single)
297 {
298 rasqal_graph_pattern* gp;
299
300 gp = rasqal_new_graph_pattern(query, op);
301 if(!gp) {
302 if(single)
303 rasqal_free_graph_pattern(single);
304
305 return NULL;
306 }
307
308 if(rasqal_graph_pattern_add_sub_graph_pattern(gp, single)) {
309 rasqal_free_graph_pattern(gp);
310 return NULL;
311 }
312
313 return gp;
314 }
315
316
317 /*
318 * rasqal_free_graph_pattern:
319 * @gp: #rasqal_graph_pattern object
320 *
321 * INTERNAL - Free a graph pattern object.
322 *
323 **/
324 void
rasqal_free_graph_pattern(rasqal_graph_pattern * gp)325 rasqal_free_graph_pattern(rasqal_graph_pattern* gp)
326 {
327 if(!gp)
328 return;
329
330 if(gp->graph_patterns)
331 raptor_free_sequence(gp->graph_patterns);
332
333 if(gp->filter_expression)
334 rasqal_free_expression(gp->filter_expression);
335
336 if(gp->origin)
337 rasqal_free_literal(gp->origin);
338
339 if(gp->projection)
340 rasqal_free_projection(gp->projection);
341
342 if(gp->modifier)
343 rasqal_free_solution_modifier(gp->modifier);
344
345 if(gp->data_graphs)
346 raptor_free_sequence(gp->data_graphs);
347
348 if(gp->var)
349 rasqal_free_variable(gp->var);
350
351 if(gp->bindings)
352 rasqal_free_bindings(gp->bindings);
353
354 RASQAL_FREE(rasqal_graph_pattern, gp);
355 }
356
357
358 /*
359 * rasqal_graph_pattern_adjust:
360 * @gp: #rasqal_graph_pattern graph pattern
361 * @offset: adjustment
362 *
363 * INTERNAL - Adjust the column in a graph pattern by the offset.
364 *
365 **/
366 void
rasqal_graph_pattern_adjust(rasqal_graph_pattern * gp,int offset)367 rasqal_graph_pattern_adjust(rasqal_graph_pattern* gp, int offset)
368 {
369 gp->start_column += offset;
370 gp->end_column += offset;
371 }
372
373
374 /**
375 * rasqal_graph_pattern_set_filter_expression:
376 * @gp: #rasqal_graph_pattern query object
377 * @expr: #rasqal_expression expr - ownership taken
378 *
379 * Set a filter graph pattern constraint expression
380 *
381 * Return value: non-0 on failure
382 **/
383 int
rasqal_graph_pattern_set_filter_expression(rasqal_graph_pattern * gp,rasqal_expression * expr)384 rasqal_graph_pattern_set_filter_expression(rasqal_graph_pattern* gp,
385 rasqal_expression* expr)
386 {
387 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(gp, rasqal_graph_pattern, 1);
388 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(expr, rasqal_expression, 1);
389
390 if(gp->filter_expression)
391 rasqal_free_expression(gp->filter_expression);
392
393 gp->filter_expression = expr;
394
395 return 0;
396 }
397
398
399 /**
400 * rasqal_graph_pattern_get_filter_expression:
401 * @gp: #rasqal_graph_pattern query object
402 *
403 * Get a filter graph pattern's constraint expression
404 *
405 * Return value: expression or NULL on failure
406 **/
407 rasqal_expression*
rasqal_graph_pattern_get_filter_expression(rasqal_graph_pattern * gp)408 rasqal_graph_pattern_get_filter_expression(rasqal_graph_pattern* gp)
409 {
410 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(gp, rasqal_graph_pattern, NULL);
411
412 return gp->filter_expression;
413 }
414
415
416 /**
417 * rasqal_graph_pattern_get_operator:
418 * @graph_pattern: #rasqal_graph_pattern graph pattern object
419 *
420 * Get the graph pattern operator .
421 *
422 * The operator for the given graph pattern. See also
423 * rasqal_graph_pattern_operator_as_string().
424 *
425 * Return value: graph pattern operator
426 **/
427 rasqal_graph_pattern_operator
rasqal_graph_pattern_get_operator(rasqal_graph_pattern * graph_pattern)428 rasqal_graph_pattern_get_operator(rasqal_graph_pattern* graph_pattern)
429 {
430 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern, rasqal_graph_pattern, RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN);
431
432 return graph_pattern->op;
433 }
434
435
436 static const char* const rasqal_graph_pattern_operator_labels[RASQAL_GRAPH_PATTERN_OPERATOR_LAST + 1] = {
437 "UNKNOWN",
438 "Basic",
439 "Optional",
440 "Union",
441 "Group",
442 "Graph",
443 "Filter",
444 "Let",
445 "Select",
446 "Service",
447 "Minus",
448 "Values"
449 };
450
451
452 /**
453 * rasqal_graph_pattern_operator_as_string:
454 * @op: the #rasqal_graph_pattern_operator verb of the query
455 *
456 * Get a string for the query verb.
457 *
458 * Return value: pointer to a shared string label for the query verb
459 **/
460 const char*
rasqal_graph_pattern_operator_as_string(rasqal_graph_pattern_operator op)461 rasqal_graph_pattern_operator_as_string(rasqal_graph_pattern_operator op)
462 {
463 if(op <= RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN ||
464 op > RASQAL_GRAPH_PATTERN_OPERATOR_LAST)
465 op = RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN;
466
467 return rasqal_graph_pattern_operator_labels[RASQAL_GOOD_CAST(int, op)];
468 }
469
470
471 #ifdef RASQAL_DEBUG
472 #define DO_INDENTING 0
473 #else
474 #define DO_INDENTING -1
475 #endif
476
477 #define SPACES_LENGTH 80
478 static const char spaces[SPACES_LENGTH + 1] = " ";
479
480 static void
rasqal_graph_pattern_write_indent(raptor_iostream * iostr,int indent)481 rasqal_graph_pattern_write_indent(raptor_iostream *iostr, int indent)
482 {
483 while(indent > 0) {
484 int sp = (indent > SPACES_LENGTH) ? SPACES_LENGTH : indent;
485 raptor_iostream_write_bytes(spaces, sizeof(char), RASQAL_GOOD_CAST(size_t, sp), iostr);
486 indent -= sp;
487 }
488 }
489
490
491 static void
rasqal_graph_pattern_write_plurals(raptor_iostream * iostr,const char * label,int value)492 rasqal_graph_pattern_write_plurals(raptor_iostream *iostr,
493 const char* label, int value)
494 {
495 raptor_iostream_decimal_write(value, iostr);
496 raptor_iostream_write_byte(' ', iostr);
497 raptor_iostream_string_write(label, iostr);
498
499 if(value != 1)
500 raptor_iostream_write_byte('s', iostr);
501 }
502
503
504 /**
505 * rasqal_graph_pattern_print_indent:
506 * @gp: the #rasqal_graph_pattern object
507 * @iostr: the iostream to write to
508 * @indent: the current indent level, <0 for no indenting
509 *
510 * INTERNAL - Print a #rasqal_graph_pattern in a debug format with indenting
511 *
512 **/
513 static int
rasqal_graph_pattern_write_internal(rasqal_graph_pattern * gp,raptor_iostream * iostr,int indent)514 rasqal_graph_pattern_write_internal(rasqal_graph_pattern* gp,
515 raptor_iostream* iostr, int indent)
516 {
517 int pending_nl = 0;
518
519 raptor_iostream_counted_string_write("graph pattern", 13, iostr);
520
521 if(gp->gp_index >= 0) {
522 raptor_iostream_write_byte('[', iostr);
523 raptor_iostream_decimal_write(gp->gp_index, iostr);
524 raptor_iostream_write_byte(']', iostr);
525 }
526
527 raptor_iostream_write_byte(' ', iostr);
528 raptor_iostream_string_write(rasqal_graph_pattern_operator_as_string(gp->op),
529 iostr);
530 raptor_iostream_write_byte('(', iostr);
531
532 if(indent >= 0)
533 indent += 2;
534
535 if(gp->silent) {
536 raptor_iostream_counted_string_write("silent", 6, iostr);
537 pending_nl = 1;
538 }
539
540 if(gp->triples) {
541 int size = gp->end_column - gp->start_column + 1;
542 int i;
543
544 if(pending_nl) {
545 raptor_iostream_counted_string_write(" ,", 2, iostr);
546
547 if(indent >= 0) {
548 raptor_iostream_write_byte('\n', iostr);
549 rasqal_graph_pattern_write_indent(iostr, indent);
550 }
551 }
552
553 raptor_iostream_counted_string_write("over ", 5, iostr);
554 rasqal_graph_pattern_write_plurals(iostr, "triple", size);
555 raptor_iostream_write_byte('[', iostr);
556
557 if(indent >= 0) {
558 raptor_iostream_write_byte('\n', iostr);
559 indent += 2;
560 rasqal_graph_pattern_write_indent(iostr, indent);
561 }
562
563 for(i = gp->start_column; i <= gp->end_column; i++) {
564 rasqal_triple *t = (rasqal_triple*)raptor_sequence_get_at(gp->triples, i);
565 if(i > gp->start_column) {
566 raptor_iostream_counted_string_write(" ,", 2, iostr);
567
568 if(indent >= 0) {
569 raptor_iostream_write_byte('\n', iostr);
570 rasqal_graph_pattern_write_indent(iostr, indent);
571 }
572 }
573 rasqal_triple_write(t, iostr);
574 }
575
576 if(indent >= 0) {
577 raptor_iostream_write_byte('\n', iostr);
578 indent -= 2;
579 rasqal_graph_pattern_write_indent(iostr, indent);
580 }
581
582 raptor_iostream_write_byte(']', iostr);
583
584 pending_nl = 1;
585 }
586
587 if(gp->origin) {
588 if(pending_nl) {
589 raptor_iostream_counted_string_write(" ,", 2, iostr);
590
591 if(indent >= 0) {
592 raptor_iostream_write_byte('\n', iostr);
593 rasqal_graph_pattern_write_indent(iostr, indent);
594 }
595 }
596
597 raptor_iostream_counted_string_write("origin ", 7, iostr);
598
599 rasqal_literal_write(gp->origin, iostr);
600
601 pending_nl = 1;
602 }
603
604 if(gp->graph_patterns) {
605 int size = raptor_sequence_size(gp->graph_patterns);
606 int i;
607
608 if(pending_nl) {
609 raptor_iostream_counted_string_write(" ,", 2, iostr);
610
611 if(indent >= 0) {
612 raptor_iostream_write_byte('\n', iostr);
613 rasqal_graph_pattern_write_indent(iostr, indent);
614 }
615 }
616
617 raptor_iostream_counted_string_write("over ", 5, iostr);
618 rasqal_graph_pattern_write_plurals(iostr, "graph pattern", size);
619 raptor_iostream_write_byte('[', iostr);
620
621 if(indent >= 0) {
622 raptor_iostream_write_byte('\n', iostr);
623 indent += 2;
624 rasqal_graph_pattern_write_indent(iostr, indent);
625 }
626
627 for(i = 0; i< size; i++) {
628 rasqal_graph_pattern* sgp;
629 sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
630 if(i) {
631 raptor_iostream_counted_string_write(" ,", 2, iostr);
632 if(indent >= 0) {
633 raptor_iostream_write_byte('\n', iostr);
634 rasqal_graph_pattern_write_indent(iostr, indent);
635 }
636 }
637
638 if(sgp)
639 rasqal_graph_pattern_write_internal(sgp, iostr, indent);
640 else
641 raptor_iostream_counted_string_write("(empty)", 7, iostr);
642 }
643
644 if(indent >= 0) {
645 raptor_iostream_write_byte('\n', iostr);
646 indent -= 2;
647 rasqal_graph_pattern_write_indent(iostr, indent);
648 }
649
650 raptor_iostream_write_byte(']', iostr);
651
652 pending_nl = 1;
653 }
654
655 if(gp->var) {
656 rasqal_variable_write(gp->var, iostr);
657 raptor_iostream_counted_string_write(" := ", 4, iostr);
658 pending_nl = 0;
659 }
660
661 if(gp->filter_expression) {
662 if(pending_nl) {
663 raptor_iostream_counted_string_write(" ,", 2, iostr);
664
665 if(indent >= 0) {
666 raptor_iostream_write_byte('\n', iostr);
667 rasqal_graph_pattern_write_indent(iostr, indent);
668 }
669 }
670
671 if(gp->triples || gp->graph_patterns)
672 raptor_iostream_counted_string_write("with ", 5, iostr);
673
674 if(indent >= 0) {
675 raptor_iostream_write_byte('\n', iostr);
676 indent += 2;
677 rasqal_graph_pattern_write_indent(iostr, indent);
678 }
679
680 rasqal_expression_write(gp->filter_expression, iostr);
681
682 if(indent >= 0)
683 indent -= 2;
684
685 pending_nl = 1;
686 }
687
688 if(gp->projection) {
689 raptor_sequence* vars_seq;
690
691 if(pending_nl) {
692 raptor_iostream_counted_string_write(" ,", 2, iostr);
693
694 if(indent >= 0) {
695 raptor_iostream_write_byte('\n', iostr);
696 rasqal_graph_pattern_write_indent(iostr, indent);
697 }
698 }
699
700 if(indent >= 0) {
701 raptor_iostream_write_byte('\n', iostr);
702 indent += 2;
703 rasqal_graph_pattern_write_indent(iostr, indent);
704 }
705
706 raptor_iostream_counted_string_write("select-variables: [", 19, iostr);
707 vars_seq = rasqal_projection_get_variables_sequence(gp->projection);
708 if(!vars_seq)
709 raptor_iostream_write_byte('*', iostr);
710 else
711 rasqal_variables_write(vars_seq, iostr);
712 raptor_iostream_counted_string_write("]", 1, iostr);
713
714 if(indent >= 0)
715 indent -= 2;
716
717 pending_nl = 1;
718 }
719
720 if(gp->bindings) {
721 int i;
722
723 if(pending_nl) {
724 raptor_iostream_counted_string_write(" ,", 2, iostr);
725
726 if(indent >= 0) {
727 raptor_iostream_write_byte('\n', iostr);
728 rasqal_graph_pattern_write_indent(iostr, indent);
729 }
730 }
731
732 raptor_iostream_counted_string_write("bindings: [", 11, iostr);
733 if(indent >= 0) {
734 raptor_iostream_write_byte('\n', iostr);
735 indent += 2;
736 rasqal_graph_pattern_write_indent(iostr, indent);
737 }
738
739 raptor_iostream_counted_string_write("variables: [", 12, iostr);
740 rasqal_variables_write(gp->bindings->variables, iostr);
741 raptor_iostream_counted_string_write("]\n", 2, iostr);
742
743 rasqal_graph_pattern_write_indent(iostr, indent);
744 raptor_iostream_counted_string_write("rows: [", 7, iostr);
745
746 indent += 2;
747 for(i = 0; 1; i++) {
748 rasqal_row* row = rasqal_bindings_get_row(gp->bindings, i);
749 if(!row)
750 break;
751
752 raptor_iostream_write_byte('\n', iostr);
753 rasqal_graph_pattern_write_indent(iostr, indent);
754 rasqal_row_write(row, iostr);
755 }
756 indent -= 2;
757
758 raptor_iostream_write_byte('\n', iostr);
759 rasqal_graph_pattern_write_indent(iostr, indent);
760 raptor_iostream_counted_string_write("]", 1, iostr);
761
762 if(indent >= 0)
763 indent -= 2;
764
765 pending_nl = 1;
766 }
767
768 #if 0
769 if(gp->where) {
770 if(pending_nl) {
771 raptor_iostream_counted_string_write(" ,", 2, iostr);
772
773 if(indent >= 0) {
774 raptor_iostream_write_byte('\n', iostr);
775 rasqal_graph_pattern_write_indent(iostr, indent);
776 }
777 }
778
779 if(indent >= 0) {
780 raptor_iostream_write_byte('\n', iostr);
781 indent += 2;
782 rasqal_graph_pattern_write_indent(iostr, indent);
783 }
784
785 rasqal_graph_pattern_write_internal(gp->where, iostr, indent);
786
787 if(indent >= 0)
788 indent -= 2;
789
790 pending_nl = 1;
791 }
792 #endif
793
794 if(indent >= 0)
795 indent -= 2;
796
797 if(pending_nl) {
798 if(indent >= 0) {
799 raptor_iostream_write_byte('\n', iostr);
800 rasqal_graph_pattern_write_indent(iostr, indent);
801 }
802 }
803
804 raptor_iostream_write_byte(')', iostr);
805
806 return 0;
807 }
808
809
810 /**
811 * rasqal_graph_pattern_print:
812 * @gp: the #rasqal_graph_pattern object
813 * @fh: the FILE* handle to print to
814 *
815 * Print a #rasqal_graph_pattern in a debug format.
816 *
817 * The print debug format may change in any release.
818 *
819 * Return value: non-0 on failure
820 **/
821 int
rasqal_graph_pattern_print(rasqal_graph_pattern * gp,FILE * fh)822 rasqal_graph_pattern_print(rasqal_graph_pattern* gp, FILE* fh)
823 {
824 raptor_iostream* iostr;
825
826 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(gp, rasqal_graph_pattern, 1);
827 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(fh, FILE*, 1);
828
829 iostr = raptor_new_iostream_to_file_handle(gp->query->world->raptor_world_ptr, fh);
830 rasqal_graph_pattern_write_internal(gp, iostr, DO_INDENTING);
831 raptor_free_iostream(iostr);
832
833 return 0;
834 }
835
836
837 /**
838 * rasqal_graph_pattern_visit:
839 * @query: #rasqal_query to operate on
840 * @gp: #rasqal_graph_pattern graph pattern
841 * @fn: pointer to function to apply that takes user data and graph pattern parameters
842 * @user_data: user data for applied function
843 *
844 * Visit a user function over a #rasqal_graph_pattern
845 *
846 * If the user function @fn returns 0, the visit is truncated.
847 *
848 * Return value: 0 if the visit was truncated.
849 **/
850 int
rasqal_graph_pattern_visit(rasqal_query * query,rasqal_graph_pattern * gp,rasqal_graph_pattern_visit_fn fn,void * user_data)851 rasqal_graph_pattern_visit(rasqal_query *query,
852 rasqal_graph_pattern* gp,
853 rasqal_graph_pattern_visit_fn fn,
854 void *user_data)
855 {
856 raptor_sequence *seq;
857 int result;
858
859 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, 1);
860 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(gp, rasqal_graph_pattern, 1);
861 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(fn, rasqal_graph_pattern_visit_fn, 1);
862
863 result = fn(query, gp, user_data);
864 if(result)
865 return result;
866
867 seq = rasqal_graph_pattern_get_sub_graph_pattern_sequence(gp);
868
869 if(seq && raptor_sequence_size(seq) > 0) {
870 int gp_index=0;
871
872 while(1) {
873 rasqal_graph_pattern* sgp;
874 sgp = rasqal_graph_pattern_get_sub_graph_pattern(gp, gp_index);
875 if(!sgp)
876 break;
877
878 result = rasqal_graph_pattern_visit(query, sgp, fn, user_data);
879 if(result)
880 return result;
881
882 gp_index++;
883 }
884 }
885
886 return 0;
887 }
888
889
890 /**
891 * rasqal_graph_pattern_get_index:
892 * @gp: #rasqal_graph_pattern graph pattern
893 *
894 * Get the graph pattern absolute index in the array of graph patterns.
895 *
896 * The graph pattern index is assigned when rasqal_query_prepare() is
897 * run on a query containing a graph pattern.
898 *
899 * Return value: index or <0 if no index has been assigned yet
900 **/
901 int
rasqal_graph_pattern_get_index(rasqal_graph_pattern * gp)902 rasqal_graph_pattern_get_index(rasqal_graph_pattern* gp)
903 {
904 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(gp, rasqal_graph_pattern, -1);
905
906 return gp->gp_index;
907 }
908
909
910 /**
911 * rasqal_graph_pattern_add_sub_graph_pattern:
912 * @graph_pattern: graph pattern to add to
913 * @sub_graph_pattern: graph pattern to add inside
914 *
915 * Add a sub graph pattern to a graph pattern.
916 *
917 * Return value: non-0 on failure
918 **/
919 int
rasqal_graph_pattern_add_sub_graph_pattern(rasqal_graph_pattern * graph_pattern,rasqal_graph_pattern * sub_graph_pattern)920 rasqal_graph_pattern_add_sub_graph_pattern(rasqal_graph_pattern* graph_pattern,
921 rasqal_graph_pattern* sub_graph_pattern)
922 {
923 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern, rasqal_graph_pattern, 1);
924 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(sub_graph_pattern, rasqal_graph_pattern, 1);
925
926 if(!graph_pattern->graph_patterns) {
927 graph_pattern->graph_patterns = raptor_new_sequence((raptor_data_free_handler)rasqal_free_graph_pattern, (raptor_data_print_handler)rasqal_graph_pattern_print);
928
929 if(!graph_pattern->graph_patterns) {
930 if(sub_graph_pattern)
931 rasqal_free_graph_pattern(sub_graph_pattern);
932 return 1;
933 }
934 }
935
936 return raptor_sequence_push(graph_pattern->graph_patterns, sub_graph_pattern);
937 }
938
939
940 /**
941 * rasqal_graph_pattern_get_triple:
942 * @graph_pattern: #rasqal_graph_pattern graph pattern object
943 * @idx: index into the sequence of triples in the graph pattern
944 *
945 * Get a triple inside a graph pattern.
946 *
947 * Return value: #rasqal_triple or NULL if out of range
948 **/
949 rasqal_triple*
rasqal_graph_pattern_get_triple(rasqal_graph_pattern * graph_pattern,int idx)950 rasqal_graph_pattern_get_triple(rasqal_graph_pattern* graph_pattern, int idx)
951 {
952 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern, rasqal_graph_pattern, NULL);
953
954 if(!graph_pattern->triples)
955 return NULL;
956
957 idx += graph_pattern->start_column;
958
959 if(idx > graph_pattern->end_column)
960 return NULL;
961
962 return (rasqal_triple*)raptor_sequence_get_at(graph_pattern->triples, idx);
963 }
964
965
966 /**
967 * rasqal_graph_pattern_get_sub_graph_pattern_sequence:
968 * @graph_pattern: #rasqal_graph_pattern graph pattern object
969 *
970 * Get the sequence of graph patterns inside a graph pattern .
971 *
972 * Return value: a #raptor_sequence of #rasqal_graph_pattern pointers.
973 **/
974 raptor_sequence*
rasqal_graph_pattern_get_sub_graph_pattern_sequence(rasqal_graph_pattern * graph_pattern)975 rasqal_graph_pattern_get_sub_graph_pattern_sequence(rasqal_graph_pattern* graph_pattern)
976 {
977 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern, rasqal_graph_pattern, NULL);
978
979 return graph_pattern->graph_patterns;
980 }
981
982
983 /**
984 * rasqal_graph_pattern_get_sub_graph_pattern:
985 * @graph_pattern: #rasqal_graph_pattern graph pattern object
986 * @idx: index into the sequence of sub graph_patterns in the graph pattern
987 *
988 * Get a sub-graph pattern inside a graph pattern.
989 *
990 * Return value: #rasqal_graph_pattern or NULL if out of range
991 **/
992 rasqal_graph_pattern*
rasqal_graph_pattern_get_sub_graph_pattern(rasqal_graph_pattern * graph_pattern,int idx)993 rasqal_graph_pattern_get_sub_graph_pattern(rasqal_graph_pattern* graph_pattern, int idx)
994 {
995 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern, rasqal_graph_pattern, NULL);
996
997 if(!graph_pattern->graph_patterns)
998 return NULL;
999
1000 return (rasqal_graph_pattern*)raptor_sequence_get_at(graph_pattern->graph_patterns, idx);
1001 }
1002
1003
1004 /**
1005 * rasqal_graph_pattern_get_origin:
1006 * @graph_pattern: #rasqal_graph_pattern graph pattern object
1007 *
1008 * Get the graph pattern literal for
1009 * #RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH graph pattern
1010 *
1011 * Return value: graph literal parameter or NULL if wrong graph pattern type or not defined
1012 **/
1013 rasqal_literal*
rasqal_graph_pattern_get_origin(rasqal_graph_pattern * graph_pattern)1014 rasqal_graph_pattern_get_origin(rasqal_graph_pattern* graph_pattern)
1015 {
1016 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern,
1017 rasqal_graph_pattern, NULL);
1018
1019 if(graph_pattern->op == RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH)
1020 return graph_pattern->origin;
1021 else
1022 return NULL;
1023 }
1024
1025
1026 /*
1027 * rasqal_graph_pattern_set_origin:
1028 * @graph_pattern: #rasqal_graph_pattern graph pattern object
1029 * @origin: #rasqal_literal variable or URI
1030 *
1031 * INTERNAL - Set the graph pattern triple origin.
1032 *
1033 **/
1034 void
rasqal_graph_pattern_set_origin(rasqal_graph_pattern * graph_pattern,rasqal_literal * origin)1035 rasqal_graph_pattern_set_origin(rasqal_graph_pattern* graph_pattern,
1036 rasqal_literal *origin)
1037 {
1038 graph_pattern->origin = rasqal_new_literal_from_literal(origin);
1039 }
1040
1041
1042 /**
1043 * rasqal_new_basic_graph_pattern_from_formula:
1044 * @query: #rasqal_graph_pattern query object
1045 * @formula: triples sequence containing the graph pattern
1046 *
1047 * INTERNAL - Create a new graph pattern object over a formula. This function
1048 * frees the formula passed in.
1049 *
1050 * Return value: a new #rasqal_graph_pattern object or NULL on failure
1051 **/
1052 rasqal_graph_pattern*
rasqal_new_basic_graph_pattern_from_formula(rasqal_query * query,rasqal_formula * formula)1053 rasqal_new_basic_graph_pattern_from_formula(rasqal_query* query,
1054 rasqal_formula* formula)
1055 {
1056 rasqal_graph_pattern* gp;
1057 raptor_sequence *triples = query->triples;
1058 raptor_sequence *formula_triples = formula->triples;
1059 int offset = raptor_sequence_size(triples);
1060 int triple_pattern_size = 0;
1061
1062 if(formula_triples) {
1063 /* Move formula triples to end of main triples sequence */
1064 triple_pattern_size = raptor_sequence_size(formula_triples);
1065
1066 if(raptor_sequence_join(triples, formula_triples)) {
1067 rasqal_free_formula(formula);
1068 return NULL;
1069 }
1070 }
1071
1072 rasqal_free_formula(formula);
1073
1074 gp = rasqal_new_basic_graph_pattern(query, triples,
1075 offset,
1076 offset + triple_pattern_size - 1);
1077
1078 return gp;
1079 }
1080
1081
1082 /**
1083 * rasqal_new_2_group_graph_pattern:
1084 * @query: query object
1085 * @first_gp: first graph pattern
1086 * @second_gp: second graph pattern
1087 *
1088 * INTERNAL - Make a new group graph pattern from two graph patterns
1089 * of which either or both may be NULL, in which case a group
1090 * of 0 graph patterns is created.
1091 *
1092 * @first_gp and @second_gp if given, become owned by the new graph
1093 * pattern.
1094 *
1095 * Return value: new group graph pattern or NULL on failure
1096 */
1097 rasqal_graph_pattern*
rasqal_new_2_group_graph_pattern(rasqal_query * query,rasqal_graph_pattern * first_gp,rasqal_graph_pattern * second_gp)1098 rasqal_new_2_group_graph_pattern(rasqal_query* query,
1099 rasqal_graph_pattern* first_gp,
1100 rasqal_graph_pattern* second_gp)
1101 {
1102 raptor_sequence *seq;
1103
1104 seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_graph_pattern, (raptor_data_print_handler)rasqal_graph_pattern_print);
1105 if(!seq) {
1106 if(first_gp)
1107 rasqal_free_graph_pattern(first_gp);
1108 if(second_gp)
1109 rasqal_free_graph_pattern(second_gp);
1110
1111 return NULL;
1112 }
1113
1114 if(first_gp && raptor_sequence_push(seq, first_gp)) {
1115 raptor_free_sequence(seq);
1116 if(second_gp)
1117 rasqal_free_graph_pattern(second_gp);
1118
1119 return NULL;
1120 }
1121
1122 if(second_gp && raptor_sequence_push(seq, second_gp)) {
1123 raptor_free_sequence(seq);
1124
1125 return NULL;
1126 }
1127
1128 return rasqal_new_graph_pattern_from_sequence(query, seq,
1129 RASQAL_GRAPH_PATTERN_OPERATOR_GROUP);
1130 }
1131
1132
1133 /**
1134 * rasqal_graph_pattern_variable_bound_in:
1135 * @gp: graph pattern
1136 * @v: variable
1137 *
1138 * Is the variable bound in this graph pattern (not including children)?
1139 *
1140 * Return value: non-0 if variable is bound in the given graph pattern.
1141 */
1142 int
rasqal_graph_pattern_variable_bound_in(rasqal_graph_pattern * gp,rasqal_variable * v)1143 rasqal_graph_pattern_variable_bound_in(rasqal_graph_pattern *gp,
1144 rasqal_variable *v)
1145 {
1146 rasqal_query* query;
1147 int width;
1148 int gp_offset;
1149 unsigned short *row;
1150
1151 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(gp, rasqal_graph_pattern, 0);
1152
1153 query = gp->query;
1154 width = rasqal_variables_table_get_total_variables_count(query->vars_table);
1155 gp_offset = (gp->gp_index + RASQAL_VAR_USE_MAP_OFFSET_LAST + 1) * width;
1156 row = &query->variables_use_map[gp_offset];
1157
1158 return ((row[v->offset] & RASQAL_VAR_USE_BOUND_HERE) != 0);
1159 }
1160
1161
1162
1163 /*
1164 * rasqal_graph_pattern_variable_bound_below:
1165 * @gp: graph pattern
1166 * @v: variable
1167 *
1168 * INTERNAL - Is the variable bound in the graph pattern or below?
1169 *
1170 * Return value: non-0 if variable is bound in the graph pattern tree
1171 */
1172 int
rasqal_graph_pattern_variable_bound_below(rasqal_graph_pattern * gp,rasqal_variable * v)1173 rasqal_graph_pattern_variable_bound_below(rasqal_graph_pattern *gp,
1174 rasqal_variable *v)
1175 {
1176 int bound;
1177
1178 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(gp, rasqal_graph_pattern, 0);
1179
1180 bound = rasqal_graph_pattern_variable_bound_in(gp, v);
1181 if(bound)
1182 return bound;
1183
1184 if(gp->graph_patterns) {
1185 int size = raptor_sequence_size(gp->graph_patterns);
1186 int i;
1187
1188 for(i = 0; i < size; i++) {
1189 rasqal_graph_pattern *sgp;
1190
1191 sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
1192 bound = rasqal_graph_pattern_variable_bound_below(sgp, v);
1193 if(bound)
1194 break;
1195 }
1196 }
1197
1198 return bound;
1199 }
1200
1201
1202
1203 /**
1204 * rasqal_new_basic_graph_pattern_from_triples:
1205 * @query: #rasqal_graph_pattern query object
1206 * @triples: triples sequence containing the graph pattern
1207 *
1208 * INTERNAL - Create a new graph pattern object from a sequence of triples.
1209 *
1210 * The @triples become owned by the graph pattern
1211 *
1212 * Return value: a new #rasqal_graph_pattern object or NULL on failure
1213 **/
1214 rasqal_graph_pattern*
rasqal_new_basic_graph_pattern_from_triples(rasqal_query * query,raptor_sequence * triples)1215 rasqal_new_basic_graph_pattern_from_triples(rasqal_query* query,
1216 raptor_sequence* triples)
1217 {
1218 rasqal_graph_pattern* gp;
1219 raptor_sequence *graph_triples = query->triples;
1220 int offset = raptor_sequence_size(graph_triples);
1221 int triple_pattern_size = 0;
1222
1223 if(triples) {
1224 /* Move triples to end of graph triples sequence */
1225 triple_pattern_size = raptor_sequence_size(triples);
1226
1227 if(raptor_sequence_join(graph_triples, triples)) {
1228 raptor_free_sequence(triples);
1229 return NULL;
1230 }
1231 }
1232
1233 raptor_free_sequence(triples);
1234
1235 gp = rasqal_new_basic_graph_pattern(query, graph_triples,
1236 offset,
1237 offset + triple_pattern_size - 1);
1238
1239 return gp;
1240 }
1241
1242
1243 /**
1244 * rasqal_new_values_graph_pattern:
1245 * @query: #rasqal_graph_pattern query object
1246 * @bindings: bindings object
1247 *
1248 * INTERNAL - Create a new values graph pattern object from a bindings
1249 *
1250 * The @bindings becomes owned by the graph pattern
1251 *
1252 * Return value: a new #rasqal_graph_pattern object or NULL on failure
1253 **/
1254 rasqal_graph_pattern*
rasqal_new_values_graph_pattern(rasqal_query * query,rasqal_bindings * bindings)1255 rasqal_new_values_graph_pattern(rasqal_query* query,
1256 rasqal_bindings* bindings)
1257 {
1258 rasqal_graph_pattern* gp;
1259
1260 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
1261
1262 gp = rasqal_new_graph_pattern(query, RASQAL_GRAPH_PATTERN_OPERATOR_VALUES);
1263 if(gp)
1264 gp->bindings = bindings;
1265
1266 return gp;
1267 }
1268
1269
1270 /**
1271 * rasqal_graph_pattern_get_variable:
1272 * @graph_pattern: #rasqal_graph_pattern graph pattern object
1273 *
1274 * Get the variable for #RASQAL_GRAPH_PATTERN_OPERATOR_LET graph pattern
1275 *
1276 * Return value: graph variable or NULL if wrong graph pattern or not defined
1277 **/
1278 rasqal_variable*
rasqal_graph_pattern_get_variable(rasqal_graph_pattern * graph_pattern)1279 rasqal_graph_pattern_get_variable(rasqal_graph_pattern* graph_pattern)
1280 {
1281 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern,
1282 rasqal_graph_pattern, NULL);
1283
1284 if(graph_pattern->op == RASQAL_GRAPH_PATTERN_OPERATOR_LET)
1285 return graph_pattern->var;
1286 else
1287 return NULL;
1288 }
1289
1290
1291 /**
1292 * rasqal_graph_pattern_get_service:
1293 * @graph_pattern: #rasqal_graph_pattern graph pattern object
1294 *
1295 * Get the literal for #RASQAL_GRAPH_PATTERN_OPERATOR_SERVICE graph pattern
1296 *
1297 * Return value: graph variable or NULL if wrong graph pattern or not defined
1298 **/
1299 rasqal_literal*
rasqal_graph_pattern_get_service(rasqal_graph_pattern * graph_pattern)1300 rasqal_graph_pattern_get_service(rasqal_graph_pattern* graph_pattern)
1301 {
1302 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern,
1303 rasqal_graph_pattern, NULL);
1304
1305 if(graph_pattern->op == RASQAL_GRAPH_PATTERN_OPERATOR_SERVICE)
1306 return graph_pattern->origin;
1307 else
1308 return NULL;
1309 }
1310
1311
1312 struct gpft
1313 {
1314 /* sequence owned here */
1315 raptor_sequence* triples;
1316 /* shared pointer to current origin */
1317 rasqal_literal* origin;
1318 };
1319
1320 static int
rasqal_graph_pattern_get_flattened_triples_visit(rasqal_query * query,rasqal_graph_pattern * gp,struct gpft * state)1321 rasqal_graph_pattern_get_flattened_triples_visit(rasqal_query* query,
1322 rasqal_graph_pattern* gp,
1323 struct gpft* state)
1324 {
1325 raptor_sequence* seq;
1326 int size;
1327
1328 if(gp->op == RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH)
1329 state->origin = gp->origin;
1330 else if(gp->op != RASQAL_GRAPH_PATTERN_OPERATOR_BASIC)
1331 return 1;
1332 else {
1333 /* RASQAL_GRAPH_PATTERN_OPERATOR_BASIC */
1334 rasqal_triples_sequence_set_origin(state->triples,
1335 gp->triples, state->origin);
1336 }
1337
1338
1339 seq = rasqal_graph_pattern_get_sub_graph_pattern_sequence(gp);
1340 if(seq) {
1341 int gp_index = 0;
1342 int result = 0;
1343
1344 size = raptor_sequence_size(seq);
1345 while(size > 0) {
1346 rasqal_graph_pattern* sgp;
1347 sgp = rasqal_graph_pattern_get_sub_graph_pattern(gp, gp_index);
1348 if(!sgp)
1349 break;
1350
1351 result = rasqal_graph_pattern_get_flattened_triples_visit(query, sgp,
1352 state);
1353 if(result)
1354 return result;
1355
1356 gp_index++;
1357 size--;
1358 }
1359 }
1360
1361
1362 if(gp->op == RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH)
1363 state->origin = NULL;
1364
1365 return 0;
1366 }
1367
1368
1369 /**
1370 * rasqal_graph_pattern_get_flattened_triples:
1371 * @query: query
1372 * @graph_pattern: graph pattern
1373 *
1374 * Get the triples inside a tree of graph patterns (BASIC + GRAPH) as a single sequence with GRAPHs turned into triple origin.
1375 *
1376 * The returned sequence and all the #rasqal_triple in it are owned
1377 * by the caller (hold references).
1378 *
1379 * Return value: new sequence of #raptor_triple or NULL on failure
1380 */
1381 raptor_sequence*
rasqal_graph_pattern_get_flattened_triples(rasqal_query * query,rasqal_graph_pattern * graph_pattern)1382 rasqal_graph_pattern_get_flattened_triples(rasqal_query* query,
1383 rasqal_graph_pattern* graph_pattern)
1384 {
1385 struct gpft state;
1386
1387 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern,
1388 rasqal_graph_pattern, NULL);
1389
1390 memset(&state, '\0', sizeof(state));
1391
1392 state.triples = raptor_new_sequence((raptor_data_free_handler)rasqal_free_triple,
1393 (raptor_data_print_handler)rasqal_triple_print);
1394 state.origin = NULL;
1395
1396 if(rasqal_graph_pattern_get_flattened_triples_visit(query, graph_pattern,
1397 &state)) {
1398 raptor_free_sequence(state.triples);
1399 return NULL;
1400 }
1401
1402 return state.triples;
1403 }
1404
1405
1406 /**
1407 * rasqal_graph_pattern_get_triples:
1408 * @query: query
1409 * @graph_pattern: graph pattern
1410 *
1411 * Get the triples inside this graph pattern (if any).
1412 *
1413 * The returned sequence and all the #rasqal_triple in it are owned
1414 * by the caller (hold references).
1415 *
1416 * Return value: new sequence of #raptor_triple or NULL on failure or no triples
1417 */
1418 raptor_sequence*
rasqal_graph_pattern_get_triples(rasqal_query * query,rasqal_graph_pattern * graph_pattern)1419 rasqal_graph_pattern_get_triples(rasqal_query* query,
1420 rasqal_graph_pattern* graph_pattern)
1421 {
1422 raptor_sequence* triples = NULL;
1423
1424 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(graph_pattern,
1425 rasqal_graph_pattern, NULL);
1426
1427 if (graph_pattern->triples) {
1428 int i;
1429 triples = raptor_new_sequence((raptor_data_free_handler)rasqal_free_triple,
1430 (raptor_data_print_handler)rasqal_triple_print);
1431
1432 for(i = graph_pattern->start_column; i <= graph_pattern->end_column; i++) {
1433 rasqal_triple *t = (rasqal_triple*)raptor_sequence_get_at(graph_pattern->triples, i);
1434 t = rasqal_new_triple_from_triple(t);
1435 if(!t) {
1436 raptor_free_sequence(triples);
1437 return NULL;
1438 }
1439 raptor_sequence_push(triples, t);
1440 }
1441 }
1442
1443 return triples;
1444 }
1445
1446 struct find_parent_data {
1447 rasqal_graph_pattern* child_gp;
1448 rasqal_graph_pattern* parent_gp;
1449 };
1450
1451 static int
rasqal_graph_pattern_find_parent(rasqal_query * query,rasqal_graph_pattern * gp,void * data)1452 rasqal_graph_pattern_find_parent(rasqal_query* query,
1453 rasqal_graph_pattern* gp,
1454 void* data)
1455 {
1456 struct find_parent_data* fpd = (struct find_parent_data*)data;
1457 int i;
1458
1459 if(gp->graph_patterns) {
1460 int size = raptor_sequence_size(gp->graph_patterns);
1461
1462 for(i = 0; i< size; i++) {
1463 rasqal_graph_pattern* sgp;
1464 sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
1465 if(sgp == fpd->child_gp) {
1466 fpd->parent_gp = gp;
1467 /* Found - truncate search */
1468 return 1;
1469 }
1470 }
1471 }
1472
1473 return 0;
1474 }
1475
1476
1477 /**
1478 * rasqal_graph_pattern_get_parent:
1479 * @query: query
1480 * @gp: graph pattern to find parent
1481 * @tree_gp: graph pattern tree to search for @gp
1482 *
1483 * Find the parent graph pattern of @gp in the tree of graph patterns @gp_tree
1484 *
1485 * Return value: pointer to parent GP or NULL on error/not found
1486 */
1487 rasqal_graph_pattern*
rasqal_graph_pattern_get_parent(rasqal_query * query,rasqal_graph_pattern * gp,rasqal_graph_pattern * tree_gp)1488 rasqal_graph_pattern_get_parent(rasqal_query *query,
1489 rasqal_graph_pattern* gp,
1490 rasqal_graph_pattern* tree_gp)
1491 {
1492 struct find_parent_data fpd;
1493
1494 fpd.child_gp = gp;
1495 fpd.parent_gp = NULL;
1496
1497 if(gp == tree_gp || gp == query->query_graph_pattern)
1498 return NULL;
1499
1500 (void)rasqal_graph_pattern_visit(query, tree_gp,
1501 rasqal_graph_pattern_find_parent,
1502 &fpd);
1503
1504 return fpd.parent_gp;
1505 }
1506