1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rasqal_rowsource.c - Rasqal query rowsource (row generator) 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 <raptor.h>
40
41 #include "rasqal.h"
42 #include "rasqal_internal.h"
43
44
45 #ifndef STANDALONE
46
47 static void rasqal_rowsource_print_header(rasqal_rowsource* rowsource, FILE* fh);
48
49 /**
50 * rasqal_new_rowsource_from_handler:
51 * @query: query object
52 * @user_data: pointer to context information to pass in to calls
53 * @handler: pointer to handler methods
54 * @vars_table: variables table to use for rows (or NULL)
55 * @flags: 0 (none defined so far)
56 *
57 * Create a new rowsource over a user-defined handler.
58 *
59 * Return value: new #rasqal_rowsource object or NULL on failure
60 **/
61 rasqal_rowsource*
rasqal_new_rowsource_from_handler(rasqal_world * world,rasqal_query * query,void * user_data,const rasqal_rowsource_handler * handler,rasqal_variables_table * vars_table,int flags)62 rasqal_new_rowsource_from_handler(rasqal_world* world,
63 rasqal_query* query,
64 void *user_data,
65 const rasqal_rowsource_handler *handler,
66 rasqal_variables_table* vars_table,
67 int flags)
68 {
69 rasqal_rowsource* rowsource;
70
71 if(!world || !handler)
72 return NULL;
73
74 if(handler->version < 1 || handler->version > 1)
75 return NULL;
76
77 rowsource = RASQAL_CALLOC(rasqal_rowsource*, 1, sizeof(*rowsource));
78 if(!rowsource) {
79 if(handler->finish)
80 handler->finish(NULL, user_data);
81 return NULL;
82 }
83
84 rowsource->usage = 1;
85 rowsource->world = world;
86 rowsource->query = query;
87 rowsource->user_data = (void*)user_data;
88 rowsource->handler = handler;
89 rowsource->flags = flags;
90
91 rowsource->size = 0;
92
93 rowsource->generate_group = 0;
94
95 if(vars_table)
96 rowsource->vars_table = rasqal_new_variables_table_from_variables_table(vars_table);
97 else
98 rowsource->vars_table = NULL;
99
100 rowsource->variables_sequence = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
101 (raptor_data_print_handler)rasqal_variable_print);
102 if(!rowsource->variables_sequence) {
103 rasqal_free_rowsource(rowsource);
104 return NULL;
105 }
106
107 if(rowsource->handler->init &&
108 rowsource->handler->init(rowsource, rowsource->user_data)) {
109 RASQAL_DEBUG2("rowsource %s init failed\n", rowsource->handler->name);
110 rasqal_free_rowsource(rowsource);
111 return NULL;
112 }
113
114 return rowsource;
115 }
116
117
118 /**
119 * rasqal_new_rowsource_from_rowsource:
120 * @row: query result row
121 *
122 * INTERNAL - Copy a rowsource.
123 *
124 * Return value: a copy of the rowsource or NULL
125 */
126 rasqal_rowsource*
rasqal_new_rowsource_from_rowsource(rasqal_rowsource * rowsource)127 rasqal_new_rowsource_from_rowsource(rasqal_rowsource* rowsource)
128 {
129 if(!rowsource)
130 return NULL;
131
132 rowsource->usage++;
133 return rowsource;
134 }
135
136
137 /**
138 * rasqal_free_rowsource:
139 * @rowsource: rowsource object
140 *
141 * INTERNAL - Destructor - destroy an rowsource.
142 **/
143 void
rasqal_free_rowsource(rasqal_rowsource * rowsource)144 rasqal_free_rowsource(rasqal_rowsource *rowsource)
145 {
146 if(!rowsource)
147 return;
148
149 if(--rowsource->usage)
150 return;
151
152 if(rowsource->handler->finish)
153 rowsource->handler->finish(rowsource, rowsource->user_data);
154
155 if(rowsource->vars_table)
156 rasqal_free_variables_table(rowsource->vars_table);
157
158 if(rowsource->variables_sequence)
159 raptor_free_sequence(rowsource->variables_sequence);
160
161 if(rowsource->rows_sequence)
162 raptor_free_sequence(rowsource->rows_sequence);
163
164 RASQAL_FREE(rasqal_rowsource, rowsource);
165 }
166
167
168
169 /**
170 * rasqal_rowsource_add_variable:
171 * @rowsource: rasqal rowsource
172 * @v: variable
173 *
174 * Add a variable to the rowsource if the variable is not already present
175 *
176 * Return value: variable offset or < 0 on failure
177 **/
178 int
rasqal_rowsource_add_variable(rasqal_rowsource * rowsource,rasqal_variable * v)179 rasqal_rowsource_add_variable(rasqal_rowsource *rowsource, rasqal_variable* v)
180 {
181 int offset;
182
183 if(!rowsource || !v)
184 return -1;
185
186 offset = rasqal_rowsource_get_variable_offset_by_name(rowsource, v->name);
187 if(offset >= 0)
188 return offset;
189
190 v = rasqal_new_variable_from_variable(v);
191 if(raptor_sequence_push(rowsource->variables_sequence, v))
192 return -1;
193
194 offset = rowsource->size;
195
196 rowsource->size++;
197
198 return offset;
199 }
200
201
202 /**
203 * rasqal_rowsource_ensure_variables:
204 * @rowsource: rasqal rowsource
205 *
206 * INTERNAL - Ensure that the variables in the rowsource are defined
207 *
208 * Return value: non-0 on failure
209 */
210 int
rasqal_rowsource_ensure_variables(rasqal_rowsource * rowsource)211 rasqal_rowsource_ensure_variables(rasqal_rowsource *rowsource)
212 {
213 int rc = 0;
214
215 if(rowsource->updated_variables)
216 return 0;
217
218 rowsource->updated_variables++;
219
220 if(rowsource->handler->ensure_variables)
221 rc = rowsource->handler->ensure_variables(rowsource, rowsource->user_data);
222
223 #ifdef RASQAL_DEBUG
224 if(!rc) {
225 RASQAL_DEBUG3("%s rowsource %p header: ", rowsource->handler->name,
226 rowsource);
227 rasqal_rowsource_print_header(rowsource, stderr);
228 }
229 #endif
230
231 return rc;
232 }
233
234
235 /**
236 * rasqal_rowsource_read_row:
237 * @rowsource: rasqal rowsource
238 *
239 * Read a query result row from the rowsource.
240 *
241 * If a row is returned, it is owned by the caller.
242 *
243 * Return value: row or NULL when no more rows are available
244 **/
245 rasqal_row*
rasqal_rowsource_read_row(rasqal_rowsource * rowsource)246 rasqal_rowsource_read_row(rasqal_rowsource *rowsource)
247 {
248 rasqal_row* row = NULL;
249
250 if(!rowsource || rowsource->finished)
251 return NULL;
252
253 if(rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVED_ROWS) {
254 /* return row from saved rows sequence at offset */
255 row = (rasqal_row*)raptor_sequence_get_at(rowsource->rows_sequence,
256 rowsource->offset++);
257 #ifdef RASQAL_DEBUG
258 RASQAL_DEBUG3("%s rowsource %p returned saved row: ",
259 rowsource->handler->name, rowsource);
260 if(row)
261 rasqal_row_print(row, stderr);
262 else
263 fputs("NONE", stderr);
264 fputs("\n", stderr);
265 #endif
266 if(row)
267 row = rasqal_new_row_from_row(row);
268 /* row is owned by us */
269 } else {
270 if(rasqal_rowsource_ensure_variables(rowsource))
271 return NULL;
272
273 if(rowsource->handler->read_row) {
274 row = rowsource->handler->read_row(rowsource, rowsource->user_data);
275 /* row is owned by us */
276
277 if(row && rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVE_ROWS) {
278 if(!rowsource->rows_sequence) {
279 rowsource->rows_sequence = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row,
280 (raptor_data_print_handler)rasqal_row_print);
281 rowsource->offset = 0;
282 }
283 /* copy to save it away */
284 row = rasqal_new_row_from_row(row);
285 raptor_sequence_push(rowsource->rows_sequence, row);
286 }
287 } else {
288 if(!rowsource->rows_sequence) {
289 raptor_sequence* seq;
290
291 seq = rasqal_rowsource_read_all_rows(rowsource);
292 if(rowsource->rows_sequence)
293 raptor_free_sequence(rowsource->rows_sequence);
294 /* rows_sequence now owns all rows */
295 rowsource->rows_sequence = seq;
296
297 rowsource->offset = 0;
298 }
299
300 if(rowsource->rows_sequence) {
301 /* return row from sequence at offset */
302 row = (rasqal_row*)raptor_sequence_get_at(rowsource->rows_sequence,
303 rowsource->offset++);
304 if(row)
305 row = rasqal_new_row_from_row(row);
306 /* row is owned by us */
307 }
308 }
309 }
310
311 if(!row) {
312 rowsource->finished = 1;
313 if(rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVE_ROWS)
314 rowsource->flags |= RASQAL_ROWSOURCE_FLAGS_SAVED_ROWS;
315 } else {
316 rowsource->count++;
317
318 /* Generate a group around all rows if there are no groups returned */
319 if(rowsource->generate_group && row->group_id < 0)
320 row->group_id = 0;
321 }
322
323 #ifdef RASQAL_DEBUG
324 RASQAL_DEBUG3("%s rowsource %p returned row: ", rowsource->handler->name,
325 rowsource);
326 if(row)
327 rasqal_row_print(row, stderr);
328 else
329 fputs("NONE", stderr);
330 fputs("\n", stderr);
331 #endif
332
333 return row;
334 }
335
336
337 /**
338 * rasqal_rowsource_get_row_count:
339 * @rowsource: rasqal rowsource
340 *
341 * Get number of rows seen from a rowsource.
342 *
343 * Return value: row count or < 0 on failure
344 **/
345 int
rasqal_rowsource_get_rows_count(rasqal_rowsource * rowsource)346 rasqal_rowsource_get_rows_count(rasqal_rowsource *rowsource)
347 {
348 if(!rowsource)
349 return -1;
350
351 return rowsource->count;
352 }
353
354
355 /**
356 * rasqal_rowsource_read_all_rows:
357 * @rowsource: rasqal rowsource
358 *
359 * Read all rows from a rowsource
360 *
361 * After calling this, the rowsource will be empty of rows and finished
362 * and if a sequence is returned, it is owned by the caller.
363 *
364 * Return value: new sequence of all rows (may be size 0) or NULL on failure
365 **/
366 raptor_sequence*
rasqal_rowsource_read_all_rows(rasqal_rowsource * rowsource)367 rasqal_rowsource_read_all_rows(rasqal_rowsource *rowsource)
368 {
369 raptor_sequence* seq;
370
371 if(!rowsource)
372 return NULL;
373
374 if(rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVED_ROWS) {
375 raptor_sequence* new_seq;
376
377 /* Return a complete copy of all previously saved rows */
378 seq = rowsource->rows_sequence;
379 new_seq = rasqal_row_sequence_copy(seq);
380 RASQAL_DEBUG4("%s rowsource %p returning a sequence of %d saved rows\n",
381 rowsource->handler->name, rowsource,
382 raptor_sequence_size(new_seq));
383 return new_seq;
384 }
385
386 /* Execute */
387 if(rasqal_rowsource_ensure_variables(rowsource))
388 return NULL;
389
390 if(rowsource->handler->read_all_rows) {
391 seq = rowsource->handler->read_all_rows(rowsource, rowsource->user_data);
392 if(!seq) {
393 seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row,
394 (raptor_data_print_handler)rasqal_row_print);
395 } else if(rowsource->generate_group) {
396 int i;
397 rasqal_row* row;
398
399 /* Set group for all rows if there are no groups returned */
400
401 for(i = 0; (row = (rasqal_row*)raptor_sequence_get_at(seq, i)); i++) {
402 /* if first row has a group ID, end */
403 if(!i && row->group_id >= 0)
404 break;
405
406 row->group_id = 0;
407 }
408 }
409
410 goto done;
411 }
412
413 seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row,
414 (raptor_data_print_handler)rasqal_row_print);
415 if(!seq)
416 return NULL;
417
418 while(1) {
419 rasqal_row* row = rasqal_rowsource_read_row(rowsource);
420 if(!row)
421 break;
422
423 /* Generate a group around all rows if there are no groups returned */
424 if(rowsource->generate_group && row->group_id < 0)
425 row->group_id = 0;
426
427 raptor_sequence_push(seq, row);
428 }
429
430 done:
431 if(seq && rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVE_ROWS) {
432 raptor_sequence* new_seq;
433
434 /* Save a complete copy of all rows */
435 new_seq = rasqal_row_sequence_copy(seq);
436 RASQAL_DEBUG4("%s rowsource %p saving a sequence of %d rows\n",
437 rowsource->handler->name, rowsource,
438 raptor_sequence_size(new_seq));
439 rowsource->rows_sequence = new_seq;
440 rowsource->flags |= RASQAL_ROWSOURCE_FLAGS_SAVED_ROWS;
441 }
442
443 RASQAL_DEBUG4("%s rowsource %p returning a sequence of %d rows\n",
444 rowsource->handler->name, rowsource,
445 raptor_sequence_size(seq));
446 return seq;
447 }
448
449
450 /**
451 * rasqal_rowsource_get_size:
452 * @rowsource: rasqal rowsource
453 *
454 * Get rowsource row width or <0 on failure
455 **/
456 int
rasqal_rowsource_get_size(rasqal_rowsource * rowsource)457 rasqal_rowsource_get_size(rasqal_rowsource *rowsource)
458 {
459 if(!rowsource)
460 return -1;
461
462 rasqal_rowsource_ensure_variables(rowsource);
463
464 return rowsource->size;
465 }
466
467
468 /**
469 * rasqal_rowsource_get_variable_by_offset:
470 * @rowsource: rasqal rowsource
471 * @offset: integer offset into array of variables
472 *
473 * Get the variable associated with the given offset
474 *
475 * Return value: pointer to shared #rasqal_variable or NULL if out of range
476 **/
477 rasqal_variable*
rasqal_rowsource_get_variable_by_offset(rasqal_rowsource * rowsource,int offset)478 rasqal_rowsource_get_variable_by_offset(rasqal_rowsource *rowsource, int offset)
479 {
480 if(!rowsource)
481 return NULL;
482
483 rasqal_rowsource_ensure_variables(rowsource);
484
485 if(!rowsource->variables_sequence)
486 return NULL;
487
488 return (rasqal_variable*)raptor_sequence_get_at(rowsource->variables_sequence,
489 offset);
490 }
491
492
493 /**
494 * rasqal_rowsource_get_variable_offset_by_name:
495 * @rowsource: rasqal rowsource
496 * @name: variable name
497 *
498 * Get the offset of a variable into the list of variables
499 *
500 * Return value: offset or <0 if not present or on failure
501 **/
502 int
rasqal_rowsource_get_variable_offset_by_name(rasqal_rowsource * rowsource,const unsigned char * name)503 rasqal_rowsource_get_variable_offset_by_name(rasqal_rowsource *rowsource,
504 const unsigned char* name)
505 {
506 int offset= -1;
507 int i;
508
509 if(!rowsource)
510 return -1;
511
512 rasqal_rowsource_ensure_variables(rowsource);
513
514 if(!rowsource->variables_sequence)
515 return -1;
516
517 for(i=0; i < raptor_sequence_size(rowsource->variables_sequence); i++) {
518 rasqal_variable* v;
519 v = (rasqal_variable*)raptor_sequence_get_at(rowsource->variables_sequence, i);
520 if(!strcmp(RASQAL_GOOD_CAST(const char*, v->name),
521 RASQAL_GOOD_CAST(const char*, name))) {
522 offset = i;
523 break;
524 }
525 }
526
527 return offset;
528 }
529
530
531 /**
532 * rasqal_rowsource_copy_variables:
533 * @dest_rowsource: destination rowsource to copy into
534 * @src_rowsource: source rowsource to copy from
535 *
536 * INTERNAL - Copy a variables projection from one rowsource to another
537 *
538 * This adds new variables from @src_rowsource to the
539 * @dest_rowsource, it does not add duplicates.
540 *
541 * Return value: 0 on success, non-0 on failure
542 **/
543 int
rasqal_rowsource_copy_variables(rasqal_rowsource * dest_rowsource,rasqal_rowsource * src_rowsource)544 rasqal_rowsource_copy_variables(rasqal_rowsource *dest_rowsource,
545 rasqal_rowsource *src_rowsource)
546 {
547 int i;
548
549 for(i = 0; i < src_rowsource->size; i++) {
550 rasqal_variable* v;
551 v = rasqal_rowsource_get_variable_by_offset(src_rowsource, i);
552 if(!v) {
553 RASQAL_DEBUG5("%s src rowsource %p failed to return variable at offset %d, size %d\n",
554 src_rowsource->handler->name, src_rowsource,
555 i, src_rowsource->size);
556 return 1;
557 }
558 if(rasqal_rowsource_add_variable(dest_rowsource, v) < 0)
559 return 1;
560 }
561
562 return 0;
563 }
564
565
566 static void
rasqal_rowsource_print_header(rasqal_rowsource * rowsource,FILE * fh)567 rasqal_rowsource_print_header(rasqal_rowsource* rowsource, FILE* fh)
568 {
569 int i;
570
571 fputs("variables: ", fh);
572 for(i = 0; i < rowsource->size; i++) {
573 rasqal_variable* v;
574 const unsigned char *name = NULL;
575
576 v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
577 if(v)
578 name = v->name;
579 if(i > 0)
580 fputs(", ", fh);
581 if(name)
582 fputs(RASQAL_GOOD_CAST(const char*, name), fh);
583 else
584 fputs("NULL", fh);
585 }
586 fputs("\n", fh);
587 }
588
589
590 /**
591 * rasqal_rowsource_print_row_sequence:
592 * @rowsource: rowsource associated with rows
593 * @seq: query result sequence of #rasqal_row
594 * @fp: FILE* handle to print to
595 *
596 * INTERNAL - Print a result set header with row values from a sequence
597 */
598 void
rasqal_rowsource_print_row_sequence(rasqal_rowsource * rowsource,raptor_sequence * seq,FILE * fh)599 rasqal_rowsource_print_row_sequence(rasqal_rowsource* rowsource,
600 raptor_sequence* seq,
601 FILE* fh)
602 {
603 int size = raptor_sequence_size(seq);
604 int i;
605
606 rasqal_rowsource_print_header(rowsource, fh);
607
608 for(i = 0; i < size; i++) {
609 rasqal_row *row = (rasqal_row*)raptor_sequence_get_at(seq, i);
610 rasqal_row_print(row, fh);
611 fputs("\n", fh);
612 }
613 }
614
615
616 /**
617 * rasqal_rowsource_reset:
618 * @rowsource: rasqal rowsource
619 *
620 * INTERNAL - Reset a rowsource to regenerate the same set of rows
621 *
622 * Return value: query or NULL
623 **/
624 int
rasqal_rowsource_reset(rasqal_rowsource * rowsource)625 rasqal_rowsource_reset(rasqal_rowsource* rowsource)
626 {
627 rowsource->finished = 0;
628 rowsource->count = 0;
629
630 if(rowsource->handler->reset)
631 return rowsource->handler->reset(rowsource, rowsource->user_data);
632
633 if(rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVED_ROWS) {
634 RASQAL_DEBUG3("%s rowsource %p resetting to use saved rows\n",
635 rowsource->handler->name, rowsource);
636 rowsource->offset = 0;
637 } else {
638 RASQAL_DEBUG3("WARNING: %s rowsource %p has no reset and there are no saved rows\n",
639 rowsource->handler->name, rowsource);
640 }
641 return 0;
642 }
643
644
645 rasqal_rowsource*
rasqal_rowsource_get_inner_rowsource(rasqal_rowsource * rowsource,int offset)646 rasqal_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource, int offset)
647 {
648 if(rowsource->handler->get_inner_rowsource)
649 return rowsource->handler->get_inner_rowsource(rowsource,
650 rowsource->user_data,
651 offset);
652 return NULL;
653 }
654
655
656 /**
657 * rasqal_rowsource_visit:
658 * @node: #rasqal_rowsource row source
659 * @fn: pointer to function to apply that takes user data and rowsource parameters
660 * @user_data: user data for applied function
661 *
662 * Visit a user function over a #rasqal_rowsource
663 *
664 * If the user function @fn returns 0, the visit is truncated.
665 *
666 * Return value: non-0 if the visit was truncated or on failure.
667 **/
668 int
rasqal_rowsource_visit(rasqal_rowsource * rowsource,rasqal_rowsource_visit_fn fn,void * user_data)669 rasqal_rowsource_visit(rasqal_rowsource* rowsource,
670 rasqal_rowsource_visit_fn fn,
671 void *user_data)
672 {
673 int result;
674 int offset;
675 rasqal_rowsource* inner_rs;
676
677 if(!rowsource || !fn)
678 return 1;
679
680 result = fn(rowsource, user_data);
681 /* end if failed */
682 if(result < 0)
683 return result;
684
685 /* Do not recurse if handled */
686 if(result > 0)
687 return 0;
688
689 for(offset = 0;
690 (inner_rs = rasqal_rowsource_get_inner_rowsource(rowsource, offset));
691 offset++) {
692 result = rasqal_rowsource_visit(inner_rs, fn, user_data);
693 /* end if failed */
694 if(result < 0)
695 return result;
696 }
697
698 return 0;
699 }
700
701
702 static int
rasqal_rowsource_visitor_set_origin(rasqal_rowsource * rowsource,void * user_data)703 rasqal_rowsource_visitor_set_origin(rasqal_rowsource* rowsource,
704 void *user_data)
705 {
706 rasqal_literal *literal = (rasqal_literal*)user_data;
707
708 if(rowsource->handler->set_origin)
709 return rowsource->handler->set_origin(rowsource, rowsource->user_data,
710 literal);
711 return 0;
712 }
713
714
715 int
rasqal_rowsource_set_origin(rasqal_rowsource * rowsource,rasqal_literal * literal)716 rasqal_rowsource_set_origin(rasqal_rowsource* rowsource,
717 rasqal_literal *literal)
718 {
719 rasqal_rowsource_visit(rowsource,
720 rasqal_rowsource_visitor_set_origin,
721 literal);
722
723 return 0;
724 }
725
726
727 static int
rasqal_rowsource_visitor_set_requirements(rasqal_rowsource * rowsource,void * user_data)728 rasqal_rowsource_visitor_set_requirements(rasqal_rowsource* rowsource,
729 void *user_data)
730 {
731 unsigned int flags = *(unsigned int*)user_data;
732
733 if(rowsource->handler->set_requirements)
734 return rowsource->handler->set_requirements(rowsource, rowsource->user_data,
735 flags);
736
737 if(flags & RASQAL_ROWSOURCE_REQUIRE_RESET) {
738 if(!rowsource->handler->reset) {
739 /* If there is no reset handler, it is handled by this module and it is needed
740 * it is handled by this module
741 */
742 RASQAL_DEBUG3("setting %s rowsource %p to save rows\n",
743 rowsource->handler->name, rowsource);
744 rowsource->flags |= RASQAL_ROWSOURCE_FLAGS_SAVE_ROWS;
745 return 1;
746 }
747 }
748
749 return 0;
750 }
751
752
753 int
rasqal_rowsource_set_requirements(rasqal_rowsource * rowsource,unsigned int flags)754 rasqal_rowsource_set_requirements(rasqal_rowsource* rowsource, unsigned int flags)
755 {
756 return rasqal_rowsource_visit(rowsource,
757 rasqal_rowsource_visitor_set_requirements,
758 &flags);
759 }
760
761
762 int
rasqal_rowsource_request_grouping(rasqal_rowsource * rowsource)763 rasqal_rowsource_request_grouping(rasqal_rowsource* rowsource)
764 {
765 rowsource->generate_group = 1;
766
767 return 0;
768 }
769
770
771 #define SPACES_LENGTH 80
772 static const char spaces[SPACES_LENGTH+1] = " ";
773
774 static void
rasqal_rowsource_write_indent(raptor_iostream * iostr,unsigned int indent)775 rasqal_rowsource_write_indent(raptor_iostream *iostr, unsigned int indent)
776 {
777 while(indent > 0) {
778 unsigned int sp = (indent > SPACES_LENGTH) ? SPACES_LENGTH : indent;
779 raptor_iostream_write_bytes(spaces, sizeof(char), RASQAL_GOOD_CAST(size_t, sp), iostr);
780 indent -= sp;
781 }
782 }
783
784
785 static int
rasqal_rowsource_write_internal(rasqal_rowsource * rowsource,raptor_iostream * iostr,unsigned int indent)786 rasqal_rowsource_write_internal(rasqal_rowsource *rowsource,
787 raptor_iostream* iostr, unsigned int indent)
788 {
789 const char* rs_name = rowsource->handler->name;
790 int arg_count = 0;
791 unsigned int indent_delta;
792 int offset;
793 rasqal_rowsource* inner_rowsource;
794
795 indent_delta = RASQAL_GOOD_CAST(unsigned int, strlen(rs_name));
796
797 raptor_iostream_counted_string_write(rs_name, indent_delta, iostr);
798 raptor_iostream_counted_string_write("(\n", 2, iostr);
799 indent_delta++;
800
801 indent += indent_delta;
802 rasqal_rowsource_write_indent(iostr, indent);
803
804
805 for(offset = 0;
806 (inner_rowsource = rasqal_rowsource_get_inner_rowsource(rowsource, offset));
807 offset++) {
808 if(arg_count) {
809 raptor_iostream_counted_string_write(" ,\n", 3, iostr);
810 rasqal_rowsource_write_indent(iostr, indent);
811 }
812 rasqal_rowsource_write_internal(inner_rowsource, iostr, indent);
813 arg_count++;
814 }
815
816 raptor_iostream_write_byte('\n', iostr);
817 indent-= indent_delta;
818
819 rasqal_rowsource_write_indent(iostr, indent);
820 raptor_iostream_write_byte(')', iostr);
821
822 return 0;
823 }
824
825
826 int
rasqal_rowsource_write(rasqal_rowsource * rowsource,raptor_iostream * iostr)827 rasqal_rowsource_write(rasqal_rowsource *rowsource, raptor_iostream *iostr)
828 {
829 return rasqal_rowsource_write_internal(rowsource, iostr, 0);
830 }
831
832
833 /**
834 * rasqal_rowsource_print:
835 * @rs: the #rasqal_rowsource object
836 * @fh: the FILE* handle to print to
837 *
838 * Print a #rasqal_rowsource in a debug format.
839 *
840 * The print debug format may change in any release.
841 *
842 **/
843 void
rasqal_rowsource_print(rasqal_rowsource * rowsource,FILE * fh)844 rasqal_rowsource_print(rasqal_rowsource *rowsource, FILE* fh)
845 {
846 raptor_iostream *iostr;
847
848 if(!rowsource || !fh)
849 return;
850
851 iostr = raptor_new_iostream_to_file_handle(rowsource->world->raptor_world_ptr, fh);
852 rasqal_rowsource_write(rowsource, iostr);
853 raptor_free_iostream(iostr);
854 }
855
856
857 /*
858 * rasqal_rowsource_remove_all_variables:
859 * @rowsource: rasqal rowsource
860 *
861 * INTERNAL - Remove all variables from a rowsource
862 */
863 void
rasqal_rowsource_remove_all_variables(rasqal_rowsource * rowsource)864 rasqal_rowsource_remove_all_variables(rasqal_rowsource *rowsource)
865 {
866 while(1) {
867 rasqal_variable* v;
868 v = (rasqal_variable*)raptor_sequence_pop(rowsource->variables_sequence);
869 if(!v)
870 break;
871 rasqal_free_variable(v);
872 }
873 rowsource->size = 0;
874 }
875
876 #endif /* not STANDALONE */
877
878
879
880 #ifdef STANDALONE
881
882 /* one more prototype */
883 int main(int argc, char *argv[]);
884
885
886 #define IN_FILENAME "in.bin"
887 #define OUT_BYTES_COUNT 14
888
889
890 int
main(int argc,char * argv[])891 main(int argc, char *argv[])
892 {
893 const char *program = rasqal_basename(argv[0]);
894 #define TEST_ITEMS_COUNT 9
895 int i;
896
897 for(i = 0; i < 4; i++) {
898 rasqal_rowsource *rowsource;
899 int count;
900
901 /* for _from_file */
902 FILE *handle = NULL;
903 /* for _from_string */
904 void *string;
905 size_t string_len;
906
907 switch(i) {
908 case 0:
909 #ifdef RASQAL_DEBUG
910 fprintf(stderr, "%s: Creating rowsource from a filename '%s'\n",
911 program, OUT_FILENAME);
912 #endif
913 rowsource = rasqal_new_rowsource_from_filename(RASQAL_GOOD_CAST(const char*, IN_FILENAME));
914 if(!rowsource) {
915 fprintf(stderr, "%s: Failed to create rowsource to filename '%s'\n",
916 program, OUT_FILENAME);
917 exit(1);
918 }
919 break;
920
921 case 1:
922 #ifdef RASQAL_DEBUG
923 fprintf(stderr, "%s: Creating rowsource from file handle\n", program);
924 #endif
925 handle = fopen(RASQAL_GOOD_CAST(const char*, OUT_FILENAME), "wb");
926 rowsource = rasqal_new_rowsource_from_file_handle(handle);
927 if(!rowsource) {
928 fprintf(stderr, "%s: Failed to create rowsource from a file handle\n", program);
929 exit(1);
930 }
931 break;
932
933 case 2:
934 #ifdef RASQAL_DEBUG
935 fprintf(stderr, "%s: Creating rowsource from a string\n", program);
936 #endif
937 rowsource = rasqal_new_rowsource_from_string(&string, &string_len, NULL);
938 if(!rowsource) {
939 fprintf(stderr, "%s: Failed to create rowsource from a string\n", program);
940 exit(1);
941 }
942 break;
943
944 case 3:
945 #ifdef RASQAL_DEBUG
946 fprintf(stderr, "%s: Creating rowsource from a sink\n", program);
947 #endif
948 rowsource = rasqal_new_rowsource_from_sink();
949 if(!rowsource) {
950 fprintf(stderr, "%s: Failed to create rowsource from a sink\n", program);
951 exit(1);
952 }
953 break;
954
955 default:
956 fprintf(stderr, "%s: Unknown test case %d init\n", program, i);
957 exit(1);
958 }
959
960
961 count = rasqal_rowsource_get_rows_count(rowsource);
962 if(count != OUT_BYTES_COUNT) {
963 fprintf(stderr, "%s: I/O stream wrote %d bytes, expected %d\n", program,
964 count, RASQAL_GOOD_CAST(int, OUT_BYTES_COUNT));
965 return 1;
966 }
967
968 #ifdef RASQAL_DEBUG
969 fprintf(stderr, "%s: Freeing rowsource\n", program);
970 #endif
971 rasqal_free_rowsource(rowsource);
972
973 switch(i) {
974 case 0:
975 remove(OUT_FILENAME);
976 break;
977
978 case 1:
979 fclose(handle);
980 remove(OUT_FILENAME);
981 break;
982
983 case 2:
984 if(!string) {
985 fprintf(stderr, "%s: I/O stream failed to create a string\n", program);
986 return 1;
987 }
988 if(string_len != count) {
989 fprintf(stderr, "%s: I/O stream created a string length %d, expected %d\n", program, RASQAL_BAD_CAST(int, string_len), count);
990 return 1;
991 }
992 rasqal_free_memory(string);
993 break;
994
995 case 3:
996 break;
997
998 default:
999 fprintf(stderr, "%s: Unknown test case %d tidy\n", program, i);
1000 exit(1);
1001 }
1002
1003 }
1004
1005 /* keep gcc -Wall happy */
1006 return(0);
1007 }
1008
1009 #endif /* STANDALONE */
1010