1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-04 17:49:45 +02:00
2010-01-24 09:19:39 +00:00

706 lines
17 KiB
C

/* -*- Mode: c; c-basic-offset: 2 -*-
*
* rdf_query.c - RDF Query Language/Syntax and Execution Interface
*
* Copyright (C) 2002-2008, David Beckett http://www.dajobe.org/
* Copyright (C) 2002-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 <rdf_config.h>
#endif
#ifdef WIN32
#include <win32_rdf_config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h> /* for abort() as used in errors */
#endif
#include <redland.h>
#include <rdf_query.h>
#ifndef STANDALONE
/* prototypes for helper functions */
static void librdf_delete_query_factories(librdf_world *world);
/**
* librdf_init_query:
* @world: redland world object
*
* INTERNAL - Initialise the query module.
*
* Initialises and registers all
* compiled query modules. Must be called before using any of the query
* factory functions such as librdf_get_query_factory()
**/
void
librdf_init_query(librdf_world *world)
{
/* Always have query triple, rasqal implementations available */
librdf_query_triples_constructor(world);
librdf_query_rasqal_constructor(world);
}
/**
* librdf_finish_query:
* @world: redland world object
*
* INTERNAL - Terminate the query module.
*
**/
void
librdf_finish_query(librdf_world *world)
{
librdf_query_rasqal_destructor(world);
librdf_delete_query_factories(world);
}
/* helper functions */
/*
* librdf_free_query_factory - delete a query factory
*/
static void
librdf_free_query_factory(librdf_query_factory *factory)
{
if(factory) {
if(factory->name)
LIBRDF_FREE(librdf_query_factory, factory->name);
if(factory->uri)
librdf_free_uri(factory->uri);
LIBRDF_FREE(librdf_query_factory, factory);
}
}
/*
* librdf_delete_query_factories - helper function to delete all the registered query factories
*/
static void
librdf_delete_query_factories(librdf_world *world)
{
librdf_query_factory *factory, *next;
for(factory=world->query_factories; factory; factory=next) {
next=factory->next;
librdf_free_query_factory(factory);
}
world->query_factories=NULL;
}
/* class methods */
/**
* librdf_query_register_factory:
* @world: redland world object
* @name: the query language name
* @uri_string: the query language URI string (or NULL if none)
* @factory: pointer to function to call to register the factory
*
* Register a query factory.
*
**/
void
librdf_query_register_factory(librdf_world *world, const char *name,
const unsigned char *uri_string,
void (*factory) (librdf_query_factory*))
{
librdf_query_factory *query;
librdf_world_open(world);
#if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
LIBRDF_DEBUG2("Received registration for query name %s\n", name);
#endif
for(query = world->query_factories; query; query = query->next ) {
if(!strcmp(query->name, name)) {
librdf_log(world,
0, LIBRDF_LOG_ERROR, LIBRDF_FROM_QUERY, NULL,
"query language %s already registered", query->name);
return;
}
}
query=(librdf_query_factory*)LIBRDF_CALLOC(librdf_query_factory, 1,
sizeof(librdf_query_factory));
if(!query)
goto oom;
query->name=(char*)LIBRDF_MALLOC(cstring, strlen(name)+1);
if(!query->name)
goto oom_tidy;
strcpy(query->name, name);
if(uri_string) {
query->uri=librdf_new_uri(world, uri_string);
if(!query->uri)
goto oom_tidy;
}
query->next = world->query_factories;
world->query_factories = query;
/* Call the query registration function on the new object */
(*factory)(query);
#if defined(LIBRDF_DEBUG) && LIBRDF_DEBUG > 1
LIBRDF_DEBUG3("%s has context size %d\n", name, query->context_length);
#endif
return;
oom_tidy:
librdf_free_query_factory(query);
oom:
LIBRDF_FATAL1(world, LIBRDF_FROM_QUERY, "Out of memory");
}
/**
* librdf_get_query_factory:
* @world: redland world object
* @name: the factory name or NULL for the default factory
* @uri: the factory URI or NULL for the default factory
*
* Get a query factory by name.
*
* Return value: the factory object or NULL if there is no such factory
**/
librdf_query_factory*
librdf_get_query_factory(librdf_world *world,
const char *name, librdf_uri *uri)
{
librdf_query_factory *factory;
librdf_world_open(world);
/* return 1st query if no particular one wanted - why? */
if(!name && !uri) {
factory=world->query_factories;
if(!factory) {
LIBRDF_DEBUG1("No (default) query factories registered\n");
return NULL;
}
} else {
for(factory=world->query_factories; factory; factory=factory->next) {
if(name && !strcmp(factory->name, name)) {
break;
}
if(uri && factory->uri && librdf_uri_equals(factory->uri, uri)) {
break;
}
}
/* else FACTORY name not found */
if(!factory) {
LIBRDF_DEBUG3("No query language with name '%s' uri %s found\n",
name, (uri ? (char*)librdf_uri_as_string(uri) : "NULL"));
return NULL;
}
}
return factory;
}
/**
* librdf_new_query:
* @world: redland world object
* @name: the name identifying the query language
* @uri: the URI identifying the query language (or NULL)
* @query_string: the query string
* @base_uri: the base URI of the query string (or NULL)
*
* Constructor - create a new #librdf_query object.
*
* Return value: a new #librdf_query object or NULL on failure
*/
librdf_query*
librdf_new_query(librdf_world *world,
const char *name, librdf_uri *uri,
const unsigned char *query_string,
librdf_uri* base_uri)
{
librdf_query_factory* factory;
librdf_world_open(world);
factory=librdf_get_query_factory(world, name, uri);
if(!factory)
return NULL;
return librdf_new_query_from_factory(world, factory, name, uri,
query_string, base_uri);
}
/**
* librdf_new_query_from_query - Copy constructor - create a new librdf_query object from an existing one
* @old_query: the existing query #librdf_query to use
*
* Should create a new query in the same context as the existing one
* as appropriate.
*
* Return value: a new #librdf_query object or NULL on failure
*/
librdf_query*
librdf_new_query_from_query(librdf_query* old_query)
{
librdf_query* new_query;
LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(old_query, librdf_query, NULL);
/* FIXME: fail if clone is not supported by this query (factory) */
if(!old_query->factory->clone) {
LIBRDF_FATAL1(old_query->world, LIBRDF_FROM_QUERY, "clone not implemented for query factory");
return NULL;
}
new_query=(librdf_query*)LIBRDF_CALLOC(librdf_query, 1,
sizeof(librdf_query));
if(!new_query)
return NULL;
new_query->usage=1;
new_query->context=(char*)LIBRDF_CALLOC(librdf_query_context, 1,
old_query->factory->context_length);
if(!new_query->context) {
librdf_free_query(new_query);
return NULL;
}
new_query->world=old_query->world;
/* do this now so librdf_free_query won't call new factory on
* partially copied query
*/
new_query->factory=old_query->factory;
/* clone is assumed to do leave the new query in the same state
* after an init() method on an existing query - i.e ready to use
*/
if(old_query->factory->clone(new_query, old_query)) {
librdf_free_query(new_query);
return NULL;
}
return new_query;
}
/**
* librdf_new_query_from_factory:
* @world: redland world object
* @factory: the factory to use to construct the query
* @name: query language name
* @uri: query language URI (or NULL)
* @query_string: the query string
* @base_uri: base URI of the query string (or NULL)
*
* Constructor - create a new #librdf_query object.
*
* Return value: a new #librdf_query object or NULL on failure
*/
librdf_query*
librdf_new_query_from_factory(librdf_world *world,
librdf_query_factory* factory,
const char *name, librdf_uri *uri,
const unsigned char *query_string,
librdf_uri *base_uri)
{
librdf_query* query;
librdf_world_open(world);
LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(factory, librdf_query_factory, NULL);
if(!factory) {
LIBRDF_DEBUG1("No query factory given\n");
return NULL;
}
query=(librdf_query*)LIBRDF_CALLOC(librdf_query, 1, sizeof(librdf_query));
if(!query)
return NULL;
query->world=world;
query->usage=1;
query->context=(char*)LIBRDF_CALLOC(librdf_query_context, 1,
factory->context_length);
if(!query->context) {
librdf_free_query(query);
return NULL;
}
query->factory=factory;
if(factory->init(query, name, uri, query_string, base_uri)) {
librdf_free_query(query);
return NULL;
}
return query;
}
/**
* librdf_free_query:
* @query: #librdf_query object
*
* Destructor - destroy a #librdf_query object.
**/
void
librdf_free_query(librdf_query* query)
{
LIBRDF_ASSERT_OBJECT_POINTER_RETURN(query, librdf_query);
if(--query->usage)
return;
if(query->factory)
query->factory->terminate(query);
if(query->context)
LIBRDF_FREE(librdf_query_context, query->context);
LIBRDF_FREE(librdf_query, query);
}
/* methods */
void
librdf_query_add_query_result(librdf_query *query,
librdf_query_results* query_results)
{
query_results->next=query->results;
query->results=query_results;
/* add reference to ensure query lives as long as this runs */
query->usage++;
}
void
librdf_query_remove_query_result(librdf_query *query,
librdf_query_results* query_results)
{
librdf_query_results *cur, *prev=NULL;
for(cur=query->results; cur && cur != query_results; cur=cur->next)
prev=cur;
if(cur == query_results) {
if(prev)
prev->next=cur->next;
}
if(cur == query->results && cur != NULL)
query->results=cur->next;
/* remove reference and free if we are the last */
librdf_free_query(query);
}
/**
* librdf_query_execute:
* @query: #librdf_query object
* @model: model to operate query on
*
* Run the query on a model.
*
* Runs the query against the (previously registered) model
* and returns a #librdf_query_results for the result objects.
*
* Return value: #librdf_query_results or NULL on failure
**/
librdf_query_results*
librdf_query_execute(librdf_query* query, librdf_model* model)
{
librdf_query_results* results=NULL;
LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, librdf_query, NULL);
LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(model, librdf_model, NULL);
if(query->factory->execute) {
if((results=query->factory->execute(query, model)))
librdf_query_add_query_result(query, results);
}
return results;
}
/**
* librdf_query_get_limit:
* @query: #librdf_query query object
*
* Get the query-specified limit on results.
*
* This is the limit given in the query on the number of results allowed.
*
* Return value: integer >=0 if a limit is given, otherwise <0
**/
int
librdf_query_get_limit(librdf_query *query)
{
if(query->factory->get_limit)
return query->factory->get_limit(query);
return -1;
}
/**
* librdf_query_set_limit:
* @query: #librdf_query query object
* @limit: the limit on results, >=0 to set a limit, <0 to have no limit
*
* Set the query-specified limit on results.
*
* This is the limit given in the query on the number of results allowed.
*
* Return value: non-0 on failure
**/
int
librdf_query_set_limit(librdf_query *query, int limit)
{
if(query->factory->set_limit) {
query->factory->set_limit(query, limit);
return 0;
}
return -1;
}
/**
* librdf_query_get_offset:
* @query: #librdf_query query object
*
* Get the query-specified offset on results.
*
* This is the offset given in the query on the number of results allowed.
*
* Return value: integer >=0 if a offset is given, otherwise <0
**/
int
librdf_query_get_offset(librdf_query *query)
{
if(query->factory->get_offset)
return query->factory->get_offset(query);
return -1;
}
/**
* librdf_query_set_offset:
* @query: #librdf_query query object
* @offset: offset for results, >=0 to set an offset, <0 to have no offset
*
* Set the query-specified offset on results.
*
* This is the offset given in the query on the number of results allowed.
*
* Return value: non-0 on failure
**/
int
librdf_query_set_offset(librdf_query *query, int offset)
{
if(query->factory->set_offset) {
query->factory->set_offset(query, offset);
return 0;
}
return -1;
}
#endif
/* TEST CODE */
#ifdef STANDALONE
/* one more prototype */
int main(int argc, char *argv[]);
#define DATA "@prefix ex: <http://example.org/> .\
ex:fido a ex:Dog ;\
ex:label \"Fido\" .\
"
#define DATA_LANGUAGE "turtle"
#define DATA_BASE_URI "http://example.org/"
#define QUERY_STRING "select ?x where (?x rdf:type ?y)";
#define QUERY_LANGUAGE "rdql"
#define VARIABLES_COUNT 1
int
main(int argc, char *argv[])
{
librdf_query* query;
librdf_query_results* results;
librdf_model* model;
librdf_storage* storage;
librdf_parser* parser;
librdf_uri *uri;
const char *program=librdf_basename((const char*)argv[0]);
librdf_world *world;
librdf_uri* format_uri;
size_t string_length;
unsigned char *string;
const char *query_string=QUERY_STRING;
world=librdf_new_world();
librdf_world_open(world);
/* create model and storage */
if(1) {
/* test in memory */
storage=librdf_new_storage(world, NULL, NULL, NULL);
} else {
/* test on disk */
storage=librdf_new_storage(world, "hashes", "test", "hash-type='bdb',dir='.',write='yes',new='yes',contexts='yes'");
}
if(!storage) {
fprintf(stderr, "%s: Failed to create new storage\n", program);
return(1);
}
fprintf(stderr, "%s: Creating model\n", program);
model=librdf_new_model(world, storage, NULL);
if(!model) {
fprintf(stderr, "%s: Failed to create new model\n", program);
return(1);
}
/* read the example data in */
uri=librdf_new_uri(world, (const unsigned char*)DATA_BASE_URI);
parser=librdf_new_parser(world, DATA_LANGUAGE, NULL, NULL);
librdf_parser_parse_string_into_model(parser, (const unsigned char*)DATA,
uri, model);
librdf_free_parser(parser);
librdf_free_uri(uri);
fprintf(stdout, "%s: Creating query\n", program);
query=librdf_new_query(world, QUERY_LANGUAGE,
NULL, (const unsigned char*)query_string, NULL);
if(!query) {
fprintf(stderr, "%s: Failed to create new query\n", program);
return(1);
}
/* do the query */
if(!(results=librdf_model_query_execute(model, query))) {
fprintf(stderr, "%s: Query of model with '%s' failed\n",
program, query_string);
return 1;
}
/* print the results */
while(!librdf_query_results_finished(results)) {
const char **names=NULL;
librdf_node* values[VARIABLES_COUNT];
if(librdf_query_results_get_bindings(results, &names, values))
break;
fputs("result: [", stdout);
if(names) {
int i;
for(i=0; names[i]; i++) {
fprintf(stdout, "%s=", names[i]);
if(values[i]) {
librdf_node_print(values[i], stdout);
librdf_free_node(values[i]);
} else
fputs("NULL", stdout);
if(names[i+1])
fputs(", ", stdout);
}
}
fputs("]\n", stdout);
librdf_query_results_next(results);
}
fprintf(stdout, "%s: Query returned %d results\n", program,
librdf_query_results_get_count(results));
librdf_free_query_results(results);
fprintf(stdout, "%s: Executing a second time\n", program);
if(!(results=librdf_model_query_execute(model, query))) {
fprintf(stderr, "%s: Second query of model with '%s' failed\n",
program, query_string);
return 1;
}
format_uri=librdf_new_uri(world, (unsigned const char*)"http://www.w3.org/TR/2004/WD-rdf-sparql-XMLres-20041221/");
string_length=0;
string=librdf_query_results_to_counted_string(results,
format_uri, NULL,
&string_length);
fprintf(stdout, "%s: Got query results string of length %d\n", program,
(int)string_length);
librdf_free_uri(format_uri);
free(string);
librdf_free_query_results(results);
fprintf(stdout, "%s: Freeing query\n", program);
librdf_free_query(query);
librdf_free_model(model);
librdf_free_storage(storage);
librdf_free_world(world);
/* keep gcc -Wall happy */
return(0);
}
#endif