/* -*- Mode: c; c-basic-offset: 2 -*- * * rasqal_redland.c - Rasqal redland interface * * $Id: rasqal_redland.c 11551 2006-10-29 21:12:27Z dajobe $ * * Copyright (C) 2004-2006, David Beckett http://purl.org/net/dajobe/ * Copyright (C) 2004-2005, University of Bristol, UK http://www.bristol.ac.uk/ * * This package is Free Software and part of Redland http://librdf.org/ * * It is licensed under the following three licenses as alternatives: * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version * 2. GNU General Public License (GPL) V2 or any newer version * 3. Apache License, V2.0 or any newer version * * You may not use this file except in compliance with at least one of * the above three licenses. * * See LICENSE.html or LICENSE.txt at the top of this package for the * complete terms and further detail along with the license texts for * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively. * * */ #ifdef HAVE_CONFIG_H #include #endif #ifdef WIN32 #include #endif #include #include #ifdef HAVE_STDLIB_H #include #endif #include #include #include "rasqal.h" #include "rasqal_internal.h" #define LIBRDF_MALLOC(type, size) malloc(size) #define LIBRDF_CALLOC(type, size, count) calloc(size, count) #define LIBRDF_FREE(type, ptr) free((void*)ptr) #ifdef RASQAL_DEBUG #define LIBRDF_DEBUG1(msg) do {fprintf(stderr, "%s:%d:%s: " msg, __FILE__, __LINE__, __func__); } while(0) #define LIBRDF_DEBUG2(msg, arg1) do {fprintf(stderr, "%s:%d:%s: " msg, __FILE__, __LINE__, __func__, arg1);} while(0) #else #define LIBRDF_DEBUG1(msg) #define LIBRDF_DEBUG2(msg, arg1) #endif static librdf_node* rasqal_literal_to_redland_node(librdf_world *world, rasqal_literal* l) { if(l->type == RASQAL_LITERAL_URI) return librdf_new_node_from_uri(world, (librdf_uri*)l->value.uri); else if (l->type == RASQAL_LITERAL_STRING || l->type == RASQAL_LITERAL_INTEGER || l->type == RASQAL_LITERAL_DOUBLE || l->type == RASQAL_LITERAL_BOOLEAN) return librdf_new_node_from_typed_literal(world, l->string, l->language, (librdf_uri*)l->datatype); else if (l->type == RASQAL_LITERAL_BLANK) return librdf_new_node_from_blank_identifier(world, l->string); else { LIBRDF_DEBUG2("Could not convert literal type %d to librdf_node", l->type); abort(); } return NULL; } static rasqal_literal* redland_node_to_rasqal_literal(librdf_node *node) { rasqal_literal* l; if(librdf_node_is_resource(node)) { raptor_uri* uri=(raptor_uri*)librdf_new_uri_from_uri(librdf_node_get_uri(node)); l=rasqal_new_uri_literal(uri); } else if(librdf_node_is_literal(node)) { char *string; librdf_uri *uri; char *new_string; char *new_language=NULL; raptor_uri *new_datatype=NULL; size_t len; string=librdf_node_get_literal_value_as_counted_string(node, &len); new_string=LIBRDF_MALLOC(cstring, len+1); strcpy(new_string, (const char*)string); string=librdf_node_get_literal_value_language(node); if(string) { new_language=LIBRDF_MALLOC(cstring, strlen(string)+1); strcpy(new_language, (const char*)string); } uri=librdf_node_get_literal_value_datatype_uri(node); if(uri) new_datatype=(raptor_uri*)librdf_new_uri_from_uri(uri); l=rasqal_new_string_literal(new_string, new_language, new_datatype, NULL); } else { char *blank=librdf_node_get_blank_identifier(node); char *new_blank=LIBRDF_MALLOC(cstring, strlen(blank)+1); strcpy(new_blank, (const char*)blank); l=rasqal_new_simple_literal(RASQAL_LITERAL_BLANK, new_blank); } return l; } typedef struct { librdf_world *world; librdf_model *model; librdf_storage *storage; /* index used while reading triples into the array below. * This is used to connect a triple to the URI of the source */ int source_index; /* size of the two arrays below */ int sources_count; /* array of source URIs */ librdf_uri **source_uris; } rasqal_redland_triples_source_user_data; /* prototypes */ static int rasqal_redland_init_triples_match(rasqal_triples_match* rtm, rasqal_triples_source *rts, void *user_data, rasqal_triple_meta *m, rasqal_triple *t); static int rasqal_redland_triple_present(rasqal_triples_source *rts, void *user_data, rasqal_triple *t); static void rasqal_redland_free_triples_source(void *user_data); static int rasqal_redland_new_triples_source(rasqal_query* rdf_query, void *factory_user_data, void *user_data, rasqal_triples_source *rts) { librdf_world *world=(librdf_world*)factory_user_data; rasqal_redland_triples_source_user_data* rtsc=(rasqal_redland_triples_source_user_data*)user_data; librdf_parser *parser; const char *parser_name; int i; if(!rdf_query->data_graphs) return -1; /* no data */ rtsc->sources_count=raptor_sequence_size(rdf_query->data_graphs); /* no default triple source possible */ if(!rtsc->sources_count) return -1; /* no data */ rtsc->world=world; /* FIXME error checking */ rtsc->storage = librdf_new_storage(world, NULL, NULL, "contexts='yes'"); rtsc->model = librdf_new_model(world, rtsc->storage, NULL); rts->init_triples_match=rasqal_redland_init_triples_match; rts->triple_present=rasqal_redland_triple_present; rts->free_triples_source=rasqal_redland_free_triples_source; rtsc->source_uris=(librdf_uri**)RASQAL_CALLOC(librdf_uri_ptr, rtsc->sources_count, sizeof(librdf_uri*)); for(i=0; i< rtsc->sources_count; i++) { rasqal_data_graph *dg=(rasqal_data_graph*)raptor_sequence_get_at(rdf_query->data_graphs, i); librdf_stream *stream; librdf_node *node; rtsc->source_index=i; rtsc->source_uris[i]=librdf_new_uri(world, raptor_uri_as_string(dg->uri)); parser_name=raptor_guess_parser_name(NULL, NULL, NULL, 0, raptor_uri_as_string(dg->uri)); parser=librdf_new_parser(world, parser_name, NULL, NULL); stream=librdf_parser_parse_as_stream(parser, (librdf_uri*)dg->uri, (librdf_uri*)dg->name_uri); node=librdf_new_node_from_uri(world, (librdf_uri*)rtsc->source_uris[i]); librdf_model_context_add_statements(rtsc->model, node, stream); librdf_free_stream(stream); librdf_free_node(node); librdf_free_parser(parser); } return 0; } static int rasqal_redland_triple_present(rasqal_triples_source *rts, void *user_data, rasqal_triple *t) { rasqal_redland_triples_source_user_data* rtsc=(rasqal_redland_triples_source_user_data*)user_data; librdf_node* nodes[3]; librdf_statement *s; int rc; /* ASSUMPTION: all the parts of the triple are not variables */ /* FIXME: and no error checks */ nodes[0]=rasqal_literal_to_redland_node(rtsc->world, t->subject); nodes[1]=rasqal_literal_to_redland_node(rtsc->world, t->predicate); nodes[2]=rasqal_literal_to_redland_node(rtsc->world, t->object); s=librdf_new_statement_from_nodes(rtsc->world, nodes[0], nodes[1], nodes[2]); rc=librdf_model_contains_statement(rtsc->model, s); librdf_free_statement(s); return rc; } static void rasqal_redland_free_triples_source(void *user_data) { rasqal_redland_triples_source_user_data* rtsc=(rasqal_redland_triples_source_user_data*)user_data; int i; for(i=0; i< rtsc->sources_count; i++) { librdf_free_uri(rtsc->source_uris[i]); } RASQAL_FREE(librdf_uri_ptr, rtsc->source_uris); librdf_free_model(rtsc->model); librdf_free_storage(rtsc->storage); } static void rasqal_redland_register_triples_source_factory(rasqal_triples_source_factory *factory) { factory->user_data_size=sizeof(rasqal_redland_triples_source_user_data); factory->new_triples_source=rasqal_redland_new_triples_source; } typedef struct { librdf_node* nodes[3]; librdf_node* origin; /* query statement, made from the nodes above (even when exact) */ librdf_statement *qstatement; librdf_stream *stream; } rasqal_redland_triples_match_context; static rasqal_triple_parts rasqal_redland_bind_match(struct rasqal_triples_match_s* rtm, void *user_data, rasqal_variable* bindings[4], rasqal_triple_parts parts) { rasqal_redland_triples_match_context* rtmc=(rasqal_redland_triples_match_context*)rtm->user_data; rasqal_literal* l; rasqal_triple_parts result=(rasqal_triple_parts)0; librdf_statement* statement; statement= librdf_stream_get_object(rtmc->stream); if(!statement) return result; #ifdef RASQAL_DEBUG LIBRDF_DEBUG1(" matched statement "); librdf_statement_print(statement, stderr); fputc('\n', stderr); #endif /* set 1 or 2 variable values from the fields of statement */ if(bindings[0] && (parts & RASQAL_TRIPLE_SUBJECT)) { LIBRDF_DEBUG1("binding subject to variable\n"); l=redland_node_to_rasqal_literal(librdf_statement_get_subject(statement)); rasqal_variable_set_value(bindings[0], rasqal_literal_as_node(l)); rasqal_free_literal(l); result= RASQAL_TRIPLE_SUBJECT; } if(bindings[1] && (parts & RASQAL_TRIPLE_PREDICATE)) { if(bindings[0] == bindings[1]) { if(!librdf_node_equals(librdf_statement_get_subject(statement), librdf_statement_get_predicate(statement))) return (rasqal_triple_parts)0; LIBRDF_DEBUG1("subject and predicate values match\n"); } else { LIBRDF_DEBUG1("binding predicate to variable\n"); l=redland_node_to_rasqal_literal(librdf_statement_get_predicate(statement)); rasqal_variable_set_value(bindings[1], rasqal_literal_as_node(l)); rasqal_free_literal(l); result= (rasqal_triple_parts)(result | RASQAL_TRIPLE_PREDICATE); } } if(bindings[2] && (parts & RASQAL_TRIPLE_OBJECT)) { int bind=1; if(bindings[0] == bindings[2]) { if(!librdf_node_equals(librdf_statement_get_subject(statement), librdf_statement_get_object(statement))) return (rasqal_triple_parts)0; bind=0; LIBRDF_DEBUG1("subject and object values match\n"); } if(bindings[1] == bindings[2] && !(bindings[0] == bindings[1]) /* don't do this check if ?x ?x ?x */ ) { if(!librdf_node_equals(librdf_statement_get_predicate(statement), librdf_statement_get_object(statement))) return (rasqal_triple_parts)0; bind=0; LIBRDF_DEBUG1("predicate and object values match\n"); } if(bind) { LIBRDF_DEBUG1("binding object to variable\n"); l=redland_node_to_rasqal_literal(librdf_statement_get_object(statement)); rasqal_variable_set_value(bindings[2], rasqal_literal_as_node(l)); rasqal_free_literal(l); result= (rasqal_triple_parts)(result | RASQAL_TRIPLE_OBJECT); } } if(bindings[3] && (parts & RASQAL_TRIPLE_ORIGIN)) { l=redland_node_to_rasqal_literal((librdf_node*)librdf_stream_get_context(rtmc->stream)); RASQAL_DEBUG1("binding origin to variable\n"); rasqal_variable_set_value(bindings[3], rasqal_literal_as_node(l)); rasqal_free_literal(l); result= (rasqal_triple_parts)(result | RASQAL_TRIPLE_ORIGIN); } return result; } static void rasqal_redland_next_match(struct rasqal_triples_match_s* rtm, void *user_data) { rasqal_redland_triples_match_context* rtmc=(rasqal_redland_triples_match_context*)rtm->user_data; librdf_stream_next(rtmc->stream); } static int rasqal_redland_is_end(struct rasqal_triples_match_s* rtm, void *user_data) { rasqal_redland_triples_match_context* rtmc=(rasqal_redland_triples_match_context*)rtm->user_data; return librdf_stream_end(rtmc->stream); } static void rasqal_redland_finish_triples_match(struct rasqal_triples_match_s* rtm, void *user_data) { rasqal_redland_triples_match_context* rtmc=(rasqal_redland_triples_match_context*)rtm->user_data; if(rtmc->stream) { librdf_free_stream(rtmc->stream); rtmc->stream=NULL; } librdf_free_statement(rtmc->qstatement); LIBRDF_FREE(rasqal_redland_triples_match_context, rtmc); } static int rasqal_redland_init_triples_match(rasqal_triples_match* rtm, rasqal_triples_source *rts, void *user_data, rasqal_triple_meta *m, rasqal_triple *t) { rasqal_redland_triples_source_user_data* rtsc=(rasqal_redland_triples_source_user_data*)user_data; rasqal_redland_triples_match_context* rtmc; rasqal_variable* var; rtm->bind_match=rasqal_redland_bind_match; rtm->next_match=rasqal_redland_next_match; rtm->is_end=rasqal_redland_is_end; rtm->finish=rasqal_redland_finish_triples_match; rtmc=(rasqal_redland_triples_match_context*)LIBRDF_CALLOC(rasqal_redland_triples_match_context, 1, sizeof(rasqal_redland_triples_match_context)); rtm->user_data=rtmc; /* at least one of the triple terms is a variable and we need to * do a triplesMatching() aka librdf_model_find_statements * * redland find_statements will do the right thing and internally * pick the most efficient, indexed way to get the answer. */ if((var=rasqal_literal_as_variable(t->subject))) { if(var->value) rtmc->nodes[0]=rasqal_literal_to_redland_node(rtsc->world, var->value); else rtmc->nodes[0]=NULL; } else rtmc->nodes[0]=rasqal_literal_to_redland_node(rtsc->world, t->subject); m->bindings[0]=var; if((var=rasqal_literal_as_variable(t->predicate))) { if(var->value) rtmc->nodes[1]=rasqal_literal_to_redland_node(rtsc->world, var->value); else rtmc->nodes[1]=NULL; } else rtmc->nodes[1]=rasqal_literal_to_redland_node(rtsc->world, t->predicate); m->bindings[1]=var; if((var=rasqal_literal_as_variable(t->object))) { if(var->value) rtmc->nodes[2]=rasqal_literal_to_redland_node(rtsc->world, var->value); else rtmc->nodes[2]=NULL; } else rtmc->nodes[2]=rasqal_literal_to_redland_node(rtsc->world, t->object); m->bindings[2]=var; if(t->origin) { if((var=rasqal_literal_as_variable(t->origin))) { if(var->value) rtmc->origin=rasqal_literal_to_redland_node(rtsc->world, var->value); } else rtmc->origin=rasqal_literal_to_redland_node(rtsc->world, t->origin); m->bindings[3]=var; } rtmc->qstatement=librdf_new_statement_from_nodes(rtsc->world, rtmc->nodes[0], rtmc->nodes[1], rtmc->nodes[2]); if(!rtmc->qstatement) return 1; #ifdef RASQAL_DEBUG LIBRDF_DEBUG1("query statement: "); librdf_statement_print(rtmc->qstatement, stderr); fputc('\n', stderr); #endif rtmc->stream=librdf_model_find_statements(rtsc->model, rtmc->qstatement); LIBRDF_DEBUG1("rasqal_init_triples_match done\n"); return 0; } static librdf_world* Rasqal_Redland_World=NULL; void rasqal_redland_init(void) { Rasqal_Redland_World=librdf_new_world(); librdf_world_open(Rasqal_Redland_World); rasqal_set_triples_source_factory(rasqal_redland_register_triples_source_factory, Rasqal_Redland_World); } void rasqal_redland_finish() { librdf_free_world(Rasqal_Redland_World); Rasqal_Redland_World=NULL; }