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