1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * rasqal_row.c - Rasqal Query Result Row
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 
44 
45 
46 static rasqal_row*
rasqal_new_row_common(rasqal_world * world,int size,int order_size)47 rasqal_new_row_common(rasqal_world* world, int size, int order_size)
48 {
49   rasqal_row* row;
50 
51   row = RASQAL_CALLOC(rasqal_row*, 1, sizeof(*row));
52   if(!row)
53     return NULL;
54 
55   row->usage = 1;
56   row->size = size;
57   row->order_size = order_size;
58 
59   if(row->size > 0) {
60     row->values = RASQAL_CALLOC(rasqal_literal**, RASQAL_GOOD_CAST(size_t, row->size),
61                                 sizeof(rasqal_literal*));
62     if(!row->values) {
63       rasqal_free_row(row);
64       return NULL;
65     }
66   }
67 
68   if(row->order_size > 0) {
69     row->order_values = RASQAL_CALLOC(rasqal_literal**, RASQAL_GOOD_CAST(size_t, row->order_size),
70                                       sizeof(rasqal_literal*));
71     if(!row->order_values) {
72       rasqal_free_row(row);
73       return NULL;
74     }
75   }
76 
77   row->group_id = -1;
78 
79   return row;
80 }
81 
82 
83 /**
84  * rasqal_new_row:
85  * @rowsource: rowsource
86  *
87  * INTERNAL - Create a new query result row at an offset into the result sequence.
88  *
89  * Return value: a new query result row or NULL on failure
90  */
91 rasqal_row*
rasqal_new_row(rasqal_rowsource * rowsource)92 rasqal_new_row(rasqal_rowsource* rowsource)
93 {
94   int size;
95   int order_size = -1;
96   rasqal_row* row;
97 
98   if(!rowsource)
99     return NULL;
100 
101   rowsource = rasqal_new_rowsource_from_rowsource(rowsource);
102 
103   size = rasqal_rowsource_get_size(rowsource);
104 
105   row = rasqal_new_row_common(rowsource->world, size, order_size);
106   if(row)
107     row->rowsource = rowsource;
108 
109   return row;
110 }
111 
112 
113 /**
114  * rasqal_new_row_for_size:
115  * @world: rasqal_world
116  * @size: width of row
117  *
118  * Constructor - Create a new query result row of a given size
119  *
120  * Return value: a new query result row or NULL on failure
121  */
122 rasqal_row*
rasqal_new_row_for_size(rasqal_world * world,int size)123 rasqal_new_row_for_size(rasqal_world* world, int size)
124 {
125   int order_size = 0;
126 
127   return rasqal_new_row_common(world, size, order_size);
128 }
129 
130 
131 /**
132  * rasqal_new_row_from_row:
133  * @row: query result row
134  *
135  * INTERNAL - Copy a query result row.
136  *
137  * Return value: a copy of the query result row or NULL
138  */
139 rasqal_row*
rasqal_new_row_from_row(rasqal_row * row)140 rasqal_new_row_from_row(rasqal_row* row)
141 {
142   row->usage++;
143   return row;
144 }
145 
146 
147 /**
148  * rasqal_free_row:
149  * @row: query result row
150  *
151  * Destructor - Free a query result row object.
152  */
153 void
rasqal_free_row(rasqal_row * row)154 rasqal_free_row(rasqal_row* row)
155 {
156   if(!row)
157     return;
158 
159   if(--row->usage)
160     return;
161 
162   if(row->values) {
163     int i;
164     for(i = 0; i < row->size; i++) {
165       if(row->values[i])
166         rasqal_free_literal(row->values[i]);
167     }
168     RASQAL_FREE(array, row->values);
169   }
170   if(row->order_values) {
171     int i;
172     for(i = 0; i < row->order_size; i++) {
173       if(row->order_values[i])
174         rasqal_free_literal(row->order_values[i]);
175     }
176     RASQAL_FREE(array, row->order_values);
177   }
178 
179   if(row->rowsource)
180     rasqal_free_rowsource(row->rowsource);
181 
182   RASQAL_FREE(rasqal_row, row);
183 }
184 
185 
186 /**
187  * rasqal_row_print:
188  * @row: query result row
189  * @fp: FILE* handle
190  *
191  * INTERNAL - Print a query result row.
192  */
193 int
rasqal_row_print(rasqal_row * row,FILE * fh)194 rasqal_row_print(rasqal_row* row, FILE* fh)
195 {
196   rasqal_rowsource* rowsource = row->rowsource;
197   int i;
198 
199   fputs("row[", fh);
200   for(i = 0; i < row->size; i++) {
201     /* Do not use rasqal_query_results_get_binding_name(row->results, i);
202      * as it does not work for a construct result
203      */
204     const unsigned char *name = NULL;
205     rasqal_literal *value;
206 
207     if(rowsource) {
208       rasqal_variable* v;
209       v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
210       if(v)
211         name = v->name;
212     }
213 
214     value = row->values[i];
215     if(i > 0)
216       fputs(", ", fh);
217     if(name)
218       fprintf(fh, "%s=", name);
219 
220     rasqal_literal_print(value, fh);
221   }
222 
223   if(row->order_size > 0) {
224     fputs(" with ordering values [", fh);
225 
226     for(i = 0; i < row->order_size; i++) {
227       rasqal_literal *value = row->order_values[i];
228 
229       if(i > 0)
230         fputs(", ", fh);
231       rasqal_literal_print(value, fh);
232     }
233     fputs("]", fh);
234 
235   }
236 
237   if(row->group_id >= 0)
238     fprintf(fh, " group %d", row->group_id);
239 
240   fprintf(fh, " offset %d]", row->offset);
241 
242   return 0;
243 }
244 
245 
246 /*
247  * rasqal_row_write:
248  * @row: query result row
249  * @iostr: raptor iostream
250  *
251  * INTERNAL - Write a query result row to an iostream.
252  *
253  * Return value: non-0 on failure
254  */
255 int
rasqal_row_write(rasqal_row * row,raptor_iostream * iostr)256 rasqal_row_write(rasqal_row* row, raptor_iostream* iostr)
257 {
258   rasqal_rowsource* rowsource;
259   int i;
260 
261   if(!row || !iostr)
262     return 1;
263 
264   rowsource = row->rowsource;
265   raptor_iostream_counted_string_write("row[", 4, iostr);
266   for(i = 0; i < row->size; i++) {
267     /* Do not use rasqal_query_results_get_binding_name(row->results, i);
268      * as it does not work for a construct result
269      */
270     const unsigned char *name = NULL;
271     rasqal_literal *value;
272 
273     if(rowsource) {
274       rasqal_variable* v;
275       v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
276       if(v)
277         name = v->name;
278     }
279 
280     value = row->values[i];
281     if(i > 0)
282       raptor_iostream_counted_string_write(", ", 2, iostr);
283     if(name) {
284       raptor_iostream_string_write(name, iostr);
285       raptor_iostream_counted_string_write("=", 1, iostr);
286     }
287 
288     rasqal_literal_write(value, iostr);
289   }
290 
291   if(row->order_size > 0) {
292     raptor_iostream_counted_string_write(" with ordering values [", 23, iostr);
293 
294     for(i = 0; i < row->order_size; i++) {
295       rasqal_literal *value = row->order_values[i];
296 
297       if(i > 0)
298         raptor_iostream_counted_string_write(", ", 2, iostr);
299       rasqal_literal_write(value, iostr);
300     }
301     raptor_iostream_counted_string_write("]", 1, iostr);
302 
303   }
304 
305   if(row->group_id >= 0) {
306     raptor_iostream_counted_string_write(" group ", 7, iostr);
307     raptor_iostream_decimal_write(row->group_id, iostr);
308   }
309 
310   raptor_iostream_counted_string_write(" offset ", 8, iostr);
311   raptor_iostream_decimal_write(row->offset, iostr);
312   raptor_iostream_counted_string_write("]", 1, iostr);
313 
314   return 0;
315 }
316 
317 
318 /**
319  * rasqal_row_set_value_at:
320  * @row: query result row
321  * @offset: offset into row (column number)
322  * @value: literal value to set
323  *
324  * Set the value of a variable in a query result row
325  *
326  * Any existing row value is freed and the literal @value passed in
327  * is copied.
328  *
329  * Return value: non-0 on failure
330  */
331 int
rasqal_row_set_value_at(rasqal_row * row,int offset,rasqal_literal * value)332 rasqal_row_set_value_at(rasqal_row* row, int offset, rasqal_literal* value)
333 {
334   if(!row || !value)
335     return 1;
336 
337   if(offset < 0 || offset >= row->size)
338     return 1;
339 
340   if(row->values[offset])
341     rasqal_free_literal(row->values[offset]);
342 
343   row->values[offset] = rasqal_new_literal_from_literal(value);
344 
345   return 0;
346 }
347 
348 
349 /**
350  * rasqal_new_row_sequence:
351  * @world: world object ot use
352  * @vt: variables table to use to declare variables
353  * @row_data: row data
354  * @vars_count: number of variables in row
355  * @vars_seq_p: OUT parameter - pointer to place to store sequence of variables (or NULL)
356  *
357  * INTERNAL - Make a sequence of #rasqal_row* objects
358  * with variables defined into the @vt table and values in the sequence
359  *
360  * The @row_data parameter is an array of strings forming a table of
361  * width (vars_count * 2).
362  * The first row is a list of variable names at offset 0.
363  * The remaining rows are values where offset 0 is a literal and
364  * offset 1 is a URI string.
365  *
366  * The last row is indicated by an entire row of NULLs.
367  *
368  * Return value: sequence of rows or NULL on failure
369  */
370 raptor_sequence*
rasqal_new_row_sequence(rasqal_world * world,rasqal_variables_table * vt,const char * const row_data[],int vars_count,raptor_sequence ** vars_seq_p)371 rasqal_new_row_sequence(rasqal_world* world,
372                         rasqal_variables_table* vt,
373                         const char* const row_data[],
374                         int vars_count,
375                         raptor_sequence** vars_seq_p)
376 {
377   raptor_sequence *seq = NULL;
378   raptor_sequence *vars_seq = NULL;
379   int row_i;
380   int column_i;
381   int failed = 0;
382 
383 #define GET_CELL(row, column, offset) \
384   row_data[((((row)*vars_count)+(column))<<1)+(offset)]
385 
386   seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row,
387                             (raptor_data_print_handler)rasqal_row_print);
388   if(!seq)
389     return NULL;
390 
391   if(vars_seq_p) {
392     vars_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
393                                    (raptor_data_print_handler)rasqal_variable_print);
394     if(!vars_seq) {
395       raptor_free_sequence(seq);
396       return NULL;
397     }
398   }
399 
400   /* row 0 is variables */
401   row_i = 0;
402 
403   for(column_i = 0; column_i < vars_count; column_i++) {
404     const char * var_name = GET_CELL(row_i, column_i, 0);
405     size_t var_name_len = strlen(var_name);
406     rasqal_variable* v;
407 
408     v = rasqal_variables_table_add2(vt, RASQAL_VARIABLE_TYPE_NORMAL,
409                                     RASQAL_GOOD_CAST(const unsigned char*, var_name),
410                                     var_name_len, NULL);
411     if(!v) {
412       failed = 1;
413       goto tidy;
414     }
415 
416     if(vars_seq) {
417       raptor_sequence_push(vars_seq, v);
418       /* v is now owned by vars_seq */
419     }
420   }
421 
422   for(row_i = 1; 1; row_i++) {
423     rasqal_row* row;
424     int data_values_seen = 0;
425 
426     /* Terminate on an entire row of NULLs */
427     for(column_i = 0; column_i < vars_count; column_i++) {
428       if(GET_CELL(row_i, column_i, 0) || GET_CELL(row_i, column_i, 1)) {
429         data_values_seen++;
430         break;
431       }
432     }
433     if(!data_values_seen)
434       break;
435 
436     row = rasqal_new_row_for_size(world, vars_count);
437     if(!row) {
438       failed = 1;
439       goto tidy;
440     }
441 
442     for(column_i = 0; column_i < vars_count; column_i++) {
443       rasqal_literal* l = NULL;
444 
445       if(GET_CELL(row_i, column_i, 0)) {
446         /* string literal */
447         const char* str = GET_CELL(row_i, column_i, 0);
448         size_t str_len = strlen(str);
449         char *eptr = NULL;
450         long number;
451 
452         number = strtol(RASQAL_GOOD_CAST(const char*, str), &eptr, 10);
453         if(!*eptr) {
454           /* is an integer */
455           l = rasqal_new_numeric_literal_from_long(world,
456                                                    RASQAL_LITERAL_INTEGER,
457                                                    number);
458         } else {
459           unsigned char *val;
460           val = RASQAL_MALLOC(unsigned char*, str_len + 1);
461           if(val) {
462             memcpy(val, str, str_len + 1);
463 
464             l = rasqal_new_string_literal_node(world, val, NULL, NULL);
465           } else
466             failed = 1;
467         }
468       } else if(GET_CELL(row_i, column_i, 1)) {
469         /* URI */
470         const unsigned char* str;
471         raptor_uri* u;
472         str = RASQAL_GOOD_CAST(const unsigned char*, GET_CELL(row_i, column_i, 1));
473         u = raptor_new_uri(world->raptor_world_ptr, str);
474         if(u)
475           l = rasqal_new_uri_literal(world, u);
476         else
477           failed = 1;
478       } else {
479         /* variable is not defined for this row */
480         continue;
481       }
482 
483       if(!l) {
484         rasqal_free_row(row);
485         failed = 1;
486         goto tidy;
487       }
488       rasqal_row_set_value_at(row, column_i, l);
489       /* free our copy of literal, rasqal_row has a reference */
490       rasqal_free_literal(l);
491     }
492 
493     raptor_sequence_push(seq, row);
494   }
495 
496   tidy:
497   if(failed) {
498     if(seq) {
499       raptor_free_sequence(seq);
500       seq = NULL;
501     }
502     if(vars_seq) {
503       raptor_free_sequence(vars_seq);
504       vars_seq = NULL;
505     }
506   } else {
507     if(vars_seq)
508       *vars_seq_p = vars_seq;
509   }
510 
511   return seq;
512 }
513 
514 
515 /**
516  * rasqal_row_to_nodes:
517  * @row: Result row
518  *
519  * INTERNAL - Turn the given result row literals into RDF strings, URIs or blank literals.
520  *
521  * Return value: non-0 on failure
522  */
523 int
rasqal_row_to_nodes(rasqal_row * row)524 rasqal_row_to_nodes(rasqal_row* row)
525 {
526   int i;
527 
528   if(!row)
529     return 1;
530 
531   for(i = 0; i < row->size; i++) {
532     if(row->values[i]) {
533       rasqal_literal* new_l;
534       new_l = rasqal_literal_as_node(row->values[i]);
535       if(!new_l)
536         return -1;
537       rasqal_free_literal(row->values[i]);
538       row->values[i] = new_l;
539     }
540   }
541 
542   return 0;
543 }
544 
545 
546 /**
547  * rasqal_row_set_values_from_variables_table:
548  * @row: Result row
549  * @vars_table: Variables table
550  *
551  * INTERNAL - Set the values of all variables in the row from the given variables table
552  *
553  */
554 void
rasqal_row_set_values_from_variables_table(rasqal_row * row,rasqal_variables_table * vars_table)555 rasqal_row_set_values_from_variables_table(rasqal_row* row,
556                                            rasqal_variables_table* vars_table)
557 {
558   int i;
559 
560   for(i = 0; i < row->size; i++) {
561     rasqal_literal *l;
562     l = rasqal_variables_table_get_value(vars_table, i);
563     if(row->values[i])
564       rasqal_free_literal(row->values[i]);
565     row->values[i] = rasqal_new_literal_from_literal(l);
566   }
567 }
568 
569 
570 /**
571  * rasqal_row_set_order_size:
572  * @row: Result row
573  * @order_size: number of order conditions
574  *
575  * INTERNAL - Initialise the row with space to handle @order_size order conditions being evaluated
576  *
577  * Return value: non-0 on failure
578  */
579 int
rasqal_row_set_order_size(rasqal_row * row,int order_size)580 rasqal_row_set_order_size(rasqal_row *row, int order_size)
581 {
582   row->order_size = order_size;
583   if(row->order_size > 0) {
584     row->order_values = RASQAL_CALLOC(rasqal_literal**, RASQAL_GOOD_CAST(size_t, row->order_size),
585                                       sizeof(rasqal_literal*));
586     if(!row->order_values) {
587       row->order_size = -1;
588       return 1;
589     }
590   }
591 
592   return 0;
593 }
594 
595 
596 /**
597  * rasqal_row_expand_size:
598  * @row: Result row
599  * @size: number of variables
600  *
601  * INTERNAL - Expand the row to be able to handle @size variables
602  *
603  * Return value: non-0 on failure
604  */
605 int
rasqal_row_expand_size(rasqal_row * row,int size)606 rasqal_row_expand_size(rasqal_row *row, int size)
607 {
608   rasqal_literal** nvalues;
609 
610   /* do not allow row size to contract & lose data */
611   if(row->size > size)
612     return 1;
613 
614   nvalues = RASQAL_CALLOC(rasqal_literal**, RASQAL_GOOD_CAST(size_t, size), sizeof(rasqal_literal*));
615   if(!nvalues)
616     return 1;
617   memcpy(nvalues, row->values, RASQAL_GOOD_CAST(size_t, sizeof(rasqal_literal*) * RASQAL_GOOD_CAST(size_t, row->size)));
618   RASQAL_FREE(array, row->values);
619   row->values = nvalues;
620 
621   row->size = size;
622   return 0;
623 }
624 
625 
626 
627 /**
628  * rasqal_row_bind_variables:
629  * @row: Result row
630  * @vars_table: Variables table
631  *
632  * INTERNAL - Bind the variable table vars with values in the row
633  *
634  * Return value: non-0 on failure
635  */
636 int
rasqal_row_bind_variables(rasqal_row * row,rasqal_variables_table * vars_table)637 rasqal_row_bind_variables(rasqal_row* row,
638                           rasqal_variables_table* vars_table)
639 {
640   int i;
641 
642   for(i = 0; i < row->size; i++) {
643     rasqal_variable* v;
644 
645     v = rasqal_rowsource_get_variable_by_offset(row->rowsource, i);
646     if(v) {
647       rasqal_literal *value = row->values[i];
648       if(value) {
649         value = rasqal_new_literal_from_literal(value);
650         if(!value)
651           return 1;
652       }
653 
654       /* it is OK to bind to NULL */
655       rasqal_variable_set_value(v, value);
656     }
657   }
658 
659   return 0;
660 }
661 
662 
663 /**
664  * rasqal_row_sequence_copy:
665  * @row_sequence: sequence of #raptor_row
666  *
667  * INTERNAL - Deep copy a sequence of rows
668  *
669  * Return value: new sequence of all rows (may be size 0) or NULL on failure
670  **/
671 raptor_sequence*
rasqal_row_sequence_copy(raptor_sequence * seq)672 rasqal_row_sequence_copy(raptor_sequence *seq)
673 {
674   raptor_sequence* new_seq;
675   int i;
676   rasqal_row* row;
677 
678   new_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row,
679                                 (raptor_data_print_handler)rasqal_row_print);
680   if(!new_seq)
681     return NULL;
682 
683   for(i = 0; (row = (rasqal_row*)raptor_sequence_get_at(seq, i)); i++) {
684     row = rasqal_new_row_from_row(row);
685 
686     raptor_sequence_push(new_seq, row);
687   }
688 
689   return new_seq;
690 }
691 
692 
693 void
rasqal_row_set_rowsource(rasqal_row * row,rasqal_rowsource * rowsource)694 rasqal_row_set_rowsource(rasqal_row* row, rasqal_rowsource* rowsource)
695 {
696   if(!(row->flags & RASQAL_ROW_FLAG_WEAK_ROWSOURCE) && row->rowsource)
697     rasqal_free_rowsource(row->rowsource);
698 
699   row->rowsource = rasqal_new_rowsource_from_rowsource(rowsource);
700   row->flags = RASQAL_GOOD_CAST(unsigned int, RASQAL_GOOD_CAST(int, row->flags) & ~RASQAL_ROW_FLAG_WEAK_ROWSOURCE);
701 }
702 
703 /* Set/reset a row's rowsource to a weak reference; one that should
704  * NOT be freed.
705  *
706  *  *DANGEROUS* : should only be used by the rasqal_rowsequence_rowsource class
707  */
708 void
rasqal_row_set_weak_rowsource(rasqal_row * row,rasqal_rowsource * rowsource)709 rasqal_row_set_weak_rowsource(rasqal_row* row, rasqal_rowsource* rowsource)
710 {
711   row->rowsource = rowsource;
712   row->flags |= RASQAL_ROW_FLAG_WEAK_ROWSOURCE;
713 }
714 
715 rasqal_variable*
rasqal_row_get_variable_by_offset(rasqal_row * row,int offset)716 rasqal_row_get_variable_by_offset(rasqal_row* row, int offset)
717 {
718   if(offset < 0)
719     return NULL;
720 
721   return rasqal_rowsource_get_variable_by_offset(row->rowsource, offset);
722 }
723