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