1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rasqal_rowsource_triples.c - Rasqal triple pattern rowsource class
4 *
5 * Copyright (C) 2008-2009, 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 /* source of triple pattern matches */
49 rasqal_triples_source* triples_source;
50
51 /* sequence of triple SHARED with query */
52 raptor_sequence* triples;
53
54 /* current column being iterated */
55 int column;
56
57 /* first triple pattern in sequence to use */
58 int start_column;
59
60 /* last triple pattern in sequence to use */
61 int end_column;
62
63 /* number of triple patterns in the sequence
64 ( = end_column - start_column + 1) */
65 int triples_count;
66
67 /* An array of items, one per triple pattern in the sequence */
68 rasqal_triple_meta* triple_meta;
69
70 /* offset into results for current row */
71 int offset;
72
73 /* number of variables used in variables table */
74 int size;
75
76 /* GRAPH origin to use */
77 rasqal_literal *origin;
78 } rasqal_triples_rowsource_context;
79
80
81 static int
rasqal_triples_rowsource_init(rasqal_rowsource * rowsource,void * user_data)82 rasqal_triples_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
83 {
84 rasqal_query *query = rowsource->query;
85 rasqal_triples_rowsource_context *con;
86 int column;
87 int rc = 0;
88 int size;
89 int i;
90
91 con = (rasqal_triples_rowsource_context*)user_data;
92
93 size = rasqal_variables_table_get_total_variables_count(query->vars_table);
94
95 /* Construct the ordered projection of the variables set by these triples */
96 con->size = 0;
97 for(i = 0; i < size; i++) {
98 rasqal_variable *v;
99 v = rasqal_variables_table_get(rowsource->vars_table, i);
100
101 for(column = con->start_column; column <= con->end_column; column++) {
102 if(rasqal_query_variable_bound_in_triple(query, v, column)) {
103 v = rasqal_new_variable_from_variable(v);
104 if(raptor_sequence_push(rowsource->variables_sequence, v))
105 return -1;
106 con->size++;
107 break; /* end column search loop */
108 }
109 }
110 }
111
112 con->column = con->start_column;
113
114 for(column = con->start_column; column <= con->end_column; column++) {
115 rasqal_triple_meta *m;
116 rasqal_triple *t;
117 rasqal_variable* v;
118
119 m = &con->triple_meta[column - con->start_column];
120
121 m->parts = (rasqal_triple_parts)0;
122
123 t = (rasqal_triple*)raptor_sequence_get_at(con->triples, column);
124
125 if((v = rasqal_literal_as_variable(t->subject)) &&
126 rasqal_query_variable_bound_in_triple(query, v, column) & RASQAL_TRIPLE_SUBJECT)
127 m->parts = (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_SUBJECT);
128
129 if((v = rasqal_literal_as_variable(t->predicate)) &&
130 rasqal_query_variable_bound_in_triple(query, v, column) & RASQAL_TRIPLE_PREDICATE)
131 m->parts = (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_PREDICATE);
132
133 if((v = rasqal_literal_as_variable(t->object)) &&
134 rasqal_query_variable_bound_in_triple(query, v, column) & RASQAL_TRIPLE_OBJECT)
135 m->parts = (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_OBJECT);
136
137 RASQAL_DEBUG4("triple pattern column %d has parts %s (%u)\n", column,
138 rasqal_engine_get_parts_string(m->parts), m->parts);
139
140 }
141
142 return rc;
143 }
144
145
146 static int
rasqal_triples_rowsource_ensure_variables(rasqal_rowsource * rowsource,void * user_data)147 rasqal_triples_rowsource_ensure_variables(rasqal_rowsource* rowsource,
148 void *user_data)
149 {
150 rasqal_triples_rowsource_context* con;
151 con = (rasqal_triples_rowsource_context*)user_data;
152
153 rowsource->size = con->size;
154
155 return 0;
156 }
157
158
159 static int
rasqal_triples_rowsource_finish(rasqal_rowsource * rowsource,void * user_data)160 rasqal_triples_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
161 {
162 rasqal_triples_rowsource_context *con;
163 int i;
164
165 con = (rasqal_triples_rowsource_context*)user_data;
166
167 if(con->triple_meta) {
168 for(i = con->start_column; i <= con->end_column; i++) {
169 rasqal_triple_meta *m;
170 m = &con->triple_meta[i - con->start_column];
171 rasqal_reset_triple_meta(m);
172 }
173
174 RASQAL_FREE(rasqal_triple_meta, con->triple_meta);
175 }
176
177 if(con->origin)
178 rasqal_free_literal(con->origin);
179
180 RASQAL_FREE(rasqal_triples_rowsource_context, con);
181
182 return 0;
183 }
184
185
186 static rasqal_engine_error
rasqal_triples_rowsource_get_next_row(rasqal_rowsource * rowsource,rasqal_triples_rowsource_context * con)187 rasqal_triples_rowsource_get_next_row(rasqal_rowsource* rowsource,
188 rasqal_triples_rowsource_context *con)
189 {
190 rasqal_query *query = rowsource->query;
191 rasqal_engine_error error = RASQAL_ENGINE_OK;
192
193 while(con->column >= con->start_column) {
194 rasqal_triple_meta *m;
195 rasqal_triple *t;
196
197 m = &con->triple_meta[con->column - con->start_column];
198 t = (rasqal_triple*)raptor_sequence_get_at(con->triples, con->column);
199
200 error = RASQAL_ENGINE_OK;
201
202 if(!m->triples_match) {
203 /* Column has no triples match so create a new query */
204 m->triples_match = rasqal_new_triples_match(query,
205 con->triples_source,
206 m, t);
207 if(!m->triples_match) {
208 /* triples matching setup failed - matching state is unknown */
209 RASQAL_DEBUG2("Failed to make a triple match for column %d\n",
210 con->column);
211 error = RASQAL_ENGINE_FAILED;
212 break;
213 }
214 RASQAL_DEBUG2("made new triples match for column %d\n", con->column);
215 }
216
217
218 if(rasqal_triples_match_is_end(m->triples_match)) {
219 RASQAL_DEBUG2("end of pattern triples match for column %d\n",
220 con->column);
221
222 /* reset this column and move to next match in previous column */
223 rasqal_reset_triple_meta(m);
224 con->column--;
225 if(con->column < con->start_column) {
226 error = RASQAL_ENGINE_FINISHED;
227 break;
228 }
229 continue;
230 }
231
232 if(m->parts) {
233 rasqal_triple_parts parts;
234 parts = rasqal_triples_match_bind_match(m->triples_match, m->bindings,
235 m->parts);
236 RASQAL_DEBUG4("bind_match for column %d returned parts %s (%u)\n",
237 con->column, rasqal_engine_get_parts_string(parts), parts);
238 if(!parts) {
239 rasqal_triples_match_next_match(m->triples_match);
240 continue;
241 }
242 } else {
243 RASQAL_DEBUG2("Nothing to bind_match for column %d\n", con->column);
244 }
245
246 rasqal_triples_match_next_match(m->triples_match);
247
248 if(con->column == con->end_column)
249 /* finished matching all columns - return result */
250 break;
251
252 /* continue matching in next column */
253 con->column++;
254 }
255
256 return error;
257 }
258
259
260 static rasqal_row*
rasqal_triples_rowsource_read_row(rasqal_rowsource * rowsource,void * user_data)261 rasqal_triples_rowsource_read_row(rasqal_rowsource* rowsource, void *user_data)
262 {
263 rasqal_triples_rowsource_context *con;
264 int i;
265 rasqal_row* row = NULL;
266 rasqal_engine_error error = RASQAL_ENGINE_OK;
267
268 con = (rasqal_triples_rowsource_context*)user_data;
269
270 error = rasqal_triples_rowsource_get_next_row(rowsource, con);
271 RASQAL_DEBUG2("rasqal_triples_rowsource_get_next_row() returned error %s\n",
272 rasqal_engine_error_as_string(error));
273
274 if(error != RASQAL_ENGINE_OK)
275 goto done;
276
277 #ifdef RASQAL_DEBUG
278 if(1) {
279 int values_returned = 0;
280 /* Count actual bound values */
281 for(i = 0; i < con->size; i++) {
282 rasqal_variable* v;
283 v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
284 if(v->value)
285 values_returned++;
286 }
287 RASQAL_DEBUG2("Solution binds %d values\n", values_returned);
288 }
289 #endif
290
291 row = rasqal_new_row(rowsource);
292 if(!row) {
293 error = RASQAL_ENGINE_FAILED;
294 goto done;
295 }
296
297 for(i = 0; i < row->size; i++) {
298 rasqal_variable* v;
299 v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
300 if(row->values[i])
301 rasqal_free_literal(row->values[i]);
302 row->values[i] = rasqal_new_literal_from_literal(v->value);
303 }
304
305 row->offset = con->offset++;
306
307 done:
308
309 return row;
310 }
311
312
313 static raptor_sequence*
rasqal_triples_rowsource_read_all_rows(rasqal_rowsource * rowsource,void * user_data)314 rasqal_triples_rowsource_read_all_rows(rasqal_rowsource* rowsource,
315 void *user_data)
316 {
317 raptor_sequence *seq = NULL;
318
319 return seq;
320 }
321
322
323 static int
rasqal_triples_rowsource_reset(rasqal_rowsource * rowsource,void * user_data)324 rasqal_triples_rowsource_reset(rasqal_rowsource* rowsource, void *user_data)
325 {
326 rasqal_triples_rowsource_context *con;
327 int column;
328
329 con = (rasqal_triples_rowsource_context*)user_data;
330
331 con->column = con->start_column;
332 for(column = con->start_column; column <= con->end_column; column++) {
333 rasqal_triple_meta *m;
334
335 m = &con->triple_meta[column - con->start_column];
336 rasqal_reset_triple_meta(m);
337 }
338
339 return 0;
340 }
341
342
343 static int
rasqal_triples_rowsource_set_origin(rasqal_rowsource * rowsource,void * user_data,rasqal_literal * origin)344 rasqal_triples_rowsource_set_origin(rasqal_rowsource *rowsource,
345 void *user_data,
346 rasqal_literal *origin)
347 {
348 rasqal_triples_rowsource_context *con;
349 int column;
350
351 con = (rasqal_triples_rowsource_context*)user_data;
352 if(con->origin)
353 rasqal_free_literal(con->origin);
354 con->origin = rasqal_new_literal_from_literal(origin);
355
356 for(column = con->start_column; column <= con->end_column; column++) {
357 rasqal_triple *t;
358 t = (rasqal_triple*)raptor_sequence_get_at(con->triples, column);
359 if(t->origin)
360 rasqal_free_literal(t->origin);
361 t->origin = rasqal_new_literal_from_literal(con->origin);
362 }
363
364 return 0;
365 }
366
367
368 static const rasqal_rowsource_handler rasqal_triples_rowsource_handler = {
369 /* .version = */ 1,
370 "triple pattern",
371 /* .init = */ rasqal_triples_rowsource_init,
372 /* .finish = */ rasqal_triples_rowsource_finish,
373 /* .ensure_variables = */ rasqal_triples_rowsource_ensure_variables,
374 /* .read_row = */ rasqal_triples_rowsource_read_row,
375 /* .read_all_rows = */ rasqal_triples_rowsource_read_all_rows,
376 /* .reset = */ rasqal_triples_rowsource_reset,
377 /* .set_requirements = */ NULL,
378 /* .get_inner_rowsource = */ NULL,
379 /* .set_origin = */ rasqal_triples_rowsource_set_origin
380 };
381
382
383 /**
384 * rasqal_new_triples_rowsource:
385 * @world: world object
386 * @query: query object
387 * @triples_source: shared triples source
388 * @triples: shared triples sequence
389 * @start_column: start column in triples sequence
390 * @end_column: end column in triples sequence
391 * @bound_in: array marking the triples that bind a variable
392 *
393 * INTERNAL - create a new triples rowsource
394 *
395 * Return value: new triples rowsource or NULL on failure
396 */
397 rasqal_rowsource*
rasqal_new_triples_rowsource(rasqal_world * world,rasqal_query * query,rasqal_triples_source * triples_source,raptor_sequence * triples,int start_column,int end_column)398 rasqal_new_triples_rowsource(rasqal_world *world,
399 rasqal_query *query,
400 rasqal_triples_source* triples_source,
401 raptor_sequence* triples,
402 int start_column, int end_column)
403 {
404 rasqal_triples_rowsource_context *con;
405 int flags = 0;
406
407 if(!world || !query || !triples_source)
408 return NULL;
409
410 if(!triples)
411 return rasqal_new_empty_rowsource(world, query);
412
413 con = RASQAL_CALLOC(rasqal_triples_rowsource_context*, 1, sizeof(*con));
414 if(!con)
415 return NULL;
416
417 con->triples_source = triples_source;
418 con->triples = triples;
419 con->start_column = start_column;
420 con->end_column = end_column;
421 con->column = -1;
422
423 con->triples_count = con->end_column - con->start_column + 1;
424
425 con->triple_meta = RASQAL_CALLOC(rasqal_triple_meta*, RASQAL_GOOD_CAST(size_t, con->triples_count),
426 sizeof(rasqal_triple_meta));
427 if(!con->triple_meta) {
428 rasqal_triples_rowsource_finish(NULL, con);
429 return NULL;
430 }
431
432 return rasqal_new_rowsource_from_handler(world, query,
433 con,
434 &rasqal_triples_rowsource_handler,
435 query->vars_table,
436 flags);
437 }
438
439
440 #endif /* not STANDALONE */
441
442
443
444 #ifdef STANDALONE
445
446 /* one more prototype */
447 int main(int argc, char *argv[]);
448
449 #define QUERY_LANGUAGE "sparql"
450 #define QUERY_FORMAT "\
451 SELECT ?s ?p ?o \
452 FROM <%s> \
453 WHERE { ?s ?p ?o }\
454 "
455
456 int
main(int argc,char * argv[])457 main(int argc, char *argv[])
458 {
459 const char *program = rasqal_basename(argv[0]);
460 rasqal_rowsource *rowsource = NULL;
461 rasqal_world *world;
462 rasqal_query *query;
463 const char *query_language_name = QUERY_LANGUAGE;
464 const char *query_format = QUERY_FORMAT;
465 unsigned char *query_string;
466 int failures = 0;
467 int start_column;
468 int end_column;
469 int rc;
470 raptor_sequence* triples;
471 rasqal_triples_source* triples_source = NULL;
472 raptor_uri *base_uri = NULL;
473 unsigned char *data_string = NULL;
474 unsigned char *uri_string = NULL;
475 /* <http://example.org#subject> <http://example.org#predicate> "object" . */
476 #define SUBJECT_URI_STRING RASQAL_GOOD_CAST(const unsigned char*, "http://example.org#subject")
477 #define PREDICATE_URI_STRING RASQAL_GOOD_CAST(const unsigned char*, "http://example.org#predicate")
478 #define OBJECT_STRING "object"
479 raptor_uri* s_uri = NULL;
480 raptor_uri* p_uri = NULL;
481 const char *data_file;
482
483 if((data_file = getenv("NT_DATA_FILE"))) {
484 /* got data from environment */
485 } else {
486 if(argc != 2) {
487 fprintf(stderr, "USAGE: %s data-filename\n", program);
488 return(1);
489 }
490 data_file = argv[1];
491 }
492
493 world = rasqal_new_world();
494 if(!world || rasqal_world_open(world)) {
495 fprintf(stderr, "%s: rasqal_world init failed\n", program);
496 return(1);
497 }
498
499 query = rasqal_new_query(world, "sparql", NULL);
500
501 data_string = raptor_uri_filename_to_uri_string(data_file);
502 query_string = RASQAL_MALLOC(unsigned char*, strlen(RASQAL_GOOD_CAST(const char*, data_string)) + strlen(query_format) + 1);
503 #pragma GCC diagnostic push
504 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
505 sprintf(RASQAL_GOOD_CAST(char*, query_string), query_format, data_string);
506 #pragma GCC diagnostic pop
507 raptor_free_memory(data_string);
508
509 uri_string = raptor_uri_filename_to_uri_string("");
510 base_uri = raptor_new_uri(world->raptor_world_ptr, uri_string);
511 raptor_free_memory(uri_string);
512
513 query = rasqal_new_query(world, query_language_name, NULL);
514 if(!query) {
515 fprintf(stderr, "%s: creating query in language %s FAILED\n", program,
516 query_language_name);
517 failures++;
518 goto tidy;
519 }
520
521 printf("%s: preparing %s query\n", program, query_language_name);
522 rc = rasqal_query_prepare(query, query_string, base_uri);
523 if(rc) {
524 fprintf(stderr, "%s: failed to prepare query '%s'\n", program,
525 query_string);
526 failures++;
527 goto tidy;
528 }
529
530 RASQAL_FREE(char*, query_string);
531 query_string = NULL;
532
533 triples = rasqal_query_get_triple_sequence(query);
534 start_column = 0;
535 end_column = 0;
536
537 triples_source = rasqal_new_triples_source(query);
538
539 rowsource = rasqal_new_triples_rowsource(world, query, triples_source,
540 triples, start_column, end_column);
541 if(!rowsource) {
542 fprintf(stderr, "%s: failed to create triples rowsource\n", program);
543 failures++;
544 goto tidy;
545 }
546
547 while(1) {
548 rasqal_row* row;
549 rasqal_literal *s;
550 rasqal_literal *p;
551 rasqal_literal *o;
552
553 row = rasqal_rowsource_read_row(rowsource);
554 if(!row)
555 break;
556
557 #ifdef RASQAL_DEBUG
558 RASQAL_DEBUG1("Result Row:\n ");
559 rasqal_row_print(row, stderr);
560 fputc('\n', stderr);
561 #endif
562
563 s_uri = raptor_new_uri(world->raptor_world_ptr, SUBJECT_URI_STRING);
564 p_uri = raptor_new_uri(world->raptor_world_ptr, PREDICATE_URI_STRING);
565
566 s = row->values[0];
567 if(!s ||
568 (s && s->type != RASQAL_LITERAL_URI) ||
569 !raptor_uri_equals(s->value.uri, s_uri)) {
570 fprintf(stderr, "%s: 's' is bound to %s not URI %s\n", program,
571 rasqal_literal_as_string(s),
572 raptor_uri_as_string(s_uri));
573 failures++;
574 }
575 p = row->values[1];
576 if(!p ||
577 (p && p->type != RASQAL_LITERAL_URI) ||
578 !raptor_uri_equals(p->value.uri, p_uri)) {
579 fprintf(stderr, "%s: 'p' is bound to %s not URI %s\n", program,
580 rasqal_literal_as_string(p),
581 raptor_uri_as_string(p_uri));
582 failures++;
583 }
584 o = row->values[2];
585 if(!o ||
586 (o && o->type != RASQAL_LITERAL_STRING) ||
587 strcmp(RASQAL_GOOD_CAST(const char*, o->string), OBJECT_STRING)) {
588 fprintf(stderr, "%s: 'o' is bound to %s not string '%s'\n", program,
589 rasqal_literal_as_string(o), OBJECT_STRING);
590 failures++;
591 }
592
593 rasqal_free_row(row);
594 if(failures)
595 break;
596 }
597
598 tidy:
599 raptor_free_uri(base_uri);
600 if(s_uri)
601 raptor_free_uri(s_uri);
602 if(p_uri)
603 raptor_free_uri(p_uri);
604
605 if(triples_source)
606 rasqal_free_triples_source(triples_source);
607 if(rowsource)
608 rasqal_free_rowsource(rowsource);
609 if(query)
610 rasqal_free_query(query);
611 if(world)
612 rasqal_free_world(world);
613
614 return failures;
615 }
616
617 #endif /* STANDALONE */
618