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