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