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