1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * rasqal_rowsource_service.c - Rasqal SERVICE rowsource class
4  *
5  * Copyright (C) 2011, 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 
38 #include <raptor.h>
39 
40 #include "rasqal.h"
41 #include "rasqal_internal.h"
42 
43 
44 #ifndef STANDALONE
45 
46 typedef struct
47 {
48   rasqal_service* svc;
49   rasqal_query* query;
50   rasqal_rowsource* rowsource;
51   int count;
52   /* bit flags; currently using RASQAL_ENGINE_BITFLAG_SILENT */
53   unsigned int flags;
54 } rasqal_service_rowsource_context;
55 
56 
57 static int
rasqal_service_rowsource_init(rasqal_rowsource * rowsource,void * user_data)58 rasqal_service_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
59 {
60   rasqal_service_rowsource_context* con;
61 
62   con = (rasqal_service_rowsource_context*)user_data;
63 
64   con->rowsource = rasqal_service_execute_as_rowsource(con->svc,
65                                                        con->query->vars_table);
66 
67   if(!con->rowsource) {
68     /* Silent errors return an empty rowsource */
69 
70     if(con->flags & RASQAL_ENGINE_BITFLAG_SILENT) {
71       con->rowsource = rasqal_new_empty_rowsource(con->query->world,
72                                                   con->query);
73       return 0;
74     }
75 
76     return 1;
77   }
78 
79   return 0;
80 }
81 
82 
83 static int
rasqal_service_rowsource_finish(rasqal_rowsource * rowsource,void * user_data)84 rasqal_service_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
85 {
86   rasqal_service_rowsource_context* con;
87 
88   con = (rasqal_service_rowsource_context*)user_data;
89 
90   if(con->svc)
91     rasqal_free_service(con->svc);
92 
93   if(con->rowsource)
94     rasqal_free_rowsource(con->rowsource);
95 
96   RASQAL_FREE(rasqal_service_rowsource_context, con);
97 
98   return 0;
99 }
100 
101 static int
rasqal_service_rowsource_ensure_variables(rasqal_rowsource * rowsource,void * user_data)102 rasqal_service_rowsource_ensure_variables(rasqal_rowsource* rowsource,
103                                           void *user_data)
104 {
105   rasqal_service_rowsource_context* con;
106   int rc;
107 
108   con = (rasqal_service_rowsource_context*)user_data;
109 
110   rc = rasqal_rowsource_ensure_variables(con->rowsource);
111   if(rc)
112     return rc;
113   /* copy in variables from format rowsource */
114   rc = rasqal_rowsource_copy_variables(rowsource, con->rowsource);
115 
116   return rc;
117 }
118 
119 static rasqal_row*
rasqal_service_rowsource_read_row(rasqal_rowsource * rowsource,void * user_data)120 rasqal_service_rowsource_read_row(rasqal_rowsource* rowsource, void *user_data)
121 {
122   rasqal_service_rowsource_context* con;
123 
124   con = (rasqal_service_rowsource_context*)user_data;
125 
126   return rasqal_rowsource_read_row(con->rowsource);
127 }
128 
129 static raptor_sequence*
rasqal_service_rowsource_read_all_rows(rasqal_rowsource * rowsource,void * user_data)130 rasqal_service_rowsource_read_all_rows(rasqal_rowsource* rowsource,
131                                        void *user_data)
132 {
133   rasqal_service_rowsource_context* con;
134 
135   con = (rasqal_service_rowsource_context*)user_data;
136 
137   return rasqal_rowsource_read_all_rows(con->rowsource);
138 }
139 
140 static const rasqal_rowsource_handler rasqal_service_rowsource_handler = {
141   /* .version = */ 1,
142   "service",
143   /* .init = */ rasqal_service_rowsource_init,
144   /* .finish = */ rasqal_service_rowsource_finish,
145   /* .ensure_variables = */ rasqal_service_rowsource_ensure_variables,
146   /* .read_row = */ rasqal_service_rowsource_read_row,
147   /* .read_all_rows = */ rasqal_service_rowsource_read_all_rows,
148   /* .reset = */ NULL,
149   /* .set_preserve = */ NULL,
150   /* .get_inner_rowsource = */ NULL,
151   /* .set_origin = */ NULL,
152 };
153 
154 
155 /**
156  * rasqal_new_service_rowsource:
157  * @world: world object
158  * @query: query object
159  * @service_uri: service URI
160  * @query_string: query to send to service
161  * @data_graphs: sequence of data graphs (or NULL)
162  * @rs_flags: service rowsource flags
163  *
164  * INTERNAL - create a new rowsource that takes rows from a service
165  *
166  * All arguments are copied.
167  *
168  * Return value: new rowsource or NULL on failure
169  */
170 rasqal_rowsource*
rasqal_new_service_rowsource(rasqal_world * world,rasqal_query * query,raptor_uri * service_uri,const unsigned char * query_string,raptor_sequence * data_graphs,unsigned int rs_flags)171 rasqal_new_service_rowsource(rasqal_world *world, rasqal_query* query,
172                              raptor_uri* service_uri,
173                              const unsigned char* query_string,
174                              raptor_sequence* data_graphs,
175                              unsigned int rs_flags)
176 {
177   rasqal_service_rowsource_context* con = NULL;
178   rasqal_service* svc = NULL;
179   int flags = 0;
180   int silent = (rs_flags & RASQAL_ENGINE_BITFLAG_SILENT);
181 
182   if(!world || !query_string)
183     goto fail;
184 
185   svc = rasqal_new_service(query->world, service_uri, query_string,
186                            data_graphs);
187   if(!svc) {
188     if(!silent)
189       goto fail;
190 
191     /* Silent errors so tidy up and return empty rowsource */
192     RASQAL_FREE(cstring, query_string);
193     if(data_graphs)
194       raptor_free_sequence(data_graphs);
195 
196     return rasqal_new_empty_rowsource(world, query);
197   }
198 
199   con = RASQAL_CALLOC(rasqal_service_rowsource_context*, 1, sizeof(*con));
200   if(!con)
201     goto fail;
202 
203   con->svc = svc;
204   con->query = query;
205   con->flags = rs_flags;
206 
207   return rasqal_new_rowsource_from_handler(world, query,
208                                            con,
209                                            &rasqal_service_rowsource_handler,
210                                            query->vars_table,
211                                            flags);
212 
213   fail:
214   if(svc)
215     rasqal_free_service(svc);
216   if(con)
217     RASQAL_FREE(rasqal_service_rowsource_context, con);
218   if(query_string)
219     RASQAL_FREE(cstring, query_string);
220   if(data_graphs)
221     raptor_free_sequence(data_graphs);
222 
223   return NULL;
224 }
225 
226 
227 #endif /* not STANDALONE */
228 
229 
230 
231 #ifdef STANDALONE
232 
233 /* one more prototype */
234 int main(int argc, char *argv[]);
235 
236 int
main(int argc,char * argv[])237 main(int argc, char *argv[])
238 {
239   const char *program = rasqal_basename(argv[0]);
240   rasqal_rowsource *rowsource = NULL;
241   rasqal_world* world = NULL;
242   rasqal_query* query = NULL;
243   rasqal_row* row = NULL;
244   int count;
245   raptor_sequence* seq = NULL;
246   int failures = 0;
247   raptor_uri* service_uri;
248   const unsigned char* query_string;
249   raptor_sequence* data_graphs = NULL;
250   unsigned int rs_flags = 0;
251 
252   world = rasqal_new_world();
253   if(!world || rasqal_world_open(world)) {
254     fprintf(stderr, "%s: rasqal_world init failed\n", program);
255     return(1);
256   }
257 
258   query = rasqal_new_query(world, "sparql", NULL);
259 
260   service_uri = raptor_new_uri(world->raptor_world_ptr,
261                                (const unsigned char *)"http://example.org/service");
262   query_string = (const unsigned char*)"SELECT * WHERE { ?s ?p ?o }";
263   rowsource = rasqal_new_service_rowsource(world, query, service_uri,
264                                            query_string, data_graphs,
265                                            rs_flags);
266   if(!rowsource) {
267     fprintf(stderr, "%s: failed to create service rowsource\n", program);
268     failures++;
269     goto tidy;
270   }
271 
272   row = rasqal_rowsource_read_row(rowsource);
273   if(!row) {
274     fprintf(stderr,
275             "%s: read_row failed to return a row for an service rowsource\n",
276             program);
277     failures++;
278     goto tidy;
279   }
280 
281   if(row->size) {
282     fprintf(stderr,
283             "%s: read_row returned an non-service row size %d for a service stream\n",
284             program, row->size);
285     failures++;
286     goto tidy;
287   }
288 
289   count = rasqal_rowsource_get_rows_count(rowsource);
290   if(count != 1) {
291     fprintf(stderr, "%s: read_rows returned count %d for a service stream\n",
292             program, count);
293     failures++;
294     goto tidy;
295   }
296 
297   rasqal_free_rowsource(rowsource);
298 
299   /* re-init rowsource */
300   rowsource = rasqal_new_service_rowsource(world, query, service_uri,
301                                            query_string, data_graphs,
302                                            rs_flags);
303 
304   seq = rasqal_rowsource_read_all_rows(rowsource);
305   if(!seq) {
306     fprintf(stderr, "%s: read_rows returned a NULL seq for a service stream\n",
307             program);
308     failures++;
309     goto tidy;
310   }
311 
312   count = raptor_sequence_size(seq);
313   if(count != 1) {
314     fprintf(stderr, "%s: read_rows returned size %d seq for a service stream\n",
315             program, count);
316     failures++;
317     goto tidy;
318   }
319 
320 
321   tidy:
322   if(seq)
323     raptor_free_sequence(seq);
324   if(rowsource)
325     rasqal_free_rowsource(rowsource);
326   if(query)
327     rasqal_free_query(query);
328   if(world)
329     rasqal_free_world(world);
330 
331   return failures;
332 }
333 
334 #endif /* STANDALONE */
335