1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * rasqal_algebra.c - Rasqal algebra class
4  *
5  * Copyright (C) 2008-2009, David Beckett http://www.dajobe.org/
6  *
7  * This package is Free Software and part of Redland http://librdf.org/
8  *
9  * It is licensed under the following three licenses as alternatives:
10  *   1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
11  *   2. GNU General Public License (GPL) V2 or any newer version
12  *   3. Apache License, V2.0 or any newer version
13  *
14  * You may not use this file except in compliance with at least one of
15  * the above three licenses.
16  *
17  * See LICENSE.html or LICENSE.txt at the top of this package for the
18  * complete terms and further detail along with the license texts for
19  * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
20  *
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <rasqal_config.h>
26 #endif
27 
28 #ifdef WIN32
29 #include <win32_rasqal_config.h>
30 #endif
31 
32 #include <stdio.h>
33 #include <string.h>
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #include <stdarg.h>
38 
39 #include "rasqal.h"
40 #include "rasqal_internal.h"
41 
42 
43 #ifndef STANDALONE
44 
45 static rasqal_algebra_node* rasqal_algebra_graph_pattern_to_algebra(rasqal_query* query, rasqal_graph_pattern* gp);
46 
47 /*
48  * rasqal_new_algebra_node:
49  * @query: #rasqal_algebra_node query object
50  * @op: enum #rasqal_algebra_operator operator
51  *
52  * INTERNAL - Create a new algebra object.
53  *
54  * Return value: a new #rasqal_algebra object or NULL on failure
55  **/
56 static rasqal_algebra_node*
rasqal_new_algebra_node(rasqal_query * query,rasqal_algebra_node_operator op)57 rasqal_new_algebra_node(rasqal_query* query, rasqal_algebra_node_operator op)
58 {
59   rasqal_algebra_node* node;
60 
61   if(!query)
62     return NULL;
63 
64   node = RASQAL_CALLOC(rasqal_algebra_node*, 1, sizeof(*node));
65   if(!node)
66     return NULL;
67 
68   node->op = op;
69   node->query = query;
70   return node;
71 }
72 
73 
74 /*
75  * rasqal_new_filter_algebra_node:
76  * @query: #rasqal_query query object
77  * @expr: FILTER expression
78  * @node: algebra node being filtered (or NULL)
79  *
80  * INTERNAL - Create a new algebra node for an expression over a node
81  *
82  * expr and node become owned by the new node.  The @node may be NULL
83  * which means that the logical input/output is a row with no bindings.
84  *
85  * Return value: a new #rasqal_algebra_node object or NULL on failure
86  **/
87 rasqal_algebra_node*
rasqal_new_filter_algebra_node(rasqal_query * query,rasqal_expression * expr,rasqal_algebra_node * node)88 rasqal_new_filter_algebra_node(rasqal_query* query,
89                                rasqal_expression* expr,
90                                rasqal_algebra_node* node)
91 {
92   rasqal_algebra_node* new_node;
93 
94   if(!query || !expr)
95     goto fail;
96 
97   new_node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_FILTER);
98   if(new_node) {
99     new_node->expr = expr;
100     new_node->node1 = node;
101     return new_node;
102   }
103 
104   fail:
105   if(expr)
106     rasqal_free_expression(expr);
107   if(node)
108     rasqal_free_algebra_node(node);
109   return NULL;
110 }
111 
112 
113 /*
114  * rasqal_new_triples_algebra_node:
115  * @query: #rasqal_query query object
116  * @triples: triples sequence (SHARED) (or NULL for empty BGP)
117  * @start_column: first triple
118  * @end_column: last triple
119  *
120  * INTERNAL - Create a new algebra node for Basic Graph Pattern
121  *
122  * Return value: a new #rasqal_algebra_node object or NULL on failure
123  **/
124 rasqal_algebra_node*
rasqal_new_triples_algebra_node(rasqal_query * query,raptor_sequence * triples,int start_column,int end_column)125 rasqal_new_triples_algebra_node(rasqal_query* query,
126                                 raptor_sequence* triples,
127                                 int start_column, int end_column)
128 {
129   rasqal_algebra_node* node;
130 
131   if(!query)
132     return NULL;
133 
134   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_BGP);
135   if(!node)
136     return NULL;
137 
138   node->triples = triples;
139   if(!triples) {
140     start_column= -1;
141     end_column= -1;
142   }
143   node->start_column = start_column;
144   node->end_column = end_column;
145 
146   return node;
147 }
148 
149 
150 /*
151  * rasqal_new_empty_algebra_node:
152  * @query: #rasqal_query query object
153  *
154  * INTERNAL - Create a new empty algebra node
155  *
156  * Return value: a new #rasqal_algebra_node object or NULL on failure
157  **/
158 rasqal_algebra_node*
rasqal_new_empty_algebra_node(rasqal_query * query)159 rasqal_new_empty_algebra_node(rasqal_query* query)
160 {
161   rasqal_algebra_node* node;
162 
163   if(!query)
164     return NULL;
165 
166   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_BGP);
167   if(!node)
168     return NULL;
169 
170   node->triples = NULL;
171   node->start_column= -1;
172   node->end_column= -1;
173 
174   return node;
175 }
176 
177 
178 /*
179  * rasqal_new_2op_algebra_node:
180  * @query: #rasqal_query query object
181  * @op: operator
182  * @node1: 1st algebra node
183  * @node2: 2nd algebra node (pr NULL for #RASQAL_ALGEBRA_OPERATOR_TOLIST only)
184  *
185  * INTERNAL - Create a new algebra node for 1 or 2 graph patterns
186  *
187  * node1 and node2 become owned by the new node
188  *
189  * Return value: a new #rasqal_algebra_node object or NULL on failure
190  **/
191 rasqal_algebra_node*
rasqal_new_2op_algebra_node(rasqal_query * query,rasqal_algebra_node_operator op,rasqal_algebra_node * node1,rasqal_algebra_node * node2)192 rasqal_new_2op_algebra_node(rasqal_query* query,
193                             rasqal_algebra_node_operator op,
194                             rasqal_algebra_node* node1,
195                             rasqal_algebra_node* node2)
196 {
197   rasqal_algebra_node* node;
198 
199   if(!query || !node1)
200     goto fail;
201   if(op != RASQAL_ALGEBRA_OPERATOR_TOLIST && !node2)
202     goto fail;
203 
204   node = rasqal_new_algebra_node(query, op);
205   if(node) {
206     node->node1 = node1;
207     node->node2 = node2;
208 
209     return node;
210   }
211 
212   fail:
213   if(node1)
214     rasqal_free_algebra_node(node1);
215   if(node2)
216     rasqal_free_algebra_node(node2);
217   return NULL;
218 }
219 
220 
221 /*
222  * rasqal_new_leftjoin_algebra_node:
223  * @query: #rasqal_query query object
224  * @node1: 1st algebra node
225  * @node2: 2nd algebra node
226  * @expr: expression
227  *
228  * INTERNAL - Create a new LEFTJOIN algebra node for 2 graph patterns
229  *
230  * node1, node2 and expr become owned by the new node
231  *
232  * Return value: a new #rasqal_algebra_node object or NULL on failure
233  **/
234 rasqal_algebra_node*
rasqal_new_leftjoin_algebra_node(rasqal_query * query,rasqal_algebra_node * node1,rasqal_algebra_node * node2,rasqal_expression * expr)235 rasqal_new_leftjoin_algebra_node(rasqal_query* query,
236                                  rasqal_algebra_node* node1,
237                                  rasqal_algebra_node* node2,
238                                  rasqal_expression* expr)
239 {
240   rasqal_algebra_node* node;
241 
242   if(!query || !node1 || !node2 || !expr)
243     goto fail;
244 
245   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_LEFTJOIN);
246   if(node) {
247     node->node1 = node1;
248     node->node2 = node2;
249     node->expr = expr;
250 
251     return node;
252   }
253 
254   fail:
255   if(node1)
256     rasqal_free_algebra_node(node1);
257   if(node2)
258     rasqal_free_algebra_node(node2);
259   if(expr)
260     rasqal_free_expression(expr);
261   return NULL;
262 }
263 
264 
265 /*
266  * rasqal_new_orderby_algebra_node:
267  * @query: #rasqal_query query object
268  * @node1: inner algebra node
269  * @seq: sequence of order condition #rasqal_expression
270  * @distinct: distinct flag
271  *
272  * INTERNAL - Create a new ORDERBY algebra node for a sequence of order conditions (with optional DISTINCTness)
273  *
274  * #node and #seq become owned by the new node
275  *
276  * Return value: a new #rasqal_algebra_node object or NULL on failure
277  **/
278 rasqal_algebra_node*
rasqal_new_orderby_algebra_node(rasqal_query * query,rasqal_algebra_node * node1,raptor_sequence * seq,int distinct)279 rasqal_new_orderby_algebra_node(rasqal_query* query,
280                                 rasqal_algebra_node* node1,
281                                 raptor_sequence* seq,
282                                 int distinct)
283 {
284   rasqal_algebra_node* node;
285 
286   if(!query || !node1 || !seq || !raptor_sequence_size(seq))
287     goto fail;
288 
289   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_ORDERBY);
290   if(node) {
291     node->node1 = node1;
292     node->seq = seq;
293     node->distinct = distinct;
294 
295     return node;
296   }
297 
298   fail:
299   if(node1)
300     rasqal_free_algebra_node(node1);
301   if(seq)
302     raptor_free_sequence(seq);
303 
304   return NULL;
305 }
306 
307 
308 /*
309  * rasqal_new_slice_algebra_node:
310  * @query: #rasqal_query query object
311  * @node1: inner algebra node
312  * @limit: max rows limit (or <0 for no limit)
313  * @offset: start row offset (or <0 for no offset)
314  *
315  * INTERNAL - Create a new SLICE algebra node for selecting a range of rows
316  *
317  * #node and #seq become owned by the new node
318  *
319  * Return value: a new #rasqal_algebra_node object or NULL on failure
320  **/
321 rasqal_algebra_node*
rasqal_new_slice_algebra_node(rasqal_query * query,rasqal_algebra_node * node1,int limit,int offset)322 rasqal_new_slice_algebra_node(rasqal_query* query,
323                               rasqal_algebra_node* node1,
324                               int limit,
325                               int offset)
326 {
327   rasqal_algebra_node* node;
328 
329   if(!query || !node1)
330     goto fail;
331 
332   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_SLICE);
333   if(node) {
334     node->node1 = node1;
335     node->limit = limit;
336     node->offset = offset;
337 
338     return node;
339   }
340 
341   fail:
342   if(node1)
343     rasqal_free_algebra_node(node1);
344 
345   return NULL;
346 }
347 
348 
349 /*
350  * rasqal_new_project_algebra_node:
351  * @query: #rasqal_query query object
352  * @node1: inner algebra node
353  * @vars_seq: sequence of variables
354  *
355  * INTERNAL - Create a new PROJECT algebra node for a sequence of variables over an inner node
356  *
357  * The inputs @node and @seq become owned by the new node
358  *
359  * Return value: a new #rasqal_algebra_node object or NULL on failure
360  **/
361 rasqal_algebra_node*
rasqal_new_project_algebra_node(rasqal_query * query,rasqal_algebra_node * node1,raptor_sequence * vars_seq)362 rasqal_new_project_algebra_node(rasqal_query* query,
363                                 rasqal_algebra_node* node1,
364                                 raptor_sequence* vars_seq)
365 {
366   rasqal_algebra_node* node;
367 
368   if(!query || !node1 || !vars_seq)
369     goto fail;
370 
371   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_PROJECT);
372   if(node) {
373     node->node1 = node1;
374     node->vars_seq = vars_seq;
375 
376     return node;
377   }
378 
379   fail:
380   if(node1)
381     rasqal_free_algebra_node(node1);
382   if(vars_seq)
383     raptor_free_sequence(vars_seq);
384 
385   return NULL;
386 }
387 
388 
389 /*
390  * rasqal_new_distinct_algebra_node:
391  * @query: #rasqal_query query object
392  * @node1: inner algebra node
393  *
394  * INTERNAL - Create a new DISTINCT algebra node for an inner node
395  *
396  * The input @node becomes owned by the new node
397  *
398  * Return value: a new #rasqal_algebra_node object or NULL on failure
399  **/
400 rasqal_algebra_node*
rasqal_new_distinct_algebra_node(rasqal_query * query,rasqal_algebra_node * node1)401 rasqal_new_distinct_algebra_node(rasqal_query* query,
402                                  rasqal_algebra_node* node1)
403 {
404   rasqal_algebra_node* node;
405 
406   if(!query || !node1)
407     goto fail;
408 
409   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_DISTINCT);
410   if(node) {
411     node->node1 = node1;
412     return node;
413   }
414 
415   fail:
416   if(node1)
417     rasqal_free_algebra_node(node1);
418 
419   return NULL;
420 }
421 
422 
423 /*
424  * rasqal_new_graph_algebra_node:
425  * @query: #rasqal_query query object
426  * @node1: inner algebra node
427  * @graph: graph literal
428  *
429  * INTERNAL - Create a new GRAPH algebra node over an inner node
430  *
431  * The inputs @node1 and @graph become owned by the new node
432  *
433  * Return value: a new #rasqal_algebra_node object or NULL on failure
434  **/
435 rasqal_algebra_node*
rasqal_new_graph_algebra_node(rasqal_query * query,rasqal_algebra_node * node1,rasqal_literal * graph)436 rasqal_new_graph_algebra_node(rasqal_query* query,
437                               rasqal_algebra_node* node1,
438                               rasqal_literal *graph)
439 {
440   rasqal_algebra_node* node;
441 
442   if(!query || !node1 || !graph)
443     goto fail;
444 
445   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_GRAPH);
446   if(node) {
447     node->node1 = node1;
448     node->graph = graph;
449 
450     return node;
451   }
452 
453   fail:
454   if(node1)
455     rasqal_free_algebra_node(node1);
456   if(graph)
457     rasqal_free_literal(graph);
458 
459   return NULL;
460 }
461 
462 
463 /*
464  * rasqal_new_assignment_algebra_node:
465  * @query: #rasqal_query query object
466  * @var: variable
467  * @expr: expression
468  *
469  * INTERNAL - Create a new LET algebra node over a variable and expression
470  *
471  * The input @expr becomes owned by the new node
472  *
473  * Return value: a new #rasqal_algebra_node object or NULL on failure
474  **/
475 rasqal_algebra_node*
rasqal_new_assignment_algebra_node(rasqal_query * query,rasqal_variable * var,rasqal_expression * expr)476 rasqal_new_assignment_algebra_node(rasqal_query* query,
477                                    rasqal_variable *var,
478                                    rasqal_expression *expr)
479 {
480   rasqal_algebra_node* node;
481 
482   if(!query || !var || !expr)
483     goto fail;
484 
485   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_ASSIGN);
486   if(node) {
487     node->var = var;
488     node->expr = expr;
489 
490     return node;
491   }
492 
493   fail:
494   if(expr)
495     rasqal_free_expression(expr);
496 
497   return NULL;
498 }
499 
500 
501 /*
502  * rasqal_new_groupby_algebra_node:
503  * @query: #rasqal_query query object
504  * @node1: inner algebra node
505  * @seq: sequence of order condition #rasqal_expression
506  *
507  * INTERNAL - Create a new GROUP algebra node for a sequence of GROUP BY conditions
508  *
509  * #node and #seq become owned by the new node
510  *
511  * Return value: a new #rasqal_algebra_node object or NULL on failure
512  **/
513 rasqal_algebra_node*
rasqal_new_groupby_algebra_node(rasqal_query * query,rasqal_algebra_node * node1,raptor_sequence * seq)514 rasqal_new_groupby_algebra_node(rasqal_query* query,
515                                 rasqal_algebra_node* node1,
516                                 raptor_sequence* seq)
517 {
518   rasqal_algebra_node* node;
519 
520   if(!query || !node1 || !seq || !raptor_sequence_size(seq))
521     goto fail;
522 
523   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_GROUP);
524   if(node) {
525     node->node1 = node1;
526     node->seq = seq;
527 
528     return node;
529   }
530 
531   fail:
532   if(node1)
533     rasqal_free_algebra_node(node1);
534   if(seq)
535     raptor_free_sequence(seq);
536 
537   return NULL;
538 }
539 
540 
541 /*
542  * rasqal_new_aggregation_algebra_node:
543  * @query: #rasqal_query query object
544  * @node1: inner algebra node
545  * @exprs_seq: sequence of #rasqal_expression
546  * @vars_seq: sequence of #rasqal_sequence
547  *
548  * INTERNAL - Create a new AGGREGATION algebra node for a query over a sequence of expressions to variables
549  *
550  * On construction @node1, @exprs_seq and @vars_seq become owned by
551  * the new node.
552  *
553  * Return value: a new #rasqal_algebra_node object or NULL on failure
554  **/
555 rasqal_algebra_node*
rasqal_new_aggregation_algebra_node(rasqal_query * query,rasqal_algebra_node * node1,raptor_sequence * exprs_seq,raptor_sequence * vars_seq)556 rasqal_new_aggregation_algebra_node(rasqal_query* query,
557                                     rasqal_algebra_node* node1,
558                                     raptor_sequence* exprs_seq,
559                                     raptor_sequence* vars_seq)
560 {
561   rasqal_algebra_node* node;
562 
563   if(!query || !node1 || !exprs_seq || !vars_seq)
564     goto fail;
565 
566   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_AGGREGATION);
567   if(node) {
568     node->node1 = node1;
569     node->seq = exprs_seq;
570     node->vars_seq = vars_seq;
571     return node;
572   }
573 
574   fail:
575   if(node1)
576     rasqal_free_algebra_node(node1);
577   if(exprs_seq)
578     raptor_free_sequence(exprs_seq);
579   if(vars_seq)
580     raptor_free_sequence(vars_seq);
581 
582   return NULL;
583 }
584 
585 
586 /*
587  * rasqal_new_having_algebra_node:
588  * @query: #rasqal_query query object
589  * @node1: inner algebra node
590  * @exprs_seq: sequence of variables
591  *
592  * INTERNAL - Create a new HAVING algebra node for a sequence of expressions over an inner node
593  *
594  * The inputs @node and @exprs_seq become owned by the new node
595  *
596  * Return value: a new #rasqal_algebra_node object or NULL on failure
597  **/
598 rasqal_algebra_node*
rasqal_new_having_algebra_node(rasqal_query * query,rasqal_algebra_node * node1,raptor_sequence * exprs_seq)599 rasqal_new_having_algebra_node(rasqal_query* query,
600                                rasqal_algebra_node* node1,
601                                raptor_sequence* exprs_seq)
602 {
603   rasqal_algebra_node* node;
604 
605   if(!query || !node1 || !exprs_seq)
606     goto fail;
607 
608   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_HAVING);
609   if(node) {
610     node->node1 = node1;
611     node->seq = exprs_seq;
612 
613     return node;
614   }
615 
616   fail:
617   if(node1)
618     rasqal_free_algebra_node(node1);
619   if(exprs_seq)
620     raptor_free_sequence(exprs_seq);
621 
622   return NULL;
623 }
624 
625 
626 /*
627  * rasqal_new_values_algebra_node:
628  * @query: #rasqal_query query object
629  * @bindings: variable bindings
630  *
631  * INTERNAL - Create a new VALUES algebra node for a binidngs
632  *
633  * The input @bindings become owned by the new node
634  *
635  * Return value: a new #rasqal_algebra_node object or NULL on failure
636  **/
637 rasqal_algebra_node*
rasqal_new_values_algebra_node(rasqal_query * query,rasqal_bindings * bindings)638 rasqal_new_values_algebra_node(rasqal_query* query,
639                                rasqal_bindings* bindings)
640 {
641   rasqal_algebra_node* node;
642 
643   if(!query || !bindings)
644     goto fail;
645 
646   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_VALUES);
647   if(node) {
648     node->bindings = bindings;
649     return node;
650   }
651 
652   fail:
653   if(bindings)
654     rasqal_free_bindings(bindings);
655 
656   return NULL;
657 }
658 
659 
660 /*
661  * rasqal_new_service_algebra_node:
662  * @query: #rasqal_query query object
663  * @service_uri: service URI
664  * @query_string: query string to send to the service
665  * @data_graphs: sequence of #rasqal_data_graph (or NULL)
666  * @silent: silent flag
667  *
668  * INTERNAL - Create a new SERVICE algebra node for a sequence of expressions over an inner node
669  *
670  * The inputs @service_uri, @query_string, and @data_graphs become owned by the new node
671  *
672  * Return value: a new #rasqal_algebra_node object or NULL on failure
673  **/
674 rasqal_algebra_node*
rasqal_new_service_algebra_node(rasqal_query * query,raptor_uri * service_uri,const unsigned char * query_string,raptor_sequence * data_graphs,int silent)675 rasqal_new_service_algebra_node(rasqal_query* query,
676                                 raptor_uri* service_uri,
677                                 const unsigned char* query_string,
678                                 raptor_sequence* data_graphs,
679                                 int silent)
680 {
681   rasqal_algebra_node* node;
682 
683   if(!query || !service_uri || !query_string)
684     goto fail;
685 
686   node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_SERVICE);
687   if(node) {
688     node->service_uri = service_uri;
689     node->query_string = query_string;
690     node->data_graphs = data_graphs;
691     node->flags = (silent ? RASQAL_ENGINE_BITFLAG_SILENT : 0);
692 
693     return node;
694   }
695 
696   fail:
697   if(service_uri)
698     raptor_free_uri(service_uri);
699   if(query_string)
700     RASQAL_FREE(cstring, query_string);
701   if(data_graphs)
702     raptor_free_sequence(data_graphs);
703 
704   return NULL;
705 }
706 
707 
708 /*
709  * rasqal_free_algebra_node:
710  * @gp: #rasqal_algebra_node object
711  *
712  * INTERNAL - Free an algebra node object.
713  *
714  **/
715 void
rasqal_free_algebra_node(rasqal_algebra_node * node)716 rasqal_free_algebra_node(rasqal_algebra_node* node)
717 {
718   if(!node)
719     return;
720 
721   /* node->triples is SHARED with the query - not freed here */
722 
723   if(node->node1)
724     rasqal_free_algebra_node(node->node1);
725 
726   if(node->node2)
727     rasqal_free_algebra_node(node->node2);
728 
729   if(node->expr)
730     rasqal_free_expression(node->expr);
731 
732   if(node->seq)
733     raptor_free_sequence(node->seq);
734 
735   if(node->vars_seq)
736     raptor_free_sequence(node->vars_seq);
737 
738   if(node->graph)
739     rasqal_free_literal(node->graph);
740 
741   if(node->var)
742     rasqal_free_variable(node->var);
743 
744   if(node->bindings)
745     rasqal_free_bindings(node->bindings);
746 
747   if(node->service_uri)
748     raptor_free_uri(node->service_uri);
749   if(node->query_string)
750     RASQAL_FREE(cstring, node->query_string);
751   if(node->data_graphs)
752     raptor_free_sequence(node->data_graphs);
753 
754   RASQAL_FREE(rasqal_algebra, node);
755 }
756 
757 
758 /**
759  * rasqal_algebra_node_get_operator:
760  * @algebra_node: #rasqal_algebra_node algebra node object
761  *
762  * Get the algebra node operator .
763  *
764  * The operator for the given algebra node. See also
765  * rasqal_algebra_node_operator_as_counted_string().
766  *
767  * Return value: algebra node operator
768  **/
769 rasqal_algebra_node_operator
rasqal_algebra_node_get_operator(rasqal_algebra_node * node)770 rasqal_algebra_node_get_operator(rasqal_algebra_node* node)
771 {
772   return node->op;
773 }
774 
775 
776 static struct {
777   const char* const label;
778   size_t length;
779 } rasqal_algebra_node_operator_labels[RASQAL_ALGEBRA_OPERATOR_LAST + 1] = {
780   { "UNKNOWN", 7 },
781   { "BGP" , 3 },
782   { "Filter", 6 },
783   { "Join", 4 },
784   { "Diff", 4 },
785   { "LeftJoin", 8 },
786   { "Union", 5 },
787   { "ToList", 6 },
788   { "OrderBy", 7 },
789   { "Project", 7 },
790   { "Distinct", 8 },
791   { "Reduced", 7 },
792   { "Slice", 5 },
793   { "Graph", 5 },
794   { "Assignment", 10 },
795   { "Group", 5 },
796   { "Aggregate", 9 },
797   { "Having", 6 },
798   { "Values", 6 },
799   { "Service", 7 }
800 };
801 
802 
803 /**
804  * rasqal_algebra_node_operator_as_counted_string:
805  * @op: the #rasqal_algebra_node_operator verb of the query
806  * @length_p: pointer to store the length (or NULL)
807  *
808  * INTERNAL - Get a counted string for the query verb.
809  *
810  * Return value: pointer to a shared string label for the query verb
811  **/
812 const char*
rasqal_algebra_node_operator_as_counted_string(rasqal_algebra_node_operator op,size_t * length_p)813 rasqal_algebra_node_operator_as_counted_string(rasqal_algebra_node_operator op,
814                                                size_t* length_p)
815 {
816   if(op <= RASQAL_ALGEBRA_OPERATOR_UNKNOWN ||
817      op > RASQAL_ALGEBRA_OPERATOR_LAST)
818     op = RASQAL_ALGEBRA_OPERATOR_UNKNOWN;
819 
820   if(length_p)
821     *length_p = rasqal_algebra_node_operator_labels[RASQAL_GOOD_CAST(int, op)].length;
822 
823   return rasqal_algebra_node_operator_labels[RASQAL_GOOD_CAST(int, op)].label;
824 }
825 
826 
827 
828 #define SPACES_LENGTH 80
829 static const char spaces[SPACES_LENGTH+1] = "                                                                                ";
830 
831 static void
rasqal_algebra_write_indent(raptor_iostream * iostr,unsigned int indent)832 rasqal_algebra_write_indent(raptor_iostream *iostr, unsigned int indent)
833 {
834   while(indent) {
835     unsigned int sp = (indent > SPACES_LENGTH) ? SPACES_LENGTH : indent;
836     raptor_iostream_write_bytes(spaces, sizeof(char), sp, iostr);
837     indent -= sp;
838   }
839 }
840 
841 static int
rasqal_algebra_algebra_node_write_internal(rasqal_algebra_node * node,raptor_iostream * iostr,unsigned int indent)842 rasqal_algebra_algebra_node_write_internal(rasqal_algebra_node *node,
843                                            raptor_iostream* iostr,
844                                            unsigned int indent)
845 {
846   const char* op_string;
847   size_t op_length;
848   int arg_count = 0;
849   unsigned int indent_delta;
850 
851   op_string = rasqal_algebra_node_operator_as_counted_string(node->op,
852                                                              &op_length);
853 
854   if(node->op == RASQAL_ALGEBRA_OPERATOR_BGP && !node->triples) {
855     raptor_iostream_write_byte('Z', iostr);
856     return 0;
857   }
858 
859   raptor_iostream_counted_string_write(op_string, op_length, iostr);
860   raptor_iostream_counted_string_write("(\n", 2, iostr);
861 
862   indent_delta = RASQAL_GOOD_CAST(unsigned int, op_length) + 1;
863 
864   indent += indent_delta;
865   rasqal_algebra_write_indent(iostr, indent);
866 
867   if(node->op == RASQAL_ALGEBRA_OPERATOR_BGP) {
868     int i;
869 
870     for(i = node->start_column; i <= node->end_column; i++) {
871       rasqal_triple *t;
872       t = (rasqal_triple*)raptor_sequence_get_at(node->triples, i);
873       if(arg_count) {
874         raptor_iostream_counted_string_write(" ,\n", 3, iostr);
875         rasqal_algebra_write_indent(iostr, indent);
876       }
877       rasqal_triple_write(t, iostr);
878       arg_count++;
879     }
880   }
881   if(node->node1) {
882     if(arg_count) {
883       raptor_iostream_counted_string_write(" ,\n", 3, iostr);
884       rasqal_algebra_write_indent(iostr, indent);
885     }
886     rasqal_algebra_algebra_node_write_internal(node->node1, iostr, indent);
887     arg_count++;
888     if(node->node2) {
889       if(arg_count) {
890         raptor_iostream_counted_string_write(" ,\n", 3, iostr);
891         rasqal_algebra_write_indent(iostr, indent);
892       }
893       rasqal_algebra_algebra_node_write_internal(node->node2, iostr, indent);
894       arg_count++;
895     }
896   }
897 
898   /* look for assignment var */
899   if(node->var) {
900     if(arg_count) {
901       raptor_iostream_counted_string_write(" ,\n", 3, iostr);
902       rasqal_algebra_write_indent(iostr, indent);
903     }
904     rasqal_variable_write(node->var, iostr);
905     arg_count++;
906   }
907 
908   /* look for FILTER expression */
909   if(node->expr) {
910     if(arg_count) {
911       raptor_iostream_counted_string_write(" ,\n", 3, iostr);
912       rasqal_algebra_write_indent(iostr, indent);
913     }
914     rasqal_expression_write(node->expr, iostr);
915     arg_count++;
916   }
917 
918   if(node->seq && node->op == RASQAL_ALGEBRA_OPERATOR_ORDERBY) {
919     int order_size = raptor_sequence_size(node->seq);
920     if(order_size) {
921       int i;
922 
923       if(arg_count) {
924         raptor_iostream_counted_string_write(" ,\n", 3, iostr);
925         rasqal_algebra_write_indent(iostr, indent);
926       }
927       raptor_iostream_counted_string_write("Conditions([ ", 13, iostr);
928       for(i = 0; i < order_size; i++) {
929         rasqal_expression* e;
930         e = (rasqal_expression*)raptor_sequence_get_at(node->seq, i);
931         if(i > 0)
932           raptor_iostream_counted_string_write(", ", 2, iostr);
933         rasqal_expression_write(e, iostr);
934         arg_count++;
935       }
936       raptor_iostream_counted_string_write(" ])", 3, iostr);
937     }
938   }
939 
940   if(node->vars_seq && node->op == RASQAL_ALGEBRA_OPERATOR_PROJECT) {
941     if(arg_count) {
942       raptor_iostream_counted_string_write(" ,\n", 3, iostr);
943       rasqal_algebra_write_indent(iostr, indent);
944     }
945     raptor_iostream_counted_string_write("Variables([ ", 12, iostr);
946     rasqal_variables_write(node->vars_seq, iostr);
947     arg_count += raptor_sequence_size(node->vars_seq);
948     raptor_iostream_counted_string_write(" ])", 3, iostr);
949   }
950 
951   if(node->op == RASQAL_ALGEBRA_OPERATOR_SLICE) {
952     if(arg_count) {
953       raptor_iostream_counted_string_write(" ,\n", 3, iostr);
954       rasqal_algebra_write_indent(iostr, indent);
955     }
956     raptor_iostream_string_write("slice limit ", iostr);
957     raptor_iostream_decimal_write(RASQAL_GOOD_CAST(int, node->limit), iostr);
958     raptor_iostream_string_write(" offset ", iostr);
959     raptor_iostream_decimal_write(RASQAL_GOOD_CAST(int, node->offset), iostr);
960     raptor_iostream_write_byte('\n', iostr);
961     arg_count++;
962   }
963 
964   if(node->op == RASQAL_ALGEBRA_OPERATOR_GRAPH) {
965     if(arg_count) {
966       raptor_iostream_counted_string_write(" ,\n", 3, iostr);
967       rasqal_algebra_write_indent(iostr, indent);
968     }
969     raptor_iostream_string_write("origin ", iostr);
970     rasqal_literal_write(node->graph, iostr);
971     raptor_iostream_write_byte('\n', iostr);
972   }
973 
974   raptor_iostream_write_byte('\n', iostr);
975   indent-= indent_delta;
976 
977   rasqal_algebra_write_indent(iostr, indent);
978   raptor_iostream_write_byte(')', iostr);
979 
980   return 0;
981 }
982 
983 
984 int
rasqal_algebra_algebra_node_write(rasqal_algebra_node * node,raptor_iostream * iostr)985 rasqal_algebra_algebra_node_write(rasqal_algebra_node *node,
986                                   raptor_iostream* iostr)
987 {
988   return rasqal_algebra_algebra_node_write_internal(node, iostr, 0);
989 }
990 
991 
992 /**
993  * rasqal_algebra_node_print:
994  * @gp: the #rasqal_algebra_node object
995  * @fh: the FILE* handle to print to
996  *
997  * Print a #rasqal_algebra_node in a debug format.
998  *
999  * The print debug format may change in any release.
1000  *
1001  * Return value: non-0 on failure
1002  **/
1003 int
rasqal_algebra_node_print(rasqal_algebra_node * node,FILE * fh)1004 rasqal_algebra_node_print(rasqal_algebra_node* node, FILE* fh)
1005 {
1006   raptor_iostream* iostr;
1007 
1008   iostr = raptor_new_iostream_to_file_handle(node->query->world->raptor_world_ptr, fh);
1009   rasqal_algebra_algebra_node_write(node, iostr);
1010   raptor_free_iostream(iostr);
1011 
1012   return 0;
1013 }
1014 
1015 
1016 /**
1017  * rasqal_algebra_node_visit:
1018  * @query: #rasqal_query to operate on
1019  * @node: #rasqal_algebra_node graph pattern
1020  * @fn: pointer to function to apply that takes user data and graph pattern parameters
1021  * @user_data: user data for applied function
1022  *
1023  * Visit a user function over a #rasqal_algebra_node
1024  *
1025  * If the user function @fn returns 0, the visit is truncated.
1026  *
1027  * Return value: 0 if the visit was truncated.
1028  **/
1029 int
rasqal_algebra_node_visit(rasqal_query * query,rasqal_algebra_node * node,rasqal_algebra_node_visit_fn fn,void * user_data)1030 rasqal_algebra_node_visit(rasqal_query *query,
1031                           rasqal_algebra_node* node,
1032                           rasqal_algebra_node_visit_fn fn,
1033                           void *user_data)
1034 {
1035   int result;
1036 
1037   result = fn(query, node, user_data);
1038   if(result)
1039     return result;
1040 
1041   if(node->node1) {
1042     result = rasqal_algebra_node_visit(query, node->node1, fn, user_data);
1043     if(result)
1044       return result;
1045   }
1046   if(node->node2) {
1047     result = rasqal_algebra_node_visit(query, node->node2, fn, user_data);
1048     if(result)
1049       return result;
1050   }
1051 
1052   return 0;
1053 }
1054 
1055 
1056 static rasqal_algebra_node*
rasqal_algebra_basic_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1057 rasqal_algebra_basic_graph_pattern_to_algebra(rasqal_query* query,
1058                                               rasqal_graph_pattern* gp)
1059 {
1060   rasqal_algebra_node* node = NULL;
1061   rasqal_expression* fs = NULL;
1062 
1063   node = rasqal_new_triples_algebra_node(query,
1064                                          rasqal_query_get_triple_sequence(query),
1065                                          gp->start_column, gp->end_column);
1066   if(!node)
1067     goto fail;
1068 
1069   if(gp->filter_expression) {
1070     fs = rasqal_new_expression_from_expression(gp->filter_expression);
1071     if(!fs) {
1072       RASQAL_DEBUG1("rasqal_new_expression_from_expression() failed\n");
1073       goto fail;
1074     }
1075 
1076     node = rasqal_new_filter_algebra_node(query, fs, node);
1077     fs = NULL; /* now owned by node */
1078     if(!node) {
1079       RASQAL_DEBUG1("rasqal_new_filter_algebra_node() failed\n");
1080       goto fail;
1081     }
1082   }
1083 
1084   return node;
1085 
1086   fail:
1087   if(node)
1088     rasqal_free_algebra_node(node);
1089 
1090   return NULL;
1091 }
1092 
1093 
1094 static rasqal_algebra_node*
rasqal_algebra_filter_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1095 rasqal_algebra_filter_graph_pattern_to_algebra(rasqal_query* query,
1096                                                rasqal_graph_pattern* gp)
1097 {
1098   rasqal_algebra_node* node = NULL;
1099   rasqal_expression* e;
1100 
1101   e = rasqal_new_expression_from_expression(gp->filter_expression);
1102   if(!e) {
1103     RASQAL_DEBUG1("rasqal_new_expression_from_expression() failed\n");
1104     return NULL;
1105   }
1106 
1107   node = rasqal_new_filter_algebra_node(query, e, NULL);
1108   e = NULL; /* now owned by node */
1109   if(!node) {
1110     RASQAL_DEBUG1("rasqal_new_filter_algebra_node() failed\n");
1111   }
1112 
1113   return node;
1114 }
1115 
1116 
1117 static rasqal_algebra_node*
rasqal_algebra_union_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1118 rasqal_algebra_union_graph_pattern_to_algebra(rasqal_query* query,
1119                                               rasqal_graph_pattern* gp)
1120 {
1121   int idx = 0;
1122   rasqal_algebra_node* node = NULL;
1123 
1124   while(1) {
1125     rasqal_graph_pattern* sgp;
1126     rasqal_algebra_node* gnode;
1127 
1128     sgp = rasqal_graph_pattern_get_sub_graph_pattern(gp, idx);
1129     if(!sgp)
1130       break;
1131 
1132     gnode = rasqal_algebra_graph_pattern_to_algebra(query, sgp);
1133     if(!gnode) {
1134       RASQAL_DEBUG1("rasqal_algebra_graph_pattern_to_algebra() failed\n");
1135       goto fail;
1136     }
1137 
1138     if(!node)
1139       node = gnode;
1140     else {
1141       node = rasqal_new_2op_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_UNION,
1142                                          node, gnode);
1143       if(!node) {
1144         RASQAL_DEBUG1("rasqal_new_2op_algebra_node() failed\n");
1145         goto fail;
1146       }
1147     }
1148 
1149     idx++;
1150   }
1151 
1152   return node;
1153 
1154   fail:
1155   if(node)
1156     rasqal_free_algebra_node(node);
1157 
1158   return NULL;
1159 }
1160 
1161 
1162 /*
1163  * Takes a reference to @bindings
1164  */
1165 static rasqal_algebra_node*
rasqal_algebra_bindings_to_algebra(rasqal_query * query,rasqal_bindings * bindings)1166 rasqal_algebra_bindings_to_algebra(rasqal_query* query,
1167                                    rasqal_bindings* bindings)
1168 {
1169   rasqal_algebra_node* node;
1170 
1171   bindings = rasqal_new_bindings_from_bindings(bindings);
1172   node = rasqal_new_values_algebra_node(query, bindings);
1173 
1174   return node;
1175 }
1176 
1177 
1178 static rasqal_algebra_node*
rasqal_algebra_values_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1179 rasqal_algebra_values_graph_pattern_to_algebra(rasqal_query* query,
1180                                                rasqal_graph_pattern* gp)
1181 {
1182   rasqal_algebra_node* node;
1183 
1184   node = rasqal_algebra_bindings_to_algebra(query, gp->bindings);
1185 
1186   return node;
1187 }
1188 
1189 
1190 /*
1191  * rasqal_algebra_new_boolean_constant_expr:
1192  * @query: query object
1193  * @value: boolean constant
1194  *
1195  * INTERNAL - Create a new expression for a boolean constant (true/false)
1196  *
1197  * Return value: new expression or NULL on failure
1198  */
1199 static rasqal_expression*
rasqal_algebra_new_boolean_constant_expr(rasqal_query * query,int value)1200 rasqal_algebra_new_boolean_constant_expr(rasqal_query* query, int value)
1201 {
1202   rasqal_literal *true_lit;
1203 
1204   true_lit = rasqal_new_boolean_literal(query->world, value);
1205   if(!true_lit) {
1206     RASQAL_DEBUG1("rasqal_new_boolean_literal() failed\n");
1207     return NULL;
1208   }
1209 
1210   return rasqal_new_literal_expression(query->world, true_lit);
1211 }
1212 
1213 
1214 static rasqal_algebra_node*
rasqal_algebra_group_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1215 rasqal_algebra_group_graph_pattern_to_algebra(rasqal_query* query,
1216                                               rasqal_graph_pattern* gp)
1217 {
1218   int idx = 0;
1219   /* Let FS := the empty set */
1220   rasqal_expression* fs = NULL;
1221   /* Let G := the empty pattern, Z, a basic graph pattern which
1222    * is the empty set. */
1223   rasqal_algebra_node* gnode = NULL;
1224 
1225   gnode = rasqal_new_empty_algebra_node(query);
1226   if(!gnode) {
1227     RASQAL_DEBUG1("rasqal_new_empty_algebra_node() failed\n");
1228     goto fail;
1229   }
1230 
1231   for(idx = 0; 1; idx++) {
1232     rasqal_graph_pattern* egp;
1233     egp = rasqal_graph_pattern_get_sub_graph_pattern(gp, idx);
1234     if(!egp)
1235       break;
1236 
1237     if(egp->op == RASQAL_GRAPH_PATTERN_OPERATOR_FILTER &&
1238        egp->filter_expression) {
1239       /* If E is of the form FILTER(expr)
1240          FS := FS set-union {expr}
1241       */
1242       rasqal_expression* e;
1243 
1244       /* add all gp->conditions_sequence to FS */
1245       e = rasqal_new_expression_from_expression(egp->filter_expression);
1246       if(!e) {
1247         RASQAL_DEBUG1("rasqal_new_expression_from_expression() failed\n");
1248         goto fail;
1249       }
1250       fs = fs ? rasqal_new_2op_expression(query->world, RASQAL_EXPR_AND, fs, e) : e;
1251 
1252       if(egp->op == RASQAL_GRAPH_PATTERN_OPERATOR_FILTER)
1253         continue;
1254     }
1255 
1256     if(egp->op == RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL) {
1257       /*  If E is of the form OPTIONAL{P} */
1258       int sgp_idx = 0;
1259       int sgp_size = raptor_sequence_size(egp->graph_patterns);
1260 
1261       /* walk through all optionals */
1262       for(sgp_idx = 0; sgp_idx < sgp_size; sgp_idx++) {
1263         rasqal_graph_pattern* sgp;
1264         rasqal_algebra_node* anode;
1265 
1266         sgp = rasqal_graph_pattern_get_sub_graph_pattern(egp, sgp_idx);
1267 
1268         /* Let A := Transform(P) */
1269         anode = rasqal_algebra_graph_pattern_to_algebra(query, sgp);
1270         if(!anode) {
1271           RASQAL_DEBUG1("rasqal_algebra_graph_pattern_to_algebra() failed\n");
1272           goto fail;
1273         }
1274 
1275         if(anode->op == RASQAL_ALGEBRA_OPERATOR_FILTER) {
1276           rasqal_expression* f_expr = anode->expr;
1277           rasqal_algebra_node *a2node = anode->node1;
1278           /* If A is of the form Filter(F, A2)
1279              G := LeftJoin(G, A2, F)
1280           */
1281           gnode = rasqal_new_leftjoin_algebra_node(query, gnode, a2node,
1282                                                    f_expr);
1283           anode->expr = NULL;
1284           anode->node1 = NULL;
1285           rasqal_free_algebra_node(anode);
1286           if(!gnode) {
1287             RASQAL_DEBUG1("rasqal_new_leftjoin_algebra_node() failed\n");
1288             goto fail;
1289           }
1290         } else  {
1291           rasqal_expression *true_expr = NULL;
1292 
1293           true_expr = rasqal_algebra_new_boolean_constant_expr(query, 1);
1294           if(!true_expr) {
1295             rasqal_free_algebra_node(anode);
1296             goto fail;
1297           }
1298 
1299           /* G := LeftJoin(G, A, true) */
1300           gnode = rasqal_new_leftjoin_algebra_node(query, gnode, anode,
1301                                                    true_expr);
1302           if(!gnode) {
1303             RASQAL_DEBUG1("rasqal_new_leftjoin_algebra_node() failed\n");
1304             goto fail;
1305           }
1306 
1307           true_expr = NULL; /* now owned by gnode */
1308         }
1309       } /* end for all optional */
1310     } else {
1311       /* If E is any other form:*/
1312       rasqal_algebra_node* anode;
1313 
1314       /* Let A := Transform(E) */
1315       anode = rasqal_algebra_graph_pattern_to_algebra(query, egp);
1316       if(!anode) {
1317         RASQAL_DEBUG1("rasqal_algebra_graph_pattern_to_algebra() failed\n");
1318         goto fail;
1319       }
1320 
1321       /* G := Join(G, A) */
1322       gnode = rasqal_new_2op_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_JOIN,
1323                                           gnode, anode);
1324       if(!gnode) {
1325         RASQAL_DEBUG1("rasqal_new_2op_algebra_node() failed\n");
1326         goto fail;
1327       }
1328     }
1329 
1330   }
1331 
1332   /*
1333     If FS is not empty:
1334     Let X := Conjunction of expressions in FS
1335     G := Filter(X, G)
1336 
1337     The result is G.
1338   */
1339   if(fs) {
1340     gnode = rasqal_new_filter_algebra_node(query, fs, gnode);
1341     fs = NULL; /* now owned by gnode */
1342     if(!gnode) {
1343       RASQAL_DEBUG1("rasqal_new_filter_algebra_node() failed\n");
1344       goto fail;
1345     }
1346   }
1347 
1348   if(gnode)
1349     return gnode;
1350 
1351   fail:
1352 
1353   if(gnode)
1354     rasqal_free_algebra_node(gnode);
1355   if(fs)
1356     rasqal_free_expression(fs);
1357   return NULL;
1358 }
1359 
1360 
1361 static rasqal_algebra_node*
rasqal_algebra_graph_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1362 rasqal_algebra_graph_graph_pattern_to_algebra(rasqal_query* query,
1363                                               rasqal_graph_pattern* gp)
1364 {
1365   rasqal_literal *graph = NULL;
1366   rasqal_graph_pattern* sgp;
1367   rasqal_algebra_node* gnode;
1368 
1369   if(gp->origin)
1370     graph = rasqal_new_literal_from_literal(gp->origin);
1371 
1372   sgp = rasqal_graph_pattern_get_sub_graph_pattern(gp, 0);
1373   if(!sgp)
1374     goto fail;
1375 
1376   gnode = rasqal_algebra_graph_pattern_to_algebra(query, sgp);
1377   if(!gnode) {
1378     RASQAL_DEBUG1("rasqal_algebra_graph_graph_pattern_to_algebra() failed\n");
1379     goto fail;
1380   }
1381 
1382   return rasqal_new_graph_algebra_node(query, gnode, graph);
1383 
1384   fail:
1385   if(graph)
1386     rasqal_free_literal(graph);
1387 
1388   return NULL;
1389 }
1390 
1391 
1392 static rasqal_algebra_node*
rasqal_algebra_let_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1393 rasqal_algebra_let_graph_pattern_to_algebra(rasqal_query* query,
1394                                             rasqal_graph_pattern* gp)
1395 {
1396   rasqal_expression *expr;
1397 
1398   expr = rasqal_new_expression_from_expression(gp->filter_expression);
1399   if(expr)
1400     return rasqal_new_assignment_algebra_node(query, gp->var, expr);
1401 
1402   return NULL;
1403 }
1404 
1405 
1406 static rasqal_algebra_node*
rasqal_algebra_select_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1407 rasqal_algebra_select_graph_pattern_to_algebra(rasqal_query* query,
1408                                                rasqal_graph_pattern* gp)
1409 {
1410   rasqal_projection* projection;
1411   rasqal_solution_modifier* modifier;
1412   rasqal_graph_pattern* where_gp;
1413   rasqal_algebra_node* where_node;
1414   rasqal_algebra_node* node;
1415   rasqal_algebra_aggregate* ae;
1416   rasqal_bindings* bindings;
1417 
1418   where_gp = rasqal_graph_pattern_get_sub_graph_pattern(gp, 0);
1419   projection = gp->projection;
1420   modifier = gp->modifier;
1421   bindings = gp->bindings;
1422 
1423   where_node = rasqal_algebra_graph_pattern_to_algebra(query, where_gp);
1424   if(!where_node)
1425     goto fail;
1426 
1427   node = rasqal_algebra_query_add_group_by(query, where_node, modifier);
1428   where_node = NULL; /* now owned by node */
1429   if(!node)
1430     goto fail;
1431 
1432   ae = rasqal_algebra_query_prepare_aggregates(query, node, projection,
1433                                                modifier);
1434   if(!ae)
1435     goto fail;
1436 
1437   if(ae) {
1438     node = rasqal_algebra_query_add_aggregation(query, ae, node);
1439     ae = NULL;
1440     if(!node)
1441       goto fail;
1442   }
1443 
1444   node = rasqal_algebra_query_add_having(query, node, modifier);
1445   if(!node)
1446     goto fail;
1447 
1448   node = rasqal_algebra_query_add_projection(query, node, projection);
1449   if(!node)
1450     goto fail;
1451 
1452   node = rasqal_algebra_query_add_orderby(query, node, projection, modifier);
1453   if(!node)
1454     goto fail;
1455 
1456   node = rasqal_algebra_query_add_distinct(query, node, projection);
1457   if(!node)
1458     goto fail;
1459 
1460   node = rasqal_algebra_query_add_slice(query, node, modifier);
1461   if(!node)
1462     goto fail;
1463 
1464   if(bindings) {
1465     rasqal_algebra_node* bindings_node;
1466 
1467     bindings_node = rasqal_algebra_bindings_to_algebra(query, bindings);
1468     if(!bindings_node) {
1469       rasqal_free_algebra_node(node);
1470       goto fail;
1471     }
1472 
1473     node = rasqal_new_2op_algebra_node(query,
1474                                        RASQAL_ALGEBRA_OPERATOR_JOIN,
1475                                        node, bindings_node);
1476   }
1477 
1478   return node;
1479 
1480   fail:
1481   return NULL;
1482 }
1483 
1484 
1485 static rasqal_algebra_node*
rasqal_algebra_service_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1486 rasqal_algebra_service_graph_pattern_to_algebra(rasqal_query* query,
1487                                                 rasqal_graph_pattern* gp)
1488 {
1489   rasqal_algebra_node* node = NULL;
1490   raptor_uri* service_uri = NULL;
1491   raptor_sequence* data_graphs = NULL;
1492   rasqal_graph_pattern* inner_gp;
1493   char* string = NULL;
1494   raptor_iostream *iostr = NULL;
1495 
1496   service_uri = rasqal_literal_as_uri(gp->origin);
1497   if(!service_uri)
1498     goto fail;
1499 
1500   inner_gp = rasqal_graph_pattern_get_sub_graph_pattern(gp, 0);
1501   if(!inner_gp)
1502     goto fail;
1503 
1504   iostr = raptor_new_iostream_to_string(query->world->raptor_world_ptr,
1505                                         (void**)&string, NULL,
1506                                         rasqal_alloc_memory);
1507   if(!iostr)
1508     goto fail;
1509 
1510   rasqal_query_write_sparql_20060406_graph_pattern(inner_gp, iostr,
1511                                                    query->base_uri);
1512   raptor_free_iostream(iostr); iostr = NULL;
1513 
1514   RASQAL_DEBUG2("Formatted query string is '%s'", string);
1515 
1516 
1517   node = rasqal_new_service_algebra_node(query,
1518                                          raptor_uri_copy(service_uri),
1519                                          (const unsigned char*)string,
1520                                          data_graphs, gp->silent);
1521   string = NULL;
1522   if(!node) {
1523     RASQAL_DEBUG1("rasqal_new_service_algebra_node() failed\n");
1524     goto fail;
1525   }
1526 
1527   return node;
1528 
1529   fail:
1530   if(string)
1531     RASQAL_FREE(char*, string);
1532 
1533   return node;
1534 }
1535 
1536 
1537 
1538 static rasqal_algebra_node*
rasqal_algebra_graph_pattern_to_algebra(rasqal_query * query,rasqal_graph_pattern * gp)1539 rasqal_algebra_graph_pattern_to_algebra(rasqal_query* query,
1540                                         rasqal_graph_pattern* gp)
1541 {
1542   rasqal_algebra_node* node = NULL;
1543 
1544   switch(gp->op) {
1545     case RASQAL_GRAPH_PATTERN_OPERATOR_BASIC:
1546       node = rasqal_algebra_basic_graph_pattern_to_algebra(query, gp);
1547       break;
1548 
1549     case RASQAL_GRAPH_PATTERN_OPERATOR_UNION:
1550       node = rasqal_algebra_union_graph_pattern_to_algebra(query, gp);
1551       break;
1552 
1553     case RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL:
1554     case RASQAL_GRAPH_PATTERN_OPERATOR_GROUP:
1555       node = rasqal_algebra_group_graph_pattern_to_algebra(query, gp);
1556       break;
1557 
1558     case RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH:
1559       node = rasqal_algebra_graph_graph_pattern_to_algebra(query, gp);
1560       break;
1561 
1562     case RASQAL_GRAPH_PATTERN_OPERATOR_LET:
1563       node = rasqal_algebra_let_graph_pattern_to_algebra(query, gp);
1564       break;
1565 
1566     case RASQAL_GRAPH_PATTERN_OPERATOR_SELECT:
1567       node = rasqal_algebra_select_graph_pattern_to_algebra(query, gp);
1568       break;
1569 
1570     case RASQAL_GRAPH_PATTERN_OPERATOR_FILTER:
1571       node = rasqal_algebra_filter_graph_pattern_to_algebra(query, gp);
1572       break;
1573 
1574     case RASQAL_GRAPH_PATTERN_OPERATOR_VALUES:
1575       node = rasqal_algebra_values_graph_pattern_to_algebra(query, gp);
1576       break;
1577 
1578     case RASQAL_GRAPH_PATTERN_OPERATOR_SERVICE:
1579       node = rasqal_algebra_service_graph_pattern_to_algebra(query, gp);
1580       break;
1581 
1582     case RASQAL_GRAPH_PATTERN_OPERATOR_MINUS:
1583 
1584     case RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN:
1585     default:
1586       RASQAL_DEBUG3("Unsupported graph pattern operator %s (%u)\n",
1587                     rasqal_graph_pattern_operator_as_string(gp->op),
1588                     gp->op);
1589       break;
1590   }
1591 
1592 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
1593   if(gp) {
1594     RASQAL_DEBUG1("Input gp:\n");
1595     rasqal_graph_pattern_print(gp, stderr);
1596     fputc('\n', stderr);
1597   }
1598 
1599   if(node) {
1600     RASQAL_DEBUG1("Resulting node:\n");
1601     rasqal_algebra_node_print(node, stderr);
1602     fputc('\n', stderr);
1603   }
1604 #endif /* not STANDALONE */
1605 
1606   return node;
1607 }
1608 
1609 
1610 /*
1611  * rasqal_algebra_node_is_empty:
1612  * @node: #rasqal_algebra_node node
1613  *
1614  * INTERNAL - Check if a an algebra node is empty
1615  *
1616  * Return value: non-0 if empty
1617  **/
1618 int
rasqal_algebra_node_is_empty(rasqal_algebra_node * node)1619 rasqal_algebra_node_is_empty(rasqal_algebra_node* node)
1620 {
1621   return (node->op == RASQAL_ALGEBRA_OPERATOR_BGP && !node->triples);
1622 }
1623 
1624 
1625 static int
rasqal_algebra_remove_znodes(rasqal_query * query,rasqal_algebra_node * node,void * data)1626 rasqal_algebra_remove_znodes(rasqal_query* query, rasqal_algebra_node* node,
1627                              void* data)
1628 {
1629   int* modified = (int*)data;
1630   int is_z1;
1631   int is_z2;
1632   rasqal_algebra_node *anode;
1633 
1634   if(!node)
1635     return 1;
1636 
1637   /* Look for join operations with no variable join conditions and see if they
1638    * can be merged, when one of node1 or node2 is an empty graph pattern.
1639    */
1640   if(node->op != RASQAL_ALGEBRA_OPERATOR_JOIN &&
1641      node->op != RASQAL_ALGEBRA_OPERATOR_LEFTJOIN)
1642     return 0;
1643 
1644   /* Evaluate if the join condition expression is constant TRUE */
1645   if(node->expr) {
1646     rasqal_literal* result;
1647     int bresult;
1648     int error = 0;
1649 
1650     if(!rasqal_expression_is_constant(node->expr))
1651        return 0;
1652 
1653     result = rasqal_expression_evaluate2(node->expr, query->eval_context,
1654                                          &error);
1655     if(error)
1656       return 0;
1657 
1658     bresult = rasqal_literal_as_boolean(result, &error);
1659     rasqal_free_literal(result);
1660     if(error)
1661       return 0;
1662 
1663     if(!bresult) {
1664       /* join condition is always FALSE - can never merge - this join
1665        * is useless and should be replaced with an empty graph
1666        * pattern - FIXME  */
1667       return 0;
1668     }
1669 
1670     /* conclusion: join condition is always TRUE - so can merge nodes */
1671     rasqal_free_expression(node->expr);
1672     node->expr = NULL;
1673   }
1674 
1675 
1676   if(!node->node1 || !node->node2)
1677     return 0;
1678 
1679   /* Look for empty graph patterns */
1680   is_z1 = rasqal_algebra_node_is_empty(node->node1);
1681   is_z2 = rasqal_algebra_node_is_empty(node->node2);
1682 
1683 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
1684   RASQAL_DEBUG1("Checking node\n");
1685   rasqal_algebra_node_print(node, stderr);
1686   fprintf(stderr, "\nNode 1 (%s): %s\n",
1687           is_z1 ? "empty" : "not empty",
1688           rasqal_algebra_node_operator_as_counted_string(node->node1->op, NULL));
1689   fprintf(stderr, "Node 2 (%s): %s\n",
1690           is_z2 ? "empty" : "not empty",
1691           rasqal_algebra_node_operator_as_counted_string(node->node2->op, NULL));
1692 #endif
1693 
1694   if(is_z1 && !is_z2) {
1695     /* Replace join(Z, A) by A */
1696 
1697     anode = node->node2;
1698     /* an empty node has no extra things to free */
1699     RASQAL_FREE(rasqal_algebra_node, node->node1);
1700     memcpy(node, anode, sizeof(rasqal_algebra_node));
1701     /* free the node struct memory - contained pointers now owned by node */
1702     RASQAL_FREE(rasqal_algebra_node, anode);
1703     *modified = 1;
1704   } else if(!is_z1 && is_z2) {
1705     /* Replace join(A, Z) by A */
1706 
1707     anode = node->node1;
1708     /* ditto */
1709     RASQAL_FREE(rasqal_algebra_node, node->node2);
1710     memcpy(node, anode, sizeof(rasqal_algebra_node));
1711     RASQAL_FREE(rasqal_algebra_node, anode);
1712     *modified = 1;
1713   }
1714 
1715   return 0;
1716 }
1717 
1718 
1719 static raptor_sequence*
rasqal_algebra_get_variables_mentioned_in(rasqal_query * query,int row_index)1720 rasqal_algebra_get_variables_mentioned_in(rasqal_query* query,
1721                                           int row_index)
1722 {
1723   raptor_sequence* seq; /* sequence of rasqal_variable* */
1724   int width;
1725   unsigned short *row;
1726   int i;
1727 
1728   seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
1729                             (raptor_data_print_handler)rasqal_variable_print);
1730   if(!seq)
1731     return NULL;
1732 
1733   width = rasqal_variables_table_get_total_variables_count(query->vars_table);
1734   row = &query->variables_use_map[row_index * width];
1735 
1736   for(i = 0; i < width; i++) {
1737     rasqal_variable* v;
1738 
1739     if(!(row[i] & RASQAL_VAR_USE_MENTIONED_HERE))
1740       continue;
1741 
1742     v = rasqal_variables_table_get(query->vars_table, i);
1743     raptor_sequence_push(seq, rasqal_new_variable_from_variable(v));
1744   }
1745 
1746   return seq;
1747 }
1748 
1749 
1750 /**
1751  * rasqal_agg_expr_var_compare:
1752  * @user_data: comparison user data pointer
1753  * @a: pointer to address of first #rasqal_expression
1754  * @b: pointer to address of second #rasqal_expression
1755  *
1756  * INTERNAL - compare two void pointers to #rasqal_expression objects with signature suitable for for #rasqal_map comparison.
1757  *
1758  * Return value: <0, 0 or >1 comparison
1759  */
1760 static int
rasqal_agg_expr_var_compare(void * user_data,const void * a,const void * b)1761 rasqal_agg_expr_var_compare(void* user_data, const void *a, const void *b)
1762 {
1763   rasqal_algebra_aggregate* ae = (rasqal_algebra_aggregate*)user_data;
1764   rasqal_expression* expr_a  = (rasqal_expression*)a;
1765   rasqal_expression* expr_b  = (rasqal_expression*)b;
1766   int result = 0;
1767 
1768   result = rasqal_expression_compare(expr_a, expr_b, ae->flags, &ae->error);
1769 
1770   return result;
1771 }
1772 
1773 
1774 /*
1775  * SPEC:
1776  *   at each node:
1777  *     if expression contains an aggregate function
1778  *       is expression is in map?
1779  *       Yes:
1780  *         get value => use existing internal variable for it
1781  *       No:
1782  *         create a new internal variable for it $$internal{id}
1783  *         inc id
1784  *         add it to the map
1785  *       rewrite expression to use internal variable
1786  *
1787  */
1788 static int
rasqal_algebra_extract_aggregate_expression_visit(void * user_data,rasqal_expression * e)1789 rasqal_algebra_extract_aggregate_expression_visit(void *user_data,
1790                                                   rasqal_expression *e)
1791 {
1792   rasqal_algebra_aggregate* ae = (rasqal_algebra_aggregate*)user_data;
1793   rasqal_variable* v;
1794 
1795   ae->error = 0;
1796 
1797   /* If not an aggregate expression, ignore it */
1798   if(!rasqal_expression_is_aggregate(e))
1799     return 0;
1800 
1801 
1802   /* is expression is in map? */
1803   v = (rasqal_variable*)rasqal_map_search(ae->agg_vars, e);
1804   if(v) {
1805     /* Yes: get value => use existing internal variable for it */
1806     RASQAL_DEBUG2("Found variable %s for existing expression\n", v->name);
1807 
1808     /* add a new reference to v */
1809     v = rasqal_new_variable_from_variable(v);
1810 
1811     /* convert expression in-situ to use existing internal variable
1812      * After this e holds a v reference
1813      */
1814     if(rasqal_expression_convert_aggregate_to_variable(e, v, NULL)) {
1815       ae->error = 1;
1816       return 1;
1817     }
1818 
1819 
1820   } else {
1821     /* No */
1822     char var_name[20];
1823     rasqal_expression* new_e = NULL;
1824 
1825     /* Check if a new variable is allowed to be added */
1826     if(ae->adding_new_vars_is_error) {
1827       rasqal_log_error_simple(ae->query->world, RAPTOR_LOG_LEVEL_ERROR,
1828                               NULL, "Found new aggregate expression in %s",
1829                               ae->error_part);
1830       ae->error = 1;
1831       return 1;
1832     }
1833 
1834     /* If not an error, create a new internal variable name for it
1835      * $$agg{id}$$ and add it to the map.
1836      */
1837     sprintf(var_name, "$$agg$$%d", ae->counter++);
1838 
1839     v = rasqal_variables_table_add2(ae->query->vars_table,
1840                                     RASQAL_VARIABLE_TYPE_ANONYMOUS,
1841                                     RASQAL_GOOD_CAST(const unsigned char*, var_name),
1842                                     0,
1843                                     NULL);
1844     if(!v) {
1845       ae->error = 1;
1846       return 1;
1847     }
1848 
1849     /* convert expression in-situ to use new internal variable
1850      * and create a new expression in new_e from the old fields.
1851      *
1852      * After this one v reference is held by new_e.
1853      */
1854     if(rasqal_expression_convert_aggregate_to_variable(e, v, &new_e)) {
1855       ae->error = 1;
1856       return 1;
1857     }
1858 
1859     v = rasqal_new_variable_from_variable(v);
1860 
1861     /* new_e is a new reference
1862      * after this new_e and 1 v reference are owned by the map
1863      */
1864     if(rasqal_map_add_kv(ae->agg_vars, new_e, v)) {
1865       ae->error = 1;
1866       return 1;
1867     }
1868 
1869 #ifdef RASQAL_DEBUG
1870     RASQAL_DEBUG1("after adding new variable, resulting aggregate vars ");
1871     rasqal_map_print(ae->agg_vars, stderr);
1872     fputc('\n', stderr);
1873 #endif
1874 
1875     new_e = rasqal_new_expression_from_expression(new_e);
1876     if(raptor_sequence_push(ae->agg_exprs, new_e)) {
1877       ae->error = 1;
1878       return 1;
1879     }
1880 
1881     /* add one more v reference for the variables sequence too */
1882     v = rasqal_new_variable_from_variable(v);
1883     if(raptor_sequence_push(ae->agg_vars_seq, v)) {
1884       ae->error = 1;
1885       return 1;
1886     }
1887 
1888   }
1889 
1890 
1891   return 0;
1892 }
1893 
1894 
1895 static int
rasqal_algebra_extract_aggregate_expressions(rasqal_query * query,rasqal_algebra_node * node,rasqal_algebra_aggregate * ae,rasqal_projection * projection)1896 rasqal_algebra_extract_aggregate_expressions(rasqal_query* query,
1897                                              rasqal_algebra_node* node,
1898                                              rasqal_algebra_aggregate* ae,
1899                                              rasqal_projection* projection)
1900 {
1901   raptor_sequence* seq;
1902   int i;
1903   int rc = 0;
1904   rasqal_variable* v;
1905 
1906   if(!projection)
1907     return 0;
1908 
1909   ae->query = query;
1910 
1911   /* Initialisation of map (key: rasqal_expression, value: rasqal_variable ) */
1912   ae->agg_vars = rasqal_new_map(/* compare key function */ rasqal_agg_expr_var_compare,
1913                                 /* compare data */ ae,
1914                                 /* free compare data */ NULL,
1915                                 (raptor_data_free_handler)rasqal_free_expression,
1916                                 (raptor_data_free_handler)rasqal_free_variable,
1917                                 (raptor_data_print_handler)rasqal_expression_print,
1918                                 (raptor_data_print_handler)rasqal_variable_print,
1919                                 /* flags */ 0);
1920 
1921   /* Sequence to hold list of aggregate expressions */
1922   seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_expression,
1923                             (raptor_data_print_handler)rasqal_expression_print);
1924   ae->agg_exprs = seq;
1925 
1926   seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
1927                             (raptor_data_print_handler)rasqal_variable_print);
1928   ae->agg_vars_seq = seq;
1929 
1930   /* init internal variable counter */
1931   ae->counter = 0;
1932 
1933   ae->flags = 0;
1934 
1935   ae->error = 0;
1936 
1937   /*
1938    * walk each select/project expression recursively and pull out aggregate
1939    * expressions into the ae->agg_vars map, replacing them with
1940    * internal variable names.
1941    */
1942   if ((seq = projection->variables)) {
1943     for(i = 0;
1944 	(v = (rasqal_variable*)raptor_sequence_get_at(seq, i));
1945 	i++) {
1946       rasqal_expression* expr = v->expression;
1947 
1948       if(!expr)
1949 	continue;
1950 
1951       if(rasqal_expression_visit(expr,
1952 				 rasqal_algebra_extract_aggregate_expression_visit,
1953 				 ae)) {
1954 	rc = 1;
1955 	goto tidy;
1956       }
1957     }
1958   }
1959 
1960   tidy:
1961   if(ae->error)
1962     rc = 1;
1963 
1964   return rc;
1965 }
1966 
1967 
1968 /**
1969  * rasqal_algebra_query_to_algebra:
1970  * @query: #rasqal_query to operate on
1971  *
1972  * Turn a graph pattern into query algebra structure
1973  *
1974  * Return value: algebra expression or NULL on failure
1975  */
1976 rasqal_algebra_node*
rasqal_algebra_query_to_algebra(rasqal_query * query)1977 rasqal_algebra_query_to_algebra(rasqal_query* query)
1978 {
1979   rasqal_graph_pattern* query_gp;
1980   rasqal_algebra_node* node;
1981   int modified = 0;
1982 
1983   query_gp = rasqal_query_get_query_graph_pattern(query);
1984   if(!query_gp)
1985     return NULL;
1986 
1987   node = rasqal_algebra_graph_pattern_to_algebra(query, query_gp);
1988   if(!node)
1989     return NULL;
1990 
1991   /* FIXME - this does not seem right to be here */
1992   if(query->bindings) {
1993     rasqal_algebra_node* bindings_node;
1994 
1995     bindings_node = rasqal_algebra_bindings_to_algebra(query, query->bindings);
1996     if(!bindings_node) {
1997       rasqal_free_algebra_node(node);
1998       return NULL;
1999     }
2000 
2001     node = rasqal_new_2op_algebra_node(query,
2002                                        RASQAL_ALGEBRA_OPERATOR_JOIN,
2003                                        node, bindings_node);
2004   }
2005 
2006   rasqal_algebra_node_visit(query, node,
2007                             rasqal_algebra_remove_znodes,
2008                             &modified);
2009 
2010 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2011   RASQAL_DEBUG1("modified after remove zones, algebra node now:\n  ");
2012   rasqal_algebra_node_print(node, stderr);
2013   fputs("\n", stderr);
2014 #endif
2015 
2016 
2017   return node;
2018 }
2019 
2020 
2021 void
rasqal_free_algebra_aggregate(rasqal_algebra_aggregate * ae)2022 rasqal_free_algebra_aggregate(rasqal_algebra_aggregate* ae)
2023 {
2024   if(!ae)
2025     return;
2026 
2027   if(ae->agg_exprs)
2028     raptor_free_sequence(ae->agg_exprs);
2029 
2030   if(ae->agg_vars)
2031     rasqal_free_map(ae->agg_vars);
2032 
2033   if(ae->agg_vars_seq)
2034     raptor_free_sequence(ae->agg_vars_seq);
2035 
2036   RASQAL_FREE(rasqal_algebra_aggregate, ae);
2037 }
2038 
2039 
2040 static int
rasqal_algebra_replace_aggregate_expressions(rasqal_query * query,raptor_sequence * exprs_seq,rasqal_algebra_aggregate * ae)2041 rasqal_algebra_replace_aggregate_expressions(rasqal_query* query,
2042                                              raptor_sequence* exprs_seq,
2043                                              rasqal_algebra_aggregate* ae)
2044 {
2045   int i;
2046   rasqal_expression* expr;
2047 
2048   /* It is now a mistake to find a new aggregate expressions not
2049    * previously found in SELECT
2050    */
2051   ae->adding_new_vars_is_error = 1;
2052   ae->error_part = "HAVING";
2053 
2054   for(i = 0;
2055       (expr = (rasqal_expression*)raptor_sequence_get_at(exprs_seq, i));
2056       i++) {
2057 
2058     if(rasqal_expression_visit(expr,
2059                                rasqal_algebra_extract_aggregate_expression_visit,
2060                                ae)) {
2061       return 1;
2062     }
2063 
2064   }
2065 
2066   return 0;
2067 }
2068 
2069 
2070 /**
2071  * rasqal_algebra_query_prepare_aggregates:
2072  * @query: #rasqal_query to read from
2073  * @node: algebra node to prepare
2074  * @projection: variable projection to use
2075  * @modifier: solution modifier to use
2076  *
2077  * INTERNAL - prepare query aggregates
2078  *
2079  * Return value: aggregate expression data or NULL on failure
2080  */
2081 rasqal_algebra_aggregate*
rasqal_algebra_query_prepare_aggregates(rasqal_query * query,rasqal_algebra_node * node,rasqal_projection * projection,rasqal_solution_modifier * modifier)2082 rasqal_algebra_query_prepare_aggregates(rasqal_query* query,
2083                                         rasqal_algebra_node* node,
2084                                         rasqal_projection* projection,
2085                                         rasqal_solution_modifier* modifier)
2086 {
2087   rasqal_algebra_aggregate* ae;
2088 
2089   ae = RASQAL_CALLOC(rasqal_algebra_aggregate*, 1, sizeof(*ae));
2090   if(!ae)
2091     return NULL;
2092 
2093   if(rasqal_algebra_extract_aggregate_expressions(query, node, ae, projection)) {
2094     RASQAL_DEBUG1("rasqal_algebra_extract_aggregate_expressions() failed\n");
2095     rasqal_free_algebra_aggregate(ae);
2096     rasqal_free_algebra_node(node);
2097     return NULL;
2098   }
2099 
2100   /* Update variable use structures since agg variables were created */
2101   if(ae->counter)
2102     rasqal_query_build_variables_use(query, projection);
2103 
2104 #ifdef RASQAL_DEBUG
2105   if(ae->counter) {
2106     raptor_sequence* seq = projection->variables;
2107 
2108     if(seq) {
2109       RASQAL_DEBUG1("after aggregate expressions extracted:\n");
2110       raptor_sequence_print(seq, stderr);
2111       fputs("\n", stderr);
2112 
2113       RASQAL_DEBUG1("aggregate expressions:\n");
2114       raptor_sequence_print(ae->agg_exprs, stderr);
2115       fputs("\n", stderr);
2116     }
2117   } else {
2118     RASQAL_DEBUG1("found no aggregate expressions in select\n");
2119   }
2120 #endif
2121 
2122 
2123   /* if agg expressions were found, need to walk HAVING list and do a
2124    * similar replacement substituion in the expressions
2125    */
2126   if(ae->counter && modifier && modifier->having_conditions) {
2127     if(rasqal_algebra_replace_aggregate_expressions(query,
2128                                                     modifier->having_conditions,
2129                                                     ae)) {
2130       RASQAL_DEBUG1("rasqal_algebra_replace_aggregate_expressions() failed\n");
2131       rasqal_free_algebra_aggregate(ae);
2132       rasqal_free_algebra_node(node);
2133       return NULL;
2134     }
2135   }
2136 
2137   return ae;
2138 }
2139 
2140 
2141 /**
2142  * rasqal_algebra_query_add_group_by:
2143  * @query: #rasqal_query to read from
2144  * @node: node to apply modifiers to
2145  * @modifier: solution modifier to use
2146  *
2147  * Apply any needed GROUP BY to query algebra structure
2148  *
2149  * Return value: non-0 on failure
2150  */
2151 rasqal_algebra_node*
rasqal_algebra_query_add_group_by(rasqal_query * query,rasqal_algebra_node * node,rasqal_solution_modifier * modifier)2152 rasqal_algebra_query_add_group_by(rasqal_query* query,
2153                                   rasqal_algebra_node* node,
2154                                   rasqal_solution_modifier* modifier)
2155 {
2156   raptor_sequence* modifier_seq;
2157 
2158   if(!modifier)
2159     return node;
2160 
2161   /* GROUP BY */
2162   modifier_seq = modifier->group_conditions;
2163 
2164   if(modifier_seq) {
2165     raptor_sequence* seq;
2166 
2167     /* Make a deep copy of the query group conditions sequence for
2168      * the GROUP algebra node
2169      */
2170     seq = rasqal_expression_copy_expression_sequence(modifier_seq);
2171     if(!seq) {
2172       rasqal_free_algebra_node(node);
2173       return NULL;
2174     }
2175 
2176     node = rasqal_new_groupby_algebra_node(query, node, seq);
2177 
2178 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2179     RASQAL_DEBUG1("modified after adding group node, algebra node now:\n  ");
2180     rasqal_algebra_node_print(node, stderr);
2181     fputs("\n", stderr);
2182 #endif
2183   }
2184 
2185   return node;
2186 }
2187 
2188 
2189 /**
2190  * rasqal_algebra_query_add_orderby:
2191  * @query: #rasqal_query to read from
2192  * @node: node to apply modifiers to
2193  * @projection: variable projection to use
2194  * @modifier: solution modifier to use
2195  *
2196  * Apply any needed modifiers to query algebra structure
2197  *
2198  * Return value: non-0 on failure
2199  */
2200 rasqal_algebra_node*
rasqal_algebra_query_add_orderby(rasqal_query * query,rasqal_algebra_node * node,rasqal_projection * projection,rasqal_solution_modifier * modifier)2201 rasqal_algebra_query_add_orderby(rasqal_query* query,
2202                                  rasqal_algebra_node* node,
2203                                  rasqal_projection* projection,
2204                                  rasqal_solution_modifier* modifier)
2205 {
2206   raptor_sequence* modifier_seq;
2207   int distinct = 0;
2208 
2209   if(!modifier)
2210     return node;
2211 
2212   /* ORDER BY */
2213   modifier_seq = modifier->order_conditions;
2214   if(modifier_seq) {
2215     raptor_sequence* seq;
2216 
2217     /* Make a deep copy of the query order conditions sequence for
2218      * the ORDERBY algebra node
2219      */
2220     seq = rasqal_expression_copy_expression_sequence(modifier_seq);
2221     if(!seq) {
2222       rasqal_free_algebra_node(node);
2223       return NULL;
2224     }
2225 
2226     if(projection)
2227       distinct = projection->distinct;
2228 
2229     node = rasqal_new_orderby_algebra_node(query, node, seq, distinct);
2230 
2231 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2232     RASQAL_DEBUG1("modified after adding orderby node, algebra node now:\n  ");
2233     rasqal_algebra_node_print(node, stderr);
2234     fputs("\n", stderr);
2235 #endif
2236   }
2237 
2238   return node;
2239 }
2240 
2241 
2242 /**
2243  * rasqal_algebra_query_add_slice:
2244  * @query: #rasqal_query to read from
2245  * @node: node to apply modifiers to
2246  * @modifier: solution modifier to use
2247  *
2248  * Apply any needed slice (LIMIT, OFFSET) modifiers to query algebra structure
2249  *
2250  * This is separate from rasqal_algebra_query_add_orderby() since currently
2251  * the query results module implements that for the outer result rows.
2252  *
2253  * Return value: non-0 on failure
2254  */
2255 rasqal_algebra_node*
rasqal_algebra_query_add_slice(rasqal_query * query,rasqal_algebra_node * node,rasqal_solution_modifier * modifier)2256 rasqal_algebra_query_add_slice(rasqal_query* query,
2257                                rasqal_algebra_node* node,
2258                                rasqal_solution_modifier* modifier)
2259 {
2260   if(!modifier)
2261     return node;
2262 
2263   /* LIMIT and OFFSET */
2264   if(modifier->limit > 0 || modifier->offset > 0) {
2265     node = rasqal_new_slice_algebra_node(query, node, modifier->limit, modifier->offset);
2266 
2267 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2268     RASQAL_DEBUG1("modified after adding slice node, algebra node now:\n  ");
2269     rasqal_algebra_node_print(node, stderr);
2270     fputs("\n", stderr);
2271 #endif
2272   }
2273 
2274   return node;
2275 }
2276 
2277 
2278 /**
2279  * rasqal_algebra_query_add_aggregation:
2280  * @query: #rasqal_query to read from
2281  * @ae: aggregation structure
2282  * @node: node to apply aggregation to
2283  *
2284  * Apply any aggregation step needed to query algebra structure
2285  *
2286  * Becomes the owner of @ae
2287  *
2288  * Return value: non-0 on failure
2289  */
2290 rasqal_algebra_node*
rasqal_algebra_query_add_aggregation(rasqal_query * query,rasqal_algebra_aggregate * ae,rasqal_algebra_node * node)2291 rasqal_algebra_query_add_aggregation(rasqal_query* query,
2292                                      rasqal_algebra_aggregate* ae,
2293                                      rasqal_algebra_node* node)
2294 {
2295   raptor_sequence* exprs_seq;
2296   raptor_sequence* vars_seq;
2297 
2298   if(!query || !ae || !node)
2299     goto tidy;
2300 
2301   if(!ae->counter) {
2302     rasqal_free_algebra_aggregate(ae);
2303     return node;
2304   }
2305 
2306   /* Move ownership of sequences inside ae to here */
2307   exprs_seq = ae->agg_exprs; ae->agg_exprs = NULL;
2308   vars_seq = ae->agg_vars_seq; ae->agg_vars_seq = NULL;
2309 
2310   rasqal_free_algebra_aggregate(ae); ae = NULL;
2311 
2312   node = rasqal_new_aggregation_algebra_node(query, node, exprs_seq, vars_seq);
2313   exprs_seq = NULL; vars_seq = NULL;
2314   if(!node) {
2315     RASQAL_DEBUG1("rasqal_new_aggregation_algebra_node() failed\n");
2316     goto tidy;
2317   }
2318 
2319 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2320   RASQAL_DEBUG1("modified after adding aggregation node, algebra node now:\n  ");
2321   rasqal_algebra_node_print(node, stderr);
2322   fputs("\n", stderr);
2323 #endif
2324 
2325   return node;
2326 
2327 
2328   tidy:
2329   if(ae)
2330     rasqal_free_algebra_aggregate(ae);
2331   if(node)
2332     rasqal_free_algebra_node(node);
2333 
2334   return NULL;
2335 }
2336 
2337 
2338 /**
2339  * rasqal_algebra_query_add_projection:
2340  * @query: #rasqal_query to read from
2341  * @node: node to apply projection to
2342  * @projection: variable projection to use
2343  *
2344  * Add a projection to the query algebra structure
2345  *
2346  * Return value: non-0 on failure
2347  */
2348 rasqal_algebra_node*
rasqal_algebra_query_add_projection(rasqal_query * query,rasqal_algebra_node * node,rasqal_projection * projection)2349 rasqal_algebra_query_add_projection(rasqal_query* query,
2350                                     rasqal_algebra_node* node,
2351                                     rasqal_projection* projection)
2352 {
2353   int vars_size = 0;
2354   raptor_sequence* seq = NULL;  /* sequence of rasqal_variable* */
2355   raptor_sequence* vars_seq;
2356   int i;
2357 
2358   if(!projection)
2359     return NULL;
2360 
2361   /* FIXME Optimization: do not always need a PROJECT node when the
2362    * variables at the top level node are the same as the projection
2363    * list.
2364    */
2365 
2366   /* project all projection variables (may be an empty sequence) */
2367   seq = projection->variables;
2368   if(seq)
2369     vars_size = raptor_sequence_size(seq);
2370 
2371   vars_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
2372                                  (raptor_data_print_handler)rasqal_variable_print);
2373   if(!vars_seq) {
2374     rasqal_free_algebra_node(node);
2375     return NULL;
2376   }
2377 
2378   for(i = 0; i < vars_size; i++) {
2379     rasqal_variable* v;
2380 
2381     v = (rasqal_variable*)raptor_sequence_get_at(seq, i);
2382     v = rasqal_new_variable_from_variable(v);
2383     raptor_sequence_push(vars_seq, v);
2384   }
2385 
2386   node = rasqal_new_project_algebra_node(query, node, vars_seq);
2387 
2388 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2389   RASQAL_DEBUG1("modified after adding project node, algebra node now:\n  ");
2390   rasqal_algebra_node_print(node, stderr);
2391   fputs("\n", stderr);
2392 #endif
2393 
2394   return node;
2395 }
2396 
2397 
2398 /**
2399  * rasqal_algebra_query_add_construct_projection:
2400  * @query: #rasqal_query to read from
2401  * @node: node to apply projection to
2402  *
2403  * Add a query projection for a CONSTRUCT to the query algebra structure
2404  *
2405  * Return value: non-0 on failure
2406  */
2407 rasqal_algebra_node*
rasqal_algebra_query_add_construct_projection(rasqal_query * query,rasqal_algebra_node * node)2408 rasqal_algebra_query_add_construct_projection(rasqal_query* query,
2409                                               rasqal_algebra_node* node)
2410 {
2411   int vars_size = 0;
2412   raptor_sequence* seq = NULL;  /* sequence of rasqal_variable* */
2413   raptor_sequence* vars_seq;
2414   int i;
2415 
2416   /* project all variables mentioned in CONSTRUCT */
2417   seq = rasqal_algebra_get_variables_mentioned_in(query,
2418                                                   RASQAL_VAR_USE_MAP_OFFSET_VERBS);
2419   if(!seq) {
2420     rasqal_free_algebra_node(node);
2421     return NULL;
2422   }
2423 
2424   vars_size = raptor_sequence_size(seq);
2425 
2426   vars_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
2427                                  (raptor_data_print_handler)rasqal_variable_print);
2428   if(!vars_seq) {
2429     rasqal_free_algebra_node(node);
2430     return NULL;
2431   }
2432 
2433   for(i = 0; i < vars_size; i++) {
2434     rasqal_variable* v;
2435 
2436     v = (rasqal_variable*)raptor_sequence_get_at(seq, i);
2437     v = rasqal_new_variable_from_variable(v);
2438     raptor_sequence_push(vars_seq, v);
2439   }
2440 
2441   node = rasqal_new_project_algebra_node(query, node, vars_seq);
2442 
2443 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2444   RASQAL_DEBUG1("modified after adding construct project node, algebra node now:\n  ");
2445   rasqal_algebra_node_print(node, stderr);
2446   fputs("\n", stderr);
2447 #endif
2448 
2449   raptor_free_sequence(seq);
2450 
2451   return node;
2452 }
2453 
2454 
2455 /**
2456  * rasqal_algebra_query_add_distinct:
2457  * @query: #rasqal_query to read from
2458  * @node: node to apply distinct to
2459  * @projection: variable projection to use
2460  *
2461  * Apply distinctness to query algebra structure
2462  *
2463  * Return value: non-0 on failure
2464  */
2465 rasqal_algebra_node*
rasqal_algebra_query_add_distinct(rasqal_query * query,rasqal_algebra_node * node,rasqal_projection * projection)2466 rasqal_algebra_query_add_distinct(rasqal_query* query,
2467                                   rasqal_algebra_node* node,
2468                                   rasqal_projection* projection)
2469 {
2470   if(!projection)
2471     return node;
2472 
2473   if(projection->distinct) {
2474     node = rasqal_new_distinct_algebra_node(query, node);
2475 
2476 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2477     RASQAL_DEBUG1("modified after adding distinct node, algebra node now:\n  ");
2478     rasqal_algebra_node_print(node, stderr);
2479     fputs("\n", stderr);
2480 #endif
2481   }
2482 
2483   return node;
2484 }
2485 
2486 
2487 /**
2488  * rasqal_algebra_query_add_having:
2489  * @query: #rasqal_query to read from
2490  * @node: node to apply having to
2491  * @modifier: solution modifier to use
2492  *
2493  * Apply any needed HAVING expressions to query algebra structure
2494  *
2495  * Return value: non-0 on failure
2496  */
2497 rasqal_algebra_node*
rasqal_algebra_query_add_having(rasqal_query * query,rasqal_algebra_node * node,rasqal_solution_modifier * modifier)2498 rasqal_algebra_query_add_having(rasqal_query* query,
2499                                 rasqal_algebra_node* node,
2500                                 rasqal_solution_modifier* modifier)
2501 {
2502   raptor_sequence* modifier_seq;
2503 
2504   if(!modifier)
2505     return node;
2506 
2507   /* HAVING */
2508   modifier_seq = modifier->having_conditions;
2509   if(modifier_seq) {
2510     raptor_sequence* exprs_seq;
2511 
2512     /* Make a deep copy of the query order conditions sequence for
2513      * the ORDERBY algebra node
2514      */
2515     exprs_seq = rasqal_expression_copy_expression_sequence(modifier_seq);
2516     if(!exprs_seq) {
2517       rasqal_free_algebra_node(node);
2518       return NULL;
2519     }
2520 
2521     node = rasqal_new_having_algebra_node(query, node, exprs_seq);
2522 
2523 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2524     RASQAL_DEBUG1("modified after adding having node, algebra node now:\n  ");
2525     rasqal_algebra_node_print(node, stderr);
2526     fputs("\n", stderr);
2527 #endif
2528   }
2529 
2530   return node;
2531 }
2532 
2533 
2534 #endif
2535 
2536 #ifdef STANDALONE
2537 #include <stdio.h>
2538 
2539 #define QUERY_LANGUAGE "sparql"
2540 #define QUERY_FORMAT "\
2541          PREFIX ex: <http://example.org/ns#/> \
2542          SELECT $subject \
2543          FROM <http://librdf.org/rasqal/rasqal.rdf> \
2544          WHERE \
2545          { $subject ex:predicate $value . \
2546            FILTER (($value + 1) < 10) \
2547          }"
2548 
2549 
2550 int main(int argc, char *argv[]);
2551 
2552 int
main(int argc,char * argv[])2553 main(int argc, char *argv[]) {
2554   char const *program = rasqal_basename(*argv);
2555   const char *query_language_name = QUERY_LANGUAGE;
2556   const unsigned char *query_format = (const unsigned char *)QUERY_FORMAT;
2557   int failures = 0;
2558 #define FAIL do { failures++; goto tidy; } while(0)
2559   rasqal_world *world;
2560   rasqal_query* query = NULL;
2561   rasqal_literal *lit1 = NULL, *lit2 = NULL;
2562   rasqal_expression *expr1 = NULL, *expr2 = NULL;
2563   rasqal_expression* expr = NULL;
2564   rasqal_expression* expr3 = NULL;
2565   rasqal_expression* expr4 = NULL;
2566   rasqal_algebra_node* node0 = NULL;
2567   rasqal_algebra_node* node1 = NULL;
2568   rasqal_algebra_node* node2 = NULL;
2569   rasqal_algebra_node* node3 = NULL;
2570   rasqal_algebra_node* node4 = NULL;
2571   rasqal_algebra_node* node5 = NULL;
2572   rasqal_algebra_node* node6 = NULL;
2573   rasqal_algebra_node* node7 = NULL;
2574   rasqal_algebra_node* node8 = NULL;
2575   rasqal_algebra_node* node9 = NULL;
2576   raptor_uri *base_uri = NULL;
2577   unsigned char *uri_string;
2578   rasqal_graph_pattern* query_gp;
2579   rasqal_graph_pattern* sgp;
2580   raptor_sequence* triples;
2581   raptor_sequence* conditions = NULL;
2582   rasqal_literal* lit3 = NULL;
2583   rasqal_literal* lit4 = NULL;
2584 
2585   world = rasqal_new_world();
2586   if(!world || rasqal_world_open(world))
2587     FAIL;
2588 
2589   uri_string = raptor_uri_filename_to_uri_string("");
2590   if(!uri_string)
2591     FAIL;
2592   base_uri = raptor_new_uri(world->raptor_world_ptr, uri_string);
2593   if(!base_uri)
2594     FAIL;
2595   raptor_free_memory(uri_string);
2596 
2597   query = rasqal_new_query(world, query_language_name, NULL);
2598   if(!query) {
2599     fprintf(stderr, "%s: creating query in language %s FAILED\n", program,
2600             query_language_name);
2601     FAIL;
2602   }
2603 
2604   if(rasqal_query_prepare(query, query_format, base_uri)) {
2605     fprintf(stderr, "%s: %s query prepare FAILED\n", program,
2606             query_language_name);
2607     FAIL;
2608   }
2609 
2610   lit1 = rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 1);
2611   if(!lit1)
2612     FAIL;
2613   expr1 = rasqal_new_literal_expression(world, lit1);
2614   if(!expr1)
2615     FAIL;
2616   lit1 = NULL; /* now owned by expr1 */
2617 
2618   lit2 = rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 1);
2619   if(!lit2)
2620     FAIL;
2621   expr2 = rasqal_new_literal_expression(world, lit2);
2622   if(!expr2)
2623     FAIL;
2624   lit2 = NULL; /* now owned by expr2 */
2625 
2626   expr = rasqal_new_2op_expression(world, RASQAL_EXPR_PLUS, expr1, expr2);
2627   if(!expr)
2628     FAIL;
2629   expr1 = NULL; expr2 = NULL; /* now owned by expr */
2630 
2631   node0 = rasqal_new_empty_algebra_node(query);
2632   if(!node0)
2633     FAIL;
2634 
2635   node1 = rasqal_new_filter_algebra_node(query, expr, node0);
2636   if(!node1) {
2637     fprintf(stderr, "%s: rasqal_new_filter_algebra_node() failed\n", program);
2638     FAIL;
2639   }
2640   node0 = NULL; expr = NULL; /* now owned by node1 */
2641 
2642   fprintf(stderr, "%s: node result: \n", program);
2643   rasqal_algebra_node_print(node1, stderr);
2644   fputc('\n', stderr);
2645 
2646   rasqal_free_algebra_node(node1);
2647 
2648 
2649   /* construct abstract nodes from query structures */
2650   query_gp = rasqal_query_get_query_graph_pattern(query);
2651 
2652 #ifdef RASQAL_DEBUG
2653   fprintf(stderr, "%s: query graph pattern: \n", program);
2654   rasqal_graph_pattern_print(query_gp, stderr);
2655   fputc('\n', stderr);
2656 #endif
2657 
2658   /* make a filter node around 2nd GP - a FILTER gp */
2659   sgp = rasqal_graph_pattern_get_sub_graph_pattern(query_gp, 1);
2660   expr = rasqal_graph_pattern_get_filter_expression(sgp);
2661   if(!expr) {
2662     fprintf(stderr, "%s: rasqal_graph_pattern_get_filter_expression() failed\n", program);
2663     FAIL;
2664   }
2665   expr = rasqal_new_expression_from_expression(expr);
2666   if(!expr) {
2667     fprintf(stderr, "%s: rasqal_new_expression_from_expression() failed\n", program);
2668     FAIL;
2669   }
2670 
2671   node8 = rasqal_new_empty_algebra_node(query);
2672   if(!node8)
2673     FAIL;
2674   node1 = rasqal_new_filter_algebra_node(query, expr, node8);
2675   if(!node1) {
2676     fprintf(stderr, "%s: rasqal_new_filter_algebra_node() failed\n", program);
2677     FAIL;
2678   }
2679   /* these are now owned by node1 */
2680   node8 = NULL;
2681   expr = NULL;
2682 
2683   fprintf(stderr, "%s: node1 result: \n", program);
2684   rasqal_algebra_node_print(node1, stderr);
2685   fputc('\n', stderr);
2686 
2687 
2688   /* make an triples node around first (and only) triple pattern */
2689   triples = rasqal_query_get_triple_sequence(query);
2690   node2 = rasqal_new_triples_algebra_node(query, triples, 0, 0);
2691   if(!node2)
2692     FAIL;
2693 
2694   fprintf(stderr, "%s: node2 result: \n", program);
2695   rasqal_algebra_node_print(node2, stderr);
2696   fputc('\n', stderr);
2697 
2698 
2699   node3 = rasqal_new_2op_algebra_node(query,
2700                                       RASQAL_ALGEBRA_OPERATOR_JOIN,
2701                                       node1, node2);
2702 
2703   if(!node3)
2704     FAIL;
2705 
2706   /* these become owned by node3 */
2707   node1 = node2 = NULL;
2708 
2709   fprintf(stderr, "%s: node3 result: \n", program);
2710   rasqal_algebra_node_print(node3, stderr);
2711   fputc('\n', stderr);
2712 
2713   node4 = rasqal_new_empty_algebra_node(query);
2714   if(!node4)
2715     FAIL;
2716 
2717   fprintf(stderr, "%s: node4 result: \n", program);
2718   rasqal_algebra_node_print(node4, stderr);
2719   fputc('\n', stderr);
2720 
2721   node5 = rasqal_new_2op_algebra_node(query,
2722                                       RASQAL_ALGEBRA_OPERATOR_UNION,
2723                                       node3, node4);
2724 
2725   if(!node5)
2726     FAIL;
2727 
2728   /* these become owned by node5 */
2729   node3 = node4 = NULL;
2730 
2731   fprintf(stderr, "%s: node5 result: \n", program);
2732   rasqal_algebra_node_print(node5, stderr);
2733   fputc('\n', stderr);
2734 
2735 
2736 
2737   lit1 = rasqal_new_boolean_literal(world, 1);
2738   if(!lit1)
2739     FAIL;
2740   expr1 = rasqal_new_literal_expression(world, lit1);
2741   if(!expr1)
2742     FAIL;
2743   lit1 = NULL; /* now owned by expr1 */
2744 
2745   node6 = rasqal_new_empty_algebra_node(query);
2746   if(!node6)
2747     FAIL;
2748 
2749   node7 = rasqal_new_leftjoin_algebra_node(query, node5, node6, expr1);
2750   if(!node7)
2751     FAIL;
2752   /* these become owned by node7 */
2753   node5 = node6 = NULL;
2754   expr1 = NULL;
2755 
2756   fprintf(stderr, "%s: node7 result: \n", program);
2757   rasqal_algebra_node_print(node7, stderr);
2758   fputc('\n', stderr);
2759 
2760   /* This is an artificial order conditions sequence equivalent to
2761    * ORDER BY 1, 2 which would probably never appear in a query.
2762    */
2763   conditions = raptor_new_sequence((raptor_data_free_handler)rasqal_free_expression,
2764                                    (raptor_data_print_handler)rasqal_expression_print);
2765   if(!conditions)
2766     FAIL;
2767   lit3 = rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 1);
2768   if(!lit3)
2769     FAIL;
2770   expr3 = rasqal_new_literal_expression(world, lit3);
2771   if(!expr3)
2772     FAIL;
2773   lit3 = NULL; /* now owned by expr3 */
2774 
2775   raptor_sequence_push(conditions, expr3);
2776   expr3 = NULL; /* now owned by conditions */
2777 
2778   lit4 = rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 2);
2779   if(!lit4)
2780     FAIL;
2781   expr4 = rasqal_new_literal_expression(world, lit4);
2782   if(!expr4)
2783     FAIL;
2784   lit4 = NULL; /* now owned by expr4 */
2785 
2786   raptor_sequence_push(conditions, expr4);
2787   expr4 = NULL; /* now owned by conditions */
2788 
2789   node9 = rasqal_new_orderby_algebra_node(query, node7, conditions, 0);
2790   if(!node9)
2791     FAIL;
2792   /* these become owned by node9 */
2793   node7 = NULL;
2794   conditions = NULL;
2795 
2796   fprintf(stderr, "%s: node9 result: \n", program);
2797   rasqal_algebra_node_print(node9, stderr);
2798   fputc('\n', stderr);
2799 
2800 
2801   tidy:
2802   if(lit1)
2803     rasqal_free_literal(lit1);
2804   if(lit2)
2805     rasqal_free_literal(lit2);
2806   if(lit3)
2807     rasqal_free_literal(lit3);
2808   if(expr1)
2809     rasqal_free_expression(expr1);
2810   if(expr2)
2811     rasqal_free_expression(expr2);
2812   if(expr3)
2813     rasqal_free_expression(expr3);
2814 
2815   if(node9)
2816     rasqal_free_algebra_node(node9);
2817   if(node8)
2818     rasqal_free_algebra_node(node8);
2819   if(node7)
2820     rasqal_free_algebra_node(node7);
2821   if(node6)
2822     rasqal_free_algebra_node(node6);
2823   if(node5)
2824     rasqal_free_algebra_node(node5);
2825   if(node4)
2826     rasqal_free_algebra_node(node4);
2827   if(node3)
2828     rasqal_free_algebra_node(node3);
2829   if(node2)
2830     rasqal_free_algebra_node(node2);
2831   if(node1)
2832     rasqal_free_algebra_node(node1);
2833   if(node0)
2834     rasqal_free_algebra_node(node0);
2835 
2836   if(query)
2837     rasqal_free_query(query);
2838   if(base_uri)
2839     raptor_free_uri(base_uri);
2840   if(world)
2841     rasqal_free_world(world);
2842 
2843   return failures;
2844 }
2845 #endif /* STANDALONE */
2846 
2847