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