1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * rasqal_bindings.c - Rasqal result bindings class
4  *
5  * Copyright (C) 2010-2013, 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 "rasqal.h"
40 #include "rasqal_internal.h"
41 
42 
43 /*
44  * rasqal_new_bindings:
45  * @query: rasqal query
46  * @variables: sequence of variables
47  * @rows: sequence of #rasqal_row (or NULL)
48  *
49  * INTERNAL - Create a new bindings object.
50  *
51  * The @variables and @rows become owned by the bindings object.
52  *
53  * Return value: a new #rasqal_bindings object or NULL on failure
54  **/
55 rasqal_bindings*
rasqal_new_bindings(rasqal_query * query,raptor_sequence * variables,raptor_sequence * rows)56 rasqal_new_bindings(rasqal_query* query,
57                     raptor_sequence* variables,
58                     raptor_sequence* rows)
59 {
60   rasqal_bindings* bindings;
61 
62   RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
63   RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(variables, raptor_sequence, NULL);
64 
65   bindings = RASQAL_CALLOC(rasqal_bindings*, 1, sizeof(*bindings));
66   if(!bindings)
67     return NULL;
68 
69   bindings->usage = 1;
70   bindings->query = query;
71   bindings->variables = variables;
72   bindings->rows = rows;
73 
74   return bindings;
75 }
76 
77 
78 
79 /*
80  * rasqal_new_bindings_from_bindings:
81  * @bindings: #rasqal_bindings to copy
82  *
83  * INTERNAL - Copy Constructor - Create a new Rasqal bindings from an existing one
84  *
85  * This adds a new reference to the bindings, it does not do a deep copy
86  *
87  * Return value: a new #rasqal_bindings or NULL on failure.
88  **/
89 rasqal_bindings*
rasqal_new_bindings_from_bindings(rasqal_bindings * bindings)90 rasqal_new_bindings_from_bindings(rasqal_bindings* bindings)
91 {
92   if(!bindings)
93     return NULL;
94 
95   bindings->usage++;
96 
97   return bindings;
98 }
99 
100 
101 /*
102  * rasqal_new_bindings_from_var_values:
103  * @query: rasqal query
104  * @var: variable
105  * @values: sequence of #rasqal_value (or NULL)
106  *
107  * INTERNAL - Create a new bindings object for one variable with multiple bindings
108  *
109  * The @var and @values become owned by the bindings object.
110  *
111  * Return value: a new #rasqal_bindings object or NULL on failure
112  **/
113 rasqal_bindings*
rasqal_new_bindings_from_var_values(rasqal_query * query,rasqal_variable * var,raptor_sequence * values)114 rasqal_new_bindings_from_var_values(rasqal_query* query,
115                                     rasqal_variable* var,
116                                     raptor_sequence* values)
117 {
118   rasqal_bindings* bindings = NULL;
119   raptor_sequence* varlist = NULL;
120   rasqal_row* row = NULL;
121   raptor_sequence* rowlist = NULL;
122   int size = 0;
123   int i;
124 
125 
126   RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, NULL);
127   RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(var, rasqal_variable, NULL);
128 
129 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
130   RASQAL_DEBUG1("binding ");
131   rasqal_variable_print(var, stderr);
132   fputs(" and row values ", stderr);
133   raptor_sequence_print(values, stderr);
134   fputc('\n', stderr);
135 #endif
136 
137   varlist = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
138                                 (raptor_data_print_handler)rasqal_variable_print);
139   if(!varlist) {
140     RASQAL_DEBUG1("Cannot create varlist sequence");
141     goto tidy;
142   }
143 
144   if(raptor_sequence_push(varlist, var)) {
145     RASQAL_DEBUG1("varlist sequence push failed");
146     goto tidy;
147   }
148   var = NULL;
149 
150   if(values)
151     size = raptor_sequence_size(values);
152 
153   row = rasqal_new_row_for_size(query->world, size);
154   if(!row) {
155     RASQAL_DEBUG1("cannot create row");
156     goto tidy;
157   }
158 
159   for(i = 0; i < size; i++) {
160     rasqal_literal* value = (rasqal_literal*)raptor_sequence_get_at(values, i);
161     rasqal_row_set_value_at(row, i, value);
162   }
163 
164   rowlist = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row,
165                                 (raptor_data_print_handler)rasqal_row_print);
166   if(!rowlist) {
167     RASQAL_DEBUG1("cannot create rowlist sequence");
168     goto tidy;
169   }
170 
171   if(raptor_sequence_push(rowlist, row)) {
172     RASQAL_DEBUG1("rowlist sequence push failed");
173     goto tidy;
174   }
175   row = NULL;
176 
177   bindings = rasqal_new_bindings(query, varlist, rowlist);
178   varlist = NULL; rowlist = NULL;
179 
180 tidy:
181   if(row)
182     rasqal_free_row(row);
183   if(rowlist)
184     raptor_free_sequence(rowlist);
185   if(varlist)
186     raptor_free_sequence(varlist);
187   if(var)
188     rasqal_free_variable(var);
189   if(values)
190     raptor_free_sequence(values);
191 
192   return bindings;
193 }
194 
195 
196 /*
197  * rasqal_free_bindings:
198  * @bindings: #rasqal_bindings object
199  *
200  * INTERNAL - Free a bindings object.
201  *
202  **/
203 void
rasqal_free_bindings(rasqal_bindings * bindings)204 rasqal_free_bindings(rasqal_bindings* bindings)
205 {
206   if(!bindings)
207     return;
208 
209   if(--bindings->usage)
210     return;
211 
212   raptor_free_sequence(bindings->variables);
213   if(bindings->rows)
214     raptor_free_sequence(bindings->rows);
215 
216   RASQAL_FREE(rasqal_bindings, bindings);
217 }
218 
219 
220 /*
221  * rasqal_bindings_print:
222  * @bindings: the #rasqal_bindings object
223  * @fh: the FILE* handle to print to
224  *
225  * INTERNAL - Print a #rasqal_bindings in a debug format.
226  *
227  * The print debug format may change in any release.
228  *
229  * Return value: non-0 on failure
230  **/
231 int
rasqal_bindings_print(rasqal_bindings * bindings,FILE * fh)232 rasqal_bindings_print(rasqal_bindings* bindings, FILE* fh)
233 {
234   int i;
235 
236   RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(bindings, rasqal_bindings, 1);
237   RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(fh, FILE*, 1);
238 
239   fputs("\n  variables: ", fh);
240   raptor_sequence_print(bindings->variables, fh);
241   fputs("\n  rows: [\n    ", fh);
242 
243   if(bindings->rows) {
244     for(i = 0; i < raptor_sequence_size(bindings->rows); i++) {
245       rasqal_row* row;
246       row = (rasqal_row*)raptor_sequence_get_at(bindings->rows, i);
247       if(i > 0)
248         fputs("\n    ", fh);
249       rasqal_row_print(row, fh);
250     }
251   }
252   fputs("\n  ]\n", fh);
253 
254   return 0;
255 }
256 
257 /*
258  * rasqal_bindings_get_row:
259  * @bindings: the #rasqal_bindings object
260  * @offset: row offset into bindings (0+)
261  *
262  * INTERNAL - get a row from a binding at the given offset
263  *
264  * Return value: new row or NULL if out of range
265  */
266 rasqal_row*
rasqal_bindings_get_row(rasqal_bindings * bindings,int offset)267 rasqal_bindings_get_row(rasqal_bindings* bindings, int offset)
268 {
269   rasqal_row* row = NULL;
270 
271   if(bindings->rows) {
272     row = (rasqal_row*)raptor_sequence_get_at(bindings->rows, offset);
273     if(row)
274       row = rasqal_new_row_from_row(row);
275   }
276 
277   return row;
278 }
279