1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rasqal_query_results.c - Rasqal RDF Query Results
4 *
5 * Copyright (C) 2003-2009, David Beckett http://www.dajobe.org/
6 * Copyright (C) 2003-2005, University of Bristol, UK http://www.bristol.ac.uk/
7 *
8 * This package is Free Software and part of Redland http://librdf.org/
9 *
10 * It is licensed under the following three licenses as alternatives:
11 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
12 * 2. GNU General Public License (GPL) V2 or any newer version
13 * 3. Apache License, V2.0 or any newer version
14 *
15 * You may not use this file except in compliance with at least one of
16 * the above three licenses.
17 *
18 * See LICENSE.html or LICENSE.txt at the top of this package for the
19 * complete terms and further detail along with the license texts for
20 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
21 *
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <rasqal_config.h>
27 #endif
28
29 #ifdef WIN32
30 #include <win32_rasqal_config.h>
31 #endif
32
33 #include <stdio.h>
34 #include <string.h>
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 #include <stdarg.h>
39
40 #include "rasqal.h"
41 #include "rasqal_internal.h"
42
43 #ifndef STANDALONE
44
45 /*
46 *
47 * Query Results Class Internals
48 *
49 * This class provides the abstraction for query results in different
50 * forms. The forms can be either a sequence of variable bindings,
51 * set of RDF triples, boolean value or a syntax.
52 *
53 * Query results can be created as a result of a #rasqal_query
54 * execution using rasqal_query_execute() or as an independent result
55 * set constructed from a query results syntax such as the SPARQL XML
56 * results format via the #rasqal_query_results_formatter class.
57 *
58 * The query results constructor rasqal_new_query_results() takes
59 * a world to use, an optional query, the type of result as well
60 * as a variable table to operate on. If the query is given, then
61 * that is used to handle limit, offset and triple construction,
62 * otherwise the result set is standalone and not associated with
63 * a query.
64 *
65 * The variables table is used for the variables that will appear in
66 * the result rows in the result set. The query results module does
67 * not own any variable information, all API calls are delegated to
68 * the variables table.
69 *
70 * If the rasqal_new_query_results_from_query_execution() is used to
71 * make a query results from a query structure via executing the
72 * query, it initialises a execution engine via the
73 * #rasqal_query_execution_factory 'execute_init' factory method.
74 * This method also determines whether the entire results need to be
75 * (or a requested to be) obtained in one go, and if so, they are
76 * done during construction.
77 *
78 * The user API to getting query results is primarily to get variable
79 * bindings - a sequence of variable:value (also called #rasqal_row
80 * internally), RDF triples, a boolean value or a syntax.
81 *
82 * The variable bindings are generated from the execution engine by
83 * retrieving #rasqal_row either one-by-one using the get_row method
84 * or getting the entire result at once with the get_all_rows method.
85 *
86 * In the case of getting the entire result the rows are stored as a
87 * sqeuence inside the #rasqal_query_results and returned one-by-one
88 * from there, respecting any limit and offset.
89 *
90 * The RDF triples and boolean value results are generated from the
91 * variable bindings (#rasqal_row) inside this class. The underlying
92 * execution engine only knows about rows.
93 *
94 * The class also handles several other results-specific methods such
95 * as getting variable binding names, values by name, counts of
96 * number of results, writing a query results as a syntax (in a
97 * simple fashion), read a query results from a syntax.
98 */
99
100 static int rasqal_query_results_execute_and_store_results(rasqal_query_results* query_results);
101 static void rasqal_query_results_update_query_bindings(rasqal_query_results* query_results, rasqal_query *query);
102
103
104 /*
105 * A query result for some query
106 */
107 struct rasqal_query_results_s {
108 rasqal_world* world;
109
110 /* type of query result (bindings, boolean, graph or syntax) */
111 rasqal_query_results_type type;
112
113 /* non-0 if have read all (variable binding) results */
114 int finished;
115
116 /* non-0 if query has been executed */
117 int executed;
118
119 /* non 0 if query had fatal error and cannot return results */
120 int failed;
121
122 /* query that this was executed over */
123 rasqal_query* query;
124
125 /* how many (variable bindings) results found so far */
126 int result_count;
127
128 /* execution data for execution engine. owned by this object */
129 void* execution_data;
130
131 /* current row of results */
132 rasqal_row* row;
133
134 /* boolean ASK result >0 true, 0 false or -1 uninitialised */
135 int ask_result;
136
137 /* boolean: non-0 to store query results rather than lazy eval */
138 int store_results;
139
140 /* current triple in the sequence of triples 'constructs' or -1 */
141 int current_triple_result;
142
143 /* constructed triple result - shared and updated for each triple */
144 raptor_statement result_triple;
145
146 /* sequence of stored results */
147 raptor_sequence* results_sequence;
148
149 /* size of result row fields:
150 * row->results, row->values
151 */
152 int size;
153
154 /* Execution engine used here */
155 const rasqal_query_execution_factory* execution_factory;
156
157 /* Variables table for variables in result rows */
158 rasqal_variables_table* vars_table;
159
160 /* non-0 if @vars_table has been initialized from first row */
161 int vars_table_init;
162 };
163
164
165 int
rasqal_init_query_results(void)166 rasqal_init_query_results(void)
167 {
168 return 0;
169 }
170
171
172 void
rasqal_finish_query_results(void)173 rasqal_finish_query_results(void)
174 {
175 }
176
177
178 /**
179 * rasqal_new_query_results2:
180 * @world: rasqal world object
181 * @query: query object (or NULL)
182 * @type: query results (expected) type
183 *
184 * Constructor - create a new query results set
185 *
186 * The @query may be NULL for result set objects that are standalone
187 * and not attached to any particular query
188 *
189 * Return value: a new query result object or NULL on failure
190 **/
191 rasqal_query_results*
rasqal_new_query_results2(rasqal_world * world,rasqal_query * query,rasqal_query_results_type type)192 rasqal_new_query_results2(rasqal_world* world,
193 rasqal_query* query,
194 rasqal_query_results_type type)
195 {
196 rasqal_query_results* query_results;
197
198 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(world, rasqal_world, NULL);
199
200 query_results = RASQAL_CALLOC(rasqal_query_results*, 1, sizeof(*query_results));
201 if(!query_results)
202 return NULL;
203
204 query_results->vars_table = rasqal_new_variables_table(world);
205 if(!query_results->vars_table) {
206 RASQAL_FREE(rasqal_query_results, query_results);
207 return NULL;
208 }
209
210 query_results->world = world;
211 query_results->type = type;
212 query_results->finished = 0;
213 query_results->executed = 0;
214 query_results->failed = 0;
215 query_results->query = query;
216 query_results->result_count = 0;
217 query_results->execution_data = NULL;
218 query_results->row = NULL;
219 query_results->ask_result = -1;
220 query_results->store_results = 0;
221 query_results->current_triple_result = -1;
222
223 /* initialize static query_results->result_triple */
224 raptor_statement_init(&query_results->result_triple, world->raptor_world_ptr);
225
226 query_results->results_sequence = NULL;
227 query_results->size = 0;
228
229 return query_results;
230 }
231
232
233 /**
234 * rasqal_new_query_results:
235 * @world: rasqal world object
236 * @query: query object (or NULL)
237 * @type: query results (expected) type
238 * @vars_table: This parameter is *IGNORED*
239 *
240 * Constructor - create a new query results set
241 *
242 * @Deprecated for rasqal_new_query_results2() that loses the unused argument.
243 *
244 * The @query may be NULL for result set objects that are standalone
245 * and not attached to any particular query
246 *
247 * Return value: a new query result object or NULL on failure
248 **/
249 rasqal_query_results*
rasqal_new_query_results(rasqal_world * world,rasqal_query * query,rasqal_query_results_type type,rasqal_variables_table * vars_table)250 rasqal_new_query_results(rasqal_world* world,
251 rasqal_query* query,
252 rasqal_query_results_type type,
253 rasqal_variables_table* vars_table)
254 {
255 return rasqal_new_query_results2(world, query, type);
256 }
257
258
259 /**
260 * rasqal_new_query_results_from_string:
261 * @world: rasqal world object
262 * @type: query results (expected) type; typically #RASQAL_QUERY_RESULTS_BINDINGS
263 * @base_uri: base URI of query results format (or NULL)
264 * @string: query results string
265 * @string_len: length of @string (or 0 to calculate it here)
266 *
267 * Constructor - create a new query results set from a results format string
268 *
269 * Return value: a new query result object or NULL on failure
270 **/
271 rasqal_query_results*
rasqal_new_query_results_from_string(rasqal_world * world,rasqal_query_results_type type,raptor_uri * base_uri,const char * string,size_t string_len)272 rasqal_new_query_results_from_string(rasqal_world* world,
273 rasqal_query_results_type type,
274 raptor_uri* base_uri,
275 const char* string,
276 size_t string_len)
277 {
278 int rc;
279 raptor_iostream* iostr = NULL;
280 rasqal_query_results_formatter* formatter = NULL;
281 rasqal_query_results* results = NULL;
282 raptor_world *raptor_world_ptr;
283 const char* formatter_name;
284 const unsigned char* id = NULL;
285
286 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(world, rasqal_world, NULL);
287 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(string, const char*, NULL);
288
289 if(!string_len)
290 string_len = strlen(string);
291
292 raptor_world_ptr = rasqal_world_get_raptor(world);
293
294 results = rasqal_new_query_results2(world, NULL, type);
295 if(!results)
296 goto failed;
297
298 iostr = raptor_new_iostream_from_string(raptor_world_ptr,
299 RASQAL_GOOD_CAST(void*, string),
300 string_len);
301 if(!iostr)
302 goto failed;
303
304 if(base_uri)
305 id = raptor_uri_as_string(base_uri);
306
307 formatter_name =
308 rasqal_world_guess_query_results_format_name(world,
309 base_uri,
310 NULL /* mime_type */,
311 RASQAL_GOOD_CAST(const unsigned char*, string),
312 string_len,
313 id);
314
315 formatter = rasqal_new_query_results_formatter(world,
316 formatter_name,
317 NULL /* mime type */,
318 NULL /* uri */);
319 if(!formatter)
320 goto failed;
321
322 rc = rasqal_query_results_formatter_read(world, iostr, formatter,
323 results, base_uri);
324 if(rc)
325 goto failed;
326
327 /* success */
328 goto tidy;
329
330 failed:
331 if(results) {
332 rasqal_free_query_results(results);
333 results = NULL;
334 }
335
336 tidy:
337 if(formatter)
338 rasqal_free_query_results_formatter(formatter);
339
340 if(iostr)
341 raptor_free_iostream(iostr);
342
343 return results;
344 }
345
346
347 /**
348 * rasqal_query_results_execute_with_engine:
349 * @query_results: the #rasqal_query_results object
350 * @engine: execution factory
351 * @store_results: non-0 to store query results
352 *
353 * INTERNAL - Create a new query results set executing a prepared query with the given execution engine
354 *
355 * return value: non-0 on failure
356 **/
357 int
rasqal_query_results_execute_with_engine(rasqal_query_results * query_results,const rasqal_query_execution_factory * engine,int store_results)358 rasqal_query_results_execute_with_engine(rasqal_query_results* query_results,
359 const rasqal_query_execution_factory* engine,
360 int store_results)
361 {
362 int rc = 0;
363 size_t ex_data_size;
364 rasqal_query* query;
365
366
367 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 1);
368
369 query = query_results->query;
370
371 if(query->failed)
372 return 1;
373
374 query_results->execution_factory = engine;
375
376 /* set executed flag early to enable cleanup on error */
377 query_results->executed = 1;
378
379 /* ensure stored results are present if ordering or distincting are being done */
380 query_results->store_results = (store_results ||
381 rasqal_query_get_order_conditions_sequence(query) ||
382 rasqal_query_get_distinct(query));
383
384 ex_data_size = query_results->execution_factory->execution_data_size;
385 if(ex_data_size > 0) {
386 query_results->execution_data = RASQAL_CALLOC(void*, 1, ex_data_size);
387
388 if(!query_results->execution_data)
389 return 1;
390 } else
391 query_results->execution_data = NULL;
392
393 /* Update the current datetime once per query execution */
394 rasqal_world_reset_now(query->world);
395
396 if(query_results->execution_factory->execute_init) {
397 rasqal_engine_error execution_error = RASQAL_ENGINE_OK;
398 int execution_flags = 0;
399
400 if(query_results->store_results)
401 execution_flags |= 1;
402
403 rc = query_results->execution_factory->execute_init(query_results->execution_data, query, query_results, execution_flags, &execution_error);
404
405 if(rc || execution_error != RASQAL_ENGINE_OK) {
406 query_results->failed = 1;
407 return 1;
408 }
409 }
410
411 #ifdef RASQAL_DEBUG
412 RASQAL_DEBUG1("After execute_init, query is now:\n");
413 rasqal_query_print(query, stderr);
414 #endif
415
416 /* Choose either to execute all now and store OR do it on demand (lazy) */
417 if(query_results->store_results)
418 rc = rasqal_query_results_execute_and_store_results(query_results);
419
420 return rc;
421 }
422
423
424 /**
425 * rasqal_free_query_results:
426 * @query_results: #rasqal_query_results object
427 *
428 * Destructor - destroy a rasqal_query_results.
429 *
430 **/
431 void
rasqal_free_query_results(rasqal_query_results * query_results)432 rasqal_free_query_results(rasqal_query_results* query_results)
433 {
434 rasqal_query* query;
435
436 if(!query_results)
437 return;
438
439 query = query_results->query;
440
441 if(query_results->executed) {
442 if(query_results->execution_factory->execute_finish) {
443 rasqal_engine_error execution_error = RASQAL_ENGINE_OK;
444
445 query_results->execution_factory->execute_finish(query_results->execution_data, &execution_error);
446 /* ignoring failure of execute_finish */
447 }
448 }
449
450 if(query_results->execution_data)
451 RASQAL_FREE(rasqal_engine_execution_data, query_results->execution_data);
452
453 if(query_results->row)
454 rasqal_free_row(query_results->row);
455
456 if(query_results->results_sequence)
457 raptor_free_sequence(query_results->results_sequence);
458
459 /* free terms owned by static query_results->result_triple */
460 raptor_free_statement(&query_results->result_triple);
461
462 if(query_results->vars_table)
463 rasqal_free_variables_table(query_results->vars_table);
464
465 if(query)
466 rasqal_query_remove_query_result(query, query_results);
467
468 RASQAL_FREE(rasqal_query_results, query_results);
469 }
470
471
472 /**
473 * rasqal_query_results_get_query:
474 * @query_results: #rasqal_query_results object
475 *
476 * Get thq query associated with this query result
477 *
478 * Return value: shared pointer to query object
479 **/
480 rasqal_query*
rasqal_query_results_get_query(rasqal_query_results * query_results)481 rasqal_query_results_get_query(rasqal_query_results* query_results)
482 {
483 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, NULL);
484
485 return query_results->query;
486 }
487
488
489 /**
490 * rasqal_query_results_get_type:
491 * @query_results: #rasqal_query_results object
492 *
493 * Get query results type
494 *
495 * Return value: non-0 if true
496 **/
497 rasqal_query_results_type
rasqal_query_results_get_type(rasqal_query_results * query_results)498 rasqal_query_results_get_type(rasqal_query_results* query_results)
499 {
500 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, (rasqal_query_results_type)0);
501
502 return query_results->type;
503 }
504
505
506 static const char* const rasqal_query_results_type_labels[RASQAL_QUERY_RESULTS_LAST + 1] = {
507 "Bindings",
508 "Boolean",
509 "Graph",
510 "Syntax",
511 "Unknown"
512 };
513
514
515
516 /**
517 * rasqal_query_results_type_label:
518 * @type: #rasqal_query_results_type type
519 *
520 * Get a label for a query results type
521 *
522 * Return value: label or NULL on failure (invalid type)
523 **/
524 const char*
rasqal_query_results_type_label(rasqal_query_results_type type)525 rasqal_query_results_type_label(rasqal_query_results_type type)
526 {
527 if(type > RASQAL_QUERY_RESULTS_LAST)
528 type = RASQAL_QUERY_RESULTS_UNKNOWN;
529
530 return rasqal_query_results_type_labels[RASQAL_GOOD_CAST(int, type)];
531 }
532
533
534 /**
535 * rasqal_query_results_is_bindings:
536 * @query_results: #rasqal_query_results object
537 *
538 * Test if rasqal_query_results is variable bindings format.
539 *
540 * Return value: non-0 if true
541 **/
542 int
rasqal_query_results_is_bindings(rasqal_query_results * query_results)543 rasqal_query_results_is_bindings(rasqal_query_results* query_results)
544 {
545 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 0);
546
547 return (query_results->type == RASQAL_QUERY_RESULTS_BINDINGS);
548 }
549
550
551 /**
552 * rasqal_query_results_is_boolean:
553 * @query_results: #rasqal_query_results object
554 *
555 * Test if rasqal_query_results is boolean format.
556 *
557 * Return value: non-0 if true
558 **/
559 int
rasqal_query_results_is_boolean(rasqal_query_results * query_results)560 rasqal_query_results_is_boolean(rasqal_query_results* query_results)
561 {
562 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 0);
563
564 return (query_results->type == RASQAL_QUERY_RESULTS_BOOLEAN);
565 }
566
567
568 /**
569 * rasqal_query_results_is_graph:
570 * @query_results: #rasqal_query_results object
571 *
572 * Test if rasqal_query_results is RDF graph format.
573 *
574 * Return value: non-0 if true
575 **/
576 int
rasqal_query_results_is_graph(rasqal_query_results * query_results)577 rasqal_query_results_is_graph(rasqal_query_results* query_results)
578 {
579 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 0);
580
581 return (query_results->type == RASQAL_QUERY_RESULTS_GRAPH);
582 }
583
584
585 /**
586 * rasqal_query_results_is_syntax:
587 * @query_results: #rasqal_query_results object
588 *
589 * Test if the rasqal_query_results is a syntax.
590 *
591 * Many of the query results may be formatted as a syntax using the
592 * #rasqal_query_formatter class however this function returns true
593 * if a syntax result was specifically requested.
594 *
595 * Return value: non-0 if true
596 **/
597 int
rasqal_query_results_is_syntax(rasqal_query_results * query_results)598 rasqal_query_results_is_syntax(rasqal_query_results* query_results)
599 {
600 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 0);
601
602 return (query_results->type == RASQAL_QUERY_RESULTS_SYNTAX);
603 }
604
605
606 /**
607 * rasqal_query_check_limit_offset_core:
608 * @result_offset: offset to check
609 * @limit: limit
610 * @offset: offset
611 *
612 * INTERNAL - Check the result_offset is in the limit and offset range if any.
613 *
614 * Return value: before range -1, in range 0, after range 1
615 */
616 int
rasqal_query_check_limit_offset_core(int result_offset,int limit,int offset)617 rasqal_query_check_limit_offset_core(int result_offset,
618 int limit,
619 int offset)
620 {
621 if(result_offset < 0)
622 return -1;
623
624 if(offset > 0) {
625 /* offset */
626 if(result_offset <= offset)
627 return -1;
628
629 if(limit >= 0) {
630 /* offset and limit */
631 if(result_offset > (offset + limit)) {
632 return 1;
633 }
634 }
635
636 } else if(limit >= 0) {
637 /* limit */
638 if(result_offset > limit) {
639 return 1;
640 }
641 }
642
643 return 0;
644 }
645
646
647 /**
648 * rasqal_query_check_limit_offset:
649 * @query_results: query results object
650 * @result_offset: offset to check
651 *
652 * INTERNAL - Check the query result count is in the limit and offset range if any.
653 *
654 * Return value: before range -1, in range 0, after range 1
655 */
656 int
rasqal_query_check_limit_offset(rasqal_query * query,int result_offset)657 rasqal_query_check_limit_offset(rasqal_query* query,
658 int result_offset)
659 {
660 int limit;
661 int offset;
662
663 if(!query)
664 return 0;
665
666 if(result_offset < 0)
667 return -1;
668
669 limit = rasqal_query_get_limit(query);
670
671 /* Ensure ASK queries never do more than one result */
672 if(query->verb == RASQAL_QUERY_VERB_ASK)
673 limit = 1;
674
675 offset = rasqal_query_get_offset(query);
676
677 return rasqal_query_check_limit_offset_core(result_offset, limit, offset);
678 }
679
680
681 /**
682 * rasqal_query_results_get_row_from_saved:
683 * @query_results: Query results to execute
684 *
685 * INTERNAL - Get next result row from a stored query result sequence
686 *
687 * Return value: result row or NULL if finished or failed
688 */
689 static rasqal_row*
rasqal_query_results_get_row_from_saved(rasqal_query_results * query_results)690 rasqal_query_results_get_row_from_saved(rasqal_query_results* query_results)
691 {
692 rasqal_query* query = query_results->query;
693 int size;
694 rasqal_row* row = NULL;
695
696 size = raptor_sequence_size(query_results->results_sequence);
697
698 while(1) {
699 int check;
700
701 if(query_results->result_count >= size) {
702 query_results->finished = 1;
703 break;
704 }
705
706 query_results->result_count++;
707
708 check = rasqal_query_check_limit_offset(query, query_results->result_count);
709
710 /* finished if beyond result range */
711 if(check > 0) {
712 query_results->finished = 1;
713 query_results->result_count--;
714 break;
715 }
716
717 /* continue if before start of result range */
718 if(check < 0)
719 continue;
720
721 /* else got result */
722 row = (rasqal_row*)raptor_sequence_get_at(query_results->results_sequence,
723 query_results->result_count - 1);
724
725 if(row) {
726 row = rasqal_new_row_from_row(row);
727
728 /* stored results may not be canonicalized yet - do it lazily */
729 rasqal_row_to_nodes(row);
730
731 query_results->row = row;
732
733 if(query && query->constructs)
734 rasqal_query_results_update_query_bindings(query_results, query);
735 }
736 break;
737 }
738
739 return row;
740 }
741
742
743 /**
744 * rasqal_query_results_ensure_have_row_internal:
745 * @query_results: #rasqal_query_results query_results
746 *
747 * INTERNAL - Ensure there is a row in the query results by getting it from the generator/stored list
748 *
749 * If one already is held, nothing is done. It is assumed
750 * that @query_results is not NULL and the query is neither finished
751 * nor failed.
752 *
753 * Return value: non-0 if failed or results exhausted
754 **/
755 static int
rasqal_query_results_ensure_have_row_internal(rasqal_query_results * query_results)756 rasqal_query_results_ensure_have_row_internal(rasqal_query_results* query_results)
757 {
758 /* already have row */
759 if(query_results->row)
760 return 0;
761
762 if(query_results->results_sequence) {
763 query_results->row = rasqal_query_results_get_row_from_saved(query_results);
764 } else if(query_results->execution_factory &&
765 query_results->execution_factory->get_row) {
766 rasqal_engine_error execution_error = RASQAL_ENGINE_OK;
767
768 /* handle limit/offset for incremental get_row() */
769 while(1) {
770 int check;
771
772 query_results->row = query_results->execution_factory->get_row(query_results->execution_data, &execution_error);
773 if(execution_error == RASQAL_ENGINE_FAILED) {
774 query_results->failed = 1;
775 break;
776 }
777
778 if(execution_error != RASQAL_ENGINE_OK)
779 break;
780
781 query_results->result_count++;
782
783 check = rasqal_query_check_limit_offset(query_results->query,
784 query_results->result_count);
785
786 /* finished if beyond result range */
787 if(check > 0) {
788 query_results->finished = 1;
789 query_results->result_count--;
790
791 /* empty row to trigger finished */
792 rasqal_free_row(query_results->row); query_results->row = NULL;
793 break;
794 }
795
796 /* continue if before start of result range */
797 if(check < 0) {
798 /* empty row because continuing */
799 rasqal_free_row(query_results->row); query_results->row = NULL;
800 continue;
801 }
802
803 /* got a row */
804 break;
805
806 } /* end while */
807
808 }
809
810 if(query_results->row) {
811 rasqal_row_to_nodes(query_results->row);
812 query_results->size = query_results->row->size;
813 } else
814 query_results->finished = 1;
815
816 if(query_results->row && !query_results->vars_table_init) {
817 /* build variables table once from first row seen */
818 int i;
819
820 query_results->vars_table_init = 1;
821
822 for(i = 0; 1; i++) {
823 rasqal_variable* v;
824
825 v = rasqal_row_get_variable_by_offset(query_results->row, i);
826 if(!v)
827 break;
828
829 v = rasqal_variables_table_add2(query_results->vars_table,
830 v->type,
831 v->name, /* name len */ 0,
832 /* value */ NULL);
833 rasqal_free_variable(v);
834 }
835 }
836
837 return (query_results->row == NULL);
838 }
839
840
841 /**
842 * rasqal_query_results_get_current_row:
843 * @query_results: query results object
844 *
845 * INTERNAL - Get the current query result as a row of values
846 *
847 * The returned row is shared and owned by query_results
848 *
849 * Return value: result row or NULL on failure
850 */
851 rasqal_row*
rasqal_query_results_get_current_row(rasqal_query_results * query_results)852 rasqal_query_results_get_current_row(rasqal_query_results* query_results)
853 {
854 if(!query_results || query_results->failed || query_results->finished)
855 return NULL;
856
857 if(!rasqal_query_results_is_bindings(query_results))
858 return NULL;
859
860 /* ensure we have a row */
861 rasqal_query_results_ensure_have_row_internal(query_results);
862
863 return query_results->row;
864 }
865
866
867 /**
868 * rasqal_query_results_get_count:
869 * @query_results: #rasqal_query_results query_results
870 *
871 * Get number of bindings so far.
872 *
873 * Return value: number of bindings found so far or < 0 on failure
874 **/
875 int
rasqal_query_results_get_count(rasqal_query_results * query_results)876 rasqal_query_results_get_count(rasqal_query_results* query_results)
877 {
878 rasqal_query* query;
879 int offset = -1;
880
881 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, -1);
882
883 if(query_results->failed)
884 return -1;
885
886 if(!rasqal_query_results_is_bindings(query_results))
887 return -1;
888
889 query = query_results->query;
890
891 if(query)
892 offset = rasqal_query_get_offset(query);
893
894 if(query && offset > 0)
895 return query_results->result_count - offset;
896 else
897 return query_results->result_count;
898 }
899
900
901 /*
902 * rasqal_query_results_next_internal:
903 * @query_results: #rasqal_query_results query_results
904 *
905 * INTERNAL - Move to the next result without query verb type checking
906 *
907 * Return value: non-0 if failed or results exhausted
908 **/
909 static int
rasqal_query_results_next_internal(rasqal_query_results * query_results)910 rasqal_query_results_next_internal(rasqal_query_results* query_results)
911 {
912 if(query_results->failed || query_results->finished)
913 return 1;
914
915 /* Remove any current row */
916 if(query_results->row) {
917 rasqal_free_row(query_results->row);
918 query_results->row = NULL;
919 }
920
921 /* Now try to get a new one */
922 return rasqal_query_results_ensure_have_row_internal(query_results);
923 }
924
925
926 /**
927 * rasqal_query_results_next:
928 * @query_results: #rasqal_query_results query_results
929 *
930 * Move to the next result.
931 *
932 * Return value: non-0 if failed or results exhausted
933 **/
934 int
rasqal_query_results_next(rasqal_query_results * query_results)935 rasqal_query_results_next(rasqal_query_results* query_results)
936 {
937 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 1);
938
939 if(!rasqal_query_results_is_bindings(query_results))
940 return 1;
941
942 return rasqal_query_results_next_internal(query_results);
943 }
944
945
946 /**
947 * rasqal_query_results_finished:
948 * @query_results: #rasqal_query_results query_results
949 *
950 * Find out if binding results are exhausted.
951 *
952 * Return value: non-0 if results are finished or query failed
953 **/
954 int
rasqal_query_results_finished(rasqal_query_results * query_results)955 rasqal_query_results_finished(rasqal_query_results* query_results)
956 {
957 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 1);
958
959 if(query_results->failed || query_results->finished)
960 return 1;
961
962 if(!rasqal_query_results_is_bindings(query_results))
963 return 1;
964
965 /* need to have at least tried to get a row once */
966 if(!query_results->failed && !query_results->finished)
967 rasqal_query_results_ensure_have_row_internal(query_results);
968
969 return (query_results->failed || query_results->finished);
970 }
971
972
973 /**
974 * rasqal_query_results_rewind:
975 * @query_results: #rasqal_query_results query_results
976 *
977 * Rewind stored query results to start
978 *
979 * This requires rasqal_query_set_store_results() to be called before
980 * query execution.
981 *
982 * Return value: non-0 if rewinding is not available when results are not stored
983 **/
984 int
rasqal_query_results_rewind(rasqal_query_results * query_results)985 rasqal_query_results_rewind(rasqal_query_results* query_results)
986 {
987 int size;
988 int limit = -1;
989 int offset = -1;
990 rasqal_query* query;
991
992 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 1);
993
994 if(!query_results->results_sequence)
995 return 1;
996
997 size = raptor_sequence_size(query_results->results_sequence);
998
999 /* This may be NULL for a static query result */
1000 query = query_results->query;
1001
1002 if(query) {
1003 /* If the query failed, it remains failed */
1004 if(query->failed)
1005 return 1;
1006
1007 limit = rasqal_query_get_limit(query);
1008 offset = rasqal_query_get_offset(query);
1009 }
1010
1011 /* reset to first result */
1012 query_results->finished = (size == 0);
1013
1014 if(query && !limit)
1015 query_results->finished = 1;
1016
1017 if(!query_results->finished) {
1018 /* Reset to first result, index-1 into sequence of results */
1019 query_results->result_count = 0;
1020
1021 /* skip past any OFFSET */
1022 if(query && offset > 0) {
1023 query_results->result_count += offset;
1024
1025 if(query_results->result_count >= size)
1026 query_results->finished = 1;
1027 }
1028
1029 }
1030
1031
1032 if(query_results->finished)
1033 query_results->result_count = 0;
1034 else {
1035 if(query && query->constructs)
1036 rasqal_query_results_update_query_bindings(query_results, query);
1037 }
1038
1039 return 0;
1040 }
1041
1042
1043 /**
1044 * rasqal_query_results_get_bindings:
1045 * @query_results: #rasqal_query_results query_results
1046 * @names: pointer to an array of binding names (or NULL)
1047 * @values: pointer to an array of binding value #rasqal_literal (or NULL)
1048 *
1049 * Get all binding names, values for current result.
1050 *
1051 * If names is not NULL, it is set to the address of a shared array
1052 * of names of the bindings (an output parameter). These names
1053 * are shared and must not be freed by the caller
1054 *
1055 * If values is not NULL, it is set to the address of a shared array
1056 * of #rasqal_literal* binding values. These values are shaerd
1057 * and must not be freed by the caller.
1058 *
1059 * Return value: non-0 if the assignment failed
1060 **/
1061 int
rasqal_query_results_get_bindings(rasqal_query_results * query_results,const unsigned char *** names,rasqal_literal *** values)1062 rasqal_query_results_get_bindings(rasqal_query_results* query_results,
1063 const unsigned char ***names,
1064 rasqal_literal ***values)
1065 {
1066 rasqal_row* row;
1067
1068 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 1);
1069
1070 if(!rasqal_query_results_is_bindings(query_results))
1071 return 1;
1072
1073 row = rasqal_query_results_get_current_row(query_results);
1074
1075 if(!row) {
1076 query_results->finished = 1;
1077 return 0;
1078 }
1079
1080 if(names)
1081 *names = rasqal_variables_table_get_names(query_results->vars_table);
1082
1083 if(values)
1084 *values = row->values;
1085
1086 return 0;
1087 }
1088
1089
1090 /**
1091 * rasqal_query_results_get_binding_value:
1092 * @query_results: #rasqal_query_results query_results
1093 * @offset: offset of binding name into array of known names
1094 *
1095 * Get one binding value for the current result.
1096 *
1097 * Return value: a pointer to a shared #rasqal_literal binding value or NULL on failure
1098 **/
1099 rasqal_literal*
rasqal_query_results_get_binding_value(rasqal_query_results * query_results,int offset)1100 rasqal_query_results_get_binding_value(rasqal_query_results* query_results,
1101 int offset)
1102 {
1103 rasqal_row* row;
1104
1105 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, NULL);
1106
1107 if(!rasqal_query_results_is_bindings(query_results))
1108 return NULL;
1109
1110 if(offset < 0 || offset > query_results->size-1)
1111 return NULL;
1112
1113 row = rasqal_query_results_get_current_row(query_results);
1114 if(row)
1115 return row->values[offset];
1116
1117 query_results->finished = 1;
1118 return NULL;
1119 }
1120
1121
1122 /**
1123 * rasqal_query_results_get_binding_name:
1124 * @query_results: #rasqal_query_results query_results
1125 * @offset: offset of binding name into array of known names
1126 *
1127 * Get binding name for the current result.
1128 *
1129 * Return value: a pointer to a shared copy of the binding name or NULL on failure
1130 **/
1131 const unsigned char*
rasqal_query_results_get_binding_name(rasqal_query_results * query_results,int offset)1132 rasqal_query_results_get_binding_name(rasqal_query_results* query_results,
1133 int offset)
1134 {
1135 rasqal_row* row;
1136 rasqal_variable* v;
1137
1138 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, NULL);
1139
1140 if(!rasqal_query_results_is_bindings(query_results))
1141 return NULL;
1142
1143 row = rasqal_query_results_get_current_row(query_results);
1144 if(!row)
1145 return NULL;
1146
1147 v = rasqal_variables_table_get(query_results->vars_table, offset);
1148 if(!v)
1149 return NULL;
1150
1151 return v->name;
1152 }
1153
1154
1155 /**
1156 * rasqal_query_results_get_binding_value_by_name:
1157 * @query_results: #rasqal_query_results query_results
1158 * @name: variable name
1159 *
1160 * Get one binding value for a given name in the current result.
1161 *
1162 * Return value: a pointer to a shared #rasqal_literal binding value or NULL on failure
1163 **/
1164 rasqal_literal*
rasqal_query_results_get_binding_value_by_name(rasqal_query_results * query_results,const unsigned char * name)1165 rasqal_query_results_get_binding_value_by_name(rasqal_query_results* query_results,
1166 const unsigned char *name)
1167 {
1168 rasqal_row* row;
1169 rasqal_variable* v;
1170
1171 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, NULL);
1172 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(name, char*, NULL);
1173
1174 if(!rasqal_query_results_is_bindings(query_results))
1175 return NULL;
1176
1177 row = rasqal_query_results_get_current_row(query_results);
1178 if(!row)
1179 return NULL;
1180
1181 v = rasqal_variables_table_get_by_name(query_results->vars_table,
1182 RASQAL_VARIABLE_TYPE_NORMAL, name);
1183 if(!v)
1184 return NULL;
1185
1186 return row->values[v->offset];
1187 }
1188
1189
1190 /**
1191 * rasqal_query_results_get_bindings_count:
1192 * @query_results: #rasqal_query_results query_results
1193 *
1194 * Get the number of bound variables in the result.
1195 *
1196 * Return value: <0 if failed or results exhausted
1197 **/
1198 int
rasqal_query_results_get_bindings_count(rasqal_query_results * query_results)1199 rasqal_query_results_get_bindings_count(rasqal_query_results* query_results)
1200 {
1201 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, -1);
1202
1203 if(query_results->failed)
1204 return -1;
1205
1206 if(!rasqal_query_results_is_bindings(query_results))
1207 return -1;
1208
1209 /* ensures an attempt is made to get at least 1 row */
1210 rasqal_query_results_ensure_have_row_internal(query_results);
1211
1212 return query_results->size;
1213 }
1214
1215
1216 static unsigned char*
rasqal_prefix_id(int prefix_id,const unsigned char * string)1217 rasqal_prefix_id(int prefix_id, const unsigned char *string)
1218 {
1219 int tmpid = prefix_id;
1220 unsigned char* buffer;
1221 size_t length = strlen(RASQAL_GOOD_CAST(const char*, string)) + 4; /* "r" +... + "q" +... \0 */
1222
1223 while(tmpid /= 10)
1224 length++;
1225
1226 buffer = RASQAL_MALLOC(unsigned char*, length);
1227 if(!buffer)
1228 return NULL;
1229
1230 sprintf(RASQAL_GOOD_CAST(char*, buffer), "r%dq%s", prefix_id, string);
1231
1232 return buffer;
1233 }
1234
1235
1236 static raptor_term*
rasqal_literal_to_result_term(rasqal_query_results * query_results,rasqal_literal * l)1237 rasqal_literal_to_result_term(rasqal_query_results* query_results,
1238 rasqal_literal* l)
1239 {
1240 rasqal_literal* nodel;
1241 raptor_term* t = NULL;
1242 unsigned char *nodeid;
1243
1244 nodel = rasqal_literal_as_node(l);
1245 if(!nodel)
1246 return NULL;
1247
1248 switch(nodel->type) {
1249 case RASQAL_LITERAL_URI:
1250 t = raptor_new_term_from_uri(query_results->world->raptor_world_ptr,
1251 nodel->value.uri);
1252 break;
1253
1254 case RASQAL_LITERAL_BLANK:
1255 if(l->type == RASQAL_LITERAL_BLANK) {
1256 /* original was a genuine blank node not a variable with a
1257 * blank node value so make a new one every result, not every triple
1258 */
1259 nodeid = rasqal_prefix_id(query_results->result_count,
1260 nodel->string);
1261 } else {
1262 nodeid = RASQAL_MALLOC(unsigned char*, nodel->string_len + 1);
1263 if(nodeid)
1264 memcpy(nodeid, nodel->string, nodel->string_len + 1);
1265 }
1266
1267 if(nodeid)
1268 l = rasqal_new_simple_literal(query_results->world,
1269 RASQAL_LITERAL_BLANK,
1270 nodeid);
1271
1272 if(!nodeid || !l)
1273 goto done;
1274
1275 t = raptor_new_term_from_blank(query_results->world->raptor_world_ptr,
1276 nodeid);
1277 rasqal_free_literal(l);
1278 break;
1279
1280 case RASQAL_LITERAL_STRING:
1281 t = raptor_new_term_from_literal(query_results->world->raptor_world_ptr,
1282 nodel->string,
1283 nodel->datatype,
1284 RASQAL_GOOD_CAST(const unsigned char*, nodel->language));
1285 break;
1286
1287 case RASQAL_LITERAL_QNAME:
1288 case RASQAL_LITERAL_PATTERN:
1289 case RASQAL_LITERAL_XSD_STRING:
1290 case RASQAL_LITERAL_BOOLEAN:
1291 case RASQAL_LITERAL_INTEGER:
1292 case RASQAL_LITERAL_DOUBLE:
1293 case RASQAL_LITERAL_FLOAT:
1294 case RASQAL_LITERAL_VARIABLE:
1295 case RASQAL_LITERAL_DECIMAL:
1296 case RASQAL_LITERAL_DATE:
1297 case RASQAL_LITERAL_DATETIME:
1298 case RASQAL_LITERAL_UDT:
1299 case RASQAL_LITERAL_INTEGER_SUBTYPE:
1300 /* QNames should be gone by the time expression eval happens
1301 * Everything else is removed by rasqal_literal_as_node() above.
1302 */
1303
1304 case RASQAL_LITERAL_UNKNOWN:
1305 default:
1306 break;
1307 }
1308
1309
1310 done:
1311 if(nodel)
1312 rasqal_free_literal(nodel);
1313
1314 return t;
1315 }
1316
1317
1318 /**
1319 * rasqal_query_results_get_triple:
1320 * @query_results: #rasqal_query_results query_results
1321 *
1322 * Get the current triple in the result.
1323 *
1324 * The return value is a shared #raptor_statement.
1325 *
1326 * Return value: #raptor_statement or NULL if failed or results exhausted
1327 **/
1328 raptor_statement*
rasqal_query_results_get_triple(rasqal_query_results * query_results)1329 rasqal_query_results_get_triple(rasqal_query_results* query_results)
1330 {
1331 rasqal_query* query;
1332 rasqal_triple *t;
1333 raptor_statement *rs = NULL;
1334
1335 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, NULL);
1336
1337 if(query_results->failed || query_results->finished)
1338 return NULL;
1339
1340 if(!rasqal_query_results_is_graph(query_results))
1341 return NULL;
1342
1343 query = query_results->query;
1344 if(!query)
1345 return NULL;
1346
1347 if(query->verb == RASQAL_QUERY_VERB_DESCRIBE)
1348 return NULL;
1349
1350
1351 /* ensure we have a row to work on */
1352 if(rasqal_query_results_ensure_have_row_internal(query_results))
1353 return NULL;
1354
1355 while(1) {
1356 int skip = 0;
1357
1358 if(query_results->current_triple_result < 0)
1359 query_results->current_triple_result = 0;
1360
1361 t = (rasqal_triple*)raptor_sequence_get_at(query->constructs,
1362 query_results->current_triple_result);
1363
1364 rs = &query_results->result_triple;
1365
1366 raptor_statement_clear(rs);
1367
1368 rs->subject = rasqal_literal_to_result_term(query_results, t->subject);
1369 if(!rs->subject || rs->subject->type == RAPTOR_TERM_TYPE_LITERAL) {
1370 rasqal_log_warning_simple(query_results->world,
1371 RASQAL_WARNING_LEVEL_BAD_TRIPLE,
1372 &query->locator,
1373 "Triple with non-RDF subject term skipped");
1374 skip = 1;
1375 } else {
1376 rs->predicate = rasqal_literal_to_result_term(query_results, t->predicate);
1377 if(!rs->predicate || rs->predicate->type != RAPTOR_TERM_TYPE_URI) {
1378 rasqal_log_warning_simple(query_results->world,
1379 RASQAL_WARNING_LEVEL_BAD_TRIPLE,
1380 &query->locator,
1381 "Triple with non-RDF predicate term skipped");
1382 skip = 1;
1383 } else {
1384 rs->object = rasqal_literal_to_result_term(query_results, t->object);
1385 if(!rs->object) {
1386 rasqal_log_warning_simple(query_results->world,
1387 RASQAL_WARNING_LEVEL_BAD_TRIPLE,
1388 &query->locator,
1389 "Triple with non-RDF object term skipped");
1390 skip = 1;
1391 }
1392 }
1393 }
1394
1395 if(!skip)
1396 /* got triple, return it */
1397 break;
1398
1399 /* Have to move to next triple internally */
1400 if(rasqal_query_results_next_triple(query_results)) {
1401 /* end of results or failed */
1402 rs = NULL;
1403 break;
1404 }
1405 }
1406
1407 return rs;
1408 }
1409
1410
1411 /**
1412 * rasqal_query_results_next_triple:
1413 * @query_results: #rasqal_query_results query_results
1414 *
1415 * Move to the next triple result.
1416 *
1417 * Return value: non-0 if failed or results exhausted
1418 **/
1419 int
rasqal_query_results_next_triple(rasqal_query_results * query_results)1420 rasqal_query_results_next_triple(rasqal_query_results* query_results)
1421 {
1422 rasqal_query* query;
1423 int rc = 0;
1424
1425 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 1);
1426
1427 if(query_results->failed || query_results->finished)
1428 return 1;
1429
1430 if(!rasqal_query_results_is_graph(query_results))
1431 return 1;
1432
1433 query = query_results->query;
1434 if(!query)
1435 return 1;
1436
1437 if(query->verb == RASQAL_QUERY_VERB_DESCRIBE)
1438 return 1;
1439
1440 if(++query_results->current_triple_result >= raptor_sequence_size(query->constructs)) {
1441 if(rasqal_query_results_next_internal(query_results))
1442 return 1;
1443
1444 query_results->current_triple_result = -1;
1445 }
1446
1447 return rc;
1448 }
1449
1450
1451 /**
1452 * rasqal_query_results_get_boolean:
1453 * @query_results: #rasqal_query_results query_results
1454 *
1455 * Get boolean query result.
1456 *
1457 * The return value is only meaningful if this is a boolean
1458 * query result - see rasqal_query_results_is_boolean()
1459 *
1460 * Return value: boolean query result - >0 is true, 0 is false, <0 on error
1461 */
1462 int
rasqal_query_results_get_boolean(rasqal_query_results * query_results)1463 rasqal_query_results_get_boolean(rasqal_query_results* query_results)
1464 {
1465 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, -1);
1466
1467 if(query_results->failed)
1468 return -1;
1469
1470 if(!rasqal_query_results_is_boolean(query_results))
1471 return -1;
1472
1473 if(query_results->ask_result >= 0)
1474 return query_results->ask_result;
1475
1476 rasqal_query_results_ensure_have_row_internal(query_results);
1477
1478 query_results->ask_result = (query_results->result_count > 0) ? 1 : 0;
1479 query_results->finished = 1;
1480
1481 return query_results->ask_result;
1482 }
1483
1484
1485 /**
1486 * rasqal_query_results_set_boolean:
1487 * @query_results: #rasqal_query_results query_results
1488 * @value: boolean value
1489 *
1490 * INTERNAL - Set boolean query result value.
1491 *
1492 * Return value: boolean query result - >0 is true, 0 is false, <0 on error
1493 */
1494 int
rasqal_query_results_set_boolean(rasqal_query_results * query_results,int value)1495 rasqal_query_results_set_boolean(rasqal_query_results* query_results, int value)
1496 {
1497 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, -1);
1498
1499 if(query_results->failed)
1500 return -1;
1501
1502 if(!rasqal_query_results_is_boolean(query_results))
1503 return -1;
1504
1505 query_results->finished = 1;
1506 query_results->ask_result = value;
1507 return 0;
1508 }
1509
1510
1511 /**
1512 * rasqal_query_results_write:
1513 * @iostr: #raptor_iostream to write the query to
1514 * @results: #rasqal_query_results query results format
1515 * @name: format name (or NULL)
1516 * @mime_type: format mime type (or NULL)
1517 * @format_uri: #raptor_uri describing the format to write (or NULL for default)
1518 * @base_uri: #raptor_uri base URI of the output format
1519 *
1520 * Write the query results to an iostream in a format.
1521 *
1522 * This uses the #rasqal_query_results_formatter class and the
1523 * rasqal_query_results_formatter_write() method to perform the
1524 * formatting.
1525 *
1526 * Note that after calling this method, the query results will be
1527 * empty and rasqal_query_results_finished() will return true (non-0)
1528 *
1529 * See rasqal_world_get_query_results_format_description() for obtaining the
1530 * supported format names, mime_types and URIs at run time.
1531 *
1532 * Return value: non-0 on failure
1533 **/
1534 int
rasqal_query_results_write(raptor_iostream * iostr,rasqal_query_results * results,const char * name,const char * mime_type,raptor_uri * format_uri,raptor_uri * base_uri)1535 rasqal_query_results_write(raptor_iostream *iostr,
1536 rasqal_query_results* results,
1537 const char *name,
1538 const char *mime_type,
1539 raptor_uri *format_uri,
1540 raptor_uri *base_uri)
1541 {
1542 rasqal_query_results_formatter *formatter;
1543 int status;
1544
1545 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(iostr, raptor_iostream, 1);
1546 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(results, rasqal_query_results, 1);
1547
1548 if(results->failed)
1549 return 1;
1550
1551 formatter = rasqal_new_query_results_formatter(results->world,
1552 name, mime_type,
1553 format_uri);
1554 if(!formatter)
1555 return 1;
1556
1557 status = rasqal_query_results_formatter_write(iostr, formatter,
1558 results, base_uri);
1559
1560 rasqal_free_query_results_formatter(formatter);
1561 return status;
1562 }
1563
1564
1565 /**
1566 * rasqal_query_results_read:
1567 * @iostr: #raptor_iostream to read the query from
1568 * @results: #rasqal_query_results query results format
1569 * @name: format name (or NULL)
1570 * @mime_type: format mime type (or NULL)
1571 * @format_uri: #raptor_uri describing the format to read (or NULL for default)
1572 * @base_uri: #raptor_uri base URI of the input format
1573 *
1574 * Read the query results from an iostream in a format.
1575 *
1576 * This uses the #rasqal_query_results_formatter class
1577 * and the rasqal_query_results_formatter_read() method
1578 * to perform the formatting.
1579 *
1580 * See rasqal_world_get_query_results_format_description() for
1581 * obtaining the supported format URIs at run time.
1582 *
1583 * Return value: non-0 on failure
1584 **/
1585 int
rasqal_query_results_read(raptor_iostream * iostr,rasqal_query_results * results,const char * name,const char * mime_type,raptor_uri * format_uri,raptor_uri * base_uri)1586 rasqal_query_results_read(raptor_iostream *iostr,
1587 rasqal_query_results* results,
1588 const char *name,
1589 const char *mime_type,
1590 raptor_uri *format_uri,
1591 raptor_uri *base_uri)
1592 {
1593 rasqal_query_results_formatter *formatter;
1594 int status;
1595
1596 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(iostr, raptor_iostream, 1);
1597 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(results, rasqal_query_results, 1);
1598
1599 if(results->failed)
1600 return 1;
1601
1602 formatter = rasqal_new_query_results_formatter(results->world,
1603 name, mime_type,
1604 format_uri);
1605 if(!formatter)
1606 return 1;
1607
1608 status = rasqal_query_results_formatter_read(results->world, iostr, formatter,
1609 results, base_uri);
1610
1611 rasqal_free_query_results_formatter(formatter);
1612 return status;
1613 }
1614
1615
1616 /**
1617 * rasqal_query_results_add_row:
1618 * @query_results: query results object
1619 * @row: query result row
1620 *
1621 * Add a query result row to the sequence of result rows
1622 *
1623 * Return value: non-0 on failure
1624 */
1625 int
rasqal_query_results_add_row(rasqal_query_results * query_results,rasqal_row * row)1626 rasqal_query_results_add_row(rasqal_query_results* query_results,
1627 rasqal_row* row)
1628 {
1629 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, 1);
1630 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(row, rasqal_row, 1);
1631
1632 if(!query_results->results_sequence) {
1633 query_results->results_sequence = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row, (raptor_data_print_handler)rasqal_row_print);
1634 if(!query_results->results_sequence)
1635 return 1;
1636
1637 query_results->result_count = 0;
1638 }
1639
1640 row->offset = raptor_sequence_size(query_results->results_sequence);
1641
1642 return raptor_sequence_push(query_results->results_sequence, row);
1643 }
1644
1645
1646 /**
1647 * rasqal_query_results_execute_and_store_results:
1648 * @query_results: query results object
1649 *
1650 * INTERNAL - Store all query result (rows) immediately
1651 *
1652 * Return value: non-0 on failure
1653 */
1654 static int
rasqal_query_results_execute_and_store_results(rasqal_query_results * query_results)1655 rasqal_query_results_execute_and_store_results(rasqal_query_results* query_results)
1656 {
1657 raptor_sequence* seq = NULL;
1658
1659 if(query_results->results_sequence)
1660 raptor_free_sequence(query_results->results_sequence);
1661
1662 if(query_results->execution_factory->get_all_rows) {
1663 rasqal_engine_error execution_error = RASQAL_ENGINE_OK;
1664
1665 seq = query_results->execution_factory->get_all_rows(query_results->execution_data, &execution_error);
1666 if(execution_error == RASQAL_ENGINE_FAILED)
1667 query_results->failed = 1;
1668 }
1669
1670 query_results->results_sequence = seq;
1671
1672 if(!seq) {
1673 query_results->finished = 1;
1674 } else
1675 rasqal_query_results_rewind(query_results);
1676
1677 return query_results->failed;
1678 }
1679
1680
1681 /*
1682 * rasqal_query_results_update_query_bindings:
1683 * @query_results: query results to read from
1684 * @query: query to set bindings to
1685 *
1686 * INTERNAL - bind the query variables to the values from the current query results row
1687 *
1688 * Used to handle query CONSTRUCT
1689 */
1690 static void
rasqal_query_results_update_query_bindings(rasqal_query_results * query_results,rasqal_query * query)1691 rasqal_query_results_update_query_bindings(rasqal_query_results* query_results, rasqal_query* query)
1692 {
1693 int i;
1694 int size;
1695 rasqal_row* row;
1696
1697 RASQAL_ASSERT_OBJECT_POINTER_RETURN(query_results, rasqal_query_results);
1698
1699 rasqal_query_results_ensure_have_row_internal(query_results);
1700
1701 row = query_results->row;
1702 if(!row) {
1703 query_results->finished = 1;
1704 return;
1705 }
1706
1707 size = rasqal_variables_table_get_named_variables_count(query_results->vars_table);
1708 for(i = 0; i < size; i++) {
1709 rasqal_variable* srcv;
1710 rasqal_variable* v;
1711 /* source value is in row */
1712 rasqal_literal* value = row->values[i];
1713
1714 /* source variable is in query results */
1715 srcv = rasqal_variables_table_get(query_results->vars_table, i);
1716
1717 /* destination variable is in query */
1718 v = rasqal_variables_table_get_by_name(query->vars_table, srcv->type, srcv->name);
1719 if(v)
1720 rasqal_variable_set_value(v, rasqal_new_literal_from_literal(value));
1721 else {
1722 RASQAL_DEBUG2("Cannot bind query results variable %s into query", srcv->name);
1723 }
1724 }
1725 }
1726
1727
1728 void
rasqal_query_results_remove_query_reference(rasqal_query_results * query_results)1729 rasqal_query_results_remove_query_reference(rasqal_query_results* query_results)
1730 {
1731 rasqal_query* query;
1732
1733 RASQAL_ASSERT_OBJECT_POINTER_RETURN(query_results, rasqal_query_results);
1734
1735 query = query_results->query;
1736 query_results->query = NULL;
1737
1738 rasqal_free_query(query);
1739 }
1740
1741
1742 rasqal_variables_table*
rasqal_query_results_get_variables_table(rasqal_query_results * query_results)1743 rasqal_query_results_get_variables_table(rasqal_query_results* query_results)
1744 {
1745 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, NULL);
1746
1747 return query_results->vars_table;
1748 }
1749
1750
1751
1752 rasqal_world*
rasqal_query_results_get_world(rasqal_query_results * query_results)1753 rasqal_query_results_get_world(rasqal_query_results* query_results)
1754 {
1755 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, NULL);
1756
1757 return query_results->world;
1758 }
1759
1760
1761 /**
1762 * rasqal_query_results_get_row_by_offset:
1763 * @query_results: query result
1764 * @result_offset: index into result rows
1765 *
1766 * Get stored result row by an offset
1767 *
1768 * The result_offset index is 0-indexed into the subset of results
1769 * constrained by any query limit and offset.
1770 *
1771 * Return value: row or NULL if @result_offset is out of range
1772 */
1773 rasqal_row*
rasqal_query_results_get_row_by_offset(rasqal_query_results * query_results,int result_offset)1774 rasqal_query_results_get_row_by_offset(rasqal_query_results* query_results,
1775 int result_offset)
1776 {
1777 rasqal_query* query;
1778 int check;
1779 rasqal_row* row;
1780 int offset = 0;
1781
1782 RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query_results, rasqal_query_results, NULL);
1783
1784 if(!query_results->results_sequence)
1785 return NULL;
1786
1787 if(result_offset < 0)
1788 return NULL;
1789
1790 query = query_results->query;
1791 if(query)
1792 offset = rasqal_query_get_offset(query);
1793
1794 /* Adjust 0-indexed to query results 1-indexed + query result offset */
1795 result_offset += 1 + offset;
1796
1797 check = rasqal_query_check_limit_offset(query_results->query,
1798 result_offset);
1799 /* outside limit/offset range in some way */
1800 if(check < 0 || check > 0)
1801 return NULL;
1802
1803 row = (rasqal_row*)raptor_sequence_get_at(query_results->results_sequence,
1804 result_offset - 1);
1805 if(row) {
1806 row = rasqal_new_row_from_row(row);
1807
1808 /* stored results may not be canonicalized yet - do it lazily */
1809 rasqal_row_to_nodes(row);
1810 }
1811
1812 return row;
1813 }
1814
1815
1816 struct rqr_context
1817 {
1818 rasqal_query_results* results;
1819
1820 /* size of @order - number of values */
1821 int size;
1822
1823 /* Sequence of offsets to variables in lexical order */
1824 int* order;
1825 };
1826
1827
1828 /**
1829 * rasqal_query_results_sort_compare_row:
1830 * @a: pointer to address of first #row
1831 * @b: pointer to address of second #row
1832 * @arg: query results pointer
1833 *
1834 * INTERNAL - compare two pointers to #row objects with user data arg
1835 *
1836 * Suitable for use as a compare function with raptor_sort_r() or
1837 * compatible. Used by rasqal_query_results_sort().
1838 *
1839 * Return value: <0, 0 or >0 comparison
1840 */
1841 static int
rasqal_query_results_sort_compare_row(const void * a,const void * b,void * arg)1842 rasqal_query_results_sort_compare_row(const void *a, const void *b, void *arg)
1843 {
1844 rasqal_row* row_a;
1845 rasqal_row* row_b;
1846 struct rqr_context* rqr;
1847 int result = 0;
1848
1849 row_a = *(rasqal_row**)a;
1850 row_b = *(rasqal_row**)b;
1851 rqr = (struct rqr_context*)arg;
1852
1853 result = rasqal_literal_array_compare_by_order(row_a->values, row_b->values,
1854 rqr->order, row_a->size, 0);
1855
1856 /* still equal? make sort stable by using the original order */
1857 if(!result) {
1858 result = row_a->offset - row_b->offset;
1859 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
1860 RASQAL_DEBUG2("Got equality result so using offsets, returning %d\n",
1861 result);
1862 #endif
1863 }
1864
1865 return result;
1866 }
1867
1868
1869 int
rasqal_query_results_sort(rasqal_query_results * query_results)1870 rasqal_query_results_sort(rasqal_query_results* query_results)
1871 {
1872 struct rqr_context rqr;
1873
1874 if(query_results->execution_factory && !query_results->results_sequence) {
1875 int rc;
1876
1877 rc = rasqal_query_results_execute_and_store_results(query_results);
1878 if(rc)
1879 return rc;
1880 }
1881
1882 rqr.results = query_results;
1883 rqr.size = query_results->size;
1884 rqr.order = rasqal_variables_table_get_order(query_results->vars_table);
1885 if(!rqr.order)
1886 return 1;
1887
1888 if(query_results->results_sequence) {
1889 int size = raptor_sequence_size(query_results->results_sequence);
1890 if(size > 1) {
1891 #if RAPTOR_VERSION < 20015
1892 raptor_sequence *seq;
1893 void** array;
1894 size_t i;
1895
1896 seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row, (raptor_data_print_handler)rasqal_row_print);
1897 if(!seq) {
1898 RASQAL_FREE(int*, rqr.order);
1899 return 1;
1900 }
1901
1902 array = rasqal_sequence_as_sorted(seq,
1903 rasqal_query_results_sort_compare_row,
1904 &rqr);
1905 if(!array) {
1906 raptor_free_sequence(seq);
1907 RASQAL_FREE(int*, rqr.order);
1908 return 1;
1909 }
1910
1911 for(i = 0; i < RASQAL_GOOD_CAST(size_t, size); i++) {
1912 rasqal_row* row = rasqal_new_row_from_row(RASQAL_GOOD_CAST(rasqal_row*, array[i]));
1913 raptor_sequence_push(seq, row);
1914 }
1915 raptor_free_sequence(query_results->results_sequence);
1916 query_results->results_sequence = seq;
1917 RASQAL_FREE(void*, array);
1918 #else
1919 raptor_sequence_sort_r(query_results->results_sequence,
1920 rasqal_query_results_sort_compare_row,
1921 &rqr);
1922 #endif
1923 }
1924 }
1925
1926 RASQAL_FREE(int*, rqr.order);
1927 return 0;
1928 }
1929
1930 #endif /* not STANDALONE */
1931
1932
1933
1934 #ifdef STANDALONE
1935
1936 /* one more prototype */
1937 int main(int argc, char *argv[]);
1938
1939 #define NTESTS 2
1940
1941 const struct {
1942 const char* qr_string;
1943 int expected_vars_count;
1944 int expected_rows_count;
1945 int expected_equality;
1946 } expected_data[NTESTS] = {
1947 {
1948 "a\tb\tc\td\n\"a\"\t\"b\"\t\"c\"\t\"d\"\n",
1949 4, 1, 1
1950 },
1951 {
1952 "a,b,c,d,e,f\n\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"\n",
1953 6, 1, 1
1954 }
1955 };
1956
1957
1958 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
1959 static void
print_bindings_results_simple(rasqal_query_results * results,FILE * output)1960 print_bindings_results_simple(rasqal_query_results *results, FILE* output)
1961 {
1962 while(!rasqal_query_results_finished(results)) {
1963 int i;
1964
1965 fputs("row: [", output);
1966 for(i = 0; i < rasqal_query_results_get_bindings_count(results); i++) {
1967 const unsigned char *name;
1968 rasqal_literal *value;
1969
1970 name = rasqal_query_results_get_binding_name(results, i);
1971 value = rasqal_query_results_get_binding_value(results, i);
1972
1973 if(i > 0)
1974 fputs(", ", output);
1975
1976 fprintf(output, "%s=", name);
1977 rasqal_literal_print(value, output);
1978 }
1979 fputs("]\n", output);
1980
1981 rasqal_query_results_next(results);
1982 }
1983 }
1984 #endif
1985
1986 int
main(int argc,char * argv[])1987 main(int argc, char *argv[])
1988 {
1989 const char *program = rasqal_basename(argv[0]);
1990 rasqal_world* world = NULL;
1991 raptor_world* raptor_world_ptr;
1992 int failures = 0;
1993 int i;
1994 rasqal_query_results_type type = RASQAL_QUERY_RESULTS_BINDINGS;
1995
1996 world = rasqal_new_world(); rasqal_world_open(world);
1997
1998 raptor_world_ptr = rasqal_world_get_raptor(world);
1999
2000 for(i = 0; i < NTESTS; i++) {
2001 raptor_uri* base_uri = raptor_new_uri(raptor_world_ptr,
2002 (const unsigned char*)"http://example.org/");
2003 rasqal_query_results *qr;
2004 int expected_vars_count = expected_data[i].expected_vars_count;
2005 int vars_count;
2006
2007 qr = rasqal_new_query_results_from_string(world,
2008 type,
2009 base_uri,
2010 expected_data[i].qr_string,
2011 0);
2012 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
2013 RASQAL_DEBUG1("Query result from string:");
2014 print_bindings_results_simple(first_qr, stderr);
2015 rasqal_query_results_rewind(first_qr);
2016 #endif
2017
2018 raptor_free_uri(base_uri);
2019
2020 if(!qr) {
2021 fprintf(stderr, "%s: failed to create query results\n", program);
2022 failures++;
2023 } else {
2024 rasqal_variables_table* vt;
2025
2026 vt = rasqal_query_results_get_variables_table(qr);
2027 vars_count = rasqal_variables_table_get_named_variables_count(vt);
2028 RASQAL_DEBUG4("%s: query results test %d returned %d vars\n", program, i,
2029 vars_count);
2030 if(vars_count != expected_vars_count) {
2031 fprintf(stderr,
2032 "%s: FAILED query results test %d returned %d vars expected %d vars\n",
2033 program, i, vars_count, expected_vars_count);
2034 failures++;
2035 }
2036 }
2037
2038 if(qr)
2039 rasqal_free_query_results(qr);
2040 }
2041
2042 if(world)
2043 rasqal_free_world(world);
2044
2045 return failures;
2046 }
2047
2048 #endif /* STANDALONE */
2049