1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * rasqal_triples_source.c - Rasqal triples source matching triple patterns against triples
4  *
5  * Copyright (C) 2004-2009, David Beckett http://www.dajobe.org/
6  * Copyright (C) 2004-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  * rasqal_set_triples_source_factory:
46  * @world: rasqal_world object
47  * @register_fn: registration function
48  * @user_data: user data for registration
49  *
50  * Register a factory to generate triple sources.
51  *
52  * Registers the factory that returns triples sources.  Note that
53  * there is only one of these per runtime.
54  *
55  * The #rasqal_triples_source_factory factory method new_triples_source is
56  * called with the user data for some query and #rasqal_triples_source.
57  *
58  * Return value: non-zero on failure
59  **/
60 RASQAL_EXTERN_C
61 int
rasqal_set_triples_source_factory(rasqal_world * world,rasqal_triples_source_factory_register_fn register_fn,void * user_data)62 rasqal_set_triples_source_factory(rasqal_world* world,
63                                   rasqal_triples_source_factory_register_fn register_fn,
64                                   void* user_data)
65 {
66   int rc;
67   int version;
68 
69   if(!world || !register_fn)
70     return 1;
71 
72   /* for compatibility with old API that does not call this - FIXME Remove V2 */
73   rasqal_world_open(world);
74 
75   world->triples_source_factory.user_data = user_data;
76   rc = register_fn(&world->triples_source_factory);
77 
78   /* Failed if the factory API version is not in the supported range */
79   version = world->triples_source_factory.version;
80   if(!(version >= RASQAL_TRIPLES_SOURCE_FACTORY_MIN_VERSION &&
81        version <= RASQAL_TRIPLES_SOURCE_FACTORY_MAX_VERSION)
82      ) {
83     rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_ERROR, NULL,
84                             "Failed to register triples source factory - API %d is not in supported range %d to %d",
85                             version,
86                             RASQAL_TRIPLES_SOURCE_FACTORY_MIN_VERSION,
87                             RASQAL_TRIPLES_SOURCE_FACTORY_MAX_VERSION);
88     rc = 1;
89   }
90 
91   return rc;
92 }
93 
94 
95 /**
96  * rasqal_triples_source_error_handler:
97  * @query: query
98  * @locator: any locator information
99  * @message: error message
100  *
101  * INTERNAL - Return an error during creation of a triples source
102  */
103 void
rasqal_triples_source_error_handler(rasqal_query * rdf_query,raptor_locator * locator,const char * message)104 rasqal_triples_source_error_handler(rasqal_query* rdf_query,
105                                     raptor_locator* locator,
106                                     const char* message)
107 {
108   rasqal_log_error_simple(rdf_query->world, RAPTOR_LOG_LEVEL_ERROR, locator,
109                           "%s", message);
110 }
111 
112 
113 /**
114  * rasqal_triples_source_error_handler2:
115  * @world: world
116  * @locator: any locator information
117  * @message: error message
118  *
119  * INTERNAL - Return an error during creation of a triples source
120  */
121 void
rasqal_triples_source_error_handler2(rasqal_world * world,raptor_locator * locator,const char * message)122 rasqal_triples_source_error_handler2(rasqal_world* world,
123                                      raptor_locator* locator,
124                                      const char* message)
125 {
126   rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_ERROR, locator,
127                           "%s", message);
128 }
129 
130 
131 /**
132  * rasqal_new_triples_source:
133  * @query: query
134  *
135  * INTERNAL - Create a new triples source
136  *
137  * Return value: a new triples source or NULL on failure
138  */
139 rasqal_triples_source*
rasqal_new_triples_source(rasqal_query * query)140 rasqal_new_triples_source(rasqal_query* query)
141 {
142   rasqal_triples_source_factory* rtsf = &query->world->triples_source_factory;
143   rasqal_triples_source* rts;
144   int rc = 0;
145 
146   rts = RASQAL_CALLOC(rasqal_triples_source*, 1, sizeof(*rts));
147   if(!rts)
148     return NULL;
149 
150   rts->user_data = RASQAL_CALLOC(void*, 1, rtsf->user_data_size);
151   if(!rts->user_data) {
152     RASQAL_FREE(rasqal_triples_source, rts);
153     return NULL;
154   }
155   rts->query = query;
156 
157   if(rtsf->version >= 3 && rtsf->init_triples_source2) {
158     /* rasqal_triples_source_factory API V3 */
159     unsigned int flags = 0;
160 
161     if(query->features[RASQAL_FEATURE_NO_NET])
162       flags |= 1;
163     rc = rtsf->init_triples_source2(query->world, query->data_graphs,
164                                     rtsf->user_data, rts->user_data, rts,
165                                     rasqal_triples_source_error_handler2,
166                                     flags);
167     /* if there is an error, it will have been already reported more
168      * specifically via the error handler so no need to do it again
169      * below in a generic form.
170      */
171     goto error_tidy;
172   } else if(rtsf->version >= 2 && rtsf->init_triples_source) {
173     /* rasqal_triples_source_factory API V2 */
174     rc = rtsf->init_triples_source(query, rtsf->user_data, rts->user_data, rts,
175                                    rasqal_triples_source_error_handler);
176     /* if there is an error, it will have been already reported more
177      * specifically via the error handler so no need to do it again
178      * below in a generic form.
179      */
180     goto error_tidy;
181   } else
182     /* rasqal_triples_source_factory API V1 */
183     rc = rtsf->new_triples_source(query, rtsf->user_data, rts->user_data, rts);
184 
185 
186   /* Failure if the returned triples source API version is not in the
187    * supported range
188    */
189   if(!(rts->version >= RASQAL_TRIPLES_SOURCE_MIN_VERSION &&
190        rts->version <= RASQAL_TRIPLES_SOURCE_MAX_VERSION)
191      ) {
192     rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
193                             "Failed to create triples source - API %d not in range %d to %d",
194                             rts->version,
195                             RASQAL_TRIPLES_SOURCE_MIN_VERSION,
196                             RASQAL_TRIPLES_SOURCE_MAX_VERSION);
197     rc = 1;
198   }
199 
200   if(rc) {
201     if(rc > 0) {
202       rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
203                               &query->locator,
204                               "Failed to make triples source.");
205     } else {
206       rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
207                               &query->locator,
208                               "No data to query.");
209     }
210   }
211 
212   error_tidy:
213   if(rc) {
214     RASQAL_FREE(user_data, rts->user_data);
215     RASQAL_FREE(rasqal_triples_source, rts);
216     return NULL;
217   }
218 
219   return rts;
220 }
221 
222 
223 void
rasqal_free_triples_source(rasqal_triples_source * rts)224 rasqal_free_triples_source(rasqal_triples_source *rts)
225 {
226   if(!rts)
227     return;
228 
229   if(rts->user_data) {
230     rts->free_triples_source(rts->user_data);
231     RASQAL_FREE(user_data, rts->user_data);
232     rts->user_data = NULL;
233   }
234 
235   RASQAL_FREE(rasqal_triples_source, rts);
236 }
237 
238 
239 int
rasqal_triples_source_triple_present(rasqal_triples_source * rts,rasqal_triple * t)240 rasqal_triples_source_triple_present(rasqal_triples_source *rts,
241                                      rasqal_triple *t)
242 {
243   return rts->triple_present(rts, rts->user_data, t);
244 }
245 
246 
247 static void
rasqal_free_triples_match(rasqal_triples_match * rtm)248 rasqal_free_triples_match(rasqal_triples_match* rtm)
249 {
250   if(!rtm)
251     return;
252 
253   if(!rtm->is_exact)
254     rtm->finish(rtm, rtm->user_data);
255 
256   RASQAL_FREE(rasqal_triples_match, rtm);
257 }
258 
259 
260 rasqal_triples_match*
rasqal_new_triples_match(rasqal_query * query,rasqal_triples_source * triples_source,rasqal_triple_meta * m,rasqal_triple * t)261 rasqal_new_triples_match(rasqal_query* query,
262                          rasqal_triples_source* triples_source,
263                          rasqal_triple_meta *m, rasqal_triple *t)
264 {
265   rasqal_triples_match* rtm;
266 
267   if(!triples_source)
268     return NULL;
269 
270   rtm = RASQAL_CALLOC(rasqal_triples_match*, 1, sizeof(*rtm));
271   if(rtm) {
272     rtm->world = query->world;
273 
274     /* exact if there are no variables in the triple parts */
275     rtm->is_exact = 1;
276     if(rasqal_literal_as_variable(t->predicate) ||
277        rasqal_literal_as_variable(t->subject) ||
278        rasqal_literal_as_variable(t->object))
279       rtm->is_exact = 0;
280 
281     if(rtm->is_exact) {
282       if(!triples_source->triple_present(triples_source,
283                                          triples_source->user_data, t)) {
284         rasqal_free_triples_match(rtm);
285         rtm = NULL;
286       }
287     } else {
288       if(triples_source->init_triples_match(rtm, triples_source,
289                                             triples_source->user_data,
290                                             m, t)) {
291         rasqal_free_triples_match(rtm);
292         rtm = NULL;
293       }
294     }
295   }
296 
297   return rtm;
298 }
299 
300 
301 /* methods */
302 rasqal_triple_parts
rasqal_triples_match_bind_match(struct rasqal_triples_match_s * rtm,rasqal_variable * bindings[4],rasqal_triple_parts parts)303 rasqal_triples_match_bind_match(struct rasqal_triples_match_s* rtm,
304                                 rasqal_variable *bindings[4],
305                                 rasqal_triple_parts parts)
306 {
307   if(rtm->is_exact)
308     return RASQAL_TRIPLE_SPO;
309 
310   return rtm->bind_match(rtm, rtm->user_data, bindings, parts);
311 }
312 
313 
314 void
rasqal_triples_match_next_match(struct rasqal_triples_match_s * rtm)315 rasqal_triples_match_next_match(struct rasqal_triples_match_s* rtm)
316 {
317   if(rtm->is_exact) {
318     rtm->finished++;
319     return;
320   }
321 
322   rtm->next_match(rtm, rtm->user_data);
323 }
324 
325 
326 int
rasqal_triples_match_is_end(struct rasqal_triples_match_s * rtm)327 rasqal_triples_match_is_end(struct rasqal_triples_match_s* rtm)
328 {
329   if(rtm->finished)
330     return 1;
331   if(rtm->is_exact)
332     return rtm->finished;
333 
334   return rtm->is_end(rtm, rtm->user_data);
335 }
336 
337 
338 /**
339  * rasqal_reset_triple_meta:
340  * @m: Triple pattern metadata
341  *
342  * INTERNAL - reset the metadata associated with a triple pattern
343  *
344  * Return value: number of parts of the triple that were reset (0..4)
345  **/
346 int
rasqal_reset_triple_meta(rasqal_triple_meta * m)347 rasqal_reset_triple_meta(rasqal_triple_meta* m)
348 {
349   int resets = 0;
350 
351   if(m->triples_match) {
352     rasqal_free_triples_match(m->triples_match);
353     m->triples_match = NULL;
354   }
355 
356   if(m->bindings[0] && (m->parts & RASQAL_TRIPLE_SUBJECT)) {
357     rasqal_variable_set_value(m->bindings[0],  NULL);
358     resets++;
359   }
360   if(m->bindings[1] && (m->parts & RASQAL_TRIPLE_PREDICATE)) {
361     rasqal_variable_set_value(m->bindings[1],  NULL);
362     resets++;
363   }
364   if(m->bindings[2] && (m->parts & RASQAL_TRIPLE_OBJECT)) {
365     rasqal_variable_set_value(m->bindings[2],  NULL);
366     resets++;
367   }
368   if(m->bindings[3] && (m->parts & RASQAL_TRIPLE_ORIGIN)) {
369     rasqal_variable_set_value(m->bindings[3],  NULL);
370     resets++;
371   }
372 
373   m->executed = 0;
374 
375   return resets;
376 }
377 
378 
379 
380 /*
381  * rasqal_triples_source_support_feature:
382  * @rts: triples source
383  * @feature: triples source feature
384  *
385  * INTERNAL - Test support for a feature
386  *
387  * Return value: non-0 if @feature is supported
388  */
389 int
rasqal_triples_source_support_feature(rasqal_triples_source * rts,rasqal_triples_source_feature feature)390 rasqal_triples_source_support_feature(rasqal_triples_source *rts,
391                                       rasqal_triples_source_feature feature)
392 {
393   if(rts->version >= 2 && rts->support_feature)
394     return rts->support_feature(rts->user_data, feature);
395   else
396     return 0;
397 }
398 
399 
400