[tracker] Import rasqal r14939 into repository
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Subject: [tracker] Import rasqal r14939 into repository
- Date: Thu, 16 Apr 2009 09:24:07 -0400 (EDT)
commit 0bd40670f86e1dd20890429f23d2a04eba6a5bc5
Author: Jürg Billeter <j bitron ch>
Date: Thu Apr 9 10:42:24 2009 +0200
Import rasqal r14939 into repository
---
configure.ac | 29 +-
po/POTFILES.skip | 2 +
src/Makefile.am | 2 +
src/rasqal/Makefile.am | 95 +
src/rasqal/fix-bison | 65 +
src/rasqal/fix-flex | 84 +
src/rasqal/rasqal.h | 1368 ++++++++++++
src/rasqal/rasqal_algebra.c | 1403 +++++++++++++
src/rasqal/rasqal_config.h | 2 +
src/rasqal/rasqal_datetime.c | 802 ++++++++
src/rasqal/rasqal_decimal.c | 941 +++++++++
src/rasqal/rasqal_engine.c | 1783 ++++++++++++++++
src/rasqal/rasqal_engine_algebra.c | 398 ++++
src/rasqal/rasqal_engine_sort.c | 375 ++++
src/rasqal/rasqal_expr.c | 2547 +++++++++++++++++++++++
src/rasqal/rasqal_feature.c | 224 ++
src/rasqal/rasqal_general.c | 1128 ++++++++++
src/rasqal/rasqal_graph.c | 459 +++++
src/rasqal/rasqal_graph_pattern.c | 864 ++++++++
src/rasqal/rasqal_internal.h | 1200 +++++++++++
src/rasqal/rasqal_literal.c | 3198 +++++++++++++++++++++++++++++
src/rasqal/rasqal_map.c | 319 +++
src/rasqal/rasqal_query.c | 2382 +++++++++++++++++++++
src/rasqal/rasqal_query_results.c | 1425 +++++++++++++
src/rasqal/rasqal_query_transform.c | 1320 ++++++++++++
src/rasqal/rasqal_raptor.c | 816 ++++++++
src/rasqal/rasqal_redland.c | 474 +++++
src/rasqal/rasqal_result_formats.c | 676 ++++++
src/rasqal/rasqal_row.c | 509 +++++
src/rasqal/rasqal_rowsource.c | 712 +++++++
src/rasqal/rasqal_rowsource_empty.c | 194 ++
src/rasqal/rasqal_rowsource_filter.c | 241 +++
src/rasqal/rasqal_rowsource_join.c | 677 ++++++
src/rasqal/rasqal_rowsource_project.c | 410 ++++
src/rasqal/rasqal_rowsource_rowsequence.c | 464 +++++
src/rasqal/rasqal_rowsource_sort.c | 260 +++
src/rasqal/rasqal_rowsource_triples.c | 720 +++++++
src/rasqal/rasqal_rowsource_union.c | 579 ++++++
src/rasqal/rasqal_skiplist.c | 604 ++++++
src/rasqal/rasqal_sparql_xml.c | 1067 ++++++++++
src/rasqal/rasqal_triples_source.c | 236 +++
src/rasqal/rasqal_variable.c | 688 +++++++
src/rasqal/rasqal_xsd_datatypes.c | 981 +++++++++
src/rasqal/rdql_common.h | 63 +
src/rasqal/rdql_lexer.l | 1238 +++++++++++
src/rasqal/rdql_parser.y | 937 +++++++++
src/rasqal/sparql_common.h | 63 +
src/rasqal/sparql_lexer.l | 1610 +++++++++++++++
src/rasqal/sparql_parser.y | 3068 +++++++++++++++++++++++++++
src/rasqal/strcasecmp.c | 118 ++
src/rasqal/win32_rasqal_config.h | 129 ++
51 files changed, 39948 insertions(+), 1 deletions(-)
diff --git a/configure.ac b/configure.ac
index 4e4cdb7..dfa89a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -209,10 +209,36 @@ AC_SUBST(UUID_CFLAGS)
AC_SUBST(UUID_LIBS)
# Check for Raptor
-PKG_CHECK_MODULES(RAPTOR, [raptor >= 1.4.17])
+PKG_CHECK_MODULES(RAPTOR, [raptor >= 1.4.18])
AC_SUBST(RAPTOR_CFLAGS)
AC_SUBST(RAPTOR_LIBS)
+AC_PROG_LEX
+if test "$LEX" = :; then
+ AC_MSG_ERROR([flex not found but required])
+fi
+
+AC_CHECK_PROGS(YACC, 'bison -y' byacc yacc, :)
+if test "$YACC" = :; then
+ AC_MSG_ERROR([bison not found but required])
+fi
+
+AC_CHECK_FUNCS(strcasecmp)
+
+AC_DEFINE_UNQUOTED(RASQAL_VERSION_MAJOR, 0, [Major version number])
+AC_DEFINE_UNQUOTED(RASQAL_VERSION_MINOR, 9, [Minor version number])
+AC_DEFINE_UNQUOTED(RASQAL_VERSION_RELEASE, 17, [Release version number])
+AC_DEFINE_UNQUOTED(RASQAL_VERSION_DECIMAL, 917, [Release version as a decimal])
+AC_DEFINE([RAPTOR_TRIPLES_SOURCE_RAPTOR], 1, [Use raptor to provide triples])
+AC_DEFINE(RASQAL_REGEX_POSIX, 1, [Use posix regex library])
+AC_DEFINE([RASQAL_DECIMAL_NONE], 1, [Decimal without a library])
+AC_DEFINE(RASQAL_QUERY_RDQL, 1, [Building RDQL query])
+AC_DEFINE(RASQAL_QUERY_LAQRS, 1, [Building LAQRS query])
+AC_DEFINE(RASQAL_QUERY_SPARQL, 1, [Building SPARQL query])
+AM_CONDITIONAL(RASQAL_QUERY_RDQL, true)
+AM_CONDITIONAL(RASQAL_QUERY_LAQRS, true)
+AM_CONDITIONAL(RASQAL_QUERY_SPARQL, true)
+
# Check we have the DBUS binding tool we need
AC_PATH_PROG(DBUSBINDINGTOOL, dbus-binding-tool)
if test -z $DBUSBINDINGTOOL; then
@@ -1377,6 +1403,7 @@ AC_CONFIG_FILES([
src/libtracker/Makefile
src/Makefile
src/qdbm/Makefile
+ src/rasqal/Makefile
src/tracker-applet/Makefile
src/tracker-applet/tracker-applet.desktop.in
src/trackerd/Makefile
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 1c3deb0..43a1ef1 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -2,6 +2,8 @@
# Please keep this file sorted alphabetically.
data/trackerd.desktop.in
+src/rasqal/rdql_parser.c
+src/rasqal/sparql_parser.c
src/tracker-applet/tracker-applet.desktop.in
src/tracker-preferences/tracker-preferences.desktop.in
src/tracker-search-tool/tracker-search-tool.desktop.in
diff --git a/src/Makefile.am b/src/Makefile.am
index 138d238..bbb6553 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,6 +32,7 @@ SUBDIRS = \
libstemmer \
$(build_qdbm) \
$(build_libinotify) \
+ rasqal \
libtracker-common \
libtracker-db \
libtracker-data \
@@ -51,6 +52,7 @@ DIST_SUBDIRS = \
libstemmer \
qdbm \
libinotify \
+ rasqal \
libtracker-common \
libtracker-db \
libtracker-data \
diff --git a/src/rasqal/Makefile.am b/src/rasqal/Makefile.am
new file mode 100644
index 0000000..fbf4bf3
--- /dev/null
+++ b/src/rasqal/Makefile.am
@@ -0,0 +1,95 @@
+# -*- Mode: Makefile -*-
+#
+# Makefile.am - automake file for Rasqal RDF query language library
+#
+# Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+# Copyright (C) 2003-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.
+#
+
+noinst_LTLIBRARIES = librasqal.la
+
+noinst_HEADERS = rasqal.h rasqal_internal.h rasqal_config.h win32_rasqal_config.h
+
+MAINTAINERCLEANFILES=rdql_lexer.c rdql_lexer.h \
+rdql_parser.c rdql_parser.h rdql_parser.output \
+sparql_lexer.c sparql_lexer.h \
+sparql_parser.c sparql_parser.h sparql_parser.output
+
+INCLUDES = \
+ -DRASQAL_INTERNAL=1 \
+ -DVERSION=\""0.9.17"\" \
+ $(RAPTOR_CFLAGS)
+
+librasqal_la_SOURCES = \
+rasqal_algebra.c \
+rasqal_expr.c rasqal_general.c rasqal_query.c rasqal_query_results.c \
+rasqal_engine.c rasqal_raptor.c rasqal_literal.c \
+rasqal_graph_pattern.c rasqal_map.c rasqal_feature.c \
+rasqal_result_formats.c rasqal_xsd_datatypes.c rasqal_decimal.c \
+rasqal_datetime.c rasqal_rowsource.c rasqal_sparql_xml.c \
+rasqal_variable.c rasqal_rowsource_empty.c rasqal_rowsource_union.c \
+rasqal_rowsource_rowsequence.c rasqal_query_transform.c rasqal_row.c \
+rasqal_engine_algebra.c rasqal_triples_source.c \
+rasqal_rowsource_triples.c rasqal_rowsource_filter.c \
+rasqal_rowsource_sort.c rasqal_engine_sort.c \
+rasqal_rowsource_project.c rasqal_rowsource_join.c
+
+if RASQAL_QUERY_RDQL
+librasqal_la_SOURCES += rdql_lexer.c rdql_lexer.h \
+rdql_parser.c rdql_parser.h rdql_common.h
+endif
+if RASQAL_QUERY_SPARQL
+librasqal_la_SOURCES += sparql_lexer.c sparql_lexer.h \
+sparql_parser.c sparql_parser.h sparql_common.h
+endif
+
+librasqal_la_LIBADD = $(RAPTOR_LIBS)
+
+
+EXTRA_DIST= \
+rdql_lexer.l rdql_parser.y \
+sparql_lexer.l sparql_parser.y \
+fix-flex fix-bison \
+rasqal.vapi
+
+LEX= LEX@
+YACC= YACC@
+
+# Actually it needs rdql_parser.h but nevermind
+rdql_lexer.c: $(srcdir)/rdql_lexer.l rdql_parser.c $(srcdir)/fix-flex
+ $(LEX) -o$@ $(srcdir)/rdql_lexer.l
+ $(PERL) $(srcdir)/fix-flex $@ > rdql_lexer.t
+ mv rdql_lexer.t $@
+
+rdql_parser.c: $(srcdir)/rdql_parser.y $(srcdir)/fix-bison
+ $(YACC) -b rdql_parser -p rdql_parser_ -d -v $(srcdir)/rdql_parser.y
+ $(PERL) $(srcdir)/fix-bison rdql_parser.tab.c > $@
+ mv rdql_parser.tab.h rdql_parser.h
+ rm -f rdql_parser.tab.c
+
+# Actually it needs sparql_parser.h but nevermind
+sparql_lexer.c: $(srcdir)/sparql_lexer.l sparql_parser.c $(srcdir)/fix-flex
+ $(LEX) -o$@ $(srcdir)/sparql_lexer.l
+ $(PERL) $(srcdir)/fix-flex $@ > sparql_lexer.t
+ mv sparql_lexer.t $@
+
+sparql_parser.c: $(srcdir)/sparql_parser.y $(srcdir)/fix-bison
+ $(YACC) -b sparql_parser -p sparql_parser_ -d -v $(srcdir)/sparql_parser.y
+ $(PERL) $(srcdir)/fix-bison sparql_parser.tab.c > $@
+ mv sparql_parser.tab.h sparql_parser.h
+ rm -f sparql_parser.tab.c
+
diff --git a/src/rasqal/fix-bison b/src/rasqal/fix-bison
new file mode 100755
index 0000000..188118b
--- /dev/null
+++ b/src/rasqal/fix-bison
@@ -0,0 +1,65 @@
+#!/usr/bin/perl
+#
+# $Id: fix-bison 14688 2008-10-10 06:51:17Z laalto $
+#
+# Format output generated by bison
+#
+# Usage:
+# bison -b brql_parser -p brql_parser_ -d -v brql_parser.y
+# perl fix-bison brql_parser.tab.c > $tmp
+# mv $tmp brql_parser.tab.c
+#
+# Copyright (C) 2004-2006, David Beckett http://purl.org/net/dajobe/
+# Copyright (C) 2004, University of Bristol, UK http://www.bristol.ac.uk/
+#
+
+my $seen_yyerrlab1=0;
+my $line_offset=1; # #line directives always refer to the NEXT line
+while(<>) {
+ # HACK: Pass YYPARSE_PARAM* to %destructors
+ s/(yydestruct\s*\()const/$1void *YYPARSE_PARAM, const/; # yydestruct() definition sig 1
+ if(/(yydestruct\s*\()yymsg(.*)$/) { # yydestruct() defintion sig 2
+ print "$1YYPARSE_PARAM, yymsg$2\n void *YYPARSE_PARAM;\n";
+ $line_offset++; # added a line
+ next;
+ }
+ s/(yydestruct\s*\()(".*)$/$1YYPARSE_PARAM, $2/; # yydestruct() calls
+
+ # Remove code that causes a warning
+ if(/Suppress GCC warning that yyerrlab1/) {
+ do {
+ $_=<>;
+ $line_offset--; # skipped a line
+ } while(!/^\#endif/);
+ $line_offset--; # skipped a line
+ next;
+ }
+
+ $seen_yyerrlab1=1 if /goto yyerrlab1/;
+
+ s/^yyerrlab1:// unless $seen_yyerrlab1;
+
+ # Do not use macro name for a temporary variable
+ s/unsigned int yylineno = /unsigned int yylineno_tmp = /;
+ s/yyrule - 1, yylineno\)/yyrule - 1, yylineno_tmp\)/;
+
+ # Do not (re)define prototypes that the system did better
+ if(m%^void \*malloc\s*\(%) {
+ $line_offset--; # skipped a line
+ next;
+ }
+ if(m%^void free\s*\(%) {
+ $line_offset--; # skipped a line
+ next;
+ }
+
+ # Suppress warnings about empty declarations
+ s/(^static int .*_init_globals.*);$/$1/;
+
+ # Fixup pending filename renaming, see above.
+ # Fix line numbers.
+ my $line=$. +$line_offset;
+ s/^(\#line) \d+ (.*)\.tab\.c/$1 $line $2.c/;
+
+ print;
+}
diff --git a/src/rasqal/fix-flex b/src/rasqal/fix-flex
new file mode 100755
index 0000000..54be711
--- /dev/null
+++ b/src/rasqal/fix-flex
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+#
+# $Id: fix-flex 14390 2008-08-25 11:18:52Z laalto $
+#
+# Format output generated by flex 2.5.31
+#
+# Usage:
+# flex -o$output $input
+# perl fix-flex $output > $tmp
+# mv $tmp $output
+#
+# Copyright (C) 2004-2006, David Beckett http://purl.org/net/dajobe/
+# Copyright (C) 2004, University of Bristol, UK http://www.bristol.ac.uk/
+#
+
+my $line_offset=1; # #line directives always refer to the NEXT line
+
+print <<'EOT';
+#ifdef HAVE_CONFIG_H
+#include <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+EOT
+$line_offset+=8; # added 8 lines to output
+
+my $prefix=undef;
+
+while(<>) {
+ # Remove generated yy_fatal_error declaration and definition to avoid warnings about unused/non-defined static function
+ # declaration
+ if(/^static void yy_fatal_error\s*\(.*\)\s*\;\s*$/) {
+ $line_offset--; # skipped 1 line
+ next;
+ }
+ # definition
+ if(/^static void yy_fatal_error\s*\(.*\)\s*[^\;]\s*$/) {
+ do {
+ $_=<>;
+ $line_offset--; # skipped 1 line
+ } while(!/^}/);
+ $line_offset--; # skipped 1 line
+ next;
+ }
+
+ # Replace calls to yy_fatal_error("msg", yyscanner) to YY_FATAL_ERROR("msg") macro
+ s/(^\s*)yy_fatal_error\s*\(\s*(\".*\")\s*,\s*yyscanner\s*\)/$1YY_FATAL_ERROR($2)/;
+
+ # flex has %option nounistd however it does not work in 2.5.31
+ # It is safe to add yet another wrapper.
+ if(m%^(\#include \<unistd.h\>)$%) {
+ $_=<<"EOT";
+#ifndef YY_NO_UNISTD_H
+$1
+#endif
+EOT
+ $line_offset+=2; # added 2 lines to output
+ }
+
+ # Add $prefix_cleanup() call at the end of $prefix_lex_destroy()
+ # find the start of lex_destroy function definition and capture prefix
+ if(/^int\s+(\S+)_lex_destroy\s*\(.*\)\s*[^\;]\s*$/) { $prefix=$1; }
+ # look for lexer_free(yyscanner, yyscanner) statement within the function and place the cleanup call before it
+ if($prefix) {
+ if(/(^\s*)(${prefix}_free\s*\(\s*yyscanner\s*,\s*yyscanner\s*\)\s*\;)\s*$/) {
+ $_=<<"EOT";
+$1/* clean up leaks if any before freeing yyscanner */
+$1${prefix}_cleanup(yyscanner);
+$1$2
+EOT
+ $line_offset+=2; # added 2 lines to output
+ $prefix=undef; # lex_destroy() patched
+ }
+ }
+
+ # Fix .[ch] line references because we have added lines to it
+ my $line = $. +$line_offset;
+ s/^#line \d+ (\".*\.[ch]\")/#line $line $1/;
+
+ print;
+}
diff --git a/src/rasqal/rasqal.h b/src/rasqal/rasqal.h
new file mode 100644
index 0000000..225e34e
--- /dev/null
+++ b/src/rasqal/rasqal.h
@@ -0,0 +1,1368 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal.h - Rasqal RDF Query library interfaces and definition
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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.
+ *
+ */
+
+
+
+#ifndef RASQAL_H
+#define RASQAL_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * RASQAL_API:
+ *
+ * Macro for wrapping API function call declarations.
+ *
+ */
+#ifndef RASQAL_API
+# ifdef WIN32
+# ifdef __GNUC__
+# undef _declspec
+# define _declspec(x) __declspec(x)
+# endif
+# ifdef RASQAL_STATIC
+# define RASQAL_API
+# else
+# ifdef RASQAL_INTERNAL
+# define RASQAL_API _declspec(dllexport)
+# else
+# define RASQAL_API _declspec(dllimport)
+# endif
+# endif
+# else
+# define RASQAL_API
+# endif
+#endif
+
+/* Use gcc 3.1+ feature to allow marking of deprecated API calls.
+ * This gives a warning during compiling.
+ */
+#if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3
+#ifdef __APPLE_CC__
+/* OSX gcc cpp-precomp is broken */
+#define RASQAL_DEPRECATED
+#else
+#define RASQAL_DEPRECATED __attribute__((deprecated))
+#endif
+#else
+#define RASQAL_DEPRECATED
+#endif
+
+
+#ifndef LIBRDF_OBJC_FRAMEWORK
+#include <raptor.h>
+#else
+#include <Redland/raptor.h>
+#endif
+
+#ifndef RAPTOR_WORLD_DECLARED
+#define RAPTOR_WORLD_DECLARED 1
+/* Declare raptor_world type unless it is declared in raptor.h */
+typedef struct raptor_world_s raptor_world;
+#endif
+
+/* Public statics */
+RASQAL_API
+extern const char * const rasqal_short_copyright_string;
+RASQAL_API
+extern const char * const rasqal_copyright_string;
+RASQAL_API
+extern const char * const rasqal_version_string;
+RASQAL_API
+extern const unsigned int rasqal_version_major;
+RASQAL_API
+extern const unsigned int rasqal_version_minor;
+RASQAL_API
+extern const unsigned int rasqal_version_release;
+RASQAL_API
+extern const unsigned int rasqal_version_decimal;
+RASQAL_API
+extern const char * const rasqal_license_string;
+RASQAL_API
+extern const char * const rasqal_home_url_string;
+
+
+/* Public structures */
+
+#ifndef RASQAL_WORLD_DECLARED
+#define RASQAL_WORLD_DECLARED 1
+/**
+ * rasqal_world:
+ *
+ * Rasqal world class.
+ */
+typedef struct rasqal_world_s rasqal_world;
+#endif
+
+/**
+ * rasqal_query:
+ *
+ * Rasqal query class.
+ */
+typedef struct rasqal_query_s rasqal_query;
+
+/**
+ * rasqal_query_results:
+ *
+ * Rasqal query results class.
+ */
+typedef struct rasqal_query_results_s rasqal_query_results;
+
+
+#ifndef RASQAL_QUERY_RESULTS_FORMATTER_DECLARED
+#define RASQAL_QUERY_RESULTS_FORMATTER_DECLARED 1
+/**
+ * rasqal_query_results_formatter:
+ *
+ * Rasqal query results formatter class.
+ */
+typedef struct rasqal_query_results_formatter_s rasqal_query_results_formatter;
+#endif
+
+
+typedef struct rasqal_literal_s rasqal_literal;
+
+/**
+ * rasqal_graph_pattern:
+ *
+ * Rasqal graph pattern class.
+ */
+typedef struct rasqal_graph_pattern_s rasqal_graph_pattern;
+
+/**
+ * rasqal_algebra_node:
+ *
+ * Rasqal graph pattern class.
+ */
+typedef struct rasqal_algebra_node_s rasqal_algebra_node;
+
+/**
+ * rasqal_feature:
+ * @RASQAL_FEATURE_NO_NET: Deny network requests.
+ * @RASQAL_FEATURE_LAST: Internal.
+ *
+ * Query features.
+ *
+ * None currently defined.
+ */
+typedef enum {
+ RASQAL_FEATURE_NO_NET,
+ RASQAL_FEATURE_LAST = RASQAL_FEATURE_NO_NET
+} rasqal_feature;
+
+
+/**
+ * rasqal_prefix:
+ * @prefix: short prefix string
+ * @uri: URI associated with the prefix.
+ * @declared: Internal flag.
+ * @depth: Internal flag.
+ * @world: rasqal_world object
+ *
+ * Namespace (prefix, uri) pair.
+ *
+ * Includes internal flags used for marking when prefixes are
+ * declared and at what XML element depth when used in XML formats.
+ */
+typedef struct {
+ const unsigned char *prefix;
+ raptor_uri* uri;
+ int declared;
+ int depth;
+ rasqal_world* world;
+} rasqal_prefix;
+
+
+/**
+ * rasqal_variable_type:
+ * @RASQAL_VARIABLE_TYPE_NORMAL: The regular variable type.
+ * @RASQAL_VARIABLE_TYPE_ANONYMOUS: Anonymous variable type.
+ * @RASQAL_VARIABLE_TYPE_UNKNOWN: Internal.
+ *
+ * Rasqal variable types.
+ *
+ * ANONYMOUS can be used in queries but cannot be returned in a
+ * result.
+ */
+typedef enum {
+ RASQAL_VARIABLE_TYPE_UNKNOWN = 0,
+ RASQAL_VARIABLE_TYPE_NORMAL = 1,
+ RASQAL_VARIABLE_TYPE_ANONYMOUS = 2
+} rasqal_variable_type;
+
+
+/* forward reference */
+struct rasqal_expression_s;
+
+/**
+ * rasqal_variable:
+ * @name: Variable name.
+ * @value: Variable value or NULL if unbound.
+ * @offset: Internal.
+ * @type: Variable type.
+ * @expression: Expression when the variable is a computed SELECT expression
+ *
+ * Binding between a variable name and a value.
+ *
+ * Includes internal field @offset for recording the offset into the
+ * (internal) rasqal_query variables array.
+ */
+typedef struct {
+ const unsigned char *name;
+ rasqal_literal* value;
+ int offset;
+ rasqal_variable_type type;
+ struct rasqal_expression_s* expression;
+} rasqal_variable;
+
+
+/**
+ * rasqal_data_graph_flags:
+ * @RASQAL_DATA_GRAPH_NONE: Internal.
+ * @RASQAL_DATA_GRAPH_NAMED: Graphs with a source and name.
+ * @RASQAL_DATA_GRAPH_BACKGROUND: Graphs with a source only.
+ *
+ * Flags for the type of #rasqal_data_graph.
+ *
+ * These are used by rasqal_query_add_data_graph(). See #rasqal_data_graph.
+ */
+typedef enum {
+ RASQAL_DATA_GRAPH_NONE = 0,
+ RASQAL_DATA_GRAPH_NAMED = 1,
+ RASQAL_DATA_GRAPH_BACKGROUND = 2,
+} rasqal_data_graph_flags;
+
+
+/**
+ * rasqal_data_graph:
+ * @uri: source URI
+ * @name_uri: name of graph for %RASQAL_DATA_NAMED
+ * @flags: %RASQAL_DATA_GRAPH_NAMED or %RASQAL_DATA_GRAPH_BACKGROUND
+ * @world: rasqal_world object
+ *
+ * A source of RDF data for querying.
+ *
+ * The #uri is the original source (base URI) of the content. It may
+ * also have an additional name @name_uri as long as @flags is
+ * %RASQAL_DATA_NAMED
+ */
+typedef struct {
+ raptor_uri* uri;
+ raptor_uri* name_uri;
+ int flags;
+ rasqal_world* world;
+} rasqal_data_graph;
+
+
+/**
+ * rasqal_literal_type:
+ * @RASQAL_LITERAL_BLANK: RDF blank node literal (SPARQL r:bNode)
+ * @RASQAL_LITERAL_URI: RDF URI Literal (SPARQL r:URI)
+ * @RASQAL_LITERAL_STRING: RDF Literal / xsd:string (SPARQL r:Literal)
+ * @RASQAL_LITERAL_BOOLEAN: Boolean literal xsd:boolean.
+ * @RASQAL_LITERAL_INTEGER: Integer literal xsd:integer.
+ * @RASQAL_LITERAL_DOUBLE: Double floating point literal xsd:double.
+ * @RASQAL_LITERAL_FLOAT: Floating point literal xsd:float.
+ * @RASQAL_LITERAL_DECIMAL: Decimal integer xsd:decimal.
+ * @RASQAL_LITERAL_DATETIME: Date/Time literal xsd:dateTime.
+ * @RASQAL_LITERAL_PATTERN: Pattern literal for a regex.
+ * @RASQAL_LITERAL_QNAME: XML Qname literal.
+ * @RASQAL_LITERAL_VARIABLE: Variable literal.
+ * @RASQAL_LITERAL_UNKNOWN: Internal.
+ * @RASQAL_LITERAL_FIRST_XSD: Internal.
+ * @RASQAL_LITERAL_LAST_XSD: Internal.
+ * @RASQAL_LITERAL_LAST: Internal.
+ *
+ * Types of literal.
+ *
+ * The order in the enumeration is significant as it encodes
+ * the SPARQL term ordering conditions:
+ *
+ * Blank Nodes << IRIs << RDF literals << typed literals
+ *
+ * which coresponds to in enum values
+ *
+ * BLANK << URI << STRING <<
+ * (BOOLEAN | INTEGER | DOUBLE | FLOAT | DECIMAL | DATETIME)
+ *
+ * (RASQAL_LITERAL_FIRST_XSD ... RASQAL_LITERAL_LAST_XSD)
+ *
+ * Not used (internal): PATTERN, QNAME, VARIABLE
+ *
+ * See rasqal_literal_compare() when used with flags
+ * %RASQAL_COMPARE_XQUERY
+ */
+typedef enum {
+ /* internal */
+ RASQAL_LITERAL_UNKNOWN,
+ RASQAL_LITERAL_BLANK,
+ RASQAL_LITERAL_URI,
+ RASQAL_LITERAL_STRING,
+ RASQAL_LITERAL_BOOLEAN,
+ RASQAL_LITERAL_INTEGER,
+ RASQAL_LITERAL_DOUBLE,
+ RASQAL_LITERAL_FLOAT,
+ RASQAL_LITERAL_DECIMAL,
+ RASQAL_LITERAL_DATETIME,
+ /* internal */
+ RASQAL_LITERAL_FIRST_XSD = RASQAL_LITERAL_STRING,
+ /* internal */
+ RASQAL_LITERAL_LAST_XSD = RASQAL_LITERAL_DATETIME,
+ RASQAL_LITERAL_PATTERN,
+ RASQAL_LITERAL_QNAME,
+ RASQAL_LITERAL_VARIABLE,
+ /* internal */
+ RASQAL_LITERAL_LAST= RASQAL_LITERAL_VARIABLE
+} rasqal_literal_type;
+
+
+/**
+ * rasqal_xsd_decimal:
+ *
+ * Rasqal XSD Decimal class.
+ */
+typedef struct rasqal_xsd_decimal_s rasqal_xsd_decimal;
+
+/**
+ * rasqal_literal:
+ * @usage: Usage count.
+ * @type: Type of literal.
+ * @string: String form of literal for literal types UTF-8 string, pattern, qname, blank, double, float, decimal, datetime.
+ * @string_len: Length of @string.
+ * @value: Alternate value content.
+ * @language: Language for string literal type.
+ * @datatype: Datatype for string literal type.
+ * @flags: Flags for literal types
+ *
+ * Rasqal literal class.
+ *
+ */
+struct rasqal_literal_s {
+ int usage;
+ rasqal_literal_type type;
+ /* UTF-8 string, pattern, qname, blank, double, float, decimal, datetime */
+ const unsigned char *string;
+ unsigned int string_len;
+
+ union {
+ /* integer and boolean types */
+ int integer;
+ /* double and float */
+ double floating;
+ /* uri (can be temporarily NULL if a qname, see flags below) */
+ raptor_uri* uri;
+ /* variable */
+ rasqal_variable* variable;
+ /* decimal */
+ rasqal_xsd_decimal* decimal;
+ } value;
+
+ /* for string */
+ const char *language;
+ raptor_uri *datatype;
+
+ /* various flags for literal types:
+ * pattern regex flags
+ * string datatype of qname
+ * uri qname of URI not yet expanded (temporary)
+ */
+ const unsigned char *flags;
+
+ /* parent XSD type if any or RASQAL_LITERAL_UNKNOWN */
+ rasqal_literal_type parent_type;
+
+ /* world object */
+ rasqal_world *world;
+};
+
+
+/**
+ * rasqal_op:
+ * @RASQAL_EXPR_AND: Expression for AND(A, B)
+ * @RASQAL_EXPR_OR: Expression for OR(A, B)
+ * @RASQAL_EXPR_EQ: Expression for A equals B
+ * @RASQAL_EXPR_NEQ: Expression for A not equals B.
+ * @RASQAL_EXPR_LT: Expression for A less than B.
+ * @RASQAL_EXPR_GT: Expression for A greather than B.
+ * @RASQAL_EXPR_LE: Expression for A less than or equal to B.
+ * @RASQAL_EXPR_GE: Expression for A greater than or equal to B.
+ * @RASQAL_EXPR_UMINUS: Expression for -A.
+ * @RASQAL_EXPR_PLUS: Expression for +A.
+ * @RASQAL_EXPR_MINUS: Expression for A-B.
+ * @RASQAL_EXPR_STAR: Expression for A*B.
+ * @RASQAL_EXPR_SLASH: Expression for A/B.
+ * @RASQAL_EXPR_REM: Expression for A/B remainder.
+ * @RASQAL_EXPR_STR_EQ: Expression for A string equals B.
+ * @RASQAL_EXPR_STR_NEQ: Expression for A string not-equals B.
+ * @RASQAL_EXPR_STR_MATCH: Expression for string A matches literal regex B with flags.
+ * @RASQAL_EXPR_STR_NMATCH: Expression for string A not-matches literal regex B with flags.
+ * @RASQAL_EXPR_REGEX: Expression for string A matches expression regex B with flags.
+ * @RASQAL_EXPR_TILDE: Expression for binary not A.
+ * @RASQAL_EXPR_BANG: Expression for logical not A.
+ * @RASQAL_EXPR_LITERAL: Expression for a #rasqal_literal.
+ * @RASQAL_EXPR_FUNCTION: Expression for a function A with arguments (B...).
+ * @RASQAL_EXPR_BOUND: Expression for SPARQL ISBOUND(A).
+ * @RASQAL_EXPR_STR: Expression for SPARQL STR(A).
+ * @RASQAL_EXPR_LANG: Expression for SPARQL LANG(A).
+ * @RASQAL_EXPR_LANGMATCHES: Expression for SPARQL LANGMATCHES(A, B).
+ * @RASQAL_EXPR_DATATYPE: Expression for SPARQL DATATYPE(A).
+ * @RASQAL_EXPR_ISURI: Expression for SPARQL ISURI(A).
+ * @RASQAL_EXPR_ISBLANK: Expression for SPARQL ISBLANK(A).
+ * @RASQAL_EXPR_ISLITERAL: Expression for SPARQL ISLITERAL(A).
+ * @RASQAL_EXPR_CAST: Expression for cast literal A to type B.
+ * @RASQAL_EXPR_ORDER_COND_ASC: Expression for SPARQL order condition ascending.
+ * @RASQAL_EXPR_ORDER_COND_DESC: Expression for SPARQL order condition descending.
+ * @RASQAL_EXPR_GROUP_COND_ASC: Expression for LAQRS group condition ascending.
+ * @RASQAL_EXPR_GROUP_COND_DESC: Expression for LAQRS group condition descending.
+ * @RASQAL_EXPR_COUNT: Expression for LAQRS select COUNT()
+ * @RASQAL_EXPR_VARSTAR: Expression for LAQRS select Variable *
+ * @RASQAL_EXPR_SAMETERM: Expression for SPARQL sameTerm
+ * @RASQAL_EXPR_UNKNOWN: Internal
+ * @RASQAL_EXPR_LAST: Internal
+ *
+ * Rasqal expression operators. A mixture of unary, binary and
+ * tertiary operators (string matches). Also includes casting and
+ * two ordering operators from ORDER BY in SPARQL.
+ */
+typedef enum {
+ /* internal */
+ RASQAL_EXPR_UNKNOWN,
+ RASQAL_EXPR_AND,
+ RASQAL_EXPR_OR,
+ RASQAL_EXPR_EQ,
+ RASQAL_EXPR_NEQ,
+ RASQAL_EXPR_LT,
+ RASQAL_EXPR_GT,
+ RASQAL_EXPR_LE,
+ RASQAL_EXPR_GE,
+ RASQAL_EXPR_UMINUS,
+ RASQAL_EXPR_PLUS,
+ RASQAL_EXPR_MINUS,
+ RASQAL_EXPR_STAR,
+ RASQAL_EXPR_SLASH,
+ RASQAL_EXPR_REM,
+ RASQAL_EXPR_STR_EQ,
+ RASQAL_EXPR_STR_NEQ,
+ RASQAL_EXPR_STR_MATCH,
+ RASQAL_EXPR_STR_NMATCH,
+ RASQAL_EXPR_TILDE,
+ RASQAL_EXPR_BANG,
+ RASQAL_EXPR_LITERAL,
+ RASQAL_EXPR_FUNCTION,
+ RASQAL_EXPR_BOUND,
+ RASQAL_EXPR_STR,
+ RASQAL_EXPR_LANG,
+ RASQAL_EXPR_DATATYPE,
+ RASQAL_EXPR_ISURI,
+ RASQAL_EXPR_ISBLANK,
+ RASQAL_EXPR_ISLITERAL,
+ RASQAL_EXPR_CAST,
+ RASQAL_EXPR_ORDER_COND_ASC,
+ RASQAL_EXPR_ORDER_COND_DESC,
+ RASQAL_EXPR_LANGMATCHES,
+ RASQAL_EXPR_REGEX,
+ RASQAL_EXPR_GROUP_COND_ASC,
+ RASQAL_EXPR_GROUP_COND_DESC,
+ RASQAL_EXPR_COUNT,
+ RASQAL_EXPR_VARSTAR,
+ RASQAL_EXPR_SAMETERM,
+ /* internal */
+ RASQAL_EXPR_LAST= RASQAL_EXPR_SAMETERM
+} rasqal_op;
+
+
+/**
+ * rasqal_expression:
+ *
+ * expression (arg1), unary op (arg1), binary op (arg1,arg2),
+ * literal or variable
+ */
+struct rasqal_expression_s {
+ int usage; /* reference count - 1 for itself */
+
+ rasqal_op op;
+ struct rasqal_expression_s* arg1;
+ struct rasqal_expression_s* arg2;
+ struct rasqal_expression_s* arg3; /* optional 3rd arg for EXPR_REGEX */
+ rasqal_literal* literal;
+ unsigned char *value; /* UTF-8 value */
+
+ /* for extension function qname(args...) and cast-to-uri */
+ raptor_uri* name;
+ raptor_sequence* args;
+
+ /* rasqal_world object */
+ rasqal_world* world;
+};
+typedef struct rasqal_expression_s rasqal_expression;
+
+
+/**
+ * rasqal_triple_flags:
+ * @RASQAL_TRIPLE_FLAGS_EXACT: Not used.
+ * @RASQAL_TRIPLE_FLAGS_OPTIONAL: Not used.
+ * @RASQAL_TRIPLE_FLAGS_LAST: Internal.
+ *
+ * Flags for triple patterns.
+ */
+typedef enum {
+
+ /* Not used - was only used internally in the execution engine */
+ RASQAL_TRIPLE_FLAGS_EXACT=1,
+
+ /* Not used - this is now a property of a graph pattern */
+ RASQAL_TRIPLE_FLAGS_OPTIONAL=2,
+
+ RASQAL_TRIPLE_FLAGS_LAST=RASQAL_TRIPLE_FLAGS_OPTIONAL
+} rasqal_triple_flags;
+
+
+/**
+ * rasqal_triple:
+ * @subject: Triple subject.
+ * @predicate: Triple predicate.
+ * @object: Triple object.
+ * @origin: Triple origin.
+ * @flags: Or of enum #rasqal_triple_flags bits.
+ *
+ * A triple pattern or RDF triple.
+ *
+ * This is used as a triple pattern in queries and
+ * an RDF triple when generating RDF triples such as with SPARQL CONSTRUCT.
+ */
+typedef struct {
+ rasqal_literal* subject;
+ rasqal_literal* predicate;
+ rasqal_literal* object;
+ rasqal_literal* origin;
+ unsigned int flags;
+} rasqal_triple;
+
+
+/**
+ * rasqal_pattern_flags:
+ * @RASQAL_PATTERN_FLAGS_OPTIONAL: True when the graph pattern is an optional match.
+ * @RASQAL_PATTERN_FLAGS_LAST: Internal
+ *
+ * Flags for #rasqal_graph_pattern.
+ */
+typedef enum {
+ RASQAL_PATTERN_FLAGS_OPTIONAL=1,
+
+ RASQAL_PATTERN_FLAGS_LAST=RASQAL_PATTERN_FLAGS_OPTIONAL
+} rasqal_pattern_flags;
+
+
+typedef unsigned char* (*rasqal_generate_bnodeid_handler)(rasqal_query* query, void *user_data, unsigned char *user_bnodeid);
+
+
+/**
+ * rasqal_query_verb:
+ * @RASQAL_QUERY_VERB_SELECT: RDQL/SPARQL query select verb.
+ * @RASQAL_QUERY_VERB_CONSTRUCT: SPARQL query construct verb.
+ * @RASQAL_QUERY_VERB_DESCRIBE: SPARQL query describe verb.
+ * @RASQAL_QUERY_VERB_ASK: SPARQL query ask verb.
+ * @RASQAL_QUERY_VERB_DELETE: LAQRS query delete verb.
+ * @RASQAL_QUERY_VERB_INSERT: LAQRS query insert verb.
+ * @RASQAL_QUERY_VERB_UNKNOWN: Internal
+ * @RASQAL_QUERY_VERB_LAST: Internal
+ *
+ * Query main operation verbs describing the major type of query
+ * being performed.
+ */
+typedef enum {
+ /* internal */
+ RASQAL_QUERY_VERB_UNKNOWN = 0,
+ RASQAL_QUERY_VERB_SELECT = 1,
+ RASQAL_QUERY_VERB_CONSTRUCT = 2,
+ RASQAL_QUERY_VERB_DESCRIBE = 3,
+ RASQAL_QUERY_VERB_ASK = 4,
+ RASQAL_QUERY_VERB_DELETE = 5,
+ RASQAL_QUERY_VERB_INSERT = 6,
+
+ /* internal */
+ RASQAL_QUERY_VERB_LAST=RASQAL_QUERY_VERB_INSERT
+} rasqal_query_verb;
+
+
+/**
+ * rasqal_graph_pattern_operator:
+ * @RASQAL_GRAPH_PATTERN_OPERATOR_BASIC: Just triple patterns and constraints.
+ * @RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL: Set of graph patterns (ANDed) and constraints.
+ * @RASQAL_GRAPH_PATTERN_OPERATOR_UNION: Set of graph patterns (UNIONed) and constraints.
+ * @RASQAL_GRAPH_PATTERN_OPERATOR_GROUP: Set of graph patterns (ANDed) and constraints.
+ * @RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH: A graph term + a graph pattern and constraints.
+ * @RASQAL_GRAPH_PATTERN_OPERATOR_FILTER: A filter graph pattern with an expression
+ * @RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN: Internal.
+ * @RASQAL_GRAPH_PATTERN_OPERATOR_LAST: Internal.
+ *
+ * Graph pattern operators
+ */
+typedef enum {
+ RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN = 0,
+ RASQAL_GRAPH_PATTERN_OPERATOR_BASIC = 1,
+ RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL = 2,
+ RASQAL_GRAPH_PATTERN_OPERATOR_UNION = 3,
+ RASQAL_GRAPH_PATTERN_OPERATOR_GROUP = 4,
+ RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH = 5,
+ RASQAL_GRAPH_PATTERN_OPERATOR_FILTER = 6,
+
+ RASQAL_GRAPH_PATTERN_OPERATOR_LAST=RASQAL_GRAPH_PATTERN_OPERATOR_FILTER
+} rasqal_graph_pattern_operator;
+
+
+/**
+ * rasqal_graph_pattern_visit_fn:
+ * @query: #rasqal_query containing the graph pattern
+ * @gp: current graph_pattern
+ * @user_data: user data passed in
+ *
+ * User function to visit an graph_pattern and operate on it with
+ * rasqal_graph_pattern_visit() or rasqal_query_graph_pattern_visit()
+ *
+ * Return value: 0 to truncate the visit
+ */
+typedef int (*rasqal_graph_pattern_visit_fn)(rasqal_query* query, rasqal_graph_pattern* gp, void *user_data);
+
+
+/* RASQAL API */
+
+/* Public functions */
+
+RASQAL_API
+rasqal_world *rasqal_new_world(void);
+RASQAL_API
+int rasqal_world_open(rasqal_world* world);
+RASQAL_API
+void rasqal_free_world(rasqal_world* world);
+
+RASQAL_API
+void rasqal_world_set_raptor(rasqal_world* world, raptor_world* raptor_world_ptr);
+RASQAL_API
+raptor_world *rasqal_world_get_raptor(rasqal_world* world);
+
+/* Features */
+RASQAL_API
+int rasqal_features_enumerate(rasqal_world* world, const rasqal_feature feature, const char **name, raptor_uri **uri, const char **label);
+RASQAL_API
+unsigned int rasqal_get_feature_count(void);
+RASQAL_API
+rasqal_feature rasqal_feature_from_uri(rasqal_world* world, raptor_uri *uri);
+RASQAL_API
+int rasqal_feature_value_type(const rasqal_feature feature);
+
+RASQAL_API
+int rasqal_languages_enumerate(rasqal_world* world, unsigned int counter, const char **name, const char **label, const unsigned char **uri_string);
+
+RASQAL_API
+int rasqal_language_name_check(rasqal_world* world, const char *name);
+
+
+/* Query class */
+
+/* Create */
+RASQAL_API
+rasqal_query* rasqal_new_query(rasqal_world* world, const char *name, const unsigned char *uri);
+
+/* Destroy */
+RASQAL_API
+void rasqal_free_query(rasqal_query* query);
+
+/* Methods */
+RASQAL_API
+const char* rasqal_query_get_name(rasqal_query* query);
+RASQAL_API
+const char* rasqal_query_get_label(rasqal_query* query);
+RASQAL_API
+void rasqal_query_set_fatal_error_handler(rasqal_query* query, void *user_data, raptor_message_handler handler);
+RASQAL_API
+void rasqal_query_set_error_handler(rasqal_query* query, void *user_data, raptor_message_handler handler);
+RASQAL_API
+void rasqal_query_set_warning_handler(rasqal_query* query, void *user_data, raptor_message_handler handler);
+RASQAL_API
+int rasqal_query_set_feature(rasqal_query* query, rasqal_feature feature, int value);
+RASQAL_API
+int rasqal_query_set_feature_string(rasqal_query *query, rasqal_feature feature, const unsigned char *value);
+RASQAL_API
+int rasqal_query_get_feature(rasqal_query *query, rasqal_feature feature);
+RASQAL_API
+const unsigned char* rasqal_query_get_feature_string(rasqal_query *query, rasqal_feature feature);
+RASQAL_API
+void rasqal_query_set_default_generate_bnodeid_parameters(rasqal_query* rdf_query, char *prefix, int base);
+RASQAL_API
+void rasqal_query_set_generate_bnodeid_handler(rasqal_query* query, void *user_data, rasqal_generate_bnodeid_handler handler);
+
+RASQAL_API
+rasqal_query_verb rasqal_query_get_verb(rasqal_query* query);
+RASQAL_API
+int rasqal_query_get_wildcard(rasqal_query* query);
+RASQAL_API
+int rasqal_query_get_distinct(rasqal_query* query);
+RASQAL_API
+void rasqal_query_set_distinct(rasqal_query* query, int distinct_mode);
+RASQAL_API
+int rasqal_query_get_explain(rasqal_query* query);
+RASQAL_API
+void rasqal_query_set_explain(rasqal_query* query, int is_explain);
+RASQAL_API
+int rasqal_query_get_limit(rasqal_query* query);
+RASQAL_API
+void rasqal_query_set_limit(rasqal_query* query, int limit);
+RASQAL_API
+int rasqal_query_get_offset(rasqal_query* query);
+RASQAL_API
+void rasqal_query_set_offset(rasqal_query* query, int offset);
+
+RASQAL_API
+int rasqal_query_add_data_graph(rasqal_query* query, raptor_uri* uri, raptor_uri* name_uri, int flags);
+RASQAL_API
+raptor_sequence* rasqal_query_get_data_graph_sequence(rasqal_query* query);
+RASQAL_API
+rasqal_data_graph* rasqal_query_get_data_graph(rasqal_query* query, int idx);
+RASQAL_API
+int rasqal_query_dataset_contains_named_graph(rasqal_query* query, raptor_uri *graph_uri);
+
+RASQAL_API
+int rasqal_query_add_variable(rasqal_query* query, rasqal_variable* var);
+RASQAL_API
+raptor_sequence* rasqal_query_get_bound_variable_sequence(rasqal_query* query);
+RASQAL_API
+raptor_sequence* rasqal_query_get_anonymous_variable_sequence(rasqal_query* query);
+RASQAL_API
+raptor_sequence* rasqal_query_get_all_variable_sequence(rasqal_query* query);
+RASQAL_API
+rasqal_variable* rasqal_query_get_variable(rasqal_query* query, int idx);
+RASQAL_API
+int rasqal_query_has_variable(rasqal_query* query, const unsigned char *name);
+RASQAL_API
+int rasqal_query_set_variable(rasqal_query* query, const unsigned char *name, rasqal_literal* value);
+RASQAL_API
+raptor_sequence* rasqal_query_get_triple_sequence(rasqal_query* query);
+RASQAL_API
+rasqal_triple* rasqal_query_get_triple(rasqal_query* query, int idx);
+RASQAL_API
+int rasqal_query_add_prefix(rasqal_query* query, rasqal_prefix* prefix);
+RASQAL_API
+raptor_sequence* rasqal_query_get_prefix_sequence(rasqal_query* query);
+RASQAL_API
+rasqal_prefix* rasqal_query_get_prefix(rasqal_query* query, int idx);
+RASQAL_API
+raptor_sequence* rasqal_query_get_order_conditions_sequence(rasqal_query* query);
+RASQAL_API
+rasqal_expression* rasqal_query_get_order_condition(rasqal_query* query, int idx);
+RASQAL_API
+raptor_sequence* rasqal_query_get_group_conditions_sequence(rasqal_query* query);
+RASQAL_API
+rasqal_expression* rasqal_query_get_group_condition(rasqal_query* query, int idx);
+RASQAL_API
+raptor_sequence* rasqal_query_get_construct_triples_sequence(rasqal_query* query);
+RASQAL_API
+rasqal_triple* rasqal_query_get_construct_triple(rasqal_query* query, int idx);
+RASQAL_API
+void rasqal_query_graph_pattern_visit(rasqal_query* query, rasqal_graph_pattern_visit_fn visit_fn, void* data);
+RASQAL_API
+int rasqal_query_write(raptor_iostream* iostr, rasqal_query* query, raptor_uri* format_uri, raptor_uri* base_uri);
+
+/* graph patterns */
+RASQAL_API
+rasqal_graph_pattern* rasqal_query_get_query_graph_pattern(rasqal_query* query);
+RASQAL_API
+raptor_sequence* rasqal_query_get_graph_pattern_sequence(rasqal_query* query);
+RASQAL_API
+rasqal_graph_pattern* rasqal_query_get_graph_pattern(rasqal_query* query, int idx);
+RASQAL_API
+int rasqal_graph_pattern_add_sub_graph_pattern(rasqal_graph_pattern* graph_pattern, rasqal_graph_pattern* sub_graph_pattern);
+RASQAL_API
+rasqal_triple* rasqal_graph_pattern_get_triple(rasqal_graph_pattern* graph_pattern, int idx);
+RASQAL_API
+raptor_sequence* rasqal_graph_pattern_get_sub_graph_pattern_sequence(rasqal_graph_pattern* graph_pattern);
+RASQAL_API
+rasqal_graph_pattern* rasqal_graph_pattern_get_sub_graph_pattern(rasqal_graph_pattern* graph_pattern, int idx);
+RASQAL_API
+rasqal_graph_pattern_operator rasqal_graph_pattern_get_operator(rasqal_graph_pattern* graph_pattern);
+RASQAL_API
+const char* rasqal_graph_pattern_operator_as_string(rasqal_graph_pattern_operator op);
+RASQAL_API
+void rasqal_graph_pattern_print(rasqal_graph_pattern* gp, FILE* fh);
+RASQAL_API RASQAL_DEPRECATED
+int rasqal_graph_pattern_add_constraint(rasqal_graph_pattern* gp, rasqal_expression* expr);
+RASQAL_API RASQAL_DEPRECATED
+raptor_sequence* rasqal_graph_pattern_get_constraint_sequence(rasqal_graph_pattern* gp);
+RASQAL_API RASQAL_DEPRECATED
+rasqal_expression* rasqal_graph_pattern_get_constraint(rasqal_graph_pattern* gp, int idx);
+RASQAL_API
+int rasqal_graph_pattern_set_filter_expression(rasqal_graph_pattern* gp, rasqal_expression* expr);
+RASQAL_API
+rasqal_expression* rasqal_graph_pattern_get_filter_expression(rasqal_graph_pattern* gp);
+RASQAL_API
+int rasqal_graph_pattern_visit(rasqal_query* query, rasqal_graph_pattern *gp, rasqal_graph_pattern_visit_fn fn, void* user_data);
+RASQAL_API
+int rasqal_graph_pattern_get_index(rasqal_graph_pattern* gp);
+
+/* Utility methods */
+RASQAL_API
+const char* rasqal_query_verb_as_string(rasqal_query_verb verb);
+RASQAL_API
+void rasqal_query_print(rasqal_query* query, FILE* fh);
+
+/* Query */
+RASQAL_API
+int rasqal_query_prepare(rasqal_query* query, const unsigned char *query_string, raptor_uri *base_uri);
+RASQAL_API
+rasqal_query_results* rasqal_query_execute(rasqal_query* query);
+
+RASQAL_API
+void* rasqal_query_get_user_data(rasqal_query* query);
+RASQAL_API
+void rasqal_query_set_user_data(rasqal_query* query, void *user_data);
+
+/* query results */
+RASQAL_API
+void rasqal_free_query_results(rasqal_query_results *query_results);
+
+RASQAL_API
+rasqal_query* rasqal_query_results_get_query(rasqal_query_results* query_results);
+
+/* Bindings result format */
+RASQAL_API
+int rasqal_query_results_is_bindings(rasqal_query_results *query_results);
+RASQAL_API
+int rasqal_query_results_get_count(rasqal_query_results *query_results);
+RASQAL_API
+int rasqal_query_results_next(rasqal_query_results *query_results);
+RASQAL_API
+int rasqal_query_results_finished(rasqal_query_results *query_results);
+RASQAL_API
+int rasqal_query_results_get_bindings(rasqal_query_results *query_results, const unsigned char ***names, rasqal_literal ***values);
+RASQAL_API
+rasqal_literal* rasqal_query_results_get_binding_value(rasqal_query_results *query_results, int offset);
+RASQAL_API
+const unsigned char* rasqal_query_results_get_binding_name(rasqal_query_results *query_results, int offset);
+RASQAL_API
+rasqal_literal* rasqal_query_results_get_binding_value_by_name(rasqal_query_results *query_results, const unsigned char *name);
+RASQAL_API
+int rasqal_query_results_get_bindings_count(rasqal_query_results *query_results);
+
+/* Boolean result format */
+RASQAL_API
+int rasqal_query_results_is_boolean(rasqal_query_results *query_results);
+RASQAL_API
+int rasqal_query_results_get_boolean(rasqal_query_results *query_results);
+
+/* Graph result format */
+RASQAL_API
+int rasqal_query_results_is_graph(rasqal_query_results *query_results);
+RASQAL_API
+raptor_statement* rasqal_query_results_get_triple(rasqal_query_results *query_results);
+RASQAL_API
+int rasqal_query_results_next_triple(rasqal_query_results *query_results);
+
+/* Syntax result format */
+RASQAL_API
+int rasqal_query_results_is_syntax(rasqal_query_results* query_results);
+
+RASQAL_API
+int rasqal_query_results_write(raptor_iostream *iostr, rasqal_query_results *results, raptor_uri *format_uri, raptor_uri *base_uri);
+RASQAL_API
+int rasqal_query_results_read(raptor_iostream *iostr, rasqal_query_results *results, raptor_uri *format_uri, raptor_uri *base_uri);
+
+
+/**
+ * RASQAL_QUERY_RESULTS_FORMAT_FLAG_READER:
+ *
+ * Flag for rasqal_query_results_formats_enumerate() to get query results formats that can be read.
+ */
+#define RASQAL_QUERY_RESULTS_FORMAT_FLAG_READER 1
+
+/**
+ * RASQAL_QUERY_RESULTS_FORMAT_FLAG_WRITER:
+ *
+ * Flag for rasqal_query_results_formats_enumerate() to get query results formats that can be written.
+ */
+#define RASQAL_QUERY_RESULTS_FORMAT_FLAG_WRITER 2
+
+RASQAL_API
+int rasqal_query_results_formats_enumerate(rasqal_world* world, unsigned int counter, const char **name, const char **label, const unsigned char **uri_string, const char **mime_type, int* flags);
+RASQAL_API
+int rasqal_query_results_formats_check(rasqal_world* world, const char *name, raptor_uri* uri, const char *mime_type);
+RASQAL_API
+rasqal_query_results_formatter* rasqal_new_query_results_formatter(rasqal_world* world, const char *name, raptor_uri* format_uri);
+RASQAL_API
+rasqal_query_results_formatter* rasqal_new_query_results_formatter_by_mime_type(rasqal_world* world, const char *mime_type);
+RASQAL_API
+void rasqal_free_query_results_formatter(rasqal_query_results_formatter* formatter);
+RASQAL_API
+int rasqal_query_results_formatter_write(raptor_iostream *iostr, rasqal_query_results_formatter* formatter, rasqal_query_results* results, raptor_uri *base_uri);
+RASQAL_API
+int rasqal_query_results_formatter_read(rasqal_world* world, raptor_iostream *iostr, rasqal_query_results_formatter* formatter, rasqal_query_results* results, raptor_uri *base_uri);
+RASQAL_API
+const char* rasqal_query_results_formatter_get_mime_type(rasqal_query_results_formatter *formatter);
+
+RASQAL_API
+int rasqal_query_iostream_write_escaped_counted_string(rasqal_query* query, raptor_iostream* iostr, const unsigned char* string, size_t len);
+RASQAL_API
+unsigned char* rasqal_query_escape_counted_string(rasqal_query* query, const unsigned char *string, size_t len, size_t* output_len_p);
+
+
+/* Data graph class */
+RASQAL_API
+rasqal_data_graph* rasqal_new_data_graph(rasqal_world* world, raptor_uri* uri, raptor_uri* name_uri, int flags);
+RASQAL_API
+void rasqal_free_data_graph(rasqal_data_graph* dg);
+RASQAL_API
+void rasqal_data_graph_print(rasqal_data_graph* dg, FILE* fh);
+
+
+/**
+ * rasqal_compare_flags:
+ * @RASQAL_COMPARE_NOCASE: String comparisons are case independent.
+ * @RASQAL_COMPARE_XQUERY: XQuery comparsion rules apply.
+ * @RASQAL_COMPARE_RDF: RDF Term comparsion rules apply.
+ * @RASQAL_COMPARE_URI: Allow comparison of URIs
+ *
+ * Flags for rasqal_expression_evaluate() or rasqal_literal_compare().
+ */
+typedef enum {
+ RASQAL_COMPARE_NOCASE = 1,
+ RASQAL_COMPARE_XQUERY = 2,
+ RASQAL_COMPARE_RDF = 4,
+ RASQAL_COMPARE_URI = 8
+} rasqal_compare_flags;
+
+
+/* Expression class */
+RASQAL_API
+rasqal_expression* rasqal_new_0op_expression(rasqal_world* world, rasqal_op op);
+RASQAL_API
+rasqal_expression* rasqal_new_1op_expression(rasqal_world* world, rasqal_op op, rasqal_expression* arg);
+RASQAL_API
+rasqal_expression* rasqal_new_2op_expression(rasqal_world* world, rasqal_op op, rasqal_expression* arg1, rasqal_expression* arg2);
+RASQAL_API
+rasqal_expression* rasqal_new_3op_expression(rasqal_world* world, rasqal_op op, rasqal_expression* arg1, rasqal_expression* arg2, rasqal_expression* arg3);
+RASQAL_API
+rasqal_expression* rasqal_new_string_op_expression(rasqal_world* world, rasqal_op op, rasqal_expression* arg1, rasqal_literal* literal);
+RASQAL_API
+rasqal_expression* rasqal_new_literal_expression(rasqal_world* world, rasqal_literal* literal);
+RASQAL_API
+rasqal_expression* rasqal_new_function_expression(rasqal_world* world, raptor_uri* name, raptor_sequence* args);
+RASQAL_API
+rasqal_expression* rasqal_new_cast_expression(rasqal_world* world, raptor_uri* name, rasqal_expression *value);
+RASQAL_API
+rasqal_expression* rasqal_new_expression_from_expression(rasqal_expression* e);
+
+RASQAL_API
+void rasqal_free_expression(rasqal_expression* e);
+RASQAL_API
+void rasqal_expression_print_op(rasqal_expression* e, FILE* fh);
+RASQAL_API
+void rasqal_expression_print(rasqal_expression* e, FILE* fh);
+RASQAL_API
+rasqal_literal* rasqal_expression_evaluate_v2(rasqal_world *world, raptor_locator *locator, rasqal_expression* e, int flags);
+RASQAL_API RASQAL_DEPRECATED
+rasqal_literal* rasqal_expression_evaluate(rasqal_query* query, rasqal_expression* e, int flags);
+
+/**
+ * rasqal_expression_visit_fn:
+ * @user_data: user data passed in with rasqal_expression_visit()
+ * @e: current expression
+ *
+ * User function to visit an expression and operate on it with
+ * rasqal_expression_visit()
+ *
+ * Return value: 0 to truncate the visit
+ */
+typedef int (*rasqal_expression_visit_fn)(void *user_data, rasqal_expression *e);
+RASQAL_API
+int rasqal_expression_visit(rasqal_expression* e, rasqal_expression_visit_fn fn, void *user_data);
+
+
+/* Literal class */
+RASQAL_API
+rasqal_literal* rasqal_new_integer_literal(rasqal_world* world, rasqal_literal_type type, int integer);
+RASQAL_API
+rasqal_literal* rasqal_new_typed_literal(rasqal_world* world, rasqal_literal_type type, const unsigned char* string);
+RASQAL_API
+rasqal_literal* rasqal_new_double_literal(rasqal_world* world, double d);
+RASQAL_API
+rasqal_literal* rasqal_new_float_literal(rasqal_world* world, float f);
+RASQAL_API
+rasqal_literal* rasqal_new_uri_literal(rasqal_world* world, raptor_uri* uri);
+RASQAL_API
+rasqal_literal* rasqal_new_pattern_literal(rasqal_world* world, const unsigned char *pattern, const char *flags);
+RASQAL_API
+rasqal_literal* rasqal_new_string_literal(rasqal_world* world, const unsigned char *string, const char *language, raptor_uri *datatype, const unsigned char *datatype_qname);
+RASQAL_API
+rasqal_literal* rasqal_new_simple_literal(rasqal_world* world, rasqal_literal_type type, const unsigned char *string);
+RASQAL_API
+rasqal_literal* rasqal_new_boolean_literal(rasqal_world* world, int value);
+RASQAL_API
+rasqal_literal* rasqal_new_variable_literal(rasqal_world* world, rasqal_variable *variable);
+RASQAL_API
+rasqal_literal* rasqal_new_decimal_literal(rasqal_world* world, const unsigned char *string);
+RASQAL_API
+rasqal_literal* rasqal_new_decimal_literal_from_decimal(rasqal_world* world, const unsigned char *string, rasqal_xsd_decimal* decimal);
+
+RASQAL_API
+rasqal_literal* rasqal_new_literal_from_literal(rasqal_literal* l);
+RASQAL_API
+void rasqal_free_literal(rasqal_literal* l);
+RASQAL_API
+void rasqal_literal_print(rasqal_literal* l, FILE* fh);
+RASQAL_API
+void rasqal_literal_print_type(rasqal_literal* l, FILE* fh);
+RASQAL_API
+rasqal_variable* rasqal_literal_as_variable(rasqal_literal* l);
+RASQAL_API
+const unsigned char* rasqal_literal_as_string(rasqal_literal* l);
+RASQAL_API
+const unsigned char* rasqal_literal_as_string_flags(rasqal_literal* l, int flags, int *error);
+RASQAL_API
+rasqal_literal* rasqal_literal_as_node(rasqal_literal* l);
+RASQAL_API
+raptor_uri* rasqal_literal_datatype(rasqal_literal* l);
+RASQAL_API
+rasqal_literal* rasqal_literal_value(rasqal_literal* l);
+
+RASQAL_API
+int rasqal_literal_compare(rasqal_literal* l1, rasqal_literal* l2, int flags, int *error);
+RASQAL_API
+int rasqal_literal_equals(rasqal_literal* l1, rasqal_literal* l2);
+
+RASQAL_API
+rasqal_prefix* rasqal_new_prefix(rasqal_world* world, const unsigned char* prefix, raptor_uri* uri);
+RASQAL_API
+void rasqal_free_prefix(rasqal_prefix* p);
+RASQAL_API
+void rasqal_prefix_print(rasqal_prefix* p, FILE* fh);
+
+/* Triple class */
+RASQAL_API
+rasqal_triple* rasqal_new_triple(rasqal_literal* subject, rasqal_literal* predicate, rasqal_literal* object);
+RASQAL_API
+rasqal_triple* rasqal_new_triple_from_triple(rasqal_triple* t);
+RASQAL_API
+void rasqal_free_triple(rasqal_triple* t);
+RASQAL_API
+void rasqal_triple_print(rasqal_triple* t, FILE* fh);
+RASQAL_API
+void rasqal_triple_set_origin(rasqal_triple* t, rasqal_literal *l);
+RASQAL_API
+rasqal_literal* rasqal_triple_get_origin(rasqal_triple* t);
+
+/* Variable class */
+RASQAL_API
+rasqal_variable* rasqal_new_variable_typed(rasqal_query* rq, rasqal_variable_type type, unsigned char *name, rasqal_literal *value);
+RASQAL_API
+rasqal_variable* rasqal_new_variable(rasqal_query* rq, unsigned char *name, rasqal_literal *value);
+RASQAL_API
+rasqal_variable* rasqal_new_variable_from_variable(rasqal_variable* v);
+RASQAL_API
+void rasqal_free_variable(rasqal_variable* v);
+RASQAL_API
+void rasqal_variable_print(rasqal_variable* v, FILE* fh);
+RASQAL_API
+void rasqal_variable_set_value(rasqal_variable* v, rasqal_literal* l);
+
+/* memory functions */
+RASQAL_API
+void rasqal_free_memory(void *ptr);
+RASQAL_API
+void* rasqal_alloc_memory(size_t size);
+RASQAL_API
+void* rasqal_calloc_memory(size_t nmemb, size_t size);
+
+
+/* decimal functions */
+RASQAL_API
+rasqal_xsd_decimal* rasqal_new_xsd_decimal(void);
+RASQAL_API
+void rasqal_free_xsd_decimal(rasqal_xsd_decimal* dec);
+RASQAL_API
+int rasqal_xsd_decimal_set_string(rasqal_xsd_decimal* dec, const char* string);
+RASQAL_API
+double rasqal_xsd_decimal_get_double(rasqal_xsd_decimal* dec);
+RASQAL_API
+char* rasqal_xsd_decimal_as_string(rasqal_xsd_decimal* dec);
+RASQAL_API
+char* rasqal_xsd_decimal_as_counted_string(rasqal_xsd_decimal* dec, size_t* len_p);
+RASQAL_API
+int rasqal_xsd_decimal_set_long(rasqal_xsd_decimal* dec, long l);
+RASQAL_API
+int rasqal_xsd_decimal_set_double(rasqal_xsd_decimal* dec, double d);
+RASQAL_API
+int rasqal_xsd_decimal_print(rasqal_xsd_decimal* dec, FILE* stream);
+RASQAL_API
+int rasqal_xsd_decimal_add(rasqal_xsd_decimal* result, rasqal_xsd_decimal* a, rasqal_xsd_decimal* b);
+RASQAL_API
+int rasqal_xsd_decimal_subtract(rasqal_xsd_decimal* result, rasqal_xsd_decimal* a, rasqal_xsd_decimal* b);
+RASQAL_API
+int rasqal_xsd_decimal_multiply(rasqal_xsd_decimal* result, rasqal_xsd_decimal* a, rasqal_xsd_decimal* b);
+RASQAL_API
+int rasqal_xsd_decimal_divide(rasqal_xsd_decimal* result, rasqal_xsd_decimal* a, rasqal_xsd_decimal* b);
+RASQAL_API
+int rasqal_xsd_decimal_negate(rasqal_xsd_decimal* result, rasqal_xsd_decimal* a);
+RASQAL_API
+int rasqal_xsd_decimal_compare(rasqal_xsd_decimal* a, rasqal_xsd_decimal* b);
+RASQAL_API
+int rasqal_xsd_decimal_equals(rasqal_xsd_decimal* a, rasqal_xsd_decimal* b);
+RASQAL_API
+int rasqal_xsd_decimal_is_zero(rasqal_xsd_decimal* d);
+
+/* rasqal_engine.c */
+
+/**
+ * rasqal_triple_parts:
+ * @RASQAL_TRIPLE_SUBJECT: Subject present in a triple.
+ * @RASQAL_TRIPLE_PREDICATE: Predicate present in a triple.
+ * @RASQAL_TRIPLE_OBJECT: Object present in a triple.
+ * @RASQAL_TRIPLE_ORIGIN: Origin/graph present in a triple.
+ * @RASQAL_TRIPLE_GRAPH: Alias for RASQAL_TRIPLE_ORIGIN
+ * @RASQAL_TRIPLE_SPO: Subject, Predicate and Object present in a triple.
+ * @RASQAL_TRIPLE_SPOG: Subject, Predicate, Object, Graph present in a triple.
+ *
+ * Flags for parts of a triple.
+ */
+typedef enum {
+ RASQAL_TRIPLE_SUBJECT = 1,
+ RASQAL_TRIPLE_PREDICATE= 2,
+ RASQAL_TRIPLE_OBJECT = 4,
+ RASQAL_TRIPLE_ORIGIN = 8,
+ RASQAL_TRIPLE_GRAPH = RASQAL_TRIPLE_ORIGIN,
+ RASQAL_TRIPLE_SPO = RASQAL_TRIPLE_SUBJECT | RASQAL_TRIPLE_PREDICATE | RASQAL_TRIPLE_OBJECT,
+ RASQAL_TRIPLE_SPOG = RASQAL_TRIPLE_SPO | RASQAL_TRIPLE_GRAPH
+} rasqal_triple_parts;
+
+
+
+/**
+ * rasqal_triples_match:
+ * @user_data: User data pointer for factory methods.
+ * @bind_match: The [4]array (s,p,o,origin) bindings against the current triple match only touching triple parts given. Returns parts that were bound or 0 on failure.
+ * @next_match: Move to next match.
+ * @is_end: Check for end of triple match - return non-0 if is end.
+ * @finish: Finish triples match and destroy any allocated memory.
+ * @world: rasqal_world object
+ *
+ * Triples match structure as initialised by #rasqal_triples_source
+ * method init_triples_match.
+ */
+struct rasqal_triples_match_s {
+ void *user_data;
+
+ rasqal_triple_parts (*bind_match)(struct rasqal_triples_match_s* rtm, void *user_data, rasqal_variable *bindings[4], rasqal_triple_parts parts);
+
+ void (*next_match)(struct rasqal_triples_match_s* rtm, void *user_data);
+
+ int (*is_end)(struct rasqal_triples_match_s* rtm, void *user_data);
+
+ void (*finish)(struct rasqal_triples_match_s* rtm, void *user_data);
+
+ rasqal_world *world;
+};
+typedef struct rasqal_triples_match_s rasqal_triples_match;
+
+/**
+ * rasqal_triple_meta:
+ * @bindings: Variable bindings for this triple+origin to set.
+ * @triples_match: The matcher that is setting these bindings.
+ * @context: Context data used by the matcher.
+ * @parts: Parts of the triple to match/bindings to set.
+ * @is_exact: non-0 if all parts of the triple are given
+ * @executed: non-0 if the triple pattern has been fully executed
+ *
+ * Triple matching metadata for one triple pattern.
+ */
+typedef struct {
+ /* triple (subject, predicate, object) and origin */
+ rasqal_variable* bindings[4];
+
+ rasqal_triples_match *triples_match;
+
+ void *context;
+
+ rasqal_triple_parts parts;
+
+ /* non-0 if the associated triple pattern contains no variables */
+ int is_exact;
+
+ /* non-0 if the triple pattern has been fully executed */
+ int executed;
+} rasqal_triple_meta;
+
+
+/**
+ * rasqal_triples_source:
+ * @query: Source for this query.
+ * @user_data: Context user data passed into the factory methods.
+ * @init_triples_match: Factory method to initalise a new #rasqal_triples_match.
+ * @triple_present: Factory method to return presence or absence of a complete triple.
+ * @free_triples_source: Factory method to deallocate resources.
+ *
+ * Triples source as initialised by a #rasqal_triples_source_factory.
+ */
+struct rasqal_triples_source_s {
+ rasqal_query* query;
+
+ void *user_data;
+
+ int (*init_triples_match)(rasqal_triples_match* rtm, struct rasqal_triples_source_s* rts, void *user_data, rasqal_triple_meta *m, rasqal_triple *t);
+
+ int (*triple_present)(struct rasqal_triples_source_s* rts, void *user_data, rasqal_triple *t);
+
+ void (*free_triples_source)(void *user_data);
+};
+typedef struct rasqal_triples_source_s rasqal_triples_source;
+
+
+/**
+ * rasqal_triples_source_factory:
+ * @user_data: User data for triples_source_factory.
+ * @user_data_size: Size Of @user_data for new_triples_source.
+ * @new_triples_source: Create a new triples source - returns non-zero on failure < 0 is a 'no rdf data error', > 0 is an unspecified error..
+ *
+ * A factory that initialises #rasqal_triples_source structures
+ * to returning matches to a triple pattern.
+ */
+typedef struct {
+ void *user_data;
+ size_t user_data_size;
+
+ int (*new_triples_source)(rasqal_query* query, void *factory_user_data, void *user_data, rasqal_triples_source* rts);
+} rasqal_triples_source_factory;
+
+
+/* set the triples_source_factory */
+RASQAL_API
+void rasqal_set_triples_source_factory(rasqal_world* world, void (*register_fn)(rasqal_triples_source_factory *factory), void* user_data);
+
+
+
+/* The info below is solely for gtk-doc - ignore it */
+
+/**
+ * RASQAL_QUERY_RESULTS_FORMATTER_DECLARED:
+ *
+ * Internal
+ */
+
+/**
+ * RASQAL_WORLD_DECLARED:
+ *
+ * Internal
+ */
+
+/**
+ * rasqal_expression_s:
+ * @usage: Internal
+ * @op: Internal
+ * @arg1: Internal
+ * @arg2: Internal
+ * @arg3: Internal
+ * @literal: Internal
+ * @value: Internal
+ * @name: Internal
+ * @args: Internal
+ *
+ * Internal - see #rasqal_expression.
+ *
+ */
+
+/**
+ * bind_match:
+ * @rtm: triples match context
+ * @user_data: user data
+ * @bindings: variable binding for parts of triple (s, p, o, g)
+ * @parts: parts of triple to match
+ *
+ * Internal - see #rasqal_triples_match
+ *
+ * Return value: match parts
+*/
+
+/**
+ * next_match:
+ * @rtm: triples match context
+ * @user_data: user data
+ *
+ * Internal - see #rasqal_triples_match
+ */
+
+/**
+ * is_end:
+ * @rtm: triples match context
+ * @user_data: user data
+ *
+ * Internal - see #rasqal_triples_match
+ *
+ * Return value: non-0 if end of match
+ */
+
+/**
+ * finish:
+ * @rtm: triples match context
+ * @user_data: user data
+ *
+ * Internal - see #rasqal_triples_match
+ */
+
+/**
+ * init_triples_match:
+ * @rtm: triples match context
+ * @rts: triples match source
+ * @user_data: user data
+ * @m: triple meta
+ * @t: triple
+ *
+ * Internal - see #rasqal_triples_source
+ *
+ * Return value: non-0 on failure
+ */
+
+/**
+ * triple_present:
+ * @rts: triples match source
+ * @user_data: user data
+ * @t: triple to test for presence
+ *
+ * Internal - see #rasqal_triples_source
+ *
+ * Return value: non-0 on failure
+ */
+
+/**
+ * free_triples_source:
+ * @user_data: user data
+ *
+ * Internal - see #rasqal_triples_source
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/rasqal/rasqal_algebra.c b/src/rasqal/rasqal_algebra.c
new file mode 100644
index 0000000..6c25c65
--- /dev/null
+++ b/src/rasqal/rasqal_algebra.c
@@ -0,0 +1,1403 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_algebra.c - Rasqal algebra class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#ifndef STANDALONE
+
+static rasqal_algebra_node* rasqal_algebra_graph_pattern_to_algebra(rasqal_query* query, rasqal_graph_pattern* gp);
+
+/*
+ * rasqal_new_algebra_node:
+ * @query: #rasqal_algebra_node query object
+ * @op: enum #rasqal_algebra_operator operator
+ *
+ * INTERNAL - Create a new algebra object.
+ *
+ * Return value: a new #rasqal_algebra object or NULL on failure
+ **/
+static rasqal_algebra_node*
+rasqal_new_algebra_node(rasqal_query* query, rasqal_algebra_node_operator op)
+{
+ rasqal_algebra_node* node;
+
+ if(!query)
+ return NULL;
+
+ node = (rasqal_algebra_node*)RASQAL_CALLOC(rasqal_algebra, 1,
+ sizeof(rasqal_algebra_node));
+ if(!node)
+ return NULL;
+
+ node->op = op;
+ node->query = query;
+ return node;
+}
+
+
+/*
+ * rasqal_new_filter_algebra_node:
+ * @query: #rasqal_query query object
+ * @expr: FILTER expression
+ * @node: algebra node being filtered
+ *
+ * INTERNAL - Create a new algebra node for an expression over a node
+ *
+ * Return value: a new #rasqal_algebra_node object or NULL on failure
+ **/
+rasqal_algebra_node*
+rasqal_new_filter_algebra_node(rasqal_query* query,
+ rasqal_expression* expr,
+ rasqal_algebra_node* node)
+{
+ rasqal_algebra_node* new_node;
+
+ if(!query || !expr)
+ return NULL;
+
+ new_node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_FILTER);
+ if(!new_node)
+ return NULL;
+
+ new_node->expr = expr;
+ new_node->node1 = node;
+
+ return new_node;
+}
+
+
+/*
+ * rasqal_new_triples_algebra_node:
+ * @query: #rasqal_query query object
+ * @triples: triples sequence (SHARED) (or NULL for empty BGP)
+ * @start_column: first triple
+ * @end_column: last triple
+ *
+ * INTERNAL - Create a new algebra node for Basic Graph Pattern
+ *
+ * Return value: a new #rasqal_algebra_node object or NULL on failure
+ **/
+rasqal_algebra_node*
+rasqal_new_triples_algebra_node(rasqal_query* query,
+ raptor_sequence* triples,
+ int start_column, int end_column)
+{
+ rasqal_algebra_node* node;
+
+ if(!query)
+ return NULL;
+
+ node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_BGP);
+ if(!node)
+ return NULL;
+
+ node->triples = triples;
+ if(!triples) {
+ start_column= -1;
+ end_column= -1;
+ }
+ node->start_column = start_column;
+ node->end_column = end_column;
+
+ return node;
+}
+
+
+/*
+ * rasqal_new_empty_algebra_node:
+ * @query: #rasqal_query query object
+ *
+ * INTERNAL - Create a new empty algebra node
+ *
+ * Return value: a new #rasqal_algebra_node object or NULL on failure
+ **/
+rasqal_algebra_node*
+rasqal_new_empty_algebra_node(rasqal_query* query)
+{
+ rasqal_algebra_node* node;
+
+ if(!query)
+ return NULL;
+
+ node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_BGP);
+ if(!node)
+ return NULL;
+
+ node->triples = NULL;
+ node->start_column= -1;
+ node->end_column= -1;
+
+ return node;
+}
+
+
+/*
+ * rasqal_new_2op_algebra_node:
+ * @query: #rasqal_query query object
+ * @op: operator
+ * @node1: 1st algebra node
+ * @node2: 2nd algebra node (pr NULL for #RASQAL_ALGEBRA_OPERATOR_TOLIST only)
+ *
+ * INTERNAL - Create a new algebra node for 1 or 2 graph patterns
+ *
+ * node1 and ndoe2 become owned by the new node
+ *
+ * Return value: a new #rasqal_algebra_node object or NULL on failure
+ **/
+rasqal_algebra_node*
+rasqal_new_2op_algebra_node(rasqal_query* query,
+ rasqal_algebra_node_operator op,
+ rasqal_algebra_node* node1,
+ rasqal_algebra_node* node2)
+{
+ rasqal_algebra_node* node;
+
+ if(!query || !node1)
+ goto fail;
+ if(op != RASQAL_ALGEBRA_OPERATOR_TOLIST && !node2)
+ goto fail;
+
+ node = rasqal_new_algebra_node(query, op);
+ if(node) {
+ node->node1 = node1;
+ node->node2 = node2;
+
+ return node;
+ }
+
+ fail:
+ if(node1)
+ rasqal_free_algebra_node(node1);
+ if(node2)
+ rasqal_free_algebra_node(node2);
+ return NULL;
+}
+
+
+/*
+ * rasqal_new_leftjoin_algebra_node:
+ * @query: #rasqal_query query object
+ * @node1: 1st algebra node
+ * @node2: 2nd algebra node
+ * @expr: expression
+ *
+ * INTERNAL - Create a new LEFTJOIN algebra node for 2 graph patterns
+ *
+ * node1 and ndoe2 become owned by the new node
+ *
+ * Return value: a new #rasqal_algebra_node object or NULL on failure
+ **/
+rasqal_algebra_node*
+rasqal_new_leftjoin_algebra_node(rasqal_query* query,
+ rasqal_algebra_node* node1,
+ rasqal_algebra_node* node2,
+ rasqal_expression* expr)
+{
+ rasqal_algebra_node* node;
+
+ if(!query || !node1 || !node2 || !expr)
+ goto fail;
+
+ node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_LEFTJOIN);
+ if(node) {
+ node->node1 = node1;
+ node->node2 = node2;
+ node->expr = expr;
+
+ return node;
+ }
+
+ fail:
+ if(node1)
+ rasqal_free_algebra_node(node1);
+ if(node2)
+ rasqal_free_algebra_node(node2);
+ if(expr)
+ rasqal_free_expression(expr);
+ return NULL;
+}
+
+
+/*
+ * rasqal_new_orderby_algebra_node:
+ * @query: #rasqal_query query object
+ * @node1: inner algebra node
+ * @seq: sequence of order condition #rasqal_expression
+ *
+ * INTERNAL - Create a new ORDERBY algebra node for a sequence of order conditions
+ *
+ * #node and #seq become owned by the new node
+ *
+ * Return value: a new #rasqal_algebra_node object or NULL on failure
+ **/
+rasqal_algebra_node*
+rasqal_new_orderby_algebra_node(rasqal_query* query,
+ rasqal_algebra_node* node1,
+ raptor_sequence* seq)
+{
+ rasqal_algebra_node* node;
+
+ if(!query || !node1 || !seq || !raptor_sequence_size(seq))
+ goto fail;
+
+ node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_ORDERBY);
+ if(node) {
+ node->node1 = node1;
+ node->seq = seq;
+
+ return node;
+ }
+
+ fail:
+ if(node1)
+ rasqal_free_algebra_node(node1);
+ if(seq)
+ raptor_free_sequence(seq);
+
+ return NULL;
+}
+
+
+/*
+ * rasqal_new_project_algebra_node:
+ * @query: #rasqal_query query object
+ * @node1: inner algebra node
+ * @vars_seq: sequence of variables
+ *
+ * INTERNAL - Create a new PROJECT algebra node for a sequence of variables over an inner node
+ *
+ * The inputs @node and @seq become owned by the new node
+ *
+ * Return value: a new #rasqal_algebra_node object or NULL on failure
+ **/
+rasqal_algebra_node*
+rasqal_new_project_algebra_node(rasqal_query* query,
+ rasqal_algebra_node* node1,
+ raptor_sequence* vars_seq)
+{
+ rasqal_algebra_node* node;
+
+ if(!query || !node1 || !vars_seq)
+ goto fail;
+
+ node = rasqal_new_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_PROJECT);
+ if(node) {
+ node->node1 = node1;
+ node->vars_seq = vars_seq;
+
+ return node;
+ }
+
+ fail:
+ if(node1)
+ rasqal_free_algebra_node(node1);
+ if(vars_seq)
+ raptor_free_sequence(vars_seq);
+
+ return NULL;
+}
+
+
+/*
+ * rasqal_free_algebra_node:
+ * @gp: #rasqal_algebra_node object
+ *
+ * INTERNAL - Free an algebra node object.
+ *
+ **/
+void
+rasqal_free_algebra_node(rasqal_algebra_node* node)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(node, rasqal_algebra_node);
+
+ /* node->triples is SHARED with the query - not freed here */
+
+ if(node->node1)
+ rasqal_free_algebra_node(node->node1);
+
+ if(node->node2)
+ rasqal_free_algebra_node(node->node2);
+
+ if(node->expr)
+ rasqal_free_expression(node->expr);
+
+ if(node->seq)
+ raptor_free_sequence(node->seq);
+
+ if(node->vars_seq)
+ raptor_free_sequence(node->vars_seq);
+
+ RASQAL_FREE(rasqal_algebra, node);
+}
+
+
+/**
+ * rasqal_algebra_node_get_operator:
+ * @algebra_node: #rasqal_algebra_node algebra node object
+ *
+ * Get the algebra node operator .
+ *
+ * The operator for the given algebra node. See also
+ * rasqal_algebra_node_operator_as_string().
+ *
+ * Return value: algebra node operator
+ **/
+rasqal_algebra_node_operator
+rasqal_algebra_node_get_operator(rasqal_algebra_node* node)
+{
+ return node->op;
+}
+
+
+static const char* const rasqal_algebra_node_operator_labels[RASQAL_ALGEBRA_OPERATOR_LAST+1] = {
+ "UNKNOWN",
+ "BGP",
+ "Filter",
+ "Join",
+ "Diff",
+ "LeftJoin",
+ "Union",
+ "ToList",
+ "OrderBy",
+ "Project",
+ "Distinct",
+ "Reduced",
+ "Slice"
+};
+
+
+/**
+ * rasqal_algebra_node_operator_as_string:
+ * @op: the #rasqal_algebra_node_operator verb of the query
+ *
+ * Get a string for the query verb.
+ *
+ * Return value: pointer to a shared string label for the query verb
+ **/
+const char*
+rasqal_algebra_node_operator_as_string(rasqal_algebra_node_operator op)
+{
+ if(op <= RASQAL_ALGEBRA_OPERATOR_UNKNOWN ||
+ op > RASQAL_ALGEBRA_OPERATOR_LAST)
+ op = RASQAL_ALGEBRA_OPERATOR_UNKNOWN;
+
+ return rasqal_algebra_node_operator_labels[(int)op];
+}
+
+
+
+#define SPACES_LENGTH 80
+static const char spaces[SPACES_LENGTH+1] = " ";
+
+static void
+rasqal_algebra_write_indent(raptor_iostream *iostr, int indent)
+{
+ while(indent > 0) {
+ int sp = (indent > SPACES_LENGTH) ? SPACES_LENGTH : indent;
+ raptor_iostream_write_bytes(iostr, spaces, sizeof(char), sp);
+ indent -= sp;
+ }
+}
+
+static int
+rasqal_algebra_algebra_node_write_internal(rasqal_algebra_node *node,
+ raptor_iostream* iostr, int indent)
+{
+ const char* op_string = rasqal_algebra_node_operator_as_string(node->op);
+ int arg_count = 0;
+ int indent_delta;
+
+ if(node->op == RASQAL_ALGEBRA_OPERATOR_BGP && !node->triples) {
+ raptor_iostream_write_byte(iostr, 'Z');
+ return 0;
+ }
+
+ indent_delta = strlen(op_string);
+
+ raptor_iostream_write_counted_string(iostr, op_string, indent_delta);
+ raptor_iostream_write_counted_string(iostr, "(\n", 2);
+ indent_delta++;
+
+ indent += indent_delta;
+ rasqal_algebra_write_indent(iostr, indent);
+
+ if(node->op == RASQAL_ALGEBRA_OPERATOR_BGP) {
+ int i;
+
+ for(i = node->start_column; i <= node->end_column; i++) {
+ rasqal_triple *t;
+ t = (rasqal_triple*)raptor_sequence_get_at(node->triples, i);
+ if(arg_count) {
+ raptor_iostream_write_counted_string(iostr, " ,\n", 3);
+ rasqal_algebra_write_indent(iostr, indent);
+ }
+ rasqal_triple_write(t, iostr);
+ arg_count++;
+ }
+ }
+ if(node->node1) {
+ if(arg_count) {
+ raptor_iostream_write_counted_string(iostr, " ,\n", 3);
+ rasqal_algebra_write_indent(iostr, indent);
+ }
+ rasqal_algebra_algebra_node_write_internal(node->node1, iostr, indent);
+ arg_count++;
+ if(node->node2) {
+ if(arg_count) {
+ raptor_iostream_write_counted_string(iostr, " ,\n", 3);
+ rasqal_algebra_write_indent(iostr, indent);
+ }
+ rasqal_algebra_algebra_node_write_internal(node->node2, iostr, indent);
+ arg_count++;
+ }
+ }
+
+ /* look for FILTER expression */
+ if(node->expr) {
+ if(arg_count) {
+ raptor_iostream_write_counted_string(iostr, " ,\n", 3);
+ rasqal_algebra_write_indent(iostr, indent);
+ }
+ rasqal_expression_write(node->expr, iostr);
+ arg_count++;
+ }
+
+ if(node->seq && node->op == RASQAL_ALGEBRA_OPERATOR_ORDERBY) {
+ int order_size = raptor_sequence_size(node->seq);
+ if(order_size) {
+ int i;
+
+ if(arg_count) {
+ raptor_iostream_write_counted_string(iostr, " ,\n", 3);
+ rasqal_algebra_write_indent(iostr, indent);
+ }
+ raptor_iostream_write_counted_string(iostr, "Conditions([ ", 13);
+ for(i = 0; i < order_size; i++) {
+ rasqal_expression* e;
+ e = (rasqal_expression*)raptor_sequence_get_at(node->seq, i);
+ if(i > 0)
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_expression_write(e, iostr);
+ arg_count++;
+ }
+ raptor_iostream_write_counted_string(iostr, " ])", 3);
+ }
+ }
+
+ if(node->vars_seq && node->op == RASQAL_ALGEBRA_OPERATOR_PROJECT) {
+ int vars_size = raptor_sequence_size(node->vars_seq);
+ int i;
+
+ if(arg_count) {
+ raptor_iostream_write_counted_string(iostr, " ,\n", 3);
+ rasqal_algebra_write_indent(iostr, indent);
+ }
+ raptor_iostream_write_counted_string(iostr, "Variables([ ", 12);
+ for(i = 0; i < vars_size; i++) {
+ rasqal_variable* v;
+ v = (rasqal_variable*)raptor_sequence_get_at(node->vars_seq, i);
+ if(i > 0)
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_variable_write(v, iostr);
+ arg_count++;
+ }
+ raptor_iostream_write_counted_string(iostr, " ])", 3);
+ }
+
+ if(node->op == RASQAL_ALGEBRA_OPERATOR_SLICE) {
+ if(arg_count) {
+ raptor_iostream_write_counted_string(iostr, " ,\n", 3);
+ rasqal_algebra_write_indent(iostr, indent);
+ }
+ raptor_iostream_write_string(iostr, "slice start ");
+ raptor_iostream_write_decimal(iostr, node->start);
+ raptor_iostream_write_string(iostr, " length ");
+ raptor_iostream_write_decimal(iostr, node->length);
+ raptor_iostream_write_byte(iostr, '\n');
+ arg_count++;
+ }
+
+ raptor_iostream_write_byte(iostr, '\n');
+ indent-= indent_delta;
+
+ rasqal_algebra_write_indent(iostr, indent);
+ raptor_iostream_write_byte(iostr, ')');
+
+ return 0;
+}
+
+
+int
+rasqal_algebra_algebra_node_write(rasqal_algebra_node *node,
+ raptor_iostream* iostr)
+{
+ return rasqal_algebra_algebra_node_write_internal(node, iostr, 0);
+}
+
+
+/**
+ * rasqal_algebra_node_print:
+ * @gp: the #rasqal_algebra_node object
+ * @fh: the #FILE* handle to print to
+ *
+ * Print a #rasqal_algebra_node in a debug format.
+ *
+ * The print debug format may change in any release.
+ *
+ **/
+void
+rasqal_algebra_node_print(rasqal_algebra_node* node, FILE* fh)
+{
+ raptor_iostream* iostr;
+
+ iostr = raptor_new_iostream_to_file_handle(fh);
+ rasqal_algebra_algebra_node_write(node, iostr);
+ raptor_free_iostream(iostr);
+}
+
+/**
+ * rasqal_algebra_node_visit:
+ * @query: #rasqal_query to operate on
+ * @node: #rasqal_algebra_node graph pattern
+ * @fn: pointer to function to apply that takes user data and graph pattern parameters
+ * @user_data: user data for applied function
+ *
+ * Visit a user function over a #rasqal_algebra_node
+ *
+ * If the user function @fn returns 0, the visit is truncated.
+ *
+ * Return value: 0 if the visit was truncated.
+ **/
+int
+rasqal_algebra_node_visit(rasqal_query *query,
+ rasqal_algebra_node* node,
+ rasqal_algebra_node_visit_fn fn,
+ void *user_data)
+{
+ int result;
+
+ result = fn(query, node, user_data);
+ if(result)
+ return result;
+
+ if(node->node1) {
+ result = rasqal_algebra_node_visit(query, node->node1, fn, user_data);
+ if(result)
+ return result;
+ }
+ if(node->node2) {
+ result = rasqal_algebra_node_visit(query, node->node2, fn, user_data);
+ if(result)
+ return result;
+ }
+
+ return 0;
+}
+
+
+static rasqal_algebra_node*
+rasqal_algebra_basic_graph_pattern_to_algebra(rasqal_query* query,
+ rasqal_graph_pattern* gp)
+{
+ rasqal_algebra_node* node = NULL;
+ rasqal_expression* fs = NULL;
+
+ node = rasqal_new_triples_algebra_node(query,
+ rasqal_query_get_triple_sequence(query),
+ gp->start_column, gp->end_column);
+ if(!node)
+ goto fail;
+
+ if(gp->filter_expression) {
+ rasqal_expression* e;
+ e = rasqal_new_expression_from_expression(gp->filter_expression);
+ if(!e) {
+ RASQAL_DEBUG1("rasqal_new_expression_from_expression() failed");
+ goto fail;
+ }
+ fs = fs ? rasqal_new_2op_expression(query->world, RASQAL_EXPR_AND, fs, e) : e;
+ }
+
+ if(fs) {
+ node = rasqal_new_filter_algebra_node(query, fs, node);
+ if(!node) {
+ RASQAL_DEBUG1("rasqal_new_filter_algebra_node() failed");
+ goto fail;
+ }
+ fs = NULL; /* now owned by node */
+ }
+
+
+ return node;
+
+ fail:
+ if(node)
+ rasqal_free_algebra_node(node);
+ if(fs)
+ rasqal_free_expression(fs);
+
+ return node;
+}
+
+static rasqal_algebra_node*
+rasqal_algebra_union_graph_pattern_to_algebra(rasqal_query* query,
+ rasqal_graph_pattern* gp)
+{
+ int idx = 0;
+ rasqal_algebra_node* node = NULL;
+
+ while(1) {
+ rasqal_graph_pattern* sgp;
+ rasqal_algebra_node* gnode;
+
+ sgp = rasqal_graph_pattern_get_sub_graph_pattern(gp, idx);
+ if(!sgp)
+ break;
+
+ gnode = rasqal_algebra_graph_pattern_to_algebra(query, sgp);
+ if(!gnode) {
+ RASQAL_DEBUG1("rasqal_algebra_graph_pattern_to_algebra() failed");
+ goto fail;
+ }
+
+ if(!node)
+ node = gnode;
+ else {
+ node = rasqal_new_2op_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_UNION,
+ node, gnode);
+ if(!node) {
+ RASQAL_DEBUG1("rasqal_new_2op_algebra_node() failed");
+ goto fail;
+ }
+ }
+
+ idx++;
+ }
+
+ return node;
+
+ fail:
+ if(node)
+ rasqal_free_algebra_node(node);
+
+ return NULL;
+}
+
+
+static rasqal_algebra_node*
+rasqal_algebra_group_graph_pattern_to_algebra(rasqal_query* query,
+ rasqal_graph_pattern* gp)
+{
+ int idx = 0;
+ /* Let FS := the empty set */
+ rasqal_expression* fs = NULL;
+ /* Let G := the empty pattern, Z, a basic graph pattern which
+ * is the empty set. */
+ rasqal_algebra_node* gnode = NULL;
+
+ gnode = rasqal_new_empty_algebra_node(query);
+ if(!gnode) {
+ RASQAL_DEBUG1("rasqal_new_empty_algebra_node() failed");
+ goto fail;
+ }
+
+ for(idx = 0; 1; idx++) {
+ rasqal_graph_pattern* egp;
+ egp = rasqal_graph_pattern_get_sub_graph_pattern(gp, idx);
+ if(!egp)
+ break;
+
+ if(egp->filter_expression) {
+ /* If E is of the form FILTER(expr)
+ FS := FS set-union {expr}
+ */
+ rasqal_expression* e;
+
+ /* add all gp->conditions_sequence to FS */
+ e = rasqal_new_expression_from_expression(egp->filter_expression);
+ if(!e) {
+ RASQAL_DEBUG1("rasqal_new_expression_from_expression() failed");
+ goto fail;
+ }
+ fs = fs ? rasqal_new_2op_expression(query->world, RASQAL_EXPR_AND, fs, e) : e;
+
+ if(egp->op == RASQAL_GRAPH_PATTERN_OPERATOR_FILTER)
+ continue;
+ }
+
+ if(egp->op == RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL) {
+ /* If E is of the form OPTIONAL{P} */
+ int sgp_idx = 0;
+ int sgp_size = raptor_sequence_size(egp->graph_patterns);
+
+ /* walk through all optionals */
+ for(sgp_idx = 0; sgp_idx < sgp_size; sgp_idx++) {
+ rasqal_graph_pattern* sgp;
+ rasqal_algebra_node* anode;
+
+ sgp = rasqal_graph_pattern_get_sub_graph_pattern(egp, sgp_idx);
+
+ /* Let A := Transform(P) */
+ anode = rasqal_algebra_graph_pattern_to_algebra(query, sgp);
+ if(!anode) {
+ RASQAL_DEBUG1("rasqal_algebra_graph_pattern_to_algebra() failed");
+ goto fail;
+ }
+
+ if(anode->op == RASQAL_ALGEBRA_OPERATOR_FILTER) {
+ rasqal_expression* f_expr = anode->expr;
+ rasqal_algebra_node *a2node = anode->node1;
+ /* If A is of the form Filter(F, A2)
+ G := LeftJoin(G, A2, F)
+ */
+ gnode = rasqal_new_leftjoin_algebra_node(query, gnode, a2node,
+ f_expr);
+ if(!gnode) {
+ RASQAL_DEBUG1("rasqal_new_leftjoin_algebra_node() failed");
+ goto fail;
+ }
+
+ anode->expr = NULL;
+ anode->node1 = NULL;
+ rasqal_free_algebra_node(anode);
+ } else {
+ rasqal_literal *true_lit = NULL;
+ rasqal_expression *true_expr = NULL;
+
+ true_lit = rasqal_new_boolean_literal(query->world, 1);
+ if(!true_lit) {
+ RASQAL_DEBUG1("rasqal_new_boolean_literal() failed");
+ goto fail;
+ }
+
+ true_expr = rasqal_new_literal_expression(query->world, true_lit);
+ if(!true_expr) {
+ RASQAL_DEBUG1("rasqal_new_literal_expression() failed");
+ goto fail;
+ }
+ true_lit = NULL; /* now owned by true_expr */
+
+ /* G := LeftJoin(G, A, true) */
+ gnode = rasqal_new_leftjoin_algebra_node(query, gnode, anode,
+ true_expr);
+ if(!gnode) {
+ RASQAL_DEBUG1("rasqal_new_leftjoin_algebra_node() failed");
+ rasqal_free_expression(true_expr);
+ goto fail;
+ }
+
+ true_expr = NULL; /* now owned by gnode */
+ }
+ } /* end for all optional */
+ } else {
+ /* If E is any other form:*/
+ rasqal_algebra_node* anode;
+
+ /* Let A := Transform(E) */
+ anode = rasqal_algebra_graph_pattern_to_algebra(query, egp);
+ if(!anode) {
+ RASQAL_DEBUG1("rasqal_algebra_graph_pattern_to_algebra() failed");
+ goto fail;
+ }
+
+ /* G := Join(G, A) */
+ gnode = rasqal_new_2op_algebra_node(query, RASQAL_ALGEBRA_OPERATOR_JOIN,
+ gnode, anode);
+ if(!gnode) {
+ RASQAL_DEBUG1("rasqal_new_2op_algebra_node() failed");
+ goto fail;
+ }
+ }
+
+ }
+
+ /*
+ If FS is not empty:
+ Let X := Conjunction of expressions in FS
+ G := Filter(X, G)
+
+ The result is G.
+ */
+ if(fs) {
+ gnode = rasqal_new_filter_algebra_node(query, fs, gnode);
+ if(!gnode) {
+ RASQAL_DEBUG1("rasqal_new_filter_algebra_node() failed");
+ goto fail;
+ }
+ fs = NULL; /* now owned by gnode */
+ }
+
+ if(gnode)
+ return gnode;
+
+ fail:
+
+ if(gnode)
+ rasqal_free_algebra_node(gnode);
+ if(fs)
+ rasqal_free_expression(fs);
+ return NULL;
+}
+
+
+static rasqal_algebra_node*
+rasqal_algebra_graph_pattern_to_algebra(rasqal_query* query,
+ rasqal_graph_pattern* gp)
+{
+ rasqal_algebra_node* node = NULL;
+
+ switch(gp->op) {
+ case RASQAL_GRAPH_PATTERN_OPERATOR_BASIC:
+ node = rasqal_algebra_basic_graph_pattern_to_algebra(query, gp);
+ break;
+
+ case RASQAL_GRAPH_PATTERN_OPERATOR_UNION:
+ node = rasqal_algebra_union_graph_pattern_to_algebra(query, gp);
+ break;
+
+ case RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL:
+ case RASQAL_GRAPH_PATTERN_OPERATOR_GROUP:
+ node = rasqal_algebra_group_graph_pattern_to_algebra(query, gp);
+ break;
+
+ case RASQAL_GRAPH_PATTERN_OPERATOR_FILTER:
+ case RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH:
+
+ case RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN:
+ default:
+ RASQAL_DEBUG3("Unsupported graph pattern operator %s (%d)\n",
+ rasqal_graph_pattern_operator_as_string(gp->op),
+ gp->op);
+ break;
+ }
+
+#if RASQAL_DEBUG
+ if(!node)
+ abort();
+#endif
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG1("Resulting node:\n");
+ rasqal_algebra_node_print(node, stderr);
+ fputc('\n', stderr);
+#endif
+
+ return node;
+}
+
+
+/*
+ * rasqal_algebra_node_is_empty:
+ * @node: #rasqal_algebra_node node
+ *
+ * INTERNAL - Check if a an algebra node is empty
+ *
+ * Return value: non-0 if empty
+ **/
+int
+rasqal_algebra_node_is_empty(rasqal_algebra_node* node)
+{
+ return (node->op == RASQAL_ALGEBRA_OPERATOR_BGP && !node->triples);
+}
+
+
+static int
+rasqal_algebra_remove_znodes(rasqal_query* query, rasqal_algebra_node* node,
+ void* data)
+{
+ int* modified = (int*)data;
+ int is_z1;
+ int is_z2;
+
+ /* Look at 2-node operations and see if they can be merged */
+ if(!node->node1 || !node->node2)
+ return 0;
+
+ is_z1 = rasqal_algebra_node_is_empty(node->node1);
+ is_z2 = rasqal_algebra_node_is_empty(node->node2);
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG1("Checking node\n");
+ rasqal_algebra_node_print(node, stderr);
+ fprintf(stderr, "\nNode 1 (%s): %s\n",
+ is_z1 ? "empty" : "not empty",
+ rasqal_algebra_node_operator_as_string(node->node1->op));
+ fprintf(stderr, "Node 2 (%s): %s\n",
+ is_z2 ? "empty" : "not empty",
+ rasqal_algebra_node_operator_as_string(node->node2->op));
+#endif
+
+ if(is_z1 && !is_z2) {
+ /* Replace join(Z, A) by A */
+ /* an empty node has no extra things to free */
+ RASQAL_FREE(rasqal_algebra_node, node->node1);
+ memcpy(node, node->node2, sizeof(rasqal_algebra_node));
+ *modified = 1;
+ } else if(!is_z1 && is_z2) {
+ /* Replace join(A, Z) by A */
+ /* ditto */
+ RASQAL_FREE(rasqal_algebra_node, node->node2);
+ memcpy(node, node->node1, sizeof(rasqal_algebra_node));
+ *modified = 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_algebra_query_to_algebra:
+ * @query: #rasqal_query to operate on
+ *
+ * Turn a graph pattern into query algebra structure
+ *
+ * Return value: algebra expression or NULL on failure
+ */
+rasqal_algebra_node*
+rasqal_algebra_query_to_algebra(rasqal_query* query)
+{
+ rasqal_graph_pattern* query_gp;
+ rasqal_algebra_node* node;
+ int modified = 0;
+
+ query_gp = rasqal_query_get_query_graph_pattern(query);
+ if(!query_gp)
+ return NULL;
+
+ node = rasqal_algebra_graph_pattern_to_algebra(query, query_gp);
+
+ if(!node)
+ return node;
+
+
+ rasqal_algebra_node_visit(query, node,
+ rasqal_algebra_remove_znodes,
+ &modified);
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("modified=%d after remove zones, algebra node now:\n ", modified);
+ rasqal_algebra_node_print(node, stderr);
+ fputs("\n", stderr);
+#endif
+
+ if(query->order_conditions_sequence) {
+ int order_size = raptor_sequence_size(query->order_conditions_sequence);
+ if(order_size) {
+ int i;
+ raptor_sequence* seq;
+
+ /* Make a deep copy of the query order conditions sequence for
+ * the ORDERBY algebra node
+ */
+ seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_expression, (raptor_sequence_print_handler*)rasqal_expression_print);
+ if(!seq) {
+ rasqal_free_algebra_node(node);
+ return NULL;
+ }
+ for(i = 0; i < order_size; i++) {
+ rasqal_expression* e;
+ e = (rasqal_expression*)raptor_sequence_get_at(query->order_conditions_sequence, i);
+ raptor_sequence_push(seq, rasqal_new_expression_from_expression(e));
+ }
+
+ node = rasqal_new_orderby_algebra_node(query, node, seq);
+ modified = 1;
+ }
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("modified=%d after adding orderby node, algebra node now:\n ", modified);
+ rasqal_algebra_node_print(node, stderr);
+ fputs("\n", stderr);
+#endif
+
+ }
+
+
+ /* FIXME - do not always need a PROJECT node */
+ if(1) {
+ int vars_size = raptor_sequence_size(query->selects);
+ raptor_sequence* vars_seq;
+ int i;
+
+ vars_seq = raptor_new_sequence(NULL, (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!vars_seq) {
+ rasqal_free_algebra_node(node);
+ return NULL;
+ }
+ for(i = 0; i < vars_size; i++) {
+ rasqal_variable* v;
+ v = (rasqal_variable*)raptor_sequence_get_at(query->selects, i);
+ raptor_sequence_push(vars_seq, rasqal_new_variable_from_variable(v));
+ }
+
+ node = rasqal_new_project_algebra_node(query, node, vars_seq);
+ modified = 1;
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("modified=%d after adding project node, algebra node now:\n ", modified);
+ rasqal_algebra_node_print(node, stderr);
+ fputs("\n", stderr);
+#endif
+ }
+
+
+ return node;
+}
+
+
+#endif
+
+#ifdef STANDALONE
+#include <stdio.h>
+
+#define QUERY_LANGUAGE "sparql"
+#define QUERY_FORMAT "\
+ PREFIX ex: <http://example.org/ns#/> \
+ SELECT $subject \
+ FROM <http://librdf.org/rasqal/rasqal.rdf> \
+ WHERE \
+ { $subject ex:predicate $value . \
+ FILTER (($value + 1) < 10) \
+ }"
+
+
+int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[]) {
+ char const *program = rasqal_basename(*argv);
+ const char *query_language_name = QUERY_LANGUAGE;
+ const unsigned char *query_format = (const unsigned char *)QUERY_FORMAT;
+ int failures = 0;
+#define FAIL do { failures++; goto tidy; } while(0)
+ rasqal_world *world;
+ rasqal_query* query = NULL;
+ rasqal_literal *lit1 = NULL, *lit2 = NULL;
+ rasqal_expression *expr1 = NULL, *expr2 = NULL;
+ rasqal_expression* expr = NULL;
+ rasqal_expression* expr3 = NULL;
+ rasqal_expression* expr4 = NULL;
+ rasqal_algebra_node* node0 = NULL;
+ rasqal_algebra_node* node1 = NULL;
+ rasqal_algebra_node* node2 = NULL;
+ rasqal_algebra_node* node3 = NULL;
+ rasqal_algebra_node* node4 = NULL;
+ rasqal_algebra_node* node5 = NULL;
+ rasqal_algebra_node* node6 = NULL;
+ rasqal_algebra_node* node7 = NULL;
+ rasqal_algebra_node* node8 = NULL;
+ rasqal_algebra_node* node9 = NULL;
+ raptor_uri *base_uri = NULL;
+ unsigned char *uri_string;
+ rasqal_graph_pattern* query_gp;
+ rasqal_graph_pattern* sgp;
+ raptor_sequence* triples;
+ raptor_sequence* conditions = NULL;
+ rasqal_literal* lit3 = NULL;
+ rasqal_literal* lit4 = NULL;
+
+ world = rasqal_new_world();
+ if(!world || rasqal_world_open(world))
+ FAIL;
+
+ uri_string = raptor_uri_filename_to_uri_string("");
+ if(!uri_string)
+ FAIL;
+#ifdef RAPTOR_V2_AVAILABLE
+ base_uri = raptor_new_uri_v2(world->raptor_world_ptr, uri_string);
+#else
+ base_uri = raptor_new_uri(uri_string);
+#endif
+ if(!base_uri)
+ FAIL;
+ raptor_free_memory(uri_string);
+
+ query = rasqal_new_query(world, query_language_name, NULL);
+ if(!query) {
+ fprintf(stderr, "%s: creating query in language %s FAILED\n", program,
+ query_language_name);
+ FAIL;
+ }
+
+ if(rasqal_query_prepare(query, query_format, base_uri)) {
+ fprintf(stderr, "%s: %s query prepare FAILED\n", program,
+ query_language_name);
+ FAIL;
+ }
+
+ lit1 = rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 1);
+ if(!lit1)
+ FAIL;
+ expr1 = rasqal_new_literal_expression(world, lit1);
+ if(!expr1)
+ FAIL;
+ lit1 = NULL; /* now owned by expr1 */
+
+ lit2 = rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 1);
+ if(!lit2)
+ FAIL;
+ expr2 = rasqal_new_literal_expression(world, lit2);
+ if(!expr2)
+ FAIL;
+ lit2 = NULL; /* now owned by expr2 */
+
+ expr = rasqal_new_2op_expression(world, RASQAL_EXPR_PLUS, expr1, expr2);
+ if(!expr)
+ FAIL;
+ expr1 = NULL; expr2 = NULL; /* now owned by expr */
+
+ node0 = rasqal_new_empty_algebra_node(query);
+ if(!node0)
+ FAIL;
+
+ node1 = rasqal_new_filter_algebra_node(query, expr, node0);
+ if(!node1) {
+ fprintf(stderr, "%s: rasqal_new_filter_algebra_node() failed\n", program);
+ FAIL;
+ }
+ node0 = NULL; expr = NULL; /* now owned by node1 */
+
+ fprintf(stderr, "%s: node result: \n", program);
+ rasqal_algebra_node_print(node1, stderr);
+ fputc('\n', stderr);
+
+ rasqal_free_algebra_node(node1);
+
+
+ /* construct abstract nodes from query structures */
+ query_gp = rasqal_query_get_query_graph_pattern(query);
+
+#ifdef RASQAL_DEBUG
+ fprintf(stderr, "%s: query graph pattern: \n", program);
+ rasqal_graph_pattern_print(query_gp, stderr);
+ fputc('\n', stderr);
+#endif
+
+ /* make a filter node around 2nd GP - a FILTER gp */
+ sgp = rasqal_graph_pattern_get_sub_graph_pattern(query_gp, 1);
+ expr = rasqal_graph_pattern_get_filter_expression(sgp);
+ if(!expr) {
+ fprintf(stderr, "%s: rasqal_graph_pattern_get_constraint() failed\n", program);
+ FAIL;
+ }
+ expr = rasqal_new_expression_from_expression(expr);
+ if(!expr) {
+ fprintf(stderr, "%s: rasqal_new_expression_from_expression() failed\n", program);
+ FAIL;
+ }
+
+ node8 = rasqal_new_empty_algebra_node(query);
+ if(!node8)
+ FAIL;
+ node1 = rasqal_new_filter_algebra_node(query, expr, node8);
+ if(!node1) {
+ fprintf(stderr, "%s: rasqal_new_filter_algebra_node() failed\n", program);
+ FAIL;
+ }
+ /* these are now owned by node1 */
+ node8 = NULL;
+ expr = NULL;
+
+ fprintf(stderr, "%s: node1 result: \n", program);
+ rasqal_algebra_node_print(node1, stderr);
+ fputc('\n', stderr);
+
+
+ /* make an triples node around first (and only) triple pattern */
+ triples = rasqal_query_get_triple_sequence(query);
+ node2 = rasqal_new_triples_algebra_node(query, triples, 0, 0);
+ if(!node2)
+ FAIL;
+
+ fprintf(stderr, "%s: node2 result: \n", program);
+ rasqal_algebra_node_print(node2, stderr);
+ fputc('\n', stderr);
+
+
+ node3 = rasqal_new_2op_algebra_node(query,
+ RASQAL_ALGEBRA_OPERATOR_JOIN,
+ node1, node2);
+
+ if(!node3)
+ FAIL;
+
+ /* these become owned by node3 */
+ node1 = node2 = NULL;
+
+ fprintf(stderr, "%s: node3 result: \n", program);
+ rasqal_algebra_node_print(node3, stderr);
+ fputc('\n', stderr);
+
+ node4 = rasqal_new_empty_algebra_node(query);
+ if(!node4)
+ FAIL;
+
+ fprintf(stderr, "%s: node4 result: \n", program);
+ rasqal_algebra_node_print(node4, stderr);
+ fputc('\n', stderr);
+
+ node5 = rasqal_new_2op_algebra_node(query,
+ RASQAL_ALGEBRA_OPERATOR_UNION,
+ node3, node4);
+
+ if(!node5)
+ FAIL;
+
+ /* these become owned by node5 */
+ node3 = node4 = NULL;
+
+ fprintf(stderr, "%s: node5 result: \n", program);
+ rasqal_algebra_node_print(node5, stderr);
+ fputc('\n', stderr);
+
+
+
+ lit1 = rasqal_new_boolean_literal(world, 1);
+ if(!lit1)
+ FAIL;
+ expr1 = rasqal_new_literal_expression(world, lit1);
+ if(!expr1)
+ FAIL;
+ lit1 = NULL; /* now owned by expr1 */
+
+ node6 = rasqal_new_empty_algebra_node(query);
+ if(!node6)
+ FAIL;
+
+ node7 = rasqal_new_leftjoin_algebra_node(query, node5, node6, expr1);
+ if(!node7)
+ FAIL;
+ /* these become owned by node7 */
+ node5 = node6 = NULL;
+ expr1 = NULL;
+
+ fprintf(stderr, "%s: node7 result: \n", program);
+ rasqal_algebra_node_print(node7, stderr);
+ fputc('\n', stderr);
+
+ /* This is an artificial order conditions sequence equivalent to
+ * ORDER BY 1, 2 which would probably never appear in a query.
+ */
+ conditions = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_expression, (raptor_sequence_print_handler*)rasqal_expression_print);
+ if(!conditions)
+ FAIL;
+ lit3 = rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 1);
+ if(!lit3)
+ FAIL;
+ expr3 = rasqal_new_literal_expression(world, lit3);
+ if(!expr3)
+ FAIL;
+ lit3 = NULL; /* now owned by expr3 */
+
+ raptor_sequence_push(conditions, expr3);
+ expr3 = NULL; /* now owned by conditions */
+
+ lit4 = rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 2);
+ if(!lit4)
+ FAIL;
+ expr4 = rasqal_new_literal_expression(world, lit4);
+ if(!expr4)
+ FAIL;
+ lit4 = NULL; /* now owned by expr4 */
+
+ raptor_sequence_push(conditions, expr4);
+ expr4 = NULL; /* now owned by conditions */
+
+ node9 = rasqal_new_orderby_algebra_node(query, node7, conditions);
+ if(!node9)
+ FAIL;
+ /* these become owned by node9 */
+ node7 = NULL;
+ conditions = NULL;
+
+ fprintf(stderr, "%s: node9 result: \n", program);
+ rasqal_algebra_node_print(node9, stderr);
+ fputc('\n', stderr);
+
+
+ tidy:
+ if(lit1)
+ rasqal_free_literal(lit1);
+ if(lit2)
+ rasqal_free_literal(lit2);
+ if(lit3)
+ rasqal_free_literal(lit3);
+ if(expr1)
+ rasqal_free_expression(expr1);
+ if(expr2)
+ rasqal_free_expression(expr2);
+ if(expr3)
+ rasqal_free_expression(expr3);
+
+ if(node9)
+ rasqal_free_algebra_node(node9);
+ if(node8)
+ rasqal_free_algebra_node(node8);
+ if(node7)
+ rasqal_free_algebra_node(node7);
+ if(node6)
+ rasqal_free_algebra_node(node6);
+ if(node5)
+ rasqal_free_algebra_node(node5);
+ if(node4)
+ rasqal_free_algebra_node(node4);
+ if(node3)
+ rasqal_free_algebra_node(node3);
+ if(node2)
+ rasqal_free_algebra_node(node2);
+ if(node1)
+ rasqal_free_algebra_node(node1);
+ if(node0)
+ rasqal_free_algebra_node(node0);
+
+ if(query)
+ rasqal_free_query(query);
+ if(base_uri)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, base_uri);
+#else
+ raptor_free_uri(base_uri);
+#endif
+ if(world)
+ rasqal_free_world(world);
+
+ return failures;
+}
+#endif
diff --git a/src/rasqal/rasqal_config.h b/src/rasqal/rasqal_config.h
new file mode 100644
index 0000000..968f9d4
--- /dev/null
+++ b/src/rasqal/rasqal_config.h
@@ -0,0 +1,2 @@
+#include "config.h"
+
diff --git a/src/rasqal/rasqal_datetime.c b/src/rasqal/rasqal_datetime.c
new file mode 100644
index 0000000..592decb
--- /dev/null
+++ b/src/rasqal/rasqal_datetime.c
@@ -0,0 +1,802 @@
+/*
+ * rasqal_datetime.c - Rasqal XSD dateTime
+ *
+ * Copyright (C) 2007-2008, David Beckett http://www.dajobe.org/
+ *
+ * Contributions:
+ * Copyright (C) 2007, Lauri Aalto <laalto iki fi>
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+#include <limits.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+/* Local definitions */
+
+/**
+ * rasqal_xsd_datetime:
+ *
+ * INTERNAL - XML schema dateTime datatype
+ *
+ * Signed types are required for normalization process where a value
+ * can be negative temporarily.
+ */
+typedef struct {
+ signed int year;
+ /* the following fields are integer values not characters */
+ unsigned char month;
+ unsigned char day;
+ signed char hour;
+ signed char minute;
+ signed char second;
+ /* second_frac is a string of 1-3 length (+1 for NUL)
+ * supports only up to milliseconds
+ */
+ char second_frac[3+1];
+ /* have_tz is an integer flag: non-0 if 'Z'ulu timezone is present */
+ char have_tz;
+} rasqal_xsd_datetime;
+
+
+static int rasqal_xsd_datetime_parse_and_normalize(const unsigned char *datetime_string, rasqal_xsd_datetime *result);
+static unsigned char *rasqal_xsd_datetime_to_string(const rasqal_xsd_datetime *dt);
+static unsigned int days_per_month(int month, int year);
+
+
+#ifndef ISNUM
+#define ISNUM(c) ((c)>='0'&&(c)<='9')
+#endif
+
+
+/**
+ * rasqal_xsd_datetime_normalize:
+ * @datetime: date time
+ *
+ * INTERNAl - Normalize a date time into the allowed range
+ *
+ * Return value: zero on success, non zero on failure.
+ */
+static int
+rasqal_xsd_datetime_normalize(rasqal_xsd_datetime *datetime)
+{
+ int t;
+
+ /* second & second parts: no need to normalize as they are not
+ * touched after range check
+ */
+
+ /* minute */
+ if(datetime->minute < 0) {
+ datetime->minute += 60;
+ datetime->hour--;
+ } else if(datetime->minute > 59) {
+ datetime->minute -= 60;
+ datetime->hour++;
+ }
+
+ /* hour */
+ if(datetime->hour < 0) {
+ datetime->hour += 24;
+ datetime->day--;
+ } else if(datetime->hour > 23) {
+ datetime->hour -= 24;
+ datetime->day++;
+ }
+
+ /* day */
+ if(datetime->day < 1) {
+ int y2;
+ t = --datetime->month;
+ /* going back beyond year boundary? */
+ if(!t) {
+ t = 12;
+ y2 = datetime->year-1;
+ } else
+ y2 = datetime->year;
+ datetime->day += days_per_month(t, y2);
+ } else if(datetime->day > (t=days_per_month(datetime->month, datetime->year))) {
+ datetime->day -= t;
+ datetime->month++;
+ }
+
+ /* month & year */
+ if(datetime->month < 1) {
+ datetime->month += 12;
+ datetime->year--;
+ /* there is no year 0 - go backwards to year -1 */
+ if(!datetime->year)
+ datetime->year--;
+ } else if(datetime->month > 12) {
+ datetime->month -= 12;
+ datetime->year++;
+ /* there is no year 0 - go forwards to year 1 */
+ if(!datetime->year)
+ datetime->year++;
+ }
+
+ /* success */
+ return 0;
+}
+
+
+/**
+ * rasqal_xsd_datetime_parse_and_normalize:
+ * @datetime_string: xsd:dateTime as lexical form string
+ * @result: target struct for holding dateTime components
+ *
+ * INTERNAL - Parse a xsd:dateTime string to a normalized #rasqal_xsd_datetime struct.
+ *
+ * http://www.w3.org/TR/xmlschema-2/#dt-dateTime
+ *
+ * "The lexical space of dateTime consists of finite-length sequences of
+ * characters of the form:
+ * '-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?,
+ * where
+ *
+ * * '-'? yyyy is a four-or-more digit optionally negative-signed numeral that
+ * represents the year; if more than four digits, leading zeros are
+ * prohibited, and '0000' is prohibited (see the Note above (3.2.7); also
+ * note that a plus sign is not permitted);
+ * * the remaining '-'s are separators between parts of the date portion;
+ * * the first mm is a two-digit numeral that represents the month;
+ * * dd is a two-digit numeral that represents the day;
+ * * 'T' is a separator indicating that time-of-day follows;
+ * * hh is a two-digit numeral that represents the hour; '24' is permitted if
+ * the minutes and seconds represented are zero, and the dateTime value so
+ * represented is the first instant of the following day (the hour property
+ * of a dateTime object in the value space cannot have a value greater
+ * than 23);
+ * * ':' is a separator between parts of the time-of-day portion;
+ * * the second mm is a two-digit numeral that represents the minute;
+ * * ss is a two-integer-digit numeral that represents the whole seconds;
+ * * '.' s+ (if present) represents the fractional seconds;
+ * * zzzzzz (if present) represents the timezone"
+ *
+ * Return value: zero on success, non zero on failure.
+ */
+int
+rasqal_xsd_datetime_parse_and_normalize(const unsigned char *datetime_string,
+ rasqal_xsd_datetime *result)
+{
+ const char *p, *q;
+ char b[16];
+ unsigned int l, t, t2, is_neg;
+ unsigned long u;
+
+ if(!datetime_string || !result)
+ return -1;
+
+ p=(const char *)datetime_string;
+ is_neg=0;
+
+ /* Parse year */
+
+ /* negative years permitted */
+ if(*p == '-') {
+ is_neg=1;
+ p++;
+ }
+ for(q=p; ISNUM(*p); p++)
+ ;
+ l=p-q;
+
+ /* error if
+ - less than 4 digits in year
+ - more than 4 digits && leading zeros
+ - '-' does not follow numbers
+ */
+ if(l < 4 || (l > 4 && *q=='0') || *p!='-')
+ return -1;
+
+ l=(l < sizeof(b)-1 ? l : sizeof(b)-1);
+ strncpy(b, q, l);
+ b[l]=0; /* ensure nul termination */
+ u=strtoul(b, 0, 10);
+
+ /* year "0000" not permitted
+ * restrict to signed int range
+ * >= instead of > to allow for +-1 year adjustment in normalization
+ * (however, these +-INT_MAX years cannot be parsed back in if
+ * converted to string)
+ */
+ if(!u || u >= INT_MAX)
+ return -1;
+
+ result->year=is_neg ? -(int)u : (int)u;
+
+ /* parse month */
+
+ for(q=++p; ISNUM(*p); p++)
+ ;
+ l=p-q;
+
+ /* error if month is not 2 digits or '-' is not the separator */
+ if(l != 2 || *p!='-')
+ return -2;
+
+ t=(*q++-'0')*10;
+ t+=*q-'0';
+
+ /* month must be 1..12 */
+ if(t < 1 || t > 12)
+ return -2;
+
+ result->month=t;
+
+ /* parse day */
+
+ for(q=++p; ISNUM(*p); p++)
+ ;
+ l=p-q;
+
+ /* error if day is not 2 digits or 'T' is not the separator */
+ if(l != 2 || *p != 'T')
+ return -3;
+
+ t=(*q++-'0')*10;
+ t+=*q-'0';
+
+ /* day must be 1..days_per_month */
+ if(t < 1 || t > days_per_month(result->month, result->year))
+ return -3;
+
+ result->day=t;
+
+ /* parse hour */
+
+ for(q=++p; ISNUM(*p); p++)
+ ;
+ l=p-q;
+
+ /* error if hour is not 2 digits or ':' is not the separator */
+ if(l != 2 || *p != ':')
+ return -4;
+
+ t=(*q++-'0')*10;
+ t+=*q-'0';
+
+ /* hour must be 0..24 - will handle special case 24 later
+ * (no need to check for < 0)
+ */
+ if(t > 24)
+ return -4;
+
+ result->hour=t;
+
+ /* parse minute */
+
+ for(q=++p; ISNUM(*p); p++)
+ ;
+ l=p-q;
+
+ /* error if minute is not 2 digits or ':' is not the separator */
+ if(l != 2 || *p != ':')
+ return -5;
+
+ t=(*q++-'0')*10;
+ t+=*q-'0';
+
+ /* minute must be 0..59
+ * (no need to check for < 0)
+ */
+ if(t > 59)
+ return -5;
+
+ result->minute=t;
+
+ /* parse second whole part */
+
+ for(q=++p; ISNUM(*p); p++)
+ ;
+ l=p-q;
+
+ /* error if second is not 2 digits or separator is not
+ * '.' (second fraction)
+ * 'Z' (utc)
+ * '+' or '-' (timezone offset)
+ * nul (end of string - second fraction and timezone are optional)
+ */
+ if(l != 2 || (*p && *p != '.' && *p != 'Z' && *p != '+' && *p != '-'))
+ return -6;
+
+ t=(*q++-'0')*10;
+ t+=*q-'0';
+
+ /* second must be 0..59
+ * (no need to check for < 0)
+ */
+ if(t > 59)
+ return -6;
+
+ result->second=t;
+
+ /* now that we have hour, minute and second, we can check
+ * if hour == 24 -> only 24:00:00 permitted (normalized later)
+ */
+ if(result->hour==24 && (result->minute || result->second))
+ return -7;
+
+ /* parse fraction seconds if any */
+ result->second_frac[0]=0;
+ if(*p == '.') {
+ for(q=++p; ISNUM(*p); p++)
+ ;
+
+ /* ignore trailing zeros */
+ while(*--p == '0')
+ ;
+ p++;
+
+ if(!(*q=='0' && q==p)) {
+ /* allow ".0" */
+ l=p-q;
+ /* support only to milliseconds with truncation */
+ if(l > sizeof(result->second_frac)-1)
+ l=sizeof(result->second_frac)-1;
+
+ if(l<1) /* need at least 1 num */
+ return -8;
+
+ for(t2=0; t2 < l; ++t2)
+ result->second_frac[t2]=*q++;
+
+ result->second_frac[l]=0;
+ }
+
+ /* skip ignored trailing zeros */
+ while(*p == '0')
+ p++;
+ }
+
+ /* parse & adjust timezone offset */
+ /* result is normalized later */
+ result->have_tz=0;
+ if(*p) {
+ if(*p == 'Z') {
+ /* utc timezone - no need to adjust */
+ p++;
+ result->have_tz=1;
+ } else if(*p=='+' || *p=='-') {
+ /* work out timezone offsets */
+ is_neg=*p == '-';
+
+ /* timezone hours */
+ for(q=++p; ISNUM(*p); p++)
+ ;
+ l=p-q;
+ if(l != 2 || *p!=':')
+ return -9;
+
+ t2=(*q++ - '0')*10;
+ t2+=*q - '0';
+ if(t2 > 14)
+ /* tz offset hours are restricted to 0..14
+ * (no need to check for < 0)
+ */
+ return -9;
+
+ /* negative tz offset adds to the result */
+ result->hour+=is_neg ? t2 : -t2;
+
+ /* timezone minutes */
+ for(q=++p; ISNUM(*p); p++)
+ ;
+ l=p-q;
+ if(l!=2)
+ return -10;
+
+ t=(*q++ - '0')*10;
+ t+=*q - '0';
+ if(t > 59 || (t2 == 14 && t!=0)) {
+ /* tz offset minutes are restricted to 0..59
+ * (no need to check for < 0)
+ * or 0 if hour offset is exactly +-14
+ */
+ return -10;
+ }
+
+ /* negative tz offset adds to the result */
+ result->minute += is_neg ? t : -t;
+ result->have_tz=1;
+ }
+
+ /* failure if extra chars after the timezone part */
+ if(*p)
+ return -11;
+
+ }
+
+ return rasqal_xsd_datetime_normalize(result);
+}
+
+
+/**
+ * rasqal_xsd_datetime_to_string:
+ * @dt: datetime struct
+ *
+ * INTERNAL - Convert a #rasqal_xsd_datetime struct to a xsd:dateTime lexical form string.
+ *
+ * Caller should RASQAL_FREE() the returned string.
+ *
+ * Return value: lexical form string or NULL on failure.
+ */
+static unsigned char*
+rasqal_xsd_datetime_to_string(const rasqal_xsd_datetime *dt)
+{
+ unsigned char *ret=0;
+ int is_neg;
+ int r=0;
+ int i;
+
+ if(!dt)
+ return NULL;
+
+ is_neg=dt->year<0;
+
+ /* format twice: first with null buffer of zero size to get the
+ * required buffer size second time to the allocated buffer
+ */
+ for(i=0; i < 2; i++) {
+ r=snprintf((char*)ret, r, "%s%04d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d%s%s%s",
+ is_neg ? "-" : "",
+ is_neg ? -dt->year : dt->year,
+ dt->month,
+ dt->day,
+ dt->hour,
+ dt->minute,
+ dt->second,
+ *dt->second_frac ? "." : "",
+ dt->second_frac,
+ dt->have_tz ? "Z" : "");
+
+ /* error? */
+ if(r<0) {
+ if(ret)
+ RASQAL_FREE(cstring, ret);
+ return NULL;
+ }
+
+ /* alloc return buffer on first pass */
+ if(!i) {
+ ret=(unsigned char *)RASQAL_MALLOC(cstring, ++r);
+ if(!ret)
+ return NULL;
+ }
+ }
+ return ret;
+}
+
+
+/**
+ * rasqal_xsd_datetime_string_to_canonical:
+ * @datetime_string: xsd:dateTime as lexical form string
+ *
+ * Convert a XML Schema dateTime lexical form string to its canonical form.
+ *
+ * Caller should RASQAL_FREE() the returned string.
+ *
+ * Return value: canonical lexical form string or NULL on failure.
+ *
+ *
+ * http://www.w3.org/TR/xmlschema-2/#dateTime-canonical-representation
+ *
+ * "Except for trailing fractional zero digits in the seconds representation,
+ * '24:00:00' time representations, and timezone (for timezoned values),
+ * the mapping from literals to values is one-to-one.
+ * Where there is more than one possible representation,
+ * the canonical representation is as follows:
+ * * The 2-digit numeral representing the hour must not be '24';
+ * * The fractional second string, if present, must not end in '0';
+ * * for timezoned values, the timezone must be represented with 'Z'
+ * (All timezoned dateTime values are UTC.)."
+ */
+const unsigned char*
+rasqal_xsd_datetime_string_to_canonical(const unsigned char* datetime_string)
+{
+ rasqal_xsd_datetime d; /* allocated on stack */
+
+ /* parse_and_normalize makes the rasqal_xsd_datetime canonical... */
+ if(rasqal_xsd_datetime_parse_and_normalize(datetime_string, &d))
+ return NULL;
+ /* ... so return a string representation of it */
+ return rasqal_xsd_datetime_to_string(&d);
+}
+
+
+
+
+/**
+ * days_per_month:
+ * @month: month 1-12
+ * @year: gregorian year
+ *
+ * INTERNAL - returns the number of days in given month and year.
+ *
+ * Return value: number of days or 0 on invalid arguments
+ */
+static unsigned int
+days_per_month(int month, int year) {
+ switch(month) {
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ case 8:
+ case 10:
+ case 12:
+ return 31;
+
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ return 30;
+
+ case 2:
+ /* any of bottom 2 bits non-zero -> not 0 mod 4 -> not leap year */
+ if(year & 3)
+ return 28;
+
+ /* 0 mod 400 and 0 mod 4 -> leap year */
+ if(!(year % 400))
+ return 29;
+
+ /* 0 mod 100 and not 0 mod 400 and 0 mod 4 -> not leap year */
+ if(!(year % 100))
+ return 28;
+
+ /* other 0 mod 4 years -> leap year */
+ return 29;
+
+ default:
+ /* error */
+ return 0;
+ }
+}
+
+
+int
+rasqal_xsd_datetime_check(const unsigned char* string)
+{
+ rasqal_xsd_datetime d;
+
+ /* This should be correct according to
+ * http://www.w3.org/TR/xmlschema-2/#dateTime
+ */
+ return !rasqal_xsd_datetime_parse_and_normalize(string, &d);
+}
+
+
+#ifdef STANDALONE
+#include <stdio.h>
+
+int main(int argc, char *argv[]);
+
+#define MYASSERT(c) \
+ if(!(c)) { \
+ fprintf(stderr, "%s: assertion failed at %s:%d: %s\n", program, __FILE__, __LINE__, #c); \
+ exit(1); \
+ }
+
+
+static int test_datetime_parser_tostring(const char *in_str, const char *out_expected)
+{
+ unsigned char const *s;
+ int r=1;
+ s=rasqal_xsd_datetime_string_to_canonical((const unsigned char *)in_str);
+ if(s) {
+ r=strcmp((char*)s, out_expected);
+ if(r)
+ fprintf(stderr, "input \"%s\" converted to canonical \"%s\", expected \"%s\"\n", in_str, s, out_expected);
+ RASQAL_FREE(cstring, (void*)s);
+ } else
+ fprintf(stderr, "input \"%s\" converted to canonical (null), expected \"%s\"\n", in_str, out_expected);
+ return r;
+}
+
+
+int
+main(int argc, char *argv[]) {
+ char const *program=rasqal_basename(*argv);
+ rasqal_xsd_datetime d;
+
+ /* days_per_month */
+
+ MYASSERT(!days_per_month(0,287));
+
+ MYASSERT(days_per_month(1,467) == 31);
+
+ MYASSERT(days_per_month(2,1900) == 28);
+ MYASSERT(days_per_month(2,1901) == 28);
+ MYASSERT(days_per_month(2,2000) == 29);
+ MYASSERT(days_per_month(2,2004) == 29);
+
+ MYASSERT(days_per_month(3,1955) == 31);
+ MYASSERT(days_per_month(4,3612) == 30);
+ MYASSERT(days_per_month(5,467) == 31);
+ MYASSERT(days_per_month(6,398) == 30);
+ MYASSERT(days_per_month(7,1832) == 31);
+ MYASSERT(days_per_month(8,8579248) == 31);
+ MYASSERT(days_per_month(9,843) == 30);
+ MYASSERT(days_per_month(10,84409) == 31);
+ MYASSERT(days_per_month(11,398) == 30);
+ MYASSERT(days_per_month(12,4853) == 31);
+ MYASSERT(!days_per_month(13,45894));
+
+ /* rasqal_xsd_datetime_parse_and_normalize,
+ rasqal_xsd_datetime_to_string and
+ rasqal_xsd_datetime_string_to_canonical */
+
+ #define PARSE_AND_NORMALIZE(_s,_d) \
+ rasqal_xsd_datetime_parse_and_normalize((const unsigned char*)_s, _d)
+
+ /* generic */
+
+ MYASSERT(!rasqal_xsd_datetime_to_string(0));
+
+ MYASSERT(PARSE_AND_NORMALIZE(0,0));
+ MYASSERT(PARSE_AND_NORMALIZE("uhgsufi",0));
+ MYASSERT(PARSE_AND_NORMALIZE(0,&d));
+ MYASSERT(PARSE_AND_NORMALIZE("fsdhufhdsuifhidu",&d));
+
+ /* year */
+
+ MYASSERT(PARSE_AND_NORMALIZE("123-12-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("-123-12-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("0000-12-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("01234-12-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("-01234-12-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("1234a12-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("-1234b12-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("g162-12-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("5476574658746587465874-12-12T12:12:12Z",&d));
+
+ MYASSERT(test_datetime_parser_tostring("1234-12-12T12:12:12Z", "1234-12-12T12:12:12Z")==0);
+ MYASSERT(test_datetime_parser_tostring("-1234-12-12T12:12:12Z", "-1234-12-12T12:12:12Z")==0);
+ MYASSERT(test_datetime_parser_tostring("1234567890-12-12T12:12:12Z", "1234567890-12-12T12:12:12Z")==0);
+ MYASSERT(test_datetime_parser_tostring("-1234567890-12-12T12:12:12Z", "-1234567890-12-12T12:12:12Z")==0);
+
+ /* month */
+
+ MYASSERT(PARSE_AND_NORMALIZE("2004-v-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-00-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("PARSE_AND_NORMALIZE-011-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-13-12T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-12.12T12:12:12Z",&d));
+
+ MYASSERT(test_datetime_parser_tostring("2004-01-01T12:12:12Z", "2004-01-01T12:12:12Z")==0);
+
+ /* day */
+
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-ffT12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-00T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-007T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-32T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01t12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01- 1T12:12:12Z",&d));
+
+ MYASSERT(PARSE_AND_NORMALIZE("2005-02-29T12:12:12Z",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2005-02-28T12:12:12Z",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-02-29T12:12:12Z",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2000-02-29T12:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("1900-02-29T12:12:12Z",&d));
+
+ MYASSERT(test_datetime_parser_tostring("2012-04-12T12:12:12Z", "2012-04-12T12:12:12Z")==0);
+
+ /* hour */
+
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01Tew:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T-1:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T001:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T25:12:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T01.12:12Z",&d));
+
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T24:12:00Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T24:00:34Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T24:12:34Z",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T24:00:00Z",&d));
+
+ MYASSERT(test_datetime_parser_tostring("2012-04-12T24:00:00", "2012-04-13T00:00:00")==0);
+
+ /* minute */
+
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:ij:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:-1:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:042:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:69:12Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12.12Z",&d));
+
+ /* second */
+
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:ijZ",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:-1",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:054Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:69Z",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12z",&d));
+
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12",&d));
+
+ /* fraction second */
+
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12.",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12.i",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12.0",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12.01",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12.1",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12.100",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12.1000000000000000000000000000000000000000000",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12.5798459847598743987549",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12.1d",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12.1Z",&d));
+
+ MYASSERT(test_datetime_parser_tostring("2006-05-18T18:36:03.01Z", "2006-05-18T18:36:03.01Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2006-05-18T18:36:03.10Z", "2006-05-18T18:36:03.1Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2006-05-18T18:36:03.010Z", "2006-05-18T18:36:03.01Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2006-05-18T18:36:03.1234Z", "2006-05-18T18:36:03.123Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2006-05-18T18:36:03.1234", "2006-05-18T18:36:03.123")==0);
+ MYASSERT(test_datetime_parser_tostring("2006-05-18T18:36:03.1239Z", "2006-05-18T18:36:03.123Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2006-05-18T18:36:03.1239", "2006-05-18T18:36:03.123")==0);
+
+ /* timezones + normalization */
+
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12-",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+00.00",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+aa:bb",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+15:00",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+14:01",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12+14:00",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12-14:01",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12-14:00",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+10:99",&d));
+ MYASSERT(!PARSE_AND_NORMALIZE("2004-01-01T12:12:12+10:59",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+10:059",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+010:59",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+10:59a",&d));
+ MYASSERT(PARSE_AND_NORMALIZE("2004-01-01T12:12:12+10:059",&d));
+
+ MYASSERT(test_datetime_parser_tostring("2004-12-31T23:50:22-01:15", "2005-01-01T01:05:22Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2005-01-01T01:00:05+02:12", "2004-12-31T22:48:05Z")==0);
+ MYASSERT(test_datetime_parser_tostring("0001-01-01T00:00:00+00:01", "-0001-12-31T23:59:00Z")==0);
+ MYASSERT(test_datetime_parser_tostring("-0001-12-31T23:59:00-00:01", "0001-01-01T00:00:00Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2005-03-01T00:00:00+01:00", "2005-02-28T23:00:00Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2004-03-01T00:00:00+01:00", "2004-02-29T23:00:00Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2005-02-28T23:00:00-01:00", "2005-03-01T00:00:00Z")==0);
+ MYASSERT(test_datetime_parser_tostring("2004-02-29T23:00:00-01:00", "2004-03-01T00:00:00Z")==0);
+
+ return 0;
+}
+
+#endif
diff --git a/src/rasqal/rasqal_decimal.c b/src/rasqal/rasqal_decimal.c
new file mode 100644
index 0000000..1051224
--- /dev/null
+++ b/src/rasqal/rasqal_decimal.c
@@ -0,0 +1,941 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_decimal.c - Rasqal XSD Decimal
+ *
+ * Copyright (C) 2007-2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+/* prototypes */
+static void rasqal_xsd_decimal_init(rasqal_xsd_decimal* dec);
+static void rasqal_xsd_decimal_clear(rasqal_xsd_decimal* dec);
+
+
+#ifdef RASQAL_DECIMAL_C99
+/* C99 Decimal
+ * Based on http://www2.hursley.ibm.com/decimal/
+ */
+
+#include <float.h>
+#define RASQAL_DECIMAL_RAW _Decimal64
+#define RASQAL_DECIMAL_ROUNDING int
+
+#else
+#ifdef RASQAL_DECIMAL_MPFR
+/* MPFR multiple-precision floating-point computations with correct rounding
+ * http://www.mpfr.org/
+ */
+
+#ifdef HAVE_MPFR_H
+#include <mpfr.h>
+#endif
+#define RASQAL_DECIMAL_RAW mpfr_t
+#define RASQAL_DECIMAL_ROUNDING mp_rnd_t
+
+#else
+#ifdef RASQAL_DECIMAL_GMP
+/* GNU MP - GNU Multiple Precision Arithmetic Library
+ * http://gmplib.org/
+ */
+#ifdef HAVE_GMP_H
+#include <gmp.h>
+#endif
+#define RASQAL_DECIMAL_RAW mpf_t
+#define RASQAL_DECIMAL_ROUNDING int
+
+#else
+
+/* No implementation - use double. */
+#define RASQAL_DECIMAL_RAW double
+#define RASQAL_DECIMAL_ROUNDING int
+
+#endif
+#endif
+#endif
+
+struct rasqal_xsd_decimal_s {
+ unsigned int precision_digits;
+ unsigned int precision_bits;
+ RASQAL_DECIMAL_RAW raw;
+ RASQAL_DECIMAL_ROUNDING rounding;
+ char* string;
+ size_t string_len;
+};
+
+
+/**
+ * rasqal_new_xsd_decimal:
+ *
+ * Create a new XSD Decimal object.
+ *
+ * Return value: new xsd:decimal object or NULL on failure.
+ **/
+rasqal_xsd_decimal*
+rasqal_new_xsd_decimal(void)
+{
+ rasqal_xsd_decimal* dec;
+ dec=(rasqal_xsd_decimal*)RASQAL_MALLOC(decimal, sizeof(rasqal_xsd_decimal));
+ if(dec)
+ rasqal_xsd_decimal_init(dec);
+ return dec;
+}
+
+
+/**
+ * rasqal_free_xsd_decimal:
+ * @dec: Decimal object
+ *
+ * Destroy XSD Decimal object.
+ **/
+void
+rasqal_free_xsd_decimal(rasqal_xsd_decimal* dec)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(dec, rasqal_xsd_decimal);
+
+ rasqal_xsd_decimal_clear(dec);
+ RASQAL_FREE(decimal, dec);
+}
+
+
+static void
+rasqal_xsd_decimal_init(rasqal_xsd_decimal* dec)
+{
+ /* XSD wants min of 18 decimal (base 10) digits
+ * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#decimal
+ */
+ dec->precision_digits= 32;
+ /* over-estimate bits since log(10)/log(2) = 3.32192809488736234789 < 4 */
+ dec->precision_bits= dec->precision_digits*4;
+
+#ifdef RASQAL_DECIMAL_C99
+ dec->raw= 0DD;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ mpfr_init2(dec->raw, dec->precision_bits);
+
+ /* GMP_RNDD, GMP_RNDU, GMP_RNDN, GMP_RNDZ */
+ dec->rounding=mpfr_get_default_rounding_mode();
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_init2(dec->raw, dec->precision_bits);
+#endif
+#ifdef RASQAL_DECIMAL_NONE
+ dec->raw= 0e0;
+#endif
+
+ dec->string=NULL;
+ dec->string_len=0;
+}
+
+
+static void
+rasqal_xsd_decimal_clear_string(rasqal_xsd_decimal* dec)
+{
+ if(dec->string) {
+ RASQAL_FREE(cstring, dec->string);
+ dec->string=NULL;
+ }
+ dec->string_len=0;
+}
+
+
+static void
+rasqal_xsd_decimal_clear(rasqal_xsd_decimal* dec)
+{
+ rasqal_xsd_decimal_clear_string(dec);
+#ifdef RASQAL_DECIMAL_C99
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ mpfr_clear(dec->raw);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_clear(dec->raw);
+#endif
+#ifdef RASQAL_DECIMAL_NONE
+ dec->raw= 0e0;
+#endif
+}
+
+
+/**
+ * rasqal_xsd_decimal_set_string:
+ * @dec: XSD Decimal
+ * @string: lexical form
+ *
+ * Set an XSD Decimal value from a string lexical form
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_set_string(rasqal_xsd_decimal* dec, const char* string)
+{
+ int rc=0;
+ size_t len;
+
+ if(!string)
+ return 1;
+
+ rasqal_xsd_decimal_clear_string(dec);
+
+ len=strlen(string);
+ dec->string=(char*)RASQAL_MALLOC(cstring, len+1);
+ if(!dec->string)
+ return 1;
+ strncpy(dec->string, string, len+1);
+ dec->string_len=len;
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ dec->raw=strtod(string, NULL);
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ rc=mpfr_set_str(dec->raw, string, 10, dec->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ rc=mpf_set_str(dec->raw, string, 10);
+#endif
+
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_set_long:
+ * @dec: XSD Decimal
+ * @l: long
+ *
+ * Set an XSD Decimal value from a long.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_set_long(rasqal_xsd_decimal* dec, long l)
+{
+ int rc=0;
+
+ rasqal_xsd_decimal_clear_string(dec);
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ dec->raw=l;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ rc=mpfr_set_si(dec->raw, l, dec->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_set_si(dec->raw, l);
+#endif
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_set_double:
+ * @dec: XSD Decimal
+ * @d: double
+ *
+ * Set an XSD Decimal value from a double.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_set_double(rasqal_xsd_decimal* dec, double d)
+{
+ int rc=0;
+
+ rasqal_xsd_decimal_clear_string(dec);
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ dec->raw=d;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ mpfr_set_d(dec->raw, d, dec->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_set_d(dec->raw, d);
+#endif
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_get_double:
+ * @dec: XSD Decimal
+ *
+ * Get an XSD Decimal as a double (may lose precision)
+ *
+ * Return value: double value.
+ **/
+double
+rasqal_xsd_decimal_get_double(rasqal_xsd_decimal* dec)
+{
+ double result=0e0;
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ result=(double)dec->raw;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ result=mpfr_get_d(dec->raw, dec->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ result=mpf_get_d(dec->raw);
+#endif
+
+ return result;
+}
+
+
+/**
+ * rasqal_xsd_decimal_as_string:
+ * @dec: XSD Decimal
+ *
+ * Get an XSD Decimal as a string lexical form.
+ *
+ * The returned string is shared and owned by the @dec object and
+ * must be copied.
+ *
+ * Return value: lexical form string or NULL on failure.
+ **/
+char*
+rasqal_xsd_decimal_as_string(rasqal_xsd_decimal* dec)
+{
+ char *s=NULL;
+ size_t len=0;
+#if defined(RASQAL_DECIMAL_MPFR) || defined(RASQAL_DECIMAL_GMP)
+ mp_exp_t expo;
+ char *mpf_s;
+#endif
+
+ if(dec->string)
+ return dec->string;
+
+#ifdef RASQAL_DECIMAL_C99
+ len=dec->precision_digits;
+ s=RASQAL_MALLOC(cstring, len+1);
+ if(!s)
+ return NULL;
+ /* NOTE: Never seen a sprintf that supports _Decimal yet */
+ snprintf(s, len, "%DDf", dec->raw);
+ len=strlen(s);
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ mpf_s=mpfr_get_str(NULL, &expo, 10, 0, dec->raw, dec->rounding);
+ if(mpf_s) {
+ size_t from_len=strlen(mpf_s);
+ char *from_p=mpf_s;
+ size_t to_len;
+
+ /* 7=strlen("0.0e0")+1 for sign */
+ to_len=!from_len ? 6 : (from_len*2);
+
+ s=(char*)RASQAL_MALLOC(cstring, to_len);
+ if(!s) {
+ mpfr_free_str((char*)mpf_s);
+ return NULL;
+ }
+ /* first digit of mantissa */
+ if(!*from_p || *from_p == '0') {
+ len=5;
+ strncpy(s, "0.0e0", len+1);
+ } else {
+ char* to_p=s;
+ int n;
+
+ if(*from_p == '-') {
+ *to_p++ = *from_p++;
+ from_len--;
+ }
+
+ *to_p++ = *from_p++;
+ from_len--;
+ *to_p++ = '.';
+ /* rest of mantissa */
+ /* remove trailing 0s */
+ while(from_len > 1 && from_p[from_len-1]=='0')
+ from_len--;
+ strncpy(to_p, from_p, from_len);
+ to_p += from_len;
+ /* exp */
+ n=sprintf(to_p, "e%ld", expo-1);
+ len=to_p+n-s;
+ }
+ mpfr_free_str((char*)mpf_s);
+ }
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_s=mpf_get_str(NULL, &expo, 10, 0, dec->raw);
+ if(mpf_s) {
+ size_t from_len=strlen(mpf_s);
+ char *from_p=mpf_s;
+ size_t to_len;
+
+ /* 7=strlen("0.0e0")+1 for sign */
+ to_len=!from_len ? 6 : (from_len*2);
+
+ s=RASQAL_MALLOC(cstring, to_len+1);
+ if(!s) {
+ free(mpf_s);
+ return NULL;
+ }
+ /* first digit of mantissa */
+ if(!*from_p || *from_p == '0') {
+ len=5;
+ strncpy(s, "0.0e0", len+1);
+ } else {
+ char *to_p=s;
+ int n;
+
+ if(*from_p == '-') {
+ *to_p++ = *from_p++;
+ from_len--;
+ }
+
+ *to_p++ = *from_p++;
+ from_len--;
+ *to_p++ = '.';
+ /* rest of mantissa */
+ strncpy(to_p, from_p, from_len);
+ to_p+= from_len;
+ /* exp */
+ n=sprintf(to_p, "e%ld", expo-1);
+ len=to_p+n-s;
+ }
+ free(mpf_s);
+ }
+#endif
+#ifdef RASQAL_DECIMAL_NONE
+ {
+ char *p, *p2;
+ char fmt[16];
+ /* construct a format string */
+ snprintf(fmt, sizeof(fmt), "%%.%de", dec->precision_digits);
+
+ /* snprintf with no buffer to get buffer length */
+ len=snprintf(NULL, 0, fmt, dec->raw)+1;
+ s=(char*)RASQAL_MALLOC(cstring, len);
+ if(!s)
+ return NULL;
+
+ /* format with snprintf */
+ snprintf(s, len, fmt, dec->raw);
+
+ /* "1.2000e+02"
+ * - remove zeros before 'e', leave one for ".0"
+ * - remove '+' after 'e' (leave '-')
+ * - remove leading zero after 'e' */
+
+ /* find 'e' */
+ p=strchr(s, 'e');
+
+ /* move 'e' and everything that follows on top of the trailing zeros */
+ for(p2=p; *--p2 == '0'; ) ;
+ if(*p2=='.') p2++; /* leave ".0" */
+ p2++;
+
+ /* move string tail if required */
+ if(p != p2)
+ while((*p2++=*p++)) ;
+
+ /* adjust p to the first char after 'e' */
+ p=strchr(s, 'e');
+ p++;
+
+ /* leave '-' but remove '+' */
+ if(*p=='-') {
+ p++;
+ p2=p;
+ } else {
+ p2=p+1;
+ }
+ /* skip leading zero afer "e[+-]" */
+ if(*p2=='0') p2++;
+
+ /* move string tail if required */
+ if(p != p2)
+ while((*p++=*p2++)) ;
+
+ len=strlen(s);
+ }
+#endif
+
+ dec->string=s;
+ dec->string_len=len;
+ return s;
+}
+
+
+/**
+ * rasqal_xsd_decimal_as_counted_string:
+ * @dec: XSD Decimal
+ * @len_p: pointer to length variable (or NULL)
+ *
+ * Get an XSD Decimal as a string lexical form with optional length.
+ *
+ * The returned string is shared and owned by the @dec object and
+ * must be copied. If @len_p is not NULL, the length of the returned
+ * string is stored.
+ *
+ * Return value: lexical form string or NULL on failure.
+ **/
+char*
+rasqal_xsd_decimal_as_counted_string(rasqal_xsd_decimal* dec, size_t* len_p)
+{
+ char* s=rasqal_xsd_decimal_as_string(dec);
+ if(s && len_p)
+ *len_p=dec->string_len;
+ return s;
+}
+
+
+/**
+ * rasqal_xsd_decimal_print:
+ * @dec: XSD Decimal
+ * @stream: FILE* stream
+ *
+ * Write an XSD Decimal to a FILE* stream
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_print(rasqal_xsd_decimal* dec, FILE* stream)
+{
+ char* s=NULL;
+ size_t len=0;
+
+ s=rasqal_xsd_decimal_as_counted_string(dec, &len);
+ if(!s)
+ return 1;
+
+ fwrite(s, 1, len, stream);
+ return 0;
+}
+
+
+/**
+ * rasqal_xsd_decimal_add:
+ * @result: result variable
+ * @a: argment decimal 1
+ * @b: argument decimal 2
+ *
+ * Add two XSD Decimals and store in result XSD Decimal
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_add(rasqal_xsd_decimal* result,
+ rasqal_xsd_decimal* a, rasqal_xsd_decimal* b)
+{
+ int rc=0;
+
+ rasqal_xsd_decimal_clear_string(result);
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ result->raw = a->raw + b->raw;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ rc=mpfr_add(result->raw, a->raw, b->raw, result->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_add(result->raw, a->raw, b->raw);
+#endif
+
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_subtract:
+ * @result: result variable
+ * @a: argment decimal 1
+ * @b: argument decimal 2
+ *
+ * Subtract two XSD Decimals and store in result XSD Decimal
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_subtract(rasqal_xsd_decimal* result,
+ rasqal_xsd_decimal* a, rasqal_xsd_decimal* b)
+{
+ int rc=0;
+
+ rasqal_xsd_decimal_clear_string(result);
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ result->raw = a->raw - b->raw;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ rc=mpfr_sub(result->raw, a->raw, b->raw, result->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_sub(result->raw, a->raw, b->raw);
+#endif
+
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_multiply:
+ * @result: result variable
+ * @a: argment decimal 1
+ * @b: argument decimal 2
+ *
+ * Multiply two XSD Decimals and store in result XSD Decimal
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_multiply(rasqal_xsd_decimal* result,
+ rasqal_xsd_decimal* a, rasqal_xsd_decimal* b)
+{
+ int rc=0;
+
+ rasqal_xsd_decimal_clear_string(result);
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ result->raw = a->raw * b->raw;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ rc=mpfr_mul(result->raw, a->raw, b->raw, result->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_mul(result->raw, a->raw, b->raw);
+#endif
+
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_is_zero:
+ * @d: decimal
+ *
+ * Test if an XSD decimal is zero.
+ *
+ * Return value: non-0 if decimal is zero
+ **/
+int
+rasqal_xsd_decimal_is_zero(rasqal_xsd_decimal* d)
+{
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ if(!d->raw)
+ return 1;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ if(mpfr_zero_p(d->raw))
+ return 1;
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ if(!mpf_sgn(d->raw))
+ return 1;
+#endif
+
+ return 0;
+}
+
+
+/**
+ * rasqal_xsd_decimal_divide:
+ * @result: result variable
+ * @a: argment decimal 1
+ * @b: argument decimal 2
+ *
+ * Divide two XSD Decimals and store in result XSD Decimal
+ *
+ * If the divisor @b is 0, failure is returned
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_divide(rasqal_xsd_decimal* result,
+ rasqal_xsd_decimal* a, rasqal_xsd_decimal* b)
+{
+ int rc=0;
+
+ rasqal_xsd_decimal_clear_string(result);
+
+ if(rasqal_xsd_decimal_is_zero(b))
+ return 1;
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ result->raw = a->raw / b->raw;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ rc=mpfr_div(result->raw, a->raw, b->raw, result->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_div(result->raw, a->raw, b->raw);
+#endif
+
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_negate:
+ * @result: result variable
+ * @a: argment decimal
+ *
+ * Negate an XSD Decimal
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_xsd_decimal_negate(rasqal_xsd_decimal* result, rasqal_xsd_decimal* a)
+{
+ int rc=0;
+
+ rasqal_xsd_decimal_clear_string(result);
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ result->raw = -a->raw;
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ rc=mpfr_neg(result->raw, a->raw, result->rounding);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ mpf_neg(result->raw, a->raw);
+#endif
+
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_compare:
+ * @a: first XSD decimal
+ * @b: second XSD decimal
+ *
+ * Compare two XSD Decimals
+ *
+ * Return value: <0 if @a is less than @b, 0 if equal, >1 otherwise
+ **/
+int
+rasqal_xsd_decimal_compare(rasqal_xsd_decimal* a, rasqal_xsd_decimal* b)
+{
+ int rc=0;
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ rc= (int)(b->raw - a->raw);
+#endif
+#ifdef RASQAL_DECIMAL_MPFR
+ rc=mpfr_cmp(a->raw, b->raw);
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+ rc=mpf_cmp(a->raw, b->raw);
+#endif
+
+ return rc;
+}
+
+
+/**
+ * rasqal_xsd_decimal_equals:
+ * @a: first XSD Decimal
+ * @b: second XSD Decimal
+ *
+ * Compare two XSD Decimals for equality.
+ *
+ * Return value: non-0 if equal.
+ **/
+int
+rasqal_xsd_decimal_equals(rasqal_xsd_decimal* a, rasqal_xsd_decimal* b)
+{
+ int rc;
+
+#if defined(RASQAL_DECIMAL_C99) || defined(RASQAL_DECIMAL_NONE)
+ rc= (b->raw == a->raw);
+#elif defined(RASQAL_DECIMAL_MPFR)
+ rc=mpfr_equal_p(a->raw, b->raw);
+#elif defined(RASQAL_DECIMAL_GMP)
+ /* NOTE: Not using mpf_eq() but could do, with sufficient bits */
+ rc=!mpf_cmp(a->raw, b->raw);
+#else
+#error RASQAL_DECIMAL flagging error
+#endif
+
+ return rc;
+}
+
+
+#ifdef STANDALONE
+#include <stdio.h>
+
+int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[]) {
+ char const *program=rasqal_basename(*argv);
+ int failures=0;
+ rasqal_xsd_decimal a;
+ rasqal_xsd_decimal b;
+ rasqal_xsd_decimal *result;
+ rasqal_xsd_decimal *result2;
+ double result_d;
+ char *result_s;
+ int result_i;
+ const long a_long=1234567890L;
+ const double a_double=1234567890e0;
+ const char* b_string="123456789012345678e0";
+ const char* expected_a_plus_b="1.23456790246913568e17";
+ const char* expected_a_plus_b_minus_b="1.23456789e9";
+ const char* expected_a_plus_b_minus_b_minus_a="0.0e0";
+ const char* expected_negative_b="-1.23456789012345678e17";
+ int expected_a_compare_b= -1;
+ int expected_a_equals_b= 0;
+
+#ifdef RASQAL_DECIMAL_MPFR
+ fprintf(stderr, "%s: Using MPFR %s\n", program, mpfr_get_version());
+#endif
+#ifdef RASQAL_DECIMAL_GMP
+#ifdef HAVE_GMP_VERSION
+ fprintf(stderr, "%s: Using GMP %s\n", program, gmp_version);
+#else
+ fprintf(stderr, "%s: Using GMP version unknown\n", program);
+#endif
+#endif
+#ifdef RASQAL_DECIMAL_NONE
+ fprintf(stderr, "%s: Using double\n", program);
+#endif
+
+#ifdef RASQAL_DECIMAL_NONE
+#define FAIL_LABEL
+#define FAIL failures++
+#else
+#define FAIL_LABEL tidy:
+#define FAIL failures++; goto tidy
+#endif
+
+ rasqal_xsd_decimal_init(&a);
+ rasqal_xsd_decimal_init(&b);
+
+ result=rasqal_new_xsd_decimal();
+ result2=rasqal_new_xsd_decimal();
+ if(!result || !result2) {
+ fprintf(stderr, "%s: rasqal_new_xsd_decimal() failed\n", program);
+ FAIL;
+ }
+
+ rasqal_xsd_decimal_set_long(&a, a_long);
+ rasqal_xsd_decimal_set_string(&b, b_string);
+
+ result_d=rasqal_xsd_decimal_get_double(&a);
+ if(result_d != a_double) {
+ fprintf(stderr, "FAILED: a=%f expected %f\n", result_d, a_double);
+ FAIL;
+ }
+
+ result_s=rasqal_xsd_decimal_as_string(&b);
+ if(strcmp(result_s, b_string)) {
+ fprintf(stderr, "FAILED: b=%s expected %s\n", result_s, b_string);
+ FAIL;
+ }
+
+ /* result = a+b */
+ rasqal_xsd_decimal_add(result, &a, &b);
+
+ result_s=rasqal_xsd_decimal_as_string(result);
+ if(strcmp(result_s, expected_a_plus_b)) {
+ fprintf(stderr, "FAILED: a+b=%s expected %s\n", result_s,
+ expected_a_plus_b);
+ FAIL;
+ }
+
+ /* result2 = result-b */
+ rasqal_xsd_decimal_subtract(result2, result, &b);
+
+ result_s=rasqal_xsd_decimal_as_string(result2);
+ if(strcmp(result_s, expected_a_plus_b_minus_b)) {
+ fprintf(stderr, "FAILED: (a+b)-b=%s expected %s\n", result_s,
+ expected_a_plus_b_minus_b);
+ FAIL;
+ }
+
+ /* result = result2-a */
+ rasqal_xsd_decimal_subtract(result, result2, &a);
+
+ result_s=rasqal_xsd_decimal_as_string(result);
+ if(strcmp(result_s, expected_a_plus_b_minus_b_minus_a)) {
+ fprintf(stderr, "FAILED: (a+b)-b-a=%s expected %s\n", result_s,
+ expected_a_plus_b_minus_b_minus_a);
+ FAIL;
+ }
+
+ result_i=rasqal_xsd_decimal_compare(&a, &b);
+ if((expected_a_compare_b < 0 && result_i >= 0) ||
+ (expected_a_compare_b > 0 && result_i <= 0) ||
+ (expected_a_compare_b == 0 && result_i != 0))
+ {
+ fprintf(stderr, "FAILED: a compare b = %d expected %d\n",
+ result_i, expected_a_compare_b);
+ FAIL;
+ }
+
+ result_i=rasqal_xsd_decimal_equals(&a, &b);
+ if(result_i != expected_a_equals_b) {
+ fprintf(stderr, "FAILED: a equals b = %d expected %d\n",
+ result_i, expected_a_equals_b);
+ FAIL;
+ }
+
+ /* result2 = -b */
+ rasqal_xsd_decimal_negate(result, &b);
+
+ result_s=rasqal_xsd_decimal_as_string(result);
+ if(strcmp(result_s, expected_negative_b)) {
+ fprintf(stderr, "FAILED: -b=%s expected %s\n", result_s,
+ expected_negative_b);
+ FAIL;
+ }
+
+
+ FAIL_LABEL
+ rasqal_xsd_decimal_clear(&a);
+ rasqal_xsd_decimal_clear(&b);
+ if(result)
+ rasqal_free_xsd_decimal(result);
+ if(result2)
+ rasqal_free_xsd_decimal(result2);
+
+#ifdef RASQAL_DECIMAL_NONE
+ if(failures)
+ fprintf(stderr, "%s: ignoring %d failures as RASQAL_DECIMAL_NONE specified\n", program, failures);
+ return 0;
+#else
+ return failures;
+#endif
+}
+#endif
diff --git a/src/rasqal/rasqal_engine.c b/src/rasqal/rasqal_engine.c
new file mode 100644
index 0000000..f27aeca
--- /dev/null
+++ b/src/rasqal/rasqal_engine.c
@@ -0,0 +1,1783 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_engine.c - Rasqal query engine
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+/**
+ *
+ * Query Engine 1 Internals
+ *
+ * This is the rasqal 0.9.16 and earlier query engine.
+ *
+ * This query engine is based on executing directly the query graph
+ * pattern structure by using graph-pattern specific data objects
+ * to preserve execution state.
+ *
+ * This version was refactored from earlier version code to return
+ * #rasqal_row on demand or all rows in one go if required.
+ *
+ * The lower-level query engine operates over a triples source
+ * factory that returns triples that match a triple pattern for a
+ * graph and bindings variables or determines if a triple is present
+ * in a graph.
+ *
+ * Each graph pattern data records information per-triple pattern
+ * (#rasqal_triple_meta), the current 'column' aka absolute triple#
+ * being executed and various flags and counts. It iterates over the
+ * triple patterns until they are all exhausted.
+ *
+ * For a basic graph pattern (#RASQAL_GRAPH_PATTERN_OPERATOR_BASIC),
+ * every triple_meta in every column must match for a result to be
+ * returned. A match may bind 0 or more variables per triple.
+ *
+ * For an optional graph pattern
+ * (#RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL), a result may be
+ * returned even if there are no matches; i.e. an optional graph
+ * pattern always succeeds. This is the flaw in this execution
+ * engine since in the case where there are multiple optionals it
+ * cannot properly iterate across them when some match and some do
+ * not.
+ *
+ * The execution engine also does not understand group graph patterns
+ * and expects a single top-level sequence of graph patterns (group)
+ * that are basic graph patterns or optional. Filters are expected
+ * to be contained in the basic or optional graph patterns and
+ * rasqal_query_engine_1_execute_transform_hack() is used to
+ * transform via a hack to turn the query structure into one that can
+ * be executed.
+ *
+ * An internal rowsource is constructed by
+ * rasqal_engine_make_rowsource() in order to get all result rows
+ * in rasqal_query_engine_1_get_all_rows() but is otherwise only
+ * referenced.
+ */
+
+
+#if 0
+#undef RASQAL_DEBUG
+#define RASQAL_DEBUG 2
+#endif
+
+
+#define DEBUG_FH stderr
+
+
+
+/* local types */
+
+/* The execution data here is a sequence of
+ * rasqal_graph_pattern_data execution data of size
+ * query->graph_pattern_count with each rasqal_graph_pattern_data
+ */
+typedef struct {
+ rasqal_query* query;
+ rasqal_query_results* query_results;
+
+ raptor_sequence* seq;
+
+ rasqal_triples_source* triples_source;
+
+ /* New variables bound from during the current 'next result' run */
+ int new_bindings_count;
+
+ /* Source of rows that are filling the query result */
+ rasqal_rowsource* rowsource;
+
+ /* how many results already found (for get_row to check limit/offset) */
+ int result_count;
+
+ /* number of variables in a row */
+ int size;
+} rasqal_engine_execution_data;
+
+
+typedef enum {
+ STEP_UNKNOWN,
+ STEP_SEARCHING,
+ STEP_GOT_MATCH,
+ STEP_FINISHED,
+ STEP_ERROR,
+
+ STEP_LAST = STEP_ERROR
+} rasqal_engine_step;
+
+
+#ifdef RASQAL_DEBUG
+static const char * rasqal_engine_step_names[STEP_LAST+1] = {
+ "<unknown>",
+ "searching",
+ "got match",
+ "finished",
+ "error"
+};
+#endif
+
+
+
+/* local prototypes */
+static rasqal_engine_step rasqal_engine_check_constraint(rasqal_engine_execution_data* execution_data, rasqal_graph_pattern *gp);
+static int rasqal_engine_graph_pattern_init(rasqal_engine_execution_data* execution_data, rasqal_graph_pattern *gp);
+
+
+typedef struct {
+ rasqal_graph_pattern* gp;
+
+ /* An array of items, one per triple in the pattern graph */
+ rasqal_triple_meta* triple_meta;
+
+ /* Executing column in the current graph pattern */
+ int column;
+
+ /* first graph_pattern in sequence with flags RASQAL_TRIPLE_FLAGS_OPTIONAL */
+ int optional_graph_pattern;
+
+ /* current position in the sequence */
+ int current_graph_pattern;
+
+ /* Count of all optional matches for the current mandatory matches */
+ int optional_graph_pattern_matches_count;
+
+ /* Number of matches returned */
+ int matches_returned;
+
+ /* true when this graph pattern matched last time */
+ int matched;
+
+ /* true when an optional graph pattern finished last time round */
+ int finished;
+
+ /* Max optional graph pattern allowed so far to stop backtracking
+ * going over old graph patterns
+ */
+ int max_optional_graph_pattern;
+
+} rasqal_engine_gp_data;
+
+
+static rasqal_engine_gp_data*
+rasqal_new_engine_gp_data(rasqal_graph_pattern* gp)
+{
+ rasqal_engine_gp_data* gp_data;
+
+ gp_data = (rasqal_engine_gp_data*)RASQAL_CALLOC(rasqal_engine_gp_data, 1,
+ sizeof(rasqal_engine_gp_data));
+ if(!gp_data)
+ return NULL;
+
+ gp_data->gp = gp;
+
+ gp_data->optional_graph_pattern= -1;
+ gp_data->matches_returned = 0;
+ gp_data->column= -1;
+
+ return gp_data;
+}
+
+
+static void
+rasqal_free_gp_data(rasqal_engine_gp_data* gp_data)
+{
+ rasqal_graph_pattern* gp;
+
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(gp_data, rasqal_engine_gp_data);
+
+ gp = gp_data->gp;
+ if(gp_data->triple_meta) {
+ if(gp) {
+ while(gp_data->column >= gp->start_column) {
+ rasqal_triple_meta *m;
+ m = &gp_data->triple_meta[gp_data->column - gp->start_column];
+ rasqal_reset_triple_meta(m);
+ gp_data->column--;
+ }
+ }
+ RASQAL_FREE(rasqal_triple_meta, gp_data->triple_meta);
+ gp_data->triple_meta = NULL;
+ }
+
+ RASQAL_FREE(rasqal_engine_gp_data, gp_data);
+ return;
+}
+
+
+/**
+ * rasqal_engine_group_graph_pattern_get_next_match:
+ * @query_results: Query results to execute
+ * @gp: group graph pattern
+ *
+ * INTERNAL - Get the next match in a group graph pattern
+ *
+ * return: <0 failure, 0 end of results, >0 match
+ */
+static int
+rasqal_engine_group_graph_pattern_get_next_match(rasqal_engine_execution_data* execution_data,
+ rasqal_graph_pattern* gp)
+{
+ rasqal_query* query;
+ rasqal_query_results* query_results;
+
+ query = execution_data->query;
+ query_results = execution_data->query_results;
+
+#if 0
+ rasqal_engine_gp_data* gp_data;
+
+ gp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp->gp_index);
+#endif
+
+ /* FIXME - sequence of graph_patterns not implemented, finish */
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Graph pattern %s operation is not implemented yet. Ending query execution.",
+ rasqal_graph_pattern_operator_as_string(gp->op));
+
+ RASQAL_DEBUG1("Failing query with sequence of graph_patterns\n");
+ return -1;
+}
+
+
+/**
+ * rasqal_engine_triple_graph_pattern_get_next_match:
+ * @query_results: Query results to execute
+ * @gp: graph pattern to use
+ *
+ * INTERNAL - Get the next match in a triple graph pattern
+ *
+ * return: <0 failure, 0 end of results, >0 match
+ */
+static int
+rasqal_engine_triple_graph_pattern_get_next_match(rasqal_engine_execution_data* execution_data,
+ rasqal_graph_pattern* gp)
+{
+ rasqal_query* query;
+ rasqal_query_results* query_results;
+ int rc = 0;
+ rasqal_engine_gp_data* gp_data;
+
+ query = execution_data->query;
+ query_results = execution_data->query_results;
+ gp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp->gp_index);
+
+ while(gp_data->column >= gp->start_column) {
+ rasqal_triple_meta *m;
+ rasqal_triple *t;
+
+ m = &gp_data->triple_meta[gp_data->column - gp->start_column];
+ t = (rasqal_triple*)raptor_sequence_get_at(gp->triples, gp_data->column);
+
+ rc = 1;
+
+ if(!m) {
+ /* error recovery - no match */
+ gp_data->column--;
+ rc= -1;
+ return rc;
+ }
+
+ if(m->executed) {
+ RASQAL_DEBUG2("triplesMatch already executed in column %d\n",
+ gp_data->column);
+ gp_data->column--;
+ continue;
+ }
+
+ if (m->is_exact) {
+ /* exact triple match wanted */
+
+ if(!rasqal_triples_source_triple_present(execution_data->triples_source, t)) {
+ /* failed */
+ RASQAL_DEBUG2("exact match failed for column %d\n", gp_data->column);
+ gp_data->column--;
+ }
+#ifdef RASQAL_DEBUG
+ else
+ RASQAL_DEBUG2("exact match OK for column %d\n", gp_data->column);
+#endif
+
+ RASQAL_DEBUG2("end of exact triplesMatch for column %d\n",
+ gp_data->column);
+ m->executed = 1;
+
+ } else {
+ /* triple pattern match wanted */
+ int parts;
+
+ if(!m->triples_match) {
+ /* Column has no triplesMatch so create a new query */
+ m->triples_match = rasqal_new_triples_match(execution_data->query,
+ execution_data->triples_source,
+ m, t);
+ if(!m->triples_match) {
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Failed to make a triple match for column%d",
+ gp_data->column);
+ /* failed to match */
+ gp_data->column--;
+ rc= -1;
+ return rc;
+ }
+ RASQAL_DEBUG2("made new triplesMatch for column %d\n", gp_data->column);
+ }
+
+
+ if(rasqal_triples_match_is_end(m->triples_match)) {
+ int resets = 0;
+
+ RASQAL_DEBUG2("end of pattern triplesMatch for column %d\n",
+ gp_data->column);
+ m->executed = 1;
+
+ resets = rasqal_reset_triple_meta(m);
+ execution_data->new_bindings_count-= resets;
+ if(execution_data->new_bindings_count < 0)
+ execution_data->new_bindings_count = 0;
+
+ gp_data->column--;
+ continue;
+ }
+
+ if(m->parts) {
+ parts = rasqal_triples_match_bind_match(m->triples_match, m->bindings,
+ m->parts);
+ RASQAL_DEBUG3("bind_match for column %d returned parts %d\n",
+ gp_data->column, parts);
+ if(!parts)
+ rc = 0;
+ if(parts & RASQAL_TRIPLE_SUBJECT)
+ execution_data->new_bindings_count++;
+ if(parts & RASQAL_TRIPLE_PREDICATE)
+ execution_data->new_bindings_count++;
+ if(parts & RASQAL_TRIPLE_OBJECT)
+ execution_data->new_bindings_count++;
+ if(parts & RASQAL_TRIPLE_ORIGIN)
+ execution_data->new_bindings_count++;
+ } else {
+ RASQAL_DEBUG2("Nothing to bind_match for column %d\n", gp_data->column);
+ }
+
+ rasqal_triples_match_next_match(m->triples_match);
+ if(!rc)
+ continue;
+
+ }
+
+ if(gp_data->column == gp->end_column) {
+ /* Done all conjunctions */
+
+ /* exact match, so column must have ended */
+ if(m->is_exact)
+ gp_data->column--;
+
+ /* return with result (rc is 1) */
+ return rc;
+ } else if (gp_data->column >= gp->start_column)
+ gp_data->column++;
+
+ }
+
+ if(gp_data->column < gp->start_column)
+ rc = 0;
+
+ return rc;
+}
+
+
+
+/**
+ * rasqal_engine_graph_pattern_get_next_match:
+ * @query_results: Query results to execute
+ * @gp: graph pattern to use
+ *
+ * INTERNAL -Get the next match in a graph pattern
+ *
+ * return: <0 failure, 0 end of results, >0 match
+ */
+static int
+rasqal_engine_graph_pattern_get_next_match(rasqal_engine_execution_data* execution_data,
+ rasqal_graph_pattern* gp)
+{
+ if(gp->graph_patterns)
+ return rasqal_engine_group_graph_pattern_get_next_match(execution_data,
+ gp);
+ else
+ return rasqal_engine_triple_graph_pattern_get_next_match(execution_data,
+ gp);
+}
+
+
+
+#if 0
+static int
+rasqal_engine_graph_pattern_order(const void *a, const void *b)
+{
+ rasqal_graph_pattern *gp_a = *(rasqal_graph_pattern**)a;
+ rasqal_graph_pattern *gp_b = *(rasqal_graph_pattern**)b;
+
+ return (gp_a->op == RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL) -
+ (gp_b->op == RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL);
+}
+#endif
+
+
+/**
+ * rasqal_engine_graph_pattern_init:
+ * @query_results: query results to execute
+ * @gp: graph pattern in query results.
+ *
+ * INTERNAL - once only per execution initialisation of a graph pattern.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+rasqal_engine_graph_pattern_init(rasqal_engine_execution_data* execution_data,
+ rasqal_graph_pattern *gp)
+{
+ rasqal_query *query = execution_data->query;
+ rasqal_engine_gp_data* gp_data;
+
+ RASQAL_DEBUG2("Initing execution graph pattern #%d\n", gp->gp_index);
+
+ gp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp->gp_index);
+ if(!gp_data)
+ return -1;
+
+ gp_data->optional_graph_pattern= -1;
+ gp_data->current_graph_pattern= -1;
+ gp_data->column= -1;
+ gp_data->matches_returned= 0;
+
+ gp_data->matched= 0;
+ gp_data->finished= 0;
+
+ if(gp->graph_patterns)
+ gp_data->current_graph_pattern = 0;
+
+ if(gp->triples) {
+ int triples_count = gp->end_column - gp->start_column+1;
+
+ gp_data->column = gp->start_column;
+ if(gp_data->triple_meta) {
+ /* reset any previous execution */
+ rasqal_reset_triple_meta(gp_data->triple_meta);
+ memset(gp_data->triple_meta, '\0',
+ sizeof(rasqal_triple_meta)*triples_count);
+ } else {
+ gp_data->triple_meta = (rasqal_triple_meta*)RASQAL_CALLOC(rasqal_triple_meta, triples_count, sizeof(rasqal_triple_meta));
+ if(!gp_data->triple_meta)
+ return -1;
+ }
+ }
+
+ if(gp->graph_patterns) {
+ int i;
+
+#if 0
+ /* sort graph patterns, optional graph triples last */
+ raptor_sequence_sort(gp->graph_patterns, rasqal_engine_graph_pattern_order);
+#endif
+
+ for(i = 0; i < raptor_sequence_size(gp->graph_patterns); i++) {
+ int rc;
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ rc = rasqal_engine_graph_pattern_init(execution_data, sgp);
+ if(rc)
+ return rc;
+
+ if((sgp->op == RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL) &&
+ gp_data->optional_graph_pattern < 0)
+ gp_data->optional_graph_pattern = i;
+ }
+
+ }
+
+ if(gp->triples) {
+ int i;
+
+ for(i = gp->start_column; i <= gp->end_column; i++) {
+ rasqal_triple_meta *m;
+ rasqal_triple *t;
+ rasqal_variable* v;
+
+ m = &gp_data->triple_meta[i - gp->start_column];
+ if(!m)
+ return -1;
+ m->parts = (rasqal_triple_parts)0;
+
+ t = (rasqal_triple*)raptor_sequence_get_at(gp->triples, i);
+
+ if((v = rasqal_literal_as_variable(t->subject)) &&
+ query->variables_declared_in[v->offset] == i)
+ m->parts= (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_SUBJECT);
+
+ if((v = rasqal_literal_as_variable(t->predicate)) &&
+ query->variables_declared_in[v->offset] == i)
+ m->parts= (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_PREDICATE);
+
+ if((v = rasqal_literal_as_variable(t->object)) &&
+ query->variables_declared_in[v->offset] == i)
+ m->parts= (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_OBJECT);
+
+ if(t->origin &&
+ (v = rasqal_literal_as_variable(t->origin)) &&
+ query->variables_declared_in[v->offset] == i)
+ m->parts= (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_ORIGIN);
+
+ RASQAL_DEBUG4("graph pattern #%d Triple %d has parts %d\n",
+ gp->gp_index, i, m->parts);
+
+ /* exact if there are no variables in the triple parts */
+ m->is_exact = 1;
+ if(rasqal_literal_as_variable(t->predicate) ||
+ rasqal_literal_as_variable(t->subject) ||
+ rasqal_literal_as_variable(t->object))
+ m->is_exact = 0;
+
+ }
+
+ }
+
+ return 0;
+}
+
+
+static int
+rasqal_engine_remove_filter_graph_patterns(rasqal_query* query,
+ rasqal_graph_pattern* gp,
+ void *data)
+{
+ int i;
+ int saw_filter_gp = 0;
+ raptor_sequence *seq;
+ int* modified_p = (int*)data;
+ rasqal_graph_pattern* prev_gp = NULL;
+
+ if(!gp->graph_patterns)
+ return 0;
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Checking graph pattern #%d:\n ", gp->gp_index);
+ rasqal_graph_pattern_print(gp, stdout);
+ fputs("\n", stdout);
+#endif
+
+ for(i = 0; i < raptor_sequence_size(gp->graph_patterns); i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ if(sgp->op == RASQAL_GRAPH_PATTERN_OPERATOR_FILTER) {
+ /* One is enough to know we need to rewrite */
+ saw_filter_gp = 1;
+ break;
+ }
+ }
+
+ if(!saw_filter_gp) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Ending graph pattern #%d - saw no filter GPs\n",
+ gp->gp_index);
+#endif
+ return 0;
+ }
+
+
+ seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_graph_pattern, (raptor_sequence_print_handler*)rasqal_graph_pattern_print);
+ if(!seq) {
+ RASQAL_DEBUG1("Cannot create new gp sequence\n");
+ *modified_p = -1;
+ return 1;
+ }
+
+
+ while(raptor_sequence_size(gp->graph_patterns) > 0) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_unshift(gp->graph_patterns);
+ if(sgp->op == RASQAL_GRAPH_PATTERN_OPERATOR_FILTER) {
+ if(prev_gp)
+ rasqal_graph_pattern_move_constraints(prev_gp, sgp);
+ rasqal_free_graph_pattern(sgp);
+ continue;
+ }
+ if(raptor_sequence_push(seq, sgp)) {
+ RASQAL_DEBUG1("Cannot push to gp sequence\n");
+ raptor_free_sequence(seq);
+ *modified_p = -1;
+ return 1;
+ }
+ prev_gp = sgp;
+ }
+ raptor_free_sequence(gp->graph_patterns);
+ gp->graph_patterns = seq;
+
+ if(!*modified_p)
+ *modified_p = 1;
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Ending graph pattern #%d\n ", gp->gp_index);
+ rasqal_graph_pattern_print(gp, stdout);
+ fputs("\n\n", stdout);
+#endif
+
+ return 0;
+}
+
+
+static void
+rasqal_engine_move_to_graph_pattern(rasqal_engine_execution_data* execution_data,
+ rasqal_graph_pattern *gp,
+ int delta)
+{
+ rasqal_engine_gp_data* gp_data;
+ int graph_patterns_size = raptor_sequence_size(gp->graph_patterns);
+ int i;
+
+ gp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp->gp_index);
+
+ if(gp_data->optional_graph_pattern < 0 ) {
+ gp_data->current_graph_pattern += delta;
+ RASQAL_DEBUG3("Moved to graph pattern %d (delta %d)\n",
+ gp_data->current_graph_pattern, delta);
+ return;
+ }
+
+ /* Otherwise, there are optionals */
+
+ if(delta > 0) {
+ gp_data->current_graph_pattern++;
+ if(gp_data->current_graph_pattern == gp_data->optional_graph_pattern) {
+ RASQAL_DEBUG1("Moved to first optional graph pattern\n");
+ for(i = gp_data->current_graph_pattern; i < graph_patterns_size; i++) {
+ rasqal_graph_pattern *gp2;
+ gp2 = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ rasqal_engine_graph_pattern_init(execution_data, gp2);
+ }
+ gp_data->max_optional_graph_pattern = graph_patterns_size-1;
+ }
+ gp_data->optional_graph_pattern_matches_count = 0;
+ } else {
+ RASQAL_DEBUG1("Moving to previous graph pattern\n");
+
+ if(gp_data->current_graph_pattern > gp_data->optional_graph_pattern) {
+ rasqal_graph_pattern *gp2;
+ gp2 = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns,
+ gp_data->current_graph_pattern);
+ rasqal_engine_graph_pattern_init(execution_data, gp2);
+ }
+ gp_data->current_graph_pattern--;
+ }
+}
+
+
+static rasqal_engine_step
+rasqal_engine_check_constraint(rasqal_engine_execution_data* execution_data,
+ rasqal_graph_pattern *gp)
+{
+ rasqal_query* query;
+ rasqal_query_results* query_results;
+ rasqal_engine_step step = STEP_SEARCHING;
+ rasqal_literal* result;
+ int bresult = 1; /* constraint succeeds */
+ int error = 0;
+
+ query = execution_data->query;
+ query_results = execution_data->query_results;
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("filter expression:\n");
+ rasqal_expression_print(gp->filter_expression, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+
+ result = rasqal_expression_evaluate_v2(query->world, &query->locator,
+ gp->filter_expression,
+ query->compare_flags);
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("filter expression result:\n");
+ if(!result)
+ fputs("type error", DEBUG_FH);
+ else
+ rasqal_literal_print(result, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+ if(!result) {
+ bresult = 0;
+ step = STEP_ERROR;
+ } else {
+ bresult = rasqal_literal_as_boolean(result, &error);
+ if(error) {
+ RASQAL_DEBUG1("filter boolean expression returned error\n");
+ step = STEP_ERROR;
+ }
+#ifdef RASQAL_DEBUG
+ else
+ RASQAL_DEBUG2("filter boolean expression result: %d\n", bresult);
+#endif
+ rasqal_free_literal(result);
+ }
+
+ if(!bresult)
+ /* Constraint failed so move to try next match */
+ return STEP_SEARCHING;
+
+ return STEP_GOT_MATCH;
+}
+
+
+/**
+ * rasqal_engine_do_step:
+ * @execution_data: execution data
+ * @outergp: outer graph pattern
+ * @gp: inner graph pattern
+ *
+ * INTERNAL - Execute a graph pattern inside an outer graph pattern
+ *
+ * return: <0 failure, 0 end of results, >0 match
+ */
+static rasqal_engine_step
+rasqal_engine_do_step(rasqal_engine_execution_data* execution_data,
+ rasqal_graph_pattern* outergp, rasqal_graph_pattern* gp)
+{
+ int graph_patterns_size = raptor_sequence_size(outergp->graph_patterns);
+ rasqal_engine_step step = STEP_SEARCHING;
+ int rc;
+ rasqal_engine_gp_data* outergp_data;
+ rasqal_engine_gp_data* gp_data;
+
+ outergp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ outergp->gp_index);
+ gp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp->gp_index);
+
+ /* return: <0 failure, 0 end of results, >0 match */
+ rc = rasqal_engine_graph_pattern_get_next_match(execution_data, gp);
+
+ RASQAL_DEBUG3("Graph pattern %d returned %d\n",
+ outergp_data->current_graph_pattern, rc);
+
+ /* no matches is always a failure */
+ if(rc < 0)
+ return STEP_ERROR;
+
+ if(!rc) {
+ /* otherwise this is the end of the results */
+ RASQAL_DEBUG2("End of non-optional graph pattern %d\n",
+ outergp_data->current_graph_pattern);
+
+ return STEP_FINISHED;
+ }
+
+
+ if(gp->filter_expression) {
+ step = rasqal_engine_check_constraint(execution_data, gp);
+ if(step != STEP_GOT_MATCH)
+ return step;
+ }
+
+ if(outergp->filter_expression) {
+ step = rasqal_engine_check_constraint(execution_data, outergp);
+ if(step != STEP_GOT_MATCH)
+ return step;
+ }
+
+ /* got match */
+ RASQAL_DEBUG1("Got match\n");
+ gp_data->matched = 1;
+
+ /* if this is a match but not the last graph pattern in the
+ * sequence move to the next graph pattern
+ */
+ if(outergp_data->current_graph_pattern < graph_patterns_size-1) {
+ RASQAL_DEBUG1("Not last graph pattern\n");
+ rasqal_engine_move_to_graph_pattern(execution_data, outergp, +1);
+ return STEP_SEARCHING;
+ }
+
+ return STEP_GOT_MATCH;
+}
+
+
+/**
+ * rasqal_engine_do_optional_step:
+ * @execution_data: execution data
+ * @outergp: outer graph pattern
+ * @gp: inner graph pattern
+ *
+ * INTERNAL - Execute an OPTIONAL graph pattern inside an outer graph pattern
+ *
+ * return: <0 failure, 0 end of results, >0 match
+ */
+static rasqal_engine_step
+rasqal_engine_do_optional_step(rasqal_engine_execution_data* execution_data,
+ rasqal_graph_pattern *outergp,
+ rasqal_graph_pattern *gp)
+{
+ rasqal_query* query;
+ rasqal_query_results* query_results;
+ int graph_patterns_size = raptor_sequence_size(outergp->graph_patterns);
+ rasqal_engine_step step = STEP_SEARCHING;
+ int rc;
+ rasqal_engine_gp_data* gp_data;
+ rasqal_engine_gp_data* outergp_data;
+
+ query = execution_data->query;
+ query_results = execution_data->query_results;
+
+ gp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp->gp_index);
+ outergp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ outergp->gp_index);
+
+ if(gp_data->finished) {
+ if(!outergp_data->current_graph_pattern) {
+ step = STEP_FINISHED;
+ RASQAL_DEBUG1("Ended first graph pattern - finished\n");
+ return STEP_FINISHED;
+ }
+
+ RASQAL_DEBUG2("Ended graph pattern %d, backtracking\n",
+ outergp_data->current_graph_pattern);
+
+ /* backtrack optionals */
+ rasqal_engine_move_to_graph_pattern(execution_data, outergp, -1);
+ return STEP_SEARCHING;
+ }
+
+
+ /* return: <0 failure, 0 end of results, >0 match */
+ rc = rasqal_engine_graph_pattern_get_next_match(execution_data, gp);
+
+ RASQAL_DEBUG3("Graph pattern %d returned %d\n",
+ outergp_data->current_graph_pattern, rc);
+
+ /* count all optional matches */
+ if(rc > 0)
+ outergp_data->optional_graph_pattern_matches_count++;
+
+ if(rc < 0) {
+ /* optional always matches */
+ RASQAL_DEBUG2("Optional graph pattern %d failed to match, continuing\n",
+ outergp_data->current_graph_pattern);
+ step = STEP_SEARCHING;
+ }
+
+ if(!rc) {
+ int i;
+ int mandatory_matches = 0;
+ int optional_matches = 0;
+
+ /* end of graph_pattern results */
+ step = STEP_FINISHED;
+
+ /* if this is not the last (optional graph pattern) in the
+ * sequence, move on and continue
+ */
+ RASQAL_DEBUG2("End of optionals graph pattern %d\n",
+ outergp_data->current_graph_pattern);
+
+ gp_data->matched = 0;
+
+ /* Next time we get here, backtrack */
+ gp_data->finished = 1;
+
+ if(outergp_data->current_graph_pattern < outergp_data->max_optional_graph_pattern) {
+ RASQAL_DEBUG1("More optionals graph patterns to search\n");
+ rasqal_engine_move_to_graph_pattern(execution_data, outergp, +1);
+ return STEP_SEARCHING;
+ }
+
+ outergp_data->max_optional_graph_pattern--;
+ RASQAL_DEBUG2("Max optional graph patterns lowered to %d\n",
+ outergp_data->max_optional_graph_pattern);
+
+ /* Last optional match ended.
+ * If we got any non optional matches, then we have a result.
+ */
+ for(i = 0; i < graph_patterns_size; i++) {
+ rasqal_graph_pattern *gp2;
+ rasqal_engine_gp_data* gp2_data;
+
+ gp2 = (rasqal_graph_pattern*)raptor_sequence_get_at(outergp->graph_patterns, i);
+ gp2_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp2->gp_index);
+
+ if(outergp_data->optional_graph_pattern >= 0 &&
+ i >= outergp_data->optional_graph_pattern)
+ optional_matches += gp2_data->matched;
+ else
+ mandatory_matches += gp2_data->matched;
+ }
+
+
+ RASQAL_DEBUG2("Optional graph pattern has %d matches returned\n",
+ outergp_data->matches_returned);
+
+ RASQAL_DEBUG2("Found %d query optional graph pattern matches\n",
+ outergp_data->optional_graph_pattern_matches_count);
+
+ RASQAL_DEBUG3("Found %d mandatory matches, %d optional matches\n",
+ mandatory_matches, optional_matches);
+ RASQAL_DEBUG2("Found %d new binds\n", execution_data->new_bindings_count);
+
+ if(optional_matches) {
+ RASQAL_DEBUG1("Found some matches, returning a result\n");
+ return STEP_GOT_MATCH;
+ }
+
+ if(gp_data->matches_returned) {
+ if(!outergp_data->current_graph_pattern) {
+ RASQAL_DEBUG1("No matches this time and first graph pattern was optional, finished\n");
+ return STEP_FINISHED;
+ }
+
+ RASQAL_DEBUG1("No matches this time, some earlier, backtracking\n");
+ rasqal_engine_move_to_graph_pattern(execution_data, outergp, -1);
+ return STEP_SEARCHING;
+ }
+
+
+ if(execution_data->new_bindings_count > 0) {
+ RASQAL_DEBUG2("%d new bindings, returning a result\n",
+ execution_data->new_bindings_count);
+ return STEP_GOT_MATCH;
+ }
+ RASQAL_DEBUG1("no new bindings, continuing searching\n");
+ return STEP_SEARCHING;
+ }
+
+
+ if(gp->filter_expression) {
+ step = rasqal_engine_check_constraint(execution_data, gp);
+ if(step != STEP_GOT_MATCH) {
+ /* The constraint failed or we have an error - no bindings count */
+ execution_data->new_bindings_count = 0;
+ return step;
+ }
+ }
+
+
+ /* got match */
+
+ /* if this is a match but not the last graph pattern in the
+ * sequence move to the next graph pattern
+ */
+ if(outergp_data->current_graph_pattern < graph_patterns_size-1) {
+ RASQAL_DEBUG1("Not last graph pattern\n");
+ rasqal_engine_move_to_graph_pattern(execution_data, outergp, +1);
+ return STEP_SEARCHING;
+ }
+
+
+ if(outergp->filter_expression) {
+ step = rasqal_engine_check_constraint(execution_data, outergp);
+ if(step != STEP_GOT_MATCH) {
+ /* The constraint failed or we have an error - no bindings count */
+ execution_data->new_bindings_count = 0;
+ return STEP_SEARCHING;
+ }
+ }
+
+
+ /* is the last graph pattern so we have a solution */
+
+ RASQAL_DEBUG1("Got match\n");
+ gp_data->matched = 1;
+
+ return STEP_GOT_MATCH;
+}
+
+
+/**
+ * rasqal_engine_get_next_result:
+ * @query_results: query results object
+ *
+ * INTERNAL - Get the next result from a query execution
+ *
+ * return: <0 failure, 0 end of results, >0 match
+ */
+static int
+rasqal_engine_get_next_result(rasqal_engine_execution_data* execution_data)
+{
+ rasqal_query* query;
+ rasqal_query_results *query_results;
+ int graph_patterns_size;
+ rasqal_engine_step step;
+ int i;
+ rasqal_graph_pattern *outergp;
+ rasqal_engine_gp_data* outergp_data;
+
+ query = execution_data->query;
+ query_results = execution_data->query_results;
+
+ outergp = query->query_graph_pattern;
+ if(!outergp || !outergp->graph_patterns) {
+ /* FIXME - no graph patterns in query - end results */
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "No graph patterns in query. Ending query execution.");
+ return -1;
+ }
+
+ graph_patterns_size = raptor_sequence_size(outergp->graph_patterns);
+ if(!graph_patterns_size) {
+ /* FIXME - no graph patterns in query - end results */
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "No graph patterns in query. Ending query execution.");
+ return -1;
+ }
+
+ outergp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ outergp->gp_index);
+
+ execution_data->new_bindings_count = 0;
+
+ step = STEP_SEARCHING;
+ while(step == STEP_SEARCHING) {
+ rasqal_graph_pattern* gp;
+ rasqal_engine_gp_data* gp_data;
+ int values_returned = 0;
+ int optional_step;
+
+ gp = (rasqal_graph_pattern*)raptor_sequence_get_at(outergp->graph_patterns,
+ outergp_data->current_graph_pattern);
+ gp_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp->gp_index);
+ if(!gp_data)
+ return -1;
+
+ RASQAL_DEBUG3("Handling graph_pattern %d %s\n",
+ outergp_data->current_graph_pattern,
+ rasqal_graph_pattern_operator_as_string(gp->op));
+
+ if(gp->graph_patterns) {
+ /* FIXME - sequence of graph_patterns not implemented, finish */
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Graph pattern %s operation is not implemented yet. Ending query execution.",
+ rasqal_graph_pattern_operator_as_string(gp->op));
+
+ RASQAL_DEBUG1("Failing query with sequence of graph_patterns\n");
+ step = STEP_ERROR;
+ break;
+ }
+
+ gp_data->matched = 0;
+ optional_step = (gp->op == RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL);
+
+ if(optional_step)
+ step = rasqal_engine_do_optional_step(execution_data, outergp, gp);
+ else
+ step = rasqal_engine_do_step(execution_data, outergp, gp);
+
+ RASQAL_DEBUG2("Returned step is %s\n",
+ rasqal_engine_step_names[step]);
+
+ /* Count actual bound values */
+ for(i = 0; i < execution_data->size; i++) {
+ rasqal_variable* v = rasqal_variables_table_get(query->vars_table, i);
+ if(v->value)
+ values_returned++;
+ }
+ RASQAL_DEBUG2("Solution binds %d values\n", values_returned);
+ RASQAL_DEBUG2("New bindings %d\n", execution_data->new_bindings_count);
+
+ if(!values_returned && optional_step &&
+ step != STEP_FINISHED && step != STEP_SEARCHING) {
+ RASQAL_DEBUG1("An optional pass set no bindings, continuing searching\n");
+ step = STEP_SEARCHING;
+ }
+
+ }
+
+
+ RASQAL_DEBUG3("Ending with step %s and graph pattern %d\n",
+ rasqal_engine_step_names[step],
+ outergp_data->current_graph_pattern);
+
+ if(step == STEP_ERROR)
+ return -1;
+
+ if(step == STEP_GOT_MATCH) {
+ for(i = 0; i < graph_patterns_size; i++) {
+ rasqal_graph_pattern *gp2;
+ rasqal_engine_gp_data* gp2_data;
+
+ gp2 = (rasqal_graph_pattern*)raptor_sequence_get_at(outergp->graph_patterns, i);
+ gp2_data = (rasqal_engine_gp_data*)raptor_sequence_get_at(execution_data->seq,
+ gp2->gp_index);
+ if(gp2_data->matched)
+ gp2_data->matches_returned++;
+ }
+
+ /* Got a valid result */
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("Returning solution[");
+ for(i = 0; i< execution_data->size; i++) {
+ rasqal_variable* v = rasqal_variables_table_get(query->vars_table, i);
+ if(i>0)
+ fputs(", ", DEBUG_FH);
+ fprintf(DEBUG_FH, "%s=", v->name);
+ if(v->value)
+ rasqal_literal_print(v->value, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ }
+ fputs("]\n", DEBUG_FH);
+#endif
+ }
+
+ /* return 0 = finished, >0 got match */
+ return (step == STEP_GOT_MATCH);
+}
+
+
+/**
+ * rasqal_engine_row_update:
+ * @row: query result row
+ * @offset: integer offset into result values array
+ *
+ * INTERNAL - Update row values from query variables
+ *
+ * Return value: non-0 on failure
+ */
+static int
+rasqal_engine_row_update(rasqal_query* query, rasqal_row* row, int offset)
+{
+ rasqal_row_set_values_from_variables_table(row, query->vars_table);
+
+ if(row->order_size)
+ rasqal_engine_rowsort_calculate_order_values(query, row);
+
+ row->offset = offset;
+
+ return 0;
+}
+
+
+typedef struct
+{
+ rasqal_query* query;
+ rasqal_query_results* results;
+ rasqal_engine_execution_data* execution_data;
+ rasqal_map* map;
+ raptor_sequence* seq;
+ int need_store_results;
+ int finished;
+ int failed;
+ int offset;
+ int order_size;
+} rasqal_rowsource_engine_context;
+
+
+/* Local handlers for getting rows from a query execution */
+
+static int
+rasqal_rowsource_engine_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_rowsource_engine_context* con;
+
+ con = (rasqal_rowsource_engine_context*)user_data;
+ con->offset = 0;
+ con->finished = 0;
+ con->failed = 0;
+ return 0;
+}
+
+
+static int
+rasqal_rowsource_engine_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_rowsource_engine_context* con;
+
+ con = (rasqal_rowsource_engine_context*)user_data;
+ if(con->map)
+ rasqal_free_map(con->map);
+ if(con->seq)
+ raptor_free_sequence(con->seq);
+ RASQAL_FREE(rasqal_rowsource_engine_context, con);
+
+ return 0;
+}
+
+
+static void
+rasqal_rowsource_engine_process(rasqal_rowsource* rowsource,
+ rasqal_rowsource_engine_context* con,
+ int read_all)
+{
+ if(con->finished || con->failed)
+ return;
+
+ while(1) {
+ rasqal_row* row;
+ int rc;
+
+ /* query_results->results_sequence is NOT assigned before here
+ * so that this function does the regular query results next
+ * operation.
+ */
+ rc = rasqal_engine_get_next_result(con->execution_data);
+ if(rc == 0) {
+ /* =0 end of results */
+ con->finished = 1;
+ break;
+ }
+
+ if(rc < 0) {
+ /* <0 failure */
+ con->finished = 1;
+ con->failed = 1;
+
+ if(con->map) {
+ rasqal_free_map(con->map);
+ con->map = NULL;
+ }
+ raptor_free_sequence(con->seq);
+ con->seq = NULL;
+ break;
+ }
+
+ /* otherwise is >0 match */
+ row = rasqal_new_row(rowsource);
+ if(!row) {
+ raptor_free_sequence(con->seq); con->seq = NULL;
+ if(con->map) {
+ rasqal_free_map(con->map); con->map = NULL;
+ }
+ con->failed = 1;
+ return;
+ }
+
+ rc = rasqal_row_set_order_size(row, con->order_size);
+ if(rc) {
+ rasqal_free_row(row);
+ raptor_free_sequence(con->seq); con->seq = NULL;
+ if(con->map) {
+ rasqal_free_map(con->map); con->map = NULL;
+ }
+ con->failed = 1;
+ return;
+ }
+
+ rasqal_engine_row_update(con->query, row, con->offset);
+
+ if(!con->map) {
+ /* no map. after this, row is owned by sequence */
+ raptor_sequence_push(con->seq, row);
+ con->offset++;
+ } else {
+ /* map. after this, row is owned by map */
+ if(!rasqal_engine_rowsort_map_add_row(con->map, row))
+ con->offset++;
+ }
+
+ /* if a row was returned and not storing result, end loop */
+ if(!read_all && !con->need_store_results)
+ return;
+ }
+
+#ifdef RASQAL_DEBUG
+ if(con->map) {
+ fputs("resulting ", DEBUG_FH);
+ rasqal_map_print(con->map, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+ }
+#endif
+
+ if(con->map) {
+ /* do sort/distinct: walk map in order, adding rows to sequence */
+ rasqal_engine_rowsort_map_to_sequence(con->map, con->seq);
+ rasqal_free_map(con->map); con->map = NULL;
+ }
+}
+
+
+static int
+rasqal_rowsource_engine_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_rowsource_engine_context* con;
+ rasqal_query* query;
+
+ con = (rasqal_rowsource_engine_context*)user_data;
+ query = con->query;
+
+ rowsource->size = con->execution_data->size;
+
+ return 0;
+}
+
+
+static rasqal_row*
+rasqal_rowsource_engine_read_row(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_rowsource_engine_context* con;
+
+ con = (rasqal_rowsource_engine_context*)user_data;
+
+ if(con->finished || con->failed)
+ return NULL;
+
+ rasqal_rowsource_engine_process(rowsource, con, 0);
+ if(con->finished || con->failed)
+ return NULL;
+
+ return (rasqal_row*)raptor_sequence_unshift(con->seq);
+}
+
+
+static raptor_sequence*
+rasqal_rowsource_engine_read_all_rows(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_rowsource_engine_context* con;
+ raptor_sequence* seq;
+
+ con = (rasqal_rowsource_engine_context*)user_data;
+
+ if(con->finished || con->failed)
+ return NULL;
+
+ rasqal_rowsource_engine_process(rowsource, con, 1);
+ if(con->failed)
+ return NULL;
+
+ seq = con->seq;
+ con->seq = NULL;
+
+ return seq;
+}
+
+
+static const rasqal_rowsource_handler rasqal_rowsource_engine_handler = {
+ /* .version = */ 1,
+ "engine V1",
+ /* .init = */ rasqal_rowsource_engine_init,
+ /* .finish = */ rasqal_rowsource_engine_finish,
+ /* .ensure_variables = */ rasqal_rowsource_engine_ensure_variables,
+ /* .read_row = */ rasqal_rowsource_engine_read_row,
+ /* .read_all_rows = */ rasqal_rowsource_engine_read_all_rows
+};
+
+
+static rasqal_rowsource*
+rasqal_engine_make_rowsource(rasqal_query* query,
+ rasqal_query_results* results,
+ rasqal_engine_execution_data* execution_data,
+ int need_store_results)
+{
+ rasqal_rowsource_engine_context* con;
+
+ con = (rasqal_rowsource_engine_context*)RASQAL_CALLOC(rasqal_rowsource_engine_context, 1, sizeof(rasqal_rowsource_engine_context));
+ if(!con)
+ return NULL;
+
+ con->query = query;
+ con->results = results;
+ con->execution_data = execution_data;
+ con->need_store_results = need_store_results;
+
+ if(con->need_store_results) {
+ /* make a row:NULL map in order to sort or do distinct */
+ con->map = rasqal_engine_new_rowsort_map(query->distinct,
+ query->compare_flags,
+ query->order_conditions_sequence);
+ if(!con->map) {
+ rasqal_rowsource_engine_finish(NULL, con);
+ return NULL;
+ }
+
+ if(query->order_conditions_sequence)
+ con->order_size = raptor_sequence_size(query->order_conditions_sequence);
+ }
+
+ con->seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_row, (raptor_sequence_print_handler*)rasqal_row_print);
+ if(!con->seq) {
+ rasqal_rowsource_engine_finish(NULL, con);
+ return NULL;
+ }
+
+ return rasqal_new_rowsource_from_handler(query->world, query,
+ con,
+ &rasqal_rowsource_engine_handler,
+ query->vars_table,
+ 0);
+}
+
+
+/**
+ * rasqal_query_engine_1_get_row:
+ * @ex_data: execution data
+ * @error_p: execution error (OUT variable)
+ *
+ * INTERNAL - Execute a query to get one result, finished or failure.
+ *
+ * Return value: new row or NULL on finished or failure
+ */
+static rasqal_row*
+rasqal_query_engine_1_get_row(void* ex_data, rasqal_engine_error *error_p)
+{
+ rasqal_engine_execution_data* execution_data;
+ rasqal_query_results* query_results;
+ rasqal_row* row = NULL;
+
+ execution_data = (rasqal_engine_execution_data*)ex_data;
+
+ query_results = execution_data->query_results;
+
+ if(*error_p != RASQAL_ENGINE_OK)
+ return NULL;
+
+ while(1) {
+ int rc;
+
+ /* rc<0 error rc=0 end of results, rc>0 got a result */
+ rc = rasqal_engine_get_next_result(execution_data);
+
+ if(rc < 1) {
+ /* <0 failure OR =0 end of results */
+ *error_p = RASQAL_ENGINE_FINISHED;
+
+ /* <0 failure */
+ if(rc < 0)
+ *error_p = RASQAL_ENGINE_FAILED;
+ break;
+ }
+
+ /* otherwise is >0 match */
+ execution_data->result_count++;
+
+ /* finished if beyond result range */
+ if(rasqal_query_results_check_limit_offset(query_results) > 0) {
+ execution_data->result_count--;
+ break;
+ }
+
+ /* continue if before start of result range */
+ if(rasqal_query_results_check_limit_offset(query_results) < 0)
+ continue;
+
+ /* else got result or finished */
+ break;
+
+ } /* while */
+
+ if(*error_p == RASQAL_ENGINE_OK) {
+ row = rasqal_new_row(execution_data->rowsource);
+
+ if(row)
+ rasqal_engine_row_update(execution_data->query, row,
+ execution_data->result_count);
+ }
+
+ return row;
+}
+
+
+/**
+ * rasqal_query_engine_1_execute_transform_hack:
+ * @query: query object
+ *
+ * INTERNAL - Transform queries in the new query algebra into an executable form understood by the old query engine.
+ *
+ * That means in particular:
+ *
+ * 1) removing RASQAL_GRAPH_PATTERN_OPERATOR_FILTER graph patterns
+ * and moving the constraints to the previous GP in the sequence.
+ * Filter GPs always appear after another GP.
+ *
+ * 2) Ensuring that the root graph pattern is a GROUP even if
+ * there is only 1 GP inside it.
+ *
+ * Return value: non-0 on failure
+ */
+static int
+rasqal_query_engine_1_execute_transform_hack(rasqal_query* query)
+{
+ if(query->query_graph_pattern) {
+ int modified = 0;
+
+ /* modified is set to 1 if a change was made and -1 on failure */
+ rasqal_query_graph_pattern_visit(query,
+ rasqal_engine_remove_filter_graph_patterns,
+ &modified);
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "modified=%d after remove filter GPs, query graph pattern now:\n ", modified);
+ rasqal_graph_pattern_print(query->query_graph_pattern, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ if(modified < 0)
+ return 1;
+
+ if(query->query_graph_pattern->op != RASQAL_GRAPH_PATTERN_OPERATOR_GROUP) {
+ rasqal_graph_pattern* new_qgp;
+
+ new_qgp = rasqal_new_graph_pattern_from_sequence(query, NULL,
+ RASQAL_GRAPH_PATTERN_OPERATOR_GROUP);
+ if(!new_qgp)
+ return 1;
+
+ new_qgp->gp_index = (query->graph_pattern_count++);
+ if(rasqal_graph_pattern_add_sub_graph_pattern(new_qgp,
+ query->query_graph_pattern)) {
+ rasqal_free_graph_pattern(new_qgp);
+ query->query_graph_pattern = NULL;
+ return 1;
+ }
+
+ query->query_graph_pattern = new_qgp;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "after insert top level group GPs, query graph pattern now:\n");
+ rasqal_graph_pattern_print(query->query_graph_pattern, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+ }
+
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_engine_1_execute_init:
+ * @ex_data: execution data
+ * @query: query to execute
+ * @query_results: query results to put results in
+ * @error_p: execution error (OUT variable)
+ *
+ * INTERNAL - Prepare to execute a query.
+ *
+ * Initialises all state for a new query execution but do not
+ * start executing it.
+ *
+ * Return value: non-0 on failure
+ */
+static int
+rasqal_query_engine_1_execute_init(void* ex_data,
+ rasqal_query* query,
+ rasqal_query_results* query_results,
+ int flags,
+ rasqal_engine_error *error_p)
+{
+ rasqal_engine_execution_data* execution_data;
+ int rc = 0;
+ int need_store_results= (flags & 1);
+
+ execution_data = (rasqal_engine_execution_data*)ex_data;
+
+ if(!query->triples) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return 1;
+ }
+
+ /* FIXME - invoke a temporary transformation to turn queries in the
+ * new query algebra into an executable form understood by this
+ * query engine.
+ */
+ if(rasqal_query_engine_1_execute_transform_hack(query)) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return 1;
+ }
+
+
+ /* initialise the execution_data filelds */
+ execution_data->query = query;
+ execution_data->query_results = query_results;
+ execution_data->result_count = 0;
+
+ if(!execution_data->triples_source) {
+ execution_data->triples_source = rasqal_new_triples_source(execution_data->query);
+ if(!execution_data->triples_source) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return 1;
+ }
+ }
+
+ execution_data->seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_gp_data, NULL);
+ if(!execution_data->seq) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return 1;
+ }
+
+
+ /* calculate number of variables returned per row */
+ if(query->constructs)
+ execution_data->size = rasqal_variables_table_get_named_variables_count(query->vars_table);
+ else
+ execution_data->size = query->select_variables_count;
+
+
+ /* create all graph pattern-specific execution data */
+ if(query->graph_patterns_sequence) {
+ int i;
+
+ for(i = 0; i < query->graph_pattern_count; i++) {
+ rasqal_graph_pattern* gp;
+ rasqal_engine_gp_data* gp_data;
+
+ gp = (rasqal_graph_pattern*)raptor_sequence_get_at(query->graph_patterns_sequence, i);
+ gp_data = rasqal_new_engine_gp_data(gp);
+ if(!gp_data || raptor_sequence_set_at(execution_data->seq, i, gp_data)) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return 1;
+ }
+ }
+ }
+
+ /* initialise all the graph pattern-specific data */
+ if(query->query_graph_pattern) {
+ rc = rasqal_engine_graph_pattern_init(execution_data,
+ query->query_graph_pattern);
+ if(rc) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return 1;
+ }
+ }
+
+
+ /* Initialise the rowsource */
+ if(execution_data->rowsource)
+ rasqal_free_rowsource(execution_data->rowsource);
+ execution_data->rowsource = rasqal_engine_make_rowsource(query, query_results,
+ execution_data,
+ need_store_results);
+ if(!execution_data->rowsource) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return 1;
+ }
+
+ return rc;
+}
+
+
+/**
+ * rasqal_query_engine_1_get_all_rows:
+ * @ex_data: execution data
+ * @error_p: execution error (OUT variable)
+ *
+ * INTERNAL - Execute a query to get all results
+ *
+ * Return value: all rows or NULL on failure
+ */
+static raptor_sequence*
+rasqal_query_engine_1_get_all_rows(void* ex_data, rasqal_engine_error *error_p)
+{
+ rasqal_engine_execution_data* execution_data;
+ raptor_sequence* seq;
+
+ execution_data = (rasqal_engine_execution_data*)ex_data;
+
+ seq = rasqal_rowsource_read_all_rows(execution_data->rowsource);
+ rasqal_free_rowsource(execution_data->rowsource);
+ execution_data->rowsource = NULL;
+
+ if(!seq)
+ *error_p = RASQAL_ENGINE_FAILED;
+
+ return seq;
+}
+
+
+/**
+ * rasqal_query_engine_1_execute_finish:
+ * @ex_data: execution data
+ * @error_p: execution error (OUT variable)
+ *
+ * INTERNAL - Finish execution of a query
+ *
+ * Return value: non-0 on failure
+ */
+static int
+rasqal_query_engine_1_execute_finish(void* ex_data,
+ rasqal_engine_error *error_p)
+{
+ rasqal_engine_execution_data* execution_data;
+ execution_data = (rasqal_engine_execution_data*)ex_data;
+
+ if(!execution_data) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return -1;
+ }
+
+ if(execution_data->triples_source) {
+ rasqal_free_triples_source(execution_data->triples_source);
+ execution_data->triples_source = NULL;
+ }
+
+ if(execution_data->rowsource) {
+ rasqal_free_rowsource(execution_data->rowsource);
+ execution_data->rowsource = NULL;
+ }
+
+ if(execution_data->seq) {
+ raptor_free_sequence(execution_data->seq);
+ execution_data->seq = NULL;
+ }
+
+ return 0;
+}
+
+
+static void
+rasqal_query_engine_1_finish_factory(rasqal_query_execution_factory* factory)
+{
+ return;
+}
+
+
+const rasqal_query_execution_factory rasqal_query_engine_1 =
+{
+ /* .name= */ "rasqal 0.9.16 engine",
+ /* .execution_data_size= */ sizeof(rasqal_engine_execution_data),
+ /* .execute_init= */ rasqal_query_engine_1_execute_init,
+ /* .get_all_rows= */ rasqal_query_engine_1_get_all_rows,
+ /* .get_row= */ rasqal_query_engine_1_get_row,
+ /* .execute_finish= */ rasqal_query_engine_1_execute_finish,
+ /* .finish_factory= */ rasqal_query_engine_1_finish_factory
+};
diff --git a/src/rasqal/rasqal_engine_algebra.c b/src/rasqal/rasqal_engine_algebra.c
new file mode 100644
index 0000000..9415fe1
--- /dev/null
+++ b/src/rasqal/rasqal_engine_algebra.c
@@ -0,0 +1,398 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_engine_algebra.c - Rasqal query engine over query algebra
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#define DEBUG_FH stderr
+
+
+typedef struct {
+ rasqal_query* query;
+ rasqal_query_results* query_results;
+
+ /* query algebra representation of query */
+ rasqal_algebra_node* algebra_node;
+
+ /* number of nodes in #algebra_node tree */
+ int nodes_count;
+
+ /* rowsource that provides the result rows */
+ rasqal_rowsource* rowsource;
+
+ rasqal_triples_source* triples_source;
+} rasqal_engine_algebra_data;
+
+
+static rasqal_rowsource* rasqal_algebra_node_to_rowsource(rasqal_engine_algebra_data* execution_data, rasqal_algebra_node* node, rasqal_engine_error *error_p);
+
+
+static int
+rasqal_engine_algebra_count_nodes(rasqal_query* query,
+ rasqal_algebra_node* node,
+ void* data)
+{
+ int *count_p = (int*)data;
+ (*count_p)++;
+
+ return 0;
+}
+
+
+static rasqal_rowsource*
+rasqal_algebra_basic_algebra_node_to_rowsource(rasqal_engine_algebra_data* execution_data,
+ rasqal_algebra_node* node,
+ rasqal_engine_error *error_p)
+{
+ rasqal_query *query = execution_data->query;
+ int size;
+ int *declared_in;
+ int i;
+
+ size = rasqal_variables_table_get_named_variables_count(query->vars_table);
+ declared_in = (int*)RASQAL_CALLOC(intarray, size+1, sizeof(int));
+ if(!declared_in)
+ return NULL;
+
+ for(i = 0; i < size; i++)
+ declared_in[i] = query->variables_declared_in[i];
+
+ return rasqal_new_triples_rowsource(query->world, query,
+ execution_data->triples_source,
+ node->triples,
+ node->start_column, node->end_column,
+ declared_in);
+}
+
+
+static rasqal_rowsource*
+rasqal_algebra_filter_algebra_node_to_rowsource(rasqal_engine_algebra_data* execution_data,
+ rasqal_algebra_node* node,
+ rasqal_engine_error *error_p)
+{
+ rasqal_query *query = execution_data->query;
+ rasqal_rowsource *rs;
+
+ rs = rasqal_algebra_node_to_rowsource(execution_data, node->node1, error_p);
+ if(!rs || *error_p)
+ return NULL;
+
+ return rasqal_new_filter_rowsource(query->world, query, rs, node->expr);
+}
+
+
+static rasqal_rowsource*
+rasqal_algebra_orderby_algebra_node_to_rowsource(rasqal_engine_algebra_data* execution_data,
+ rasqal_algebra_node* node,
+ rasqal_engine_error *error_p)
+{
+ rasqal_query *query = execution_data->query;
+ rasqal_rowsource *rs;
+
+ rs = rasqal_algebra_node_to_rowsource(execution_data, node->node1, error_p);
+ if(!rs || *error_p)
+ return NULL;
+
+ return rasqal_new_sort_rowsource(query->world, query, rs, node->seq);
+}
+
+
+static rasqal_rowsource*
+rasqal_algebra_union_algebra_node_to_rowsource(rasqal_engine_algebra_data* execution_data,
+ rasqal_algebra_node* node,
+ rasqal_engine_error *error_p)
+{
+ rasqal_query *query = execution_data->query;
+ rasqal_rowsource *left_rs;
+ rasqal_rowsource *right_rs;
+
+ left_rs = rasqal_algebra_node_to_rowsource(execution_data, node->node1,
+ error_p);
+ if(!left_rs || *error_p)
+ return NULL;
+
+ right_rs = rasqal_algebra_node_to_rowsource(execution_data, node->node2,
+ error_p);
+ if(!right_rs || *error_p) {
+ rasqal_free_rowsource(left_rs);
+ return NULL;
+ }
+
+ return rasqal_new_union_rowsource(query->world, query, left_rs, right_rs);
+}
+
+
+static rasqal_rowsource*
+rasqal_algebra_project_algebra_node_to_rowsource(rasqal_engine_algebra_data* execution_data,
+ rasqal_algebra_node* node,
+ rasqal_engine_error *error_p)
+{
+ rasqal_query *query = execution_data->query;
+ rasqal_rowsource *rs;
+
+ rs = rasqal_algebra_node_to_rowsource(execution_data, node->node1,
+ error_p);
+ if(!rs || *error_p)
+ return NULL;
+
+ return rasqal_new_project_rowsource(query->world, query, rs, node->vars_seq);
+}
+
+
+static rasqal_rowsource*
+rasqal_algebra_leftjoin_algebra_node_to_rowsource(rasqal_engine_algebra_data* execution_data,
+ rasqal_algebra_node* node,
+ rasqal_engine_error *error_p)
+{
+ rasqal_query *query = execution_data->query;
+ rasqal_rowsource *left_rs;
+ rasqal_rowsource *right_rs;
+
+ left_rs = rasqal_algebra_node_to_rowsource(execution_data, node->node1,
+ error_p);
+ if(!left_rs || *error_p)
+ return NULL;
+
+ right_rs = rasqal_algebra_node_to_rowsource(execution_data, node->node2,
+ error_p);
+ if(!right_rs || *error_p) {
+ rasqal_free_rowsource(left_rs);
+ return NULL;
+ }
+
+ return rasqal_new_join_rowsource(query->world, query, left_rs, right_rs, 0, node->expr);
+}
+
+
+static rasqal_rowsource*
+rasqal_algebra_node_to_rowsource(rasqal_engine_algebra_data* execution_data,
+ rasqal_algebra_node* node,
+ rasqal_engine_error *error_p)
+{
+ rasqal_rowsource* rs = NULL;
+
+ switch(node->op) {
+ case RASQAL_ALGEBRA_OPERATOR_BGP:
+ rs = rasqal_algebra_basic_algebra_node_to_rowsource(execution_data,
+ node, error_p);
+ break;
+
+ case RASQAL_ALGEBRA_OPERATOR_FILTER:
+ rs = rasqal_algebra_filter_algebra_node_to_rowsource(execution_data,
+ node, error_p);
+ break;
+
+ case RASQAL_ALGEBRA_OPERATOR_ORDERBY:
+ rs = rasqal_algebra_orderby_algebra_node_to_rowsource(execution_data,
+ node, error_p);
+ break;
+
+ case RASQAL_ALGEBRA_OPERATOR_UNION:
+ rs = rasqal_algebra_union_algebra_node_to_rowsource(execution_data,
+ node, error_p);
+ break;
+
+ case RASQAL_ALGEBRA_OPERATOR_PROJECT:
+ rs = rasqal_algebra_project_algebra_node_to_rowsource(execution_data,
+ node, error_p);
+ break;
+
+ case RASQAL_ALGEBRA_OPERATOR_LEFTJOIN:
+ rs = rasqal_algebra_leftjoin_algebra_node_to_rowsource(execution_data,
+ node, error_p);
+ break;
+
+ case RASQAL_ALGEBRA_OPERATOR_UNKNOWN:
+ case RASQAL_ALGEBRA_OPERATOR_JOIN:
+ case RASQAL_ALGEBRA_OPERATOR_DIFF:
+ case RASQAL_ALGEBRA_OPERATOR_TOLIST:
+ case RASQAL_ALGEBRA_OPERATOR_DISTINCT:
+ case RASQAL_ALGEBRA_OPERATOR_REDUCED:
+ case RASQAL_ALGEBRA_OPERATOR_SLICE:
+ default:
+ RASQAL_DEBUG2("Unsupported algebra node operator %s\n",
+ rasqal_algebra_node_operator_as_string(node->op));
+ break;
+ }
+
+#if RASQAL_DEBUG
+ if(!rs)
+ abort();
+#endif
+
+ return rs;
+}
+
+
+
+static int
+rasqal_query_engine_algebra_execute_init(void* ex_data,
+ rasqal_query* query,
+ rasqal_query_results* query_results,
+ int flags,
+ rasqal_engine_error *error_p)
+{
+ rasqal_engine_algebra_data* execution_data;
+ rasqal_engine_error error;
+ int rc = 0;
+
+ execution_data = (rasqal_engine_algebra_data*)ex_data;
+
+ /* initialise the execution_data fields */
+ execution_data->query = query;
+ execution_data->query_results = query_results;
+
+ if(!execution_data->triples_source) {
+ execution_data->triples_source = rasqal_new_triples_source(execution_data->query);
+ if(!execution_data->triples_source) {
+ *error_p = RASQAL_ENGINE_FAILED;
+ return 1;
+ }
+ }
+
+ execution_data->algebra_node = rasqal_algebra_query_to_algebra(query);
+ if(!execution_data->algebra_node)
+ return 1;
+
+ execution_data->nodes_count = 0;
+ rasqal_algebra_node_visit(query, execution_data->algebra_node,
+ rasqal_engine_algebra_count_nodes,
+ &execution_data->nodes_count);
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("algebra result: \n");
+ rasqal_algebra_node_print(execution_data->algebra_node, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+ RASQAL_DEBUG2("algebra nodes: %d\n", execution_data->nodes_count);
+
+ error = RASQAL_ENGINE_OK;
+ execution_data->rowsource = rasqal_algebra_node_to_rowsource(execution_data,
+ execution_data->algebra_node,
+ &error);
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("rowsource (query plan) result: \n");
+ rasqal_rowsource_print(execution_data->rowsource, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+ if(error != RASQAL_ENGINE_OK)
+ rc = 1;
+
+ return rc;
+}
+
+
+static raptor_sequence*
+rasqal_query_engine_algebra_get_all_rows(void* ex_data,
+ rasqal_engine_error *error_p)
+{
+ rasqal_engine_algebra_data* execution_data;
+ raptor_sequence *seq = NULL;
+
+ execution_data = (rasqal_engine_algebra_data*)ex_data;
+
+ if(execution_data->rowsource) {
+ seq = rasqal_rowsource_read_all_rows(execution_data->rowsource);
+ if(!seq)
+ *error_p = RASQAL_ENGINE_FAILED;
+ } else
+ *error_p = RASQAL_ENGINE_FAILED;
+
+ return seq;
+}
+
+
+static rasqal_row*
+rasqal_query_engine_algebra_get_row(void* ex_data,
+ rasqal_engine_error *error_p)
+{
+ rasqal_engine_algebra_data* execution_data;
+ rasqal_row *row = NULL;
+
+ execution_data = (rasqal_engine_algebra_data*)ex_data;
+
+ if(execution_data->rowsource) {
+ row = rasqal_rowsource_read_row(execution_data->rowsource);
+ if(!row)
+ *error_p = RASQAL_ENGINE_FINISHED;
+ } else
+ *error_p = RASQAL_ENGINE_FAILED;
+
+ return row;
+}
+
+
+static int
+rasqal_query_engine_algebra_execute_finish(void* ex_data,
+ rasqal_engine_error *error_p)
+{
+ rasqal_engine_algebra_data* execution_data;
+
+ execution_data = (rasqal_engine_algebra_data*)ex_data;
+
+ if(execution_data->algebra_node)
+ rasqal_free_algebra_node(execution_data->algebra_node);
+
+ if(execution_data->triples_source)
+ rasqal_free_triples_source(execution_data->triples_source);
+
+ if(execution_data->rowsource)
+ rasqal_free_rowsource(execution_data->rowsource);
+
+ return 0;
+}
+
+
+static void
+rasqal_query_engine_algebra_finish_factory(rasqal_query_execution_factory* factory)
+{
+ return;
+}
+
+
+const rasqal_query_execution_factory rasqal_query_engine_algebra =
+{
+ /* .name= */ "rasqal query algebra query engine",
+ /* .execution_data_size= */ sizeof(rasqal_engine_algebra_data),
+ /* .execute_init= */ rasqal_query_engine_algebra_execute_init,
+ /* .get_all_rows= */ rasqal_query_engine_algebra_get_all_rows,
+ /* .get_row= */ rasqal_query_engine_algebra_get_row,
+ /* .execute_finish= */ rasqal_query_engine_algebra_execute_finish,
+ /* .finish_factory= */ rasqal_query_engine_algebra_finish_factory
+};
diff --git a/src/rasqal/rasqal_engine_sort.c b/src/rasqal/rasqal_engine_sort.c
new file mode 100644
index 0000000..f5f10eb
--- /dev/null
+++ b/src/rasqal/rasqal_engine_sort.c
@@ -0,0 +1,375 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_engine_sort.c - Rasqal query engine row sorting routines
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#define DEBUG_FH stderr
+
+
+/**
+ * rasqal_engine_rowsort_compare_literals_sequence:
+ * @compare_flags: comparison flags for rasqal_literal_compare()
+ * @values_a: first array of literals
+ * @values_b: second array of literals
+ * @expr_sequence: array of expressions
+ * @size: size of arrays
+ *
+ * INTERNAL - compare two arrays of literals evaluated in an array of expressions
+ *
+ * Return value: <0, 0 or >1 comparison
+ */
+static int
+rasqal_engine_rowsort_compare_literals_sequence(int compare_flags,
+ rasqal_literal** values_a,
+ rasqal_literal** values_b,
+ raptor_sequence* expr_sequence,
+ int size)
+{
+ int result = 0;
+ int i;
+
+ for(i = 0; i < size; i++) {
+ rasqal_expression* e = NULL;
+ int error = 0;
+ rasqal_literal* literal_a = values_a[i];
+ rasqal_literal* literal_b = values_b[i];
+
+ if(expr_sequence)
+ e = (rasqal_expression*)raptor_sequence_get_at(expr_sequence, i);
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("Comparing ");
+ rasqal_literal_print(literal_a, DEBUG_FH);
+ fputs(" to ", DEBUG_FH);
+ rasqal_literal_print(literal_b, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ if(!literal_a || !literal_b) {
+ if(!literal_a && !literal_b)
+ result = 0;
+ else {
+ result = literal_a ? 1 : -1;
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG2("Got one NULL literal comparison, returning %d\n", result);
+#endif
+ break;
+ }
+ }
+
+ result = rasqal_literal_compare(literal_a, literal_b,
+ compare_flags | RASQAL_COMPARE_URI,
+ &error);
+
+ if(error) {
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG2("Got literal comparison error at expression %d, returning 0\n", i);
+#endif
+ result = 0;
+ break;
+ }
+
+ if(!result)
+ continue;
+
+ if(e && e->op == RASQAL_EXPR_ORDER_COND_DESC)
+ result= -result;
+ /* else Order condition is RASQAL_EXPR_ORDER_COND_ASC so nothing to do */
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG3("Returning comparison result %d at expression %d\n", result, i);
+#endif
+ break;
+ }
+
+ return result;
+}
+
+
+/**
+ * rasqal_engine_rowsort_literal_sequence_equals:
+ * @values_a: first array of literals
+ * @values_b: second array of literals
+ * @size: size of arrays
+ *
+ * INTERNAL - compare two arrays of literals for equality
+ *
+ * Return value: non-0 if equal
+ */
+static int
+rasqal_engine_rowsort_literal_sequence_equals(rasqal_literal** values_a,
+ rasqal_literal** values_b,
+ int size)
+{
+ int result = 1; /* equal */
+ int i;
+ int error = 0;
+
+ for(i = 0; i < size; i++) {
+ rasqal_literal* literal_a = values_a[i];
+ rasqal_literal* literal_b = values_b[i];
+
+ result = rasqal_literal_equals_flags(literal_a, literal_b,
+ RASQAL_COMPARE_RDF, &error);
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("Comparing ");
+ rasqal_literal_print(literal_a, DEBUG_FH);
+ fputs(" to ", DEBUG_FH);
+ rasqal_literal_print(literal_b, DEBUG_FH);
+ fprintf(DEBUG_FH, " gave %s\n", (result ? "equality" : "not equal"));
+#endif
+
+ if(error)
+ result = 0;
+
+ /* if different, end */
+ if(!result)
+ break;
+ }
+
+ return result;
+}
+
+
+typedef struct
+{
+ int is_distinct;
+ int compare_flags;
+ raptor_sequence* order_conditions_sequence;
+} rowsort_compare_data;
+
+
+static void
+rasqal_engine_rowsort_free_compare_data(const void* user_data)
+{
+ rowsort_compare_data* rcd = (rowsort_compare_data*)user_data;
+
+ RASQAL_FREE(rowsort_compare_data, rcd);
+}
+
+
+/**
+ * rasqal_engine_rowsort_row_compare:
+ * @user_data: comparison user data pointer
+ * @a: pointer to address of first #row
+ * @b: pointer to address of second #row
+ *
+ * INTERNAL - compare two pointers to #row objects
+ *
+ * Suitable for use as a compare function in qsort_r() or similar.
+ *
+ * Return value: <0, 0 or >1 comparison
+ */
+static int
+rasqal_engine_rowsort_row_compare(void* user_data, const void *a, const void *b)
+{
+ rasqal_row* row_a;
+ rasqal_row* row_b;
+ rowsort_compare_data* rcd;
+ int result = 0;
+ rcd = (rowsort_compare_data*)user_data;
+ row_a = *(rasqal_row**)a;
+ row_b = *(rasqal_row**)b;
+
+ if(rcd->is_distinct) {
+ result = !rasqal_engine_rowsort_literal_sequence_equals(row_a->values,
+ row_b->values,
+ row_a->size);
+
+ if(!result)
+ /* duplicate, so return that */
+ return 0;
+ }
+
+ /* now order it */
+ result = rasqal_engine_rowsort_compare_literals_sequence(rcd->compare_flags,
+ row_a->order_values,
+ row_b->order_values,
+ rcd->order_conditions_sequence,
+ row_a->order_size);
+
+ /* still equal? make sort stable by using the original order */
+ if(!result) {
+ result = row_a->offset - row_b->offset;
+ RASQAL_DEBUG2("Got equality result so using offsets, returning %d\n",
+ result);
+ }
+
+ return result;
+}
+
+
+static void
+rasqal_engine_rowsort_map_free_row(const void *key, const void *value)
+{
+ if(key)
+ rasqal_free_row((rasqal_row*)key);
+ if(value)
+ rasqal_free_row((rasqal_row*)value);
+}
+
+
+static void
+rasqal_engine_rowsort_map_print_row(void *object, FILE *fh)
+{
+ if(object)
+ rasqal_row_print((rasqal_row*)object, fh);
+ else
+ fputs("NULL", fh);
+}
+
+
+/**
+ * rasqal_engine_new_rowsort_map:
+ * @flags: 1: do distinct
+ *
+ * INTERNAL - create a new map for sorting rows
+ *
+ */
+rasqal_map*
+rasqal_engine_new_rowsort_map(int is_distinct, int compare_flags,
+ raptor_sequence* order_conditions_sequence)
+{
+ rowsort_compare_data* rcd;
+
+ rcd = (rowsort_compare_data*)RASQAL_MALLOC(rowsort_compare_data,
+ sizeof(rowsort_compare_data));
+ if(!rcd)
+ return NULL;
+
+ rcd->is_distinct = is_distinct;
+ rcd->compare_flags = compare_flags;
+ rcd->order_conditions_sequence = order_conditions_sequence;
+
+ return rasqal_new_map(rasqal_engine_rowsort_row_compare, rcd,
+ rasqal_engine_rowsort_free_compare_data,
+ rasqal_engine_rowsort_map_free_row,
+ rasqal_engine_rowsort_map_print_row,
+ NULL,
+ 0);
+}
+
+
+/**
+ * rasqal_engine_rowsort_map_add_row:
+ * @map: row map
+ * @row: row to add
+ *
+ * INTERNAL - Add a row o a rowsort_map for sorting
+ *
+ * return value: non-0 if the row was a duplicate (and not added)
+ */
+int
+rasqal_engine_rowsort_map_add_row(rasqal_map* map, rasqal_row* row)
+{
+ /* map. after this, row is owned by map */
+ if(!rasqal_map_add_kv(map, row, NULL))
+ return 0;
+
+ /* duplicate, and not added so delete it */
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("Got duplicate row ");
+ rasqal_row_print(row, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+ rasqal_free_row(row);
+
+ return 1;
+}
+
+
+static void
+rasqal_engine_rowsort_map_add_to_sequence(void *key, void *value,
+ void *user_data)
+{
+ rasqal_row* row;
+ row = rasqal_new_row_from_row((rasqal_row*)key);
+ raptor_sequence_push((raptor_sequence*)user_data, row);
+}
+
+
+raptor_sequence*
+rasqal_engine_rowsort_map_to_sequence(rasqal_map* map, raptor_sequence* seq)
+{
+
+ /* do sort/distinct: walk map in order, adding rows to seq */
+ rasqal_map_visit(map, rasqal_engine_rowsort_map_add_to_sequence, (void*)seq);
+
+ return seq;
+}
+
+
+/**
+ * rasqal_engine_rowsort_calculate_order_values:
+ * @query: query object
+ * @row: row
+ *
+ * INTERNAL - Calculate the order condition values for a row
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_engine_rowsort_calculate_order_values(rasqal_query* query,
+ rasqal_row* row)
+{
+ int i;
+
+ if(!row->order_size)
+ return 1;
+
+ for(i = 0; i < row->order_size; i++) {
+ rasqal_expression* e;
+ rasqal_literal *l;
+
+ e = (rasqal_expression*)raptor_sequence_get_at(query->order_conditions_sequence, i);
+ l = rasqal_expression_evaluate_v2(query->world, &query->locator,
+ e, query->compare_flags);
+ if(row->order_values[i])
+ rasqal_free_literal(row->order_values[i]);
+ if(l) {
+ row->order_values[i] = rasqal_new_literal_from_literal(rasqal_literal_value(l));
+ rasqal_free_literal(l);
+ } else
+ row->order_values[i] = NULL;
+ }
+
+ return 0;
+}
diff --git a/src/rasqal/rasqal_expr.c b/src/rasqal/rasqal_expr.c
new file mode 100644
index 0000000..07d99fd
--- /dev/null
+++ b/src/rasqal/rasqal_expr.c
@@ -0,0 +1,2547 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_expr.c - Rasqal general expression support
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#ifdef RASQAL_REGEX_PCRE
+#include <pcre.h>
+#endif
+
+#ifdef RASQAL_REGEX_POSIX
+#include <sys/types.h>
+#include <regex.h>
+#endif
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#ifndef STANDALONE
+
+
+/**
+ * rasqal_new_data_graph:
+ * @world: rasqal_world object
+ * @uri: source URI
+ * @name_uri: name of graph (or NULL)
+ * @flags: %RASQAL_DATA_GRAPH_NAMED or %RASQAL_DATA_GRAPH_BACKGROUND
+ *
+ * Constructor - create a new #rasqal_data_graph.
+ *
+ * The name_uri is only used when the flags are %RASQAL_DATA_GRAPH_NAMED.
+ *
+ * Return value: a new #rasqal_data_graph or NULL on failure.
+ **/
+rasqal_data_graph*
+rasqal_new_data_graph(rasqal_world* world, raptor_uri* uri, raptor_uri* name_uri, int flags)
+{
+ rasqal_data_graph* dg = (rasqal_data_graph*)RASQAL_CALLOC(rasqal_data_graph, 1,
+ sizeof(rasqal_data_graph));
+ if(dg) {
+ dg->world = world;
+#ifdef RAPTOR_V2_AVAILABLE
+ dg->uri = raptor_uri_copy_v2(world->raptor_world_ptr, uri);
+ if(name_uri)
+ dg->name_uri = raptor_uri_copy_v2(world->raptor_world_ptr, name_uri);
+#else
+ dg->uri = raptor_uri_copy(uri);
+ if(name_uri)
+ dg->name_uri = raptor_uri_copy(name_uri);
+#endif
+ dg->flags = flags;
+ }
+
+ return dg;
+}
+
+
+/**
+ * rasqal_free_data_graph:
+ * @dg: #rasqal_data_graph object
+ *
+ * Destructor - destroy a #rasqal_data_graph object.
+ *
+ **/
+void
+rasqal_free_data_graph(rasqal_data_graph* dg)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(dg, rasqal_data_graph);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ if(dg->uri)
+ raptor_free_uri_v2(dg->world->raptor_world_ptr, dg->uri);
+ if(dg->name_uri)
+ raptor_free_uri_v2(dg->world->raptor_world_ptr, dg->name_uri);
+#else
+ if(dg->uri)
+ raptor_free_uri(dg->uri);
+ if(dg->name_uri)
+ raptor_free_uri(dg->name_uri);
+#endif
+ RASQAL_FREE(rasqal_data_graph, dg);
+}
+
+
+/**
+ * rasqal_data_graph_print:
+ * @dg: #rasqal_data_graph object
+ * @fh: the #FILE* handle to print to
+ *
+ * Print a Rasqal data graph in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_data_graph_print(rasqal_data_graph* dg, FILE* fh)
+{
+#ifdef RAPTOR_V2_AVAILABLE
+ if(dg->name_uri)
+ fprintf(fh, "data graph(%s named as %s flags %d)",
+ raptor_uri_as_string_v2(dg->world->raptor_world_ptr, dg->uri),
+ raptor_uri_as_string_v2(dg->world->raptor_world_ptr, dg->name_uri),
+ dg->flags);
+ else
+ fprintf(fh, "data graph(%s, flags %d)",
+ raptor_uri_as_string_v2(dg->world->raptor_world_ptr, dg->uri), dg->flags);
+#else
+ if(dg->name_uri)
+ fprintf(fh, "data graph(%s named as %s flags %d)",
+ raptor_uri_as_string(dg->uri),
+ raptor_uri_as_string(dg->name_uri),
+ dg->flags);
+ else
+ fprintf(fh, "data graph(%s, flags %d)",
+ raptor_uri_as_string(dg->uri), dg->flags);
+#endif
+}
+
+
+/**
+ * rasqal_new_prefix:
+ * @world: rasqal_world object
+ * @prefix: Short prefix string to stand for URI or NULL.
+ * @uri: Name #raptor_uri.
+ *
+ * Constructor - create a new #rasqal_prefix.
+ * Takes ownership of prefix and uri.
+ *
+ * Return value: a new #rasqal_prefix or NULL on failure.
+ **/
+rasqal_prefix*
+rasqal_new_prefix(rasqal_world* world, const unsigned char *prefix, raptor_uri* uri)
+{
+ rasqal_prefix* p = (rasqal_prefix*)RASQAL_CALLOC(rasqal_prefix, 1,
+ sizeof(rasqal_prefix));
+
+ if(p) {
+ p->world = world;
+ p->prefix = prefix;
+ p->uri = uri;
+ } else {
+ RASQAL_FREE(cstring, prefix);
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, uri);
+#else
+ raptor_free_uri(uri);
+#endif
+ }
+
+ return p;
+}
+
+
+/**
+ * rasqal_free_prefix:
+ * @p: #rasqal_prefix object.
+ *
+ * Destructor - destroy a #rasqal_prefix object.
+ **/
+void
+rasqal_free_prefix(rasqal_prefix* p)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(p, rasqal_prefix);
+
+ if(p->prefix)
+ RASQAL_FREE(cstring, (void*)p->prefix);
+ if(p->uri)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(p->world->raptor_world_ptr, p->uri);
+#else
+ raptor_free_uri(p->uri);
+#endif
+ RASQAL_FREE(rasqal_prefix, p);
+}
+
+
+/**
+ * rasqal_prefix_print:
+ * @p: #rasqal_prefix object.
+ * @fh: The #FILE* handle to print to.
+ *
+ * Print a Rasqal prefix in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_prefix_print(rasqal_prefix* p, FILE* fh)
+{
+ fprintf(fh, "prefix(%s as %s)", (p->prefix ? (const char*)p->prefix : "(default)"),
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(p->world->raptor_world_ptr, p->uri)
+#else
+ raptor_uri_as_string(p->uri)
+#endif
+ );
+}
+
+
+
+/**
+ * rasqal_new_triple:
+ * @subject: Triple subject.
+ * @predicate: Triple predicate.
+ * @object: Triple object.
+ *
+ * Constructor - create a new #rasqal_triple triple or triple pattern.
+ * Takes ownership of the literals passed in.
+ *
+ * The triple origin can be set with rasqal_triple_set_origin().
+ *
+ * Return value: a new #rasqal_triple or NULL on failure.
+ **/
+rasqal_triple*
+rasqal_new_triple(rasqal_literal* subject, rasqal_literal* predicate, rasqal_literal* object)
+{
+ rasqal_triple* t=(rasqal_triple*)RASQAL_CALLOC(rasqal_triple, 1, sizeof(rasqal_triple));
+
+ if(t) {
+ t->subject=subject;
+ t->predicate=predicate;
+ t->object=object;
+ } else {
+ if(subject)
+ rasqal_free_literal(subject);
+ if(predicate)
+ rasqal_free_literal(predicate);
+ if(object)
+ rasqal_free_literal(object);
+ }
+
+ return t;
+}
+
+
+/**
+ * rasqal_new_triple_from_triple:
+ * @t: Triple to copy.
+ *
+ * Copy constructor - create a new #rasqal_triple from an existing one.
+ *
+ * Return value: a new #rasqal_triple or NULL on failure.
+ **/
+rasqal_triple*
+rasqal_new_triple_from_triple(rasqal_triple* t)
+{
+ rasqal_triple* newt=(rasqal_triple*)RASQAL_CALLOC(rasqal_triple, 1, sizeof(rasqal_triple));
+
+ if(newt) {
+ newt->subject=rasqal_new_literal_from_literal(t->subject);
+ newt->predicate=rasqal_new_literal_from_literal(t->predicate);
+ newt->object=rasqal_new_literal_from_literal(t->object);
+ }
+
+ return newt;
+}
+
+
+/**
+ * rasqal_free_triple:
+ * @t: #rasqal_triple object.
+ *
+ * Destructor - destroy a #rasqal_triple object.
+ **/
+void
+rasqal_free_triple(rasqal_triple* t)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(t, rasqal_triple);
+
+ if(t->subject)
+ rasqal_free_literal(t->subject);
+ if(t->predicate)
+ rasqal_free_literal(t->predicate);
+ if(t->object)
+ rasqal_free_literal(t->object);
+ if(t->origin)
+ rasqal_free_literal(t->origin);
+ RASQAL_FREE(rasqal_triple, t);
+}
+
+
+/**
+ * rasqal_triple_write:
+ * @t: #rasqal_triple object.
+ * @iostr: The #raptor_iostream handle to write to.
+ *
+ * Write a Rasqal triple to an iostream in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_triple_write(rasqal_triple* t, raptor_iostream* iostr)
+{
+ raptor_iostream_write_counted_string(iostr, "triple(", 7);
+ rasqal_literal_write(t->subject, iostr);
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_literal_write(t->predicate, iostr);
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_literal_write(t->object, iostr);
+ raptor_iostream_write_byte(iostr, ')');
+ if(t->origin) {
+ raptor_iostream_write_counted_string(iostr, " with origin(", 13);
+ rasqal_literal_write(t->origin, iostr);
+ raptor_iostream_write_byte(iostr, ')');
+ }
+}
+
+
+/**
+ * rasqal_triple_print:
+ * @t: #rasqal_triple object.
+ * @fh: The #FILE* handle to print to.
+ *
+ * Print a Rasqal triple in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_triple_print(rasqal_triple* t, FILE* fh)
+{
+ fputs("triple(", fh);
+ rasqal_literal_print(t->subject, fh);
+ fputs(", ", fh);
+ rasqal_literal_print(t->predicate, fh);
+ fputs(", ", fh);
+ rasqal_literal_print(t->object, fh);
+ fputc(')', fh);
+ if(t->origin) {
+ fputs(" with origin(", fh);
+ rasqal_literal_print(t->origin, fh);
+ fputc(')', fh);
+ }
+}
+
+
+/**
+ * rasqal_triple_set_origin:
+ * @t: The triple object.
+ * @l: The #rasqal_literal object to set as origin.
+ *
+ * Set the origin field of a #rasqal_triple.
+ **/
+void
+rasqal_triple_set_origin(rasqal_triple* t, rasqal_literal* l)
+{
+ t->origin=l;
+}
+
+
+/**
+ * rasqal_triple_get_origin:
+ * @t: The triple object.
+ *
+ * Get the origin field of a #rasqal_triple.
+ *
+ * Return value: The triple origin or NULL.
+ **/
+rasqal_literal*
+rasqal_triple_get_origin(rasqal_triple* t)
+{
+ return t->origin;
+}
+
+
+/**
+ * rasqal_new_0op_expression:
+ * @world: rasqal_world object
+ * @op: Expression operator
+ *
+ * Constructor - create a new 0-operand (constant) expression.
+ *
+ * The operators are:
+ * @RASQAL_EXPR_VARSTAR
+ *
+ * The only operator here is the '*' in COUNT(*) as used by LAQRS.
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_0op_expression(rasqal_world* world, rasqal_op op)
+{
+ rasqal_expression* e = (rasqal_expression*)RASQAL_CALLOC(rasqal_expression, 1, sizeof(rasqal_expression));
+ if(e) {
+ e->usage = 1;
+ e->world = world;
+ e->op = op;
+ }
+ return e;
+}
+
+
+/**
+ * rasqal_new_1op_expression:
+ * @world: rasqal_world object
+ * @op: Expression operator
+ * @arg: Operand 1
+ *
+ * Constructor - create a new 1-operand expression.
+ * Takes ownership of the operand expression.
+ *
+ * The operators are:
+ * @RASQAL_EXPR_TILDE @RASQAL_EXPR_BANG @RASQAL_EXPR_UMINUS
+ * @RASQAL_EXPR_BOUND @RASQAL_EXPR_STR @RASQAL_EXPR_LANG
+ * @RASQAL_EXPR_LANGMATCHES
+ * @RASQAL_EXPR_DATATYPE @RASQAL_EXPR_ISURI @RASQAL_EXPR_ISBLANK
+ * @RASQAL_EXPR_ISLITERAL @RASQAL_EXPR_ORDER_COND_ASC
+ * @RASQAL_EXPR_ORDER_COND_DESC @RASQAL_EXPR_GROUP_COND_ASC
+ * @RASQAL_EXPR_GROUP_COND_DESC @RASQAL_EXPR_COUNT
+ *
+ * @RASQAL_EXPR_BANG and @RASQAL_EXPR_UMINUS are used by RDQL and
+ * SPARQL. @RASQAL_EXPR_TILDE by RDQL only. The rest by SPARQL
+ * only.
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_1op_expression(rasqal_world* world, rasqal_op op, rasqal_expression* arg)
+{
+ rasqal_expression* e = NULL;
+
+ if(!arg)
+ goto tidy;
+
+ e = (rasqal_expression*)RASQAL_CALLOC(rasqal_expression, 1,
+ sizeof(rasqal_expression));
+ if(e) {
+ e->usage = 1;
+ e->world = world;
+ e->op = op;
+ e->arg1 = arg; arg = NULL;
+ }
+
+ tidy:
+ if(arg)
+ rasqal_free_expression(arg);
+
+ return e;
+}
+
+
+/**
+ * rasqal_new_2op_expression:
+ * @world: rasqal_world object
+ * @op: Expression operator
+ * @arg1: Operand 1
+ * @arg2: Operand 2
+ *
+ * Constructor - create a new 2-operand expression.
+ * Takes ownership of the operand expressions.
+ *
+ * The operators are:
+ * @RASQAL_EXPR_AND @RASQAL_EXPR_OR @RASQAL_EXPR_EQ
+ * @RASQAL_EXPR_NEQ @RASQAL_EXPR_LT @RASQAL_EXPR_GT @RASQAL_EXPR_LE
+ * @RASQAL_EXPR_GE @RASQAL_EXPR_PLUS @RASQAL_EXPR_MINUS
+ * @RASQAL_EXPR_STAR @RASQAL_EXPR_SLASH @RASQAL_EXPR_REM
+ * @RASQAL_EXPR_STR_EQ @RASQAL_EXPR_STR_NEQ
+ *
+ * @RASQAL_EXPR_REM @RASQAL_EXPR_STR_EQ and @RASQAL_EXPR_STR_NEQ are
+ * not used by SPARQL. @RASQAL_EXPR_REM is used by RDQL.
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_2op_expression(rasqal_world* world,
+ rasqal_op op,
+ rasqal_expression* arg1,
+ rasqal_expression* arg2)
+{
+ rasqal_expression* e = NULL;
+
+ if(!arg1 || !arg2)
+ goto tidy;
+
+ e = (rasqal_expression*)RASQAL_CALLOC(rasqal_expression, 1,
+ sizeof(rasqal_expression));
+ if(e) {
+ e->usage = 1;
+ e->world = world;
+ e->op = op;
+ e->arg1 = arg1; arg1 = NULL;
+ e->arg2 = arg2; arg2 = NULL;
+ }
+
+tidy:
+ if(arg1)
+ rasqal_free_expression(arg1);
+ if(arg2)
+ rasqal_free_expression(arg2);
+
+ return e;
+}
+
+
+/**
+ * rasqal_new_3op_expression:
+ * @world: rasqal_world object
+ * @op: Expression operator
+ * @arg1: Operand 1
+ * @arg2: Operand 2
+ * @arg3: Operand 3 (may be NULL)
+ *
+ * Constructor - create a new 3-operand expression.
+ * Takes ownership of the operands.
+ *
+ * The only operator is:
+ * @RASQAL_EXPR_REGEX
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_3op_expression(rasqal_world* world,
+ rasqal_op op,
+ rasqal_expression* arg1,
+ rasqal_expression* arg2,
+ rasqal_expression* arg3)
+{
+ rasqal_expression* e = NULL;
+
+ if(!arg1 || !arg2) /* arg3 may be NULL */
+ goto tidy;
+
+ e = (rasqal_expression*)RASQAL_CALLOC(rasqal_expression, 1,
+ sizeof(rasqal_expression));
+ if(e) {
+ e->usage = 1;
+ e->world = world;
+ e->op = op;
+ e->arg1 = arg1; arg1 = NULL;
+ e->arg2 = arg2; arg2 = NULL;
+ e->arg3 = arg3; arg3 = NULL;
+ }
+
+ tidy:
+ if(arg1)
+ rasqal_free_expression(arg1);
+ if(arg2)
+ rasqal_free_expression(arg2);
+ if(arg3)
+ rasqal_free_expression(arg3);
+
+ return e;
+}
+
+
+/**
+ * rasqal_new_string_op_expression:
+ * @world: rasqal_world object
+ * @op: Expression operator
+ * @arg1: Operand 1
+ * @literal: Literal operand 2
+ *
+ * Constructor - create a new expression with one expression and one string operand.
+ * Takes ownership of the operands.
+ *
+ * The operators are:
+ * @RASQAL_EXPR_STR_MATCH (RDQL, SPARQL) and
+ * @RASQAL_EXPR_STR_NMATCH (RDQL)
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_string_op_expression(rasqal_world* world,
+ rasqal_op op,
+ rasqal_expression* arg1,
+ rasqal_literal* literal)
+{
+ rasqal_expression* e = NULL;
+
+ if(!arg1 || !literal)
+ goto tidy;
+
+ e = (rasqal_expression*)RASQAL_CALLOC(rasqal_expression, 1,
+ sizeof(rasqal_expression));
+ if(e) {
+ e->usage = 1;
+ e->world = world;
+ e->op = op;
+ e->arg1 = arg1; arg1 = NULL;
+ e->literal = literal; literal = NULL;
+ }
+
+ tidy:
+ if(arg1)
+ rasqal_free_expression(arg1);
+ if(literal)
+ rasqal_free_literal(literal);
+
+ return e;
+}
+
+
+/**
+ * rasqal_new_literal_expression:
+ * @world: rasqal_world object
+ * @literal: Literal operand 1
+ *
+ * Constructor - create a new expression for a #rasqal_literal
+ * Takes ownership of the operand literal.
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_literal_expression(rasqal_world* world, rasqal_literal *literal)
+{
+ rasqal_expression* e;
+
+ if(!literal)
+ return NULL;
+
+ e = (rasqal_expression*)RASQAL_CALLOC(rasqal_expression, 1,
+ sizeof(rasqal_expression));
+ if(e) {
+ e->usage = 1;
+ e->world = world;
+ e->op = RASQAL_EXPR_LITERAL;
+ e->literal = literal;
+ } else {
+ rasqal_free_literal(literal);
+ }
+ return e;
+}
+
+
+/**
+ * rasqal_new_function_expression:
+ * @world: rasqal_world object
+ * @name: function name
+ * @args: sequence of #rasqal_expression function arguments
+ *
+ * Constructor - create a new expression for a function with expression arguments.
+ * Takes ownership of the function uri and arguments.
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_function_expression(rasqal_world* world,
+ raptor_uri* name,
+ raptor_sequence* args)
+{
+ rasqal_expression* e = NULL;
+
+ if(!name || !args)
+ goto tidy;
+
+ e = (rasqal_expression*)RASQAL_CALLOC(rasqal_expression, 1,
+ sizeof(rasqal_expression));
+ if(e) {
+ e->usage = 1;
+ e->world = world;
+ e->op = RASQAL_EXPR_FUNCTION;
+ e->name = name; name = NULL;
+ e->args = args; args = NULL;
+ }
+
+ tidy:
+ if(name)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, name);
+#else
+ raptor_free_uri(name);
+#endif
+ if(args)
+ raptor_free_sequence(args);
+
+ return e;
+}
+
+
+/**
+ * rasqal_new_cast_expression:
+ * @world: rasqal_world object
+ * @name: cast datatype URI
+ * @value: expression value to cast to @datatype type
+ *
+ * Constructor - create a new expression for casting and expression to a datatype.
+ * Takes ownership of the datatype uri and expression value.
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_cast_expression(rasqal_world* world, raptor_uri* name, rasqal_expression *value)
+{
+ rasqal_expression* e = NULL;
+
+ if(!name || !value)
+ goto tidy;
+
+ e = (rasqal_expression*)RASQAL_CALLOC(rasqal_expression, 1,
+ sizeof(rasqal_expression));
+ if(e) {
+ e->usage = 1;
+ e->world = world;
+ e->op = RASQAL_EXPR_CAST;
+ e->name = name; name = NULL;
+ e->arg1 = value; value = NULL;
+ }
+
+ tidy:
+ if(name)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, name);
+#else
+ raptor_free_uri(name);
+#endif
+ if(value)
+ rasqal_free_expression(value);
+
+ return e;
+}
+
+
+/**
+ * rasqal_expression_clear:
+ * @e: expression
+ *
+ * Empty an expression of contained content.
+ *
+ * Intended to be used to deallocate resources from a statically
+ * declared #rasqal_expression such as on a stack.
+ **/
+void
+rasqal_expression_clear(rasqal_expression* e)
+{
+ switch(e->op) {
+ case RASQAL_EXPR_AND:
+ case RASQAL_EXPR_OR:
+ case RASQAL_EXPR_EQ:
+ case RASQAL_EXPR_NEQ:
+ case RASQAL_EXPR_LT:
+ case RASQAL_EXPR_GT:
+ case RASQAL_EXPR_LE:
+ case RASQAL_EXPR_GE:
+ case RASQAL_EXPR_PLUS:
+ case RASQAL_EXPR_MINUS:
+ case RASQAL_EXPR_STAR:
+ case RASQAL_EXPR_SLASH:
+ case RASQAL_EXPR_REM:
+ case RASQAL_EXPR_STR_EQ:
+ case RASQAL_EXPR_STR_NEQ:
+ case RASQAL_EXPR_LANGMATCHES:
+ case RASQAL_EXPR_SAMETERM:
+ rasqal_free_expression(e->arg1);
+ rasqal_free_expression(e->arg2);
+ break;
+ case RASQAL_EXPR_REGEX:
+ rasqal_free_expression(e->arg1);
+ rasqal_free_expression(e->arg2);
+ if(e->arg3)
+ rasqal_free_expression(e->arg3);
+ break;
+ case RASQAL_EXPR_TILDE:
+ case RASQAL_EXPR_BANG:
+ case RASQAL_EXPR_UMINUS:
+ case RASQAL_EXPR_BOUND:
+ case RASQAL_EXPR_STR:
+ case RASQAL_EXPR_LANG:
+ case RASQAL_EXPR_DATATYPE:
+ case RASQAL_EXPR_ISURI:
+ case RASQAL_EXPR_ISBLANK:
+ case RASQAL_EXPR_ISLITERAL:
+ case RASQAL_EXPR_ORDER_COND_ASC:
+ case RASQAL_EXPR_ORDER_COND_DESC:
+ case RASQAL_EXPR_GROUP_COND_ASC:
+ case RASQAL_EXPR_GROUP_COND_DESC:
+ case RASQAL_EXPR_COUNT:
+ rasqal_free_expression(e->arg1);
+ break;
+ case RASQAL_EXPR_STR_MATCH:
+ case RASQAL_EXPR_STR_NMATCH:
+ rasqal_free_expression(e->arg1);
+ /* FALLTHROUGH */
+ case RASQAL_EXPR_LITERAL:
+ rasqal_free_literal(e->literal);
+ break;
+ case RASQAL_EXPR_FUNCTION:
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(e->world->raptor_world_ptr, e->name);
+#else
+ raptor_free_uri(e->name);
+#endif
+ raptor_free_sequence(e->args);
+ break;
+ case RASQAL_EXPR_CAST:
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(e->world->raptor_world_ptr, e->name);
+#else
+ raptor_free_uri(e->name);
+#endif
+ rasqal_free_expression(e->arg1);
+ break;
+
+ case RASQAL_EXPR_VARSTAR:
+ /* constants */
+ break;
+
+ case RASQAL_EXPR_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown operation %d", e->op);
+ }
+}
+
+
+/**
+ * rasqal_new_expression_from_expression:
+ * @e: #rasqal_expression object to copy
+ *
+ * Copy Constructor - create a new #rasqal_expression object from an existing rasqal_expression object.
+ *
+ * Return value: a new #rasqal_expression object or NULL on failure
+ **/
+rasqal_expression*
+rasqal_new_expression_from_expression(rasqal_expression* e)
+{
+ if(!e)
+ return NULL;
+
+ e->usage++;
+ return e;
+}
+
+
+/**
+ * rasqal_free_expression:
+ * @e: #rasqal_expression object
+ *
+ * Destructor - destroy a #rasqal_expression object.
+ *
+ **/
+void
+rasqal_free_expression(rasqal_expression* e)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(e, rasqal_expression);
+
+ if(--e->usage)
+ return;
+
+ rasqal_expression_clear(e);
+ RASQAL_FREE(rasqal_expression, e);
+}
+
+
+/**
+ * rasqal_expression_visit:
+ * @e: #rasqal_expression to visit
+ * @fn: visit function
+ * @user_data: user data to pass to visit function
+ *
+ * Visit a user function over a #rasqal_expression
+ *
+ * If the user function @fn returns 0, the visit is truncated.
+ *
+ * Return value: 0 if the visit was truncated.
+ **/
+int
+rasqal_expression_visit(rasqal_expression* e,
+ rasqal_expression_visit_fn fn,
+ void *user_data)
+{
+ int i;
+ int result=0;
+
+ /* This ordering allows fn to potentially edit 'e' in-place */
+ result=fn(user_data, e);
+ if(result)
+ return result;
+
+ switch(e->op) {
+ case RASQAL_EXPR_AND:
+ case RASQAL_EXPR_OR:
+ case RASQAL_EXPR_EQ:
+ case RASQAL_EXPR_NEQ:
+ case RASQAL_EXPR_LT:
+ case RASQAL_EXPR_GT:
+ case RASQAL_EXPR_LE:
+ case RASQAL_EXPR_GE:
+ case RASQAL_EXPR_PLUS:
+ case RASQAL_EXPR_MINUS:
+ case RASQAL_EXPR_STAR:
+ case RASQAL_EXPR_SLASH:
+ case RASQAL_EXPR_REM:
+ case RASQAL_EXPR_STR_EQ:
+ case RASQAL_EXPR_STR_NEQ:
+ case RASQAL_EXPR_LANGMATCHES:
+ case RASQAL_EXPR_SAMETERM:
+ return rasqal_expression_visit(e->arg1, fn, user_data) ||
+ rasqal_expression_visit(e->arg2, fn, user_data);
+ break;
+ case RASQAL_EXPR_REGEX:
+ return rasqal_expression_visit(e->arg1, fn, user_data) ||
+ rasqal_expression_visit(e->arg2, fn, user_data) ||
+ (e->arg3 && rasqal_expression_visit(e->arg3, fn, user_data));
+ break;
+ case RASQAL_EXPR_TILDE:
+ case RASQAL_EXPR_BANG:
+ case RASQAL_EXPR_UMINUS:
+ case RASQAL_EXPR_BOUND:
+ case RASQAL_EXPR_STR:
+ case RASQAL_EXPR_LANG:
+ case RASQAL_EXPR_DATATYPE:
+ case RASQAL_EXPR_ISURI:
+ case RASQAL_EXPR_ISBLANK:
+ case RASQAL_EXPR_ISLITERAL:
+ case RASQAL_EXPR_CAST:
+ case RASQAL_EXPR_ORDER_COND_ASC:
+ case RASQAL_EXPR_ORDER_COND_DESC:
+ case RASQAL_EXPR_GROUP_COND_ASC:
+ case RASQAL_EXPR_GROUP_COND_DESC:
+ case RASQAL_EXPR_COUNT:
+ return rasqal_expression_visit(e->arg1, fn, user_data);
+ break;
+ case RASQAL_EXPR_STR_MATCH:
+ case RASQAL_EXPR_STR_NMATCH:
+ return fn(user_data, e->arg1);
+ break;
+ case RASQAL_EXPR_LITERAL:
+ return 0;
+ case RASQAL_EXPR_FUNCTION:
+ for(i=0; i<raptor_sequence_size(e->args); i++) {
+ rasqal_expression* e2=(rasqal_expression*)raptor_sequence_get_at(e->args, i);
+ if(!rasqal_expression_visit(e2, fn, user_data)) {
+ result=0;
+ break;
+ }
+ }
+ return result;
+ break;
+
+ case RASQAL_EXPR_VARSTAR:
+ /* constants */
+ return 0;
+ break;
+
+ case RASQAL_EXPR_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown operation %d", e->op);
+ return -1; /* keep some compilers happy */
+ }
+}
+
+
+/*
+ * rasqal_language_matches:
+ * @lang_tag: language tag such as "en" or "en-US" or "ab-cd-ef"
+ * @lang_range: language range such as "*" (SPARQL) or "en" or "ab-cd"
+ *
+ * INTERNAL - Match a language tag against a language range
+ *
+ * Returns true if @lang_range matches @lang_tag per
+ * Matching of Language Tags [RFC4647] section 2.1
+ * RFC4647 defines a case-insensitive, hierarchical matching
+ * algorithm which operates on ISO-defined subtags for language and
+ * country codes, and user defined subtags.
+ *
+ * (Note: RFC3066 section 2.5 matching is identical to
+ * RFC4647 section 3.3.1 Basic Filtering )
+ *
+ * In SPARQL, a language-range of "*" matches any non-empty @lang_tag string.
+ * See http://www.w3.org/TR/2007/WD-rdf-sparql-query-20070326/#func-langMatches
+ *
+ * Return value: non-0 if true
+ */
+static int
+rasqal_language_matches(const unsigned char* lang_tag,
+ const unsigned char* lang_range)
+{
+ int b= 0;
+
+ if(!(lang_tag && lang_range && *lang_tag && *lang_range)) {
+ /* One of the arguments is NULL or the empty string */
+ return 0;
+ }
+
+ /* Now have two non-empty arguments */
+
+ /* Simple range string "*" matches anything excluding NULL/empty
+ * lang_tag (checked above)
+ */
+ if(lang_range[0] == '*') {
+ if(!lang_range[1])
+ b = 1;
+ return b;
+ }
+
+ while (1) {
+ char tag_c = tolower(*lang_tag++);
+ char range_c = tolower(*lang_range++);
+ if ((!tag_c && !range_c) || (!range_c && tag_c == '-')) {
+ /* EITHER
+ * The end of both strings (thus everything previous matched
+ * such as e.g. tag "fr-CA" matching range "fr-ca")
+ * OR
+ * The end of the range and end of the tag prefix (e.g. tag
+ * "en-US" matching range "en")
+ * means a match
+ */
+ b = 1;
+ break;
+ }
+ if (range_c != tag_c) {
+ /* If a difference was found - including one of the
+ * strings being shorter than the other, it means no match
+ * (b is set to 0 above)
+ */
+ break;
+ }
+ }
+
+ return b;
+}
+
+
+/*
+ * rasqal_expression_evaluate_strmatch:
+ * @world: #rasqal_world
+ * @locator: error locator object
+ * @e: The expression to evaluate.
+ * @flags: Compare flags
+ *
+ * INTERNAL - Evaluate RASQAL_EXPR_STR_MATCH, RASQAL_EXPR_STR_NMATCH and
+ * RASQAL_EXPR_REGEX expressions.
+ *
+ * Return value: A #rasqal_literal value or NULL on failure.
+ */
+static rasqal_literal*
+rasqal_expression_evaluate_strmatch(rasqal_world *world,
+ raptor_locator *locator,
+ rasqal_expression *e,
+ int flags)
+{
+ int b=0;
+ int flag_i=0; /* flags contains i */
+ const unsigned char *p;
+ const unsigned char *match_string;
+ const unsigned char *pattern;
+ const unsigned char *regex_flags;
+ rasqal_literal *l1, *l2, *l3;
+ int error=0;
+ int rc=0;
+#ifdef RASQAL_REGEX_PCRE
+ pcre* re;
+ int options=0;
+ const char *re_error=NULL;
+ int erroffset=0;
+#endif
+#ifdef RASQAL_REGEX_POSIX
+ regex_t reg;
+ int options=REG_EXTENDED | REG_NOSUB;
+#endif
+
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ match_string=rasqal_literal_as_string_flags(l1, flags, &error);
+ if(error || !match_string) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ l3=NULL;
+ regex_flags=NULL;
+ if(e->op == RASQAL_EXPR_REGEX) {
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ if(e->arg3) {
+ l3=rasqal_expression_evaluate_v2(world, locator, e->arg3, flags);
+ if(!l3) {
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ goto failed;
+ }
+ regex_flags=l3->string;
+ }
+
+ } else {
+ l2=e->literal;
+ regex_flags=l2->flags;
+ }
+ pattern=l2->string;
+
+ for(p=regex_flags; p && *p; p++)
+ if(*p == 'i')
+ flag_i++;
+
+#ifdef RASQAL_REGEX_PCRE
+ if(flag_i)
+ options |= PCRE_CASELESS;
+
+ re=pcre_compile((const char*)pattern, options,
+ &re_error, &erroffset, NULL);
+ if(!re) {
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_ERROR, locator,
+ "Regex compile of '%s' failed - %s", pattern, re_error);
+ rc= -1;
+ } else {
+ rc=pcre_exec(re,
+ NULL, /* no study */
+ (const char*)match_string, strlen((const char*)match_string),
+ 0 /* startoffset */,
+ 0 /* options */,
+ NULL, 0 /* ovector, ovecsize - no matches wanted */
+ );
+ if(rc >= 0)
+ b=1;
+ else if(rc != PCRE_ERROR_NOMATCH) {
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_ERROR, locator,
+ "Regex match failed - returned code %d", rc);
+ rc= -1;
+ } else
+ rc=0;
+ }
+ pcre_free(re);
+
+#endif
+
+#ifdef RASQAL_REGEX_POSIX
+ if(flag_i)
+ options |=REG_ICASE;
+
+ rc=regcomp(®, (const char*)pattern, options);
+ if(rc) {
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_ERROR, locator,
+ "Regex compile of '%s' failed", pattern);
+ rc= -1;
+ } else {
+ rc=regexec(®, (const char*)match_string,
+ 0, NULL, /* nmatch, regmatch_t pmatch[] - no matches wanted */
+ 0 /* eflags */
+ );
+ if(!rc)
+ b=1;
+ else if (rc != REG_NOMATCH) {
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_ERROR, locator,
+ "Regex match failed - returned code %d", rc);
+ rc= -1;
+ } else
+ rc= 0;
+ }
+ regfree(®);
+#endif
+
+#ifdef RASQAL_REGEX_NONE
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_WARNING, locator,
+ "Regex support missing, cannot compare '%s' to '%s'", match_string, pattern);
+ b=1;
+ rc= -1;
+#endif
+
+ RASQAL_DEBUG5("regex match returned %s for '%s' against '%s' (flags=%s)\n", b ? "true" : "false", match_string, pattern, l2->flags ? (char*)l2->flags : "");
+
+ if(e->op == RASQAL_EXPR_STR_NMATCH)
+ b=1-b;
+
+ rasqal_free_literal(l1);
+ if(e->op == RASQAL_EXPR_REGEX) {
+ rasqal_free_literal(l2);
+ if(l3)
+ rasqal_free_literal(l3);
+ }
+
+ if(rc<0)
+ goto failed;
+
+ return rasqal_new_boolean_literal(world, b);
+
+ failed:
+ return NULL;
+}
+
+
+/**
+ * rasqal_expression_evaluate_v2:
+ * @query: #rasqal_query this expression belongs to
+ * @locator: error locator
+ * @e: The expression to evaluate.
+ * @flags: Flags for rasqal_literal_compare() and RASQAL_COMPARE_NOCASE for string matches.
+ *
+ * Evaluate a #rasqal_expression tree to give a #rasqal_literal result
+ * or error.
+ *
+ * Return value: a #rasqal_literal value or NULL on failure.
+ **/
+rasqal_literal*
+rasqal_expression_evaluate_v2(rasqal_world *world, raptor_locator *locator,
+ rasqal_expression* e, int flags)
+{
+ rasqal_literal* result=NULL;
+
+ rasqal_literal *l1;
+ rasqal_literal *l2;
+ const unsigned char *s;
+
+ /* pack vars from different switch cases in unions to save some stack space */
+ union {
+ struct { int e1; int e2; } errs;
+ struct { int dummy_do_not_mask_e; int free_literal; } flags;
+ int e;
+ } errs;
+ union {
+ struct { int b1; int b2; } bools;
+ int b;
+ int i;
+ raptor_uri *dt_uri;
+ const unsigned char *s;
+ unsigned char *new_s;
+ rasqal_variable *v;
+ } vars;
+
+ errs.e=0;
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG2("evaluating expression %p: ", e);
+ rasqal_expression_print(e, stderr);
+ fprintf(stderr, "\n");
+#endif
+
+ switch(e->op) {
+ case RASQAL_EXPR_AND:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1) {
+ errs.errs.e1=1;
+ vars.bools.b1=0;
+ } else {
+ errs.errs.e1=0;
+ vars.bools.b1=rasqal_literal_as_boolean(l1, &errs.errs.e1);
+ rasqal_free_literal(l1);
+ }
+
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l1) {
+ errs.errs.e2=1;
+ vars.bools.b2=0;
+ } else {
+ errs.errs.e2=0;
+ vars.bools.b2=rasqal_literal_as_boolean(l1, &errs.errs.e2);
+ rasqal_free_literal(l1);
+ }
+
+ /* See http://www.w3.org/TR/2005/WD-rdf-sparql-query-20051123/#truthTable */
+ if(!errs.errs.e1 && !errs.errs.e2) {
+ /* No type error, answer is A && B */
+ vars.b = vars.bools.b1 && vars.bools.b2; /* don't need b1,b2 anymore */
+ } else {
+ if((!vars.bools.b1 && errs.errs.e2) || (errs.errs.e1 && vars.bools.b2))
+ /* F && E => F. E && F => F. */
+ vars.b=0;
+ else
+ /* Otherwise E */
+ goto failed;
+ }
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_OR:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1) {
+ errs.errs.e1=1;
+ vars.bools.b1=0;
+ } else {
+ errs.errs.e1=0;
+ vars.bools.b1=rasqal_literal_as_boolean(l1, &errs.errs.e1);
+ rasqal_free_literal(l1);
+ }
+
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l1) {
+ errs.errs.e2=1;
+ vars.bools.b2=0;
+ } else {
+ errs.errs.e2=0;
+ vars.bools.b2=rasqal_literal_as_boolean(l1, &errs.errs.e2);
+ rasqal_free_literal(l1);
+ }
+
+ /* See http://www.w3.org/TR/2005/WD-rdf-sparql-query-20051123/#truthTable */
+ if(!errs.errs.e1 && !errs.errs.e2) {
+ /* No type error, answer is A || B */
+ vars.b = vars.bools.b1 || vars.bools.b2; /* don't need b1,b2 anymore */
+ } else {
+ if((vars.bools.b1 && errs.errs.e2) || (errs.errs.e1 && vars.bools.b2))
+ /* T || E => T. E || T => T */
+ vars.b=1;
+ else
+ /* Otherwise E */
+ goto failed;
+ }
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_EQ:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_equals_flags(l1, l2, flags, &errs.e) != 0);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_NEQ:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_equals_flags(l1, l2, flags, &errs.e) == 0);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_LT:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_compare(l1, l2, flags, &errs.e) < 0);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_GT:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_compare(l1, l2, flags, &errs.e) > 0);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_LE:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_compare(l1, l2, flags, &errs.e) <= 0);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_GE:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_compare(l1, l2, flags, &errs.e) >= 0);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_UMINUS:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ result=rasqal_literal_negate(l1, &errs.e);
+ rasqal_free_literal(l1);
+ if(errs.e)
+ goto failed;
+ break;
+
+ case RASQAL_EXPR_BOUND:
+ /* Do not use rasqal_expression_evaluate() here since
+ * we need to check the argument is a variable, and
+ * that function will flatten such thing to literals
+ * as early as possible. See (FLATTEN_LITERAL) below
+ */
+ if(!e->arg1 || e->arg1->op != RASQAL_EXPR_LITERAL)
+ goto failed;
+
+ l1=e->arg1->literal;
+ if(!l1 || l1->type != RASQAL_LITERAL_VARIABLE)
+ goto failed;
+
+ vars.v=rasqal_literal_as_variable(l1);
+ if(!vars.v)
+ goto failed;
+
+ result=rasqal_new_boolean_literal(world, (vars.v->value != NULL));
+ break;
+
+ case RASQAL_EXPR_STR:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ /* Note: flags removes RASQAL_COMPARE_XQUERY as this is the
+ * explicit stringify operation
+ */
+ s=rasqal_literal_as_string_flags(l1, (flags & ~RASQAL_COMPARE_XQUERY),
+ &errs.e);
+ if(!s || errs.e) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.new_s=(unsigned char *)RASQAL_MALLOC(cstring, strlen((const char*)s)+1);
+ if(!vars.new_s) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+ strcpy((char*)vars.new_s, (const char*)s);
+
+ result=rasqal_new_string_literal(world, vars.new_s, NULL, NULL, NULL);
+ rasqal_free_literal(l1);
+
+ break;
+
+ case RASQAL_EXPR_LANG:
+ errs.flags.free_literal=1;
+
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ vars.v=rasqal_literal_as_variable(l1);
+ if(vars.v) {
+ rasqal_free_literal(l1);
+ l1=vars.v->value; /* don't need vars.v after this */
+ errs.flags.free_literal=0;
+ if(!l1)
+ goto failed;
+ }
+
+ if(rasqal_literal_get_rdf_term_type(l1) != RASQAL_LITERAL_STRING) {
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ if(l1->language) {
+ vars.new_s=(unsigned char*)RASQAL_MALLOC(cstring,
+ strlen(l1->language)+1);
+ if(!vars.new_s) {
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+ strcpy((char*)vars.new_s, l1->language);
+ } else {
+ vars.new_s=(unsigned char*)RASQAL_MALLOC(cstring, 1);
+ if(!vars.new_s) {
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+ *vars.new_s='\0';
+ }
+ result=rasqal_new_string_literal(world, vars.new_s, NULL, NULL, NULL);
+
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+
+ break;
+
+ case RASQAL_EXPR_LANGMATCHES:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ s=rasqal_literal_as_string_flags(l1, flags, &errs.e);
+ vars.s=rasqal_literal_as_string_flags(l2, flags, &errs.e);
+
+ if(errs.e)
+ vars.b=0;
+ else
+ vars.b=rasqal_language_matches(s, vars.s); /* don't need s anymore */
+
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_DATATYPE:
+ errs.flags.free_literal=1;
+ vars.dt_uri=NULL;
+
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ vars.v=rasqal_literal_as_variable(l1);
+ if(vars.v) {
+ rasqal_free_literal(l1);
+ l1=vars.v->value; /* don't need vars.v after this */
+ errs.flags.free_literal=0;
+ if(!l1)
+ goto failed;
+ }
+
+ if(rasqal_literal_get_rdf_term_type(l1) != RASQAL_LITERAL_STRING) {
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ if(l1->language) {
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ /* The datatype of a plain literal is xsd:string */
+ vars.dt_uri=l1->datatype;
+ if(!vars.dt_uri && l1->type == RASQAL_LITERAL_STRING)
+ vars.dt_uri=rasqal_xsd_datatype_type_to_uri(l1->world, l1->type);
+
+ if(!vars.dt_uri) {
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+#ifdef RAPTOR_V2_AVAILABLE
+ result = rasqal_new_uri_literal(world, raptor_uri_copy_v2(world->raptor_world_ptr, vars.dt_uri));
+#else
+ result = rasqal_new_uri_literal(world, raptor_uri_copy(vars.dt_uri));
+#endif
+
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+
+ break;
+
+ case RASQAL_EXPR_ISURI:
+ errs.flags.free_literal=1;
+
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ vars.v=rasqal_literal_as_variable(l1);
+ if(vars.v) {
+ rasqal_free_literal(l1);
+ l1=vars.v->value; /* don't need vars.v after this */
+ errs.flags.free_literal=0;
+ if(!l1)
+ goto failed;
+ }
+
+ vars.b=(l1->type == RASQAL_LITERAL_URI);
+
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_ISBLANK:
+ errs.flags.free_literal=1;
+
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ vars.v=rasqal_literal_as_variable(l1);
+ if(vars.v) {
+ rasqal_free_literal(l1);
+ l1=vars.v->value; /* don't need vars.v after this */
+ errs.flags.free_literal=0;
+ if(!l1)
+ goto failed;
+ }
+
+ vars.b=(l1->type == RASQAL_LITERAL_BLANK);
+
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_ISLITERAL:
+ errs.flags.free_literal=1;
+
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ vars.v=rasqal_literal_as_variable(l1);
+ if(vars.v) {
+ rasqal_free_literal(l1);
+ l1=vars.v->value; /* don't need vars.v after this */
+ errs.flags.free_literal=0;
+ if(!l1)
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_get_rdf_term_type(l1) == RASQAL_LITERAL_STRING);
+
+ if(errs.flags.free_literal)
+ rasqal_free_literal(l1);
+
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_PLUS:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ result=rasqal_literal_add(l1, l2, &errs.e);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+
+ break;
+
+ case RASQAL_EXPR_MINUS:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ result=rasqal_literal_subtract(l1, l2, &errs.e);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+
+ break;
+
+ case RASQAL_EXPR_STAR:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ result=rasqal_literal_multiply(l1, l2, &errs.e);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+
+ break;
+
+ case RASQAL_EXPR_SLASH:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ result=rasqal_literal_divide(l1, l2, &errs.e);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+
+ break;
+
+ case RASQAL_EXPR_REM:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.i=rasqal_literal_as_integer(l2, &errs.errs.e2);
+ /* error if divisor is zero */
+ if(!vars.i)
+ errs.errs.e2=1;
+ else
+ vars.i=rasqal_literal_as_integer(l1, &errs.errs.e1) % vars.i;
+
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.errs.e1 || errs.errs.e2)
+ goto failed;
+
+ result=rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, vars.i);
+ break;
+
+ case RASQAL_EXPR_STR_EQ:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_compare(l1, l2, flags | RASQAL_COMPARE_NOCASE,
+ &errs.e) == 0);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_STR_NEQ:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=(rasqal_literal_compare(l1, l2, flags | RASQAL_COMPARE_NOCASE,
+ &errs.e) != 0);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_TILDE:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ vars.i= ~ rasqal_literal_as_integer(l1, &errs.e);
+ rasqal_free_literal(l1);
+ if(errs.e)
+ goto failed;
+
+ result=rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, vars.i);
+ break;
+
+ case RASQAL_EXPR_BANG:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ vars.b= ! rasqal_literal_as_boolean(l1, &errs.e);
+ rasqal_free_literal(l1);
+ if(errs.e)
+ goto failed;
+
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_STR_MATCH:
+ case RASQAL_EXPR_STR_NMATCH:
+ case RASQAL_EXPR_REGEX:
+ result=rasqal_expression_evaluate_strmatch(world, locator, e, flags);
+ break;
+
+ case RASQAL_EXPR_LITERAL:
+ /* flatten any literal to a value as soon as possible - this
+ * removes variables from expressions the first time they are seen.
+ * (FLATTEN_LITERAL)
+ */
+ result=rasqal_new_literal_from_literal(rasqal_literal_value(e->literal));
+ break;
+
+ case RASQAL_EXPR_FUNCTION:
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_WARNING, locator,
+ "No function expressions support at present. Returning false.");
+ result=rasqal_new_boolean_literal(world, 0);
+ break;
+
+ case RASQAL_EXPR_CAST:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ result=rasqal_literal_cast(l1, e->name, flags, &errs.e);
+
+ rasqal_free_literal(l1);
+ if(errs.e)
+ goto failed;
+
+ break;
+
+ case RASQAL_EXPR_ORDER_COND_ASC:
+ case RASQAL_EXPR_ORDER_COND_DESC:
+ case RASQAL_EXPR_GROUP_COND_ASC:
+ case RASQAL_EXPR_GROUP_COND_DESC:
+ case RASQAL_EXPR_COUNT:
+ result=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ break;
+
+ case RASQAL_EXPR_VARSTAR:
+ /* constants */
+ break;
+
+ case RASQAL_EXPR_SAMETERM:
+ l1=rasqal_expression_evaluate_v2(world, locator, e->arg1, flags);
+ if(!l1)
+ goto failed;
+
+ l2=rasqal_expression_evaluate_v2(world, locator, e->arg2, flags);
+ if(!l2) {
+ rasqal_free_literal(l1);
+ goto failed;
+ }
+
+ vars.b=rasqal_literal_equals_flags(l1, l2, RASQAL_COMPARE_RDF, &errs.e);
+ rasqal_free_literal(l1);
+ rasqal_free_literal(l2);
+ if(errs.e)
+ goto failed;
+
+ result=rasqal_new_boolean_literal(world, vars.b);
+ break;
+
+ case RASQAL_EXPR_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown operation %d", e->op);
+ }
+
+ got_result:
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG2("result of %p: ", e);
+ rasqal_expression_print(e, stderr);
+ fputs( ": ", stderr);
+ if(result)
+ rasqal_literal_print(result, stderr);
+ else
+ fputs("(NULL)",stderr);
+ fputc('\n', stderr);
+#endif
+
+ return result;
+
+ failed:
+
+ if(result) {
+ rasqal_free_literal(result);
+ result=NULL;
+ }
+ goto got_result;
+}
+
+
+/**
+ * rasqal_expression_evaluate:
+ * @query: #rasqal_query this expression belongs to
+ * @e: The expression to evaluate.
+ * @flags: Flags for rasqal_literal_compare() and RASQAL_COMPARE_NOCASE for string matches.
+ *
+ * Evaluate a #rasqal_expression tree to give a #rasqal_literal result
+ * or error.
+ *
+ * Return value: a #rasqal_literal value or NULL on failure.
+ **/
+rasqal_literal*
+rasqal_expression_evaluate(rasqal_query *query, rasqal_expression* e,
+ int flags)
+{
+ return rasqal_expression_evaluate_v2(query->world, &query->locator, e, flags);
+}
+
+
+static const char* const rasqal_op_labels[RASQAL_EXPR_LAST+1]={
+ "UNKNOWN",
+ "and",
+ "or",
+ "eq",
+ "neq",
+ "lt",
+ "gt",
+ "le",
+ "ge",
+ "uminus",
+ "plus",
+ "minus",
+ "star",
+ "slash",
+ "rem",
+ "str_eq",
+ "str_ne",
+ "str_match",
+ "str_nmatch",
+ "tilde",
+ "bang",
+ "literal",
+ "function",
+ "bound",
+ "str",
+ "lang",
+ "datatype",
+ "isUri",
+ "isBlank",
+ "isLiteral",
+ "cast",
+ "order asc",
+ "order desc",
+ "langMatches",
+ "regex",
+ "group asc",
+ "group desc",
+ "count",
+ "varstar",
+ "sameTerm"
+};
+
+
+/**
+ * rasqal_expression_write_op:
+ * @e: the #rasqal_expression object
+ * @iostr: the #raptor_iostream to write to
+ *
+ * Write a rasqal expression operator to an iostream in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_expression_write_op(rasqal_expression* e, raptor_iostream* iostr)
+{
+ rasqal_op op=e->op;
+ if(op > RASQAL_EXPR_LAST)
+ op=RASQAL_EXPR_UNKNOWN;
+ raptor_iostream_write_string(iostr, rasqal_op_labels[(int)op]);
+}
+
+
+/**
+ * rasqal_expression_print_op:
+ * @e: the #rasqal_expression object
+ * @fh: the #FILE* handle to print to
+ *
+ * Print a rasqal expression operator in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_expression_print_op(rasqal_expression* e, FILE* fh)
+{
+ rasqal_op op=e->op;
+ if(op > RASQAL_EXPR_LAST)
+ op=RASQAL_EXPR_UNKNOWN;
+ fputs(rasqal_op_labels[(int)op], fh);
+}
+
+
+/**
+ * rasqal_expression_write:
+ * @e: #rasqal_expression object.
+ * @iostr: The #raptor_iostream to write to.
+ *
+ * Write a Rasqal expression to an iostream in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_expression_write(rasqal_expression* e, raptor_iostream* iostr)
+{
+ int i;
+
+ raptor_iostream_write_counted_string(iostr, "expr(", 5);
+ switch(e->op) {
+ case RASQAL_EXPR_AND:
+ case RASQAL_EXPR_OR:
+ case RASQAL_EXPR_EQ:
+ case RASQAL_EXPR_NEQ:
+ case RASQAL_EXPR_LT:
+ case RASQAL_EXPR_GT:
+ case RASQAL_EXPR_LE:
+ case RASQAL_EXPR_GE:
+ case RASQAL_EXPR_PLUS:
+ case RASQAL_EXPR_MINUS:
+ case RASQAL_EXPR_STAR:
+ case RASQAL_EXPR_SLASH:
+ case RASQAL_EXPR_REM:
+ case RASQAL_EXPR_STR_EQ:
+ case RASQAL_EXPR_STR_NEQ:
+ case RASQAL_EXPR_LANGMATCHES:
+ case RASQAL_EXPR_REGEX:
+ case RASQAL_EXPR_SAMETERM:
+ raptor_iostream_write_counted_string(iostr, "op ", 3);
+ rasqal_expression_write_op(e, iostr);
+ raptor_iostream_write_byte(iostr, '(');
+ rasqal_expression_write(e->arg1, iostr);
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_expression_write(e->arg2, iostr);
+ /* There is only one 3-op expression and it's handled here */
+ if(e->op == RASQAL_EXPR_REGEX && e->arg3) {
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_expression_write(e->arg3, iostr);
+ }
+ raptor_iostream_write_byte(iostr, ')');
+ break;
+ case RASQAL_EXPR_STR_MATCH:
+ case RASQAL_EXPR_STR_NMATCH:
+ raptor_iostream_write_counted_string(iostr, "op ", 3);
+ rasqal_expression_write_op(e, iostr);
+ raptor_iostream_write_byte(iostr, '(');
+ rasqal_expression_write(e->arg1, iostr);
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_literal_write(e->literal, iostr);
+ raptor_iostream_write_byte(iostr, ')');
+ break;
+ case RASQAL_EXPR_TILDE:
+ case RASQAL_EXPR_BANG:
+ case RASQAL_EXPR_UMINUS:
+ case RASQAL_EXPR_BOUND:
+ case RASQAL_EXPR_STR:
+ case RASQAL_EXPR_LANG:
+ case RASQAL_EXPR_DATATYPE:
+ case RASQAL_EXPR_ISURI:
+ case RASQAL_EXPR_ISBLANK:
+ case RASQAL_EXPR_ISLITERAL:
+ case RASQAL_EXPR_ORDER_COND_ASC:
+ case RASQAL_EXPR_ORDER_COND_DESC:
+ case RASQAL_EXPR_GROUP_COND_ASC:
+ case RASQAL_EXPR_GROUP_COND_DESC:
+ case RASQAL_EXPR_COUNT:
+ raptor_iostream_write_counted_string(iostr, "op ", 3);
+ rasqal_expression_write_op(e, iostr);
+ raptor_iostream_write_byte(iostr, '(');
+ rasqal_expression_write(e->arg1, iostr);
+ raptor_iostream_write_byte(iostr, ')');
+ break;
+
+ case RASQAL_EXPR_LITERAL:
+ rasqal_literal_write(e->literal, iostr);
+ break;
+
+ case RASQAL_EXPR_FUNCTION:
+ raptor_iostream_write_counted_string(iostr, "function(uri=", 13);
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_iostream_write_uri_v2(e->world->raptor_world_ptr, iostr, e->name);
+#else
+ raptor_iostream_write_uri(iostr, e->name);
+#endif
+ raptor_iostream_write_counted_string(iostr, ", args=", 7);
+ for(i=0; i<raptor_sequence_size(e->args); i++) {
+ rasqal_expression* e2;
+ if(i>0)
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ e2=(rasqal_expression*)raptor_sequence_get_at(e->args, i);
+ rasqal_expression_write(e2, iostr);
+ }
+ raptor_iostream_write_byte(iostr, ')');
+ break;
+
+ case RASQAL_EXPR_CAST:
+ raptor_iostream_write_counted_string(iostr, "cast(type=", 10);
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_iostream_write_uri_v2(e->world->raptor_world_ptr, iostr, e->name);
+#else
+ raptor_iostream_write_uri(iostr, e->name);
+#endif
+ raptor_iostream_write_counted_string(iostr, ", value=", 8);
+ rasqal_expression_write(e->arg1, iostr);
+ raptor_iostream_write_byte(iostr, ')');
+ break;
+
+ case RASQAL_EXPR_VARSTAR:
+ raptor_iostream_write_counted_string(iostr, "varstar", 7);
+ break;
+
+ case RASQAL_EXPR_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown operation %d", e->op);
+ }
+ raptor_iostream_write_byte(iostr, ')');
+}
+
+
+/**
+ * rasqal_expression_print:
+ * @e: #rasqal_expression object.
+ * @fh: The #FILE* handle to print to.
+ *
+ * Print a Rasqal expression in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_expression_print(rasqal_expression* e, FILE* fh)
+{
+ fputs("expr(", fh);
+ switch(e->op) {
+ case RASQAL_EXPR_AND:
+ case RASQAL_EXPR_OR:
+ case RASQAL_EXPR_EQ:
+ case RASQAL_EXPR_NEQ:
+ case RASQAL_EXPR_LT:
+ case RASQAL_EXPR_GT:
+ case RASQAL_EXPR_LE:
+ case RASQAL_EXPR_GE:
+ case RASQAL_EXPR_PLUS:
+ case RASQAL_EXPR_MINUS:
+ case RASQAL_EXPR_STAR:
+ case RASQAL_EXPR_SLASH:
+ case RASQAL_EXPR_REM:
+ case RASQAL_EXPR_STR_EQ:
+ case RASQAL_EXPR_STR_NEQ:
+ case RASQAL_EXPR_LANGMATCHES:
+ case RASQAL_EXPR_REGEX:
+ case RASQAL_EXPR_SAMETERM:
+ fputs("op ", fh);
+ rasqal_expression_print_op(e, fh);
+ fputc('(', fh);
+ rasqal_expression_print(e->arg1, fh);
+ fputs(", ", fh);
+ rasqal_expression_print(e->arg2, fh);
+ /* There is only one 3-op expression and it's handled here */
+ if(e->op == RASQAL_EXPR_REGEX && e->arg3) {
+ fputs(", ", fh);
+ rasqal_expression_print(e->arg3, fh);
+ }
+ fputc(')', fh);
+ break;
+ case RASQAL_EXPR_STR_MATCH:
+ case RASQAL_EXPR_STR_NMATCH:
+ fputs("op ", fh);
+ rasqal_expression_print_op(e, fh);
+ fputc('(', fh);
+ rasqal_expression_print(e->arg1, fh);
+ fputs(", ", fh);
+ rasqal_literal_print(e->literal, fh);
+ fputc(')', fh);
+ break;
+ case RASQAL_EXPR_TILDE:
+ case RASQAL_EXPR_BANG:
+ case RASQAL_EXPR_UMINUS:
+ case RASQAL_EXPR_BOUND:
+ case RASQAL_EXPR_STR:
+ case RASQAL_EXPR_LANG:
+ case RASQAL_EXPR_DATATYPE:
+ case RASQAL_EXPR_ISURI:
+ case RASQAL_EXPR_ISBLANK:
+ case RASQAL_EXPR_ISLITERAL:
+ case RASQAL_EXPR_ORDER_COND_ASC:
+ case RASQAL_EXPR_ORDER_COND_DESC:
+ case RASQAL_EXPR_GROUP_COND_ASC:
+ case RASQAL_EXPR_GROUP_COND_DESC:
+ case RASQAL_EXPR_COUNT:
+ fputs("op ", fh);
+ rasqal_expression_print_op(e, fh);
+ fputc('(', fh);
+ rasqal_expression_print(e->arg1, fh);
+ fputc(')', fh);
+ break;
+
+ case RASQAL_EXPR_LITERAL:
+ rasqal_literal_print(e->literal, fh);
+ break;
+
+ case RASQAL_EXPR_FUNCTION:
+ fputs("function(uri=", fh);
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_print_v2(e->world->raptor_world_ptr, e->name, fh);
+#else
+ raptor_uri_print(e->name, fh);
+#endif
+ fputs(", args=", fh);
+ raptor_sequence_print(e->args, fh);
+ fputc(')', fh);
+ break;
+
+ case RASQAL_EXPR_CAST:
+ fputs("cast(type=", fh);
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_print_v2(e->world->raptor_world_ptr, e->name, fh);
+#else
+ raptor_uri_print(e->name, fh);
+#endif
+ fputs(", value=", fh);
+ rasqal_expression_print(e->arg1, fh);
+ fputc(')', fh);
+ break;
+
+ case RASQAL_EXPR_VARSTAR:
+ fputs("varstar", fh);
+ break;
+
+ case RASQAL_EXPR_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown operation %d", e->op);
+ }
+ fputc(')', fh);
+}
+
+
+/* for use with rasqal_expression_visit and user_data=rasqal_query */
+int
+rasqal_expression_has_qname(void *user_data, rasqal_expression *e)
+{
+ if(e->op == RASQAL_EXPR_LITERAL)
+ return rasqal_literal_has_qname(e->literal);
+
+ return 0;
+}
+
+
+/* for use with rasqal_expression_visit and user_data=rasqal_query */
+int
+rasqal_expression_expand_qname(void *user_data, rasqal_expression *e)
+{
+ if(e->op == RASQAL_EXPR_LITERAL)
+ return rasqal_literal_expand_qname(user_data, e->literal);
+
+ return 0;
+}
+
+
+int
+rasqal_expression_is_constant(rasqal_expression* e)
+{
+ int i;
+ int result=0;
+
+ switch(e->op) {
+ case RASQAL_EXPR_AND:
+ case RASQAL_EXPR_OR:
+ case RASQAL_EXPR_EQ:
+ case RASQAL_EXPR_NEQ:
+ case RASQAL_EXPR_LT:
+ case RASQAL_EXPR_GT:
+ case RASQAL_EXPR_LE:
+ case RASQAL_EXPR_GE:
+ case RASQAL_EXPR_PLUS:
+ case RASQAL_EXPR_MINUS:
+ case RASQAL_EXPR_STAR:
+ case RASQAL_EXPR_SLASH:
+ case RASQAL_EXPR_REM:
+ case RASQAL_EXPR_STR_EQ:
+ case RASQAL_EXPR_STR_NEQ:
+ case RASQAL_EXPR_LANGMATCHES:
+ case RASQAL_EXPR_SAMETERM:
+ result=rasqal_expression_is_constant(e->arg1) &&
+ rasqal_expression_is_constant(e->arg2);
+ break;
+ case RASQAL_EXPR_REGEX:
+ result=rasqal_expression_is_constant(e->arg1) &&
+ rasqal_expression_is_constant(e->arg2) &&
+ (e->arg3 && rasqal_expression_is_constant(e->arg3));
+ break;
+ case RASQAL_EXPR_STR_MATCH:
+ case RASQAL_EXPR_STR_NMATCH:
+ result=rasqal_expression_is_constant(e->arg1) &&
+ rasqal_literal_is_constant(e->literal);
+ break;
+ case RASQAL_EXPR_TILDE:
+ case RASQAL_EXPR_BANG:
+ case RASQAL_EXPR_UMINUS:
+ case RASQAL_EXPR_BOUND:
+ case RASQAL_EXPR_STR:
+ case RASQAL_EXPR_LANG:
+ case RASQAL_EXPR_DATATYPE:
+ case RASQAL_EXPR_ISURI:
+ case RASQAL_EXPR_ISBLANK:
+ case RASQAL_EXPR_ISLITERAL:
+ case RASQAL_EXPR_ORDER_COND_ASC:
+ case RASQAL_EXPR_ORDER_COND_DESC:
+ case RASQAL_EXPR_GROUP_COND_ASC:
+ case RASQAL_EXPR_GROUP_COND_DESC:
+ case RASQAL_EXPR_COUNT:
+ result=rasqal_expression_is_constant(e->arg1);
+ break;
+
+ case RASQAL_EXPR_LITERAL:
+ result=rasqal_literal_is_constant(e->literal);
+ break;
+
+ case RASQAL_EXPR_FUNCTION:
+ result=1;
+ for(i=0; i<raptor_sequence_size(e->args); i++) {
+ rasqal_expression* e2=(rasqal_expression*)raptor_sequence_get_at(e->args, i);
+ if(!rasqal_expression_is_constant(e2)) {
+ result=0;
+ break;
+ }
+ }
+ break;
+
+ case RASQAL_EXPR_CAST:
+ result=rasqal_expression_is_constant(e->arg1);
+ break;
+
+ case RASQAL_EXPR_VARSTAR:
+ result=0;
+ break;
+
+ case RASQAL_EXPR_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown operation %d", e->op);
+ }
+
+ return result;
+}
+
+
+void
+rasqal_expression_convert_to_literal(rasqal_expression* e, rasqal_literal* l)
+{
+ int usage=e->usage;
+
+ /* update expression 'e' in place */
+ rasqal_expression_clear(e);
+
+ memset(e, 0, sizeof(rasqal_expression));
+ e->usage=usage;
+ e->op=RASQAL_EXPR_LITERAL;
+ e->literal=l;
+}
+
+
+
+
+/* for use with rasqal_expression_visit and user_data=rasqal_query */
+static int
+rasqal_expression_has_variable(void *user_data, rasqal_expression *e)
+{
+ rasqal_variable* v;
+ const unsigned char* name=((rasqal_variable*)user_data)->name;
+
+ if(e->op != RASQAL_EXPR_LITERAL)
+ return 0;
+
+ v=rasqal_literal_as_variable(e->literal);
+ if(!v)
+ return 0;
+
+ if(!strcmp((const char*)v->name, (const char*)name))
+ return 1;
+
+ return 0;
+}
+
+
+int
+rasqal_expression_mentions_variable(rasqal_expression* e, rasqal_variable* v)
+{
+ return rasqal_expression_visit(e, rasqal_expression_has_variable, v);
+}
+
+
+#endif /* not STANDALONE */
+
+
+
+
+#ifdef STANDALONE
+#include <stdio.h>
+
+int main(int argc, char *argv[]);
+
+
+#define assert_match(function, result, string) do { if(strcmp(result, string)) { fprintf(stderr, #function " failed - returned %s, expected %s\n", result, string); exit(1); } } while(0)
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *program=rasqal_basename(argv[0]);
+ rasqal_literal *lit1, *lit2;
+ rasqal_expression *expr1, *expr2;
+ rasqal_expression* expr;
+ rasqal_literal* result;
+ int error=0;
+ rasqal_world *world;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_world* raptor_world_ptr;
+ raptor_world_ptr = raptor_new_world();
+ if(!raptor_world_ptr || raptor_world_open(raptor_world_ptr))
+ exit(1);
+#else
+ raptor_init();
+#endif
+
+ world = rasqal_new_world();
+#ifdef RAPTOR_V2_AVAILABLE
+ rasqal_world_set_raptor(world, raptor_world_ptr);
+#endif
+ /* no rasqal_world_open() */
+
+ rasqal_uri_init(world);
+
+ rasqal_xsd_init(world);
+
+ lit1=rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 1);
+ expr1=rasqal_new_literal_expression(world, lit1);
+ lit2=rasqal_new_integer_literal(world, RASQAL_LITERAL_INTEGER, 1);
+ expr2=rasqal_new_literal_expression(world, lit2);
+ expr=rasqal_new_2op_expression(world, RASQAL_EXPR_PLUS, expr1, expr2);
+
+ fprintf(stderr, "%s: expression: ", program);
+ rasqal_expression_print(expr, stderr);
+ fputc('\n', stderr);
+
+ result=rasqal_expression_evaluate_v2(world, NULL, expr, 0);
+
+ if(result) {
+ int bresult;
+
+ fprintf(stderr, "%s: expression result: \n", program);
+ rasqal_literal_print(result, stderr);
+ fputc('\n', stderr);
+ bresult=rasqal_literal_as_boolean(result, &error);
+ if(error) {
+ fprintf(stderr, "%s: boolean expression FAILED\n", program);
+ } else
+ fprintf(stderr, "%s: boolean expression result: %d\n", program, bresult);
+
+
+ } else
+ fprintf(stderr, "%s: expression evaluation FAILED with error\n", program);
+
+ rasqal_free_expression(expr);
+
+ if(result)
+ rasqal_free_literal(result);
+
+ rasqal_xsd_finish(world);
+
+ rasqal_uri_finish(world);
+
+ RASQAL_FREE(rasqal_world, world);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_world(raptor_world_ptr);
+#else
+ raptor_finish();
+#endif
+
+ return error;
+}
+#endif
diff --git a/src/rasqal/rasqal_feature.c b/src/rasqal/rasqal_feature.c
new file mode 100644
index 0000000..acfda69
--- /dev/null
+++ b/src/rasqal/rasqal_feature.c
@@ -0,0 +1,224 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_feature.c - Query system features
+ *
+ * Copyright (C) 2006, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+/* Rasqal includes */
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+static const struct
+{
+ rasqal_feature feature;
+ /* flag bits
+ * 1=query feature
+ * 2=unused
+ * 4=string value (else int)
+ */
+ int flags;
+ const char *name;
+ const char *label;
+} rasqal_features_list [RASQAL_FEATURE_LAST+1]= {
+ { RASQAL_FEATURE_NO_NET, 1, "noNet", "Deny network requests." }
+};
+
+
+static const char * const rasqal_feature_uri_prefix="http://feature.librdf.org/rasqal-";
+/* NOTE: this is strlen(rasqal_feature_uri_prefix) */
+#define RASQAL_FEATURE_URI_PREFIX_LEN 33
+
+
+/*
+ * rasqal_features_enumerate_common:
+ * @world: rasqal_world object
+ * @feature: feature enumeration (0+)
+ * @name: pointer to store feature short name (or NULL)
+ * @uri: pointer to store feature URI (or NULL)
+ * @label: pointer to feature label (or NULL)
+ * @flags: flags to match
+ *
+ * Internal: Get list of rasqal features.
+ *
+ * If @uri is not NULL, a pointer to a new raptor_uri is returned
+ * that must be freed by the caller with raptor_free_uri().
+ *
+ * Return value: 0 on success, <0 on failure, >0 if feature is unknown
+ **/
+static int
+rasqal_features_enumerate_common(rasqal_world* world,
+ const rasqal_feature feature,
+ const char **name,
+ raptor_uri **uri, const char **label,
+ int flags)
+{
+ int i;
+
+ for(i=0; i <= RASQAL_FEATURE_LAST; i++)
+ if(rasqal_features_list[i].feature == feature &&
+ (rasqal_features_list[i].flags & flags)) {
+ if(name)
+ *name=rasqal_features_list[i].name;
+
+ if(uri) {
+ raptor_uri *base_uri;
+#ifdef RAPTOR_V2_AVAILABLE
+ base_uri = raptor_new_uri_v2(world->raptor_world_ptr, (const unsigned char*)rasqal_feature_uri_prefix);
+ if(!base_uri)
+ return -1;
+ *uri = raptor_new_uri_from_uri_local_name_v2(world->raptor_world_ptr, base_uri,
+ (const unsigned char*)rasqal_features_list[i].name);
+ raptor_free_uri_v2(world->raptor_world_ptr, base_uri);
+#else
+ base_uri = raptor_new_uri((const unsigned char*)rasqal_feature_uri_prefix);
+ if(!base_uri)
+ return -1;
+ *uri = raptor_new_uri_from_uri_local_name(base_uri,
+ (const unsigned char*)rasqal_features_list[i].name);
+ raptor_free_uri(base_uri);
+#endif
+ }
+ if(label)
+ *label=rasqal_features_list[i].label;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/**
+ * rasqal_features_enumerate:
+ * @world: rasqal_world object
+ * @feature: feature enumeration (0+)
+ * @name: pointer to store feature short name (or NULL)
+ * @uri: pointer to store feature URI (or NULL)
+ * @label: pointer to feature label (or NULL)
+ *
+ * Get list of rasqal features.
+ *
+ * If uri is not NULL, a pointer to a new raptor_uri is returned
+ * that must be freed by the caller with raptor_free_uri().
+ *
+ * Return value: 0 on success, <0 on failure, >0 if feature is unknown
+ **/
+int
+rasqal_features_enumerate(rasqal_world* world,
+ const rasqal_feature feature,
+ const char **name,
+ raptor_uri **uri, const char **label)
+{
+ return rasqal_features_enumerate_common(world, feature, name, uri, label, 1);
+}
+
+
+/**
+ * rasqal_feature_value_type
+ * @feature: rasqal query feature
+ *
+ * Get the type of a features.
+ *
+ * The type of the @feature is 0=integer , 1=string. Other values are
+ * undefined. Most features are integer values and use
+ * rasqal_query_set_feature rasqal_query_get_feature()
+ *
+ * Return value: the type of the feature or <0 if @feature is unknown
+ */
+int
+rasqal_feature_value_type(const rasqal_feature feature) {
+ if(feature > RASQAL_FEATURE_LAST)
+ return -1;
+ return (rasqal_features_list[feature].flags & 4) ? 1 : 0;
+}
+
+
+/**
+ * rasqal_feature_from_uri:
+ * @world: rasqal_world object
+ * @uri: feature URI
+ *
+ * Turn a feature URI into an feature enum.
+ *
+ * The allowed feature URIs are available via rasqal_features_enumerate().
+ *
+ * Return value: < 0 if the feature is unknown
+ **/
+rasqal_feature
+rasqal_feature_from_uri(rasqal_world* world, raptor_uri *uri)
+{
+ unsigned char *uri_string;
+ int i;
+ rasqal_feature feature= (rasqal_feature)-1;
+
+ if(!uri)
+ return feature;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ uri_string = raptor_uri_as_string_v2(world->raptor_world_ptr, uri);
+#else
+ uri_string = raptor_uri_as_string(uri);
+#endif
+ if(strncmp((const char*)uri_string, rasqal_feature_uri_prefix,
+ RASQAL_FEATURE_URI_PREFIX_LEN))
+ return feature;
+
+ uri_string += RASQAL_FEATURE_URI_PREFIX_LEN;
+
+ for(i=0; i <= RASQAL_FEATURE_LAST; i++)
+ if(!strcmp(rasqal_features_list[i].name, (const char*)uri_string)) {
+ feature=(rasqal_feature)i;
+ break;
+ }
+
+ return feature;
+}
+
+
+/**
+ * rasqal_get_feature_count:
+ *
+ * Get the count of features defined.
+ *
+ * This is prefered to the compile time-only symbol #RASQAL_FEATURE_LAST
+ * and returns a count of the number of features which is
+ * #RASQAL_FEATURE_LAST+1.
+ *
+ * Return value: count of features in the #rasqal_feature enumeration
+ **/
+unsigned int
+rasqal_get_feature_count(void) {
+ return RASQAL_FEATURE_LAST+1;
+}
diff --git a/src/rasqal/rasqal_general.c b/src/rasqal/rasqal_general.c
new file mode 100644
index 0000000..8619509
--- /dev/null
+++ b/src/rasqal/rasqal_general.c
@@ -0,0 +1,1128 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_general.c - Rasqal library startup, shutdown and factories
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+/* prototypes for helper functions */
+static void rasqal_delete_query_language_factories(rasqal_world*);
+
+
+/* statics */
+
+const char * const rasqal_short_copyright_string = "Copyright 2003-2008 David Beckett. Copyright 2003-2005 University of Bristol";
+
+const char * const rasqal_copyright_string = "Copyright (C) 2003-2008 David Beckett - http://www.dajobe.org/\nCopyright (C) 2003-2005 University of Bristol - http://www.bristol.ac.uk/";
+
+const char * const rasqal_license_string = "LGPL 2.1 or newer, GPL 2 or newer, Apache 2.0 or newer.\nSee http://librdf.org/rasqal/LICENSE.html for full terms.";
+
+const char * const rasqal_home_url_string = "http://librdf.org/rasqal/";
+
+/**
+ * rasqal_version_string:
+ *
+ * Library full version as a string.
+ *
+ * See also #rasqal_version_decimal.
+ */
+const char * const rasqal_version_string = VERSION;
+
+/**
+ * rasqal_version_major:
+ *
+ * Library major version number as a decimal integer.
+ */
+const unsigned int rasqal_version_major = RASQAL_VERSION_MAJOR;
+
+/**
+ * rasqal_version_minor:
+ *
+ * Library minor version number as a decimal integer.
+ */
+const unsigned int rasqal_version_minor = RASQAL_VERSION_MINOR;
+
+/**
+ * rasqal_version_release:
+ *
+ * Library release version number as a decimal integer.
+ */
+const unsigned int rasqal_version_release = RASQAL_VERSION_RELEASE;
+
+/**
+ * rasqal_version_decimal:
+ *
+ * Library full version as a decimal integer.
+ *
+ * See also #rasqal_version_string.
+ */
+const unsigned int rasqal_version_decimal = RASQAL_VERSION_DECIMAL;
+
+
+/**
+ * rasqal_new_world:
+ *
+ * Allocate a new rasqal_world object.
+ *
+ * The rasqal_world is initialized with rasqal_world_open().
+ * Allocation and initialization are decoupled to allow
+ * changing settings on the world object before init.
+ *
+ * Return value: rasqal_world object or NULL on failure
+ **/
+rasqal_world*
+rasqal_new_world(void)
+{
+ return (rasqal_world*)RASQAL_CALLOC(rasqal_world, sizeof(rasqal_world), 1);
+}
+
+
+/**
+ * rasqal_world_open:
+ *
+ * Initialise the rasqal library.
+ *
+ * Initializes a #rasqal_world object created by rasqal_new_world().
+ * Allocation and initialization are decoupled to allow
+ * changing settings on the world object before init.
+ * These settings include e.g. the raptor library instance set with
+ * rasqal_world_set_raptor().
+ *
+ * The initialized world object is used with subsequent rasqal API calls.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_world_open(rasqal_world *world)
+{
+ int rc;
+
+ if(!world)
+ return -1;
+
+ if(world->opened)
+ return 0; /* not an error */
+
+#ifdef RAPTOR_V2_AVAILABLE
+ /* Create and init a raptor_world unless one is provided externally with rasqal_world_set_raptor() */
+ if(!world->raptor_world_ptr) {
+ world->raptor_world_ptr = raptor_new_world();
+ if(!world->raptor_world_ptr)
+ return -1;
+ world->raptor_world_allocated_here = 1;
+ rc = raptor_world_open(world->raptor_world_ptr);
+ if(rc)
+ return rc;
+ }
+#else
+ raptor_init();
+#endif
+
+ rc = rasqal_uri_init(world);
+ if(rc)
+ return rc;
+
+ rc = rasqal_xsd_init(world);
+ if(rc)
+ return rc;
+
+/* FIXME */
+#ifndef RAPTOR_ERROR_HANDLER_MAGIC
+#define RAPTOR_ERROR_HANDLER_MAGIC 0xD00DB1FF
+#endif
+ world->error_handlers.magic=RAPTOR_ERROR_HANDLER_MAGIC;
+
+ /* last one declared is the default - RDQL */
+
+#ifdef RASQAL_QUERY_RDQL
+ rc = rasqal_init_query_language_rdql(world);
+ if(rc)
+ return rc;
+#endif
+
+#ifdef RASQAL_QUERY_LAQRS
+ rc = rasqal_init_query_language_laqrs(world);
+ if(rc)
+ return rc;
+#endif
+
+#ifdef RASQAL_QUERY_SPARQL
+ rc = rasqal_init_query_language_sparql(world);
+ if(rc)
+ return rc;
+#endif
+
+#ifdef RAPTOR_TRIPLES_SOURCE_RAPTOR
+ rc = rasqal_raptor_init(world);
+ if(rc)
+ return rc;
+#endif
+#ifdef RAPTOR_TRIPLES_SOURCE_REDLAND
+ rc = rasqal_redland_init(world);
+ if(rc)
+ return rc;
+#endif
+
+ rc = rasqal_init_query_results();
+ if(rc)
+ return rc;
+
+ rc = rasqal_init_result_formats(world);
+ if(rc)
+ return rc;
+
+ world->opened = 1;
+
+ return 0;
+}
+
+
+/**
+ * rasqal_free_world:
+ * @world: rasqal_world object
+ *
+ * Terminate the rasqal library.
+ *
+ * Destroys a rasqal_world object and all static information.
+ *
+ **/
+void
+rasqal_free_world(rasqal_world* world)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(world, rasqal_world);
+
+ rasqal_finish_result_formats(world);
+ rasqal_finish_query_results();
+
+ rasqal_delete_query_language_factories(world);
+
+#ifdef RAPTOR_TRIPLES_SOURCE_REDLAND
+ rasqal_redland_finish();
+#endif
+
+ rasqal_xsd_finish(world);
+
+ rasqal_uri_finish(world);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ if(world->raptor_world_ptr && world->raptor_world_allocated_here)
+ raptor_free_world(world->raptor_world_ptr);
+#else
+ raptor_finish();
+#endif
+
+ RASQAL_FREE(rasqal_world, world);
+}
+
+
+/**
+ * rasqal_world_set_raptor:
+ * @world: rasqal_world object
+ * @raptor_world_ptr: raptor_world object
+ *
+ * Set the #raptor_world instance to be used with this #rasqal_world.
+ *
+ * If no raptor_world instance is set with this function,
+ * rasqal_world_open() creates a new instance.
+ *
+ * Ownership of the raptor_world is not taken. If the raptor library
+ * instance is set with this function, rasqal_free_world() will not
+ * free it.
+ *
+ **/
+void
+rasqal_world_set_raptor(rasqal_world* world, raptor_world* raptor_world_ptr)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(world, rasqal_world);
+ world->raptor_world_ptr = raptor_world_ptr;
+}
+
+
+/**
+ * rasqal_world_get_raptor:
+ * @world: rasqal_world object
+ *
+ * Get the #raptor_world instance used by this #rasqal_world.
+ *
+ * Return value: raptor_world object or NULL on failure (e.g. not initialized)
+ **/
+raptor_world*
+rasqal_world_get_raptor(rasqal_world* world)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(world, rasqal_world, NULL);
+ return world->raptor_world_ptr;
+}
+
+
+/* helper functions */
+
+/*
+ * rasqal_free_query_language_factory - delete a query language factory
+ */
+static void
+rasqal_free_query_language_factory(rasqal_query_language_factory *factory)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(factory, rasqal_query_language_factory);
+
+ if(factory) {
+ if(factory->finish_factory)
+ factory->finish_factory(factory);
+
+ if(factory->name)
+ RASQAL_FREE(rasqal_query_language_factory, (void*)factory->name);
+ if(factory->label)
+ RASQAL_FREE(rasqal_query_language_factory, (void*)factory->label);
+ if(factory->alias)
+ RASQAL_FREE(rasqal_query_language_factory, (void*)factory->alias);
+ if(factory->uri_string)
+ RASQAL_FREE(rasqal_query_language_factory, (void*)factory->uri_string);
+
+ RASQAL_FREE(rasqal_query_language_factory, factory);
+ }
+}
+
+
+/*
+ * rasqal_delete_query_language_factories - helper function to delete all the registered query language factories
+ */
+static void
+rasqal_delete_query_language_factories(rasqal_world *world)
+{
+ rasqal_query_language_factory *factory, *next;
+
+ for(factory=world->query_languages; factory; factory=next) {
+ next=factory->next;
+ rasqal_free_query_language_factory(factory);
+ }
+ world->query_languages=NULL;
+}
+
+
+/* class methods */
+
+/*
+ * rasqal_query_language_register_factory - Register a syntax handled by a query factory
+ * @name: the short syntax name
+ * @label: readable label for syntax
+ * @uri_string: URI string of the syntax (or NULL)
+ * @factory: pointer to function to call to register the factory
+ *
+ * INTERNAL
+ *
+ * Return value: non-0 on failure
+ **/
+RASQAL_EXTERN_C
+int
+rasqal_query_language_register_factory(rasqal_world *world,
+ const char *name, const char *label,
+ const char *alias,
+ const unsigned char *uri_string,
+ void (*factory) (rasqal_query_language_factory*))
+{
+ rasqal_query_language_factory *query, *h;
+ char *name_copy, *label_copy, *alias_copy;
+ unsigned char *uri_string_copy;
+
+#if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
+ RASQAL_DEBUG4("Received registration for syntax %s '%s' with alias '%s'\n",
+ name, label, (alias ? alias : "none"));
+ RASQAL_DEBUG2("URI %s\n", (uri_string ? (const char*)uri_string : (const char*)"none"));
+#endif
+
+ query=(rasqal_query_language_factory*)RASQAL_CALLOC(rasqal_query_language_factory, 1,
+ sizeof(rasqal_query_language_factory));
+ if(!query)
+ goto tidy_noquery;
+
+ for(h = world->query_languages; h; h = h->next ) {
+ if(!strcmp(h->name, name) ||
+ (alias && !strcmp(h->name, alias))) {
+ RASQAL_FATAL2("query %s already registered\n", h->name);
+ }
+ }
+
+ name_copy=(char*)RASQAL_CALLOC(cstring, strlen(name)+1, 1);
+ if(!name_copy)
+ goto tidy;
+ strcpy(name_copy, name);
+ query->name=name_copy;
+
+ label_copy=(char*)RASQAL_CALLOC(cstring, strlen(label)+1, 1);
+ if(!label_copy)
+ goto tidy;
+ strcpy(label_copy, label);
+ query->label=label_copy;
+
+ if(uri_string) {
+ uri_string_copy=(unsigned char*)RASQAL_CALLOC(cstring, strlen((const char*)uri_string)+1, 1);
+ if(!uri_string_copy)
+ goto tidy;
+ strcpy((char*)uri_string_copy, (const char*)uri_string);
+ query->uri_string=uri_string_copy;
+ }
+
+ if(alias) {
+ alias_copy=(char*)RASQAL_CALLOC(cstring, strlen(alias)+1, 1);
+ if(!alias_copy)
+ goto tidy;
+ strcpy(alias_copy, alias);
+ query->alias=alias_copy;
+ }
+
+ /* Call the query registration function on the new object */
+ (*factory)(query);
+
+#if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("%s has context size %d\n", name, (int)query->context_length);
+#endif
+
+ query->next = world->query_languages;
+ world->query_languages = query;
+
+ return 0;
+
+ tidy:
+ rasqal_free_query_language_factory(query);
+ tidy_noquery:
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_FATAL, NULL,
+ "Out of memory in rasqal_query_language_register_factory()");
+ return 1;
+}
+
+
+/**
+ * rasqal_get_query_language_factory:
+ * @name: the factory name or NULL for the default factory
+ * @uri: the query syntax URI or NULL
+ *
+ * Get a query factory by name.
+ *
+ * Return value: the factory object or NULL if there is no such factory
+ **/
+rasqal_query_language_factory*
+rasqal_get_query_language_factory(rasqal_world *world, const char *name,
+ const unsigned char *uri)
+{
+ rasqal_query_language_factory *factory;
+
+ /* return 1st query if no particular one wanted - why? */
+ if(!name && !uri) {
+ factory=world->query_languages;
+ if(!factory) {
+ RASQAL_DEBUG1("No (default) query_languages registered\n");
+ return NULL;
+ }
+ } else {
+ for(factory=world->query_languages; factory; factory=factory->next) {
+ if((name && !strcmp(factory->name, name)) ||
+ (factory->alias && !strcmp(factory->alias, name)))
+ break;
+ if(uri && !strcmp((const char*)factory->uri_string, (const char*)uri))
+ break;
+ }
+ /* else FACTORY name not found */
+ if(!factory) {
+ RASQAL_DEBUG2("No query language with name %s found\n", name);
+ return NULL;
+ }
+ }
+
+ return factory;
+}
+
+
+/**
+ * rasqal_languages_enumerate:
+ * @world: rasqal_world object
+ * @counter: index into the list of syntaxes
+ * @name: pointer to store the name of the syntax (or NULL)
+ * @label: pointer to store syntax readable label (or NULL)
+ * @uri_string: pointer to store syntax URI string (or NULL)
+ *
+ * Get information on query languages.
+ *
+ * Return value: non 0 on failure of if counter is out of range
+ **/
+int
+rasqal_languages_enumerate(rasqal_world *world,
+ unsigned int counter,
+ const char **name, const char **label,
+ const unsigned char **uri_string)
+{
+ unsigned int i;
+ rasqal_query_language_factory *factory=world->query_languages;
+
+ if(!factory)
+ return 1;
+
+ for(i=0; factory && i<=counter ; i++, factory=factory->next) {
+ if(i == counter) {
+ if(name)
+ *name=factory->name;
+ if(label)
+ *label=factory->label;
+ if(uri_string)
+ *uri_string=factory->uri_string;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+/**
+ * rasqal_language_name_check:
+ * @world: rasqal_world object
+ * @name: the query language name
+ *
+ * Check name of a query language.
+ *
+ * Return value: non 0 if name is a known query language
+ */
+int
+rasqal_language_name_check(rasqal_world* world, const char *name) {
+ return (rasqal_get_query_language_factory(world, name, NULL) != NULL);
+}
+
+
+static const char* const rasqal_log_level_labels[RAPTOR_LOG_LEVEL_LAST+1]={
+ "none",
+ "fatal error",
+ "error",
+ "warning"
+};
+
+
+/* internal */
+void
+rasqal_log_error_simple(rasqal_world* world, raptor_log_level level,
+ raptor_locator* locator, const char* message, ...)
+{
+ va_list arguments;
+
+ if(level == RAPTOR_LOG_LEVEL_NONE)
+ return;
+
+ va_start(arguments, message);
+ rasqal_log_error_varargs(world, level, locator, message, arguments);
+ va_end(arguments);
+}
+
+
+void
+rasqal_log_error_varargs(rasqal_world* world, raptor_log_level level,
+ raptor_locator* locator,
+ const char* message, va_list arguments)
+{
+ char *buffer;
+ size_t length;
+ raptor_message_handler handler=world->error_handlers.handlers[level].handler;
+ void* handler_data=world->error_handlers.handlers[level].user_data;
+
+ if(level == RAPTOR_LOG_LEVEL_NONE)
+ return;
+
+ buffer=raptor_vsnprintf(message, arguments);
+ if(!buffer) {
+ if(locator) {
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_print_locator_v2(world->raptor_world_ptr, stderr, locator);
+#else
+ raptor_print_locator(stderr, locator);
+#endif
+ fputc(' ', stderr);
+ }
+ fputs("rasqal ", stderr);
+ fputs(rasqal_log_level_labels[level], stderr);
+ fputs(" - ", stderr);
+ vfprintf(stderr, message, arguments);
+ fputc('\n', stderr);
+ return;
+ }
+
+ length=strlen(buffer);
+ if(buffer[length-1]=='\n')
+ buffer[length-1]='\0';
+
+ if(handler)
+ /* This is the single place in rasqal that the user error handler
+ * functions are called.
+ */
+ handler(handler_data, locator, buffer);
+ else {
+ if(locator) {
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_print_locator_v2(world->raptor_world_ptr, stderr, locator);
+#else
+ raptor_print_locator(stderr, locator);
+#endif
+ fputc(' ', stderr);
+ }
+ fputs("rasqal ", stderr);
+ fputs(rasqal_log_level_labels[level], stderr);
+ fputs(" - ", stderr);
+ fputs(buffer, stderr);
+ fputc('\n', stderr);
+ }
+
+ RASQAL_FREE(cstring, buffer);
+}
+
+
+/*
+ * rasqal_query_simple_error - Error from a query - Internal
+ *
+ * Matches the raptor_simple_message_handler API but same as
+ * rasqal_query_error
+ */
+void
+rasqal_query_simple_error(void* user_data, const char *message, ...)
+{
+ rasqal_query* query=(rasqal_query*)user_data;
+
+ va_list arguments;
+
+ va_start(arguments, message);
+
+ query->failed=1;
+ rasqal_log_error_varargs(query->world,
+ RAPTOR_LOG_LEVEL_ERROR, NULL,
+ message, arguments);
+
+ va_end(arguments);
+}
+
+
+/* wrapper */
+const char*
+rasqal_basename(const char *name)
+{
+ char *p;
+ if((p=strrchr(name, '/')))
+ name=p+1;
+ else if((p=strrchr(name, '\\')))
+ name=p+1;
+
+ return name;
+}
+
+
+/**
+ * rasqal_escaped_name_to_utf8_string:
+ * @src: source name string
+ * @len: length of source name string
+ * @dest_lenp: pointer to store result string (or NULL)
+ * @error_handler: error handling function
+ * @error_data: data for error handle
+ *
+ * Get a UTF-8 and/or \u-escaped name as UTF-8.
+ *
+ * If dest_lenp is not NULL, the length of the resulting string is
+ * stored at the pointed size_t.
+ *
+ * Return value: new UTF-8 string or NULL on failure.
+ */
+unsigned char*
+rasqal_escaped_name_to_utf8_string(const unsigned char *src, size_t len,
+ size_t *dest_lenp,
+ raptor_simple_message_handler error_handler,
+ void *error_data)
+{
+ const unsigned char *p=src;
+ size_t ulen=0;
+ unsigned long unichar=0;
+ unsigned char *result;
+ unsigned char *dest;
+ int n;
+
+ result=(unsigned char*)RASQAL_MALLOC(cstring, len+1);
+ if(!result)
+ return NULL;
+
+ dest=result;
+
+ /* find end of string, fixing backslashed characters on the way */
+ while(len > 0) {
+ unsigned char c=*p;
+
+ if(c > 0x7f) {
+ /* just copy the UTF-8 bytes through */
+ size_t unichar_len=raptor_utf8_to_unicode_char(NULL, (const unsigned char*)p, len+1);
+ if(unichar_len > len) {
+ if(error_handler)
+ error_handler(error_data, "UTF-8 encoding error at character %d (0x%02X) found.", c, c);
+ /* UTF-8 encoding had an error or ended in the middle of a string */
+ RASQAL_FREE(cstring, result);
+ return NULL;
+ }
+ memcpy(dest, p, unichar_len);
+ dest+= unichar_len;
+ p += unichar_len;
+ len -= unichar_len;
+ continue;
+ }
+
+ p++; len--;
+
+ if(c != '\\') {
+ /* not an escape - store and move on */
+ *dest++=c;
+ continue;
+ }
+
+ if(!len) {
+ RASQAL_FREE(cstring, result);
+ return NULL;
+ }
+
+ c = *p++; len--;
+
+ switch(c) {
+ case '"':
+ case '\\':
+ *dest++=c;
+ break;
+ case 'u':
+ case 'U':
+ ulen=(c == 'u') ? 4 : 8;
+
+ if(len < ulen) {
+ if(error_handler)
+ error_handler(error_data, "%c over end of line", c);
+ RASQAL_FREE(cstring, result);
+ return 0;
+ }
+
+ n=sscanf((const char*)p, ((ulen == 4) ? "%04lx" : "%08lx"), &unichar);
+ if(n != 1) {
+ if(error_handler)
+ error_handler(error_data, "Bad %c escape", c);
+ break;
+ }
+
+ p+=ulen;
+ len-=ulen;
+
+ if(unichar > 0x10ffff) {
+ if(error_handler)
+ error_handler(error_data, "Illegal Unicode character with code point #x%lX.", unichar);
+ break;
+ }
+
+ dest+=raptor_unicode_char_to_utf8(unichar, dest);
+ break;
+
+ default:
+ if(error_handler)
+ error_handler(error_data, "Illegal string escape \\%c in \"%s\"", c, src);
+ RASQAL_FREE(cstring, result);
+ return 0;
+ }
+
+ } /* end while */
+
+
+ /* terminate dest, can be shorter than source */
+ *dest='\0';
+
+ if(dest_lenp)
+ *dest_lenp=dest-result;
+
+ return result;
+}
+
+
+int
+rasqal_uri_init(rasqal_world* world)
+{
+#ifdef RAPTOR_V2_AVAILABLE
+ world->rdf_namespace_uri = raptor_new_uri_v2(world->raptor_world_ptr, raptor_rdf_namespace_uri);
+#else
+ world->rdf_namespace_uri = raptor_new_uri(raptor_rdf_namespace_uri);
+#endif
+ if(!world->rdf_namespace_uri)
+ goto oom;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ world->rdf_first_uri = raptor_new_uri_from_uri_local_name_v2(world->raptor_world_ptr, world->rdf_namespace_uri, (const unsigned char*)"first");
+ world->rdf_rest_uri = raptor_new_uri_from_uri_local_name_v2(world->raptor_world_ptr, world->rdf_namespace_uri, (const unsigned char*)"rest");
+ world->rdf_nil_uri = raptor_new_uri_from_uri_local_name_v2(world->raptor_world_ptr, world->rdf_namespace_uri, (const unsigned char*)"nil");
+#else
+ world->rdf_first_uri = raptor_new_uri_from_uri_local_name(world->rdf_namespace_uri, (const unsigned char*)"first");
+ world->rdf_rest_uri = raptor_new_uri_from_uri_local_name(world->rdf_namespace_uri, (const unsigned char*)"rest");
+ world->rdf_nil_uri = raptor_new_uri_from_uri_local_name(world->rdf_namespace_uri, (const unsigned char*)"nil");
+#endif
+
+ if(!world->rdf_first_uri || !world->rdf_rest_uri || !world->rdf_nil_uri)
+ goto oom;
+
+ return 0;
+
+ oom:
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_FATAL,
+ NULL,
+ "Out of memory");
+ return 1;
+}
+
+
+void
+rasqal_uri_finish(rasqal_world* world)
+{
+#ifdef RAPTOR_V2_AVAILABLE
+ if(world->rdf_first_uri) {
+ raptor_free_uri_v2(world->raptor_world_ptr, world->rdf_first_uri);
+ world->rdf_first_uri = NULL;
+ }
+ if(world->rdf_rest_uri) {
+ raptor_free_uri_v2(world->raptor_world_ptr, world->rdf_rest_uri);
+ world->rdf_rest_uri = NULL;
+ }
+ if(world->rdf_nil_uri) {
+ raptor_free_uri_v2(world->raptor_world_ptr, world->rdf_nil_uri);
+ world->rdf_nil_uri = NULL;
+ }
+ if(world->rdf_namespace_uri) {
+ raptor_free_uri_v2(world->raptor_world_ptr, world->rdf_namespace_uri);
+ world->rdf_namespace_uri = NULL;
+ }
+#else
+ if(world->rdf_first_uri) {
+ raptor_free_uri(world->rdf_first_uri);
+ world->rdf_first_uri=NULL;
+ }
+ if(world->rdf_rest_uri) {
+ raptor_free_uri(world->rdf_rest_uri);
+ world->rdf_rest_uri=NULL;
+ }
+ if(world->rdf_nil_uri) {
+ raptor_free_uri(world->rdf_nil_uri);
+ world->rdf_nil_uri=NULL;
+ }
+ if(world->rdf_namespace_uri) {
+ raptor_free_uri(world->rdf_namespace_uri);
+ world->rdf_namespace_uri=NULL;
+ }
+#endif
+}
+
+
+/**
+ * rasqal_query_set_default_generate_bnodeid_parameters - Set default bnodeid generation parameters
+ * @rdf_query: #rasqal_query object
+ * @prefix: prefix string
+ * @base: integer base identifier
+ *
+ * Sets the parameters for the default algorithm used to generate
+ * blank node IDs. The default algorithm uses both @prefix and @base
+ * to generate a new identifier. The exact identifier generated is
+ * not guaranteed to be a strict concatenation of @prefix and @base
+ * but will use both parts.
+ *
+ * For finer control of the generated identifiers, use
+ * rasqal_set_default_generate_bnodeid_handler()
+ *
+ * If prefix is NULL, the default prefix is used (currently "bnodeid")
+ * If base is less than 1, it is initialised to 1.
+ *
+ **/
+void
+rasqal_query_set_default_generate_bnodeid_parameters(rasqal_query* rdf_query,
+ char *prefix, int base)
+{
+ char *prefix_copy=NULL;
+ size_t length=0;
+
+ if(--base<0)
+ base=0;
+
+ if(prefix) {
+ length=strlen(prefix);
+
+ prefix_copy=(char*)RASQAL_MALLOC(cstring, length+1);
+ if(!prefix_copy)
+ return;
+ strcpy(prefix_copy, prefix);
+ }
+
+ if(rdf_query->default_generate_bnodeid_handler_prefix)
+ RASQAL_FREE(cstring, rdf_query->default_generate_bnodeid_handler_prefix);
+
+ rdf_query->default_generate_bnodeid_handler_prefix=prefix_copy;
+ rdf_query->default_generate_bnodeid_handler_prefix_length=length;
+ rdf_query->default_generate_bnodeid_handler_base=base;
+}
+
+
+/**
+ * rasqal_query_set_generate_bnodeid_handler:
+ * @query: #rasqal_query query object
+ * @user_data: user data pointer for callback
+ * @handler: generate blank ID callback function
+ *
+ * Set the generate blank node ID handler function for the query.
+ *
+ * Sets the function to generate blank node IDs for the query.
+ * The handler is called with a pointer to the rasqal_query, the
+ * @user_data pointer and a user_bnodeid which is the value of
+ * a user-provided blank node identifier (may be NULL).
+ * It can either be returned directly as the generated value when present or
+ * modified. The passed in value must be free()d if it is not used.
+ *
+ * If handler is NULL, the default method is used
+ *
+ **/
+void
+rasqal_query_set_generate_bnodeid_handler(rasqal_query* query,
+ void *user_data,
+ rasqal_generate_bnodeid_handler handler)
+{
+ query->generate_bnodeid_handler_user_data=user_data;
+ query->generate_bnodeid_handler=handler;
+}
+
+
+static unsigned char*
+rasqal_default_generate_bnodeid_handler(void *user_data,
+ unsigned char *user_bnodeid)
+{
+ rasqal_query *rdf_query=(rasqal_query *)user_data;
+ int id;
+ unsigned char *buffer;
+ int length;
+ int tmpid;
+
+ if(user_bnodeid)
+ return user_bnodeid;
+
+ id=++rdf_query->default_generate_bnodeid_handler_base;
+
+ tmpid=id;
+ length=2; /* min length 1 + \0 */
+ while(tmpid/=10)
+ length++;
+
+ if(rdf_query->default_generate_bnodeid_handler_prefix)
+ length += rdf_query->default_generate_bnodeid_handler_prefix_length;
+ else
+ length += 7; /* bnodeid */
+
+ buffer=(unsigned char*)RASQAL_MALLOC(cstring, length);
+ if(!buffer)
+ return NULL;
+ if(rdf_query->default_generate_bnodeid_handler_prefix) {
+ strncpy((char*)buffer, rdf_query->default_generate_bnodeid_handler_prefix,
+ rdf_query->default_generate_bnodeid_handler_prefix_length);
+ sprintf((char*)buffer + rdf_query->default_generate_bnodeid_handler_prefix_length,
+ "%d", id);
+ } else
+ sprintf((char*)buffer, "bnodeid%d", id);
+
+ return buffer;
+}
+
+
+/*
+ * rasqal_query_generate_bnodeid - Default generate id - internal
+ */
+unsigned char*
+rasqal_query_generate_bnodeid(rasqal_query* rdf_query,
+ unsigned char *user_bnodeid)
+{
+ if(rdf_query->generate_bnodeid_handler)
+ return rdf_query->generate_bnodeid_handler(rdf_query,
+ rdf_query->generate_bnodeid_handler_user_data, user_bnodeid);
+ else
+ return rasqal_default_generate_bnodeid_handler(rdf_query, user_bnodeid);
+}
+
+
+
+
+/**
+ * rasqal_free_memory:
+ * @ptr: memory pointer
+ *
+ * Free memory allocated inside rasqal.
+ *
+ * Some systems require memory allocated in a library to
+ * be deallocated in that library. This function allows
+ * memory allocated by rasqal to be freed.
+ *
+ **/
+void
+rasqal_free_memory(void *ptr)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(ptr, memory);
+
+ RASQAL_FREE(void, ptr);
+}
+
+
+/**
+ * rasqal_alloc_memory:
+ * @size: size of memory to allocate
+ *
+ * Allocate memory inside rasqal.
+ *
+ * Some systems require memory allocated in a library to
+ * be deallocated in that library. This function allows
+ * memory to be allocated inside the rasqal shared library
+ * that can be freed inside rasqal either internally or via
+ * rasqal_free_memory().
+ *
+ * Return value: the address of the allocated memory or NULL on failure
+ *
+ **/
+void*
+rasqal_alloc_memory(size_t size)
+{
+ return RASQAL_MALLOC(void, size);
+}
+
+
+/**
+ * rasqal_calloc_memory:
+ * @nmemb: number of members
+ * @size: size of item
+ *
+ * Allocate zeroed array of items inside rasqal.
+ *
+ * Some systems require memory allocated in a library to
+ * be deallocated in that library. This function allows
+ * memory to be allocated inside the rasqal shared library
+ * that can be freed inside rasqal either internally or via
+ * rasqal_free_memory().
+ *
+ * Return value: the address of the allocated memory or NULL on failure
+ *
+ **/
+void*
+rasqal_calloc_memory(size_t nmemb, size_t size)
+{
+ return RASQAL_CALLOC(void, nmemb, size);
+}
+
+
+#if defined (RASQAL_DEBUG) && defined(RASQAL_MEMORY_SIGN)
+void*
+rasqal_sign_malloc(size_t size)
+{
+ int *p;
+
+ size += sizeof(int);
+
+ p=(int*)malloc(size);
+ *p++ = RASQAL_SIGN_KEY;
+ return p;
+}
+
+void*
+rasqal_sign_calloc(size_t nmemb, size_t size)
+{
+ int *p;
+
+ /* turn into bytes */
+ size = nmemb*size + sizeof(int);
+
+ p=(int*)calloc(1, size);
+ *p++ = RASQAL_SIGN_KEY;
+ return p;
+}
+
+void*
+rasqal_sign_realloc(void *ptr, size_t size)
+{
+ int *p;
+
+ if(!ptr)
+ return rasqal_sign_malloc(size);
+
+ p=(int*)ptr;
+ p--;
+
+ if(*p != RASQAL_SIGN_KEY)
+ RASQAL_FATAL3("memory signature %08X != %08X", *p, RASQAL_SIGN_KEY);
+
+ size += sizeof(int);
+
+ p=(int*)realloc(p, size);
+ *p++= RASQAL_SIGN_KEY;
+ return p;
+}
+
+void
+rasqal_sign_free(void *ptr)
+{
+ int *p;
+
+ if(!ptr)
+ return;
+
+ p=(int*)ptr;
+ p--;
+
+ if(*p != RASQAL_SIGN_KEY)
+ RASQAL_FATAL3("memory signature %08X != %08X", *p, RASQAL_SIGN_KEY);
+
+ free(p);
+}
+#endif
+
+
+#if defined (RASQAL_DEBUG) && defined(HAVE_DMALLOC_H) && defined(RASQAL_MEMORY_DEBUG_DMALLOC)
+
+#undef malloc
+void*
+rasqal_system_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+#undef free
+void
+rasqal_system_free(void *ptr)
+{
+ return free(ptr);
+
+}
+
+#endif
+
diff --git a/src/rasqal/rasqal_graph.c b/src/rasqal/rasqal_graph.c
new file mode 100644
index 0000000..6f7d1aa
--- /dev/null
+++ b/src/rasqal/rasqal_graph.c
@@ -0,0 +1,459 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_graph.c - Rasqal Graph API
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+typedef struct
+{
+ int usage;
+ rasqal_world *world;
+ raptor_uri *uri;
+ void *user_data;
+} rasqal_graph;
+
+typedef struct
+{
+ rasqal_world *world;
+ rasqal_graph *graph;
+ void *user_data;
+} rasqal_graph_match;
+
+typedef struct
+{
+ rasqal_world *world;
+ rasqal_graph *graph;
+ void *user_data;
+} rasqal_graph_bindings;
+
+
+struct rasqal_graph_factory_s
+{
+ int version; /* API version */
+
+ /* One-time initialisation/termination of graph factory (optional) */
+ void* (*init_factory)(rasqal_world* world);
+ void (*terminate_factory)(void *graph_factory_user_data);
+
+ /* Dataset API (required)
+ *
+ * Manage a set of RDF graphs
+ */
+ /* list dataset graphs */
+ raptor_uri* (*dataset_enumerate)(void *graph_factory_user_data, int offset);
+ /* load dataset with a graph via URI */
+ int (*dataset_load)(void *graph_factory_user_data, raptor_uri* uri);
+
+ /* RDF Graph API (required)
+ *
+ * (acts like librdf_model)
+ */
+ void *(*new_graph)(rasqal_world* world, raptor_uri* uri);
+ void (*free_graph)(void *graph_user_data);
+ /* Check for presence of a triple (NOT triple pattern) in a graph (required)
+ * (acts like librdf_model_contains_statement)
+ */
+ int (*graph_triple_present)(void *graph_user_data, rasqal_triple *triple);
+
+ /* Triple pattern matching API (required)
+ *
+ * Find triples matching a triple pattern
+ * (acts like librdf_model_find_statements returning a librdf_stream of
+ * librdf_statement)
+ */
+ void* (*new_graph_match)(rasqal_graph *graph, rasqal_triple *triple);
+ rasqal_triple* (*graph_match_get_triple)(void *match_user_data);
+ void (*free_graph_match)(void *match_user_data);
+
+ /* Graph pattern binding API (optional)
+ *
+ * Bind variables when triples in the graph match a graph pattern
+ */
+ void* (*new_graph_bindings)(rasqal_graph *graph, rasqal_triple **triples, int triples_count, rasqal_expression *filter);
+ int (*graph_bindings_bind)(void *graph_bindings_user_data);
+ void (*free_graph_bindings)(void *graph_bindings_user_data);
+};
+
+
+/* prototypes */
+int rasqal_init_graph_factory(rasqal_world *world, rasqal_graph_factory *factory);
+void rasqal_free_graph_factory(rasqal_world *world);
+int rasqal_dataset_graph_present(rasqal_world* world, raptor_uri* uri);
+raptor_uri* rasqal_dataset_enumerate(rasqal_world* world, int offset);
+int rasqal_dataset_graph_load(rasqal_world* world, raptor_uri* uri);
+rasqal_graph* rasqal_new_graph(rasqal_world* world, raptor_uri *uri);
+void rasqal_free_graph(rasqal_graph *graph);
+int rasqal_graph_triple_present(rasqal_graph *graph, rasqal_triple *triple);
+rasqal_graph_match* rasqal_new_graph_match(rasqal_graph *graph, rasqal_triple *triple);
+void rasqal_free_graph_match(rasqal_graph_match *match);
+rasqal_triple* rasqal_graph_match_get_triple(rasqal_graph_match *match);
+rasqal_graph_bindings* rasqal_new_graph_bindings(rasqal_graph *graph, rasqal_triple **triples, int triples_count, rasqal_expression *filter);
+void rasqal_free_graph_bindings(rasqal_graph_bindings *graph_bindings);
+int rasqal_graph_bindings_bind(rasqal_graph_bindings *graph_bindings);
+
+
+/**
+ * rasqal_init_graph_factory:
+ * @world: rasqal world
+ * @factory: factory
+ *
+ * Set graph matching factory for rasqal world.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_init_graph_factory(rasqal_world *world,
+ rasqal_graph_factory *factory)
+{
+ if(world->graph_factory)
+ rasqal_free_graph_factory(world);
+
+ world->graph_factory = factory;
+
+ if(factory->init_factory) {
+ world->graph_factory_user_data = factory->init_factory(world);
+ return (world->graph_factory_user_data == NULL);
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_free_graph_factory:
+ * @world: rasqal world
+ *
+ * Free any resources attached to the graph factory
+ */
+void
+rasqal_free_graph_factory(rasqal_world *world)
+{
+ rasqal_graph_factory *factory = world->graph_factory;
+
+ if(factory->terminate_factory)
+ factory->terminate_factory(world->graph_factory_user_data);
+}
+
+
+/**
+ * rasqal_dataset_enumerate:
+ * @world: rasqal world
+ * @offset: offset
+ *
+ * Get the URIs of the graphs in the dataset
+ *
+ * Return value: URI or NULL if offset is out of rangek
+ **/
+raptor_uri*
+rasqal_dataset_enumerate(rasqal_world* world, int offset)
+{
+ rasqal_graph_factory *factory = world->graph_factory;
+
+ return factory->dataset_enumerate(world->graph_factory_user_data, offset);
+}
+
+
+/**
+ * rasqal_dataset_graph_present:
+ * @world: rasqal world
+ * @uri: graph URI
+ *
+ * Check if a graph is in the dataset
+ *
+ * Return value: non-0 if the graph is present
+ **/
+int
+rasqal_dataset_graph_present(rasqal_world* world, raptor_uri* uri)
+{
+ int offset = 0;
+
+ while(1) {
+ raptor_uri *graph_uri;
+
+ graph_uri = rasqal_dataset_enumerate(world, offset++);
+ if(!graph_uri)
+ break;
+
+ if(raptor_uri_equals(uri, graph_uri))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_dataset_graph_load:
+ * @world: rasqal world
+ * @uri: graph URI to load
+ *
+ * Load graph into daaset
+ *
+ * Return value: graph API object or NULL on failure
+ **/
+int
+rasqal_dataset_graph_load(rasqal_world* world, raptor_uri* uri)
+{
+ rasqal_graph_factory *factory = world->graph_factory;
+
+ return factory->dataset_load(world->graph_factory_user_data, uri);
+}
+
+
+/**
+ * rasqal_new_graph:
+ * @world: rasqal world
+ * @uri: graph URI (or NULL for default graph)
+ *
+ * Constructor - Create a new graph API for a given URI
+ *
+ * Returns: graph API object or NULL on failure
+ **/
+rasqal_graph*
+rasqal_new_graph(rasqal_world* world, raptor_uri *uri)
+{
+ rasqal_graph* g;
+ rasqal_graph_factory *factory = world->graph_factory;
+
+ g = (rasqal_graph*)RASQAL_CALLOC(rasqal_graph, sizeof(rasqal_graph), 1);
+ if(!g)
+ return NULL;
+ g->world = world;
+ g->user_data = factory->new_graph(world, uri);
+ if(!g->user_data) {
+ RASQAL_FREE(rasqal_graph, g);
+ return NULL;
+ }
+
+ g->usage = 1;
+ return g;
+}
+
+
+/**
+ * rasqal_free_graph:
+ * @graph: graph API object
+ *
+ * Destructor - Destroy a graph API object
+ *
+ **/
+void
+rasqal_free_graph(rasqal_graph *graph)
+{
+ rasqal_graph_factory *factory = graph->world->graph_factory;
+
+ if(graph->usage--)
+ return;
+
+ if(factory->free_graph)
+ factory->free_graph(graph->user_data);
+ RASQAL_FREE(rasqal_graph, graph);
+}
+
+
+/**
+ * rasqal_new_graph_from_graph:
+ * @graph: graph API object
+ *
+ * Copy constructor
+ *
+ * Return value: new graph object
+ */
+static rasqal_graph*
+rasqal_new_graph_from_graph(rasqal_graph *graph)
+{
+ graph->usage++;
+
+ return graph;
+}
+
+
+/**
+ * rasqal_graph_triple_present:
+ * @graph: graph API object
+ * @triple: triple
+ *
+ * Test if a triple is in a graph
+ *
+ * Return value: non-0 if triple is present
+ */
+int
+rasqal_graph_triple_present(rasqal_graph *graph, rasqal_triple *triple)
+{
+ rasqal_graph_factory *factory = graph->world->graph_factory;
+
+ return factory->graph_triple_present(graph->user_data, triple);
+}
+
+
+/**
+ * rasqal_new_graph_match:
+ * @graph: graph API object
+ * @triple: triple pattern
+ *
+ * Constructor - create a new triple pattern matcher for a triple pattern
+ *
+ * Returns: triple pattern matcher or NULL on failure
+ **/
+rasqal_graph_match*
+rasqal_new_graph_match(rasqal_graph *graph, rasqal_triple *triple)
+{
+ rasqal_graph_match* gm;
+ rasqal_graph_factory *factory = graph->world->graph_factory;
+
+ gm = (rasqal_graph_match*)RASQAL_CALLOC(rasqal_graph_match,
+ sizeof(rasqal_graph_match), 1);
+ if(!gm)
+ return NULL;
+
+ gm->graph = rasqal_new_graph_from_graph(graph);
+ gm->user_data = factory->new_graph_match(graph, triple);
+ if(!gm->user_data) {
+ RASQAL_FREE(graph_match, gm);
+ return NULL;
+ }
+
+ return gm;
+}
+
+
+/**
+ * rasqal_free_graph_match:
+ * @match: triple pattern matcher object
+ *
+ * Destructor - Delete a triple pattern matcher
+ **/
+void
+rasqal_free_graph_match(rasqal_graph_match *match)
+{
+ rasqal_graph_factory *factory = match->world->graph_factory;
+
+ rasqal_free_graph(match->graph);
+
+ if(factory->free_graph_match)
+ factory->free_graph_match(match->user_data);
+ RASQAL_FREE(rasqal_graph_match, match);
+}
+
+
+/**
+ * rasqal_graph_match_get_triple:
+ * @match: triple pattern matcher object
+ *
+ * Get the next triple from a triple pattern matcher
+ *
+ * Returns: new triple object or NULL when no (more) triples match
+ **/
+rasqal_triple*
+rasqal_graph_match_get_triple(rasqal_graph_match *match)
+{
+ rasqal_graph_factory *factory = match->world->graph_factory;
+
+ return factory->graph_match_get_triple(match->user_data);
+}
+
+
+/**
+ * rasqal_new_graph_bindings:
+ * @graph: graph API object
+ * @triples: graph pattern as an array of triples of size @triples_count
+ * @triples_count: number of triples in graph pattern
+ * @filter: expression over the resulting bound variables to filter and constrain matches
+ *
+ * Returns:
+ **/
+rasqal_graph_bindings*
+rasqal_new_graph_bindings(rasqal_graph *graph,
+ rasqal_triple **triples,
+ int triples_count,
+ rasqal_expression *filter)
+{
+ rasqal_graph_bindings* gb;
+ rasqal_graph_factory *factory = graph->world->graph_factory;
+
+ gb = (rasqal_graph_bindings*)RASQAL_CALLOC(rasqal_graph_bindings,
+ sizeof(rasqal_graph_bindings), 1);
+ if(!gb)
+ return NULL;
+
+ gb->graph = rasqal_new_graph_from_graph(graph);
+ gb->user_data = factory->new_graph_bindings(graph, triples, triples_count,
+ filter);
+ if(!gb->user_data) {
+ RASQAL_FREE(graph_bindings, gb);
+ return NULL;
+ }
+
+ return gb;
+}
+
+
+/**
+ * rasqal_free_graph_bindings:
+ * @graph_bindings: graph binding object
+ *
+ * Destructor - free a graph bindings object
+ **/
+void
+rasqal_free_graph_bindings(rasqal_graph_bindings *graph_bindings)
+{
+ rasqal_graph_factory *factory = graph_bindings->world->graph_factory;
+
+ rasqal_free_graph(graph_bindings->graph);
+
+ if(factory->free_graph_bindings)
+ factory->free_graph_bindings(graph_bindings->user_data);
+ RASQAL_FREE(rasqal_graph_bindings, graph_bindings);
+}
+
+
+/**
+ * rasqal_graph_bindings_bind:
+ * @graph_bindings: graph bindings object
+ *
+ * Match a graph pattern and bind variables to the matches
+ *
+ * Returns: non-0 on failure
+ **/
+int
+rasqal_graph_bindings_bind(rasqal_graph_bindings *graph_bindings)
+{
+ rasqal_graph_factory *factory = graph_bindings->world->graph_factory;
+
+ return factory->graph_bindings_bind(graph_bindings->user_data);
+}
diff --git a/src/rasqal/rasqal_graph_pattern.c b/src/rasqal/rasqal_graph_pattern.c
new file mode 100644
index 0000000..e4032b5
--- /dev/null
+++ b/src/rasqal/rasqal_graph_pattern.c
@@ -0,0 +1,864 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_graph_pattern.c - Rasqal graph pattern class
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+/*
+ * rasqal_new_graph_pattern:
+ * @query: #rasqal_graph_pattern query object
+ * @op: enum #rasqal_graph_pattern_operator operator
+ *
+ * INTERNAL - Create a new graph pattern object.
+ *
+ * NOTE: This does not initialise the graph pattern completely
+ * but relies on other operations. The empty graph pattern
+ * has no triples and no sub-graphs.
+ *
+ * Return value: a new #rasqal_graph_pattern object or NULL on failure
+ **/
+static rasqal_graph_pattern*
+rasqal_new_graph_pattern(rasqal_query* query,
+ rasqal_graph_pattern_operator op)
+{
+ rasqal_graph_pattern* gp;
+
+ if(!query)
+ return NULL;
+
+ gp=(rasqal_graph_pattern*)RASQAL_CALLOC(rasqal_graph_pattern, 1, sizeof(rasqal_graph_pattern));
+ if(!gp)
+ return NULL;
+
+ gp->op = op;
+
+ gp->query=query;
+ gp->triples= NULL;
+ gp->start_column= -1;
+ gp->end_column= -1;
+ /* This is initialised by rasqal_query_prepare_count_graph_patterns() inside
+ * rasqal_query_prepare()
+ */
+ gp->gp_index= -1;
+
+ return gp;
+}
+
+
+/*
+ * rasqal_new_basic_graph_pattern:
+ * @query: #rasqal_graph_pattern query object
+ * @triples: triples sequence containing the graph pattern
+ * @start_column: first triple in the pattern
+ * @end_column: last triple in the pattern
+ *
+ * INTERNAL - Create a new graph pattern object over triples.
+ *
+ * Return value: a new #rasqal_graph_pattern object or NULL on failure
+ **/
+rasqal_graph_pattern*
+rasqal_new_basic_graph_pattern(rasqal_query* query,
+ raptor_sequence *triples,
+ int start_column, int end_column)
+{
+ rasqal_graph_pattern* gp;
+
+ if(!triples)
+ return NULL;
+
+ gp=rasqal_new_graph_pattern(query, RASQAL_GRAPH_PATTERN_OPERATOR_BASIC);
+ if(!gp)
+ return NULL;
+
+ gp->triples=triples;
+ gp->start_column=start_column;
+ gp->end_column=end_column;
+
+ return gp;
+}
+
+
+/*
+ * rasqal_new_graph_pattern_from_sequence:
+ * @query: #rasqal_graph_pattern query object
+ * @graph_patterns: sequence containing the graph patterns
+ * @operator: enum #rasqal_graph_pattern_operator such as
+ * RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL
+ *
+ * INTERNAL - Create a new graph pattern from a sequence of graph_patterns.
+ *
+ * Return value: a new #rasqal_graph_pattern object or NULL on failure
+ **/
+rasqal_graph_pattern*
+rasqal_new_graph_pattern_from_sequence(rasqal_query* query,
+ raptor_sequence *graph_patterns,
+ rasqal_graph_pattern_operator op)
+{
+ rasqal_graph_pattern* gp;
+
+ gp=rasqal_new_graph_pattern(query, op);
+ if(!gp) {
+ if(graph_patterns)
+ raptor_free_sequence(graph_patterns);
+ return NULL;
+ }
+
+ gp->graph_patterns=graph_patterns;
+ return gp;
+}
+
+
+/*
+ * rasqal_new_filter_graph_pattern:
+ * @query: #rasqal_graph_pattern query object
+ * @expr: expression
+ *
+ * INTERNAL - Create a new graph pattern from a sequence of graph_patterns.
+ *
+ * Return value: a new #rasqal_graph_pattern object or NULL on failure
+ **/
+rasqal_graph_pattern*
+rasqal_new_filter_graph_pattern(rasqal_query* query,
+ rasqal_expression* expr)
+{
+ rasqal_graph_pattern* gp;
+
+ gp=rasqal_new_graph_pattern(query, RASQAL_GRAPH_PATTERN_OPERATOR_FILTER);
+ if(!gp) {
+ rasqal_free_expression(expr);
+ return NULL;
+ }
+
+ if(rasqal_graph_pattern_set_filter_expression(gp, expr)) {
+ rasqal_free_graph_pattern(gp);
+ gp=NULL;
+ }
+
+ return gp;
+}
+
+
+/*
+ * rasqal_free_graph_pattern:
+ * @gp: #rasqal_graph_pattern object
+ *
+ * INTERNAL - Free a graph pattern object.
+ *
+ **/
+void
+rasqal_free_graph_pattern(rasqal_graph_pattern* gp)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(gp, rasqal_graph_pattern);
+
+ if(gp->graph_patterns)
+ raptor_free_sequence(gp->graph_patterns);
+
+ if(gp->filter_expression)
+ rasqal_free_expression(gp->filter_expression);
+
+ if(gp->constraints)
+ raptor_free_sequence(gp->constraints);
+
+ if(gp->origin)
+ rasqal_free_literal(gp->origin);
+
+ RASQAL_FREE(rasqal_graph_pattern, gp);
+}
+
+
+/*
+ * rasqal_graph_pattern_adjust:
+ * @gp: #rasqal_graph_pattern graph pattern
+ * @offset: adjustment
+ *
+ * INTERNAL - Adjust the column in a graph pattern by the offset.
+ *
+ **/
+void
+rasqal_graph_pattern_adjust(rasqal_graph_pattern* gp, int offset)
+{
+ gp->start_column += offset;
+ gp->end_column += offset;
+}
+
+
+/**
+ * rasqal_graph_pattern_set_filter_expression:
+ * @gp: #rasqal_graph_pattern query object
+ * @expr: #rasqal_expression expr - ownership taken
+ *
+ * Set a filter graph pattern constraint expression
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_graph_pattern_set_filter_expression(rasqal_graph_pattern* gp,
+ rasqal_expression* expr)
+{
+ if(gp->filter_expression)
+ rasqal_free_expression(gp->filter_expression);
+ gp->filter_expression = expr;
+ return 0;
+}
+
+
+/**
+ * rasqal_graph_pattern_get_filter_expression:
+ * @gp: #rasqal_graph_pattern query object
+ *
+ * Get a filter graph pattern's constraint expression
+ *
+ * Return value: expression or NULL on failure
+ **/
+rasqal_expression*
+rasqal_graph_pattern_get_filter_expression(rasqal_graph_pattern* gp)
+{
+ return gp->filter_expression;
+}
+
+
+/**
+ * rasqal_graph_pattern_add_constraint:
+ * @gp: #rasqal_graph_pattern query object
+ * @expr: #rasqal_expression expr - ownership taken
+ *
+ * Add a constraint expression to the graph_pattern.
+ *
+ * @deprecated: Use rasqal_graph_pattern_set_filter_expression()
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_graph_pattern_add_constraint(rasqal_graph_pattern* gp,
+ rasqal_expression* expr)
+{
+ if(!gp->constraints) {
+ gp->constraints=raptor_new_sequence(NULL,
+ (raptor_sequence_print_handler*)rasqal_expression_print);
+ if(!gp->constraints) {
+ rasqal_free_expression(expr);
+ return 1;
+ }
+ }
+ raptor_sequence_set_at(gp->constraints, 0, expr);
+
+ return rasqal_graph_pattern_set_filter_expression(gp, expr);
+}
+
+
+/**
+ * rasqal_graph_pattern_get_constraint_sequence:
+ * @gp: #rasqal_graph_pattern object
+ *
+ * Get the sequence of constraints expressions in the query.
+ *
+ * @deprecated: always returns a sequence with one expression.
+ * Use rasqal_graph_pattern_get_filter_expression() to return it.
+ *
+ * Return value: NULL
+ **/
+raptor_sequence*
+rasqal_graph_pattern_get_constraint_sequence(rasqal_graph_pattern* gp)
+{
+ return gp->constraints;
+}
+
+
+/**
+ * rasqal_graph_pattern_get_constraint:
+ * @gp: #rasqal_graph_pattern query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a constraint in the sequence of constraint expressions in the query.
+ *
+ * @deprecated: A FILTER graph pattern always has one expression
+ * that can be returned with rasqal_graph_pattern_get_filter_expression()
+ *
+ * Return value: a #rasqal_expression pointer or NULL if out of the sequence range
+ **/
+rasqal_expression*
+rasqal_graph_pattern_get_constraint(rasqal_graph_pattern* gp, int idx)
+{
+ return rasqal_graph_pattern_get_filter_expression(gp);
+}
+
+
+/**
+ * rasqal_graph_pattern_get_operator:
+ * @graph_pattern: #rasqal_graph_pattern graph pattern object
+ *
+ * Get the graph pattern operator .
+ *
+ * The operator for the given graph pattern. See also
+ * rasqal_graph_pattern_operator_as_string().
+ *
+ * Return value: graph pattern operator
+ **/
+rasqal_graph_pattern_operator
+rasqal_graph_pattern_get_operator(rasqal_graph_pattern* graph_pattern)
+{
+ return graph_pattern->op;
+}
+
+
+static const char* const rasqal_graph_pattern_operator_labels[RASQAL_GRAPH_PATTERN_OPERATOR_LAST+1]={
+ "UNKNOWN",
+ "Basic",
+ "Optional",
+ "Union",
+ "Group",
+ "Graph",
+ "Filter"
+};
+
+
+/**
+ * rasqal_graph_pattern_operator_as_string:
+ * @op: the #rasqal_graph_pattern_operator verb of the query
+ *
+ * Get a string for the query verb.
+ *
+ * Return value: pointer to a shared string label for the query verb
+ **/
+const char*
+rasqal_graph_pattern_operator_as_string(rasqal_graph_pattern_operator op)
+{
+ if(op <= RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN ||
+ op > RASQAL_GRAPH_PATTERN_OPERATOR_LAST)
+ op=RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN;
+
+ return rasqal_graph_pattern_operator_labels[(int)op];
+}
+
+
+#ifdef RASQAL_DEBUG
+#define DO_INDENTING 0
+#else
+#define DO_INDENTING -1
+#endif
+
+#define SPACES_LENGTH 80
+static const char spaces[SPACES_LENGTH+1]=" ";
+
+static void
+rasqal_graph_pattern_write_indent(raptor_iostream *iostr, int indent)
+{
+ while(indent > 0) {
+ int sp=(indent > SPACES_LENGTH) ? SPACES_LENGTH : indent;
+ raptor_iostream_write_bytes(iostr, spaces, sizeof(char), sp);
+ indent -= sp;
+ }
+}
+
+
+static void
+rasqal_graph_pattern_write_plurals(raptor_iostream *iostr,
+ const char* label, int value)
+{
+ raptor_iostream_write_decimal(iostr, value);
+ raptor_iostream_write_byte(iostr, ' ');
+ raptor_iostream_write_string(iostr, label);
+ if(value != 1)
+ raptor_iostream_write_byte(iostr, 's');
+}
+
+
+/**
+ * rasqal_graph_pattern_print_indent:
+ * @gp: the #rasqal_graph_pattern object
+ * @iostr: the iostream to write to
+ * @indent: the current indent level, <0 for no indenting
+ *
+ * INTERNAL - Print a #rasqal_graph_pattern in a debug format with indenting
+ *
+ **/
+static int
+rasqal_graph_pattern_write_internal(rasqal_graph_pattern* gp,
+ raptor_iostream* iostr, int indent)
+{
+ int pending_nl=0;
+
+ raptor_iostream_write_counted_string(iostr, "graph pattern", 13);
+ if(gp->gp_index >= 0) {
+ raptor_iostream_write_byte(iostr, '[');
+ raptor_iostream_write_decimal(iostr, gp->gp_index);
+ raptor_iostream_write_byte(iostr, ']');
+ }
+ raptor_iostream_write_byte(iostr, ' ');
+ raptor_iostream_write_string(iostr,
+ rasqal_graph_pattern_operator_as_string(gp->op));
+ raptor_iostream_write_byte(iostr, '(');
+
+ if(indent >= 0)
+ indent+= 2;
+
+ if(gp->triples) {
+ int size=gp->end_column - gp->start_column +1;
+ int i;
+ raptor_iostream_write_counted_string(iostr, "over ", 5);
+ rasqal_graph_pattern_write_plurals(iostr, "triple", size);
+ raptor_iostream_write_byte(iostr, '[');
+
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ indent+= 2;
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+
+ for(i=gp->start_column; i <= gp->end_column; i++) {
+ rasqal_triple *t=(rasqal_triple*)raptor_sequence_get_at(gp->triples, i);
+ if(i > gp->start_column) {
+ raptor_iostream_write_counted_string(iostr, " ,", 2);
+
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+ }
+ rasqal_triple_write(t, iostr);
+ }
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ indent-= 2;
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+ raptor_iostream_write_byte(iostr, ']');
+
+ pending_nl=1;
+ }
+
+ if(gp->origin) {
+ if(pending_nl) {
+ raptor_iostream_write_counted_string(iostr, " ,", 2);
+
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+ }
+
+ raptor_iostream_write_counted_string(iostr, "origin ", 7);
+
+ rasqal_literal_write(gp->origin, iostr);
+
+ pending_nl=1;
+ }
+
+ if(gp->graph_patterns) {
+ int size=raptor_sequence_size(gp->graph_patterns);
+ int i;
+
+ if(pending_nl) {
+ raptor_iostream_write_counted_string(iostr, " ,", 2);
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+ }
+
+ raptor_iostream_write_counted_string(iostr, "over ", 5);
+ rasqal_graph_pattern_write_plurals(iostr, "graph pattern", size);
+ raptor_iostream_write_byte(iostr, '[');
+
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ indent+= 2;
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+
+ for(i=0; i< size; i++) {
+ rasqal_graph_pattern* sgp;
+ sgp=(rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ if(i) {
+ raptor_iostream_write_counted_string(iostr, " ,", 2);
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+ }
+ if(sgp)
+ rasqal_graph_pattern_write_internal(sgp, iostr, indent);
+ else
+ raptor_iostream_write_counted_string(iostr, "(empty)", 7);
+ }
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ indent-= 2;
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+ raptor_iostream_write_byte(iostr, ']');
+
+ pending_nl=1;
+ }
+
+ if(gp->filter_expression) {
+ if(pending_nl) {
+ raptor_iostream_write_counted_string(iostr, " ,", 2);
+
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+ }
+
+ if(gp->triples || gp->graph_patterns)
+ raptor_iostream_write_counted_string(iostr, "with ", 5);
+
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ indent+= 2;
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+
+ rasqal_expression_write(gp->filter_expression, iostr);
+ if(indent >= 0)
+ indent-= 2;
+
+ pending_nl=1;
+ }
+
+ if(indent >= 0)
+ indent-= 2;
+
+ if(pending_nl) {
+ if(indent >= 0) {
+ raptor_iostream_write_byte(iostr, '\n');
+ rasqal_graph_pattern_write_indent(iostr, indent);
+ }
+ }
+
+ raptor_iostream_write_byte(iostr, ')');
+
+ return 0;
+}
+
+
+/**
+ * rasqal_graph_pattern_print:
+ * @gp: the #rasqal_graph_pattern object
+ * @fh: the #FILE* handle to print to
+ *
+ * Print a #rasqal_graph_pattern in a debug format.
+ *
+ * The print debug format may change in any release.
+ *
+ **/
+void
+rasqal_graph_pattern_print(rasqal_graph_pattern* gp, FILE* fh)
+{
+ raptor_iostream* iostr;
+ iostr=raptor_new_iostream_to_file_handle(fh);
+ rasqal_graph_pattern_write_internal(gp, iostr, DO_INDENTING);
+ raptor_free_iostream(iostr);
+}
+
+
+/**
+ * rasqal_graph_pattern_visit:
+ * @query: #rasqal_query to operate on
+ * @gp: #rasqal_graph_pattern graph pattern
+ * @fn: pointer to function to apply that takes user data and graph pattern parameters
+ * @user_data: user data for applied function
+ *
+ * Visit a user function over a #rasqal_graph_pattern
+ *
+ * If the user function @fn returns 0, the visit is truncated.
+ *
+ * Return value: 0 if the visit was truncated.
+ **/
+int
+rasqal_graph_pattern_visit(rasqal_query *query,
+ rasqal_graph_pattern* gp,
+ rasqal_graph_pattern_visit_fn fn,
+ void *user_data)
+{
+ raptor_sequence *seq;
+ int result;
+
+ result=fn(query, gp, user_data);
+ if(result)
+ return result;
+
+ seq=rasqal_graph_pattern_get_sub_graph_pattern_sequence(gp);
+ if(seq && raptor_sequence_size(seq) > 0) {
+ int gp_index=0;
+ while(1) {
+ rasqal_graph_pattern* sgp;
+ sgp=rasqal_graph_pattern_get_sub_graph_pattern(gp, gp_index);
+ if(!sgp)
+ break;
+
+ result=rasqal_graph_pattern_visit(query, sgp, fn, user_data);
+ if(result)
+ return result;
+ gp_index++;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_graph_pattern_get_index:
+ * @gp: #rasqal_graph_pattern graph pattern
+ *
+ * Get the graph pattern absolute index in the array of graph patterns.
+ *
+ * The graph pattern index is assigned when rasqal_query_prepare() is
+ * run on a query containing a graph pattern.
+ *
+ * Return value: index or <0 if no index has been assigned yet
+ **/
+int
+rasqal_graph_pattern_get_index(rasqal_graph_pattern* gp)
+{
+ return gp->gp_index;
+}
+
+
+/**
+ * rasqal_graph_pattern_add_sub_graph_pattern:
+ * @graph_pattern: graph pattern to add to
+ * @sub_graph_pattern: graph pattern to add inside
+ *
+ * Add a sub graph pattern to a graph pattern.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_graph_pattern_add_sub_graph_pattern(rasqal_graph_pattern* graph_pattern,
+ rasqal_graph_pattern* sub_graph_pattern)
+{
+ if(!graph_pattern->graph_patterns) {
+ graph_pattern->graph_patterns=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_graph_pattern, (raptor_sequence_print_handler*)rasqal_graph_pattern_print);
+ if(!graph_pattern->graph_patterns) {
+ if(sub_graph_pattern)
+ rasqal_free_graph_pattern(sub_graph_pattern);
+ return 1;
+ }
+ }
+ return raptor_sequence_push(graph_pattern->graph_patterns, sub_graph_pattern);
+}
+
+
+/**
+ * rasqal_graph_pattern_get_triple:
+ * @graph_pattern: #rasqal_graph_pattern graph pattern object
+ * @idx: index into the sequence of triples in the graph pattern
+ *
+ * Get a triple inside a graph pattern.
+ *
+ * Return value: #rasqal_triple or NULL if out of range
+ **/
+rasqal_triple*
+rasqal_graph_pattern_get_triple(rasqal_graph_pattern* graph_pattern, int idx)
+{
+ if(!graph_pattern->triples)
+ return NULL;
+
+ idx += graph_pattern->start_column;
+
+ if(idx > graph_pattern->end_column)
+ return NULL;
+
+ return (rasqal_triple*)raptor_sequence_get_at(graph_pattern->triples, idx);
+}
+
+
+/**
+ * rasqal_graph_pattern_get_sub_graph_pattern_sequence:
+ * @graph_pattern: #rasqal_graph_pattern graph pattern object
+ *
+ * Get the sequence of graph patterns inside a graph pattern .
+ *
+ * Return value: a #raptor_sequence of #rasqal_graph_pattern pointers.
+ **/
+raptor_sequence*
+rasqal_graph_pattern_get_sub_graph_pattern_sequence(rasqal_graph_pattern* graph_pattern)
+{
+ return graph_pattern->graph_patterns;
+}
+
+
+/**
+ * rasqal_graph_pattern_get_sub_graph_pattern:
+ * @graph_pattern: #rasqal_graph_pattern graph pattern object
+ * @idx: index into the sequence of sub graph_patterns in the graph pattern
+ *
+ * Get a sub-graph pattern inside a graph pattern.
+ *
+ * Return value: #rasqal_graph_pattern or NULL if out of range
+ **/
+rasqal_graph_pattern*
+rasqal_graph_pattern_get_sub_graph_pattern(rasqal_graph_pattern* graph_pattern, int idx)
+{
+ if(!graph_pattern->graph_patterns)
+ return NULL;
+
+ return (rasqal_graph_pattern*)raptor_sequence_get_at(graph_pattern->graph_patterns, idx);
+}
+
+
+/*
+ * rasqal_graph_pattern_set_origin:
+ * @graph_pattern: #rasqal_graph_pattern graph pattern object
+ * @origin: #rasqal_literal variable or URI
+ *
+ * INTERNAL - Set the graph pattern triple origin.
+ *
+ * All triples in this graph pattern or contained graph patterns are set
+ * to have the given origin.
+ **/
+void
+rasqal_graph_pattern_set_origin(rasqal_graph_pattern* graph_pattern,
+ rasqal_literal *origin)
+{
+ raptor_sequence* s;
+
+ s=graph_pattern->triples;
+ if(s) {
+ int i;
+
+ /* Flag all the triples in this graph pattern with origin */
+ for(i= graph_pattern->start_column; i <= graph_pattern->end_column; i++) {
+ rasqal_triple *t=(rasqal_triple*)raptor_sequence_get_at(s, i);
+ rasqal_triple_set_origin(t, rasqal_new_literal_from_literal(origin));
+ }
+ }
+
+ s=graph_pattern->graph_patterns;
+ if(s) {
+ int i;
+
+ /* Flag all the triples in sub-graph patterns with origin */
+ for(i=0; i < raptor_sequence_size(s); i++) {
+ rasqal_graph_pattern *gp=(rasqal_graph_pattern*)raptor_sequence_get_at(s, i);
+ rasqal_graph_pattern_set_origin(gp, origin);
+ }
+ }
+
+}
+
+
+/**
+ * rasqal_new_basic_graph_pattern_from_formula:
+ * @query: #rasqal_graph_pattern query object
+ * @formula: triples sequence containing the graph pattern
+ * @op: enum #rasqal_graph_pattern_operator operator
+ *
+ * INTERNAL - Create a new graph pattern object over a formula. This function
+ * frees the formula passed in.
+ *
+ * Return value: a new #rasqal_graph_pattern object or NULL on failure
+ **/
+rasqal_graph_pattern*
+rasqal_new_basic_graph_pattern_from_formula(rasqal_query* query,
+ rasqal_formula* formula)
+{
+ rasqal_graph_pattern* gp;
+ raptor_sequence *triples=query->triples;
+ raptor_sequence *formula_triples=formula->triples;
+ int offset=raptor_sequence_size(triples);
+ int triple_pattern_size=0;
+
+ if(formula_triples) {
+ /* Move formula triples to end of main triples sequence */
+ triple_pattern_size=raptor_sequence_size(formula_triples);
+ if(raptor_sequence_join(triples, formula_triples)) {
+ rasqal_free_formula(formula);
+ return NULL;
+ }
+ }
+
+ rasqal_free_formula(formula);
+
+ gp=rasqal_new_basic_graph_pattern(query, triples,
+ offset,
+ offset+triple_pattern_size-1);
+ return gp;
+}
+
+
+/**
+ * rasqal_new_2_group_graph_pattern:
+ * @query: query object
+ * @first_gp: first graph pattern
+ * @second_gp: second graph pattern
+ *
+ * INTERNAL - Make a new group graph pattern from two graph patterns
+ * of which either or both may be NULL, in which case a group
+ * of 0 graph patterns is created.
+ *
+ * @first_gp and @second_gp if given, become owned by the new graph
+ * pattern.
+ *
+ * Return value: new group graph pattern or NULL on failure
+ */
+rasqal_graph_pattern*
+rasqal_new_2_group_graph_pattern(rasqal_query* query,
+ rasqal_graph_pattern* first_gp,
+ rasqal_graph_pattern* second_gp)
+{
+ raptor_sequence *seq;
+
+ seq=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_graph_pattern, (raptor_sequence_print_handler*)rasqal_graph_pattern_print);
+ if(!seq) {
+ if(first_gp)
+ rasqal_free_graph_pattern(first_gp);
+ if(second_gp)
+ rasqal_free_graph_pattern(second_gp);
+ return NULL;
+ }
+
+ if(first_gp && raptor_sequence_push(seq, first_gp)) {
+ raptor_free_sequence(seq);
+ if(second_gp)
+ rasqal_free_graph_pattern(second_gp);
+ return NULL;
+ }
+ if(second_gp && raptor_sequence_push(seq, second_gp)) {
+ raptor_free_sequence(seq);
+ return NULL;
+ }
+
+ return rasqal_new_graph_pattern_from_sequence(query, seq,
+ RASQAL_GRAPH_PATTERN_OPERATOR_GROUP);
+}
diff --git a/src/rasqal/rasqal_internal.h b/src/rasqal/rasqal_internal.h
new file mode 100644
index 0000000..f0e7a14
--- /dev/null
+++ b/src/rasqal/rasqal_internal.h
@@ -0,0 +1,1200 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_internal.h - Rasqal RDF Query library internals
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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.
+ *
+ */
+
+
+
+#ifndef RASQAL_INTERNAL_H
+#define RASQAL_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#define RASQAL_EXTERN_C extern "C"
+#else
+#define RASQAL_EXTERN_C
+#endif
+
+#ifdef RASQAL_INTERNAL
+
+/* for the memory allocation functions */
+#if defined(HAVE_DMALLOC_H) && defined(RASQAL_MEMORY_DEBUG_DMALLOC)
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#undef HAVE_STDLIB_H
+#endif
+#include <dmalloc.h>
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define RASQAL_PRINTF_FORMAT(string_index, first_to_check_index) \
+ __attribute__((__format__(__printf__, string_index, first_to_check_index)))
+#else
+#define RASQAL_PRINTF_FORMAT(string_index, first_to_check_index)
+#endif
+
+/* Can be over-ridden or undefined in a config.h file or -Ddefine */
+#ifndef RASQAL_INLINE
+#define RASQAL_INLINE inline
+#endif
+
+#ifdef LIBRDF_DEBUG
+#define RASQAL_DEBUG 1
+#endif
+
+#if defined(RASQAL_MEMORY_SIGN)
+#define RASQAL_SIGN_KEY 0x08A59A10
+void* rasqal_sign_malloc(size_t size);
+void* rasqal_sign_calloc(size_t nmemb, size_t size);
+void* rasqal_sign_realloc(void *ptr, size_t size);
+void rasqal_sign_free(void *ptr);
+
+#define RASQAL_MALLOC(type, size) rasqal_sign_malloc(size)
+#define RASQAL_CALLOC(type, nmemb, size) rasqal_sign_calloc(nmemb, size)
+#define RASQAL_REALLOC(type, ptr, size) rasqal_sign_realloc(ptr, size)
+#define RASQAL_FREE(type, ptr) rasqal_sign_free(ptr)
+
+#else
+#define RASQAL_MALLOC(type, size) malloc(size)
+#define RASQAL_CALLOC(type, size, count) calloc(size, count)
+#define RASQAL_FREE(type, ptr) free((void*)ptr)
+
+#endif
+
+#ifdef RASQAL_DEBUG
+/* Debugging messages */
+#define RASQAL_DEBUG1(msg) do {fprintf(stderr, "%s:%d:%s: " msg, __FILE__, __LINE__, __func__); } while(0)
+#define RASQAL_DEBUG2(msg, arg1) do {fprintf(stderr, "%s:%d:%s: " msg, __FILE__, __LINE__, __func__, arg1);} while(0)
+#define RASQAL_DEBUG3(msg, arg1, arg2) do {fprintf(stderr, "%s:%d:%s: " msg, __FILE__, __LINE__, __func__, arg1, arg2);} while(0)
+#define RASQAL_DEBUG4(msg, arg1, arg2, arg3) do {fprintf(stderr, "%s:%d:%s: " msg, __FILE__, __LINE__, __func__, arg1, arg2, arg3);} while(0)
+#define RASQAL_DEBUG5(msg, arg1, arg2, arg3, arg4) do {fprintf(stderr, "%s:%d:%s: " msg, __FILE__, __LINE__, __func__, arg1, arg2, arg3, arg4);} while(0)
+#define RASQAL_DEBUG6(msg, arg1, arg2, arg3, arg4, arg5) do {fprintf(stderr, "%s:%d:%s: " msg, __FILE__, __LINE__, __func__, arg1, arg2, arg3, arg4, arg5);} while(0)
+
+#if defined(HAVE_DMALLOC_H) && defined(RASQAL_MEMORY_DEBUG_DMALLOC)
+void* rasqal_system_malloc(size_t size);
+void rasqal_system_free(void *ptr);
+#define SYSTEM_MALLOC(size) rasqal_system_malloc(size)
+#define SYSTEM_FREE(ptr) rasqal_system_free(ptr)
+#else
+#define SYSTEM_MALLOC(size) malloc(size)
+#define SYSTEM_FREE(ptr) free(ptr)
+#endif
+
+#ifndef RASQAL_ASSERT_DIE
+#define RASQAL_ASSERT_DIE abort();
+#endif
+
+#else
+/* DEBUGGING TURNED OFF */
+
+/* No debugging messages */
+#define RASQAL_DEBUG1(msg)
+#define RASQAL_DEBUG2(msg, arg1)
+#define RASQAL_DEBUG3(msg, arg1, arg2)
+#define RASQAL_DEBUG4(msg, arg1, arg2, arg3)
+#define RASQAL_DEBUG5(msg, arg1, arg2, arg3, arg4)
+#define RASQAL_DEBUG6(msg, arg1, arg2, arg3, arg4, arg5)
+
+#define SYSTEM_MALLOC(size) malloc(size)
+#define SYSTEM_FREE(ptr) free(ptr)
+
+#ifndef RASQAL_ASSERT_DIE
+#define RASQAL_ASSERT_DIE
+#endif
+
+#endif
+
+
+#ifdef RASQAL_DISABLE_ASSERT_MESSAGES
+#define RASQAL_ASSERT_REPORT(line)
+#else
+#define RASQAL_ASSERT_REPORT(msg) fprintf(stderr, "%s:%d: (%s) assertion failed: " msg "\n", __FILE__, __LINE__, __func__);
+#endif
+
+
+#ifdef RASQAL_DISABLE_ASSERT
+
+#define RASQAL_ASSERT(condition, msg)
+#define RASQAL_ASSERT_RETURN(condition, msg, ret)
+#define RASQAL_ASSERT_OBJECT_POINTER_RETURN(pointer, type) do { \
+ if(!pointer) \
+ return; \
+} while(0)
+#define RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(pointer, type, ret)
+
+#else
+
+#define RASQAL_ASSERT(condition, msg) do { \
+ if(condition) { \
+ RASQAL_ASSERT_REPORT(msg) \
+ RASQAL_ASSERT_DIE \
+ } \
+} while(0)
+
+#define RASQAL_ASSERT_RETURN(condition, msg, ret) do { \
+ if(condition) { \
+ RASQAL_ASSERT_REPORT(msg) \
+ RASQAL_ASSERT_DIE \
+ return ret; \
+ } \
+} while(0)
+
+#define RASQAL_ASSERT_OBJECT_POINTER_RETURN(pointer, type) do { \
+ if(!pointer) { \
+ RASQAL_ASSERT_REPORT("object pointer of type " #type " is NULL.") \
+ RASQAL_ASSERT_DIE \
+ return; \
+ } \
+} while(0)
+
+#define RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(pointer, type, ret) do { \
+ if(!pointer) { \
+ RASQAL_ASSERT_REPORT("object pointer of type " #type " is NULL.") \
+ RASQAL_ASSERT_DIE \
+ return ret; \
+ } \
+} while(0)
+
+#endif
+
+
+/* Fatal errors - always happen */
+#define RASQAL_FATAL1(msg) do {fprintf(stderr, "%s:%d:%s: fatal error: " msg, __FILE__, __LINE__ , __func__); abort();} while(0)
+#define RASQAL_FATAL2(msg,arg) do {fprintf(stderr, "%s:%d:%s: fatal error: " msg, __FILE__, __LINE__ , __func__, arg); abort();} while(0)
+#define RASQAL_FATAL3(msg,arg1,arg2) do {fprintf(stderr, "%s:%d:%s: fatal error: " msg, __FILE__, __LINE__ , __func__, arg1, arg2); abort();} while(0)
+
+#ifndef NO_STATIC_DATA
+#define RASQAL_DEPRECATED_MESSAGE(msg) do {static int warning_given=0; if(!warning_given++) fprintf(stderr, "Function %s is deprecated - " msg, __func__); } while(0)
+#define RASQAL_DEPRECATED_WARNING(rq, msg) do {static int warning_given=0; if(!warning_given++) rasqal_query_warning(rq, msg); } while(0)
+#else
+#define RASQAL_DEPRECATED_MESSAGE(msg) do { fprintf(stderr, "Function %s is deprecated - " msg, __func__); } while(0)
+#define RASQAL_DEPRECATED_WARNING(rq, msg) do { rasqal_query_warning(rq, msg); } while(0)
+#endif
+
+
+typedef struct rasqal_query_execution_factory_s rasqal_query_execution_factory;
+typedef struct rasqal_query_language_factory_s rasqal_query_language_factory;
+typedef struct rasqal_variables_table_s rasqal_variables_table;
+
+
+/*
+ * Graph Pattern
+ */
+struct rasqal_graph_pattern_s {
+ rasqal_query* query;
+
+ /* operator for this graph pattern's contents */
+ rasqal_graph_pattern_operator op;
+
+ raptor_sequence* triples; /* ... rasqal_triple* */
+ raptor_sequence* graph_patterns; /* ... rasqal_graph_pattern* */
+
+ int start_column;
+ int end_column;
+
+ /* used to support DEPRECATED functions
+ * rasqal_graph_pattern_get_constraint_sequence() and
+ * rasqal_graph_pattern_get_constraint() */
+ raptor_sequence *constraints; /* ... rasqal_expression* */
+
+ /* the FILTER graph pattern expression */
+ rasqal_expression* filter_expression;
+
+ /* index of the graph pattern in the query (0.. query->graph_pattern_count-1) */
+ int gp_index;
+
+ /* Graph literal */
+ rasqal_literal *origin;
+};
+
+rasqal_graph_pattern* rasqal_new_basic_graph_pattern(rasqal_query* query, raptor_sequence* triples, int start_column, int end_column);
+rasqal_graph_pattern* rasqal_new_graph_pattern_from_sequence(rasqal_query* query, raptor_sequence* graph_patterns, rasqal_graph_pattern_operator op);
+rasqal_graph_pattern* rasqal_new_filter_graph_pattern(rasqal_query* query, rasqal_expression* expr);
+void rasqal_free_graph_pattern(rasqal_graph_pattern* gp);
+void rasqal_graph_pattern_adjust(rasqal_graph_pattern* gp, int offset);
+void rasqal_graph_pattern_set_origin(rasqal_graph_pattern* graph_pattern, rasqal_literal* origin);
+
+
+/*
+ * A query in some query language
+ */
+struct rasqal_query_s {
+ rasqal_world* world; /* world object */
+
+ int usage; /* reference count - 1 for itself, plus for query_results */
+
+ unsigned char* query_string;
+ int query_string_length; /* length including NULs */
+
+ raptor_namespace_stack* namespaces;
+
+ /* query graph pattern, containing the sequence of graph_patterns below */
+ rasqal_graph_pattern* query_graph_pattern;
+
+ /* the query verb - in SPARQL terms: SELECT, CONSTRUCT, DESCRIBE or ASK */
+ rasqal_query_verb verb;
+
+ /* sequences of ... */
+ raptor_sequence* selects; /* ... rasqal_variable* names only */
+ raptor_sequence* data_graphs; /* ... rasqal_data_graph* */
+ /* NOTE: Cannot assume that triples are in any of
+ * graph pattern use / query execution / document order
+ */
+ raptor_sequence* triples; /* ... rasqal_triple* */
+ raptor_sequence* prefixes; /* ... rasqal_prefix* */
+ raptor_sequence* constructs; /* ... rasqal_triple* SPARQL */
+ raptor_sequence* optional_triples; /* ... rasqal_triple* SPARQL */
+ raptor_sequence* describes; /* ... rasqal_literal* (var or URIs) SPARQL */
+
+ /* DISTINCT mode:
+ * 0 if not given
+ * 1 if DISTINCT: ensure solutions are unique
+ * 2 if SPARQL REDUCED: permit elimination of some non-unique solutions
+ * otherwise undefined
+ */
+ int distinct;
+
+ /* result limit LIMIT (>=0) or <0 if not given */
+ int limit;
+
+ /* result offset OFFSET (>=0) or <0 if not given */
+ int offset;
+
+ /* non-0 if '*' was seen after a verb (the appropriate list such as selects or constructs will be NULL) */
+ int wildcard;
+
+ int prepared;
+
+ rasqal_variables_table* vars_table;
+
+ /* The number of selected variables: these are always the first
+ * in the variables table and are the ones returend to the user.
+ */
+ int select_variables_count;
+
+ /* array of size (number of total variables)
+ * pointing to triple column where a variable[offset] is declared
+ */
+ int* variables_declared_in;
+
+ /* can be filled with error location information */
+ raptor_locator locator;
+
+ /* base URI of this query for resolving relative URIs in queries */
+ raptor_uri* base_uri;
+
+ /* non 0 if query had fatal error in parsing and cannot be executed */
+ int failed;
+
+ /* stuff for our user */
+ void* user_data;
+
+ int default_generate_bnodeid_handler_base;
+ char *default_generate_bnodeid_handler_prefix;
+ size_t default_generate_bnodeid_handler_prefix_length;
+
+ void *generate_bnodeid_handler_user_data;
+ rasqal_generate_bnodeid_handler generate_bnodeid_handler;
+
+
+ /* query engine specific stuff */
+ void* context;
+
+ struct rasqal_query_language_factory_s* factory;
+
+ rasqal_triples_source_factory* triples_source_factory;
+
+ /* sequence of query results made from this query */
+ raptor_sequence* results;
+
+ /* incrementing counter for declaring prefixes in order of appearance */
+ int prefix_depth;
+
+ /* sequence of order condition expressions */
+ raptor_sequence* order_conditions_sequence;
+
+ /* sequence of group by condition expressions */
+ raptor_sequence* group_conditions_sequence;
+
+ /* INTERNAL rasqal_literal_compare / rasqal_expression_evaluate flags */
+ int compare_flags;
+
+ /* Number of graph patterns in this query */
+ int graph_pattern_count;
+
+ /* Graph pattern shared pointers by gp index (after prepare) */
+ raptor_sequence* graph_patterns_sequence;
+
+ /* Features */
+ int features[RASQAL_FEATURE_LAST+1];
+
+ /* Name of requested query results syntax. If present, this
+ * is the name used for constructing a rasqal_query_formatter
+ * from the results.
+ */
+ const char* query_results_formatter_name;
+
+ /* EXPLAIN was given */
+ int explain;
+
+ /* generated counter - increments at every generation */
+ int genid_counter;
+
+ /* INTERNAL lexer internal data */
+ void* lexer_user_data;
+
+ /* INTERNAL for now: non-0 to store results otherwise lazy eval results */
+ int store_results;
+};
+
+
+/*
+ * A query language factory for a query language.
+ *
+ * This structure is about turning a query syntax string into a
+ * #rasqal_query structure. It does not deal with execution of the
+ * query in any manner.
+ */
+struct rasqal_query_language_factory_s {
+ struct rasqal_query_language_factory_s* next;
+
+ /* query language name */
+ const char* name;
+
+ /* query language readable label */
+ const char* label;
+
+ /* query language alternate name */
+ const char* alias;
+
+ /* query language MIME type (or NULL) */
+ const char* mime_type;
+
+ /* query language URI (or NULL) */
+ const unsigned char* uri_string;
+
+ /* the rest of this structure is populated by the
+ query-language-specific register function */
+ size_t context_length;
+
+ /* create a new query */
+ int (*init)(rasqal_query* rq, const char *name);
+
+ /* destroy a query */
+ void (*terminate)(rasqal_query* rq);
+
+ /* prepare a query */
+ int (*prepare)(rasqal_query* rq);
+
+ /* finish the query language factory */
+ void (*finish_factory)(rasqal_query_language_factory* factory);
+
+ /* Write a string to an iostream in escaped form suitable for the query */
+ int (*iostream_write_escaped_counted_string)(rasqal_query* rq, raptor_iostream* iostr, const unsigned char* string, size_t len);
+};
+
+
+typedef struct rasqal_rowsource_s rasqal_rowsource;
+
+/*
+ * A row of values from a query result, usually generated by a rowsource
+ */
+typedef struct {
+ /* reference count */
+ int usage;
+
+ /* Rowsource this row is associated with (or NULL if none) */
+ rasqal_rowsource* rowsource;
+
+ /* current row number in the sequence of rows*/
+ int offset;
+
+ /* values for each variable in the query sequence of values */
+ int size;
+ rasqal_literal** values;
+
+ /* literal values for ORDER BY expressions evaluated for this row */
+ /* number of expressions (can be 0) */
+ int order_size;
+ rasqal_literal** order_values;
+} rasqal_row;
+
+
+typedef struct rasqal_map_s rasqal_map;
+
+/**
+ * rasqal_query_results_type:
+ * @RASQAL_QUERY_RESULTS_BINDINGS: variable binding
+ * @RASQAL_QUERY_RESULTS_BOOLEAN: a single boolean
+ * @RASQAL_QUERY_RESULTS_GRAPH: an RDF graph
+ * @RASQAL_QUERY_RESULTS_SYNTAX: a syntax
+ *
+ * Query result type.
+ */
+
+typedef enum {
+ RASQAL_QUERY_RESULTS_BINDINGS,
+ RASQAL_QUERY_RESULTS_BOOLEAN,
+ RASQAL_QUERY_RESULTS_GRAPH,
+ RASQAL_QUERY_RESULTS_SYNTAX
+} rasqal_query_results_type;
+
+
+/* rasqal_rowsource_empty.c */
+rasqal_rowsource* rasqal_new_empty_rowsource(rasqal_world *world, rasqal_query* query);
+
+/* rasqal_rowsource_engine.c */
+rasqal_rowsource* rasqal_new_execution_rowsource(rasqal_query_results* query_results);
+
+/* rasqal_rowsource_filter.c */
+rasqal_rowsource* rasqal_new_filter_rowsource(rasqal_world *world, rasqal_query *query, rasqal_rowsource* rs, rasqal_expression* expr);
+
+/* rasqal_rowsource_join.c */
+rasqal_rowsource* rasqal_new_join_rowsource(rasqal_world *world, rasqal_query* query, rasqal_rowsource* left, rasqal_rowsource* right, int join_type, rasqal_expression *expr);
+
+/* rasqal_rowsource_project.c */
+rasqal_rowsource* rasqal_new_project_rowsource(rasqal_world *world, rasqal_query *query, rasqal_rowsource* rowsource, raptor_sequence* projection_variables);
+
+/* rasqal_rowsource_rowsequence.c */
+rasqal_rowsource* rasqal_new_rowsequence_rowsource(rasqal_world *world, rasqal_query* query, rasqal_variables_table* vt, raptor_sequence* row, raptor_sequence* vars_seq);
+
+/* rasqal_rowsource_sort.c */
+rasqal_rowsource* rasqal_new_sort_rowsource(rasqal_world *world, rasqal_query *query, rasqal_rowsource *rowsource, raptor_sequence *seq);
+
+/* rasqal_rowsource_triples.c */
+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, int *declared_in);
+
+/* rasqal_rowsource_union.c */
+rasqal_rowsource* rasqal_new_union_rowsource(rasqal_world *world, rasqal_query* query, rasqal_rowsource* left, rasqal_rowsource* right);
+
+
+/**
+ * rasqal_rowsource_init_func:
+ * @context: stream context data
+ *
+ * Handler function for #rasqal_rowsource initialising.
+ *
+ * Return value: non-0 on failure.
+ */
+typedef int (*rasqal_rowsource_init_func) (rasqal_rowsource* rowsource, void *user_data);
+
+/**
+ * rasqal_rowsource_finish_func:
+ * @user_data: user data
+ *
+ * Handler function for #rasqal_rowsource terminating.
+ *
+ * Return value: non-0 on failure
+ */
+typedef int (*rasqal_rowsource_finish_func) (rasqal_rowsource* rowsource, void *user_data);
+
+/**
+ * rasqal_rowsource_ensure_variables_func
+ * @rowsource: #rasqal_rowsource
+ * @user_data: user data
+ *
+ * Handler function for ensuring rowsource variables fields are initialised
+ *
+ * Return value: non-0 on failure
+ */
+typedef int (*rasqal_rowsource_ensure_variables_func) (rasqal_rowsource* rowsource, void *user_data);
+
+/**
+ * rasqal_rowsource_read_row_func
+ * @user_data: user data
+ *
+ * Handler function for returning the next result row
+ *
+ * Return value: a query result row or NULL if exhausted
+ */
+typedef rasqal_row* (*rasqal_rowsource_read_row_func) (rasqal_rowsource* rowsource, void *user_data);
+
+
+/**
+ * rasqal_rowsource_read_all_rows_func
+ * @user_data: user data
+ *
+ * Handler function for returning all rows as a sequence
+ *
+ * Return value: a sequence of result rows (which may be size 0) or NULL if exhausted
+ */
+typedef raptor_sequence* (*rasqal_rowsource_read_all_rows_func) (rasqal_rowsource* rowsource, void *user_data);
+
+
+/**
+ * rasqal_rowsource_reset_func
+ * @user_data: user data
+ *
+ * Handler function for resetting a rowsource to generate the same set of rows
+ *
+ * Return value: non-0 on failure
+ */
+typedef int (*rasqal_rowsource_reset_func) (rasqal_rowsource* rowsource, void *user_data);
+
+
+/**
+ * rasqal_rowsource_set_preserve_func
+ * @user_data: user data
+ * @preserve: flag
+ *
+ * Handler function for setting preserve binding states on a rowsource
+ *
+ * Return value: non-0 on failure
+ */
+typedef int (*rasqal_rowsource_set_preserve_func) (rasqal_rowsource* rowsource, void *user_data, int preserve);
+
+
+/**
+ * rasqal_rowsource_get_inner_rowsource_func
+ * @user_data: user data
+ * @offset: offset
+ *
+ * Handler function for getting an inner rowsource at an offset
+ *
+ * Return value: rowsource object or NULL if offset out of range
+ */
+typedef rasqal_rowsource* (*rasqal_rowsource_get_inner_rowsource_func) (rasqal_rowsource* rowsource, void *user_data, int offset);
+
+
+/**
+ * rasqal_rowsource_handler:
+ * @version: API version - 1
+ * @name: rowsource name for debugging
+ * @init: initialisation handler - optional, called at most once (V1)
+ * @finish: finishing handler - optional, called at most once (V1)
+ * @ensure_variables: update variables handler- optional, called at most once (V1)
+ * @read_row: read row handler - this or @read_all_rows required (V1)
+ * @read_all_rows: read all rows handler - this or @read_row required (V1)
+ * @reset: reset rowsource to starting state handler - optional (V1)
+ * @set_preserve: set preserve flag handler - optional (V1)
+ * @get_inner_rowsource: get inner rowsource handler - optional if has no inner rowsources (V1)
+ *
+ * Row Source implementation factory handler structure.
+ *
+ */
+typedef struct {
+ int version;
+ const char* name;
+ /* API V1 methods */
+ rasqal_rowsource_init_func init;
+ rasqal_rowsource_finish_func finish;
+ rasqal_rowsource_ensure_variables_func ensure_variables;
+ rasqal_rowsource_read_row_func read_row;
+ rasqal_rowsource_read_all_rows_func read_all_rows;
+ rasqal_rowsource_reset_func reset;
+ rasqal_rowsource_set_preserve_func set_preserve;
+ rasqal_rowsource_get_inner_rowsource_func get_inner_rowsource;
+} rasqal_rowsource_handler;
+
+
+/**
+ * rasqal_rowsource:
+ * @world: rasqal world
+ * @query: query that this may be associated with (or NULL)
+ * @flags: flags - none currently defined.
+ * @user_data: rowsource handler data
+ * @handler: rowsource handler pointer
+ * @finished: non-0 if rowsource has been exhausted
+ * @count: number of rows returned
+ * @updated_variables: non-0 if ensure_variables factory method has been called to get the variables_sequence updated
+ * @vars_table: variables table where variables used in this row are declared/owned
+ * @variables_sequence: variables declared in this row from @vars_table
+ * @size: number of variables in @variables_sequence
+ * @rows_sequence: stored sequence of rows for use by rasqal_rowsource_read_row() (or NULL)
+ * @offset: size of @rows_sequence
+ *
+ * Rasqal Row Source class providing a sequence of rows of values similar to a SQL table.
+ *
+ * The table has @size columns which are #rasqal_variable names that
+ * are declared in the associated variables table.
+ * @variables_sequence contains the ordered projection of the
+ * variables for the columns for this row sequence, from the full set
+ * of variables in @vars_table.
+ *
+ * Each row has @size #rasqal_literal values for the variables or
+ * NULL if unset.
+ *
+ * Row sources are constructed indirectly via an @handler passed
+ * to the rasqal_new_rowsource_from_handler() constructor.
+ *
+ * The main methods are rasqal_rowsource_read_row() to read one row
+ * and rasqal_rowsource_read_all_rows() to get all rows as a
+ * sequence, draining the row source.
+ * rasqal_rowsource_get_rows_count() returns the current number of
+ * rows that have been read which is only useful in the read one row
+ * case.
+ *
+ * The variables associated with a rowsource can be read by
+ * rasqal_rowsource_get_variable_by_offset() and
+ * rasqal_rowsource_get_variable_offset_by_name() which all are
+ * offsets into @variables_sequence but refer to variables owned by
+ * the full internal variables table @vars_table
+ *
+ * The @rows_sequence and @offset variables are used by the
+ * rasqal_rowsource_read_row() function when operating over a handler
+ * that will only return a full sequence: handler->read_all_rows is NULL.
+ */
+struct rasqal_rowsource_s
+{
+ rasqal_world* world;
+
+ rasqal_query* query;
+
+ int flags;
+
+ void *user_data;
+
+ const rasqal_rowsource_handler* handler;
+
+ int finished;
+
+ int count;
+
+ int updated_variables;
+
+ rasqal_variables_table* vars_table;
+
+ raptor_sequence* variables_sequence;
+
+ int size;
+
+ raptor_sequence* rows_sequence;
+
+ int offset;
+};
+
+/* rasqal_rowsource.c */
+rasqal_rowsource* rasqal_new_rowsource_from_handler(rasqal_world *world, rasqal_query* query, void* user_data, const rasqal_rowsource_handler *handler, rasqal_variables_table* vars_table, int flags);
+void rasqal_free_rowsource(rasqal_rowsource *rowsource);
+
+rasqal_row* rasqal_rowsource_read_row(rasqal_rowsource *rowsource);
+int rasqal_rowsource_get_rows_count(rasqal_rowsource *rowsource);
+raptor_sequence* rasqal_rowsource_read_all_rows(rasqal_rowsource *rowsource);
+int rasqal_rowsource_get_size(rasqal_rowsource *rowsource);
+int rasqal_rowsource_add_variable(rasqal_rowsource *rowsource, rasqal_variable* v);
+rasqal_variable* rasqal_rowsource_get_variable_by_offset(rasqal_rowsource *rowsource, int offset);
+int rasqal_rowsource_get_variable_offset_by_name(rasqal_rowsource *rowsource, const unsigned char* name);
+void rasqal_rowsource_copy_variables(rasqal_rowsource *dest_rowsource, rasqal_rowsource *src_rowsource);
+void rasqal_rowsource_print_row_sequence(rasqal_rowsource* rowsource,raptor_sequence* seq, FILE* fh);
+int rasqal_rowsource_reset(rasqal_rowsource* rowsource);
+int rasqal_rowsource_set_preserve(rasqal_rowsource* rowsource, int preserve);
+rasqal_rowsource* rasqal_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource, int offset);
+int rasqal_rowsource_write(rasqal_rowsource *rowsource, raptor_iostream *iostr);
+void rasqal_rowsource_print(rasqal_rowsource* rs, FILE* fh);
+int rasqal_rowsource_ensure_variables(rasqal_rowsource *rowsource);
+
+typedef int (*rasqal_query_results_formatter_func)(raptor_iostream *iostr, rasqal_query_results* results, raptor_uri *base_uri);
+
+typedef rasqal_rowsource* (*rasqal_query_results_get_rowsource_func)(rasqal_world*, rasqal_variables_table* vars_table, raptor_iostream *iostr, raptor_uri *base_uri);
+
+
+typedef struct {
+ /* query results format name */
+ const char* name;
+
+ /* query results format name */
+ const char* label;
+
+ /* query results format URI (or NULL) */
+ const unsigned char* uri_string;
+
+ /* format writer: READ from results, WRITE syntax (using base URI) to iostr */
+ rasqal_query_results_formatter_func writer;
+
+ /* format reader: READ syntax from iostr using base URI, WRITE to results */
+ rasqal_query_results_formatter_func reader;
+
+ /* format get rowsource: get a rowsource that will return a sequence of rows from an iostram */
+ rasqal_query_results_get_rowsource_func get_rowsource;
+
+ /* MIME Type of the format */
+ const char* mime_type;
+} rasqal_query_results_format_factory;
+
+
+/*
+ * A query results formatter for some query_results
+ */
+struct rasqal_query_results_formatter_s {
+ rasqal_query_results_format_factory* factory;
+
+ const char *mime_type;
+};
+
+typedef struct {
+ raptor_sequence *triples;
+ rasqal_literal *value;
+} rasqal_formula;
+
+
+/* rasqal_datetime.c */
+int rasqal_xsd_datetime_check(const unsigned char* string);
+
+
+/* rasqal_general.c */
+char* rasqal_vsnprintf(const char* message, va_list arguments);
+
+int rasqal_query_language_register_factory(rasqal_world*, const char* name, const char* label, const char* alias, const unsigned char* uri_string, void (*factory) (rasqal_query_language_factory*));
+rasqal_query_language_factory* rasqal_get_query_language_factory (rasqal_world*, const char* name, const unsigned char* uri);
+void rasqal_log_error_simple(rasqal_world* world, raptor_log_level level, raptor_locator* locator, const char* message, ...) RASQAL_PRINTF_FORMAT(4, 5);
+void rasqal_log_error_varargs(rasqal_world* world, raptor_log_level level, raptor_locator* locator, const char* message, va_list arguments) RASQAL_PRINTF_FORMAT(4, 0);
+void rasqal_log_error(raptor_log_level level, raptor_message_handler handler, void* handler_data, raptor_locator* locator, const char* message);
+void rasqal_query_simple_error(void* query, const char *message, ...) RASQAL_PRINTF_FORMAT(2, 3);
+
+const char* rasqal_basename(const char* name);
+
+
+/* rasqal_graph_pattern.c */
+unsigned char* rasqal_escaped_name_to_utf8_string(const unsigned char* src, size_t len, size_t* dest_lenp, raptor_simple_message_handler error_handler, void* error_data);
+unsigned char* rasqal_query_generate_bnodeid(rasqal_query* rdf_query, unsigned char *user_bnodeid);
+
+rasqal_graph_pattern* rasqal_new_basic_graph_pattern_from_formula(rasqal_query* query, rasqal_formula* formula);
+rasqal_graph_pattern* rasqal_new_2_group_graph_pattern(rasqal_query* query, rasqal_graph_pattern* first_gp, rasqal_graph_pattern* second_gp);
+
+/* rdql_parser.y */
+int rasqal_init_query_language_rdql(rasqal_world*);
+
+/* sparql_parser.y */
+int rasqal_init_query_language_sparql(rasqal_world*);
+int rasqal_init_query_language_laqrs(rasqal_world*);
+
+/* rasqal_query_transform.c */
+int rasqal_query_expand_triple_qnames(rasqal_query* rq);
+int rasqal_sequence_has_qname(raptor_sequence* seq);
+int rasqal_query_constraints_has_qname(rasqal_query* gp);
+int rasqal_query_expand_graph_pattern_constraints_qnames(rasqal_query* rq, rasqal_graph_pattern* gp);
+int rasqal_query_expand_query_constraints_qnames(rasqal_query* rq);
+int rasqal_query_build_anonymous_variables(rasqal_query* rq);
+int rasqal_query_expand_wildcards(rasqal_query* rq);
+int rasqal_query_remove_duplicate_select_vars(rasqal_query* rq);
+int rasqal_query_prepare_common(rasqal_query *query);
+int rasqal_query_merge_graph_patterns(rasqal_query* query, rasqal_graph_pattern* gp, void* data);
+int rasqal_graph_patterns_join(rasqal_graph_pattern *dest_gp, rasqal_graph_pattern *src_gp);
+int rasqal_graph_pattern_move_constraints(rasqal_graph_pattern* dest_gp, rasqal_graph_pattern* src_gp);
+int* rasqal_query_triples_build_declared_in(rasqal_query* query, int size, int start_column, int end_column);
+
+/* rasqal_expr.c */
+rasqal_literal* rasqal_new_string_literal_node(rasqal_world*, const unsigned char *string, const char *language, raptor_uri *datatype);
+int rasqal_literal_as_boolean(rasqal_literal* literal, int* error);
+int rasqal_literal_as_integer(rasqal_literal* l, int* error);
+double rasqal_literal_as_floating(rasqal_literal* l, int* error);
+raptor_uri* rasqal_literal_as_uri(rasqal_literal* l);
+int rasqal_literal_string_to_native(rasqal_literal *l, raptor_simple_message_handler error_handler, void *error_data, int flags);
+int rasqal_literal_has_qname(rasqal_literal* l);
+int rasqal_literal_expand_qname(void* user_data, rasqal_literal* l);
+int rasqal_literal_is_constant(rasqal_literal* l);
+int rasqal_expression_has_qname(void* user_data, rasqal_expression* e);
+int rasqal_expression_expand_qname(void* user_data, rasqal_expression* e);
+int rasqal_literal_ebv(rasqal_literal* l);
+int rasqal_expression_is_constant(rasqal_expression* e);
+void rasqal_expression_clear(rasqal_expression* e);
+void rasqal_expression_convert_to_literal(rasqal_expression* e, rasqal_literal* l);
+int rasqal_expression_mentions_variable(rasqal_expression* e, rasqal_variable* v);
+void rasqal_triple_write(rasqal_triple* t, raptor_iostream* iostr);
+void rasqal_variable_write(rasqal_variable* v, raptor_iostream* iostr);
+
+
+/* strcasecmp.c */
+#ifdef HAVE_STRCASECMP
+# define rasqal_strcasecmp strcasecmp
+# define rasqal_strncasecmp strncasecmp
+#else
+# ifdef HAVE_STRICMP
+# define rasqal_strcasecmp stricmp
+# define rasqal_strncasecmp strnicmp
+# else
+int rasqal_strcasecmp(const char* s1, const char* s2);
+int rasqal_strncasecmp(const char* s1, const char* s2, size_t n);
+# endif
+#endif
+
+/* rasqal_raptor.c */
+int rasqal_raptor_init(rasqal_world*);
+
+#ifdef RAPTOR_TRIPLES_SOURCE_REDLAND
+/* rasqal_redland.c */
+int rasqal_redland_init(rasqal_world*);
+void rasqal_redland_finish(void);
+#endif
+
+
+/* rasqal_general.c */
+int rasqal_uri_init(rasqal_world*);
+void rasqal_uri_finish(rasqal_world*);
+
+/* rasqal_literal.c */
+rasqal_formula* rasqal_new_formula(void);
+void rasqal_free_formula(rasqal_formula* formula);
+void rasqal_formula_print(rasqal_formula* formula, FILE *stream);
+rasqal_formula* rasqal_formula_join(rasqal_formula* first_formula, rasqal_formula* second_formula);
+
+/* The following should be public eventually in rasqal.h or raptor.h or ...? */
+
+typedef int (rasqal_compare_fn)(void* user_data, const void *a, const void *b);
+typedef void (rasqal_compare_free_user_data_fn)(const void *data);
+typedef void (rasqal_kv_free_fn)(const void *key, const void *value);
+
+
+#define RASQAL_XSD_BOOLEAN_TRUE (const unsigned char*)"true"
+#define RASQAL_XSD_BOOLEAN_FALSE (const unsigned char*)"false"
+
+rasqal_literal* rasqal_literal_cast(rasqal_literal* l, raptor_uri* datatype, int flags, int* error_p);
+rasqal_literal* rasqal_new_numeric_literal(rasqal_world*, rasqal_literal_type type, double d);
+int rasqal_literal_is_numeric(rasqal_literal* literal);
+rasqal_literal* rasqal_literal_add(rasqal_literal* l1, rasqal_literal* l2, int *error);
+rasqal_literal* rasqal_literal_subtract(rasqal_literal* l1, rasqal_literal* l2, int *error);
+rasqal_literal* rasqal_literal_multiply(rasqal_literal* l1, rasqal_literal* l2, int *error);
+rasqal_literal* rasqal_literal_divide(rasqal_literal* l1, rasqal_literal* l2, int *error);
+rasqal_literal* rasqal_literal_negate(rasqal_literal* l, int *error_p);
+int rasqal_literal_equals_flags(rasqal_literal* l1, rasqal_literal* l2, int flags, int* error);
+rasqal_literal_type rasqal_literal_get_rdf_term_type(rasqal_literal* l);
+void rasqal_literal_write_type(rasqal_literal* l, raptor_iostream* iostr);
+void rasqal_literal_write(rasqal_literal* l, raptor_iostream* iostr);
+void rasqal_expression_write_op(rasqal_expression* e, raptor_iostream* iostr);
+void rasqal_expression_write(rasqal_expression* e, raptor_iostream* iostr);
+
+/* rasqal_map.c */
+typedef void (*rasqal_map_visit_fn)(void *key, void *value, void *user_data);
+
+rasqal_map* rasqal_new_map(rasqal_compare_fn* compare_fn, void* compare_user_data, rasqal_compare_free_user_data_fn* free_compare_user_data, rasqal_kv_free_fn* free_fn, raptor_sequence_print_handler* print_key_fn, raptor_sequence_print_handler* print_value_fn, int flags);
+void rasqal_free_map(rasqal_map *map);
+int rasqal_map_add_kv(rasqal_map* map, void* key, void *value);
+void rasqal_map_visit(rasqal_map* map, rasqal_map_visit_fn fn, void *user_data);
+void rasqal_map_print(rasqal_map* map, FILE* fh);
+
+/* rasqal_query.c */
+rasqal_query_results* rasqal_query_execute_with_engine(rasqal_query* query, const rasqal_query_execution_factory* engine);
+void rasqal_query_remove_query_result(rasqal_query* query, rasqal_query_results* query_results);
+int rasqal_query_declare_prefix(rasqal_query* rq, rasqal_prefix* prefix);
+int rasqal_query_declare_prefixes(rasqal_query* rq);
+unsigned char* rasqal_query_get_genid(rasqal_query* query, const unsigned char* base, int counter);
+void rasqal_query_set_base_uri(rasqal_query* rq, raptor_uri* base_uri);
+void rasqal_query_set_store_results(rasqal_query* query, int store_results);
+rasqal_variable* rasqal_query_get_variable_by_offset(rasqal_query* query, int idx);
+const rasqal_query_execution_factory* rasqal_query_get_engine_by_name(const char* name);
+
+/* rasqal_query_results.c */
+int rasqal_init_query_results(void);
+void rasqal_finish_query_results(void);
+rasqal_query_results* rasqal_new_query_results(rasqal_world* world, rasqal_query* query, rasqal_query_results_type type, rasqal_variables_table* vars_table);
+rasqal_query_results* rasqal_query_results_execute_with_engine(rasqal_query* query, const rasqal_query_execution_factory* factory);
+void rasqal_query_results_add_row(rasqal_query_results* query_results, rasqal_row* row);
+int rasqal_query_results_check_limit_offset(rasqal_query_results* query_results);
+void rasqal_query_results_remove_query_reference(rasqal_query_results* query_results);
+rasqal_variables_table* rasqal_query_results_get_variables_table(rasqal_query_results* query_results);
+
+/* rasqal_result_formats.c */
+int rasqal_query_results_format_register_factory(rasqal_world*, const char *name, const char *label, const unsigned char* uri_string, rasqal_query_results_formatter_func writer, rasqal_query_results_formatter_func reader, rasqal_query_results_get_rowsource_func get_rowsource, const char *mime_type);
+int rasqal_init_result_formats(rasqal_world*);
+void rasqal_finish_result_formats(rasqal_world*);
+
+/* rasqal_result_format_sparql_xml.c */
+int rasqal_init_result_format_sparql_xml(rasqal_world*);
+
+/* rasqal_row.c */
+rasqal_row* rasqal_new_row(rasqal_rowsource* rowsource);
+rasqal_row* rasqal_new_row_for_size(int size);
+rasqal_row* rasqal_new_row_from_row(rasqal_row* row);
+void rasqal_free_row(rasqal_row* row);
+void rasqal_row_print(rasqal_row* row, FILE* fh);
+void rasqal_row_set_value_at(rasqal_row* row, int offset, rasqal_literal* value);
+raptor_sequence* rasqal_new_row_sequence(rasqal_world* world, rasqal_variables_table* vt, const char* const row_data[], int vars_count, raptor_sequence** vars_seq_p);
+int rasqal_row_to_nodes(rasqal_row* row);
+void rasqal_row_set_values_from_variables_table(rasqal_row* row, rasqal_variables_table* vars_table);
+int rasqal_row_set_order_size(rasqal_row *row, int order_size);
+int rasqal_row_expand_size(rasqal_row *row, int size);
+
+/* rasqal_triples_source.c */
+rasqal_triples_source* rasqal_new_triples_source(rasqal_query* query);
+int rasqal_reset_triple_meta(rasqal_triple_meta* m);
+void rasqal_free_triples_source(rasqal_triples_source *rts);
+int rasqal_triples_source_triple_present(rasqal_triples_source *rts, rasqal_triple *t);
+rasqal_triples_match* rasqal_new_triples_match(rasqal_query* query, rasqal_triples_source* triples_source, rasqal_triple_meta *m, rasqal_triple *t);
+int rasqal_triples_match_bind_match(struct rasqal_triples_match_s* rtm, rasqal_variable *bindings[4],rasqal_triple_parts parts);
+void rasqal_triples_match_next_match(struct rasqal_triples_match_s* rtm);
+int rasqal_triples_match_is_end(struct rasqal_triples_match_s* rtm);
+
+/* rasqal_xsd_datatypes.c */
+int rasqal_xsd_init(rasqal_world*);
+void rasqal_xsd_finish(rasqal_world*);
+rasqal_literal_type rasqal_xsd_datatype_uri_to_type(rasqal_world*, raptor_uri* uri);
+raptor_uri* rasqal_xsd_datatype_type_to_uri(rasqal_world*, rasqal_literal_type type);
+int rasqal_xsd_datatype_check(rasqal_literal_type native_type, const unsigned char* string, int flags);
+const char* rasqal_xsd_datatype_label(rasqal_literal_type native_type);
+int rasqal_xsd_is_datatype_uri(rasqal_world*, raptor_uri* uri);
+const unsigned char* rasqal_xsd_datetime_string_to_canonical(const unsigned char* datetime_string);
+rasqal_literal_type rasqal_xsd_datatype_uri_parent_type(rasqal_world* world, raptor_uri* uri);
+int rasqal_xsd_datatype_is_numeric(rasqal_literal_type type);
+unsigned char* rasqal_xsd_format_double(double d, size_t *len_p);
+
+
+typedef struct rasqal_graph_factory_s rasqal_graph_factory;
+
+/* rasqal_world structure */
+struct rasqal_world_s {
+ /* opened flag */
+ int opened;
+
+ /* raptor_world object */
+ raptor_world *raptor_world_ptr;
+
+ /* should rasqal free the raptor_world */
+ int raptor_world_allocated_here;
+
+ /* error handlers structure */
+ raptor_error_handlers error_handlers;
+
+ /* linked list of query languages */
+ rasqal_query_language_factory *query_languages;
+
+ /* registered query results formats */
+ raptor_sequence *query_results_formats;
+
+ /* rasqal_uri rdf uris */
+ raptor_uri *rdf_namespace_uri;
+ raptor_uri *rdf_first_uri;
+ raptor_uri *rdf_rest_uri;
+ raptor_uri *rdf_nil_uri;
+
+ /* triples source factory */
+ rasqal_triples_source_factory triples_source_factory;
+
+ /* rasqal_xsd_datatypes */
+ raptor_uri *xsd_namespace_uri;
+ raptor_uri **xsd_datatype_uris;
+
+ /* graph factory */
+ rasqal_graph_factory *graph_factory;
+ void *graph_factory_user_data;
+};
+
+
+/*
+ * Rasqal Algebra
+ *
+ * Based on http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
+ */
+
+typedef enum {
+ RASQAL_ALGEBRA_OPERATOR_UNKNOWN = 0,
+ RASQAL_ALGEBRA_OPERATOR_BGP = 1,
+ RASQAL_ALGEBRA_OPERATOR_FILTER = 2,
+ RASQAL_ALGEBRA_OPERATOR_JOIN = 3,
+ RASQAL_ALGEBRA_OPERATOR_DIFF = 4,
+ RASQAL_ALGEBRA_OPERATOR_LEFTJOIN = 5,
+ RASQAL_ALGEBRA_OPERATOR_UNION = 6,
+ RASQAL_ALGEBRA_OPERATOR_TOLIST = 7,
+ RASQAL_ALGEBRA_OPERATOR_ORDERBY = 8,
+ RASQAL_ALGEBRA_OPERATOR_PROJECT = 9,
+ RASQAL_ALGEBRA_OPERATOR_DISTINCT = 10,
+ RASQAL_ALGEBRA_OPERATOR_REDUCED = 11,
+ RASQAL_ALGEBRA_OPERATOR_SLICE = 12,
+
+ RASQAL_ALGEBRA_OPERATOR_LAST=RASQAL_ALGEBRA_OPERATOR_SLICE
+} rasqal_algebra_node_operator;
+
+
+/*
+ * Algebra Node
+ */
+struct rasqal_algebra_node_s {
+ rasqal_query* query;
+
+ /* operator for this algebra_node's contents */
+ rasqal_algebra_node_operator op;
+
+ /* type BGP (otherwise NULL and start_column and end_column are -1) */
+ raptor_sequence* triples;
+ int start_column;
+ int end_column;
+
+ /* types JOIN, DIFF, LEFTJOIN, UNION, ORDERBY: node1 and node2 ALWAYS present
+ * types FILTER, TOLIST: node1 ALWAYS present, node2 ALWAYS NULL
+ * type PROJECT: node1 always present
+ * (otherwise NULL)
+ */
+ rasqal_algebra_node *node1;
+ rasqal_algebra_node *node2;
+
+ /* types FILTER, LEFTJOIN
+ * (otherwise NULL)
+ */
+ rasqal_expression* expr;
+
+ /* types ORDERBY always present
+ * (otherwise NULL)
+ */
+ raptor_sequence* seq;
+
+ /* types PROJECT, DISTINCT, REDUCED
+ * FIXME: sequence of solution mappings */
+
+ /* types PROJECT, SLICE */
+ raptor_sequence* vars_seq;
+
+ /* type SLICE: start and length */
+ unsigned int start;
+ unsigned int length;
+};
+
+/**
+ * rasqal_algebra_node_visit_fn:
+ * @query: #rasqal_query containing the graph pattern
+ * @gp: current algebra_node
+ * @user_data: user data passed in
+ *
+ * User function to visit an algebra_node and operate on it with
+ * rasqal_algebra_node_visit() or rasqal_query_algebra_node_visit()
+ *
+ * Return value: 0 to truncate the visit
+ */
+typedef int (*rasqal_algebra_node_visit_fn)(rasqal_query* query, rasqal_algebra_node* node, void *user_data);
+
+/* rasqal_algebra.c */
+rasqal_algebra_node* rasqal_new_filter_algebra_node(rasqal_query* query, rasqal_expression* expr, rasqal_algebra_node* node);
+rasqal_algebra_node* rasqal_new_empty_algebra_node(rasqal_query* query);
+rasqal_algebra_node* rasqal_new_triples_algebra_node(rasqal_query* query, raptor_sequence* triples, int start_column, int end_column);
+rasqal_algebra_node* rasqal_new_2op_algebra_node(rasqal_query* query, rasqal_algebra_node_operator op, rasqal_algebra_node* node1, rasqal_algebra_node* node2);
+rasqal_algebra_node* rasqal_new_leftjoin_algebra_node(rasqal_query* query, rasqal_algebra_node* node1, rasqal_algebra_node* node2, rasqal_expression* expr);
+rasqal_algebra_node* rasqal_new_orderby_algebra_node(rasqal_query* query, rasqal_algebra_node* node, raptor_sequence* seq);
+rasqal_algebra_node* rasqal_new_project_algebra_node(rasqal_query* query, rasqal_algebra_node* node1, raptor_sequence* vars_seq);
+void rasqal_free_algebra_node(rasqal_algebra_node* node);
+rasqal_algebra_node_operator rasqal_algebra_node_get_operator(rasqal_algebra_node* node);
+const char* rasqal_algebra_node_operator_as_string(rasqal_algebra_node_operator op);
+int rasqal_algebra_algebra_node_write(rasqal_algebra_node *node, raptor_iostream* iostr);
+void rasqal_algebra_node_print(rasqal_algebra_node* node, FILE* fh);
+int rasqal_algebra_node_visit(rasqal_query *query, rasqal_algebra_node* node, rasqal_algebra_node_visit_fn fn, void *user_data);
+rasqal_algebra_node* rasqal_algebra_query_to_algebra(rasqal_query* query);
+int rasqal_algebra_node_is_empty(rasqal_algebra_node* node);
+
+/* rasqal_variable.c */
+rasqal_variables_table* rasqal_new_variables_table(rasqal_world* world);
+rasqal_variables_table* rasqal_new_variables_table_from_variables_table(rasqal_variables_table* vt);
+void rasqal_free_variables_table(rasqal_variables_table* vt);
+rasqal_variable* rasqal_variables_table_add(rasqal_variables_table* vt, rasqal_variable_type type, const unsigned char *name, rasqal_literal *value);
+rasqal_variable* rasqal_variables_table_get(rasqal_variables_table* vt, int idx);
+rasqal_variable* rasqal_variables_table_get_by_name(rasqal_variables_table* vt, const unsigned char *name);
+rasqal_literal* rasqal_variables_table_get_value(rasqal_variables_table* vt, int idx);
+int rasqal_variables_table_has(rasqal_variables_table* vt, const unsigned char *name);
+int rasqal_variables_table_set(rasqal_variables_table* vt, const unsigned char *name, rasqal_literal* value);
+int rasqal_variables_table_get_named_variables_count(rasqal_variables_table* vt);
+int rasqal_variables_table_get_anonymous_variables_count(rasqal_variables_table* vt);
+int rasqal_variables_table_get_total_variables_count(rasqal_variables_table* vt);
+raptor_sequence* rasqal_variables_table_get_named_variables_sequence(rasqal_variables_table* vt);
+raptor_sequence* rasqal_variables_table_get_anonymous_variables_sequence(rasqal_variables_table* vt);
+const unsigned char** rasqal_variables_table_get_names(rasqal_variables_table* vt);
+
+
+/**
+ * @RASQAL_ENGINE_OK:
+ * @RASQAL_ENGINE_FAILED:
+ * @RASQAL_ENGINE_FINISHED:
+ *
+ * Execution engine errors.
+ *
+ */
+typedef enum {
+ RASQAL_ENGINE_OK,
+ RASQAL_ENGINE_FAILED,
+ RASQAL_ENGINE_FINISHED
+} rasqal_engine_error;
+
+
+/*
+ * A query execution engine factory
+ *
+ * This structure is about executing the query recorded in
+ * #rasqal_query structure into results accessed via #rasqal_query_results
+ */
+struct rasqal_query_execution_factory_s {
+ /* execution engine name */
+ const char* name;
+
+ /* size of execution engine private data */
+ size_t execution_data_size;
+
+ /*
+ * @ex_data: execution data
+ * @query: query to execute
+ * @query_results: query results
+ * @flags: execution flags. 1: execute and store results
+ * @error_p: execution error (OUT variable)
+ *
+ * Initialise a new execution
+ *
+ * Return value: non-0 on failure
+ */
+ int (*execute_init)(void* ex_data, rasqal_query* query, rasqal_query_results* query_results, int flags, rasqal_engine_error *error_p);
+
+ /**
+ * @ex_data: execution data
+ * @error_p: execution error (OUT variable)
+ *
+ * Get all bindings result rows (returning a new raptor_sequence object holding new objects.
+ *
+ * Will not be called if query results is NULL, finished or failed.
+ */
+ raptor_sequence* (*get_all_rows)(void* ex_data, rasqal_engine_error *error_p);
+
+ /*
+ * @ex_data: execution object
+ * @error_p: execution error (OUT variable)
+ *
+ * Get current bindings result row (returning a new object)
+ *
+ * Will not be called if query results is NULL, finished or failed.
+ */
+ rasqal_row* (*get_row)(void* ex_data, rasqal_engine_error *error_p);
+
+ /* finish (free) execution */
+ int (*execute_finish)(void* ex_data, rasqal_engine_error *error_p);
+
+ /* finish the query execution factory */
+ void (*finish_factory)(rasqal_query_execution_factory* factory);
+
+};
+
+
+/* rasqal_engine.c */
+
+/* Original Rasqal 0.9.16 query engine executing over graph patterns */
+extern const rasqal_query_execution_factory rasqal_query_engine_1;
+
+/* rasqal_engine_sort.c */
+rasqal_map* rasqal_engine_new_rowsort_map(int is_distinct, int compare_flags, raptor_sequence* order_conditions_sequence);
+int rasqal_engine_rowsort_map_add_row(rasqal_map* map, rasqal_row* row);
+raptor_sequence* rasqal_engine_rowsort_map_to_sequence(rasqal_map* map, raptor_sequence* seq);
+int rasqal_engine_rowsort_calculate_order_values(rasqal_query* query, rasqal_row* row);
+
+/* rasqal_engine_algebra.c */
+
+/* New query engine based on executing over query algebra */
+extern const rasqal_query_execution_factory rasqal_query_engine_algebra;
+
+/* end of RASQAL_INTERNAL */
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/rasqal/rasqal_literal.c b/src/rasqal/rasqal_literal.c
new file mode 100644
index 0000000..874b23e
--- /dev/null
+++ b/src/rasqal/rasqal_literal.c
@@ -0,0 +1,3198 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_literal.c - Rasqal literals
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+/* for isnan() */
+#include <math.h>
+
+#ifdef RASQAL_REGEX_PCRE
+#include <pcre.h>
+#endif
+
+#ifdef RASQAL_REGEX_POSIX
+#include <sys/types.h>
+#include <regex.h>
+#endif
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+/* prototypes */
+static rasqal_literal_type rasqal_literal_promote_numerics(rasqal_literal* l1, rasqal_literal* l2, int flags);
+static int rasqal_literal_set_typed_value(rasqal_literal* l, rasqal_literal_type type, const unsigned char* string, raptor_simple_message_handler error_handler, void *error_data, int flags);
+
+
+/**
+ * rasqal_new_integer_literal:
+ * @world: rasqal world object
+ * @type: Type of literal such as RASQAL_LITERAL_INTEGER or RASQAL_LITERAL_BOOLEAN
+ * @integer: int value
+ *
+ * Constructor - Create a new Rasqal integer literal.
+ *
+ * The integer decimal number is turned into a rasqal integer literal
+ * and given a datatype of xsd:integer
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_integer_literal(rasqal_world* world, rasqal_literal_type type, int integer)
+{
+ raptor_uri* dt_uri;
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+ l->type=type;
+ l->value.integer=integer;
+ l->string=(unsigned char*)RASQAL_MALLOC(cstring, 30); /* FIXME */
+ if(!l->string) {
+ rasqal_free_literal(l);
+ return NULL;
+ }
+ sprintf((char*)l->string, "%d", integer);
+ l->string_len=strlen((const char*)l->string);
+ dt_uri=rasqal_xsd_datatype_type_to_uri(world, l->type);
+ if(!dt_uri) {
+ rasqal_free_literal(l);
+ return NULL;
+ }
+#ifdef RAPTOR_V2_AVAILABLE
+ l->datatype = raptor_uri_copy_v2(world->raptor_world_ptr, dt_uri);
+#else
+ l->datatype = raptor_uri_copy(dt_uri);
+#endif
+ if(type == RASQAL_LITERAL_INTEGER)
+ l->parent_type=RASQAL_LITERAL_DECIMAL;
+ }
+ return l;
+}
+
+
+/**
+ * rasqal_new_typed_literal:
+ * @world: rasqal world object
+ * @type: Type of literal such as RASQAL_LITERAL_INTEGER or RASQAL_LITERAL_BOOLEAN
+ * @string: lexical form - ownership not taken
+ *
+ * Constructor - Create a new Rasqal integer literal from a string
+ *
+ * The integer decimal number is turned into a rasqal integer literal
+ * and given a datatype of xsd:integer
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_typed_literal(rasqal_world* world, rasqal_literal_type type, const unsigned char* string)
+{
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1,
+ sizeof(rasqal_literal));
+ if(!l)
+ return NULL;
+
+ l->usage=1;
+ l->world=world;
+ l->type=type;
+ if(rasqal_literal_set_typed_value(l, type, string, NULL, NULL, 0)) {
+ rasqal_free_literal(l);
+ l=NULL;
+ }
+
+ return l;
+}
+
+
+/**
+ * rasqal_new_double_literal:
+ * @world: rasqal world object
+ * @d: double literal
+ *
+ * Constructor - Create a new Rasqal double literal.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_double_literal(rasqal_world*world, double d)
+{
+ raptor_uri* dt_uri;
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+ l->type=RASQAL_LITERAL_DOUBLE;
+ l->value.floating=d;
+ l->string=rasqal_xsd_format_double(d, (size_t*)&l->string_len);
+ if(!l->string) {
+ rasqal_free_literal(l);
+ return NULL;
+ }
+ dt_uri=rasqal_xsd_datatype_type_to_uri(world, l->type);
+ if(!dt_uri) {
+ rasqal_free_literal(l);
+ return NULL;
+ }
+#ifdef RAPTOR_V2_AVAILABLE
+ l->datatype = raptor_uri_copy_v2(world->raptor_world_ptr, dt_uri);
+#else
+ l->datatype = raptor_uri_copy(dt_uri);
+#endif
+ }
+ return l;
+}
+
+
+/**
+ * rasqal_new_float_literal:
+ * @world: rasqal world object
+ * @f: float literal
+ *
+ * Constructor - Create a new Rasqal float literal.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_float_literal(rasqal_world *world, float f)
+{
+ raptor_uri* dt_uri;
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+ l->type=RASQAL_LITERAL_FLOAT;
+ l->value.floating=(double)f;
+ l->string=(unsigned char*)RASQAL_MALLOC(cstring, 30); /* FIXME */
+ if(!l->string) {
+ rasqal_free_literal(l);
+ return NULL;
+ }
+ sprintf((char*)l->string, "%1g", f);
+ l->string_len=strlen((const char*)l->string);
+ dt_uri=rasqal_xsd_datatype_type_to_uri(world, l->type);
+ if(!dt_uri) {
+ rasqal_free_literal(l);
+ return NULL;
+ }
+#ifdef RAPTOR_V2_AVAILABLE
+ l->datatype = raptor_uri_copy_v2(world->raptor_world_ptr, dt_uri);
+#else
+ l->datatype = raptor_uri_copy(dt_uri);
+#endif
+ }
+ return l;
+}
+
+
+/**
+ * rasqal_new_uri_literal:
+ * @world: rasqal world object
+ * @uri: #raptor_uri uri
+ *
+ * Constructor - Create a new Rasqal URI literal from a raptor URI.
+ *
+ * The uri is an input parameter and is stored in the literal, not copied.
+ * The uri is freed also on failure.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_uri_literal(rasqal_world* world, raptor_uri *uri)
+{
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+ l->type=RASQAL_LITERAL_URI;
+ l->value.uri=uri;
+ } else {
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, uri);
+#else
+ raptor_free_uri(uri);
+#endif
+ }
+ return l;
+}
+
+
+/**
+ * rasqal_new_pattern_literal:
+ * @world: rasqal world object
+ * @pattern: regex pattern
+ * @flags: regex flags
+ *
+ * Constructor - Create a new Rasqal pattern literal.
+ *
+ * The pattern and flags are input parameters and are stored in the
+ * literal, not copied. They are freed also on failure.
+ * The set of flags recognised depends on the regex library and the query
+ * language.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_pattern_literal(rasqal_world* world,
+ const unsigned char *pattern,
+ const char *flags)
+{
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+ l->type=RASQAL_LITERAL_PATTERN;
+ l->string=pattern;
+ l->string_len=strlen((const char*)pattern);
+ l->flags=(const unsigned char*)flags;
+ } else {
+ if(flags)
+ RASQAL_FREE(cstring, (void*)flags);
+ RASQAL_FREE(cstring, (void*)pattern);
+ }
+ return l;
+}
+
+
+/**
+ * rasqal_new_decimal_literal:
+ * @world: rasqal world object
+ * @string: decimal literal
+ *
+ * Constructor - Create a new Rasqal decimal literal.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_decimal_literal(rasqal_world* world, const unsigned char *string)
+{
+ return rasqal_new_decimal_literal_from_decimal(world, string, NULL);
+}
+
+
+/**
+ * rasqal_new_decimal_literal_from_decimal:
+ * @world: rasqal world object
+ * @string: decimal literal string
+ * @decimal: rasqal XSD Decimal
+ *
+ * Constructor - Create a new Rasqal decimal literal.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_decimal_literal_from_decimal(rasqal_world* world,
+ const unsigned char *string,
+ rasqal_xsd_decimal* decimal)
+{
+ rasqal_literal* l;
+ raptor_uri *dt_uri;
+
+ l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(!l)
+ return NULL;
+
+ l->usage=1;
+ l->world=world;
+ l->type=RASQAL_LITERAL_DECIMAL;
+ if(string) {
+ if(rasqal_literal_set_typed_value(l, l->type, string, NULL, NULL, 0)) {
+ rasqal_free_literal(l);
+ l=NULL;
+ }
+ } else if(decimal) {
+ dt_uri=rasqal_xsd_datatype_type_to_uri(world, l->type);
+ if(!dt_uri) {
+ rasqal_free_literal(l);
+ l=NULL;
+ } else {
+#ifdef RAPTOR_V2_AVAILABLE
+ l->datatype = raptor_uri_copy_v2(world->raptor_world_ptr, dt_uri);
+#else
+ l->datatype = raptor_uri_copy(dt_uri);
+#endif
+ l->value.decimal=decimal;
+ /* string is owned by l->value.decimal */
+ l->string=(unsigned char*)rasqal_xsd_decimal_as_counted_string(l->value.decimal,
+ (size_t*)&l->string_len);
+ if(!l->string) {
+ rasqal_free_literal(l);
+ l=NULL;
+ }
+ }
+ } else {
+ /* no string or decimal was given */
+ rasqal_free_literal(l);
+ l=NULL;
+ }
+
+ return l;
+}
+
+
+/**
+ * rasqal_new_numeric_literal:
+ * @world: rasqal world object
+ * @type: datatype
+ * @double: double
+ *
+ * INTERNAL - Make a numeric datatype from a double
+ *
+ * Return value: new literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_numeric_literal(rasqal_world* world, rasqal_literal_type type, double d)
+{
+ char buffer[30];
+
+ switch(type) {
+ case RASQAL_LITERAL_INTEGER:
+ return rasqal_new_integer_literal(world, type, (int)d);
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ return rasqal_new_double_literal(world, d);
+ break;
+
+ case RASQAL_LITERAL_FLOAT:
+ return rasqal_new_float_literal(world, d);
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ sprintf(buffer, "%g", d);
+ return rasqal_new_decimal_literal(world, (unsigned char*)buffer);
+ break;
+
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DATETIME:
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_VARIABLE:
+ RASQAL_FATAL2("Unexpected numeric type %d\n", type);
+ }
+
+ return NULL;
+}
+
+
+/*
+ * rasqal_literal_set_typed_value:
+ * @l: literal
+ * @type: type
+ * @string: string or NULL to use existing literal string
+ * @error_handler: error handling function
+ * @error_data: data for error handle
+ * @flags: non-0 to ignore type errors
+ *
+ * INTERNAL - Set a literal typed value
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+rasqal_literal_set_typed_value(rasqal_literal* l, rasqal_literal_type type,
+ const unsigned char* string,
+ raptor_simple_message_handler error_handler,
+ void *error_data, int flags)
+{
+ char *eptr;
+ raptor_uri* dt_uri;
+ int i;
+ double d;
+ const unsigned char *new_string;
+ int valid;
+
+ valid=rasqal_xsd_datatype_check(type, string ? string : l->string, flags);
+ if(!valid) {
+ if(!flags) {
+ if(error_handler)
+ error_handler(error_data, "Illegal type %s string '%s'",
+ rasqal_xsd_datatype_label(type), string ? string : l->string);
+ return 1;
+ }
+ return 0;
+ }
+
+ if(l->language) {
+ RASQAL_FREE(cstring, (void*)l->language);
+ l->language=NULL;
+ }
+ l->type=type;
+
+ if(string) {
+ if(l->string)
+ RASQAL_FREE(cstring, (void*)l->string);
+ l->string_len=strlen((const char*)string);
+ l->string=(unsigned char*)RASQAL_MALLOC(cstring, l->string_len+1);
+ if(!l->string)
+ return 1;
+ strncpy((char*)l->string, (const char*)string, l->string_len+1);
+ }
+
+ dt_uri=rasqal_xsd_datatype_type_to_uri(l->world, l->type);
+ if(!dt_uri)
+ return 1;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ if(l->datatype)
+ raptor_free_uri_v2(l->world->raptor_world_ptr, l->datatype);
+ l->datatype = raptor_uri_copy_v2(l->world->raptor_world_ptr, dt_uri);
+#else
+ if(l->datatype)
+ raptor_free_uri(l->datatype);
+ l->datatype = raptor_uri_copy(dt_uri);
+#endif
+
+ if(type == RASQAL_LITERAL_INTEGER)
+ l->parent_type=RASQAL_LITERAL_DECIMAL;
+
+ switch(type) {
+ case RASQAL_LITERAL_INTEGER:
+ eptr=NULL;
+ i=(int)strtol((const char*)l->string, &eptr, 10);
+ if(*eptr)
+ return 1;
+
+ l->value.integer=i;
+ l->parent_type=RASQAL_LITERAL_DECIMAL;
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ d=0.0;
+ (void)sscanf((char*)l->string, "%lf", &d);
+ l->value.floating=d;
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ l->value.decimal=rasqal_new_xsd_decimal();
+ if(!l->value.decimal) {
+ RASQAL_FREE(cstring, (void*)l->string);
+ return 1;
+ }
+ if(rasqal_xsd_decimal_set_string(l->value.decimal,
+ (const char*)l->string)) {
+ RASQAL_FREE(cstring, (void*)l->string);
+ return 1;
+ }
+ RASQAL_FREE(cstring, (void*)l->string);
+ /* string is owned by l->value.decimal */
+ l->string=(unsigned char*)rasqal_xsd_decimal_as_counted_string(l->value.decimal,
+ (size_t*)&l->string_len);
+ if(!l->string)
+ return 1;
+ break;
+
+ case RASQAL_LITERAL_BOOLEAN:
+ i=0;
+ if(!strcmp((const char*)l->string, "true") ||
+ !strcmp((const char*)l->string, "TRUE") ||
+ !strcmp((const char*)l->string, "1"))
+ i=1;
+
+ /* Free passed in string */
+ RASQAL_FREE(cstring, (void*)l->string);
+ /* and replace with a static string */
+ l->string=i ? RASQAL_XSD_BOOLEAN_TRUE : RASQAL_XSD_BOOLEAN_FALSE;
+ l->string_len=(i ? 4 : 5);
+
+ l->value.integer=i;
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ /* No change - kept as a string */
+ break;
+
+ case RASQAL_LITERAL_DATETIME:
+ new_string=rasqal_xsd_datetime_string_to_canonical(l->string);
+ if(new_string) {
+ RASQAL_DEBUG3("converted xsd:dateTime \"%s\" to canonical form \"%s\"\n", l->string, new_string);
+ RASQAL_FREE(cstring, l->string);
+ l->string=new_string;
+ l->string_len=strlen((const char*)l->string);
+ break; /* success */
+ }
+ RASQAL_DEBUG2("rasqal_xsd_datetime_string_to_canonical(\"%s\") failed\n", l->string);
+ return 1; /* error */
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_VARIABLE:
+ RASQAL_FATAL2("Unexpected native type %d\n", type);
+ break;
+
+ default:
+ RASQAL_FATAL2("Unknown native type %d\n", type);
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * rasqal_literal_string_to_native:
+ * @l: #rasqal_literal to operate on inline
+ * @error_handler: error handling function
+ * @error_data: data for error handle
+ * @flags: flags for literal checking. non-0 to ignore type errors
+ *
+ * INTERNAL Upgrade a datatyped literal string to an internal typed literal
+ *
+ * At present this promotes datatyped literals
+ * xsd:integer to RASQAL_LITERAL_INTEGER
+ * xsd:double to RASQAL_LITERAL_DOUBLE
+ * xsd:float to RASQAL_LITERAL_FLOAT
+ * xsd:boolean to RASQAL_LITERAL_BOOLEAN
+ * xsd:decimal to RASQAL_LITERAL_DECIMAL
+ * xsd:dateTime to RASQAL_LITERAL_DATETIME
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_literal_string_to_native(rasqal_literal *l,
+ raptor_simple_message_handler error_handler,
+ void *error_data, int flags)
+{
+ rasqal_literal_type native_type=RASQAL_LITERAL_UNKNOWN;
+ int rc=0;
+
+ /* RDF literal with no datatype (plain literal) */
+ if(!l->datatype)
+ return 0;
+
+ native_type=rasqal_xsd_datatype_uri_to_type(l->world, l->datatype);
+
+ /* If not a native type return ok but do not change literal */
+ if(native_type == RASQAL_LITERAL_UNKNOWN)
+ return 0;
+ /* xsd:string but nothing need be done */
+ if(native_type == RASQAL_LITERAL_STRING)
+ return 0;
+
+ rc=rasqal_literal_set_typed_value(l, native_type, NULL /* existing string */,
+ error_handler, error_data, flags);
+ return rc;
+}
+
+
+/*
+ * rasqal_new_string_literal_common:
+ * @world: rasqal world object
+ * @string: UTF-8 string lexical form
+ * @language: RDF language (xml:lang) (or NULL)
+ * @datatype: datatype URI (or NULL for plain literal)
+ * @datatype_qname: datatype qname string (or NULL for plain literal)
+ * @flags: flags - 1 to do native type promotion
+ *
+ * INTERNAL Constructor - Create a new Rasqal string literal.
+ *
+ * All parameters are input parameters and if present are stored in
+ * the literal, not copied. They are freed also on failure.
+ *
+ * The datatype and datatype_qname parameters are alternatives; the
+ * qname is a datatype that cannot be resolved till later since the
+ * prefixes have not yet been declared or checked.
+ *
+ * If the string literal is datatyped and of certain types recognised
+ * it may be converted to a different literal type by
+ * rasqal_literal_string_to_native() only if @flags is 1.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+static rasqal_literal*
+rasqal_new_string_literal_common(rasqal_world* world,
+ const unsigned char *string,
+ const char *language,
+ raptor_uri *datatype,
+ const unsigned char *datatype_qname,
+ int flags)
+{
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+
+ if(datatype && language) {
+ /* RDF typed literal but this is not allowed so delete language */
+ RASQAL_FREE(cstring, (void*)language);
+ language=NULL;
+ }
+
+ l->type=RASQAL_LITERAL_STRING;
+ l->string=string;
+ l->string_len=strlen((const char*)string);
+ l->language=language;
+ l->datatype=datatype;
+ l->flags=datatype_qname;
+
+ if(datatype)
+ /* This is either RASQAL_LITERAL_DECIMAL or ...INTEGER or ...UNKNOWN */
+ l->parent_type=rasqal_xsd_datatype_uri_parent_type(world, datatype);
+
+ if((flags == 1) && rasqal_literal_string_to_native(l, NULL, NULL, 1)) {
+ rasqal_free_literal(l);
+ l=NULL;
+ }
+ } else {
+ if(language)
+ RASQAL_FREE(cstring, (void*)language);
+ if(datatype)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, datatype);
+#else
+ raptor_free_uri(datatype);
+#endif
+ if(datatype_qname)
+ RASQAL_FREE(cstring, (void*)datatype_qname);
+ RASQAL_FREE(cstring, (void*)string);
+ }
+
+ return l;
+}
+
+
+/**
+ * rasqal_new_string_literal:
+ * @world: rasqal world object
+ * @string: UTF-8 string lexical form
+ * @language: RDF language (xml:lang) (or NULL)
+ * @datatype: datatype URI (or NULL for plain literal)
+ * @datatype_qname: datatype qname string (or NULL for plain literal)
+ *
+ * Constructor - Create a new Rasqal string literal.
+ *
+ * All parameters are input parameters and if present are stored in
+ * the literal, not copied. They are freed also on failure.
+ *
+ * The datatype and datatype_qname parameters are alternatives; the
+ * qname is a datatype that cannot be resolved till later since the
+ * prefixes have not yet been declared or checked.
+ *
+ * If the string literal is datatyped and of certain types recognised
+ * it may be converted to a different literal type by
+ * rasqal_literal_string_to_native()
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_string_literal(rasqal_world* world,
+ const unsigned char *string,
+ const char *language,
+ raptor_uri *datatype,
+ const unsigned char *datatype_qname)
+{
+ return rasqal_new_string_literal_common(world, string, language, datatype,
+ datatype_qname, 1);
+}
+
+rasqal_literal*
+rasqal_new_string_literal_node(rasqal_world* world, const unsigned char *string,
+ const char *language, raptor_uri *datatype)
+{
+ return rasqal_new_string_literal_common(world, string, language, datatype, NULL, 0);
+}
+
+
+/**
+ * rasqal_new_simple_literal:
+ * @world: rasqal world object
+ * @type: RASQAL_LITERAL_BLANK or RASQAL_LITERAL_BLANK_QNAME
+ * @string: the UTF-8 string value to store
+ *
+ * Constructor - Create a new Rasqal simple literal.
+ *
+ * The string is an input parameter and is stored in the
+ * literal, not copied. It is freed also on failure.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_simple_literal(rasqal_world* world,
+ rasqal_literal_type type,
+ const unsigned char *string)
+{
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+ l->type=type;
+ l->string=string;
+ l->string_len=strlen((const char*)string);
+ } else {
+ RASQAL_FREE(cstring, (void*)string);
+ }
+ return l;
+}
+
+
+/**
+ * rasqal_new_boolean_literal:
+ * @world: rasqal world object
+ * @value: non-0 for true, 0 for false
+ *
+ * Constructor - Create a new Rasqal boolean literal.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_boolean_literal(rasqal_world* world, int value)
+{
+ raptor_uri* dt_uri;
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+ l->type=RASQAL_LITERAL_BOOLEAN;
+ l->value.integer=value;
+ l->string=value ? RASQAL_XSD_BOOLEAN_TRUE : RASQAL_XSD_BOOLEAN_FALSE;
+ l->string_len=(value ? 4 : 5);
+ dt_uri=rasqal_xsd_datatype_type_to_uri(world, l->type);
+ if(!dt_uri) {
+ rasqal_free_literal(l);
+ return NULL;
+ }
+#ifdef RAPTOR_V2_AVAILABLE
+ l->datatype = raptor_uri_copy_v2(world->raptor_world_ptr, dt_uri);
+#else
+ l->datatype = raptor_uri_copy(dt_uri);
+#endif
+ }
+ return l;
+}
+
+
+/**
+ * rasqal_new_variable_literal:
+ * @world: rasqal_world object
+ * @variable: #rasqal_variable to use
+ *
+ * Constructor - Create a new Rasqal variable literal.
+ *
+ * variable is an input parameter and stored in the literal, not copied.
+ *
+ * Return value: New #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_new_variable_literal(rasqal_world* world, rasqal_variable *variable)
+{
+ rasqal_literal* l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(l) {
+ l->usage=1;
+ l->world=world;
+ l->type=RASQAL_LITERAL_VARIABLE;
+ l->value.variable=variable;
+ }
+
+ /* Do not rasqal_free_variable(variable) on error since
+ * all variables are shared and owned by rasqal_query
+ * variables_sequence */
+
+ return l;
+}
+
+
+/**
+ * rasqal_new_literal_from_literal:
+ * @l: #rasqal_literal object to copy
+ *
+ * Copy Constructor - create a new rasqal_literal object from an existing rasqal_literal object.
+ *
+ * Return value: a new #rasqal_literal object or NULL
+ **/
+rasqal_literal*
+rasqal_new_literal_from_literal(rasqal_literal* l)
+{
+ if(!l)
+ return NULL;
+
+ l->usage++;
+ return l;
+}
+
+
+/**
+ * rasqal_free_literal:
+ * @l: #rasqal_literal object
+ *
+ * Destructor - destroy an rasqal_literal object.
+ *
+ **/
+void
+rasqal_free_literal(rasqal_literal* l)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(l, rasqal_literal);
+
+ if(--l->usage)
+ return;
+
+ switch(l->type) {
+ case RASQAL_LITERAL_URI:
+ if(l->value.uri)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(l->world->raptor_world_ptr, l->value.uri);
+#else
+ raptor_free_uri(l->value.uri);
+#endif
+ break;
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DATETIME:
+ if(l->string)
+ RASQAL_FREE(cstring, (void*)l->string);
+ if(l->language)
+ RASQAL_FREE(cstring, (void*)l->language);
+ if(l->datatype)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(l->world->raptor_world_ptr, l->datatype);
+#else
+ raptor_free_uri(l->datatype);
+#endif
+ if(l->type == RASQAL_LITERAL_STRING ||
+ l->type == RASQAL_LITERAL_PATTERN) {
+ if(l->flags)
+ RASQAL_FREE(cstring, (void*)l->flags);
+ }
+ break;
+ case RASQAL_LITERAL_DECIMAL:
+ /* l->string is owned by l->value.decimal - do not free it */
+ if(l->datatype)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(l->world->raptor_world_ptr, l->datatype);
+#else
+ raptor_free_uri(l->datatype);
+#endif
+ if(l->value.decimal)
+ rasqal_free_xsd_decimal(l->value.decimal);
+ break;
+
+ case RASQAL_LITERAL_BOOLEAN:
+ /* static l->string for boolean, does not need freeing */
+ if(l->datatype)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(l->world->raptor_world_ptr, l->datatype);
+#else
+ raptor_free_uri(l->datatype);
+#endif
+ break;
+
+ case RASQAL_LITERAL_VARIABLE:
+ /* It is correct that this is not called here
+ * since all variables are shared and owned by
+ * the rasqal_query sequence variables_sequence */
+
+ /* rasqal_free_variable(l->value.variable); */
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown literal type %d", l->type);
+ }
+ RASQAL_FREE(rasqal_literal, l);
+}
+
+
+/*
+ * The order here must match that of rasqal_literal_type
+ * in rasqal.h and is significant as rasqal_literal_compare
+ * uses it for type comparisons with the RASQAL_COMPARE_XQUERY
+ * flag.
+ */
+static const char* const rasqal_literal_type_labels[RASQAL_LITERAL_LAST+1]={
+ "UNKNOWN",
+ "blank",
+ "uri",
+ "string",
+ "boolean",
+ "integer",
+ "double",
+ "float",
+ "decimal",
+ "datetime",
+ "pattern",
+ "qname",
+ "variable"
+};
+
+
+/**
+ * rasqal_literal_write_type:
+ * @l: the #rasqal_literal object
+ * @iostr: the #raptor_iostream handle to print to
+ *
+ * Write a string form for a rasqal literal type to an iostream
+ *
+ **/
+void
+rasqal_literal_write_type(rasqal_literal* l, raptor_iostream* iostr)
+{
+ rasqal_literal_type type;
+
+ if(!l) {
+ raptor_iostream_write_counted_string(iostr, "null", 4);
+ return;
+ }
+
+ type=l->type;
+ if(type > RASQAL_LITERAL_LAST)
+ type=RASQAL_LITERAL_UNKNOWN;
+ raptor_iostream_write_string(iostr, rasqal_literal_type_labels[(int)type]);
+}
+
+
+/**
+ * rasqal_literal_print_type:
+ * @l: the #rasqal_literal object
+ * @fh: the #FILE* handle to print to
+ *
+ * Print a string form for a rasqal literal type.
+ *
+ **/
+void
+rasqal_literal_print_type(rasqal_literal* l, FILE* fh)
+{
+ rasqal_literal_type type;
+
+ if(!l) {
+ fputs("null", fh);
+ return;
+ }
+
+ type=l->type;
+ if(type > RASQAL_LITERAL_LAST)
+ type=RASQAL_LITERAL_UNKNOWN;
+ fputs(rasqal_literal_type_labels[(int)type], fh);
+}
+
+
+/**
+ * rasqal_literal_write:
+ * @l: the #rasqal_literal object
+ * @iostr: the #raptor_iostream handle to write to
+ *
+ * Write a Rasqal literal to an iostream in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_literal_write(rasqal_literal* l, raptor_iostream* iostr)
+{
+ const unsigned char*str;
+ size_t len;
+
+ if(!l) {
+ raptor_iostream_write_counted_string(iostr, "null", 4);
+ return;
+ }
+
+ if(l->type != RASQAL_LITERAL_VARIABLE)
+ rasqal_literal_write_type(l, iostr);
+
+ switch(l->type) {
+ case RASQAL_LITERAL_URI:
+ raptor_iostream_write_byte(iostr, '<');
+#ifdef RAPTOR_V2_AVAILABLE
+ str = raptor_uri_as_counted_string_v2(l->world->raptor_world_ptr, l->value.uri, &len);
+#else
+ str = raptor_uri_as_counted_string(l->value.uri, &len);
+#endif
+ raptor_iostream_write_string_ntriples(iostr, str, len, '>');
+ raptor_iostream_write_byte(iostr, '>');
+ break;
+ case RASQAL_LITERAL_BLANK:
+ raptor_iostream_write_byte(iostr, ' ');
+ raptor_iostream_write_counted_string(iostr, l->string, l->string_len);
+ break;
+ case RASQAL_LITERAL_PATTERN:
+ raptor_iostream_write_byte(iostr, '/');
+ raptor_iostream_write_counted_string(iostr, l->string, l->string_len);
+ raptor_iostream_write_byte(iostr, '/');
+ if(l->flags)
+ raptor_iostream_write_string(iostr, l->flags);
+ break;
+ case RASQAL_LITERAL_STRING:
+ raptor_iostream_write_counted_string(iostr, "(\"", 2);
+ raptor_iostream_write_string_ntriples(iostr, l->string, l->string_len, '"');
+ raptor_iostream_write_byte(iostr, '"');
+ if(l->language) {
+ raptor_iostream_write_byte(iostr, '@');
+ raptor_iostream_write_string(iostr, l->language);
+ }
+ if(l->datatype) {
+ raptor_iostream_write_counted_string(iostr, "^^<", 3);
+#ifdef RAPTOR_V2_AVAILABLE
+ str = raptor_uri_as_counted_string_v2(l->world->raptor_world_ptr, l->datatype, &len);
+#else
+ str = raptor_uri_as_counted_string(l->datatype, &len);
+#endif
+ raptor_iostream_write_string_ntriples(iostr, str, len, '>');
+ raptor_iostream_write_byte(iostr, '>');
+ }
+ raptor_iostream_write_byte(iostr, ')');
+ break;
+ case RASQAL_LITERAL_VARIABLE:
+ rasqal_variable_write(l->value.variable, iostr);
+ break;
+
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ raptor_iostream_write_byte(iostr, '(');
+ raptor_iostream_write_counted_string(iostr, l->string, l->string_len);
+ raptor_iostream_write_byte(iostr, ')');
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown literal type %d", l->type);
+ }
+}
+
+
+
+/**
+ * rasqal_literal_print:
+ * @l: the #rasqal_literal object
+ * @fh: the #FILE* handle to print to
+ *
+ * Print a Rasqal literal in a debug format.
+ *
+ * The print debug format may change in any release.
+ **/
+void
+rasqal_literal_print(rasqal_literal* l, FILE* fh)
+{
+ if(!l) {
+ fputs("null", fh);
+ return;
+ }
+
+ if(l->type != RASQAL_LITERAL_VARIABLE)
+ rasqal_literal_print_type(l, fh);
+
+ switch(l->type) {
+ case RASQAL_LITERAL_URI:
+ fputc('<', fh);
+ raptor_print_ntriples_string(fh,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(l->world->raptor_world_ptr, l->value.uri),
+#else
+ raptor_uri_as_string(l->value.uri),
+#endif
+ '>');
+ fputc('>', fh);
+ break;
+ case RASQAL_LITERAL_BLANK:
+ fprintf(fh, " %s", l->string);
+ break;
+ case RASQAL_LITERAL_PATTERN:
+ fprintf(fh, "/%s/%s", l->string, l->flags ? (const char*)l->flags : "");
+ break;
+ case RASQAL_LITERAL_STRING:
+ fputs("(\"", fh);
+ raptor_print_ntriples_string(fh, l->string, '"');
+ fputc('"', fh);
+ if(l->language)
+ fprintf(fh, "@%s", l->language);
+ if(l->datatype) {
+ fputs("^^<", fh);
+ raptor_print_ntriples_string(fh,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(l->world->raptor_world_ptr, l->datatype),
+#else
+ raptor_uri_as_string(l->datatype),
+#endif
+ '>');
+ fputc('>', fh);
+ }
+ fputc(')', fh);
+ break;
+ case RASQAL_LITERAL_VARIABLE:
+ rasqal_variable_print(l->value.variable, fh);
+ break;
+
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ fputc('(', fh);
+ fwrite(l->string, 1, l->string_len, fh);
+ fputc(')', fh);
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown literal type %d", l->type);
+ }
+}
+
+
+
+/*
+ * rasqal_literal_as_boolean:
+ * @l: #rasqal_literal object
+ * @error: pointer to error flag
+ *
+ * INTERNAL: Return a literal as a boolean value
+ *
+ * SPARQL Effective Boolean Value (EBV) rules:
+ * - If the argument is a typed literal with a datatype of xsd:boolean, the
+ * EBV is the value of that argument.
+ * - If the argument is a plain literal or a typed literal with a datatype of
+ * xsd:string, the EBV is false if the operand value has zero length;
+ * otherwise the EBV is true.
+ * - If the argument is a numeric type or a typed literal with a datatype
+ * derived from a numeric type, the EBV is false if the operand value is NaN
+ * or is numerically equal to zero; otherwise the EBV is true.
+ * - All other arguments, including unbound arguments, produce a type error.
+ *
+ * Return value: non-0 if true
+ **/
+int
+rasqal_literal_as_boolean(rasqal_literal* l, int *error)
+{
+ if(!l)
+ return 0;
+
+ switch(l->type) {
+ case RASQAL_LITERAL_STRING:
+ if(l->datatype) {
+ if(
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_equals_v2(l->world->raptor_world_ptr, l->datatype,
+ rasqal_xsd_datatype_type_to_uri(l->world, RASQAL_LITERAL_STRING))
+#else
+ raptor_uri_equals(l->datatype,
+ rasqal_xsd_datatype_type_to_uri(l->world, RASQAL_LITERAL_STRING))
+#endif
+ )
+ {
+ /* typed literal with xsd:string datatype -> true if non-empty */
+ return l->string && *l->string;
+ }
+ /* typed literal with other datatype -> type error */
+ *error = 1;
+ return 0;
+ }
+ /* plain literal -> true if non-empty */
+ return l->string && *l->string;
+
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ *error = 1;
+ return 0;
+ break;
+
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ return l->value.integer != 0;
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ return l->value.floating != 0.0 && !isnan(l->value.floating);
+ break;
+
+ case RASQAL_LITERAL_VARIABLE:
+ return rasqal_literal_as_boolean(l->value.variable->value, error);
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown literal type %d", l->type);
+ return 0; /* keep some compilers happy */
+ }
+}
+
+
+/*
+ * rasqal_literal_as_integer - INTERNAL Return a literal as an integer value
+ * @l: #rasqal_literal object
+ * @error: pointer to error flag
+ *
+ * Integers, booleans, double and float literals natural are turned into
+ * integers. If string values are the lexical form of an integer, that is
+ * returned. Otherwise the error flag is set.
+ *
+ * Return value: integer value
+ **/
+int
+rasqal_literal_as_integer(rasqal_literal* l, int *error)
+{
+ if(!l)
+ return 0;
+
+ switch(l->type) {
+ case RASQAL_LITERAL_INTEGER:
+ return l->value.integer;
+ break;
+
+ case RASQAL_LITERAL_BOOLEAN:
+ return l->value.integer != 0;
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ return (int)l->value.floating;
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ return (int)rasqal_xsd_decimal_get_double(l->value.decimal);
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ {
+ char *eptr;
+ double d;
+ int v;
+
+ eptr=NULL;
+ v=(int)strtol((const char*)l->string, &eptr, 10);
+ if((unsigned char*)eptr != l->string && *eptr=='\0')
+ return v;
+
+ eptr=NULL;
+ d=strtod((const char*)l->string, &eptr);
+ if((unsigned char*)eptr != l->string && *eptr=='\0')
+ return (int)d;
+ }
+ if(error)
+ *error=1;
+ return 0;
+ break;
+
+ case RASQAL_LITERAL_VARIABLE:
+ return rasqal_literal_as_integer(l->value.variable->value, error);
+ break;
+
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_DATETIME:
+ if(error)
+ *error=1;
+ return 0;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown literal type %d", l->type);
+ return 0; /* keep some compilers happy */
+ }
+}
+
+
+/*
+ * rasqal_literal_as_floating - INTERNAL Return a literal as a floating value
+ * @l: #rasqal_literal object
+ * @error: pointer to error flag
+ *
+ * Integers, booleans, double and float literals natural are turned into
+ * integers. If string values are the lexical form of an floating, that is
+ * returned. Otherwise the error flag is set.
+ *
+ * Return value: floating value
+ **/
+double
+rasqal_literal_as_floating(rasqal_literal* l, int *error)
+{
+ if(!l)
+ return 0;
+
+ switch(l->type) {
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ return (double)l->value.integer;
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ return l->value.floating;
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ return rasqal_xsd_decimal_get_double(l->value.decimal);
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ {
+ char *eptr=NULL;
+ double d=strtod((const char*)l->string, &eptr);
+ if((unsigned char*)eptr != l->string && *eptr=='\0')
+ return d;
+ }
+ if(error)
+ *error=1;
+ return 0.0;
+ break;
+
+ case RASQAL_LITERAL_VARIABLE:
+ return rasqal_literal_as_integer(l->value.variable->value, error);
+ break;
+
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_DATETIME:
+ if(error)
+ *error=1;
+ return 0.0;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown literal type %d", l->type);
+ return 0.0; /* keep some compilers happy */
+ }
+}
+
+
+/*
+ * rasqal_literal_as_uri - INTERNAL Return a literal as a raptor_uri*
+ * @l: #rasqal_literal object
+ *
+ * Return value: raptor_uri* value or NULL on failure
+ **/
+raptor_uri*
+rasqal_literal_as_uri(rasqal_literal* l)
+{
+ if(!l)
+ return NULL;
+
+ if(l->type==RASQAL_LITERAL_URI)
+ return l->value.uri;
+
+ if(l->type==RASQAL_LITERAL_VARIABLE)
+ return rasqal_literal_as_uri(l->value.variable->value);
+
+ RASQAL_FATAL2("Literal type %d has no URI value", l->type);
+
+ return NULL;
+}
+
+
+/**
+ * rasqal_literal_as_string_flags:
+ * @l: #rasqal_literal object
+ * @flags: comparison flags
+ * @error: pointer to error
+ *
+ * Return the string format of a literal according to flags.
+ *
+ * flag bits affects conversion:
+ * RASQAL_COMPARE_XQUERY: use XQuery conversion rules
+ *
+ * If @error is not NULL, *error is set to non-0 on error
+ *
+ * Return value: pointer to a shared string format of the literal.
+ **/
+const unsigned char*
+rasqal_literal_as_string_flags(rasqal_literal* l, int flags, int *error)
+{
+ if(!l)
+ return NULL;
+
+ switch(l->type) {
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ return l->string;
+
+ case RASQAL_LITERAL_URI:
+ if(flags & RASQAL_COMPARE_XQUERY) {
+ if(error)
+ *error=1;
+ return NULL;
+ }
+#ifdef RAPTOR_V2_AVAILABLE
+ return raptor_uri_as_string_v2(l->world->raptor_world_ptr, l->value.uri);
+#else
+ return raptor_uri_as_string(l->value.uri);
+#endif
+
+ case RASQAL_LITERAL_VARIABLE:
+ return rasqal_literal_as_string_flags(l->value.variable->value, flags,
+ error);
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown literal type %d", l->type);
+ return NULL; /* keep some compilers happy */
+ }
+}
+
+
+/**
+ * rasqal_literal_as_string:
+ * @l: #rasqal_literal object
+ *
+ * Return the string format of a literal.
+ *
+ * Return value: pointer to a shared string format of the literal.
+ **/
+const unsigned char*
+rasqal_literal_as_string(rasqal_literal* l)
+{
+ return rasqal_literal_as_string_flags(l, 0, NULL);
+}
+
+/**
+ * rasqal_literal_as_variable:
+ * @l: #rasqal_literal object
+ *
+ * Get the variable inside a literal.
+ *
+ * Return value: the #rasqal_variable or NULL if the literal is not a variable
+ **/
+rasqal_variable*
+rasqal_literal_as_variable(rasqal_literal* l)
+{
+ return (l->type == RASQAL_LITERAL_VARIABLE) ? l->value.variable : NULL;
+}
+
+
+/**
+ * rasqal_literal_promote_numerics:
+ * @l1: first literal
+ * @l2: second literal
+ * @flags: promotion flags
+ *
+ * INTERNAL - Calculate the type to promote a pair of literals to
+ *
+ * Numeric type promotion
+ * http://www.w3.org/TR/xpath20/#dt-type-promotion
+ *
+ * [[xs:decimal (or any type derived by restriction from xs:decimal,
+ * including xs:integer) can be promoted to either of the types
+ * xs:float or xs:double.]]
+ *
+ * For here that means xs:integer to xs:double and xs:decimal to xs:double
+ *
+ * Return value: promote type or RASQAL_LITERAL_UNKNOWN
+ */
+static rasqal_literal_type
+rasqal_literal_promote_numerics(rasqal_literal* l1, rasqal_literal* l2,
+ int flags)
+{
+ rasqal_literal_type type1=l1->type;
+ rasqal_literal_type type2=l2->type;
+
+ /* No promotion needed */
+ if(type1 == type2)
+ return type1;
+
+ /* No parents - no promotion possible */
+ if(l1->parent_type == RASQAL_LITERAL_UNKNOWN &&
+ l2->parent_type == RASQAL_LITERAL_UNKNOWN)
+ return l1->parent_type;
+
+ /* First promotion is to xsd:integer */
+ if(l1->parent_type == RASQAL_LITERAL_INTEGER &&
+ type2 == RASQAL_LITERAL_INTEGER)
+ return type2;
+
+ if(l2->parent_type == RASQAL_LITERAL_INTEGER &&
+ type1 == RASQAL_LITERAL_INTEGER)
+ return type1;
+
+ if(l1->parent_type == RASQAL_LITERAL_INTEGER)
+ type1=RASQAL_LITERAL_INTEGER;
+ if(l2->parent_type == RASQAL_LITERAL_INTEGER)
+ type2=RASQAL_LITERAL_INTEGER;
+
+ if(type1 == type2)
+ return type1;
+
+ /* Second promotion is to xsd:decimal */
+ if(type1 == RASQAL_LITERAL_INTEGER)
+ type1=RASQAL_LITERAL_DECIMAL;
+ if(type2 == RASQAL_LITERAL_INTEGER)
+ type2=RASQAL_LITERAL_DECIMAL;
+
+ if(type1 == type2)
+ return type1;
+
+ /* Third/Fourth promotions are either to xsd:float or xsd:double */
+ if(type1 == RASQAL_LITERAL_FLOAT || type2 == RASQAL_LITERAL_FLOAT)
+ return RASQAL_LITERAL_FLOAT;
+
+ if(type1 == RASQAL_LITERAL_DOUBLE || type2 == RASQAL_LITERAL_DOUBLE)
+ return RASQAL_LITERAL_DOUBLE;
+
+ /* failed! */
+ return RASQAL_LITERAL_UNKNOWN;
+}
+
+
+/**
+ * rasqal_literal_get_rdf_term_type:
+ * @l: literal
+ *
+ * INTERNAL - Get the RDF term type of a literal
+ *
+ * Return value: type or RASQAL_LITERAL_UNKNOWN if cannot be an RDF term
+ */
+rasqal_literal_type
+rasqal_literal_get_rdf_term_type(rasqal_literal* l)
+{
+ rasqal_literal_type type;
+ type=(l->parent_type != RASQAL_LITERAL_UNKNOWN) ? l->parent_type : l->type;
+
+ /* squash literal datatypes into one type: RDF Literal */
+ if(type >= RASQAL_LITERAL_FIRST_XSD &&
+ type <= RASQAL_LITERAL_LAST_XSD)
+ type = RASQAL_LITERAL_STRING;
+
+ if(type != RASQAL_LITERAL_URI &&
+ type != RASQAL_LITERAL_STRING &&
+ type != RASQAL_LITERAL_BLANK)
+ type=RASQAL_LITERAL_UNKNOWN;
+
+ return type;
+}
+
+
+static rasqal_literal*
+rasqal_new_literal_from_promotion(rasqal_literal* lit,
+ rasqal_literal_type type)
+{
+ rasqal_literal* new_lit=NULL;
+ int errori=0;
+ double d;
+ int i;
+ unsigned char *new_s=NULL;
+ const unsigned char* s;
+ size_t len;
+
+ if(lit->type == type)
+ return rasqal_new_literal_from_literal(lit);
+
+ RASQAL_DEBUG3("promoting literal type %s to type %s\n",
+ rasqal_literal_type_labels[lit->type],
+ rasqal_literal_type_labels[type]);
+
+ /* May not promote to non-numerics */
+ if(!rasqal_xsd_datatype_is_numeric(type)) {
+ RASQAL_DEBUG2("NOT promoting to non-numeric type %s\n",
+ rasqal_literal_type_labels[lit->type]);
+
+ if(type == RASQAL_LITERAL_STRING) {
+ s=rasqal_literal_as_string(lit);
+ len=strlen((const char*)s);
+ new_s=(unsigned char*)RASQAL_MALLOC(sstring, len+1);
+ if(new_s) {
+ strncpy((char*)new_s, (const char*)s, len+1);
+ return rasqal_new_string_literal(lit->world, new_s, NULL, NULL, NULL);
+ } else
+ return NULL;
+ }
+ return NULL;
+ }
+
+ switch(type) {
+ case RASQAL_LITERAL_DECIMAL:
+ new_lit=rasqal_new_decimal_literal(lit->world, rasqal_literal_as_string(lit));
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ d=rasqal_literal_as_floating(lit, &errori);
+ /* failure always means no match */
+ if(errori)
+ new_lit=NULL;
+ else
+ new_lit=rasqal_new_double_literal(lit->world, d);
+ break;
+
+ case RASQAL_LITERAL_FLOAT:
+ d=rasqal_literal_as_floating(lit, &errori);
+ /* failure always means no match */
+ if(errori)
+ new_lit=NULL;
+ else
+ new_lit=rasqal_new_float_literal(lit->world, d);
+ break;
+
+
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ i=rasqal_literal_as_integer(lit, &errori);
+ /* failure always means no match */
+ if(errori)
+ new_lit=NULL;
+ else
+ new_lit=rasqal_new_integer_literal(lit->world, type, i);
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ s=rasqal_literal_as_string(lit);
+ len=strlen((const char*)s);
+ new_s=(unsigned char*)RASQAL_MALLOC(sstring, len+1);
+ if(new_s) {
+ strncpy((char*)new_s, (const char*)s, len+1);
+ new_lit=rasqal_new_string_literal(lit->world, new_s, NULL, NULL, NULL);
+ }
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_DATETIME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_VARIABLE:
+ default:
+ errori=1;
+ new_lit=NULL;
+ }
+
+#ifdef RASQAL_DEBUG
+ if(new_lit)
+ RASQAL_DEBUG4("promoted literal type %s to type %s, with value '%s'\n",
+ rasqal_literal_type_labels[new_lit->type],
+ rasqal_literal_type_labels[type],
+ rasqal_literal_as_string(new_lit));
+ else
+ RASQAL_DEBUG3("failed to promote literal type %s to type %s\n",
+ rasqal_literal_type_labels[lit->type],
+ rasqal_literal_type_labels[type]);
+#endif
+
+ return new_lit;
+}
+
+
+static int
+rasqal_literal_string_compare(rasqal_literal* l1, rasqal_literal* l2,
+ int flags, int* error)
+{
+ if(l1->type != RASQAL_LITERAL_STRING ||
+ l2->type != RASQAL_LITERAL_STRING) {
+ if(error)
+ *error=0;
+ return 0;
+ }
+
+ if(l1->language || l2->language) {
+ /* if either is null, the comparison fails */
+ if(!l1->language || !l2->language)
+ return 1;
+ if(rasqal_strcasecmp(l1->language, l2->language))
+ return 1;
+ }
+
+ if(l1->datatype || l2->datatype) {
+ int result;
+
+ /* there is no ordering between typed and plain literals:
+ if either is NULL, do not compare but return an error
+ (also implies inequality) */
+ if(!l1->datatype || !l2->datatype) {
+ if(error)
+ *error=1;
+ return 0;
+ }
+#ifdef RAPTOR_V2_AVAILABLE
+ result = raptor_uri_compare_v2(l1->world->raptor_world_ptr, l1->datatype, l2->datatype);
+#else
+ result = raptor_uri_compare(l1->datatype, l2->datatype);
+#endif
+
+ if(result)
+ return result;
+ }
+
+ if(flags & RASQAL_COMPARE_NOCASE)
+ return rasqal_strcasecmp((const char*)l1->string, (const char*)l2->string);
+ else
+ return strcmp((const char*)l1->string, (const char*)l2->string);
+}
+
+
+static rasqal_literal_type
+rasqal_literal_rdql_promote_calculate(rasqal_literal* l1, rasqal_literal* l2)
+{
+ int seen_string=0;
+ int seen_int=0;
+ int seen_double=0;
+ int seen_boolean=0;
+ int i;
+ rasqal_literal *lits[2];
+ rasqal_literal_type type=RASQAL_LITERAL_UNKNOWN;
+
+ lits[0]=l1;
+ lits[1]=l2;
+
+ for(i=0; i<2; i++) {
+ switch(lits[i]->type) {
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_DECIMAL:
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_DATETIME:
+ seen_string++;
+ break;
+
+ case RASQAL_LITERAL_BOOLEAN:
+ seen_boolean=1;
+ break;
+
+ case RASQAL_LITERAL_INTEGER:
+ seen_int++;
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ seen_double++;
+ break;
+
+ case RASQAL_LITERAL_VARIABLE:
+ /* this case was dealt with elsewhere */
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Unknown literal type %d", lits[i]->type);
+ }
+ }
+
+
+ if(lits[0]->type != lits[1]->type) {
+ type=seen_string ? RASQAL_LITERAL_STRING : RASQAL_LITERAL_INTEGER;
+ if((seen_int & seen_double) || (seen_int & seen_string))
+ type=RASQAL_LITERAL_DOUBLE;
+ if(seen_boolean & seen_string)
+ type=RASQAL_LITERAL_STRING;
+ } else
+ type=lits[0]->type;
+
+ return type;
+}
+
+
+
+/**
+ * rasqal_literal_compare:
+ * @l1: #rasqal_literal first literal
+ * @l2: #rasqal_literal second literal
+ * @flags: comparison flags
+ * @error: pointer to error
+ *
+ * Compare two literals with type promotion.
+ *
+ * The two literals are compared across their range. If the types
+ * are not the same, they are promoted. If one is a double or float, the
+ * other is promoted to double, otherwise for integers, otherwise
+ * to strings (all literals have a string value).
+ *
+ * The comparison returned is as for strcmp, first before second
+ * returns <0. equal returns 0, and first after second returns >0.
+ * For URIs, the string value is used for the comparsion.
+ *
+ * flag bits affects comparisons:
+ * RASQAL_COMPARE_NOCASE: use case independent string comparisons
+ * RASQAL_COMPARE_XQUERY: use XQuery comparison and type promotion rules
+ * RASQAL_COMPARE_RDF: use RDF term comparison
+ * RASQAL_COMPARE_URI: allow comparison of URIs (typically for SPARQL ORDER)
+ *
+ * If @error is not NULL, *error is set to non-0 on error
+ *
+ * Return value: <0, 0, or >0 as described above.
+ **/
+int
+rasqal_literal_compare(rasqal_literal* l1, rasqal_literal* l2, int flags,
+ int *error)
+{
+ rasqal_literal *lits[2];
+ rasqal_literal* new_lits[2]; /* after promotions */
+ rasqal_literal_type type; /* target promotion type */
+ int i;
+ int result=0;
+ double d=0;
+ int promotion=0;
+
+ if(error)
+ *error=0;
+
+ lits[0]=rasqal_literal_value(l1);
+ lits[1]=rasqal_literal_value(l2);
+
+ /* null literals */
+ if(!lits[0] || !lits[1]) {
+ /* if either is not NULL, the comparison fails */
+ if(lits[0] || lits[1]) {
+ if(error)
+ *error=1;
+ }
+ return 0;
+ }
+
+ new_lits[0]=NULL;
+ new_lits[1]=NULL;
+
+ RASQAL_DEBUG3("literal 0 type %s. literal 1 type %s\n",
+ rasqal_literal_type_labels[lits[0]->type],
+ rasqal_literal_type_labels[lits[1]->type]);
+
+ if(flags & RASQAL_COMPARE_RDF) {
+ /* no promotion but compare as RDF terms; like rasqal_literal_as_node() */
+ rasqal_literal_type type0=rasqal_literal_get_rdf_term_type(lits[0]);
+ rasqal_literal_type type1=rasqal_literal_get_rdf_term_type(lits[1]);
+ int type_diff;
+
+ if(type0 == RASQAL_LITERAL_UNKNOWN || type1 == RASQAL_LITERAL_UNKNOWN)
+ return 1;
+ type_diff=type0 - type1;
+ if(type_diff != 0) {
+ RASQAL_DEBUG2("RDF term literal returning type difference %d\n",
+ type_diff);
+ return type_diff;
+ }
+ type=type1;
+ } else if(flags & RASQAL_COMPARE_XQUERY) {
+ /* SPARQL / XQuery promotion rules */
+ rasqal_literal_type type0=lits[0]->type;
+ rasqal_literal_type type1=lits[1]->type;
+
+ RASQAL_DEBUG3("xquery literal compare types %s vs %s\n",
+ rasqal_literal_type_labels[type0],
+ rasqal_literal_type_labels[type1]);
+
+ type=rasqal_literal_promote_numerics(lits[0], lits[1], flags);
+ if(type == RASQAL_LITERAL_UNKNOWN) {
+ int type_diff;
+
+ /* no promotion but compare as RDF terms; like rasqal_literal_as_node() */
+ type0=rasqal_literal_get_rdf_term_type(lits[0]);
+ type1=rasqal_literal_get_rdf_term_type(lits[1]);
+
+ if(type0 == RASQAL_LITERAL_UNKNOWN || type1 == RASQAL_LITERAL_UNKNOWN)
+ return 1;
+ type_diff=type0 - type1;
+ if(type_diff != 0) {
+ RASQAL_DEBUG2("RDF term literal returning type difference %d\n",
+ type_diff);
+ return type_diff;
+ }
+ if(error)
+ *error=1;
+ return 0;
+ }
+ promotion=1;
+ } else {
+ /* RDQL promotion rules */
+ type=rasqal_literal_rdql_promote_calculate(lits[0], lits[1]);
+ promotion=1;
+ }
+
+#ifdef RASQAL_DEBUG
+ if(promotion)
+ RASQAL_DEBUG2("promoting to type %s\n", rasqal_literal_type_labels[type]);
+#endif
+
+ /* do promotions */
+ for(i=0; i<2; i++) {
+ if(promotion) {
+ new_lits[i]=rasqal_new_literal_from_promotion(lits[i], type);
+ if(!new_lits[i]) {
+ if(error)
+ *error=1;
+ goto done;
+ }
+ } else {
+ new_lits[i]=lits[i];
+ }
+ }
+
+
+ switch(type) {
+ case RASQAL_LITERAL_URI:
+ if(flags & RASQAL_COMPARE_URI)
+#ifdef RAPTOR_V2_AVAILABLE
+ result = raptor_uri_compare_v2(l1->world->raptor_world_ptr,
+ new_lits[0]->value.uri,
+ new_lits[1]->value.uri);
+#else
+ result = raptor_uri_compare(new_lits[0]->value.uri,
+ new_lits[1]->value.uri);
+#endif
+ else {
+ if(error)
+ *error=1;
+ return 0;
+ }
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ result=rasqal_literal_string_compare(new_lits[0], new_lits[1],
+ flags, error);
+ if(*error)
+ result=1;
+ break;
+
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_DATETIME:
+ if(flags & RASQAL_COMPARE_NOCASE)
+ result=rasqal_strcasecmp((const char*)new_lits[0]->string,
+ (const char*)new_lits[1]->string);
+ else
+ result=strcmp((const char*)new_lits[0]->string,
+ (const char*)new_lits[1]->string);
+ break;
+
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ result=new_lits[0]->value.integer - new_lits[1]->value.integer;
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ d=new_lits[0]->value.floating - new_lits[1]->value.floating;
+ result=(d > 0.0) ? 1: (d < 0.0) ? -1 : 0;
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ result=rasqal_xsd_decimal_compare(new_lits[0]->value.decimal,
+ new_lits[1]->value.decimal);
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_VARIABLE:
+ default:
+ RASQAL_FATAL2("Literal type %d cannot be compared", type);
+ result=0; /* keep some compilers happy */
+ }
+
+ done:
+ if(promotion) {
+ for(i=0; i<2; i++) {
+ if(new_lits[i])
+ rasqal_free_literal(new_lits[i]);
+ }
+ }
+
+ return result;
+}
+
+
+/**
+ * rasqal_literal_string_equals:
+ * @l1: #rasqal_literal first literal
+ * @l2: #rasqal_literal second literal
+ * @error: pointer to error
+ *
+ * INTERNAL - Compare two typed literals
+ *
+ * Return value: non-0 if equal
+ */
+static int
+rasqal_literal_string_equals(rasqal_literal* l1, rasqal_literal* l2,
+ int* error)
+{
+ int result=1;
+ raptor_uri* dt1=l1->datatype;
+ raptor_uri* dt2=l2->datatype;
+ raptor_uri* xsd_string_uri=rasqal_xsd_datatype_type_to_uri(l1->world, RASQAL_LITERAL_STRING);
+
+ if(l1->language || l2->language) {
+ /* if either is NULL, the comparison fails */
+ if(!l1->language || !l2->language)
+ return 0;
+ if(rasqal_strcasecmp(l1->language,l2->language))
+ return 0;
+ }
+
+ /* Treat typed literal "xx"^^xsd:string as plain literal "xx"
+ * for purposes of equality.
+ */
+#ifdef RAPTOR_V2_AVAILABLE
+ if(dt1 && raptor_uri_equals_v2(l1->world->raptor_world_ptr, dt1, xsd_string_uri))
+ dt1 = NULL;
+ if(dt2 && raptor_uri_equals_v2(l1->world->raptor_world_ptr, dt2, xsd_string_uri))
+ dt2 = NULL;
+#else
+ if(dt1 && raptor_uri_equals(dt1, xsd_string_uri))
+ dt1 = NULL;
+ if(dt2 && raptor_uri_equals(dt2, xsd_string_uri))
+ dt2 = NULL;
+#endif
+
+ if(dt1 || dt2) {
+ /* if either is NULL - type error */
+ if(!dt1 || !dt2) {
+ if(error)
+ *error=1;
+ return 0;
+ }
+ /* if different - type error */
+ if(
+#ifdef RAPTOR_V2_AVAILABLE
+ !raptor_uri_equals_v2(l1->world->raptor_world_ptr, dt1, dt2)
+#else
+ !raptor_uri_equals(dt1, dt2)
+#endif
+ )
+ {
+ if(error)
+ *error=1;
+ return 0;
+ }
+ /* at this point the datatypes (URIs) are the same */
+
+ /* If literals were both typed literals */
+ if(l1->type == RASQAL_LITERAL_STRING && l2->type == RASQAL_LITERAL_STRING) {
+ if(l1->string_len != l2->string_len) {
+ /* not-equal if lengths are different - cheap to compare this first */
+ return 0;
+ } else {
+ /* user-defined datatype - can only check for lexical identity */
+ result=!strcmp((const char*)l1->string, (const char*)l2->string);
+ if(!result) {
+ /* different strings but cannot tell if they are equal */
+ if(error)
+ *error=1;
+ return 0;
+ }
+ }
+ }
+ }
+
+ /* Finally check the lexical forms */
+
+ /* not-equal if lengths are different - cheaper to try this first */
+ if(l1->string_len != l2->string_len)
+ return 0;
+
+ result=!strcmp((const char*)l1->string, (const char*)l2->string);
+
+ return result;
+}
+
+
+/**
+ * rasqal_literal_equals:
+ * @l1: #rasqal_literal literal
+ * @l2: #rasqal_literal data literal
+ *
+ * Compare two literals with no type promotion.
+ *
+ * If the l2 data literal value is a boolean, it will match
+ * the string "true" or "false" in the first literal l1.
+ *
+ * Return value: non-0 if equal
+ **/
+int
+rasqal_literal_equals(rasqal_literal* l1, rasqal_literal* l2)
+{
+ return rasqal_literal_equals_flags(l1, l2, 0, NULL);
+}
+
+
+/**
+ * rasqal_literal_equals_flags:
+ * @l1: #rasqal_literal literal
+ * @l2: #rasqal_literal data literal
+ * @flags: comparison flags
+ * @error: type error
+ *
+ * Compare two literals with optional type promotion.
+ *
+ * flag bits affects equality:
+ * RASQAL_COMPARE_XQUERY: use XQuery comparison and type promotion rules
+ * RASQAL_COMPARE_RDF: use RDF term equality
+ *
+ * Return value: non-0 if equal
+ **/
+int
+rasqal_literal_equals_flags(rasqal_literal* l1, rasqal_literal* l2,
+ int flags, int* error)
+{
+ rasqal_literal_type type;
+ rasqal_literal* l1_p=NULL;
+ rasqal_literal* l2_p=NULL;
+ int result=0;
+ int promotion=0;
+
+ /* null literals */
+ if(!l1 || !l2) {
+ /* if either is not null, the comparison fails */
+ return (l1 || l2);
+ }
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG1(" ");
+ rasqal_literal_print(l1, stderr);
+ fputs( " to ", stderr);
+ rasqal_literal_print(l2, stderr);
+ fprintf(stderr, " with flags %d\n", flags);
+#endif
+
+ if(flags & RASQAL_COMPARE_RDF) {
+ /* no promotion but compare as RDF terms; like rasqal_literal_as_node() */
+ rasqal_literal_type type1=rasqal_literal_get_rdf_term_type(l1);
+ rasqal_literal_type type2=rasqal_literal_get_rdf_term_type(l2);
+
+ if(type1 == RASQAL_LITERAL_UNKNOWN || type2 == RASQAL_LITERAL_UNKNOWN ||
+ type1 != type2)
+ goto tidy;
+
+ type=type1;
+ } else if(flags & RASQAL_COMPARE_XQUERY) {
+ /* SPARQL / XSD promotion rules */
+ if(l1->type != l2->type) {
+ type=rasqal_literal_promote_numerics(l1, l2, flags);
+ if(type == RASQAL_LITERAL_UNKNOWN) {
+ /* Cannot numeric promote - try RDF equality */
+ rasqal_literal_type type1=rasqal_literal_get_rdf_term_type(l1);
+ rasqal_literal_type type2=rasqal_literal_get_rdf_term_type(l2);
+
+ if(type1 == RASQAL_LITERAL_UNKNOWN || type2 == RASQAL_LITERAL_UNKNOWN ||
+ type1 != type2)
+ goto tidy;
+
+ type=type1;
+ } else
+ promotion=1;
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG4("xquery promoted literals types (%s, %s) to type %s\n",
+ rasqal_literal_type_labels[l1->type],
+ rasqal_literal_type_labels[l2->type],
+ rasqal_literal_type_labels[type]);
+#endif
+ } else
+ type=l1->type;
+ } else {
+ /* RDQL rules: compare as values with no promotion */
+ if(l1->type != l2->type) {
+ /* booleans can be compared to strings */
+ if(l2->type == RASQAL_LITERAL_BOOLEAN &&
+ l1->type == RASQAL_LITERAL_STRING)
+ result=!strcmp((const char*)l1->string, (const char*)l2->string);
+ goto tidy;
+ }
+ type=l1->type;
+ }
+
+ if(promotion) {
+ l1_p=rasqal_new_literal_from_promotion(l1, type);
+ if(l1_p)
+ l2_p=rasqal_new_literal_from_promotion(l2, type);
+ if(!l1_p || !l2_p) {
+ result=1;
+ goto tidy;
+ }
+ } else {
+ l1_p=l1;
+ l2_p=l2;
+ }
+
+ switch(type) {
+ case RASQAL_LITERAL_URI:
+#ifdef RAPTOR_V2_AVAILABLE
+ result = raptor_uri_equals_v2(l1->world->raptor_world_ptr, l1_p->value.uri, l2_p->value.uri);
+#else
+ result = raptor_uri_equals(l1_p->value.uri, l2_p->value.uri);
+#endif
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ result=rasqal_literal_string_equals(l1, l2, error);
+ break;
+
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_DATETIME:
+ /* FIXME this should be xsd:dateTime equality */
+ if(l1_p->string_len != l2_p->string_len)
+ /* not-equal if lengths are different - cheap to compare this first */
+ result=0;
+ else
+ result=!strcmp((const char*)l1_p->string, (const char*)l2_p->string);
+ break;
+
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ result=l1_p->value.integer == l2_p->value.integer;
+ break;
+
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ result=l1_p->value.floating == l2_p->value.floating;
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ result=rasqal_xsd_decimal_equals(l1_p->value.decimal,
+ l2_p->value.decimal);
+ break;
+
+ case RASQAL_LITERAL_VARIABLE:
+ /* both are variables */
+ result=rasqal_literal_equals(l1_p->value.variable->value,
+ l2_p->value.variable->value);
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ default:
+ RASQAL_FATAL2("Literal type %d cannot be equaled", type);
+ result=0; /* keep some compilers happy */
+ }
+
+ tidy:
+ if(promotion) {
+ if(l1_p)
+ rasqal_free_literal(l1_p);
+ if(l2_p)
+ rasqal_free_literal(l2_p);
+ }
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("equals result %d\n", result);
+#endif
+
+ return result;
+}
+
+
+/*
+ * rasqal_literal_expand_qname - INTERNAL Expand any qname in a literal into a URI
+ * @user_data: #rasqal_query cast as void for use with raptor_sequence_foreach
+ * @l: #rasqal_literal literal
+ *
+ * Expands any QName inside the literal using prefixes that are
+ * declared in the query that may not have been present when the
+ * literal was first declared. Intended to be used standalone
+ * as well as with raptor_sequence_foreach which takes a function
+ * signature that this function matches.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_literal_expand_qname(void *user_data, rasqal_literal *l)
+{
+ rasqal_query *rq=(rasqal_query *)user_data;
+
+ if(l->type == RASQAL_LITERAL_QNAME) {
+ /* expand a literal qname */
+ raptor_uri *uri=raptor_qname_string_to_uri(rq->namespaces,
+ l->string, l->string_len,
+ (raptor_simple_message_handler)rasqal_query_simple_error, rq);
+ if(!uri)
+ return 1;
+ RASQAL_FREE(cstring, (void*)l->string);
+ l->string=NULL;
+ l->type=RASQAL_LITERAL_URI;
+ l->value.uri=uri;
+ } else if (l->type == RASQAL_LITERAL_STRING) {
+ raptor_uri *uri;
+
+ if(l->flags) {
+ /* expand a literal string datatype qname */
+ uri=raptor_qname_string_to_uri(rq->namespaces,
+ l->flags,
+ strlen((const char*)l->flags),
+ (raptor_simple_message_handler)rasqal_query_simple_error, rq);
+ if(!uri)
+ return 1;
+ l->datatype=uri;
+ RASQAL_FREE(cstring, (void*)l->flags);
+ l->flags=NULL;
+
+ if(l->language && uri) {
+ RASQAL_FREE(cstring, (void*)l->language);
+ l->language=NULL;
+ }
+
+ if(rasqal_literal_string_to_native(l, (raptor_simple_message_handler)rasqal_query_simple_error, rq, 0)) {
+ rasqal_free_literal(l);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * rasqal_literal_has_qname - INTERNAL Check if literal has a qname part
+ * @l: #rasqal_literal literal
+ *
+ * Checks if any part ofthe literal has an unexpanded QName.
+ *
+ * Return value: non-0 if a QName is present
+ **/
+int
+rasqal_literal_has_qname(rasqal_literal *l) {
+ return (l->type == RASQAL_LITERAL_QNAME) ||
+ (l->type == RASQAL_LITERAL_STRING && (l->flags));
+}
+
+
+/**
+ * rasqal_literal_as_node:
+ * @l: #rasqal_literal object
+ *
+ * Turn a literal into a new RDF string, URI or blank literal.
+ *
+ * Return value: the new #rasqal_literal or NULL on failure
+ **/
+rasqal_literal*
+rasqal_literal_as_node(rasqal_literal* l)
+{
+ raptor_uri* dt_uri;
+ rasqal_literal* new_l=NULL;
+
+ reswitch:
+ if(!l)
+ return NULL;
+ switch(l->type) {
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BLANK:
+ new_l=rasqal_new_literal_from_literal(l);
+ break;
+
+ case RASQAL_LITERAL_VARIABLE:
+ l=l->value.variable->value;
+ goto reswitch;
+
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ new_l=(rasqal_literal*)RASQAL_CALLOC(rasqal_literal, 1, sizeof(rasqal_literal));
+ if(new_l) {
+ new_l->usage=1;
+ new_l->world=l->world;
+ new_l->type=RASQAL_LITERAL_STRING;
+ new_l->string_len=l->string_len;
+ new_l->string=(unsigned char*)RASQAL_MALLOC(cstring, l->string_len+1);
+ if(!new_l->string) {
+ rasqal_free_literal(new_l);
+ return NULL;
+ }
+ strncpy((char*)new_l->string, (const char*)l->string, l->string_len+1);
+ dt_uri=rasqal_xsd_datatype_type_to_uri(l->world, l->type);
+ if(!dt_uri) {
+ rasqal_free_literal(new_l);
+ return NULL;
+ }
+#ifdef RAPTOR_V2_AVAILABLE
+ new_l->datatype = raptor_uri_copy_v2(l->world->raptor_world_ptr, dt_uri);
+#else
+ new_l->datatype = raptor_uri_copy(dt_uri);
+#endif
+ new_l->flags=NULL;
+ }
+ break;
+
+ case RASQAL_LITERAL_QNAME:
+ /* QNames should be gone by the time expression eval happens */
+
+ case RASQAL_LITERAL_PATTERN:
+ /* FALLTHROUGH */
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Literal type %d has no node value", l->type);
+ }
+
+ return new_l;
+}
+
+
+/*
+ * rasqal_literal_ebv - INTERNAL Get the rasqal_literal effective boolean value
+ * @l: #rasqal_literal literal
+ *
+ * Return value: non-0 if EBV is true, else false
+ **/
+int
+rasqal_literal_ebv(rasqal_literal* l)
+{
+ rasqal_variable* v;
+ /* Result is true unless... */
+ int b=1;
+
+ v=rasqal_literal_as_variable(l);
+ if(v) {
+ if(v->value == NULL) {
+ /* ... The operand is unbound */
+ b=0;
+ goto done;
+ }
+ l=v->value;
+ }
+
+ if(l->type == RASQAL_LITERAL_BOOLEAN && !l->value.integer) {
+ /* ... The operand is an xs:boolean with a FALSE value. */
+ b=0;
+ } else if(l->type == RASQAL_LITERAL_STRING &&
+ !l->datatype && !l->string_len) {
+ /* ... The operand is a 0-length untyped RDF literal or xs:string. */
+ b=0;
+ } else if((l->type == RASQAL_LITERAL_INTEGER && !l->value.integer) ||
+ ((l->type == RASQAL_LITERAL_DOUBLE ||
+ l->type == RASQAL_LITERAL_FLOAT) &&
+ !l->value.floating)
+ ) {
+ /* ... The operand is any numeric type with a value of 0. */
+ b=0;
+ } else if(l->type == RASQAL_LITERAL_DECIMAL &&
+ rasqal_xsd_decimal_is_zero(l->value.decimal)) {
+ /* ... The operand is any numeric type with a value of 0 (decimal) */
+ b=0;
+ } else if((l->type == RASQAL_LITERAL_DOUBLE ||
+ l->type == RASQAL_LITERAL_FLOAT) &&
+ isnan(l->value.floating)
+ ) {
+ /* ... The operand is an xs:double or xs:float with a value of NaN */
+ b=0;
+ }
+
+ done:
+ return b;
+}
+
+
+/*
+ * rasqal_literal_is_constant - INTERNAL Check if a literal is a constant
+ * @l: #rasqal_literal literal
+ *
+ * Return value: non-0 if literal is a constant
+ **/
+int
+rasqal_literal_is_constant(rasqal_literal* l)
+{
+ switch(l->type) {
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ return 1;
+
+ case RASQAL_LITERAL_VARIABLE:
+ return 0;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Literal type %d cannot be checked for constant", l->type);
+ return 0; /* keep some compilers happy */
+ }
+}
+
+
+rasqal_formula*
+rasqal_new_formula(void)
+{
+ return (rasqal_formula*)RASQAL_CALLOC(rasqal_formula, 1, sizeof(rasqal_formula));
+}
+
+void
+rasqal_free_formula(rasqal_formula* formula)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(formula, rasqal_formula);
+
+ if(formula->triples)
+ raptor_free_sequence(formula->triples);
+ if(formula->value)
+ rasqal_free_literal(formula->value);
+ RASQAL_FREE(rasqal_formula, formula);
+}
+
+
+void
+rasqal_formula_print(rasqal_formula* formula, FILE *stream)
+{
+ fputs("formula(triples=", stream);
+ if(formula->triples)
+ raptor_sequence_print(formula->triples, stream);
+ else
+ fputs("[]", stream);
+ fputs(", value=", stream);
+ if(formula->value)
+ rasqal_literal_print(formula->value, stream);
+ else
+ fputs("NULL", stream);
+ fputc(')', stream);
+}
+
+
+rasqal_formula*
+rasqal_formula_join(rasqal_formula* first_formula,
+ rasqal_formula* second_formula)
+{
+ if(!first_formula && !second_formula)
+ return NULL;
+
+ if(!first_formula)
+ return second_formula;
+
+ if(!second_formula)
+ return first_formula;
+
+ if(first_formula->triples || second_formula->triples) {
+ if(!first_formula->triples) {
+ first_formula->triples=second_formula->triples;
+ second_formula->triples=NULL;
+ } else if(second_formula->triples)
+ if(raptor_sequence_join(first_formula->triples, second_formula->triples)) {
+ rasqal_free_formula(first_formula);
+ first_formula=NULL;
+ }
+ }
+ rasqal_free_formula(second_formula);
+
+ return first_formula;
+}
+
+
+/**
+ * rasqal_literal_datatype:
+ * @l: #rasqal_literal object
+ *
+ * Get the datatype URI of a literal
+ *
+ * Return value: shared pointer to #raptor_uri of datatype or NULL on failure or no value
+ */
+raptor_uri*
+rasqal_literal_datatype(rasqal_literal* l)
+{
+ if(!l)
+ return NULL;
+
+ if(l->type != RASQAL_LITERAL_VARIABLE)
+ return l->datatype;
+ return rasqal_literal_datatype(l->value.variable->value);
+}
+
+
+rasqal_literal*
+rasqal_literal_cast(rasqal_literal* l, raptor_uri* to_datatype, int flags,
+ int* error_p)
+{
+ raptor_uri* from_datatype=NULL;
+ const unsigned char *string=NULL;
+ unsigned char *new_string;
+ rasqal_literal* result=NULL;
+ rasqal_literal_type from_native_type;
+ rasqal_literal_type to_native_type;
+
+ l=rasqal_literal_value(l);
+ if(!l)
+ return NULL;
+
+ from_datatype=l->datatype;
+ from_native_type=l->type;
+
+ to_native_type=rasqal_xsd_datatype_uri_to_type(l->world, to_datatype);
+
+ if(from_native_type == to_native_type) {
+ /* cast to same type is always allowed */
+ return rasqal_new_literal_from_literal(l);
+
+ } else {
+ /* switch on FROM type to check YES/NO conversions and get the string */
+ switch(from_native_type) {
+ /* string */
+ case RASQAL_LITERAL_STRING:
+ string=l->string;
+ break;
+
+ /* XSD datatypes: RASQAL_LITERAL_FIRST_XSD to RASQAL_LITERAL_LAST_XSD */
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DECIMAL:
+ /* XSD (boolean, integer, decimal, double, float) may NOT be
+ * cast to dateTime */
+ if(to_native_type == RASQAL_LITERAL_DATETIME) {
+ *error_p=1;
+ break;
+ }
+ string=l->string;
+ break;
+
+ case RASQAL_LITERAL_DATETIME:
+ string=l->string;
+ break;
+
+ /* SPARQL casts - FIXME */
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ string=l->string;
+ break;
+
+ case RASQAL_LITERAL_URI:
+ /* URI (IRI) May ONLY be cast to a string */
+ if(to_native_type != RASQAL_LITERAL_STRING) {
+ *error_p=1;
+ break;
+ }
+
+#ifdef RAPTOR_V2_AVAILABLE
+ string = raptor_uri_as_string_v2(l->world->raptor_world_ptr, l->value.uri);
+#else
+ string = raptor_uri_as_string(l->value.uri);
+#endif
+ break;
+
+ case RASQAL_LITERAL_VARIABLE:
+ /* fallthrough since rasqal_literal_value() handled this above */
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ RASQAL_FATAL2("Literal type %d cannot be cast", l->type);
+ return NULL; /* keep some compilers happy */
+ }
+
+ if(to_native_type == RASQAL_LITERAL_DATETIME) {
+ /* XSD dateTime may ONLY be cast from string (cast from dateTime
+ * is checked above)
+ */
+ if(from_native_type != RASQAL_LITERAL_STRING) {
+ *error_p=1;
+ }
+ }
+
+ if(*error_p)
+ return NULL;
+
+ }
+
+
+ /* switch on the TO type to check MAYBE conversions */
+
+#ifdef RAPTOR_V2_AVAILABLE
+ RASQAL_DEBUG4("CAST from \"%s\" type %s to type %s\n",
+ string,
+ from_datatype ? (const char*)raptor_uri_as_string_v2(l->world->raptor_world_ptr, from_datatype) : "(NONE)",
+ raptor_uri_as_string_v2(l->world->raptor_world_ptr, to_datatype));
+#else
+ RASQAL_DEBUG4("CAST from \"%s\" type %s to type %s\n",
+ string,
+ from_datatype ? (const char*)raptor_uri_as_string(from_datatype) : "(NONE)",
+ raptor_uri_as_string(to_datatype));
+#endif
+
+ if(!rasqal_xsd_datatype_check(to_native_type, string, flags)) {
+ *error_p=1;
+ RASQAL_DEBUG3("Illegal cast to type %s string '%s'",
+ rasqal_xsd_datatype_label(to_native_type), string);
+ return NULL;
+ }
+
+ new_string=(unsigned char*)RASQAL_MALLOC(string,
+ strlen((const char*)string)+1);
+ if(!new_string) {
+ *error_p=1;
+ return NULL;
+ }
+ strcpy((char*)new_string, (const char*)string);
+#ifdef RAPTOR_V2_AVAILABLE
+ to_datatype = raptor_uri_copy_v2(l->world->raptor_world_ptr, to_datatype);
+#else
+ to_datatype = raptor_uri_copy(to_datatype);
+#endif
+
+ result=rasqal_new_string_literal(l->world, new_string, NULL, to_datatype, NULL);
+ if(!result)
+ *error_p=1;
+ return result;
+}
+
+
+/**
+ * rasqal_literal_value:
+ * @l: #rasqal_literal object
+ *
+ * Get the literal value looking up any variables needed
+ *
+ * Return value: literal value or NULL if has no value
+ */
+rasqal_literal*
+rasqal_literal_value(rasqal_literal* l)
+{
+ while(l) {
+ if(l->type != RASQAL_LITERAL_VARIABLE)
+ break;
+
+ l=l->value.variable->value;
+ }
+
+ return l;
+}
+
+
+int
+rasqal_literal_is_numeric(rasqal_literal* literal)
+{
+ return (rasqal_xsd_datatype_is_numeric(literal->type) ||
+ rasqal_xsd_datatype_is_numeric(literal->parent_type));
+}
+
+
+rasqal_literal*
+rasqal_literal_add(rasqal_literal* l1, rasqal_literal* l2, int *error_p)
+{
+ int i;
+ double d;
+ rasqal_xsd_decimal* dec;
+ int error=0;
+ rasqal_literal_type type;
+ rasqal_literal* l1_p=NULL;
+ rasqal_literal* l2_p=NULL;
+ int flags=0;
+ rasqal_literal* result=NULL;
+
+ type=rasqal_literal_promote_numerics(l1, l2, flags);
+ switch(type) {
+ case RASQAL_LITERAL_INTEGER:
+ i=rasqal_literal_as_integer(l1, &error);
+ if(error)
+ break;
+ i=i + rasqal_literal_as_integer(l2, &error);
+ if(error)
+ break;
+
+ result=rasqal_new_integer_literal(l1->world, RASQAL_LITERAL_INTEGER, i);
+ break;
+
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DOUBLE:
+ d=rasqal_literal_as_floating(l1, &error);
+ if(error)
+ break;
+ d=d + rasqal_literal_as_floating(l2, &error);
+ if(error)
+ break;
+
+ result=rasqal_new_numeric_literal(l1->world, type, d);
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ l1_p=rasqal_new_literal_from_promotion(l1, type);
+ if(l1_p)
+ l2_p=rasqal_new_literal_from_promotion(l2, type);
+ if(l1_p && l2_p) {
+ dec=rasqal_new_xsd_decimal();
+ if(rasqal_xsd_decimal_add(dec, l1_p->value.decimal,
+ l2_p->value.decimal)) {
+ error=1;
+ rasqal_free_xsd_decimal(dec);
+ } else
+ result=rasqal_new_decimal_literal_from_decimal(l1->world, NULL, dec);
+ }
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DATETIME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_VARIABLE:
+ default:
+ error=1;
+ break;
+ }
+
+ if(error) {
+ if(error_p)
+ *error_p=1;
+ }
+
+ if(l1_p)
+ rasqal_free_literal(l1_p);
+ if(l2_p)
+ rasqal_free_literal(l2_p);
+
+ return result;
+}
+
+
+rasqal_literal*
+rasqal_literal_subtract(rasqal_literal* l1, rasqal_literal* l2, int *error_p)
+{
+ int i;
+ double d;
+ rasqal_xsd_decimal* dec;
+ int error=0;
+ rasqal_literal_type type;
+ rasqal_literal* l1_p=NULL;
+ rasqal_literal* l2_p=NULL;
+ int flags=0;
+ rasqal_literal* result=NULL;
+
+ type=rasqal_literal_promote_numerics(l1, l2, flags);
+ switch(type) {
+ case RASQAL_LITERAL_INTEGER:
+ i=rasqal_literal_as_integer(l1, &error);
+ if(error)
+ break;
+ i=i - rasqal_literal_as_integer(l2, &error);
+ if(error)
+ break;
+
+ result=rasqal_new_integer_literal(l1->world, RASQAL_LITERAL_INTEGER, i);
+ break;
+
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DOUBLE:
+ d=rasqal_literal_as_floating(l1, &error);
+ if(error)
+ break;
+ d=d - rasqal_literal_as_floating(l2, &error);
+ if(error)
+ break;
+
+ result=rasqal_new_numeric_literal(l1->world, type, d);
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ l1_p=rasqal_new_literal_from_promotion(l1, type);
+ if(l1_p)
+ l2_p=rasqal_new_literal_from_promotion(l2, type);
+ if(l1_p && l2_p) {
+ dec=rasqal_new_xsd_decimal();
+ if(rasqal_xsd_decimal_subtract(dec, l1_p->value.decimal,
+ l2_p->value.decimal)) {
+ error=1;
+ rasqal_free_xsd_decimal(dec);
+ } else
+ result=rasqal_new_decimal_literal_from_decimal(l1->world, NULL, dec);
+ }
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DATETIME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_VARIABLE:
+ default:
+ error=1;
+ break;
+ }
+
+ if(error) {
+ if(error_p)
+ *error_p=1;
+ }
+
+ if(l1_p)
+ rasqal_free_literal(l1_p);
+ if(l2_p)
+ rasqal_free_literal(l2_p);
+
+ return result;
+}
+
+
+rasqal_literal*
+rasqal_literal_multiply(rasqal_literal* l1, rasqal_literal* l2, int *error_p)
+{
+ int i;
+ double d;
+ rasqal_xsd_decimal* dec;
+ int error=0;
+ rasqal_literal_type type;
+ rasqal_literal* l1_p=NULL;
+ rasqal_literal* l2_p=NULL;
+ int flags=0;
+ rasqal_literal* result=NULL;
+
+ type=rasqal_literal_promote_numerics(l1, l2, flags);
+ switch(type) {
+ case RASQAL_LITERAL_INTEGER:
+ i=rasqal_literal_as_integer(l1, &error);
+ if(error)
+ break;
+ i=i * rasqal_literal_as_integer(l2, &error);
+ if(error)
+ break;
+
+ result=rasqal_new_integer_literal(l1->world, RASQAL_LITERAL_INTEGER, i);
+ break;
+
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DOUBLE:
+ d=rasqal_literal_as_floating(l1, &error);
+ if(error)
+ break;
+ d=d * rasqal_literal_as_floating(l2, &error);
+ if(error)
+ break;
+
+ result=rasqal_new_numeric_literal(l1->world, type, d);
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ l1_p=rasqal_new_literal_from_promotion(l1, type);
+ if(l1_p)
+ l2_p=rasqal_new_literal_from_promotion(l2, type);
+ if(l1_p && l2_p) {
+ dec=rasqal_new_xsd_decimal();
+ if(rasqal_xsd_decimal_multiply(dec, l1_p->value.decimal,
+ l2_p->value.decimal)) {
+ error=1;
+ rasqal_free_xsd_decimal(dec);
+ } else
+ result=rasqal_new_decimal_literal_from_decimal(l1->world, NULL, dec);
+ }
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DATETIME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_VARIABLE:
+ default:
+ error=1;
+ break;
+ }
+
+ if(error) {
+ if(error_p)
+ *error_p=1;
+ }
+
+ if(l1_p)
+ rasqal_free_literal(l1_p);
+ if(l2_p)
+ rasqal_free_literal(l2_p);
+
+ return result;
+}
+
+
+rasqal_literal*
+rasqal_literal_divide(rasqal_literal* l1, rasqal_literal* l2, int *error_p)
+{
+ int i1, i2;
+ double d1, d2;
+ rasqal_xsd_decimal* dec;
+ int error=0;
+ rasqal_literal_type type;
+ rasqal_literal* l1_p=NULL;
+ rasqal_literal* l2_p=NULL;
+ int flags=0;
+ rasqal_literal* result=NULL;
+
+ type=rasqal_literal_promote_numerics(l1, l2, flags);
+ switch(type) {
+ case RASQAL_LITERAL_INTEGER:
+ i2=rasqal_literal_as_integer(l2, &error);
+ if(!i2)
+ error=1;
+ if(error)
+ break;
+ i1=rasqal_literal_as_integer(l1, &error);
+ if(error)
+ break;
+ i1=i1 / i2;
+ if(error)
+ break;
+
+ result=rasqal_new_integer_literal(l1->world, RASQAL_LITERAL_INTEGER, i1);
+ break;
+
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DOUBLE:
+ d2=rasqal_literal_as_floating(l2, &error);
+ if(!d2)
+ error=1;
+ if(error)
+ break;
+ d1=rasqal_literal_as_floating(l1, &error);
+ if(error)
+ break;
+ d1=d1 / d2;
+ if(error)
+ break;
+
+ result=rasqal_new_numeric_literal(l1->world, type, d1);
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ l1_p=rasqal_new_literal_from_promotion(l1, type);
+ if(l1_p)
+ l2_p=rasqal_new_literal_from_promotion(l2, type);
+ if(l1_p && l2_p) {
+ dec=rasqal_new_xsd_decimal();
+ if(rasqal_xsd_decimal_add(dec, l1_p->value.decimal,
+ l2_p->value.decimal)) {
+ error=1;
+ rasqal_free_xsd_decimal(dec);
+ } else
+ result=rasqal_new_decimal_literal_from_decimal(l1->world, NULL, dec);
+ }
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DATETIME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_VARIABLE:
+ default:
+ error=1;
+ break;
+ }
+
+ if(error) {
+ if(error_p)
+ *error_p=1;
+ }
+
+ if(l1_p)
+ rasqal_free_literal(l1_p);
+ if(l2_p)
+ rasqal_free_literal(l2_p);
+
+ return result;
+}
+
+
+rasqal_literal*
+rasqal_literal_negate(rasqal_literal* l, int *error_p)
+{
+ int i;
+ double d;
+ rasqal_xsd_decimal* dec;
+ int error=0;
+ rasqal_literal* result=NULL;
+
+ switch(l->type) {
+ case RASQAL_LITERAL_INTEGER:
+ i=rasqal_literal_as_integer(l, &error);
+ if(error)
+ break;
+ i= -i;
+ result=rasqal_new_integer_literal(l->world, RASQAL_LITERAL_INTEGER, i);
+ break;
+
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DOUBLE:
+ d=rasqal_literal_as_floating(l, &error);
+ if(!d)
+ error=1;
+ d= -d;
+ result=rasqal_new_numeric_literal(l->world, l->type, d);
+ break;
+
+ case RASQAL_LITERAL_DECIMAL:
+ dec=rasqal_new_xsd_decimal();
+ if(rasqal_xsd_decimal_negate(dec, l->value.decimal)) {
+ error=1;
+ rasqal_free_xsd_decimal(dec);
+ } else
+ result=rasqal_new_decimal_literal_from_decimal(l->world, NULL, dec);
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_URI:
+ case RASQAL_LITERAL_STRING:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DATETIME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_VARIABLE:
+ default:
+ error=1;
+ break;
+ }
+
+ if(error) {
+ if(error_p)
+ *error_p=1;
+ }
+
+ return result;
+}
diff --git a/src/rasqal/rasqal_map.c b/src/rasqal/rasqal_map.c
new file mode 100644
index 0000000..80dfa87
--- /dev/null
+++ b/src/rasqal/rasqal_map.c
@@ -0,0 +1,319 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_map.c - Rasqal simple Key:Value Map with duplicates allowed
+ *
+ * Copyright (C) 2005-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2005-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+struct rasqal_map_node_s
+{
+ struct rasqal_map_s* map;
+ struct rasqal_map_node_s* prev;
+ struct rasqal_map_node_s* next;
+ void* key;
+ void* value;
+};
+
+struct rasqal_map_s {
+ struct rasqal_map_node_s* root;
+ rasqal_compare_fn* compare;
+ void *compare_user_data;
+ rasqal_compare_free_user_data_fn* free_compare_data;
+ rasqal_kv_free_fn* free;
+ raptor_sequence_print_handler* print_key;
+ raptor_sequence_print_handler* print_value;
+ int allow_duplicates;
+};
+
+typedef struct rasqal_map_node_s rasqal_map_node;
+
+
+static rasqal_map_node*
+rasqal_new_map_node(rasqal_map* map, void *key, void *value)
+{
+ rasqal_map_node *node;
+ node=(rasqal_map_node*)RASQAL_CALLOC(rasqal_map_node, 1, sizeof(rasqal_map_node));
+ if(!node)
+ return NULL;
+ node->map=map;
+ node->key=key;
+ node->value=value;
+ return node;
+}
+
+
+static void
+rasqal_free_map_node(rasqal_map_node *node, rasqal_kv_free_fn* free_fn)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(node, rasqal_map_node);
+
+ if(node->prev)
+ rasqal_free_map_node(node->prev, free_fn);
+ if(node->next)
+ rasqal_free_map_node(node->next, free_fn);
+
+ free_fn(node->key, node->value);
+
+ RASQAL_FREE(rasqal_map_node, node);
+}
+
+
+/**
+ * rasqal_new_map:
+ * @compare_fn: comparison function for keys
+ * @compare_user_data: user data pointer for @compare_fn
+ * @free_compare_data_fn: function to free @compare_user_data once done
+ * @free_fn: free function for (key, value) pair
+ * @print_key_fn: print a key function (or NULL)
+ * @print_value_fn: print a value function (or NULL)
+ * @flags: non-0 to allow duplicates
+ *
+ * Constructor - Create a (key:value) map.
+ *
+ * Return value: a new #rasqal_map or NULL on failure
+ **/
+rasqal_map*
+rasqal_new_map(rasqal_compare_fn* compare_fn,
+ void *compare_user_data,
+ rasqal_compare_free_user_data_fn* free_compare_data_fn,
+ rasqal_kv_free_fn* free_fn,
+ raptor_sequence_print_handler* print_key_fn,
+ raptor_sequence_print_handler* print_value_fn,
+ int flags)
+{
+ rasqal_map *map;
+ map = (rasqal_map*)RASQAL_CALLOC(rasqal_map, 1, sizeof(rasqal_map));
+ if(!map) {
+ if(free_compare_data_fn)
+ free_compare_data_fn(compare_user_data);
+ return NULL;
+ }
+
+ map->compare = compare_fn;
+ map->compare_user_data = compare_user_data;
+ map->free_compare_data = free_compare_data_fn;
+ map->free = free_fn;
+ map->print_key = print_key_fn;
+ map->print_value = print_value_fn;
+ map->allow_duplicates = flags;
+
+ return map;
+}
+
+
+/**
+ * rasqal_free_map:
+ * @map: the #rasqal_map to free
+ *
+ * Destructor - Destroy a (key:value) map.
+ *
+ **/
+void
+rasqal_free_map(rasqal_map *map)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(map, rasqal_map);
+
+ if(map->root)
+ rasqal_free_map_node(map->root, map->free);
+
+ if(map->free_compare_data)
+ map->free_compare_data(map->compare_user_data);
+
+ RASQAL_FREE(rasqal_map, map);
+}
+
+
+static int
+rasqal_map_node_add_kv(rasqal_map_node* node, void *key, void *value)
+{
+ rasqal_map *map = node->map;
+ int result;
+
+ result = map->compare(map->compare_user_data, &key, &node->key);
+ if(result < 0) {
+ if(node->prev)
+ return rasqal_map_node_add_kv(node->prev, key, value);
+ node->prev = rasqal_new_map_node(map, key, value);
+ return node->prev ? 0 : -1;
+ } else if(!result) {
+ if(!node->map->allow_duplicates) {
+ /* duplicate and not allowed */
+ return 1;
+ }
+ /* duplicate, fall through */
+ }
+
+ /* result > 0 */
+ if(node->next)
+ return rasqal_map_node_add_kv(node->next, key, value);
+
+ node->next = rasqal_new_map_node(map, key, value);
+ return node->next ? 0 : -1;
+}
+
+
+/**
+ * rasqal_map_add_kv:
+ * @map: #rasqal_map adding to
+ * @key: key data
+ * @value: value data (or NULL)
+ *
+ * Add a (key, value) pair to the map.
+ *
+ * Return value: non-0 on failure including adding a duplicate.
+ **/
+int
+rasqal_map_add_kv(rasqal_map* map, void* key, void *value)
+{
+ if(!map->root) {
+ map->root=rasqal_new_map_node(map, key, value);
+ return map->root ? 0 : -1;
+ }
+
+ return rasqal_map_node_add_kv(map->root, key, value);
+}
+
+
+#define SPACES_LENGTH 80
+static const char rasqal_map_node_spaces[SPACES_LENGTH+1]=" ";
+
+
+static void
+rasqal_map_node_write_indent(FILE *fh, int indent)
+{
+ while(indent > 0) {
+ int sp=(indent > SPACES_LENGTH) ? SPACES_LENGTH : indent;
+ (void)fwrite(rasqal_map_node_spaces, sizeof(char), sp, fh);
+ indent -= sp;
+ }
+}
+
+
+
+static void
+rasqal_map_node_visit(rasqal_map_node* node,
+ rasqal_map_visit_fn fn, void *user_data)
+{
+ if(node->prev)
+ rasqal_map_node_visit(node->prev, fn, user_data);
+ fn(node->key, node->value, user_data);
+ if(node->next)
+ rasqal_map_node_visit(node->next, fn, user_data);
+}
+
+
+/**
+ * rasqal_map_visit:
+ * @map: the #rasqal_map to visit
+ * @fn: user function to call with key, value and @user_data
+ * @user_data: user data to pass to visit function
+ *
+ * Walk all entries in a (key:value) map.
+ *
+ **/
+void
+rasqal_map_visit(rasqal_map* map, rasqal_map_visit_fn fn, void *user_data)
+{
+ if(map->root)
+ rasqal_map_node_visit(map->root, fn, user_data);
+}
+
+
+struct print_info
+{
+ rasqal_map* map;
+ FILE *fh;
+ int indent;
+};
+
+
+static void
+rasqal_map_node_print_visit(void *key, void *value, void *user_data)
+{
+ struct print_info* pi=(struct print_info*)user_data;
+ FILE* fh;
+ int indent;
+
+ fh=pi->fh;
+ indent=pi->indent;
+
+ rasqal_map_node_write_indent(fh, indent);
+ fputs("{key: ", fh);
+ if(!key)
+ fputs("NULL", fh);
+ else if(pi->map->print_key)
+ pi->map->print_key(key, fh);
+ else
+ fprintf(fh, "%p", key);
+
+ fputs(", value: ", fh);
+
+ if(!value)
+ fputs("NULL", fh);
+ else if(pi->map->print_value)
+ pi->map->print_value(value, fh);
+ else
+ fprintf(fh, "%p", value);
+
+ fputs("}\n", fh);
+}
+
+
+/**
+ * rasqal_map_print:
+ * @map: #rasqal_map to print
+ * @fh: FILE handle to write to.
+ *
+ * Print a (key:value) map in a debug format.
+ *
+ **/
+void
+rasqal_map_print(rasqal_map* map, FILE* fh)
+{
+ fprintf(fh, "map duplicates=%s {\n", map->allow_duplicates ? "yes" : "no");
+ if(map->root) {
+ struct print_info pi;
+ pi.map=map;
+ pi.fh=fh;
+ pi.indent=2;
+ rasqal_map_visit(map, rasqal_map_node_print_visit, &pi);
+ }
+
+ fputs("}\n", fh);
+}
diff --git a/src/rasqal/rasqal_query.c b/src/rasqal/rasqal_query.c
new file mode 100644
index 0000000..65f1ad6
--- /dev/null
+++ b/src/rasqal/rasqal_query.c
@@ -0,0 +1,2382 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_query.c - Rasqal RDF Query
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+/**
+ *
+ * Query Class Internals
+ *
+ * This is the main Rasqal class for constructing RDF graph queries
+ * from a syntax or by API, preparing them for execution with a query
+ * execution and executing them to return a result set.
+ *
+ * Queries are constructed from a syntax in some query language
+ * syntax and build an RDF query API structure based on triple
+ * patterns, filter expressions, graph patterns above them operating
+ * over a set of graphs.
+ *
+ * This class does not deal with manipulating result sets which are
+ * handled by the #rasqal_query_results and methods on it although
+ * rasqal_query_execute() does return a newly constructed result
+ * object.
+ *
+ * It also does not deal with executing a query which is handled by
+ * #rasqal_query_execution_factory instances that have their own
+ * simpler API.
+ *
+ */
+
+#define DEBUG_FH stderr
+
+#if 0
+#undef RASQAL_NO_GP_MERGE
+#else
+#define RASQAL_NO_GP_MERGE 1
+#endif
+
+
+static int rasqal_query_add_query_result(rasqal_query* query, rasqal_query_results* query_results);
+static int rasqal_query_write_sparql_20060406(raptor_iostream *iostr, rasqal_query* query, raptor_uri *base_uri);
+
+
+/**
+ * rasqal_new_query:
+ * @world: rasqal_world object
+ * @name: the query language name (or NULL)
+ * @uri: #raptor_uri language uri (or NULL)
+ *
+ * Constructor - create a new rasqal_query object.
+ *
+ * A query language can be named or identified by a URI, either
+ * of which is optional. The default query language will be used
+ * if both are NULL. rasqal_languages_enumerate returns
+ * information on the known names, labels and URIs.
+ *
+ * Return value: a new #rasqal_query object or NULL on failure
+ */
+rasqal_query*
+rasqal_new_query(rasqal_world *world, const char *name,
+ const unsigned char *uri)
+{
+ rasqal_query_language_factory* factory;
+ rasqal_query* query;
+#ifndef RAPTOR_V2_AVAILABLE
+ const raptor_uri_handler *uri_handler;
+ void *uri_context;
+#endif
+
+ factory = rasqal_get_query_language_factory(world, name, uri);
+ if(!factory)
+ return NULL;
+
+ query = (rasqal_query*)RASQAL_CALLOC(rasqal_query, 1, sizeof(rasqal_query));
+ if(!query)
+ return NULL;
+
+ /* set usage first to 1 so we can clean up with rasqal_free_query() on error */
+ query->usage = 1;
+
+ query->world = world;
+
+ query->factory = factory;
+
+ query->limit = -1;
+ query->offset = -1;
+
+ query->genid_counter = 1;
+
+ query->context = (char*)RASQAL_CALLOC(rasqal_query_context, 1,
+ factory->context_length);
+ if(!query->context)
+ goto tidy;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ query->namespaces = raptor_new_namespaces_v2(world->raptor_world_ptr,
+ (raptor_simple_message_handler)rasqal_query_simple_error,
+ query,
+ 0);
+#else
+ raptor_uri_get_handler(&uri_handler, &uri_context);
+ query->namespaces = raptor_new_namespaces(uri_handler, uri_context,
+ (raptor_simple_message_handler)rasqal_query_simple_error,
+ query,
+ 0);
+#endif
+ if(!query->namespaces)
+ goto tidy;
+
+ query->vars_table = rasqal_new_variables_table(query->world);
+ if(!query->vars_table)
+ goto tidy;
+
+ query->triples = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_triple, (raptor_sequence_print_handler*)rasqal_triple_print);
+ if(!query->triples)
+ goto tidy;
+
+ query->prefixes = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_prefix, (raptor_sequence_print_handler*)rasqal_prefix_print);
+ if(!query->prefixes)
+ goto tidy;
+
+ query->data_graphs = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_data_graph, (raptor_sequence_print_handler*)rasqal_data_graph_print);
+ if(!query->data_graphs)
+ goto tidy;
+
+ query->results = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_query_results_remove_query_reference, NULL);
+ if(!query->results)
+ goto tidy;
+
+ if(factory->init(query, name))
+ goto tidy;
+
+ return query;
+
+ tidy:
+ rasqal_free_query(query);
+ return NULL;
+}
+
+
+
+/**
+ * rasqal_free_query:
+ * @query: #rasqal_query object
+ *
+ * Destructor - destroy a #rasqal_query object.
+ **/
+void
+rasqal_free_query(rasqal_query* query)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(query, rasqal_query);
+
+ if(--query->usage)
+ return;
+
+ if(query->factory)
+ query->factory->terminate(query);
+
+ if(query->context)
+ RASQAL_FREE(rasqal_query_context, query->context);
+
+ if(query->namespaces)
+ raptor_free_namespaces(query->namespaces);
+
+ if(query->base_uri)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(query->world->raptor_world_ptr, query->base_uri);
+#else
+ raptor_free_uri(query->base_uri);
+#endif
+
+ if(query->query_string)
+ RASQAL_FREE(cstring, query->query_string);
+
+ if(query->data_graphs)
+ raptor_free_sequence(query->data_graphs);
+ if(query->selects)
+ raptor_free_sequence(query->selects);
+ if(query->describes)
+ raptor_free_sequence(query->describes);
+
+ if(query->triples)
+ raptor_free_sequence(query->triples);
+ if(query->optional_triples)
+ raptor_free_sequence(query->optional_triples);
+ if(query->constructs)
+ raptor_free_sequence(query->constructs);
+ if(query->prefixes)
+ raptor_free_sequence(query->prefixes);
+ if(query->results)
+ raptor_free_sequence(query->results);
+
+ if(query->variables_declared_in)
+ RASQAL_FREE(intarray, query->variables_declared_in);
+
+ if(query->query_graph_pattern)
+ rasqal_free_graph_pattern(query->query_graph_pattern);
+
+ if(query->order_conditions_sequence)
+ raptor_free_sequence(query->order_conditions_sequence);
+
+ if(query->group_conditions_sequence)
+ raptor_free_sequence(query->group_conditions_sequence);
+
+ if(query->graph_patterns_sequence)
+ raptor_free_sequence(query->graph_patterns_sequence);
+
+ if(query->query_results_formatter_name)
+ RASQAL_FREE(cstring, query->query_results_formatter_name);
+
+ /* Do this last since most everything above could refer to a variable */
+ if(query->vars_table)
+ rasqal_free_variables_table(query->vars_table);
+ RASQAL_FREE(rasqal_query, query);
+}
+
+
+/* Methods */
+
+/**
+ * rasqal_query_get_name:
+ * @query: #rasqal_query query object
+ *
+ * Get a short name for the query language.
+ *
+ * Return value: shared string label value
+ **/
+const char*
+rasqal_query_get_name(rasqal_query* query)
+{
+ return query->factory->name;
+}
+
+
+/**
+ * rasqal_query_get_label:
+ * @query: #rasqal_query query object
+ *
+ * Get a readable label for the query language.
+ *
+ * Return value: shared string label value
+ **/
+const char*
+rasqal_query_get_label(rasqal_query* query)
+{
+ return query->factory->label;
+}
+
+
+/**
+ * rasqal_query_set_fatal_error_handler:
+ * @query: the query
+ * @user_data: user data to pass to function
+ * @handler: pointer to the function
+ *
+ * Set the query error handling function.
+ *
+ * The function will receive callbacks when the query fails.
+ *
+ **/
+void
+rasqal_query_set_fatal_error_handler(rasqal_query* query, void *user_data,
+ raptor_message_handler handler)
+{
+ raptor_error_handlers* error_handlers;
+ if(!query || !query->world)
+ return;
+
+ error_handlers = &query->world->error_handlers;
+
+ error_handlers->handlers[RAPTOR_LOG_LEVEL_FATAL].user_data = user_data;
+ error_handlers->handlers[RAPTOR_LOG_LEVEL_FATAL].handler = handler;
+}
+
+
+/**
+ * rasqal_query_set_error_handler:
+ * @query: the query
+ * @user_data: user data to pass to function
+ * @handler: pointer to the function
+ *
+ * Set the query error handling function.
+ *
+ * The function will receive callbacks when the query fails.
+ *
+ **/
+void
+rasqal_query_set_error_handler(rasqal_query* query, void *user_data,
+ raptor_message_handler handler)
+{
+ raptor_error_handlers* error_handlers;
+ if(!query || !query->world)
+ return;
+
+ error_handlers = &query->world->error_handlers;
+
+ error_handlers->handlers[RAPTOR_LOG_LEVEL_ERROR].user_data = user_data;
+ error_handlers->handlers[RAPTOR_LOG_LEVEL_ERROR].handler = handler;
+}
+
+
+/**
+ * rasqal_query_set_warning_handler:
+ * @query: the query
+ * @user_data: user data to pass to function
+ * @handler: pointer to the function
+ *
+ * Set the query warning handling function.
+ *
+ * The function will receive callbacks when the query gives a warning.
+ *
+ **/
+void
+rasqal_query_set_warning_handler(rasqal_query* query, void *user_data,
+ raptor_message_handler handler)
+{
+ raptor_error_handlers* error_handlers;
+ if(!query || !query->world)
+ return;
+
+ error_handlers = &query->world->error_handlers;
+
+ error_handlers->handlers[RAPTOR_LOG_LEVEL_WARNING].user_data = user_data;
+ error_handlers->handlers[RAPTOR_LOG_LEVEL_WARNING].handler =handler;
+}
+
+
+/**
+ * rasqal_query_set_feature:
+ * @query: #rasqal_query query object
+ * @feature: feature to set from enumerated #rasqal_feature values
+ * @value: integer feature value
+ *
+ * Set various query features.
+ *
+ * The allowed features are available via rasqal_features_enumerate().
+ *
+ * Return value: non 0 on failure or if the feature is unknown
+ **/
+int
+rasqal_query_set_feature(rasqal_query* query, rasqal_feature feature, int value)
+{
+ switch(feature) {
+ case RASQAL_FEATURE_NO_NET:
+ query->features[(int)feature] = value;
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_set_feature_string:
+ * @query: #rasqal_query query object
+ * @feature: feature to set from enumerated #rasqal_feature values
+ * @value: feature value
+ *
+ * Set query features with string values.
+ *
+ * The allowed features are available via rasqal_features_enumerate().
+ * If the feature type is integer, the value is interpreted as an integer.
+ *
+ * Return value: non 0 on failure or if the feature is unknown
+ **/
+int
+rasqal_query_set_feature_string(rasqal_query *query,
+ rasqal_feature feature,
+ const unsigned char *value)
+{
+ int value_is_string = (rasqal_feature_value_type(feature) == 1);
+ if(!value_is_string)
+ return rasqal_query_set_feature(query, feature, atoi((const char*)value));
+
+ return -1;
+}
+
+
+/**
+ * rasqal_query_get_feature:
+ * @query: #rasqal_query query object
+ * @feature: feature to get value
+ *
+ * Get various query features.
+ *
+ * The allowed features are available via rasqal_features_enumerate().
+ *
+ * Note: no feature value is negative
+ *
+ * Return value: feature value or < 0 for an illegal feature
+ **/
+int
+rasqal_query_get_feature(rasqal_query *query, rasqal_feature feature)
+{
+ int result= -1;
+
+ switch(feature) {
+ case RASQAL_FEATURE_NO_NET:
+ result = (query->features[(int)feature] != 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return result;
+}
+
+
+/**
+ * rasqal_query_get_feature_string:
+ * @query: #rasqal_query query object
+ * @feature: feature to get value
+ *
+ * Get query features with string values.
+ *
+ * The allowed features are available via rasqal_features_enumerate().
+ * If a string is returned, it must be freed by the caller.
+ *
+ * Return value: feature value or NULL for an illegal feature or no value
+ **/
+const unsigned char *
+rasqal_query_get_feature_string(rasqal_query *query,
+ rasqal_feature feature)
+{
+ int value_is_string = (rasqal_feature_value_type(feature) == 1);
+ if(!value_is_string)
+ return NULL;
+
+ return NULL;
+}
+
+
+/**
+ * rasqal_query_get_distinct:
+ * @query: #rasqal_query query object
+ *
+ * Get the query distinct mode
+ *
+ * See rasqal_query_set_distinct() for the distinct modes.
+ *
+ * Return value: non-0 if the results should be distinct
+ **/
+int
+rasqal_query_get_distinct(rasqal_query* query)
+{
+ return query->distinct;
+}
+
+
+/**
+ * rasqal_query_set_distinct:
+ * @query: #rasqal_query query object
+ * @distinct_mode: distinct mode
+ *
+ * Set the query distinct results mode.
+ *
+ * The allowed @distinct_mode values are:
+ * 0 if not given
+ * 1 if DISTINCT: ensure solutions are unique
+ * 2 if SPARQL REDUCED: permit elimination of some non-unique solutions
+ *
+ **/
+void
+rasqal_query_set_distinct(rasqal_query* query, int distinct_mode)
+{
+ if(distinct_mode >= 0 && distinct_mode <= 2)
+ query->distinct= distinct_mode;
+ else
+ query->distinct= 0;
+}
+
+
+/**
+ * rasqal_query_get_explain:
+ * @query: #rasqal_query query object
+ *
+ * Get the query explain results flag.
+ *
+ * Return value: non-0 if the results should be explain
+ **/
+int
+rasqal_query_get_explain(rasqal_query* query)
+{
+ return query->explain;
+}
+
+
+/**
+ * rasqal_query_set_explain:
+ * @query: #rasqal_query query object
+ * @is_explain: non-0 if explain
+ *
+ * Set the query explain results flag.
+ *
+ **/
+void
+rasqal_query_set_explain(rasqal_query* query, int is_explain)
+{
+ query->explain= (is_explain != 0) ? 1 : 0;
+}
+
+
+/**
+ * rasqal_query_get_limit:
+ * @query: #rasqal_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
+rasqal_query_get_limit(rasqal_query* query)
+{
+ return query->limit;
+}
+
+
+/**
+ * rasqal_query_set_limit:
+ * @query: #rasqal_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.
+ **/
+void
+rasqal_query_set_limit(rasqal_query* query, int limit)
+{
+ query->limit = limit;
+}
+
+
+/**
+ * rasqal_query_get_offset:
+ * @query: #rasqal_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
+rasqal_query_get_offset(rasqal_query* query)
+{
+ return query->offset;
+}
+
+
+/**
+ * rasqal_query_set_offset:
+ * @query: #rasqal_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.
+ **/
+void
+rasqal_query_set_offset(rasqal_query* query, int offset)
+{
+ query->offset = offset;
+}
+
+
+/**
+ * rasqal_query_add_data_graph:
+ * @query: #rasqal_query query object
+ * @uri: #raptor_uri source uri for retrieval
+ * @name_uri: #raptor_uri name uri (or NULL)
+ * @flags: RASQAL_DATA_GRAPH_NAMED or RASQAL_DATA_GRAPH_BACKGROUND
+ *
+ * Add a data graph to the query.
+ *
+ * named_uri must be given if flags RASQAL_DATA_GRAPH_NAMED is set.
+ * It is the name of the graph and also used as the base URI
+ * when resolving any relative URIs for the graph in uri.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_add_data_graph(rasqal_query* query,
+ raptor_uri* uri, raptor_uri* name_uri,
+ int flags)
+{
+ rasqal_data_graph *dg;
+
+ if((flags & RASQAL_DATA_GRAPH_NAMED) && !name_uri)
+ return 1;
+
+ dg = rasqal_new_data_graph(query->world, uri, name_uri, flags);
+ if(!dg)
+ return 1;
+ if(raptor_sequence_push(query->data_graphs, (void*)dg))
+ return 1;
+ return 0;
+}
+
+
+/**
+ * rasqal_query_get_data_graph_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of data_graph URIs.
+ *
+ * Return value: a #raptor_sequence of #raptor_uri pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_data_graph_sequence(rasqal_query* query)
+{
+ return query->data_graphs;
+}
+
+
+/**
+ * rasqal_query_get_data_graph:
+ * @query: #rasqal_query query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a rasqal_data_graph* in the sequence of data_graphs.
+ *
+ * Return value: a #rasqal_data_graph pointer or NULL if out of the sequence range
+ **/
+rasqal_data_graph*
+rasqal_query_get_data_graph(rasqal_query* query, int idx)
+{
+ if(!query->data_graphs)
+ return NULL;
+
+ return (rasqal_data_graph*)raptor_sequence_get_at(query->data_graphs, idx);
+}
+
+
+/**
+ * rasqal_query_dataset_contains_named_graph:
+ * @query: #rasqal_query query object
+ * @graph_uri: query URI
+ *
+ * Test if the query dataset contains a named graph
+ *
+ * Return value: non-0 if the dataset contains a named graph
+ */
+int
+rasqal_query_dataset_contains_named_graph(rasqal_query* query,
+ raptor_uri *graph_uri)
+{
+ rasqal_data_graph *dg;
+ int idx;
+ int found = 0;
+
+ for(idx = 0; (dg = rasqal_query_get_data_graph(query, idx)); idx++) {
+ if(dg->name_uri &&
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_equals_v2(query->world->raptor_world_ptr, dg->name_uri, graph_uri)
+#else
+ raptor_uri_equals(dg->name_uri, graph_uri)
+#endif
+ )
+ {
+ /* graph_uri is a graph name in the dataset */
+ found = 1;
+ break;
+ }
+ }
+ return found;
+}
+
+
+/**
+ * rasqal_query_add_variable:
+ * @query: #rasqal_query query object
+ * @var: #rasqal_variable variable
+ *
+ * Add a binding variable to the query.
+ *
+ * See also rasqal_query_set_variable which assigns or removes a value to
+ * a previously added variable in the query.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_add_variable(rasqal_query* query, rasqal_variable* var)
+{
+ if(!query->selects) {
+ query->selects = raptor_new_sequence(NULL, (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!query->selects)
+ return 1;
+ }
+
+ return raptor_sequence_push(query->selects, (void*)var);
+}
+
+
+/**
+ * rasqal_query_get_bound_variable_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of variables to bind in the query.
+ *
+ * This returns the sequence of variables that are explicitly chosen
+ * via SELECT in RDQL, SPARQL. Or all variables mentioned with SELECT *
+ *
+ * Return value: a #raptor_sequence of #rasqal_variable pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_bound_variable_sequence(rasqal_query* query)
+{
+ return query->selects;
+}
+
+
+/**
+ * rasqal_query_get_anonymous_variable_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of anonymous variables mentioned in the query.
+ *
+ * Return value: a #raptor_sequence of #rasqal_variable pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_anonymous_variable_sequence(rasqal_query* query)
+{
+ return rasqal_variables_table_get_anonymous_variables_sequence(query->vars_table);
+}
+
+
+/**
+ * rasqal_query_get_all_variable_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of all variables mentioned in the query.
+ *
+ * Return value: a #raptor_sequence of #rasqal_variable pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_all_variable_sequence(rasqal_query* query)
+{
+ return rasqal_variables_table_get_named_variables_sequence(query->vars_table);
+}
+
+
+/**
+ * rasqal_query_get_variable:
+ * @query: #rasqal_query query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a variable in the sequence of variables to bind.
+ *
+ * Return value: a #rasqal_variable pointer or NULL if out of the sequence range
+ **/
+rasqal_variable*
+rasqal_query_get_variable(rasqal_query* query, int idx)
+{
+ if(!query->selects || idx < 0 || idx > query->select_variables_count)
+ return NULL;
+
+ return rasqal_variables_table_get(query->vars_table, idx);
+}
+
+
+/**
+ * rasqal_query_has_variable:
+ * @query: #rasqal_query query object
+ * @name: variable name
+ *
+ * Find if the named variable is in the sequence of variables to bind.
+ *
+ * Return value: non-0 if the variable name was found.
+ **/
+int
+rasqal_query_has_variable(rasqal_query* query, const unsigned char *name)
+{
+ return rasqal_variables_table_has(query->vars_table, name);
+}
+
+
+/**
+ * rasqal_query_set_variable:
+ * @query: #rasqal_query query object
+ * @name: #rasqal_variable variable
+ * @value: #rasqal_literal value to set or NULL
+ *
+ * Add a binding variable to the query.
+ *
+ * See also rasqal_query_add_variable which adds a new binding variable
+ * and must be called before this method is invoked.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_set_variable(rasqal_query* query, const unsigned char *name,
+ rasqal_literal* value)
+{
+ int i;
+
+ if(!query->selects)
+ return 1;
+
+ for(i = 0; i< raptor_sequence_size(query->selects); i++) {
+ rasqal_variable* v;
+ v = (rasqal_variable*)raptor_sequence_get_at(query->selects, i);
+ if(!strcmp((const char*)v->name, (const char*)name)) {
+ if(v->value)
+ rasqal_free_literal(v->value);
+ v->value = value;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/**
+ * rasqal_query_get_triple_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of matching triples in the query.
+ *
+ * Return value: a #raptor_sequence of #rasqal_triple pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_triple_sequence(rasqal_query* query)
+{
+ return query->triples;
+}
+
+
+/**
+ * rasqal_query_get_triple:
+ * @query: #rasqal_query query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a triple in the sequence of matching triples in the query.
+ *
+ * Return value: a #rasqal_triple pointer or NULL if out of the sequence range
+ **/
+rasqal_triple*
+rasqal_query_get_triple(rasqal_query* query, int idx)
+{
+ if(!query->triples)
+ return NULL;
+
+ return (rasqal_triple*)raptor_sequence_get_at(query->triples, idx);
+}
+
+
+int
+rasqal_query_declare_prefix(rasqal_query *rq, rasqal_prefix *p)
+{
+ if(p->declared)
+ return 0;
+
+ if(raptor_namespaces_start_namespace_full(rq->namespaces,
+ p->prefix,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(rq->world->raptor_world_ptr, p->uri),
+#else
+ raptor_uri_as_string(p->uri),
+#endif
+ rq->prefix_depth))
+ return 1;
+ p->declared = 1;
+ rq->prefix_depth++;
+ return 0;
+}
+
+
+static int
+rasqal_query_undeclare_prefix(rasqal_query *rq, rasqal_prefix *prefix)
+{
+ if(!prefix->declared) {
+ prefix->declared = 1;
+ return 0;
+ }
+
+ raptor_namespaces_end_for_depth(rq->namespaces, prefix->depth);
+ return 0;
+}
+
+
+int
+rasqal_query_declare_prefixes(rasqal_query *rq)
+{
+ int i;
+
+ if(!rq->prefixes)
+ return 0;
+
+ for(i = 0; i< raptor_sequence_size(rq->prefixes); i++) {
+ rasqal_prefix* p = (rasqal_prefix*)raptor_sequence_get_at(rq->prefixes, i);
+ if(rasqal_query_declare_prefix(rq, p))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_add_prefix:
+ * @query: #rasqal_query query object
+ * @prefix: #rasqal_prefix namespace prefix, URI
+ *
+ * Add a namespace prefix to the query.
+ *
+ * If the prefix has already been used, the old URI will be overridden.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_add_prefix(rasqal_query* query, rasqal_prefix* prefix)
+{
+ if(!query->prefixes) {
+ query->prefixes = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_prefix, (raptor_sequence_print_handler*)rasqal_prefix_print);
+ if(!query->prefixes)
+ return 1;
+ } else {
+ int i;
+ for(i = 0; i< raptor_sequence_size(query->prefixes); i++) {
+ rasqal_prefix* p;
+ p = (rasqal_prefix*)raptor_sequence_get_at(query->prefixes, i);
+ if(strcmp((const char*)p->prefix, (const char*)prefix->prefix)) {
+ rasqal_query_undeclare_prefix(query, p);
+ break;
+ }
+ }
+ }
+
+ return raptor_sequence_push(query->prefixes, (void*)prefix);
+}
+
+
+/**
+ * rasqal_query_get_prefix_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of namespace prefixes in the query.
+ *
+ * Return value: a #raptor_sequence of #rasqal_prefix pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_prefix_sequence(rasqal_query* query)
+{
+ return query->prefixes;
+}
+
+
+/**
+ * rasqal_query_get_prefix:
+ * @query: #rasqal_query query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a prefix in the sequence of namespsace prefixes in the query.
+ *
+ * Return value: a #rasqal_prefix pointer or NULL if out of the sequence range
+ **/
+rasqal_prefix*
+rasqal_query_get_prefix(rasqal_query* query, int idx)
+{
+ if(!query->prefixes)
+ return NULL;
+
+ return (rasqal_prefix*)raptor_sequence_get_at(query->prefixes, idx);
+}
+
+
+/**
+ * rasqal_query_get_query_graph_pattern:
+ * @query: #rasqal_query query object
+ *
+ * Get the top query graph pattern.
+ *
+ * Return value: a #rasqal_graph_pattern of the top query graph pattern
+ **/
+rasqal_graph_pattern*
+rasqal_query_get_query_graph_pattern(rasqal_query* query)
+{
+ return query->query_graph_pattern;
+}
+
+
+/**
+ * rasqal_query_get_graph_pattern_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of graph_patterns expressions inside the top query graph pattern.
+ *
+ * Return value: a #raptor_sequence of #rasqal_graph_pattern pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_graph_pattern_sequence(rasqal_query* query)
+{
+ return rasqal_graph_pattern_get_sub_graph_pattern_sequence(query->query_graph_pattern);
+}
+
+
+/**
+ * rasqal_query_get_graph_pattern:
+ * @query: #rasqal_query query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a graph_pattern in the sequence of graph_pattern expressions in the top query graph pattern.
+ *
+ * Return value: a #rasqal_graph_pattern pointer or NULL if out of the sequence range
+ **/
+rasqal_graph_pattern*
+rasqal_query_get_graph_pattern(rasqal_query* query, int idx)
+{
+ return rasqal_graph_pattern_get_sub_graph_pattern(query->query_graph_pattern, idx);
+}
+
+
+/**
+ * rasqal_query_get_construct_triples_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of triples for a construct.
+ *
+ * Return value: a #raptor_sequence of #rasqal_triple pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_construct_triples_sequence(rasqal_query* query)
+{
+ return query->constructs;
+}
+
+
+/**
+ * rasqal_query_get_construct_triple:
+ * @query: #rasqal_query query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a triple in the sequence of construct triples.
+ *
+ * Return value: a #rasqal_triple pointer or NULL if out of the sequence range
+ **/
+rasqal_triple*
+rasqal_query_get_construct_triple(rasqal_query* query, int idx)
+{
+ if(!query->constructs)
+ return NULL;
+
+ return (rasqal_triple*)raptor_sequence_get_at(query->constructs, idx);
+}
+
+
+
+/**
+ * rasqal_query_prepare:
+ * @query: the #rasqal_query object
+ * @query_string: the query string (or NULL)
+ * @base_uri: base URI of query string (optional)
+ *
+ * Prepare a query - typically parse it.
+ *
+ * Some query languages may require a base URI to resolve any
+ * relative URIs in the query string. If this is not given,
+ * the current directory in the filesystem is used as the base URI.
+ *
+ * The query string may be NULL in which case it is not parsed
+ * and the query parts may be created by API calls such as
+ * rasqal_query_add_source etc.
+ *
+ * Return value: non-0 on failure.
+ **/
+int
+rasqal_query_prepare(rasqal_query* query,
+ const unsigned char *query_string,
+ raptor_uri *base_uri)
+{
+ int rc = 0;
+
+ if(query->failed)
+ return 1;
+
+ if(query->prepared)
+ return 0;
+ query->prepared = 1;
+
+ if(query_string) {
+ /* flex lexers require two NULs at the end of the lexed buffer.
+ * Add them here instead of parser to allow resource cleanup on error.
+ *
+ * flex manual:
+ *
+ * Function: YY_BUFFER_STATE yy_scan_buffer (char *base, yy_size_t size)
+ * which scans in place the buffer starting at `base', consisting of
+ * `size' bytes, the last two bytes of which _must_ be
+ * `YY_END_OF_BUFFER_CHAR' (ASCII NUL). These last two bytes are not
+ * scanned; thus, scanning consists of `base[0]' through
+ * `base[size-2]', inclusive.
+ */
+ int len = strlen((const char*)query_string)+3; /* +3 for " \0\0" */
+ unsigned char *query_string_copy = (unsigned char*)RASQAL_MALLOC(cstring, len);
+ if(!query_string_copy) {
+ query->failed = 1;
+ return 1;
+ }
+ strcpy((char*)query_string_copy, (const char*)query_string);
+ query_string_copy[len-3] = ' ';
+ query_string_copy[len-2] = query_string_copy[len-1] = '\0';
+ query->query_string = query_string_copy;
+ query->query_string_length = len;
+ }
+
+ if(base_uri)
+#ifdef RAPTOR_V2_AVAILABLE
+ base_uri = raptor_uri_copy_v2(query->world->raptor_world_ptr, base_uri);
+#else
+ base_uri = raptor_uri_copy(base_uri);
+#endif
+ else {
+ unsigned char *uri_string = raptor_uri_filename_to_uri_string("");
+#ifdef RAPTOR_V2_AVAILABLE
+ base_uri = raptor_new_uri_v2(query->world->raptor_world_ptr, uri_string);
+#else
+ base_uri = raptor_new_uri(uri_string);
+#endif
+ if(uri_string)
+ raptor_free_memory(uri_string);
+ }
+
+ rasqal_query_set_base_uri(query, base_uri);
+ query->locator.line = query->locator.column = query->locator.byte = -1;
+
+ rc = query->factory->prepare(query);
+ if(rc) {
+ query->failed = 1;
+ rc = 1;
+ } else if(rasqal_query_prepare_common(query)) {
+ query->failed = 1;
+ rc = 1;
+ }
+
+ return rc;
+}
+
+
+/**
+ * rasqal_query_get_engine_by_name:
+ * @name: query engine name
+ *
+ * INTERNAL - Get a query engine by name
+ *
+ * If @name is NULL or the name is unknown, the default factory is returned
+ *
+ * return value: pointer to factory
+ **/
+const rasqal_query_execution_factory*
+rasqal_query_get_engine_by_name(const char* name)
+{
+ const rasqal_query_execution_factory* engine = &rasqal_query_engine_1;
+
+#ifdef RASQAL_DEBUG
+ if(1) {
+ char* n = getenv("RASQAL_DEBUG_ENGINE");
+ if(n)
+ name = n;
+ }
+#endif
+
+ if(name) {
+ if(!strcmp(name, "1") || !strcmp(name, "original"))
+ engine = &rasqal_query_engine_1;
+ else if(!strcmp(name, "2") || !strcmp(name, "algebra"))
+ engine = &rasqal_query_engine_algebra;
+ }
+
+ return engine;
+}
+
+
+/**
+ * rasqal_query_execute_with_engine:
+ * @query: the #rasqal_query object
+ * @engine: execution engine factory
+ *
+ * INTERNAL - Excecute a query with a given factory and return results.
+ *
+ * return value: a #rasqal_query_results structure or NULL on failure.
+ **/
+rasqal_query_results*
+rasqal_query_execute_with_engine(rasqal_query* query,
+ const rasqal_query_execution_factory* engine)
+{
+ rasqal_query_results *query_results = NULL;
+
+ if(query->failed)
+ return NULL;
+
+ if(!engine)
+ engine = rasqal_query_get_engine_by_name(NULL);
+
+ query_results = rasqal_query_results_execute_with_engine(query, engine);
+ if(query_results && rasqal_query_add_query_result(query, query_results)) {
+ rasqal_free_query_results(query_results);
+ query_results = NULL;
+ }
+
+ return query_results;
+}
+
+
+/**
+ * rasqal_query_execute:
+ * @query: the #rasqal_query object
+ *
+ * Excute a query - run and return results.
+ *
+ * return value: a #rasqal_query_results structure or NULL on failure.
+ **/
+rasqal_query_results*
+rasqal_query_execute(rasqal_query* query)
+{
+ return rasqal_query_execute_with_engine(query, NULL);
+}
+
+
+static const char* const rasqal_query_verb_labels[RASQAL_QUERY_VERB_LAST+1] = {
+ "Unknown",
+ "SELECT",
+ "CONSTRUCT",
+ "DESCRIBE",
+ "ASK",
+ "DELETE",
+ "INSERT"
+};
+
+/* Utility methods */
+
+/**
+ * rasqal_query_verb_as_string:
+ * @verb: the #rasqal_query_verb verb of the query
+ *
+ * Get a string for the query verb.
+ *
+ * Return value: pointer to a shared string label for the query verb
+ **/
+const char*
+rasqal_query_verb_as_string(rasqal_query_verb verb)
+{
+ if(verb <= RASQAL_QUERY_VERB_UNKNOWN ||
+ verb > RASQAL_QUERY_VERB_LAST)
+ verb = RASQAL_QUERY_VERB_UNKNOWN;
+
+ return rasqal_query_verb_labels[(int)verb];
+}
+
+
+/**
+ * rasqal_query_print:
+ * @query: the #rasqal_query object
+ * @fh: the #FILE* handle to print to.
+ *
+ * Print a query in a debug format.
+ *
+ **/
+void
+rasqal_query_print(rasqal_query* query, FILE *fh)
+{
+ rasqal_variables_table* vars_table = query->vars_table;
+ raptor_sequence* seq;
+
+ fprintf(fh, "query verb: %s\n", rasqal_query_verb_as_string(query->verb));
+
+ if(query->distinct)
+ fprintf(fh, "query results distinct mode: %s\n",
+ (query->distinct == 1 ? "distinct" : "reduced"));
+ if(query->explain)
+ fputs("query results explain: yes\n", fh);
+ if(query->limit >= 0)
+ fprintf(fh, "query results limit: %d\n", query->limit);
+ if(query->offset >= 0)
+ fprintf(fh, "query results offset: %d\n", query->offset);
+
+ fputs("data graphs: ", fh);
+ if(query->data_graphs)
+ raptor_sequence_print(query->data_graphs, fh);
+ seq = rasqal_variables_table_get_named_variables_sequence(vars_table);
+ if(seq) {
+ fputs("\nnamed variables: ", fh);
+ raptor_sequence_print(seq, fh);
+ }
+ seq = rasqal_variables_table_get_anonymous_variables_sequence(vars_table);
+ if(seq) {
+ fputs("\nanonymous variables: ", fh);
+ raptor_sequence_print(seq, fh);
+ }
+ if(query->selects) {
+ fputs("\nbound variables: ", fh);
+ raptor_sequence_print(query->selects, fh);
+ }
+ if(query->describes) {
+ fputs("\ndescribes: ", fh);
+ raptor_sequence_print(query->describes, fh);
+ }
+ if(query->triples) {
+ fputs("\ntriples: ", fh);
+ raptor_sequence_print(query->triples, fh);
+ }
+ if(query->optional_triples) {
+ fputs("\noptional triples: ", fh);
+ raptor_sequence_print(query->optional_triples, fh);
+ }
+ if(query->constructs) {
+ fputs("\nconstructs: ", fh);
+ raptor_sequence_print(query->constructs, fh);
+ }
+ if(query->prefixes) {
+ fputs("\nprefixes: ", fh);
+ raptor_sequence_print(query->prefixes, fh);
+ }
+ if(query->query_graph_pattern) {
+ fputs("\nquery graph pattern: ", fh);
+ rasqal_graph_pattern_print(query->query_graph_pattern, fh);
+ }
+ if(query->order_conditions_sequence) {
+ fputs("\nquery order conditions: ", fh);
+ raptor_sequence_print(query->order_conditions_sequence, fh);
+ }
+ if(query->group_conditions_sequence) {
+ fputs("\nquery group conditions: ", fh);
+ raptor_sequence_print(query->group_conditions_sequence, fh);
+ }
+ fputc('\n', fh);
+}
+
+
+static int
+rasqal_query_add_query_result(rasqal_query* query,
+ rasqal_query_results* query_results)
+{
+ /* add reference to ensure query lives as long as this runs */
+
+ /* query->results sequence has rasqal_query_results_remove_query_reference()
+ as the free handler which calls rasqal_free_query() decrementing
+ query->usage */
+
+ query->usage++;
+
+ return raptor_sequence_push(query->results, query_results);
+}
+
+
+
+void
+rasqal_query_remove_query_result(rasqal_query* query,
+ rasqal_query_results* query_results)
+{
+ int i;
+ int size;
+
+ size = raptor_sequence_size(query->results);
+ for(i = 0 ; i < size; i++) {
+ rasqal_query_results *result;
+ result = (rasqal_query_results*)raptor_sequence_get_at(query->results, i);
+
+ if(result == query_results) {
+ raptor_sequence_set_at(query->results, i, NULL);
+ break;
+ }
+ }
+}
+
+
+
+/**
+ * rasqal_query_get_user_data:
+ * @query: #rasqal_query
+ *
+ * Get query user data.
+ *
+ * Return value: user data as set by rasqal_query_set_user_data
+ **/
+void*
+rasqal_query_get_user_data(rasqal_query* query)
+{
+ return query->user_data;
+}
+
+
+/**
+ * rasqal_query_set_user_data:
+ * @query: #rasqal_query
+ * @user_data: some user data to associate with the query
+ *
+ * Set the query user data.
+ *
+ **/
+void
+rasqal_query_set_user_data(rasqal_query* query, void *user_data)
+{
+ query->user_data = user_data;
+}
+
+
+/**
+ * rasqal_query_get_verb:
+ * @query: #rasqal_query
+ *
+ * Get the query verb.
+ *
+ * Return value: the operating verb of the query of type rasqal_query_verb
+ **/
+rasqal_query_verb
+rasqal_query_get_verb(rasqal_query* query)
+{
+ return query->verb;
+}
+
+
+/**
+ * rasqal_query_get_wildcard:
+ * @query: #rasqal_query
+ *
+ * Get the query verb is wildcard flag.
+ *
+ * Return value: non-0 if the query verb was a wildcard (such as SELECT *)
+ **/
+int
+rasqal_query_get_wildcard(rasqal_query* query)
+{
+ return query->wildcard;
+}
+
+
+/**
+ * rasqal_query_get_order_conditions_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of query ordering conditions.
+ *
+ * Return value: a #raptor_sequence of #rasqal_expression pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_order_conditions_sequence(rasqal_query* query)
+{
+ return query->order_conditions_sequence;
+}
+
+
+/**
+ * rasqal_query_get_order_condition:
+ * @query: #rasqal_query query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a query ordering expression in the sequence of query ordering conditions.
+ *
+ * Return value: a #rasqal_expression pointer or NULL if out of the sequence range
+ **/
+rasqal_expression*
+rasqal_query_get_order_condition(rasqal_query* query, int idx)
+{
+ if(!query->order_conditions_sequence)
+ return NULL;
+
+ return (rasqal_expression*)raptor_sequence_get_at(query->order_conditions_sequence, idx);
+}
+
+
+/**
+ * rasqal_query_get_group_conditions_sequence:
+ * @query: #rasqal_query query object
+ *
+ * Get the sequence of query grouping conditions.
+ *
+ * Return value: a #raptor_sequence of #rasqal_expression pointers.
+ **/
+raptor_sequence*
+rasqal_query_get_group_conditions_sequence(rasqal_query* query)
+{
+ return query->group_conditions_sequence;
+}
+
+
+/**
+ * rasqal_query_get_group_condition:
+ * @query: #rasqal_query query object
+ * @idx: index into the sequence (0 or larger)
+ *
+ * Get a query grouping expression in the sequence of query grouping conditions.
+ *
+ * Return value: a #rasqal_expression pointer or NULL if out of the sequence range
+ **/
+rasqal_expression*
+rasqal_query_get_group_condition(rasqal_query* query, int idx)
+{
+ if(!query->group_conditions_sequence)
+ return NULL;
+
+ return (rasqal_expression*)raptor_sequence_get_at(query->group_conditions_sequence, idx);
+}
+
+
+/**
+ * rasqal_query_graph_pattern_visit:
+ * @query: query
+ * @visit_fn: user function to operate on
+ * @data: user data to pass to function
+ *
+ * Visit all graph patterns in a query with a user function @visit_fn.
+ *
+ * See also rasqal_graph_pattern_visit().
+ **/
+void
+rasqal_query_graph_pattern_visit(rasqal_query* query,
+ rasqal_graph_pattern_visit_fn visit_fn,
+ void* data)
+{
+ rasqal_graph_pattern* gp = rasqal_query_get_query_graph_pattern(query);
+ if(!gp)
+ return;
+
+ rasqal_graph_pattern_visit(query, gp, visit_fn, data);
+}
+
+
+
+typedef struct
+{
+ rasqal_world* world;
+ raptor_uri* type_uri;
+ raptor_uri* base_uri;
+ raptor_namespace_stack *nstack;
+} sparql_writer_context;
+
+static void rasqal_query_write_sparql_expression(sparql_writer_context *wc, raptor_iostream* iostr, rasqal_expression* e);
+
+
+static void
+rasqal_query_write_sparql_variable(sparql_writer_context *wc,
+ raptor_iostream* iostr, rasqal_variable* v)
+{
+ if(v->expression) {
+ rasqal_query_write_sparql_expression(wc, iostr, v->expression);
+ raptor_iostream_write_counted_string(iostr, " AS ", 4);
+ }
+ if(v->type == RASQAL_VARIABLE_TYPE_ANONYMOUS)
+ raptor_iostream_write_counted_string(iostr, "_:", 2);
+ else if(!v->expression)
+ raptor_iostream_write_byte(iostr, '?');
+ raptor_iostream_write_string(iostr, v->name);
+}
+
+
+static void
+rasqal_query_write_sparql_uri(sparql_writer_context *wc,
+ raptor_iostream* iostr, raptor_uri* uri)
+{
+ size_t len;
+ unsigned char* string;
+ raptor_qname* qname;
+
+ qname = raptor_namespaces_qname_from_uri(wc->nstack, uri, 10);
+ if(qname) {
+ const raptor_namespace* nspace = raptor_qname_get_namespace(qname);
+ if(!raptor_namespace_get_prefix(nspace))
+ raptor_iostream_write_byte(iostr, ':');
+ raptor_iostream_write_qname(iostr, qname);
+ raptor_free_qname(qname);
+ return;
+ }
+
+#ifdef RAPTOR_V2_AVAILABLE
+ if(wc->base_uri)
+ string = raptor_uri_to_relative_counted_uri_string_v2(wc->world->raptor_world_ptr, wc->base_uri, uri, &len);
+ else
+ string = raptor_uri_as_counted_string_v2(wc->world->raptor_world_ptr, uri, &len);
+#else
+ if(wc->base_uri)
+ string = raptor_uri_to_relative_counted_uri_string(wc->base_uri, uri, &len);
+ else
+ string = raptor_uri_as_counted_string(uri, &len);
+#endif
+
+ raptor_iostream_write_byte(iostr, '<');
+ raptor_iostream_write_string_ntriples(iostr, string, len, '>');
+ raptor_iostream_write_byte(iostr, '>');
+
+ if(wc->base_uri)
+ raptor_free_memory(string);
+}
+
+
+static void
+rasqal_query_write_sparql_literal(sparql_writer_context *wc,
+ raptor_iostream* iostr, rasqal_literal* l)
+{
+ if(!l) {
+ raptor_iostream_write_counted_string(iostr, "null", 4);
+ return;
+ }
+
+ switch(l->type) {
+ case RASQAL_LITERAL_URI:
+ rasqal_query_write_sparql_uri(wc, iostr, l->value.uri);
+ break;
+ case RASQAL_LITERAL_BLANK:
+ raptor_iostream_write_counted_string(iostr, "_:", 2);
+ raptor_iostream_write_string(iostr, l->string);
+ break;
+ case RASQAL_LITERAL_STRING:
+ raptor_iostream_write_byte(iostr, '"');
+ raptor_iostream_write_string_ntriples(iostr, l->string, l->string_len, '"');
+ raptor_iostream_write_byte(iostr, '"');
+ if(l->language) {
+ raptor_iostream_write_byte(iostr, '@');
+ raptor_iostream_write_string(iostr, l->language);
+ }
+ if(l->datatype) {
+ raptor_iostream_write_counted_string(iostr, "^^", 2);
+ rasqal_query_write_sparql_uri(wc, iostr, l->datatype);
+ }
+ break;
+ case RASQAL_LITERAL_QNAME:
+ raptor_iostream_write_counted_string(iostr, "QNAME(", 6);
+ raptor_iostream_write_counted_string(iostr, l->string, l->string_len);
+ raptor_iostream_write_byte(iostr, ')');
+ break;
+ case RASQAL_LITERAL_INTEGER:
+ raptor_iostream_write_decimal(iostr, l->value.integer);
+ break;
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_DECIMAL:
+ raptor_iostream_write_counted_string(iostr, l->string, l->string_len);
+ break;
+ case RASQAL_LITERAL_VARIABLE:
+ rasqal_query_write_sparql_variable(wc, iostr, l->value.variable);
+ break;
+ case RASQAL_LITERAL_DATETIME:
+ raptor_iostream_write_byte(iostr, '"');
+ raptor_iostream_write_string_ntriples(iostr, l->string, l->string_len, '"');
+ raptor_iostream_write_counted_string(iostr, "\"^^", 3);
+ rasqal_query_write_sparql_uri(wc, iostr,
+ rasqal_xsd_datatype_type_to_uri(l->world, l->type));
+ break;
+
+ case RASQAL_LITERAL_UNKNOWN:
+ case RASQAL_LITERAL_PATTERN:
+ default:
+ RASQAL_FATAL2("Literal type %d cannot be written as a SPARQL literal", l->type);
+ }
+}
+
+
+static void
+rasqal_query_write_sparql_triple(sparql_writer_context *wc,
+ raptor_iostream* iostr, rasqal_triple* triple)
+{
+ rasqal_query_write_sparql_literal(wc, iostr, triple->subject);
+ raptor_iostream_write_byte(iostr, ' ');
+ if(triple->predicate->type == RASQAL_LITERAL_URI &&
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_equals_v2(wc->world->raptor_world_ptr, triple->predicate->value.uri, wc->type_uri)
+#else
+ raptor_uri_equals(triple->predicate->value.uri, wc->type_uri)
+#endif
+ )
+ raptor_iostream_write_byte(iostr, 'a');
+ else
+ rasqal_query_write_sparql_literal(wc, iostr, triple->predicate);
+ raptor_iostream_write_byte(iostr, ' ');
+ rasqal_query_write_sparql_literal(wc, iostr, triple->object);
+ raptor_iostream_write_counted_string(iostr, " .", 2);
+}
+
+
+#define SPACES_LENGTH 80
+static const char spaces[SPACES_LENGTH+1] = " ";
+
+static void
+rasqal_query_write_indent(raptor_iostream* iostr, int indent)
+{
+ while(indent > 0) {
+ int sp = (indent > SPACES_LENGTH) ? SPACES_LENGTH : indent;
+ raptor_iostream_write_bytes(iostr, spaces, sizeof(char), sp);
+ indent -= sp;
+ }
+}
+
+
+
+static const char* const rasqal_sparql_op_labels[RASQAL_EXPR_LAST+1] = {
+ NULL, /* UNKNOWN */
+ "&&",
+ "||",
+ "=",
+ "!=",
+ "<",
+ ">",
+ "<=",
+ ">=",
+ "-",
+ "+",
+ "-",
+ "*",
+ "/",
+ NULL, /* REM */
+ NULL, /* STR EQ */
+ NULL, /* STR NEQ */
+ NULL, /* STR_MATCH */
+ NULL, /* STR_NMATCH */
+ NULL, /* TILDE */
+ "!",
+ NULL, /* LITERAL */
+ NULL, /* FUNCTION */
+ "BOUND",
+ "STR",
+ "LANG",
+ "DATATYPE",
+ "isIRI",
+ "isBLANK",
+ "isLITERAL",
+ NULL, /* CAST */
+ "ASC", /* ORDER BY ASC */
+ "DESC", /* ORDER BY DESC */
+ "LANGMATCHES",
+ "REGEX",
+ "ASC", /* GROUP BY ASC */
+ "DESC", /* GROUP BY DESC */
+ "COUNT",
+ NULL, /* VARSTAR */
+ "sameTerm"
+};
+
+
+
+static void
+rasqal_query_write_sparql_expression_op(sparql_writer_context *wc,
+ raptor_iostream* iostr,
+ rasqal_expression* e)
+{
+ rasqal_op op = e->op;
+ const char* string;
+ if(op > RASQAL_EXPR_LAST)
+ op = RASQAL_EXPR_UNKNOWN;
+ string = rasqal_sparql_op_labels[(int)op];
+
+ if(string)
+ raptor_iostream_write_string(iostr, string);
+ else
+ raptor_iostream_write_string(iostr, "NONE");
+}
+
+
+static void
+rasqal_query_write_sparql_expression(sparql_writer_context *wc,
+ raptor_iostream* iostr,
+ rasqal_expression* e)
+{
+ int i;
+ int count;
+
+ switch(e->op) {
+ case RASQAL_EXPR_AND:
+ case RASQAL_EXPR_OR:
+ case RASQAL_EXPR_EQ:
+ case RASQAL_EXPR_NEQ:
+ case RASQAL_EXPR_LT:
+ case RASQAL_EXPR_GT:
+ case RASQAL_EXPR_LE:
+ case RASQAL_EXPR_GE:
+ case RASQAL_EXPR_PLUS:
+ case RASQAL_EXPR_MINUS:
+ case RASQAL_EXPR_STAR:
+ case RASQAL_EXPR_SLASH:
+ case RASQAL_EXPR_REM:
+ case RASQAL_EXPR_STR_EQ:
+ case RASQAL_EXPR_STR_NEQ:
+ raptor_iostream_write_counted_string(iostr, "( ", 2);
+ rasqal_query_write_sparql_expression(wc, iostr, e->arg1);
+ raptor_iostream_write_byte(iostr, ' ');
+ rasqal_query_write_sparql_expression_op(wc, iostr, e);
+ raptor_iostream_write_byte(iostr, ' ');
+ rasqal_query_write_sparql_expression(wc, iostr, e->arg2);
+ raptor_iostream_write_counted_string(iostr, " )", 2);
+ break;
+
+ case RASQAL_EXPR_BOUND:
+ case RASQAL_EXPR_STR:
+ case RASQAL_EXPR_LANG:
+ case RASQAL_EXPR_DATATYPE:
+ case RASQAL_EXPR_ISURI:
+ case RASQAL_EXPR_ISBLANK:
+ case RASQAL_EXPR_ISLITERAL:
+ case RASQAL_EXPR_ORDER_COND_ASC:
+ case RASQAL_EXPR_ORDER_COND_DESC:
+ case RASQAL_EXPR_GROUP_COND_ASC:
+ case RASQAL_EXPR_GROUP_COND_DESC:
+ case RASQAL_EXPR_COUNT:
+ case RASQAL_EXPR_SAMETERM:
+ rasqal_query_write_sparql_expression_op(wc, iostr, e);
+ raptor_iostream_write_counted_string(iostr, "( ", 2);
+ rasqal_query_write_sparql_expression(wc, iostr, e->arg1);
+ raptor_iostream_write_counted_string(iostr, " )", 2);
+ break;
+
+ case RASQAL_EXPR_LANGMATCHES:
+ case RASQAL_EXPR_REGEX:
+ rasqal_query_write_sparql_expression_op(wc, iostr, e);
+ raptor_iostream_write_counted_string(iostr, "( ", 2);
+ rasqal_query_write_sparql_expression(wc, iostr, e->arg1);
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_query_write_sparql_expression(wc, iostr, e->arg2);
+ if(e->op == RASQAL_EXPR_REGEX && e->arg3) {
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ rasqal_query_write_sparql_expression(wc, iostr, e->arg3);
+ }
+ raptor_iostream_write_counted_string(iostr, " )", 2);
+ break;
+
+ case RASQAL_EXPR_TILDE:
+ case RASQAL_EXPR_BANG:
+ case RASQAL_EXPR_UMINUS:
+ rasqal_query_write_sparql_expression_op(wc, iostr, e);
+ raptor_iostream_write_counted_string(iostr, "( ", 2);
+ rasqal_query_write_sparql_expression(wc, iostr, e->arg1);
+ raptor_iostream_write_counted_string(iostr, " )", 2);
+ break;
+
+ case RASQAL_EXPR_LITERAL:
+ rasqal_query_write_sparql_literal(wc, iostr, e->literal);
+ break;
+
+ case RASQAL_EXPR_FUNCTION:
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_iostream_write_uri_v2(e->world->raptor_world_ptr, iostr, e->name);
+#else
+ raptor_iostream_write_uri(iostr, e->name);
+#endif
+ raptor_iostream_write_counted_string(iostr, "( ", 2);
+ count = raptor_sequence_size(e->args);
+ for(i = 0; i < count ; i++) {
+ rasqal_expression* arg;
+ arg = (rasqal_expression*)raptor_sequence_get_at(e->args, i);
+ if(i > 0)
+ raptor_iostream_write_counted_string(iostr, " ,", 2);
+ rasqal_query_write_sparql_expression(wc, iostr, arg);
+ }
+ raptor_iostream_write_counted_string(iostr, " )", 2);
+ break;
+
+ case RASQAL_EXPR_CAST:
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_iostream_write_uri_v2(e->world->raptor_world_ptr, iostr, e->name);
+#else
+ raptor_iostream_write_uri(iostr, e->name);
+#endif
+ raptor_iostream_write_counted_string(iostr, "( ", 2);
+ rasqal_query_write_sparql_expression(wc, iostr, e->arg1);
+ raptor_iostream_write_counted_string(iostr, " )", 2);
+ break;
+
+ case RASQAL_EXPR_VARSTAR:
+ raptor_iostream_write_byte(iostr, '*');
+ break;
+
+ case RASQAL_EXPR_UNKNOWN:
+ case RASQAL_EXPR_STR_MATCH:
+ case RASQAL_EXPR_STR_NMATCH:
+ default:
+ RASQAL_FATAL2("Expression op %d cannot be written as a SPARQL expresson", e->op);
+ }
+}
+
+
+static void
+rasqal_query_write_sparql_graph_pattern(sparql_writer_context *wc,
+ raptor_iostream* iostr,
+ rasqal_graph_pattern *gp,
+ int gp_index, int indent)
+{
+ int triple_index = 0;
+ rasqal_graph_pattern_operator op;
+ raptor_sequence *seq;
+ int filters_count = 0;
+
+ op = rasqal_graph_pattern_get_operator(gp);
+
+ if(op == RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL ||
+ op == RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH) {
+ /* prefix verbs */
+ if(op == RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL)
+ raptor_iostream_write_counted_string(iostr, "OPTIONAL ", 9);
+ else {
+ rasqal_graph_pattern* sgp;
+ rasqal_triple* t;
+ sgp = rasqal_graph_pattern_get_sub_graph_pattern(gp, 0);
+ t = rasqal_graph_pattern_get_triple(sgp, 0);
+
+ raptor_iostream_write_counted_string(iostr, "GRAPH ", 6);
+ rasqal_query_write_sparql_literal(wc, iostr, t->origin);
+ raptor_iostream_write_byte(iostr, ' ');
+ }
+ }
+ raptor_iostream_write_counted_string(iostr, "{\n", 2);
+
+ indent+= 2;
+
+ /* look for triples */
+ while(1) {
+ rasqal_triple* t = rasqal_graph_pattern_get_triple(gp, triple_index);
+ if(!t)
+ break;
+
+ rasqal_query_write_indent(iostr, indent);
+ rasqal_query_write_sparql_triple(wc, iostr, t);
+ raptor_iostream_write_byte(iostr, '\n');
+
+ triple_index++;
+ }
+
+
+ /* look for sub-graph patterns */
+ seq = rasqal_graph_pattern_get_sub_graph_pattern_sequence(gp);
+ if(seq && raptor_sequence_size(seq) > 0) {
+ for(gp_index = 0; 1; gp_index++) {
+ rasqal_graph_pattern* sgp = rasqal_graph_pattern_get_sub_graph_pattern(gp, gp_index);
+ if(!sgp)
+ break;
+
+ if(sgp->op == RASQAL_GRAPH_PATTERN_OPERATOR_FILTER) {
+ filters_count++;
+ continue;
+ }
+
+ if(!gp_index)
+ rasqal_query_write_indent(iostr, indent);
+ else {
+ if(op == RASQAL_GRAPH_PATTERN_OPERATOR_UNION)
+ /* infix verb */
+ raptor_iostream_write_counted_string(iostr, " UNION ", 7);
+ else {
+ /* must be prefix verb */
+ raptor_iostream_write_byte(iostr, '\n');
+ rasqal_query_write_indent(iostr, indent);
+ }
+ }
+
+ rasqal_query_write_sparql_graph_pattern(wc, iostr, sgp, gp_index, indent);
+ }
+ raptor_iostream_write_byte(iostr, '\n');
+ }
+
+
+ /* look for constraints */
+ if(filters_count > 0) {
+ for(gp_index = 0; 1; gp_index++) {
+ rasqal_graph_pattern* sgp;
+ rasqal_expression* expr;
+
+ sgp = rasqal_graph_pattern_get_sub_graph_pattern(gp, gp_index);
+ if(!sgp)
+ break;
+
+ if(sgp->op != RASQAL_GRAPH_PATTERN_OPERATOR_FILTER)
+ continue;
+
+ expr = rasqal_graph_pattern_get_filter_expression(sgp);
+
+ rasqal_query_write_indent(iostr, indent);
+ raptor_iostream_write_counted_string(iostr, "FILTER( ", 8);
+ rasqal_query_write_sparql_expression(wc, iostr, expr);
+ raptor_iostream_write_counted_string(iostr, " )\n", 3);
+ }
+ }
+
+
+ indent -= 2;
+
+ rasqal_query_write_indent(iostr, indent);
+ raptor_iostream_write_byte(iostr, '}');
+}
+
+
+
+static int
+rasqal_query_write_sparql_20060406(raptor_iostream *iostr,
+ rasqal_query* query, raptor_uri *base_uri)
+{
+ int i;
+ raptor_sequence *var_seq = NULL;
+ sparql_writer_context wc;
+#ifndef RAPTOR_V2_AVAILABLE
+ const raptor_uri_handler *uri_handler;
+ void *uri_context;
+#endif
+
+ wc.world = query->world;
+ wc.base_uri = NULL;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ wc.type_uri = raptor_new_uri_for_rdf_concept_v2(query->world->raptor_world_ptr, "type");
+ wc.nstack = raptor_new_namespaces_v2(query->world->raptor_world_ptr,
+ (raptor_simple_message_handler)rasqal_query_simple_error,
+ query,
+ 1);
+#else
+ wc.type_uri = raptor_new_uri_for_rdf_concept("type");
+ raptor_uri_get_handler(&uri_handler, &uri_context);
+ wc.nstack = raptor_new_namespaces(uri_handler, uri_context,
+ (raptor_simple_message_handler)rasqal_query_simple_error,
+ query,
+ 1);
+#endif
+
+ if(base_uri) {
+ raptor_iostream_write_counted_string(iostr, "BASE ", 5);
+ rasqal_query_write_sparql_uri(&wc, iostr, base_uri);
+ raptor_iostream_write_byte(iostr, '\n');
+
+ /* from now on all URIs are relative to this */
+#ifdef RAPTOR_V2_AVAILABLE
+ wc.base_uri = raptor_uri_copy_v2(query->world->raptor_world_ptr, base_uri);
+#else
+ wc.base_uri = raptor_uri_copy(base_uri);
+#endif
+ }
+
+
+ for(i = 0; 1 ; i++) {
+ raptor_namespace *nspace;
+ rasqal_prefix* p = rasqal_query_get_prefix(query, i);
+ if(!p)
+ break;
+
+ raptor_iostream_write_counted_string(iostr, "PREFIX ", 7);
+ if(p->prefix)
+ raptor_iostream_write_string(iostr, p->prefix);
+ raptor_iostream_write_counted_string(iostr,": ", 2);
+ rasqal_query_write_sparql_uri(&wc, iostr, p->uri);
+ raptor_iostream_write_byte(iostr, '\n');
+
+ /* Use this constructor so we copy a URI directly */
+ nspace = raptor_new_namespace_from_uri(wc.nstack, p->prefix, p->uri, i);
+ raptor_namespaces_start_namespace(wc.nstack, nspace);
+ }
+
+ if(query->explain)
+ raptor_iostream_write_counted_string(iostr, "EXPLAIN ", 8);
+
+ if(query->verb != RASQAL_QUERY_VERB_CONSTRUCT)
+ raptor_iostream_write_string(iostr,
+ rasqal_query_verb_as_string(query->verb));
+
+ if(query->distinct) {
+ if(query->distinct == 1)
+ raptor_iostream_write_counted_string(iostr, " DISTINCT", 9);
+ else
+ raptor_iostream_write_counted_string(iostr, " REDUCED", 8);
+ }
+
+ if(query->verb == RASQAL_QUERY_VERB_DESCRIBE)
+ var_seq = query->describes;
+ else if(query->verb == RASQAL_QUERY_VERB_SELECT)
+ var_seq = query->selects;
+
+ if(var_seq && query->wildcard)
+ raptor_iostream_write_counted_string(iostr, " *", 2);
+ else if(var_seq) {
+ int count = raptor_sequence_size(var_seq);
+ for(i = 0; i < count; i++) {
+ rasqal_variable* v = (rasqal_variable*)raptor_sequence_get_at(var_seq, i);
+ raptor_iostream_write_byte(iostr, ' ');
+ rasqal_query_write_sparql_variable(&wc, iostr, v);
+ }
+ }
+ raptor_iostream_write_byte(iostr, '\n');
+
+ if(query->data_graphs) {
+ for(i = 0; 1; i++) {
+ rasqal_data_graph* dg = rasqal_query_get_data_graph(query, i);
+ if(!dg)
+ break;
+
+ if(dg->flags & RASQAL_DATA_GRAPH_NAMED)
+ continue;
+
+ raptor_iostream_write_counted_string(iostr, "FROM ", 5);
+ rasqal_query_write_sparql_uri(&wc, iostr, dg->uri);
+ raptor_iostream_write_counted_string(iostr, "\n", 1);
+ }
+
+ for(i = 0; 1; i++) {
+ rasqal_data_graph* dg = rasqal_query_get_data_graph(query, i);
+ if(!dg)
+ break;
+
+ if(!(dg->flags & RASQAL_DATA_GRAPH_NAMED))
+ continue;
+
+ raptor_iostream_write_counted_string(iostr, "FROM NAMED ", 11);
+ rasqal_query_write_sparql_uri(&wc, iostr, dg->name_uri);
+ raptor_iostream_write_byte(iostr, '\n');
+ }
+
+ }
+
+ if(query->constructs) {
+ raptor_iostream_write_string(iostr, "CONSTRUCT {\n");
+ for(i = 0; 1; i++) {
+ rasqal_triple* t = rasqal_query_get_construct_triple(query, i);
+ if(!t)
+ break;
+
+ raptor_iostream_write_counted_string(iostr, " ", 2);
+ rasqal_query_write_sparql_triple(&wc, iostr, t);
+ raptor_iostream_write_byte(iostr, '\n');
+ }
+ raptor_iostream_write_counted_string(iostr, "}\n", 2);
+ }
+ if(query->query_graph_pattern) {
+ raptor_iostream_write_counted_string(iostr, "WHERE ", 6);
+ rasqal_query_write_sparql_graph_pattern(&wc, iostr,
+ query->query_graph_pattern,
+ -1, 0);
+ raptor_iostream_write_byte(iostr, '\n');
+ }
+
+ if(query->group_conditions_sequence) {
+ raptor_iostream_write_counted_string(iostr, "GROUP BY ", 9);
+ for(i = 0; 1; i++) {
+ rasqal_expression* expr = rasqal_query_get_group_condition(query, i);
+ if(!expr)
+ break;
+
+ if(i > 0)
+ raptor_iostream_write_byte(iostr, ' ');
+ rasqal_query_write_sparql_expression(&wc, iostr, expr);
+ }
+ raptor_iostream_write_byte(iostr, '\n');
+ }
+
+ if(query->order_conditions_sequence) {
+ raptor_iostream_write_counted_string(iostr, "ORDER BY ", 9);
+ for(i = 0; 1; i++) {
+ rasqal_expression* expr = rasqal_query_get_order_condition(query, i);
+ if(!expr)
+ break;
+
+ if(i > 0)
+ raptor_iostream_write_byte(iostr, ' ');
+ rasqal_query_write_sparql_expression(&wc, iostr, expr);
+ }
+ raptor_iostream_write_byte(iostr, '\n');
+ }
+
+ if(query->limit >= 0 || query->offset >= 0) {
+ if(query->limit >= 0) {
+ raptor_iostream_write_counted_string(iostr, "LIMIT ", 7);
+ raptor_iostream_write_decimal(iostr, query->limit);
+ }
+ if(query->offset >= 0) {
+ if(query->limit)
+ raptor_iostream_write_byte(iostr, ' ');
+ raptor_iostream_write_counted_string(iostr, "OFFSET ", 8);
+ raptor_iostream_write_decimal(iostr, query->offset);
+ }
+ raptor_iostream_write_byte(iostr, '\n');
+ }
+
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(query->world->raptor_world_ptr, wc.type_uri);
+ if(wc.base_uri)
+ raptor_free_uri_v2(query->world->raptor_world_ptr, wc.base_uri);
+#else
+ raptor_free_uri(wc.type_uri);
+ if(wc.base_uri)
+ raptor_free_uri(wc.base_uri);
+#endif
+ raptor_free_namespaces(wc.nstack);
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_write:
+ * @iostr: #raptor_iostream to write the query to
+ * @query: #rasqal_query pointer.
+ * @format_uri: #raptor_uri describing the format to write (or NULL for default)
+ * @base_uri: #raptor_uri base URI of the output format
+ *
+ * Write a query to an iostream in a specified format.
+ *
+ * The supported URIs for the format_uri are:
+ *
+ * Default: SPARQL Query Language 2006-04-06
+ * http://www.w3.org/TR/2006/CR-rdf-sparql-query-20060406/
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_write(raptor_iostream* iostr, rasqal_query* query,
+ raptor_uri* format_uri, raptor_uri* base_uri)
+{
+ const char *format_uri_str = NULL;
+
+ if(format_uri)
+#ifdef RAPTOR_V2_AVAILABLE
+ format_uri_str = (const char*)raptor_uri_as_string_v2(query->world->raptor_world_ptr,
+ format_uri);
+#else
+ format_uri_str = (const char*)raptor_uri_as_string(format_uri);
+#endif
+
+ if(!format_uri ||
+ !strcmp(format_uri_str,
+ "http://www.w3.org/TR/rdf-sparql-query/") ||
+ !strcmp(format_uri_str,
+ "http://www.w3.org/TR/2006/WD-rdf-sparql-query-20060220/") ||
+ !strcmp(format_uri_str,
+ "http://www.w3.org/TR/2006/CR-rdf-sparql-query-20060406/"))
+ return rasqal_query_write_sparql_20060406(iostr, query, base_uri);
+
+ return 1;
+}
+
+
+/**
+ * rasqal_query_iostream_write_escaped_counted_string:
+ * @query: #rasqal_query object
+ * @iostr: #raptor_iostream to write the escaped string to
+ * @string: string to escape
+ * @len: Length of string to escape
+ *
+ * Write a string to an iostream in escaped form suitable for the query string.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_iostream_write_escaped_counted_string(rasqal_query* query,
+ raptor_iostream* iostr,
+ const unsigned char* string,
+ size_t len)
+{
+ if(query->factory->iostream_write_escaped_counted_string)
+ return query->factory->iostream_write_escaped_counted_string(query, iostr,
+ string, len);
+ else
+ return 1;
+}
+
+
+/**
+ * rasqal_query_escape_counted_string:
+ * @query: #rasqal_query object
+ * @string: string to escape
+ * @len: Length of string to escape
+ * @output_len_p: Pointer to store length of output string (or NULL)
+ *
+ * Convert a string into an escaped form suitable for the query string.
+ *
+ * The returned string must be freed by the caller with
+ * rasqal_free_memory()
+ *
+ * Return value: the escaped string or NULL on failure.
+ **/
+unsigned char*
+rasqal_query_escape_counted_string(rasqal_query* query,
+ const unsigned char* string,
+ size_t len,
+ size_t* output_len_p)
+{
+ raptor_iostream* iostr;
+ void* output_string = NULL;
+ int rc;
+
+ iostr = raptor_new_iostream_to_string(&output_string, output_len_p,
+ rasqal_alloc_memory);
+ if(!iostr)
+ return NULL;
+ rc = rasqal_query_iostream_write_escaped_counted_string(query, iostr,
+ string, len);
+ raptor_free_iostream(iostr);
+ if(rc && output_string) {
+ rasqal_free_memory(output_string);
+ output_string = NULL;
+ }
+
+ return (unsigned char *)output_string;
+}
+
+
+unsigned char*
+rasqal_query_get_genid(rasqal_query* query, const unsigned char* base,
+ int counter)
+{
+ int tmpcounter;
+ int length;
+ unsigned char *buffer;
+
+ /* This is read-only and thread safe */
+ if(counter < 0)
+ counter= query->genid_counter++;
+
+ length = strlen((const char*)base)+2; /* base + (int) + "\0" */
+ tmpcounter = counter;
+ while(tmpcounter /= 10)
+ length++;
+
+ buffer = (unsigned char*)RASQAL_MALLOC(cstring, length);
+ if(!buffer)
+ return NULL;
+
+ sprintf((char*)buffer, "%s%d", base, counter);
+ return buffer;
+}
+
+
+void
+rasqal_query_set_base_uri(rasqal_query* query, raptor_uri* base_uri)
+{
+ if(query->base_uri)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(query->world->raptor_world_ptr, query->base_uri);
+#else
+ raptor_free_uri(query->base_uri);
+#endif
+ query->base_uri = base_uri;
+ query->locator.uri = base_uri;
+}
+
+
+void
+rasqal_query_set_store_results(rasqal_query* query, int store_results)
+{
+ query->store_results = store_results;
+}
+
+
+rasqal_variable*
+rasqal_query_get_variable_by_offset(rasqal_query* query, int idx)
+{
+ return rasqal_variables_table_get(query->vars_table, idx);
+}
diff --git a/src/rasqal/rasqal_query_results.c b/src/rasqal/rasqal_query_results.c
new file mode 100644
index 0000000..dde892d
--- /dev/null
+++ b/src/rasqal/rasqal_query_results.c
@@ -0,0 +1,1425 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_query_results.c - Rasqal RDF Query Results
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+/**
+ *
+ * Query Results Class Internals
+ *
+ * This class provides the abstraction for query results in different
+ * forms. The forms can be either a sequence of variable bindings,
+ * set of RDF triples, boolean value or a syntax.
+ *
+ * Query results can be created as a result of a #rasqal_query
+ * execution using rasqal_query_execute() or as an independent result
+ * set constructed from a query results syntax such as the SPARQL XML
+ * results format via the #rasqal_query_results_formatter class.
+ *
+ * The query results constructor rasqal_new_query_results() takes
+ * a world to use, an optional query, the type of result as well
+ * as a variable table to operate on. If the query is given, then
+ * that is used to handle limit, offset and triple construction,
+ * otherwise the result set is standalone and not associated with
+ * a query.
+ *
+ * The variables table is used for the variables that will appear in
+ * the result rows in the result set. The query results module does
+ * not own any variable information, all API calls are delegated to
+ * the variables table.
+ *
+ * If the rasqal_new_query_results_from_query_execution() is used to
+ * make a query results from a query structure via executing the
+ * query, it initialises a execution engine via the
+ * #rasqal_query_execution_factory 'execute_init' factory method.
+ * This method also determines whether the entire results need to be
+ * (or a requested to be) obtained in one go, and if so, they are
+ * done during construction.
+ *
+ * The user API to getting query results is primarily to get variable
+ * bindings - a sequence of variable:value (also called #rasqal_row
+ * internally), RDF triples, a boolean value or a syntax.
+ *
+ * The variable bindings are generated from the execution engine by
+ * retrieving #rasqal_row either one-by-one using the get_row method
+ * or getting the entire result at once with the get_all_rows method.
+ *
+ * In the case of getting the entire result the rows are stored as a
+ * sqeuence inside the #rasqal_query_results and returned one-by-one
+ * from there, respecting any limit and offset.
+ *
+ * The RDF triples and boolean value results are generated from the
+ * variable bindings (#rasqal_row) inside this class. The underlying
+ * execution engine only knows about rows.
+ *
+ * The class also handles several other results-specific methods such
+ * as getting variable binding names, values by name, counts of
+ * number of results, writing a query results as a syntax (in a
+ * simple fashion), read a query results from a syntax.
+ */
+
+static int rasqal_query_results_execute_and_store_results(rasqal_query_results* query_results);
+static void rasqal_query_results_update_bindings(rasqal_query_results* query_results);
+
+
+/*
+ * A query result for some query
+ */
+struct rasqal_query_results_s {
+ rasqal_world* world;
+
+ /* type of query result (bindings, boolean, graph or syntax) */
+ rasqal_query_results_type type;
+
+ /* non-0 if have read all (variable binding) results */
+ int finished;
+
+ /* non-0 if query has been executed */
+ int executed;
+
+ /* non 0 if query had fatal error and cannot return results */
+ int failed;
+
+ /* query that this was executed over */
+ rasqal_query* query;
+
+ /* how many (variable bindings) results found so far */
+ int result_count;
+
+ /* execution data for execution engine. owned by this object */
+ void* execution_data;
+
+ /* current row of results */
+ rasqal_row* row;
+
+ /* boolean ASK result >0 true, 0 false or -1 uninitialised */
+ int ask_result;
+
+ /* boolean: non-0 to store query results rather than lazy eval */
+ int store_results;
+
+ /* current triple in the sequence of triples 'constructs' or -1 */
+ int current_triple_result;
+
+ /* constructed triple result - shared and updated for each triple */
+ raptor_statement result_triple;
+
+ /* triple used to store references to literals for triple subject,
+ * predicate, object. never returned or used otherwise.
+ */
+ rasqal_triple* triple;
+
+ /* sequence of stored results */
+ raptor_sequence* results_sequence;
+
+ /* size of result row fields:
+ * row->results, row->values
+ */
+ int size;
+
+ /* Execution engine used here */
+ const rasqal_query_execution_factory* execution_factory;
+
+ /* Variables table for variables in result rows */
+ rasqal_variables_table* vars_table;
+};
+
+
+int
+rasqal_init_query_results(void)
+{
+ return 0;
+}
+
+
+void
+rasqal_finish_query_results(void)
+{
+}
+
+
+/**
+ * rasqal_new_query_results:
+ * @world: rasqal world object
+ * @query: query object (or NULL)
+ * @type: query results (expected) type
+ * @vars_table: variables table
+ *
+ * INTERNAL - create a query result set
+ *
+ * The @query may be NULL for result set objects that are standalone
+ * and not attached to any particular query
+ *
+ * Return value: a new query result object or NULL on failure
+ **/
+rasqal_query_results*
+rasqal_new_query_results(rasqal_world* world,
+ rasqal_query* query,
+ rasqal_query_results_type type,
+ rasqal_variables_table* vars_table)
+{
+ rasqal_query_results* query_results;
+
+ query_results = (rasqal_query_results*)RASQAL_CALLOC(rasqal_query_results, 1, sizeof(rasqal_query_results));
+ if(!query_results)
+ return NULL;
+
+ query_results->world = world;
+ query_results->type = type;
+ query_results->finished = 0;
+ query_results->executed = 0;
+ query_results->failed = 0;
+ query_results->query = query;
+ query_results->result_count = 0;
+ query_results->execution_data = NULL;
+ query_results->row = NULL;
+ query_results->ask_result = -1;
+ query_results->store_results = 0;
+ query_results->current_triple_result = -1;
+ /* query_results->result_triple is static */
+ query_results->triple = NULL;
+ query_results->results_sequence = NULL;
+ query_results->size = 0;
+ query_results->vars_table = rasqal_new_variables_table_from_variables_table(vars_table);
+
+ return query_results;
+}
+
+
+/**
+ * rasqal_query_results_execute_with_engine:
+ * @query: the #rasqal_query object
+ * @engine: execution factory
+ *
+ * INTERNAL - Create a new query results set executing a prepared query with the given execution engine
+ *
+ * return value: a #rasqal_query_results structure or NULL on failure.
+ **/
+rasqal_query_results*
+rasqal_query_results_execute_with_engine(rasqal_query* query,
+ const rasqal_query_execution_factory* engine)
+{
+ rasqal_query_results *query_results = NULL;
+ int rc = 0;
+ size_t ex_data_size;
+ rasqal_query_results_type type = RASQAL_QUERY_RESULTS_BINDINGS;
+
+ if(!query)
+ return NULL;
+
+ if(query->failed)
+ return NULL;
+
+ if(query->query_results_formatter_name)
+ type = RASQAL_QUERY_RESULTS_SYNTAX;
+ else
+ switch(query->verb) {
+ case RASQAL_QUERY_VERB_SELECT:
+ type = RASQAL_QUERY_RESULTS_BINDINGS;
+ break;
+ case RASQAL_QUERY_VERB_ASK:
+ type = RASQAL_QUERY_RESULTS_BOOLEAN;
+ break;
+ case RASQAL_QUERY_VERB_CONSTRUCT:
+ case RASQAL_QUERY_VERB_DESCRIBE:
+ type = RASQAL_QUERY_RESULTS_GRAPH;
+ break;
+
+ case RASQAL_QUERY_VERB_UNKNOWN:
+ case RASQAL_QUERY_VERB_DELETE:
+ case RASQAL_QUERY_VERB_INSERT:
+ default:
+ return NULL;
+ }
+
+ query_results = rasqal_new_query_results(query->world, query, type,
+ query->vars_table);
+ if(!query_results)
+ return NULL;
+
+ query_results->execution_factory = engine;
+
+ /* set executed flag early to enable cleanup on error */
+ query_results->executed = 1;
+
+ query_results->store_results = (query->store_results ||
+ query->order_conditions_sequence ||
+ query->distinct);
+
+ ex_data_size = query_results->execution_factory->execution_data_size;
+ if(ex_data_size > 0) {
+ query_results->execution_data = RASQAL_CALLOC(data, 1, ex_data_size);
+ if(!query_results->execution_data) {
+ rasqal_free_query_results(query_results);
+ return NULL;
+ }
+ } else
+ query_results->execution_data = NULL;
+
+ if(query_results->execution_factory->execute_init) {
+ rasqal_engine_error execution_error = RASQAL_ENGINE_OK;
+ int execution_flags = 0;
+ if(query_results->store_results)
+ execution_flags |= 1;
+
+ rc = query_results->execution_factory->execute_init(query_results->execution_data, query, query_results, execution_flags, &execution_error);
+ if(execution_error != RASQAL_ENGINE_OK) {
+ query_results->failed = 1;
+ rasqal_free_query_results(query_results);
+ return NULL;
+ }
+ }
+
+ /* Choose either to execute all now and store OR do it on demand (lazy) */
+ if(query_results->store_results)
+ rc = rasqal_query_results_execute_and_store_results(query_results);
+
+ return query_results;
+}
+
+
+/**
+ * rasqal_free_query_results:
+ * @query_results: #rasqal_query_results object
+ *
+ * Destructor - destroy a rasqal_query_results.
+ *
+ **/
+void
+rasqal_free_query_results(rasqal_query_results* query_results)
+{
+ rasqal_query* query;
+
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(query_results, rasqal_query_result);
+
+ query = query_results->query;
+
+ if(query_results->executed) {
+ if(query_results->execution_factory->execute_finish) {
+ rasqal_engine_error execution_error = RASQAL_ENGINE_OK;
+
+ query_results->execution_factory->execute_finish(query_results->execution_data, &execution_error);
+ /* ignoring failure of execute_finish */
+ }
+ }
+
+ if(query_results->execution_data)
+ RASQAL_FREE(rasqal_engine_execution_data, query_results->execution_data);
+
+ if(query_results->row)
+ rasqal_free_row(query_results->row);
+
+ if(query_results->results_sequence)
+ raptor_free_sequence(query_results->results_sequence);
+
+ if(query_results->triple)
+ rasqal_free_triple(query_results->triple);
+
+ if(query_results->vars_table)
+ rasqal_free_variables_table(query_results->vars_table);
+
+ if(query)
+ rasqal_query_remove_query_result(query, query_results);
+
+ RASQAL_FREE(rasqal_query_results, query_results);
+}
+
+
+/**
+ * rasqal_query_results_get_query:
+ * @query_results: #rasqal_query_results object
+ *
+ * Get thq query associated with this query result
+ *
+ * Return value: shared pointer to query object
+ **/
+rasqal_query*
+rasqal_query_results_get_query(rasqal_query_results* query_results)
+{
+ return query_results->query;
+}
+
+
+/**
+ * rasqal_query_results_is_bindings:
+ * @query_results: #rasqal_query_results object
+ *
+ * Test if rasqal_query_results is variable bindings format.
+ *
+ * Return value: non-0 if true
+ **/
+int
+rasqal_query_results_is_bindings(rasqal_query_results* query_results)
+{
+ return (query_results->type == RASQAL_QUERY_RESULTS_BINDINGS);
+}
+
+
+/**
+ * rasqal_query_results_is_boolean:
+ * @query_results: #rasqal_query_results object
+ *
+ * Test if rasqal_query_results is boolean format.
+ *
+ * Return value: non-0 if true
+ **/
+int
+rasqal_query_results_is_boolean(rasqal_query_results* query_results)
+{
+ return (query_results->type == RASQAL_QUERY_RESULTS_BOOLEAN);
+}
+
+
+/**
+ * rasqal_query_results_is_graph:
+ * @query_results: #rasqal_query_results object
+ *
+ * Test if rasqal_query_results is RDF graph format.
+ *
+ * Return value: non-0 if true
+ **/
+int
+rasqal_query_results_is_graph(rasqal_query_results* query_results)
+{
+ return (query_results->type == RASQAL_QUERY_RESULTS_GRAPH);
+}
+
+
+/**
+ * rasqal_query_results_is_syntax:
+ * @query_results: #rasqal_query_results object
+ *
+ * Test if the rasqal_query_results is a syntax.
+ *
+ * Many of the query results may be formatted as a syntax using the
+ * #rasqal_query_formatter class however this function returns true
+ * if a syntax result was specifically requested.
+ *
+ * Return value: non-0 if true
+ **/
+int
+rasqal_query_results_is_syntax(rasqal_query_results* query_results)
+{
+ return (query_results->type == RASQAL_QUERY_RESULTS_SYNTAX);
+}
+
+
+/**
+ * rasqal_query_results_check_limit_offset:
+ * @query_results: query results object
+ *
+ * INTERNAL - Check the query result count is in the limit and offset range if any.
+ *
+ * Return value: before range -1, in range 0, after range 1
+ */
+int
+rasqal_query_results_check_limit_offset(rasqal_query_results* query_results)
+{
+ rasqal_query* query = query_results->query;
+ int limit;
+
+ if(!query)
+ return 0;
+
+ limit = query->limit;
+
+ /* Ensure ASK queries never do more than one result */
+ if(query->verb == RASQAL_QUERY_VERB_ASK)
+ limit = 1;
+
+ if(query->offset > 0) {
+ /* offset */
+ if(query_results->result_count <= query->offset)
+ return -1;
+
+ if(limit >= 0) {
+ /* offset and limit */
+ if(query_results->result_count > (query->offset + limit)) {
+ query_results->finished = 1;
+ }
+ }
+
+ } else if(limit >= 0) {
+ /* limit */
+ if(query_results->result_count > limit) {
+ query_results->finished = 1;
+ }
+ }
+
+ return query_results->finished;
+}
+
+
+/**
+ * rasqal_query_results_get_row_from_saved:
+ * @query_results: Query results to execute
+ *
+ * INTERNAL - Get next result row from a stored query result sequence
+ *
+ * Return value: result row or NULL if finished or failed
+ */
+static rasqal_row*
+rasqal_query_results_get_row_from_saved(rasqal_query_results* query_results)
+{
+ rasqal_query* query = query_results->query;
+ int size;
+ rasqal_row* row = NULL;
+
+ size = raptor_sequence_size(query_results->results_sequence);
+
+ while(1) {
+ if(query_results->result_count >= size) {
+ query_results->finished = 1;
+ break;
+ }
+
+ query_results->result_count++;
+
+ /* finished if beyond result range */
+ if(rasqal_query_results_check_limit_offset(query_results) > 0) {
+ query_results->result_count--;
+ break;
+ }
+
+ /* continue if before start of result range */
+ if(rasqal_query_results_check_limit_offset(query_results) < 0)
+ continue;
+
+ /* else got result or finished */
+ row = (rasqal_row*)raptor_sequence_delete_at(query_results->results_sequence,
+ query_results->result_count-1);
+
+ if(row) {
+ /* stored results may not be canonicalized yet - do it lazily */
+ rasqal_row_to_nodes(row);
+
+ if(query && query->constructs)
+ rasqal_query_results_update_bindings(query_results);
+ }
+ break;
+ }
+
+ return row;
+}
+
+
+/**
+ * rasqal_query_results_ensure_have_row_internal:
+ * @query_results: #rasqal_query_results query_results
+ *
+ * INTERNAL - Ensure there is a row in the query results by getting it from the generator/stored list
+ *
+ * If one already is held, nothing is done. It is assumed
+ * that @query_results is not NULL and the query is neither finished
+ * nor failed.
+ *
+ * Return value: non-0 if failed or results exhausted
+ **/
+static int
+rasqal_query_results_ensure_have_row_internal(rasqal_query_results* query_results)
+{
+ /* already have row */
+ if(query_results->row)
+ return 0;
+
+ if(query_results->results_sequence) {
+ query_results->row = rasqal_query_results_get_row_from_saved(query_results);
+ } else if(query_results->execution_factory &&
+ query_results->execution_factory->get_row) {
+ rasqal_engine_error execution_error = RASQAL_ENGINE_OK;
+
+ query_results->row = query_results->execution_factory->get_row(query_results->execution_data, &execution_error);
+ if(execution_error == RASQAL_ENGINE_FAILED)
+ query_results->failed = 1;
+ else if(execution_error == RASQAL_ENGINE_OK)
+ query_results->result_count++;
+ }
+
+ if(query_results->row) {
+ rasqal_row_to_nodes(query_results->row);
+ query_results->size = query_results->row->size;
+ } else
+ query_results->finished = 1;
+
+ return (query_results->row == NULL);
+}
+
+
+/**
+ * rasqal_query_results_get_current_row:
+ * @query_results: query results object
+ *
+ * INTERNAL - Get the current query result as a row of values
+ *
+ * The returned row is shared and owned by query_results
+ *
+ * Return value: result row or NULL on failure
+ */
+static rasqal_row*
+rasqal_query_results_get_current_row(rasqal_query_results* query_results)
+{
+ if(!query_results || query_results->failed || query_results->finished)
+ return NULL;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return NULL;
+
+ /* ensure we have a row */
+ rasqal_query_results_ensure_have_row_internal(query_results);
+
+ return query_results->row;
+}
+
+
+/**
+ * rasqal_query_results_get_count:
+ * @query_results: #rasqal_query_results query_results
+ *
+ * Get number of bindings so far.
+ *
+ * Return value: number of bindings found so far or < 0 on failure
+ **/
+int
+rasqal_query_results_get_count(rasqal_query_results* query_results)
+{
+ rasqal_query* query;
+
+ if(!query_results || query_results->failed)
+ return -1;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return -1;
+
+ query = query_results->query;
+ if(query && query->offset > 0)
+ return query_results->result_count - query->offset;
+ return query_results->result_count;
+}
+
+
+/**
+ * rasqal_query_results_next:
+ * @query_results: #rasqal_query_results query_results
+ *
+ * Move to the next result.
+ *
+ * Return value: non-0 if failed or results exhausted
+ **/
+int
+rasqal_query_results_next(rasqal_query_results* query_results)
+{
+ if(!query_results || query_results->failed || query_results->finished)
+ return 1;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return 1;
+
+ /* Remove any current row */
+ if(query_results->row) {
+ rasqal_free_row(query_results->row);
+ query_results->row = NULL;
+ }
+
+ /* Now try to get a new one */
+ return rasqal_query_results_ensure_have_row_internal(query_results);
+}
+
+
+/**
+ * rasqal_query_results_finished:
+ * @query_results: #rasqal_query_results query_results
+ *
+ * Find out if binding results are exhausted.
+ *
+ * Return value: non-0 if results are finished or query failed
+ **/
+int
+rasqal_query_results_finished(rasqal_query_results* query_results)
+{
+ if(!query_results || query_results->failed || query_results->finished)
+ return 1;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return 1;
+
+ /* need to have at least tried to get a row once */
+ if(!query_results->failed && !query_results->finished)
+ rasqal_query_results_ensure_have_row_internal(query_results);
+
+ return (query_results->failed || query_results->finished);
+}
+
+
+/**
+ * rasqal_query_results_get_bindings:
+ * @query_results: #rasqal_query_results query_results
+ * @names: pointer to an array of binding names (or NULL)
+ * @values: pointer to an array of binding value #rasqal_literal (or NULL)
+ *
+ * Get all binding names, values for current result.
+ *
+ * If names is not NULL, it is set to the address of a shared array
+ * of names of the bindings (an output parameter). These names
+ * are shared and must not be freed by the caller
+ *
+ * If values is not NULL, it is set to the address of a shared array
+ * of #rasqal_literal* binding values. These values are shaerd
+ * and must not be freed by the caller.
+ *
+ * Return value: non-0 if the assignment failed
+ **/
+int
+rasqal_query_results_get_bindings(rasqal_query_results* query_results,
+ const unsigned char ***names,
+ rasqal_literal ***values)
+{
+ if(!query_results)
+ return 1;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return 1;
+
+ if(names)
+ *names = rasqal_variables_table_get_names(query_results->vars_table);
+
+ if(values) {
+ rasqal_row* row;
+
+ row = rasqal_query_results_get_current_row(query_results);
+ if(row)
+ *values = row->values;
+ else
+ query_results->finished = 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_results_get_binding_value:
+ * @query_results: #rasqal_query_results query_results
+ * @offset: offset of binding name into array of known names
+ *
+ * Get one binding value for the current result.
+ *
+ * Return value: a pointer to a shared #rasqal_literal binding value or NULL on failure
+ **/
+rasqal_literal*
+rasqal_query_results_get_binding_value(rasqal_query_results* query_results,
+ int offset)
+{
+ rasqal_row* row;
+
+ if(!query_results)
+ return NULL;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return NULL;
+
+ if(offset < 0 || offset > query_results->size-1)
+ return NULL;
+
+ row = rasqal_query_results_get_current_row(query_results);
+ if(row)
+ return row->values[offset];
+
+ query_results->finished = 1;
+ return NULL;
+}
+
+
+/**
+ * rasqal_query_results_get_binding_name:
+ * @query_results: #rasqal_query_results query_results
+ * @offset: offset of binding name into array of known names
+ *
+ * Get binding name for the current result.
+ *
+ * Return value: a pointer to a shared copy of the binding name or NULL on failure
+ **/
+const unsigned char*
+rasqal_query_results_get_binding_name(rasqal_query_results* query_results,
+ int offset)
+{
+ rasqal_variable* v;
+
+ if(!query_results)
+ return NULL;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return NULL;
+
+ v = rasqal_variables_table_get(query_results->vars_table, offset);
+ if(!v)
+ return NULL;
+
+ return v->name;
+}
+
+
+/**
+ * rasqal_query_results_get_binding_value_by_name:
+ * @query_results: #rasqal_query_results query_results
+ * @name: variable name
+ *
+ * Get one binding value for a given name in the current result.
+ *
+ * Return value: a pointer to a shared #rasqal_literal binding value or NULL on failure
+ **/
+rasqal_literal*
+rasqal_query_results_get_binding_value_by_name(rasqal_query_results* query_results,
+ const unsigned char *name)
+{
+ rasqal_row* row;
+ rasqal_variable* v;
+
+ if(!query_results)
+ return NULL;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return NULL;
+
+ row = rasqal_query_results_get_current_row(query_results);
+ if(!row)
+ return NULL;
+
+ v = rasqal_variables_table_get_by_name(query_results->vars_table, name);
+ if(!v)
+ return NULL;
+
+ return row->values[v->offset];
+}
+
+
+/**
+ * rasqal_query_results_get_bindings_count:
+ * @query_results: #rasqal_query_results query_results
+ *
+ * Get the number of bound variables in the result.
+ *
+ * Return value: <0 if failed or results exhausted
+ **/
+int
+rasqal_query_results_get_bindings_count(rasqal_query_results* query_results)
+{
+ if(!query_results || query_results->failed)
+ return -1;
+
+ if(!rasqal_query_results_is_bindings(query_results))
+ return -1;
+
+ return query_results->size;
+}
+
+
+static unsigned char*
+rasqal_prefix_id(int prefix_id, unsigned char *string)
+{
+ int tmpid = prefix_id;
+ unsigned char* buffer;
+ size_t length = strlen((const char*)string)+4; /* "r" +... + "_" +... \0 */
+
+ while(tmpid /= 10)
+ length++;
+
+ buffer = (unsigned char*)RASQAL_MALLOC(cstring, length);
+ if(!buffer)
+ return NULL;
+
+ sprintf((char*)buffer, "r%d_%s", prefix_id, string);
+
+ return buffer;
+}
+
+
+/**
+ * rasqal_query_results_get_triple:
+ * @query_results: #rasqal_query_results query_results
+ *
+ * Get the current triple in the result.
+ *
+ * The return value is a shared #raptor_statement.
+ *
+ * Return value: #raptor_statement or NULL if failed or results exhausted
+ **/
+raptor_statement*
+rasqal_query_results_get_triple(rasqal_query_results* query_results)
+{
+ rasqal_query* query;
+ int rc;
+ rasqal_triple *t;
+ rasqal_literal *s, *p, *o;
+ raptor_statement *rs = NULL;
+ unsigned char *nodeid;
+ int skipped;
+
+ if(!query_results || query_results->failed || query_results->finished)
+ return NULL;
+
+ if(!rasqal_query_results_is_graph(query_results))
+ return NULL;
+
+ query = query_results->query;
+ if(!query)
+ return NULL;
+
+ if(query->verb == RASQAL_QUERY_VERB_DESCRIBE)
+ return NULL;
+
+
+ /* ensure we have a row to work on */
+ if(rasqal_query_results_ensure_have_row_internal(query_results))
+ return NULL;
+
+ skipped = 0;
+ while(1) {
+ if(skipped) {
+ rc = rasqal_query_results_next(query_results);
+ if(rc) {
+ rs = NULL;
+ break;
+ }
+ query_results->current_triple_result = -1;
+ }
+
+ if(query_results->current_triple_result < 0)
+ query_results->current_triple_result = 0;
+
+ t = (rasqal_triple*)raptor_sequence_get_at(query->constructs,
+ query_results->current_triple_result);
+
+ rs = &query_results->result_triple;
+
+ s = rasqal_literal_as_node(t->subject);
+ if(!s) {
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_WARNING,
+ &query->locator,
+ "Triple with unbound subject skipped");
+ skipped = 1;
+ continue;
+ }
+ switch(s->type) {
+ case RASQAL_LITERAL_URI:
+ rs->subject = s->value.uri;
+ rs->subject_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
+ break;
+
+ case RASQAL_LITERAL_BLANK:
+ nodeid = rasqal_prefix_id(query_results->result_count,
+ (unsigned char*)s->string);
+ rasqal_free_literal(s);
+ if(!nodeid) {
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_FATAL,
+ &query->locator,
+ "Could not prefix subject blank identifier");
+ return NULL;
+ }
+ s = rasqal_new_simple_literal(query_results->world, RASQAL_LITERAL_BLANK,
+ nodeid);
+ if(!s) {
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_FATAL,
+ &query->locator,
+ "Could not create a new subject blank literal");
+ return NULL;
+ }
+ rs->subject = nodeid;
+ rs->subject_type = RAPTOR_IDENTIFIER_TYPE_ANONYMOUS;
+ break;
+
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_VARIABLE:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ /* QNames should be gone by the time expression eval happens
+ * Everything else is removed by rasqal_literal_as_node() above.
+ */
+
+ case RASQAL_LITERAL_STRING:
+ /* string [literal] subjects are not RDF */
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ /* case RASQAL_LITERAL_STRING: */
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_WARNING,
+ &query->locator,
+ "Triple with non-URI/blank node subject skipped");
+ skipped = 1;
+ break;
+ }
+ if(skipped) {
+ if(s)
+ rasqal_free_literal(s);
+ continue;
+ }
+
+
+ p = rasqal_literal_as_node(t->predicate);
+ if(!p) {
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_WARNING,
+ &query->locator,
+ "Triple with unbound predicate skipped");
+ rasqal_free_literal(s);
+ skipped = 1;
+ continue;
+ }
+ switch(p->type) {
+ case RASQAL_LITERAL_URI:
+ rs->predicate = p->value.uri;
+ rs->predicate_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
+ break;
+
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_VARIABLE:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ /* QNames should be gone by the time expression eval happens
+ * Everything else is removed by rasqal_literal_as_node() above.
+ */
+
+ case RASQAL_LITERAL_BLANK:
+ case RASQAL_LITERAL_STRING:
+ /* blank node or string [literal] predicates are not RDF */
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_WARNING,
+ &query->locator,
+ "Triple with non-URI predicate skipped");
+ skipped = 1;
+ break;
+ }
+ if(skipped) {
+ rasqal_free_literal(s);
+ if(p)
+ rasqal_free_literal(p);
+ continue;
+ }
+
+ o = rasqal_literal_as_node(t->object);
+ if(!o) {
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_WARNING,
+ &query->locator,
+ "Triple with unbound object skipped");
+ rasqal_free_literal(s);
+ rasqal_free_literal(p);
+ skipped = 1;
+ continue;
+ }
+ switch(o->type) {
+ case RASQAL_LITERAL_URI:
+ rs->object = o->value.uri;
+ rs->object_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
+ break;
+
+ case RASQAL_LITERAL_BLANK:
+ nodeid = rasqal_prefix_id(query_results->result_count,
+ (unsigned char*)o->string);
+ rasqal_free_literal(o);
+ if(!nodeid) {
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_FATAL,
+ &query->locator,
+ "Could not prefix blank identifier");
+ rasqal_free_literal(s);
+ rasqal_free_literal(p);
+ return NULL;
+ }
+ o = rasqal_new_simple_literal(query_results->world, RASQAL_LITERAL_BLANK,
+ nodeid);
+ if(!o) {
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_FATAL,
+ &query->locator,
+ "Could not create a new subject blank literal");
+ rasqal_free_literal(s);
+ rasqal_free_literal(p);
+ return NULL;
+ }
+ rs->object = nodeid;
+ rs->object_type = RAPTOR_IDENTIFIER_TYPE_ANONYMOUS;
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ rs->object = o->string;
+ rs->object_literal_language = (const unsigned char*)o->language;
+ rs->object_literal_datatype = o->datatype;
+ rs->object_type = RAPTOR_IDENTIFIER_TYPE_LITERAL;
+ break;
+
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_VARIABLE:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+ /* QNames should be gone by the time expression eval happens
+ * Everything else is removed by rasqal_literal_as_node() above.
+ */
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ rasqal_log_error_simple(query_results->world, RAPTOR_LOG_LEVEL_WARNING,
+ &query->locator,
+ "Triple with unknown object skipped");
+ skipped = 1;
+ break;
+ }
+ if(skipped) {
+ rasqal_free_literal(s);
+ rasqal_free_literal(p);
+ if(o)
+ rasqal_free_literal(o);
+ continue;
+ }
+
+ /* dispose previous triple if any */
+ if(query_results->triple) {
+ rasqal_free_triple(query_results->triple);
+ query_results->triple = NULL;
+ }
+
+ /* for saving s, p, o for later disposal */
+ query_results->triple = rasqal_new_triple(s, p, o);
+
+ /* got triple, return it */
+ break;
+ }
+
+ return rs;
+}
+
+
+/**
+ * rasqal_query_results_next_triple:
+ * @query_results: #rasqal_query_results query_results
+ *
+ * Move to the next triple result.
+ *
+ * Return value: non-0 if failed or results exhausted
+ **/
+int
+rasqal_query_results_next_triple(rasqal_query_results* query_results)
+{
+ rasqal_query* query;
+ int rc = 0;
+
+ if(!query_results || query_results->failed || query_results->finished)
+ return 1;
+
+ if(!rasqal_query_results_is_graph(query_results))
+ return 1;
+
+ query = query_results->query;
+ if(!query)
+ return 1;
+
+ if(query->verb == RASQAL_QUERY_VERB_DESCRIBE)
+ return 1;
+
+ if(query_results->triple) {
+ rasqal_free_triple(query_results->triple);
+ query_results->triple = NULL;
+ }
+
+ if(++query_results->current_triple_result >= raptor_sequence_size(query->constructs)) {
+ /* Remove any current row */
+ if(query_results->row) {
+ rasqal_free_row(query_results->row);
+ query_results->row = NULL;
+ }
+
+ /* Now try to get a new one */
+ if(rasqal_query_results_ensure_have_row_internal(query_results))
+ return 1;
+
+ query_results->current_triple_result = -1;
+ }
+
+ return rc;
+}
+
+
+/**
+ * rasqal_query_results_get_boolean:
+ * @query_results: #rasqal_query_results query_results
+ *
+ * Get boolean query result.
+ *
+ * The return value is only meaningful if this is a boolean
+ * query result - see rasqal_query_results_is_boolean()
+ *
+ * Return value: boolean query result - >0 is true, 0 is false, <0 on error
+ */
+int
+rasqal_query_results_get_boolean(rasqal_query_results* query_results)
+{
+ if(!query_results || query_results->failed)
+ return -1;
+
+ if(!rasqal_query_results_is_boolean(query_results))
+ return -1;
+
+ if(query_results->ask_result >= 0)
+ return query_results->ask_result;
+
+ query_results->ask_result= (query_results->result_count > 0) ? 1 : 0;
+ query_results->finished= 1;
+
+ return query_results->ask_result;
+}
+
+
+/**
+ * rasqal_query_results_write:
+ * @iostr: #raptor_iostream to write the query to
+ * @results: #rasqal_query_results query results format
+ * @format_uri: #raptor_uri describing the format to write (or NULL for default)
+ * @base_uri: #raptor_uri base URI of the output format
+ *
+ * Write the query results to an iostream in a format.
+ *
+ * This uses the #rasqal_query_results_formatter class
+ * and the rasqal_query_results_formatter_write() method
+ * to perform the formatting. See
+ * rasqal_query_results_formats_enumerate()
+ * for obtaining the supported format URIs at run time.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_results_write(raptor_iostream *iostr,
+ rasqal_query_results* results,
+ raptor_uri *format_uri,
+ raptor_uri *base_uri)
+{
+ rasqal_query_results_formatter *formatter;
+ int status;
+
+ if(!results || results->failed)
+ return 1;
+
+ formatter = rasqal_new_query_results_formatter(results->world, NULL,
+ format_uri);
+ if(!formatter)
+ return 1;
+
+ status = rasqal_query_results_formatter_write(iostr, formatter,
+ results, base_uri);
+
+ rasqal_free_query_results_formatter(formatter);
+ return status;
+}
+
+
+/**
+ * rasqal_query_results_read:
+ * @iostr: #raptor_iostream to read the query from
+ * @results: #rasqal_query_results query results format
+ * @format_uri: #raptor_uri describing the format to read (or NULL for default)
+ * @base_uri: #raptor_uri base URI of the input format
+ *
+ * Read the query results from an iostream in a format.
+ *
+ * This uses the #rasqal_query_results_formatter class
+ * and the rasqal_query_results_formatter_read() method
+ * to perform the formatting. See
+ * rasqal_query_results_formats_enumerate()
+ * for obtaining the supported format URIs at run time.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_results_read(raptor_iostream *iostr,
+ rasqal_query_results* results,
+ raptor_uri *format_uri,
+ raptor_uri *base_uri)
+{
+ rasqal_query_results_formatter *formatter;
+ int status;
+
+ if(!results || results->failed)
+ return 1;
+
+ formatter = rasqal_new_query_results_formatter(results->world, NULL,
+ format_uri);
+ if(!formatter)
+ return 1;
+
+ status = rasqal_query_results_formatter_read(results->world, iostr, formatter,
+ results, base_uri);
+
+ rasqal_free_query_results_formatter(formatter);
+ return status;
+}
+
+
+/**
+ * rasqal_query_results_add_row:
+ * @query_results: query results object
+ * @row: query result row
+ *
+ * INTERNAL - Add a query result row to the sequence of result rows
+ */
+void
+rasqal_query_results_add_row(rasqal_query_results* query_results,
+ rasqal_row* row)
+{
+ if(!query_results->results_sequence) {
+ query_results->results_sequence = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_row, (raptor_sequence_print_handler*)rasqal_row_print);
+ query_results->result_count = 1;
+ }
+
+ row->offset = query_results->result_count-1;
+ raptor_sequence_push(query_results->results_sequence, row);
+}
+
+
+/**
+ * rasqal_query_results_execute_and_store_results:
+ * @query_results: query results object
+ *
+ * INTERNAL - Store all query result (rows) immediately
+ *
+ * Return value: non-0 on finished or failure
+ */
+static int
+rasqal_query_results_execute_and_store_results(rasqal_query_results* query_results)
+{
+ rasqal_query* query;
+ raptor_sequence* seq = NULL;
+
+ query = query_results->query;
+
+ if(query_results->results_sequence)
+ raptor_free_sequence(query_results->results_sequence);
+
+ if(query_results->execution_factory->get_all_rows) {
+ rasqal_engine_error execution_error = RASQAL_ENGINE_OK;
+
+ seq = query_results->execution_factory->get_all_rows(query_results->execution_data, &execution_error);
+ if(execution_error == RASQAL_ENGINE_FAILED)
+ query_results->failed = 1;
+ }
+
+ query_results->results_sequence = seq;
+
+ if(!seq) {
+ query_results->finished = 1;
+ } else {
+ int size;
+
+ size = raptor_sequence_size(seq);
+ query_results->finished = (size == 0);
+
+ if(query && !query->limit)
+ query_results->finished = 1;
+
+ if(!query_results->finished) {
+ /* Reset to first result, index-1 into sequence of results */
+ query_results->result_count = 0;
+
+ /* skip past any OFFSET */
+ if(query && query->offset > 0) {
+ query_results->result_count += query->offset;
+ if(query_results->result_count >= size)
+ query_results->finished = 1;
+ }
+
+ }
+
+ if(query_results->finished)
+ query_results->result_count = 0;
+ else {
+ if(query && query->constructs)
+ rasqal_query_results_update_bindings(query_results);
+ }
+ }
+
+ return query_results->finished;
+}
+
+
+static void
+rasqal_query_results_update_bindings(rasqal_query_results* query_results)
+{
+ int i;
+ int size;
+
+ /* bind the construct variables again if running through a sequence */
+ size = rasqal_variables_table_get_named_variables_count(query_results->vars_table);
+ for(i = 0; i< size; i++) {
+ rasqal_variable* v;
+ rasqal_literal* value;
+ v = rasqal_variables_table_get(query_results->vars_table, i);
+ value = rasqal_query_results_get_binding_value(query_results, i);
+ rasqal_variable_set_value(v, rasqal_new_literal_from_literal(value));
+ }
+}
+
+
+void
+rasqal_query_results_remove_query_reference(rasqal_query_results* query_results)
+{
+ rasqal_query* query = query_results->query;
+ query_results->query = NULL;
+
+ rasqal_free_query(query);
+}
+
+
+rasqal_variables_table*
+rasqal_query_results_get_variables_table(rasqal_query_results* query_results)
+{
+ return query_results->vars_table;
+}
+
diff --git a/src/rasqal/rasqal_query_transform.c b/src/rasqal/rasqal_query_transform.c
new file mode 100644
index 0000000..afaf7e0
--- /dev/null
+++ b/src/rasqal/rasqal_query_transform.c
@@ -0,0 +1,1320 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_query_transform.c - Rasqal query transformations
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#if 0
+#undef RASQAL_DEBUG
+#define RASQAL_DEBUG 2
+#endif
+
+#define DEBUG_FH stderr
+
+
+int
+rasqal_query_expand_triple_qnames(rasqal_query* rq)
+{
+ int i;
+
+ if(!rq->triples)
+ return 0;
+
+ /* expand qnames in triples */
+ for(i = 0; i< raptor_sequence_size(rq->triples); i++) {
+ rasqal_triple* t = (rasqal_triple*)raptor_sequence_get_at(rq->triples, i);
+ if(rasqal_literal_expand_qname(rq, t->subject) ||
+ rasqal_literal_expand_qname(rq, t->predicate) ||
+ rasqal_literal_expand_qname(rq, t->object))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int
+rasqal_sequence_has_qname(raptor_sequence *seq)
+{
+ int i;
+
+ if(!seq)
+ return 0;
+
+ /* expand qnames in triples */
+ for(i = 0; i< raptor_sequence_size(seq); i++) {
+ rasqal_triple* t = (rasqal_triple*)raptor_sequence_get_at(seq, i);
+ if(rasqal_literal_has_qname(t->subject) ||
+ rasqal_literal_has_qname(t->predicate) ||
+ rasqal_literal_has_qname(t->object))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+rasqal_graph_pattern_constraints_has_qname(rasqal_graph_pattern* gp)
+{
+ int i;
+
+ /* check for qnames in sub graph patterns */
+ if(gp->graph_patterns) {
+ /* check for constraint qnames in rasqal_graph_patterns */
+ for(i = 0; i < raptor_sequence_size(gp->graph_patterns); i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ if(rasqal_graph_pattern_constraints_has_qname(sgp))
+ return 1;
+ }
+ }
+
+ if(!gp->filter_expression)
+ return 0;
+
+ /* check for qnames in constraint expressions */
+ if(rasqal_expression_visit(gp->filter_expression,
+ rasqal_expression_has_qname, gp))
+ return 1;
+
+ return 0;
+}
+
+
+int
+rasqal_query_constraints_has_qname(rasqal_query* rq)
+{
+ if(!rq->query_graph_pattern)
+ return 0;
+
+ return rasqal_graph_pattern_constraints_has_qname(rq->query_graph_pattern);
+}
+
+
+int
+rasqal_query_expand_graph_pattern_constraints_qnames(rasqal_query *rq,
+ rasqal_graph_pattern* gp)
+{
+ int i;
+
+ /* expand qnames in sub graph patterns */
+ if(gp->graph_patterns) {
+ /* check for constraint qnames in rasqal_graph_patterns */
+ for(i = 0; i < raptor_sequence_size(gp->graph_patterns); i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ if(rasqal_query_expand_graph_pattern_constraints_qnames(rq, sgp))
+ return 1;
+ }
+ }
+
+ if(!gp->filter_expression)
+ return 0;
+
+ /* expand qnames in constraint expressions */
+ if(rasqal_expression_visit(gp->filter_expression,
+ rasqal_expression_expand_qname, rq))
+ return 1;
+
+ return 0;
+}
+
+
+int
+rasqal_query_expand_query_constraints_qnames(rasqal_query *rq)
+{
+ return rasqal_query_expand_graph_pattern_constraints_qnames(rq,
+ rq->query_graph_pattern);
+}
+
+
+static int
+rasqal_query_convert_blank_node_to_anonymous_variable(rasqal_query *rq,
+ rasqal_literal *l)
+{
+ rasqal_variable* v;
+
+ v = rasqal_new_variable_typed(rq,
+ RASQAL_VARIABLE_TYPE_ANONYMOUS,
+ (unsigned char*)l->string, NULL);
+ /* rasqal_new_variable_typed took ownership of the l->string name.
+ * Set to NULL to prevent double delete. */
+ l->string = NULL;
+
+ if(!v)
+ return 1; /* error */
+
+ /* Convert the blank node literal into a variable literal */
+ l->type = RASQAL_LITERAL_VARIABLE;
+ l->value.variable = v;
+
+ return 0; /* success */
+}
+
+
+/**
+ * rasqal_query_build_anonymous_variables:
+ * @rq: query
+ *
+ * INTERNAL - Turn triple blank node parts into anonymous variables
+ *
+ * These are the blank nodes such as (Turtle/SPARQL):
+ * _:name or [] or [ prop value ] or ( collection of things )
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_query_build_anonymous_variables(rasqal_query* rq)
+{
+ int i;
+ int rc = 1;
+ raptor_sequence *s = rq->triples;
+
+ for(i = 0; i < raptor_sequence_size(s); i++) {
+ rasqal_triple* t = (rasqal_triple*)raptor_sequence_get_at(s, i);
+ if(t->subject->type == RASQAL_LITERAL_BLANK &&
+ rasqal_query_convert_blank_node_to_anonymous_variable(rq, t->subject))
+ goto done;
+ if(t->predicate->type == RASQAL_LITERAL_BLANK &&
+ rasqal_query_convert_blank_node_to_anonymous_variable(rq, t->predicate))
+ goto done;
+ if(t->object->type == RASQAL_LITERAL_BLANK &&
+ rasqal_query_convert_blank_node_to_anonymous_variable(rq, t->object))
+ goto done;
+ }
+
+ rc = 0;
+
+ done:
+ return rc;
+}
+
+
+/**
+ * rasqal_query_expand_wildcards:
+ * @rq: query
+ *
+ * INTERNAL - expand RDQL/SPARQL SELECT * to a full list of select variables
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_query_expand_wildcards(rasqal_query* rq)
+{
+ int i;
+ int size;
+
+ if(rq->verb != RASQAL_QUERY_VERB_SELECT || !rq->wildcard)
+ return 0;
+
+ /* If 'SELECT *' was given, make the selects be a list of all variables */
+ rq->selects = raptor_new_sequence(NULL, (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!rq->selects)
+ return 1;
+
+ size = rasqal_variables_table_get_named_variables_count(rq->vars_table);
+ for(i = 0; i < size; i++) {
+ rasqal_variable* v = rasqal_variables_table_get(rq->vars_table, i);
+ if(raptor_sequence_push(rq->selects, v))
+ return 1;
+ }
+
+ rq->select_variables_count = size;
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_remove_duplicate_select_vars:
+ * @rq: query
+ *
+ * INTERNAL - remove duplicate variables in SELECT sequence and warn
+ *
+ * The order of the select variables is preserved.
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_query_remove_duplicate_select_vars(rasqal_query* rq)
+{
+ int i;
+ int modified = 0;
+ int size;
+ raptor_sequence* seq = rq->selects;
+ raptor_sequence* new_seq;
+
+ if(!seq)
+ return 1;
+
+ size = raptor_sequence_size(seq);
+ if(!size)
+ return 0;
+
+ new_seq = raptor_new_sequence(NULL, (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!new_seq)
+ return 1;
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG1("bound variables before deduping: ");
+ raptor_sequence_print(rq->selects, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ for(i = 0; i < size; i++) {
+ int j;
+ rasqal_variable *v;
+ int warned = 0;
+
+ v = (rasqal_variable*)raptor_sequence_get_at(seq, i);
+ if(!v)
+ continue;
+
+ for(j = 0; j < i; j++) {
+ rasqal_variable *v2;
+ v2 = (rasqal_variable*)raptor_sequence_get_at(seq, j);
+
+ if(v == v2) {
+ if(!warned) {
+ rasqal_log_error_simple(rq->world, RAPTOR_LOG_LEVEL_WARNING,
+ &rq->locator,
+ "Variable %s duplicated in SELECT.",
+ v->name);
+ warned = 1;
+ }
+ }
+ }
+ if(!warned) {
+ raptor_sequence_push(new_seq, v);
+ modified = 1;
+ }
+ }
+
+ if(modified) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG1("bound variables after deduping: ");
+ raptor_sequence_print(new_seq, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+ raptor_free_sequence(rq->selects);
+ rq->selects = new_seq;
+ rq->select_variables_count = raptor_sequence_size(rq->selects);
+ } else
+ raptor_free_sequence(new_seq);
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_triples_build_declared_in_internal:
+ * @query: the #rasqal_query to find the variables in
+ * @declared_in: array to write declared_in
+ * @start_column: first column in triples array
+ * @end_column: last column in triples array
+ *
+ * INTERNAL - Mark where variables are first declared in a sequence of triples
+ *
+ **/
+static void
+rasqal_query_triples_build_declared_in_internal(rasqal_query* query,
+ int *declared_in,
+ int start_column,
+ int end_column)
+{
+ int col;
+
+ for(col = start_column; col <= end_column; col++) {
+ rasqal_triple *t;
+ rasqal_variable *v;
+
+ t = (rasqal_triple*)raptor_sequence_get_at(query->triples, col);
+
+ if((v = rasqal_literal_as_variable(t->subject))) {
+ if(declared_in[v->offset] < 0)
+ declared_in[v->offset] = col;
+ }
+ if((v = rasqal_literal_as_variable(t->predicate))) {
+ if(declared_in[v->offset] < 0)
+ declared_in[v->offset] = col;
+ }
+ if((v = rasqal_literal_as_variable(t->object))) {
+ if(declared_in[v->offset] < 0)
+ declared_in[v->offset] = col;
+ }
+ if(t->origin) {
+ if((v = rasqal_literal_as_variable(t->origin))) {
+ if(declared_in[v->offset] < 0)
+ declared_in[v->offset] = col;
+ }
+ }
+
+ }
+}
+
+
+/**
+ * rasqal_query_triples_build_declared_in:
+ * @query: the #rasqal_query to find the variables in
+ * @size:
+ * @start_column: first column in triples array
+ * @end_column: last column in triples array
+ *
+ * INTERNAL - Mark where variables are first declared in a graph_pattern tree walk
+ *
+ **/
+int*
+rasqal_query_triples_build_declared_in(rasqal_query* query,
+ int size,
+ int start_column,
+ int end_column)
+{
+ int i;
+ int *declared_in;
+
+ declared_in = (int*)RASQAL_CALLOC(intarray, size+1, sizeof(int));
+ if(!declared_in)
+ return NULL;
+
+ for(i = 0; i < size; i++)
+ declared_in[i] = -1;
+
+ rasqal_query_triples_build_declared_in_internal(query, declared_in,
+ start_column,
+ end_column);
+ return declared_in;
+}
+
+
+/**
+ * rasqal_query_graph_pattern_build_declared_in:
+ * @query: the #rasqal_query to find the variables in
+ * @declared_in: array to write declared_in
+ * @gp: graph pattern to use
+ *
+ * INTERNAL - Mark where variables are first declared in a graph_pattern tree walk
+ *
+ **/
+static int
+rasqal_query_graph_pattern_build_declared_in(rasqal_query* query,
+ int *declared_in,
+ rasqal_graph_pattern *gp)
+{
+ if(gp->graph_patterns) {
+ int i;
+
+ for(i = 0; i < raptor_sequence_size(gp->graph_patterns); i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ if(rasqal_query_graph_pattern_build_declared_in(query, declared_in, sgp))
+ return 1;
+ }
+ }
+
+ if(!gp->triples)
+ return 0;
+
+ rasqal_query_triples_build_declared_in_internal(query, declared_in,
+ gp->start_column,
+ gp->end_column);
+ return 0;
+}
+
+
+/**
+ * rasqal_query_build_declared_in:
+ * @query: the #rasqal_query to find the variables in
+ *
+ * INTERNAL - Record the triple columns where variables are first declared in a query
+ *
+ * Constructs an array indexed by variable offset of columns where
+ * the variable is first declared. The order used is a tree walk of
+ * the graph patterns. Later mentions of the variable are not marked.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+rasqal_query_build_declared_in(rasqal_query* query)
+{
+ int i;
+ int size;
+
+ size = rasqal_variables_table_get_total_variables_count(query->vars_table);
+
+ query->variables_declared_in = (int*)RASQAL_CALLOC(intarray, size+1, sizeof(int));
+ if(!query->variables_declared_in)
+ return 1;
+
+ for(i = 0; i < size; i++)
+ query->variables_declared_in[i] = -1;
+
+ return rasqal_query_graph_pattern_build_declared_in(query,
+ query->variables_declared_in,
+ query->query_graph_pattern);
+}
+
+
+/**
+ * rasqal_query_check_unused_variables:
+ * @query: the #rasqal_query to check
+ * @declared_in: array of columns where variables are declared as created by rasqal_query_build_declared_in()
+ *
+ * INTERNAL - warn for variables that are selected but not mentioned in a triple
+ *
+ * Return value: non-0 on failure
+ */
+static int
+rasqal_query_check_unused_variables(rasqal_query* query, int *declared_in)
+{
+ int i;
+ int size;
+
+ /* check declared in only for named variables since only they can
+ * appear in SELECT $vars
+ */
+ size = rasqal_variables_table_get_named_variables_count(query->vars_table);
+ for(i = 0; i < size; i++) {
+ int column = declared_in[i];
+ rasqal_variable *v;
+
+ v = rasqal_variables_table_get(query->vars_table, i);
+ if(column >= 0) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG4("Variable %s (%d) was declared in column %d\n",
+ v->name, i, column);
+#endif
+ } else if(!v->expression)
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_WARNING,
+ &query->locator,
+ "Variable %s was selected but is unused in the query.",
+ v->name);
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_merge_triple_patterns:
+ * @query: query (not used here)
+ * @gp: current graph pattern
+ * @data: visit data (not used here)
+ *
+ * INTERNAL - Join triple patterns in adjacent basic graph patterns into
+ * single basic graph pattern.
+ *
+ * For group graph pattern move all triples
+ * from { { a } { b } { c } D... }
+ * to { a b c D... }
+ * if the types of a, b, c are all BASIC GPs (just triples)
+ * D... is anything else
+ *
+ */
+static int
+rasqal_query_merge_triple_patterns(rasqal_query* query,
+ rasqal_graph_pattern* gp,
+ void* data)
+{
+ int* modified = (int*)data;
+ int checking;
+ int offset;
+
+#if RASQAL_DEBUG > 1
+ printf("rasqal_query_merge_triple_patterns: Checking graph pattern #%d:\n ", gp->gp_index);
+ rasqal_graph_pattern_print(gp, stdout);
+ fputs("\n", stdout);
+ RASQAL_DEBUG3("Columns %d to %d\n", gp->start_column, gp->end_column);
+#endif
+
+ if(!gp->graph_patterns) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Ending graph patterns %d - no sub-graph patterns\n", gp->gp_index);
+#endif
+ return 0;
+ }
+
+ if(gp->op != RASQAL_GRAPH_PATTERN_OPERATOR_GROUP) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("Ending graph patterns %d - operator %s\n", gp->gp_index,
+ rasqal_graph_pattern_operator_as_string(gp->op));
+#endif
+ return 0;
+ }
+
+
+ checking = 1;
+ offset = 0;
+ while(checking) {
+ int bgp_count;
+ rasqal_graph_pattern *dest_bgp;
+ raptor_sequence *seq;
+ int i, j;
+ int first = 0, last = 0;
+ int size = raptor_sequence_size(gp->graph_patterns);
+
+ /* find first basic graph pattern starting at offset */
+ for(i= offset; i < size; i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+
+ if(sgp->op == RASQAL_GRAPH_PATTERN_OPERATOR_BASIC) {
+ first = i;
+ break;
+ }
+ }
+
+ /* None found */
+ if(i >= size)
+ break;
+
+ /* Next time, start after this BGP */
+ offset = i+1;
+
+ /* count basic graph patterns */
+ bgp_count = 0;
+ dest_bgp = NULL; /* destination graph pattern */
+ for(j = i; j < size; j++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, j);
+
+ if(sgp->op == RASQAL_GRAPH_PATTERN_OPERATOR_BASIC) {
+ bgp_count++;
+ if(!dest_bgp)
+ dest_bgp = sgp;
+ last = j;
+ } else
+ break;
+ }
+
+
+ #if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("Found sequence of %d basic sub-graph patterns in %d\n", bgp_count, gp->gp_index);
+ #endif
+ if(bgp_count < 2)
+ continue;
+
+ #if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("OK to merge %d basic sub-graph patterns of %d\n", bgp_count, gp->gp_index);
+
+ RASQAL_DEBUG3("Initial columns %d to %d\n", gp->start_column, gp->end_column);
+ #endif
+ seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_graph_pattern, (raptor_sequence_print_handler*)rasqal_graph_pattern_print);
+ if(!seq)
+ return 1;
+ for(i = 0; raptor_sequence_size(gp->graph_patterns) > 0; i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_unshift(gp->graph_patterns);
+ if(i >= first && i <= last) {
+ if(sgp != dest_bgp) {
+ if(rasqal_graph_patterns_join(dest_bgp, sgp)) {
+ RASQAL_DEBUG1("Cannot join graph patterns\n");
+ *modified = -1; /* error flag */
+ }
+ rasqal_free_graph_pattern(sgp);
+ } else
+ raptor_sequence_push(seq, sgp);
+ } else
+ raptor_sequence_push(seq, sgp);
+ }
+ raptor_free_sequence(gp->graph_patterns);
+ gp->graph_patterns = seq;
+
+ if(!*modified)
+ *modified = 1;
+
+ } /* end while checking */
+
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("Ending columns %d to %d\n", gp->start_column, gp->end_column);
+
+ RASQAL_DEBUG2("Ending graph pattern #%d\n ", gp->gp_index);
+ rasqal_graph_pattern_print(gp, stdout);
+ fputs("\n\n", stdout);
+#endif
+
+ return 0;
+}
+
+
+/**
+ * rasqal_graph_pattern_move_constraints:
+ * @dest_gp: destination graph pattern
+ * @src_gp: src graph pattern
+ *
+ * INTERNAL - copy all constraints from @src_gp graph pattern to @src_gp graph pattern
+ *
+ * Return value: non-0 on error
+ */
+int
+rasqal_graph_pattern_move_constraints(rasqal_graph_pattern* dest_gp,
+ rasqal_graph_pattern* src_gp)
+{
+ int rc = 0;
+ rasqal_expression* e;
+
+ if(!src_gp->filter_expression)
+ return 0; /* no constraints is not an error */
+
+ e = rasqal_new_expression_from_expression(src_gp->filter_expression);
+ rc = rasqal_graph_pattern_set_filter_expression(dest_gp, e);
+
+ return rc;
+}
+
+
+/**
+ * rasqal_query_remove_empty_group_graph_patterns:
+ * @query: query (not used here)
+ * @gp: current graph pattern
+ * @data: visit data (not used here)
+ *
+ * INTERNAL - Remove empty group graph patterns
+ *
+ * Return value: non-0 on failure
+ */
+static int
+rasqal_query_remove_empty_group_graph_patterns(rasqal_query* query,
+ rasqal_graph_pattern* gp,
+ void* data)
+{
+ int i;
+ int saw_empty_gp = 0;
+ raptor_sequence *seq;
+ int* modified = (int*)data;
+
+ if(!gp->graph_patterns)
+ return 0;
+
+#if RASQAL_DEBUG > 1
+ printf("rasqal_query_remove_empty_group_graph_patterns: Checking graph pattern #%d:\n ", gp->gp_index);
+ rasqal_graph_pattern_print(gp, stdout);
+ fputs("\n", stdout);
+#endif
+
+ for(i = 0; i < raptor_sequence_size(gp->graph_patterns); i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ if(sgp->graph_patterns && !raptor_sequence_size(sgp->graph_patterns)) {
+ /* One is enough to know we need to rewrite */
+ saw_empty_gp = 1;
+ break;
+ }
+ }
+
+ if(!saw_empty_gp) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Ending graph patterns %d - saw no empty groups\n", gp->gp_index);
+#endif
+ return 0;
+ }
+
+
+ seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_graph_pattern, (raptor_sequence_print_handler*)rasqal_graph_pattern_print);
+ if(!seq) {
+ RASQAL_DEBUG1("Cannot create new gp sequence\n");
+ *modified = -1;
+ return 1;
+ }
+ while(raptor_sequence_size(gp->graph_patterns) > 0) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_unshift(gp->graph_patterns);
+ if(sgp->graph_patterns && !raptor_sequence_size(sgp->graph_patterns)) {
+ rasqal_graph_pattern_move_constraints(gp, sgp);
+ rasqal_free_graph_pattern(sgp);
+ continue;
+ }
+ raptor_sequence_push(seq, sgp);
+ }
+ raptor_free_sequence(gp->graph_patterns);
+ gp->graph_patterns = seq;
+
+ if(!*modified)
+ *modified = 1;
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Ending graph pattern #%d\n ", gp->gp_index);
+ rasqal_graph_pattern_print(gp, stdout);
+ fputs("\n\n", stdout);
+#endif
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_merge_graph_patterns:
+ * @query: query (not used here)
+ * @gp: current graph pattern
+ * @data: pointer to int modified flag
+ *
+ * INTERNAL - Merge graph patterns where possible
+ *
+ * When size = 1 (never for UNION)
+ * GROUP { A } -> A
+ * OPTIONAL { A } -> OPTIONAL { A }
+ *
+ * When size > 1
+ * GROUP { BASIC{2,} } -> merge-BASIC
+ * OPTIONAL { BASIC{2,} } -> OPTIONAL { merge-BASIC }
+ *
+ * Never merged: UNION
+ */
+int
+rasqal_query_merge_graph_patterns(rasqal_query* query,
+ rasqal_graph_pattern* gp,
+ void* data)
+{
+ rasqal_graph_pattern_operator op;
+ int merge_gp_ok = 0;
+ int all_gp_op_same = 0;
+ int i;
+ int size;
+ int* modified = (int*)data;
+
+#if RASQAL_DEBUG > 1
+ printf("rasqal_query_merge_graph_patterns: Checking graph pattern #%d:\n ",
+ gp->gp_index);
+ rasqal_graph_pattern_print(gp, stdout);
+ fputs("\n", stdout);
+ RASQAL_DEBUG3("Columns %d to %d\n", gp->start_column, gp->end_column);
+#endif
+
+ if(!gp->graph_patterns) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("Ending graph pattern #%d - operator %s: no sub-graph patterns\n", gp->gp_index,
+ rasqal_graph_pattern_operator_as_string(gp->op));
+#endif
+ return 0;
+ }
+
+ if(gp->op != RASQAL_GRAPH_PATTERN_OPERATOR_GROUP) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("Ending graph patterns %d - operator %s: not GROUP\n", gp->gp_index,
+ rasqal_graph_pattern_operator_as_string(gp->op));
+#endif
+ return 0;
+ }
+
+ size = raptor_sequence_size(gp->graph_patterns);
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("Doing %d sub-graph patterns of %d\n", size, gp->gp_index);
+#endif
+ op = RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN;
+ all_gp_op_same = 1;
+ for(i = 0; i < size; i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ if(op == RASQAL_GRAPH_PATTERN_OPERATOR_UNKNOWN) {
+ op = sgp->op;
+ } else {
+ if(op != sgp->op) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG4("Sub-graph pattern #%d is %s different from first %s, cannot merge\n",
+ i, rasqal_graph_pattern_operator_as_string(sgp->op),
+ rasqal_graph_pattern_operator_as_string(op));
+#endif
+ all_gp_op_same = 0;
+ }
+ }
+ }
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Sub-graph patterns of %d done\n", gp->gp_index);
+#endif
+
+ if(!all_gp_op_same) {
+ merge_gp_ok = 0;
+ goto merge_check_done;
+ }
+
+ if(size == 1) {
+ merge_gp_ok = 1;
+ goto merge_check_done;
+ }
+
+
+ /* if size > 1 check if ALL sub-graph patterns are basic graph
+ * patterns and either:
+ * 1) a single triple
+ * 2) a single constraint
+ */
+ for(i = 0; i < size; i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+
+ if(sgp->op != RASQAL_GRAPH_PATTERN_OPERATOR_BASIC) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("Found %s sub-graph pattern #%d\n",
+ rasqal_graph_pattern_operator_as_string(sgp->op),
+ sgp->gp_index);
+#endif
+ merge_gp_ok = 0;
+ break;
+ }
+
+ /* not ok if there are >1 triples */
+ if(sgp->triples && (sgp->end_column-sgp->start_column+1) > 1) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Found >1 triples in sub-graph pattern #%d\n", sgp->gp_index);
+#endif
+ merge_gp_ok = 0;
+ break;
+ }
+
+ /* not ok if there are triples and constraints */
+ if(sgp->triples && sgp->filter_expression) {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Found triples and constraints in sub-graph pattern #%d\n", sgp->gp_index);
+#endif
+ merge_gp_ok = 0;
+ break;
+ }
+
+ /* was at least 1 OK sub graph-pattern */
+ merge_gp_ok = 1;
+ }
+
+ merge_check_done:
+
+ if(merge_gp_ok) {
+ raptor_sequence *seq;
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("OK to merge sub-graph patterns of %d\n", gp->gp_index);
+
+ RASQAL_DEBUG3("Initial columns %d to %d\n", gp->start_column, gp->end_column);
+#endif
+
+ /* Pretend dest is an empty basic graph pattern */
+ seq = gp->graph_patterns;
+ gp->graph_patterns = NULL;
+ gp->op = op;
+
+ while(raptor_sequence_size(seq) > 0) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_unshift(seq);
+
+ /* fake this so that the join happens */
+ sgp->op = gp->op;
+ if(rasqal_graph_patterns_join(gp, sgp)) {
+ RASQAL_DEBUG1("Cannot join graph patterns\n");
+ *modified = -1; /* error flag */
+ }
+ rasqal_free_graph_pattern(sgp);
+ }
+
+ /* If result is 'basic' but contains graph patterns, turn it into a group */
+ if(gp->graph_patterns && gp->op == RASQAL_GRAPH_PATTERN_OPERATOR_BASIC)
+ gp->op = RASQAL_GRAPH_PATTERN_OPERATOR_GROUP;
+
+ /* Delete any evidence of sub graph patterns */
+ raptor_free_sequence(seq);
+
+ if(!*modified)
+ *modified = 1;
+
+ } else {
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("NOT OK to merge sub-graph patterns of %d\n", gp->gp_index);
+#endif
+ }
+
+#if RASQAL_DEBUG > 1
+ if(merge_gp_ok) {
+ RASQAL_DEBUG2("Ending graph pattern #%d\n ", gp->gp_index);
+ rasqal_graph_pattern_print(gp, stdout);
+ fputs("\n\n", stdout);
+ }
+#endif
+
+ return 0;
+}
+
+
+struct folding_state {
+ rasqal_query* query;
+ int changes;
+ int failed;
+};
+
+
+static int
+rasqal_expression_foreach_fold(void *user_data, rasqal_expression *e)
+{
+ struct folding_state *st = (struct folding_state*)user_data;
+ rasqal_query* query;
+ rasqal_literal* l;
+
+ /* skip if already a literal or this expression tree is not constant */
+ if(e->op == RASQAL_EXPR_LITERAL || !rasqal_expression_is_constant(e))
+ return 0;
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG2("folding expression %p: ", e);
+ rasqal_expression_print(e, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+#endif
+
+ query = st->query;
+ l = rasqal_expression_evaluate_v2(query->world, &query->locator,
+ e, query->compare_flags);
+ if(!l) {
+ st->failed++;
+ return 1;
+ }
+
+ /* In-situ conversion of 'e' to a literal expression */
+ rasqal_expression_convert_to_literal(e, l);
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("folded expression now: ");
+ rasqal_expression_print(e, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+
+ /* change made */
+ st->changes++;
+
+ return 0;
+}
+
+
+static int
+rasqal_query_expression_fold(rasqal_query* rq, rasqal_expression* e)
+{
+ struct folding_state st;
+
+ st.query = rq;
+ while(1) {
+ st.changes = 0;
+ st.failed = 0;
+ rasqal_expression_visit(e, rasqal_expression_foreach_fold,
+ (void*)&st);
+ if(!st.changes || st.failed)
+ break;
+ }
+
+ return st.failed;
+}
+
+
+static int
+rasqal_graph_pattern_fold_expressions(rasqal_query* rq,
+ rasqal_graph_pattern* gp)
+{
+ if(!gp)
+ return 1;
+
+ /* fold expressions in sub graph patterns */
+ if(gp->graph_patterns) {
+ int i;
+
+ for(i = 0; i < raptor_sequence_size(gp->graph_patterns); i++) {
+ rasqal_graph_pattern *sgp;
+ sgp = (rasqal_graph_pattern*)raptor_sequence_get_at(gp->graph_patterns, i);
+ if(rasqal_graph_pattern_fold_expressions(rq, sgp))
+ return 1;
+ }
+ }
+
+ if(gp->filter_expression)
+ return rasqal_query_expression_fold(rq, gp->filter_expression);
+
+ return 0;
+}
+
+
+static int
+rasqal_query_fold_expressions(rasqal_query* rq)
+{
+ rasqal_graph_pattern *gp = rq->query_graph_pattern;
+ int order_size;
+
+ if(gp)
+ rasqal_graph_pattern_fold_expressions(rq, gp);
+
+ if(!rq->order_conditions_sequence)
+ return 0;
+
+ order_size = raptor_sequence_size(rq->order_conditions_sequence);
+ if(order_size) {
+ int i;
+
+ for(i = 0; i < order_size; i++) {
+ rasqal_expression* e;
+ e = (rasqal_expression*)raptor_sequence_get_at(rq->order_conditions_sequence, i);
+ rasqal_query_expression_fold(rq, e);
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+rasqal_query_prepare_count_graph_patterns(rasqal_query* query,
+ rasqal_graph_pattern* gp,
+ void* data)
+{
+ raptor_sequence* seq = (raptor_sequence*)data;
+
+ if(raptor_sequence_push(seq, gp)) {
+ query->failed = 1;
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_FATAL,
+ NULL,
+ "Out of memory in rasqal_query_prepare_count_graph_patterns()");
+ return 1;
+ }
+ gp->gp_index = (query->graph_pattern_count++);
+ return 0;
+}
+
+
+/**
+ * rasqal_query_prepare_common:
+ * @query: query
+ *
+ * INTERNAL - initialise the remainder of the query structures
+ *
+ * Does not do any execution prepration - this is once-only stuff.
+ *
+ * NOTE: The caller is responsible for ensuring this is called at
+ * most once. This is currently enforced by rasqal_query_prepare()
+ * using the query->prepared flag when it calls the query factory
+ * prepare method which does the query string parsing and ends by
+ * calling this function.
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_query_prepare_common(rasqal_query *query)
+{
+ int rc = 1;
+
+ if(!query->triples)
+ goto done;
+
+ /* turn SELECT $a, $a into SELECT $a - editing query->selects */
+ if(query->selects) {
+ if(rasqal_query_remove_duplicate_select_vars(query))
+ goto done;
+ }
+
+ if(query->query_graph_pattern) {
+ /* This query prepare processing requires a query graph pattern.
+ * Not the case for a legal query like 'DESCRIBE <uri>'
+ */
+
+ /* create query->variables_declared_in to find triples where a variable
+ * is first used and look for variables selected that are not used
+ * in the execution order (graph pattern tree walk order).
+ *
+ * The query->variables_declared_in array is used in
+ * rasqal_engine_graph_pattern_init() when trying to figure out
+ * which parts of a triple pattern need to bind to a variable:
+ * only the first reference to it.
+ */
+ if(rasqal_query_build_declared_in(query))
+ goto done;
+
+ /* warn if any of the selected named variables are not in a triple */
+ if(rasqal_query_check_unused_variables(query, query->variables_declared_in))
+ goto done;
+ }
+
+ rasqal_query_fold_expressions(query);
+
+ if(query->query_graph_pattern) {
+#ifndef RASQAL_NO_GP_MERGE
+ int modified;
+
+#if RASQAL_DEBUG > 1
+ fputs("Initial query graph pattern:\n ", DEBUG_FH);
+ rasqal_graph_pattern_print(query->query_graph_pattern, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ do {
+ modified = 0;
+
+ rasqal_query_graph_pattern_visit(query,
+ rasqal_query_merge_triple_patterns,
+ &modified);
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "modified=%d after merge triples, query graph pattern now:\n ", modified);
+ rasqal_graph_pattern_print(query->query_graph_pattern, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ rasqal_query_graph_pattern_visit(query,
+ rasqal_query_remove_empty_group_graph_patterns,
+ &modified);
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "modified=%d after remove empty groups, query graph pattern now:\n ", modified);
+ rasqal_graph_pattern_print(query->query_graph_pattern, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ rasqal_query_graph_pattern_visit(query,
+ rasqal_query_merge_graph_patterns,
+ &modified);
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "modified=%d after merge graph patterns, query graph pattern now:\n ", modified);
+ rasqal_graph_pattern_print(query->query_graph_pattern, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ } while(modified>0);
+
+ rc = modified; /* error if modified<0, success if modified==0 */
+ if(rc)
+ goto done;
+
+#endif /* !RASQAL_NO_GP_MERGE */
+
+ /* Label all graph patterns with an index 0.. for use in discovering
+ * the size of the graph pattern execution data array
+ */
+ query->graph_pattern_count = 0;
+
+ /* This sequence stores shared pointers to the graph patterns it
+ * finds, indexed by the gp_index
+ */
+ query->graph_patterns_sequence = raptor_new_sequence(NULL, NULL);
+ if(!query->graph_patterns_sequence)
+ return 1;
+
+ rasqal_query_graph_pattern_visit(query,
+ rasqal_query_prepare_count_graph_patterns,
+ query->graph_patterns_sequence);
+ }
+
+
+ rc = 0;
+
+ done:
+ return rc;
+}
+
+
+/**
+ * rasqal_graph_patterns_join:
+ * @dest_gp: destination graph pattern
+ * @src_gp: src graph pattern
+ *
+ * INTERNAL - merge @src_gp graph pattern into @dest_gp graph pattern
+ *
+ * Return value: non-0 on error
+ */
+int
+rasqal_graph_patterns_join(rasqal_graph_pattern *dest_gp,
+ rasqal_graph_pattern *src_gp)
+{
+ int rc;
+
+ if(!src_gp || !dest_gp)
+ return 0;
+
+ if(src_gp->op != dest_gp->op) {
+ RASQAL_DEBUG3("Source operator %s != Destination operator %s, ending\n",
+ rasqal_graph_pattern_operator_as_string(src_gp->op),
+ rasqal_graph_pattern_operator_as_string(dest_gp->op));
+ return 1;
+ }
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Joining graph pattern #%d\n ", src_gp->gp_index);
+ rasqal_graph_pattern_print(src_gp, DEBUG_FH);
+ fprintf(DEBUG_FH, "\nto graph pattern #%d\n ", dest_gp->gp_index);
+ rasqal_graph_pattern_print(dest_gp, DEBUG_FH);
+ fprintf(DEBUG_FH, "\nboth of operator %s\n",
+ rasqal_graph_pattern_operator_as_string(src_gp->op));
+#endif
+
+
+ if(src_gp->graph_patterns) {
+ if(!dest_gp->graph_patterns) {
+ dest_gp->graph_patterns = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_graph_pattern,
+ (raptor_sequence_print_handler*)rasqal_graph_pattern_print);
+ if(!dest_gp->graph_patterns)
+ return -1;
+ }
+
+ raptor_sequence_join(dest_gp->graph_patterns, src_gp->graph_patterns);
+ }
+
+ if(src_gp->triples) {
+ int start_c = src_gp->start_column;
+ int end_c = src_gp->end_column;
+
+ /* if this is our first triple, save a free/alloc */
+ dest_gp->triples = src_gp->triples;
+ src_gp->triples = NULL;
+
+ if((dest_gp->start_column < 0) || start_c < dest_gp->start_column)
+ dest_gp->start_column = start_c;
+ if((dest_gp->end_column < 0) || end_c > dest_gp->end_column)
+ dest_gp->end_column = end_c;
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG3("Moved triples from columns %d to %d\n", start_c, end_c);
+ RASQAL_DEBUG3("Columns now %d to %d\n", dest_gp->start_column, dest_gp->end_column);
+#endif
+ }
+
+ rc = rasqal_graph_pattern_move_constraints(dest_gp, src_gp);
+
+ if(src_gp->origin) {
+ dest_gp->origin = src_gp->origin;
+ src_gp->origin = NULL;
+ }
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("Result graph pattern #%d\n ", dest_gp->gp_index);
+ rasqal_graph_pattern_print(dest_gp, stdout);
+ fputs("\n", stdout);
+#endif
+
+ return rc;
+}
diff --git a/src/rasqal/rasqal_raptor.c b/src/rasqal/rasqal_raptor.c
new file mode 100644
index 0000000..26d6fef
--- /dev/null
+++ b/src/rasqal/rasqal_raptor.c
@@ -0,0 +1,816 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_raptor.c - Rasqal triple store implementation with raptor
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+struct rasqal_raptor_triple_s {
+ struct rasqal_raptor_triple_s *next;
+ rasqal_triple *triple;
+};
+
+typedef struct rasqal_raptor_triple_s rasqal_raptor_triple;
+
+typedef struct {
+ rasqal_query* query;
+
+ rasqal_raptor_triple *head;
+ rasqal_raptor_triple *tail;
+
+ /* index used while reading triples into the two arrays below.
+ * This is used to connect a triple to the URI literal of the source
+ */
+ int source_index;
+
+ /* size of the two arrays below */
+ int sources_count;
+
+ /* shared pointers into query->data_graph uris */
+ raptor_uri* source_uri;
+
+ /* array of URI literals (allocated here) */
+ rasqal_literal **source_literals;
+
+ /* genid base for mapping user bnodes */
+ unsigned char* mapped_id_base;
+ /* length of above string */
+ int mapped_id_base_len;
+} rasqal_raptor_triples_source_user_data;
+
+
+/* prototypes */
+static int rasqal_raptor_init_triples_match(rasqal_triples_match* rtm, rasqal_triples_source *rts, void *user_data, rasqal_triple_meta *m, rasqal_triple *t);
+static int rasqal_raptor_triple_present(rasqal_triples_source *rts, void *user_data, rasqal_triple *t);
+static void rasqal_raptor_free_triples_source(void *user_data);
+
+
+static raptor_uri*
+ordinal_as_uri(rasqal_world* world, int ordinal)
+{
+ int t = ordinal;
+ size_t len;
+ unsigned char *buffer;
+ raptor_uri* uri;
+
+ len = raptor_rdf_namespace_uri_len + 1 + 1; /* 1 for min-length, 1 for '_' */
+ while(t /= 10)
+ len++;
+ buffer = (unsigned char*)RASQAL_MALLOC(cstring, len + 1);
+ if(!buffer)
+ return NULL;
+
+ sprintf((char*)buffer, "%s_%d", raptor_rdf_namespace_uri, ordinal);
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_new_uri_v2(world->raptor_world_ptr, buffer);
+#else
+ uri = raptor_new_uri(buffer);
+#endif
+ RASQAL_FREE(cstring, buffer);
+
+ return uri;
+}
+
+
+static rasqal_triple*
+raptor_statement_as_rasqal_triple(rasqal_world* world,
+ const raptor_statement *statement)
+{
+ rasqal_literal *s, *p, *o;
+
+ if(statement->subject_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS) {
+ unsigned char *new_blank;
+ size_t blank_len;
+
+ blank_len = strlen((char*)statement->subject);
+ new_blank = (unsigned char*)RASQAL_MALLOC(cstring, blank_len + 1);
+ strncpy((char*)new_blank, (const char*)statement->subject, blank_len + 1);
+ s = rasqal_new_simple_literal(world, RASQAL_LITERAL_BLANK, new_blank);
+ } else if(statement->subject_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
+ raptor_uri* uri;
+
+ uri = ordinal_as_uri(world, *((int*)statement->subject));
+ if(!uri)
+ return NULL;
+ s = rasqal_new_uri_literal(world, uri);
+ } else {
+ raptor_uri *uri;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_uri_copy_v2(world->raptor_world_ptr,
+ (raptor_uri*)statement->subject);
+#else
+ uri = raptor_uri_copy((raptor_uri*)statement->subject);
+#endif
+ s = rasqal_new_uri_literal(world, uri);
+ }
+
+ if(statement->predicate_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
+ raptor_uri* uri = ordinal_as_uri(world, *((int*)statement->predicate));
+
+ if(!uri)
+ return NULL;
+ p = rasqal_new_uri_literal(world, uri);
+ } else {
+ raptor_uri *uri;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_uri_copy_v2(world->raptor_world_ptr,
+ (raptor_uri*)statement->predicate);
+#else
+ uri = raptor_uri_copy((raptor_uri*)statement->predicate);
+#endif
+ p = rasqal_new_uri_literal(world, uri);
+ }
+
+ if(statement->object_type == RAPTOR_IDENTIFIER_TYPE_LITERAL ||
+ statement->object_type == RAPTOR_IDENTIFIER_TYPE_XML_LITERAL) {
+ unsigned char *string;
+ char *language = NULL;
+ raptor_uri *uri = NULL;
+ size_t literal_len;
+
+ literal_len = strlen((char*)statement->object);
+ string = (unsigned char*)RASQAL_MALLOC(cstring, literal_len + 1);
+ strncpy((char*)string, (const char*)statement->object, literal_len + 1);
+
+ if(statement->object_literal_language) {
+ size_t language_len;
+ language_len = strlen((const char*)statement->object_literal_language);
+ language = (char*)RASQAL_MALLOC(cstring, language_len + 1);
+ strncpy(language, (const char*)statement->object_literal_language,
+ language_len + 1);
+ }
+
+ if(statement->object_type == RAPTOR_IDENTIFIER_TYPE_XML_LITERAL) {
+ const unsigned char* dt_uri_string;
+
+ dt_uri_string = (const unsigned char*)raptor_xml_literal_datatype_uri_string;
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_new_uri_v2(world->raptor_world_ptr, dt_uri_string);
+#else
+ uri = raptor_new_uri(dt_uri_string);
+#endif
+ } else if(statement->object_literal_datatype) {
+ raptor_uri *dt_uri = (raptor_uri*)statement->object_literal_datatype;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_uri_copy_v2(world->raptor_world_ptr, dt_uri);
+#else
+ uri = raptor_uri_copy(dt_uri);
+#endif
+ }
+ o = rasqal_new_string_literal(world, string, language, uri, NULL);
+ } else if(statement->object_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS) {
+ char *blank = (char*)statement->object;
+ unsigned char *new_blank;
+ size_t blank_len;
+
+ blank_len = strlen(blank);
+ new_blank = (unsigned char*)RASQAL_MALLOC(cstring, blank_len + 1);
+ strncpy((char*)new_blank, (const char*)blank, blank_len + 1);
+ o = rasqal_new_simple_literal(world, RASQAL_LITERAL_BLANK, new_blank);
+ } else if(statement->object_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
+ raptor_uri* uri = ordinal_as_uri(world, *((int*)statement->object));
+
+ if(!uri)
+ return NULL;
+ o = rasqal_new_uri_literal(world, uri);
+ } else {
+ raptor_uri *uri;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_uri_copy_v2(world->raptor_world_ptr,
+ (raptor_uri*)statement->object);
+#else
+ uri = raptor_uri_copy((raptor_uri*)statement->object);
+#endif
+ o = rasqal_new_uri_literal(world, uri);
+ }
+
+ return rasqal_new_triple(s, p, o);
+}
+
+
+
+static void
+rasqal_raptor_statement_handler(void *user_data,
+ const raptor_statement *statement)
+{
+ rasqal_raptor_triples_source_user_data* rtsc;
+ rasqal_raptor_triple *triple;
+
+ rtsc = (rasqal_raptor_triples_source_user_data*)user_data;
+
+ triple = (rasqal_raptor_triple*)RASQAL_MALLOC(rasqal_raptor_triple,
+ sizeof(rasqal_raptor_triple));
+ triple->next = NULL;
+ triple->triple = raptor_statement_as_rasqal_triple(rtsc->query->world,
+ statement);
+
+ /* this origin URI literal is shared amongst the triples and
+ * freed only in rasqal_raptor_free_triples_source
+ */
+ rasqal_triple_set_origin(triple->triple,
+ rtsc->source_literals[rtsc->source_index]);
+
+ if(rtsc->tail)
+ rtsc->tail->next = triple;
+ else
+ rtsc->head = triple;
+
+ rtsc->tail = triple;
+}
+
+
+static void
+rasqal_raptor_error_handler(void *user_data,
+ raptor_locator* locator, const char *message)
+{
+ rasqal_query* query = (rasqal_query*)user_data;
+ int locator_len;
+
+ query->failed = 1;
+
+ if(locator &&
+#ifdef RAPTOR_V2_AVAILABLE
+ (locator_len = raptor_format_locator_v2(query->world->raptor_world_ptr,
+ NULL, 0, locator)) > 0
+#else
+ (locator_len = raptor_format_locator(NULL, 0, locator)) > 0
+#endif
+ ) {
+ char *buffer = (char*)RASQAL_MALLOC(cstring, locator_len + 1);
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_format_locator_v2(query->world->raptor_world_ptr, buffer,
+ locator_len, locator);
+#else
+ raptor_format_locator(buffer, locator_len, locator);
+#endif
+
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Failed to parse %s - %s", buffer, message);
+ RASQAL_FREE(cstring, buffer);
+ } else
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Failed to parse - %s", message);
+}
+
+
+static unsigned char*
+rasqal_raptor_generate_id_handler(void *user_data,
+ raptor_genid_type type,
+ unsigned char *user_bnodeid)
+{
+ rasqal_raptor_triples_source_user_data* rtsc;
+
+ rtsc = (rasqal_raptor_triples_source_user_data*)user_data;
+
+ if(user_bnodeid) {
+ unsigned char *mapped_id;
+ size_t user_bnodeid_len = strlen((const char*)user_bnodeid);
+
+ mapped_id = (unsigned char*)RASQAL_MALLOC(cstring,
+ rtsc->mapped_id_base_len + 1 +
+ user_bnodeid_len + 1);
+ strncpy((char*)mapped_id, (const char*)rtsc->mapped_id_base,
+ rtsc->mapped_id_base_len);
+ mapped_id[rtsc->mapped_id_base_len] = '_';
+ strncpy((char*)(mapped_id+rtsc->mapped_id_base_len + 1),
+ (const char*)user_bnodeid, user_bnodeid_len + 1);
+
+ raptor_free_memory(user_bnodeid);
+ return mapped_id;
+ }
+
+ return rasqal_query_get_genid(rtsc->query, (const unsigned char*)"genid", -1);
+}
+
+
+static int
+rasqal_raptor_new_triples_source(rasqal_query* rdf_query,
+ void *factory_user_data,
+ void *user_data,
+ rasqal_triples_source *rts)
+{
+ rasqal_raptor_triples_source_user_data* rtsc;
+ raptor_parser *parser;
+ int i;
+
+ rtsc = (rasqal_raptor_triples_source_user_data*)user_data;
+
+ if(!rdf_query->data_graphs)
+ return -1; /* no data */
+
+ rts->init_triples_match = rasqal_raptor_init_triples_match;
+ rts->triple_present = rasqal_raptor_triple_present;
+ rts->free_triples_source = rasqal_raptor_free_triples_source;
+
+ rtsc->sources_count = raptor_sequence_size(rdf_query->data_graphs);
+ /* no default triple source possible */
+ if(!rtsc->sources_count)
+ return -1; /* no data */
+
+ rtsc->source_literals = (rasqal_literal**)RASQAL_CALLOC(rasqal_literal_ptr,
+ rtsc->sources_count,
+ sizeof(rasqal_literal*));
+
+ rtsc->query = rdf_query;
+
+ for(i = 0; i < rtsc->sources_count; i++) {
+ rasqal_data_graph *dg;
+ raptor_uri* uri;
+ raptor_uri* name_uri;
+
+ dg = (rasqal_data_graph*)raptor_sequence_get_at(rdf_query->data_graphs, i);
+ uri = dg->uri;
+ name_uri = dg->name_uri;
+
+ rtsc->source_index = i;
+#ifdef RAPTOR_V2_AVAILABLE
+ rtsc->source_uri = raptor_uri_copy_v2(rdf_query->world->raptor_world_ptr,
+ uri);
+#else
+ rtsc->source_uri = raptor_uri_copy(uri);
+#endif
+ if(name_uri)
+ rtsc->source_literals[i] = rasqal_new_uri_literal(rdf_query->world,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_copy_v2(rdf_query->world->raptor_world_ptr, name_uri)
+#else
+ raptor_uri_copy(name_uri)
+#endif
+ );
+ rtsc->mapped_id_base = rasqal_query_get_genid(rdf_query,
+ (const unsigned char*)"graphid",
+ i);
+ rtsc->mapped_id_base_len = strlen((const char*)rtsc->mapped_id_base);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ parser = raptor_new_parser_v2(rdf_query->world->raptor_world_ptr, "guess");
+#else
+ parser = raptor_new_parser("guess");
+#endif
+ raptor_set_statement_handler(parser, rtsc, rasqal_raptor_statement_handler);
+ raptor_set_error_handler(parser, rdf_query, rasqal_raptor_error_handler);
+ raptor_set_generate_id_handler(parser, rtsc,
+ rasqal_raptor_generate_id_handler);
+
+#ifdef RAPTOR_FEATURE_NO_NET
+ if(rdf_query->features[RASQAL_FEATURE_NO_NET])
+ raptor_set_feature(parser, RAPTOR_FEATURE_NO_NET,
+ rdf_query->features[RASQAL_FEATURE_NO_NET]);
+#endif
+
+ raptor_parse_uri(parser, uri, dg->name_uri);
+ raptor_free_parser(parser);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(rdf_query->world->raptor_world_ptr, rtsc->source_uri);
+#else
+ raptor_free_uri(rtsc->source_uri);
+#endif
+
+ /* This is freed in rasqal_raptor_free_triples_source() */
+ /* rasqal_free_literal(rtsc->source_literal); */
+ RASQAL_FREE(cstring, rtsc->mapped_id_base);
+
+ if(rdf_query->failed) {
+ rasqal_raptor_free_triples_source(user_data);
+ break;
+ }
+ }
+
+ return rdf_query->failed;
+}
+
+
+/**
+ * rasqal_raptor_triple_match:
+ * @world: rasqal_world object
+ * @triple: #rasqal_triple to match against
+ * @match: #rasqal_triple with wildcards
+ * @parts; parts of the triple to match
+ * .
+ *
+ * Match a rasqal_triple against a rasqal_triple with NULL
+ * signifying wildcard fields in the rasqal_triple.
+ *
+ * Return value: non-0 on match
+ **/
+static int
+rasqal_raptor_triple_match(rasqal_world* world,
+ rasqal_triple *triple,
+ rasqal_triple *match,
+ rasqal_triple_parts parts)
+{
+ int rc = 0;
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG1("\ntriple ");
+ rasqal_triple_print(triple, stderr);
+ fputs("\nmatch ", stderr);
+ rasqal_triple_print(match, stderr);
+ fputs("\n", stderr);
+#endif
+
+ if(match->subject && (parts & RASQAL_TRIPLE_SUBJECT)) {
+ if(!rasqal_literal_equals_flags(triple->subject, match->subject,
+ RASQAL_COMPARE_RDF, NULL))
+ goto done;
+ }
+
+ if(match->predicate && (parts & RASQAL_TRIPLE_PREDICATE)) {
+ if(!rasqal_literal_equals_flags(triple->predicate, match->predicate,
+ RASQAL_COMPARE_RDF, NULL))
+ goto done;
+ }
+
+ if(match->object && (parts & RASQAL_TRIPLE_OBJECT)) {
+ if(!rasqal_literal_equals_flags(triple->object, match->object,
+ RASQAL_COMPARE_RDF, NULL))
+ goto done;
+ }
+
+ if(parts & RASQAL_TRIPLE_ORIGIN) {
+ /* Binding a graph */
+
+ /* If expecting a graph and triple has none then no match */
+ if(!triple->origin)
+ goto done;
+
+ if(match->origin) {
+ if(match->origin->type == RASQAL_LITERAL_URI ) {
+ raptor_uri* triple_uri = triple->origin->value.uri;
+ raptor_uri* match_uri = match->origin->value.uri;
+#ifdef RAPTOR_V2_AVAILABLE
+ if(!raptor_uri_equals_v2(world->raptor_world_ptr, triple_uri, match_uri))
+ goto done;
+#else
+ if(!raptor_uri_equals(triple_uri, match_uri))
+ goto done;
+#endif
+ }
+ }
+
+ } else {
+ /* Not binding a graph */
+
+ /* If triple has a GRAPH and there is none in the triple pattern, no match */
+ if(triple->origin)
+ goto done;
+ }
+
+ rc = 1;
+ done:
+
+#if RASQAL_DEBUG > 1
+ RASQAL_DEBUG2("result: %s\n", (rc ? "match" : "no match"));
+#endif
+
+ return rc;
+}
+
+
+/* non-0 if present */
+static int
+rasqal_raptor_triple_present(rasqal_triples_source *rts, void *user_data,
+ rasqal_triple *t)
+{
+ rasqal_raptor_triples_source_user_data* rtsc;
+ rasqal_raptor_triple *triple;
+ rasqal_triple_parts parts = RASQAL_TRIPLE_SPO;
+
+ rtsc = (rasqal_raptor_triples_source_user_data*)user_data;
+
+ if(t->origin)
+ parts = (rasqal_triple_parts)(parts | RASQAL_TRIPLE_GRAPH);
+
+ for(triple = rtsc->head; triple; triple = triple->next) {
+ if(rasqal_raptor_triple_match(rtsc->query->world, triple->triple, t, parts))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+static void
+rasqal_raptor_free_triples_source(void *user_data)
+{
+ rasqal_raptor_triples_source_user_data* rtsc;
+ rasqal_raptor_triple *cur;
+ int i;
+
+ rtsc = (rasqal_raptor_triples_source_user_data*)user_data;
+ cur = rtsc->head;
+ while(cur) {
+ rasqal_raptor_triple *next = cur->next;
+ rasqal_triple_set_origin(cur->triple, NULL); /* shared URI literal */
+ rasqal_free_triple(cur->triple);
+ RASQAL_FREE(rasqal_raptor_triple, cur);
+ cur = next;
+ }
+
+ for(i = 0; i < rtsc->sources_count; i++) {
+ if(rtsc->source_literals[i])
+ rasqal_free_literal(rtsc->source_literals[i]);
+ }
+ RASQAL_FREE(raptor_literal_ptr, rtsc->source_literals);
+}
+
+
+
+static void
+rasqal_raptor_register_triples_source_factory(rasqal_triples_source_factory *factory)
+{
+ factory->user_data_size = sizeof(rasqal_raptor_triples_source_user_data);
+ factory->new_triples_source = rasqal_raptor_new_triples_source;
+}
+
+
+typedef struct {
+ rasqal_raptor_triple *cur;
+ rasqal_raptor_triples_source_user_data* source_context;
+ rasqal_triple match;
+
+ /* parts of the triple above to match: always (S,P,O) sometimes C */
+ rasqal_triple_parts parts;
+} rasqal_raptor_triples_match_context;
+
+
+static rasqal_triple_parts
+rasqal_raptor_bind_match(struct rasqal_triples_match_s* rtm,
+ void *user_data,
+ rasqal_variable* bindings[4],
+ rasqal_triple_parts parts)
+{
+ rasqal_raptor_triples_match_context* rtmc;
+ int error = 0;
+ rasqal_triple_parts result = (rasqal_triple_parts)0;
+
+ rtmc = (rasqal_raptor_triples_match_context*)rtm->user_data;
+
+#ifdef RASQAL_DEBUG
+ if(rtmc->cur) {
+ RASQAL_DEBUG1(" matched statement ");
+ rasqal_triple_print(rtmc->cur->triple, stderr);
+ fputc('\n', stderr);
+ } else
+ RASQAL_FATAL1(" matched NO statement - BUG\n");
+#endif
+
+ /* set variable values from the fields of statement */
+
+ if(bindings[0] && (parts & RASQAL_TRIPLE_SUBJECT)) {
+ rasqal_literal *l = rtmc->cur->triple->subject;
+ RASQAL_DEBUG1("binding subject to variable\n");
+ rasqal_variable_set_value(bindings[0], rasqal_new_literal_from_literal(l));
+ result = RASQAL_TRIPLE_SUBJECT;
+ }
+
+ if(bindings[1] && (parts & RASQAL_TRIPLE_PREDICATE)) {
+ if(bindings[0] == bindings[1]) {
+ if(!rasqal_literal_equals_flags(rtmc->cur->triple->subject,
+ rtmc->cur->triple->predicate,
+ RASQAL_COMPARE_RDF, &error))
+ return (rasqal_triple_parts)0;
+ if(error)
+ return (rasqal_triple_parts)0;
+
+ RASQAL_DEBUG1("subject and predicate values match\n");
+ } else {
+ rasqal_literal *l = rtmc->cur->triple->predicate;
+ RASQAL_DEBUG1("binding predicate to variable\n");
+ rasqal_variable_set_value(bindings[1], rasqal_new_literal_from_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(!rasqal_literal_equals_flags(rtmc->cur->triple->subject,
+ rtmc->cur->triple->object,
+ RASQAL_COMPARE_RDF, &error))
+ return (rasqal_triple_parts)0;
+ if(error)
+ return (rasqal_triple_parts)0;
+
+ bind = 0;
+ RASQAL_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(!rasqal_literal_equals_flags(rtmc->cur->triple->predicate,
+ rtmc->cur->triple->object,
+ RASQAL_COMPARE_RDF, &error))
+ return (rasqal_triple_parts)0;
+ if(error)
+ return (rasqal_triple_parts)0;
+
+ bind = 0;
+ RASQAL_DEBUG1("predicate and object values match\n");
+ }
+
+ if(bind) {
+ rasqal_literal *l = rtmc->cur->triple->object;
+ RASQAL_DEBUG1("binding object to variable\n");
+ rasqal_variable_set_value(bindings[2], rasqal_new_literal_from_literal(l));
+ result = (rasqal_triple_parts)(result | RASQAL_TRIPLE_OBJECT);
+ }
+ }
+
+ if(bindings[3] && (parts & RASQAL_TRIPLE_ORIGIN)) {
+ rasqal_literal *l;
+ l = rasqal_new_literal_from_literal(rtmc->cur->triple->origin);
+ RASQAL_DEBUG1("binding origin to variable\n");
+ rasqal_variable_set_value(bindings[3], l);
+ result = (rasqal_triple_parts)(result | RASQAL_TRIPLE_ORIGIN);
+ }
+
+ return result;
+}
+
+
+
+static void
+rasqal_raptor_next_match(struct rasqal_triples_match_s* rtm, void *user_data)
+{
+ rasqal_raptor_triples_match_context* rtmc;
+
+ rtmc = (rasqal_raptor_triples_match_context*)rtm->user_data;
+
+ while(rtmc->cur) {
+ rtmc->cur = rtmc->cur->next;
+ if(rtmc->cur &&
+ rasqal_raptor_triple_match(rtm->world, rtmc->cur->triple, &rtmc->match,
+ rtmc->parts))
+ break;
+ }
+}
+
+static int
+rasqal_raptor_is_end(struct rasqal_triples_match_s* rtm, void *user_data)
+{
+ rasqal_raptor_triples_match_context* rtmc;
+
+ rtmc = (rasqal_raptor_triples_match_context*)rtm->user_data;
+
+ return !rtmc || rtmc->cur == NULL;
+}
+
+
+static void
+rasqal_raptor_finish_triples_match(struct rasqal_triples_match_s* rtm,
+ void *user_data)
+{
+ rasqal_raptor_triples_match_context* rtmc;
+
+ rtmc = (rasqal_raptor_triples_match_context*)rtm->user_data;
+
+ if(rtmc->match.subject)
+ rasqal_free_literal(rtmc->match.subject);
+
+ if(rtmc->match.predicate)
+ rasqal_free_literal(rtmc->match.predicate);
+
+ if(rtmc->match.object)
+ rasqal_free_literal(rtmc->match.object);
+
+ if(rtmc->match.origin)
+ rasqal_free_literal(rtmc->match.origin);
+
+ RASQAL_FREE(rasqal_raptor_triples_match_context, rtmc);
+}
+
+
+static int
+rasqal_raptor_init_triples_match(rasqal_triples_match* rtm,
+ rasqal_triples_source *rts, void *user_data,
+ rasqal_triple_meta *m, rasqal_triple *t)
+{
+ rasqal_raptor_triples_source_user_data* rtsc;
+ rasqal_raptor_triples_match_context* rtmc;
+ rasqal_variable* var;
+
+ rtsc = (rasqal_raptor_triples_source_user_data*)user_data;
+
+ rtm->bind_match = rasqal_raptor_bind_match;
+ rtm->next_match = rasqal_raptor_next_match;
+ rtm->is_end = rasqal_raptor_is_end;
+ rtm->finish = rasqal_raptor_finish_triples_match;
+
+ rtmc = (rasqal_raptor_triples_match_context*)RASQAL_CALLOC(rasqal_raptor_triples_match_context, 1, sizeof(rasqal_raptor_triples_match_context));
+ if(!rtmc)
+ return -1;
+
+ rtm->user_data = rtmc;
+
+ rtmc->source_context = rtsc;
+ rtmc->cur = rtsc->head;
+
+ /* at least one of the triple terms is a variable and we need to
+ * do a triplesMatching() over the list of stored raptor_statements
+ */
+
+ if((var = rasqal_literal_as_variable(t->subject))) {
+ if(var->value)
+ rtmc->match.subject = rasqal_new_literal_from_literal(var->value);
+ } else
+ rtmc->match.subject = rasqal_new_literal_from_literal(t->subject);
+
+ m->bindings[0] = var;
+
+
+ if((var = rasqal_literal_as_variable(t->predicate))) {
+ if(var->value)
+ rtmc->match.predicate = rasqal_new_literal_from_literal(var->value);
+ } else
+ rtmc->match.predicate = rasqal_new_literal_from_literal(t->predicate);
+
+ m->bindings[1] = var;
+
+
+ if((var = rasqal_literal_as_variable(t->object))) {
+ if(var->value)
+ rtmc->match.object = rasqal_new_literal_from_literal(var->value);
+ } else
+ rtmc->match.object = rasqal_new_literal_from_literal(t->object);
+
+ m->bindings[2] = var;
+
+ rtmc->parts = RASQAL_TRIPLE_SPO;
+
+ if(t->origin) {
+ if((var = rasqal_literal_as_variable(t->origin))) {
+ if(var->value)
+ rtmc->match.origin = rasqal_new_literal_from_literal(var->value);
+ } else
+ rtmc->match.origin = rasqal_new_literal_from_literal(t->origin);
+ m->bindings[3] = var;
+ rtmc->parts = (rasqal_triple_parts)(rtmc->parts | RASQAL_TRIPLE_GRAPH);
+ }
+
+
+ while(rtmc->cur) {
+ if(rasqal_raptor_triple_match(rtm->world, rtmc->cur->triple, &rtmc->match,
+ rtmc->parts))
+ break;
+ rtmc->cur = rtmc->cur->next;
+ }
+
+
+ RASQAL_DEBUG1("rasqal_init_triples_match done\n");
+
+ return 0;
+}
+
+
+int
+rasqal_raptor_init(rasqal_world* world)
+{
+ rasqal_set_triples_source_factory(world, rasqal_raptor_register_triples_source_factory, (void*)NULL);
+ return 0;
+}
diff --git a/src/rasqal/rasqal_redland.c b/src/rasqal/rasqal_redland.c
new file mode 100644
index 0000000..6a10cc3
--- /dev/null
+++ b/src/rasqal/rasqal_redland.c
@@ -0,0 +1,474 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_redland.c - Rasqal redland interface
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include <redland.h>
+
+#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
+ RASQAL_FATAL1("Literal type %d cannot be converted to a librdf_node", l->type);
+
+ return NULL;
+}
+
+
+static rasqal_literal*
+redland_node_to_rasqal_literal(rasqal_world *world, 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(world, 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=(char*)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(world, (unsigned char*)new_string, new_language, new_datatype, NULL);
+ } else {
+ char *blank=(char*)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(world, RASQAL_LITERAL_BLANK, (unsigned char*)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(rtm->world, 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(rtm->world, 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(rtm->world, 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(rtm->world, (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;
+
+int
+rasqal_redland_init(rasqal_world* world) {
+ Rasqal_Redland_World=librdf_new_world();
+ if(!Rasqal_Redland_World)
+ return 1;
+ librdf_world_open(Rasqal_Redland_World);
+ rasqal_set_triples_source_factory(world, rasqal_redland_register_triples_source_factory, Rasqal_Redland_World);
+ return 0;
+}
+
+void
+rasqal_redland_finish() {
+ librdf_free_world(Rasqal_Redland_World);
+ Rasqal_Redland_World=NULL;
+}
+
diff --git a/src/rasqal/rasqal_result_formats.c b/src/rasqal/rasqal_result_formats.c
new file mode 100644
index 0000000..c8435f5
--- /dev/null
+++ b/src/rasqal/rasqal_result_formats.c
@@ -0,0 +1,676 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_result_formats.c - Rasqal RDF Query Result Formats
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+static int rasqal_query_results_write_json1(raptor_iostream *iostr, rasqal_query_results* results, raptor_uri *base_uri);
+
+
+int
+rasqal_query_results_format_register_factory(rasqal_world* world,
+ const char *name,
+ const char *label,
+ const unsigned char* uri_string,
+ rasqal_query_results_formatter_func writer,
+ rasqal_query_results_formatter_func reader,
+ rasqal_query_results_get_rowsource_func get_rowsource,
+ const char *mime_type)
+{
+ rasqal_query_results_format_factory* factory;
+
+ factory=(rasqal_query_results_format_factory*)RASQAL_CALLOC(query_results_format_factory,
+ 1, sizeof(rasqal_query_results_format_factory));
+
+ if(!factory) {
+ rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_FATAL, NULL,
+ "Out of memory in rasqal_query_results_format_register_factory()");
+ return 1;
+ }
+ factory->name=name;
+ factory->label=label;
+ factory->uri_string=uri_string;
+ factory->writer=writer;
+ factory->reader=reader;
+ factory->get_rowsource=get_rowsource;
+ factory->mime_type=mime_type;
+
+ return raptor_sequence_push(world->query_results_formats, factory);
+}
+
+
+
+static
+void rasqal_free_query_results_format_factory(rasqal_query_results_format_factory* factory)
+{
+ RASQAL_FREE(query_results_format_factory, factory);
+}
+
+
+int
+rasqal_init_result_formats(rasqal_world* world)
+{
+ rasqal_query_results_formatter_func writer_fn=NULL;
+ rasqal_query_results_formatter_func reader_fn=NULL;
+ rasqal_query_results_get_rowsource_func get_rowsource_fn=NULL;
+ int rc=0;
+
+ world->query_results_formats=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_query_results_format_factory, NULL);
+ if(!world->query_results_formats)
+ return 1;
+
+ rc+= rasqal_init_result_format_sparql_xml(world) != 0;
+
+ /*
+ * SPARQL Query Results in JSON (http://json.org/) draft
+ * Defined in http://www.w3.org/2001/sw/DataAccess/json-sparql/
+ * Version: 1.6 $ of $Date: 2006/04/05 15:55:17
+ */
+ writer_fn=&rasqal_query_results_write_json1;
+ reader_fn=NULL;
+ get_rowsource_fn=NULL;
+ rc+= rasqal_query_results_format_register_factory(world,
+ "json",
+ "JSON",
+ (unsigned char*)"http://www.w3.org/2001/sw/DataAccess/json-sparql/",
+ writer_fn, reader_fn, get_rowsource_fn,
+ "text/json")
+ != 0;
+ rc+= rasqal_query_results_format_register_factory(world,
+ NULL,
+ NULL,
+ (unsigned char*)"http://www.mindswap.org/%7Ekendall/sparql-results-json/",
+ writer_fn, reader_fn, get_rowsource_fn,
+ "text/json")
+ != 0;
+
+ return rc;
+}
+
+
+void
+rasqal_finish_result_formats(rasqal_world* world)
+{
+ if(world->query_results_formats) {
+ raptor_free_sequence(world->query_results_formats);
+ world->query_results_formats = NULL;
+ }
+}
+
+
+/**
+ * rasqal_query_results_formats_enumerate:
+ * @world: rasqal_world object
+ * @counter: index into the list of query result syntaxes
+ * @name: pointer to store the name of the query result syntax (or NULL)
+ * @label: pointer to store query result syntax readable label (or NULL)
+ * @uri_string: pointer to store query result syntax URI string (or NULL)
+ * @mime_type: pointer to store query result syntax mime type string (or NULL)
+ * @flags: pointer to store query result syntax flags (or NULL)
+ *
+ * Get information on query result syntaxes.
+ *
+ * The current list of format names/URI is given below however
+ * the results of this function will always return the latest.
+ *
+ * SPARQL XML Results 2007-06-14 (default format when @counter is 0)
+ * name '<literal>xml</literal>' with
+ * URIs http://www.w3.org/TR/2006/WD-rdf-sparql-XMLres-20070614/ or
+ * http://www.w3.org/2005/sparql-results#
+ *
+ * JSON name '<literal>json</literal>' and
+ * URI http://www.w3.org/2001/sw/DataAccess/json-sparql/
+ *
+ * All returned strings are shared and must be copied if needed to be
+ * used dynamically.
+ *
+ * Return value: non 0 on failure of if counter is out of range
+ **/
+int
+rasqal_query_results_formats_enumerate(rasqal_world* world,
+ unsigned int counter,
+ const char **name,
+ const char **label,
+ const unsigned char **uri_string,
+ const char **mime_type,
+ int *flags)
+
+
+
+{
+ rasqal_query_results_format_factory *factory;
+ int i;
+ unsigned int real_counter;
+
+ real_counter=0;
+ for(i=0; 1; i++) {
+ factory=(rasqal_query_results_format_factory*)raptor_sequence_get_at(world->query_results_formats, i);
+ if(!factory)
+ break;
+
+ if(factory->name) {
+ if(real_counter == counter)
+ break;
+ real_counter++;
+ }
+ }
+
+ if(!factory)
+ return 1;
+
+ if(name)
+ *name=factory->name;
+ if(label)
+ *label=factory->label;
+ if(uri_string)
+ *uri_string=factory->uri_string;
+ if(mime_type)
+ *mime_type=factory->mime_type;
+ if(flags) {
+ *flags=0;
+ if(factory->reader)
+ *flags |= RASQAL_QUERY_RESULTS_FORMAT_FLAG_READER;
+ if(factory->writer)
+ *flags |= RASQAL_QUERY_RESULTS_FORMAT_FLAG_WRITER;
+ }
+
+ return 0;
+}
+
+
+static rasqal_query_results_format_factory*
+rasqal_get_query_results_formatter_factory(rasqal_world* world,
+ const char *name, raptor_uri* uri,
+ const char *mime_type)
+{
+ int i;
+ rasqal_query_results_format_factory* factory=NULL;
+
+ for(i=0; 1; i++) {
+ factory=(rasqal_query_results_format_factory*)raptor_sequence_get_at(world->query_results_formats,
+ i);
+ if(!factory)
+ break;
+
+ if(!name && !uri)
+ /* the default is the first registered format */
+ break;
+
+ if(name && factory->name &&
+ !strcmp(factory->name, (const char*)name))
+ return factory;
+
+
+ if(uri && factory->uri_string &&
+ !strcmp(
+#ifdef RAPTOR_V2_AVAILABLE
+ (const char*)raptor_uri_as_string_v2(world->raptor_world_ptr, uri),
+#else
+ (const char*)raptor_uri_as_string(uri),
+#endif
+ (const char*)factory->uri_string))
+ break;
+
+
+ if(mime_type && factory->mime_type &&
+ !strcmp(factory->mime_type, (const char*)mime_type))
+ return factory;
+ }
+
+ return factory;
+}
+
+
+/**
+ * rasqal_query_results_formats_check:
+ * @world: rasqal_world object
+ * @name: the query results format name (or NULL)
+ * @uri: #raptor_uri query results format uri (or NULL)
+ * @mime_type: mime type name
+ *
+ * Check if a query results formatter exists for the requested format.
+ *
+ * Return value: non-0 if a formatter exists.
+ **/
+int
+rasqal_query_results_formats_check(rasqal_world* world,
+ const char *name, raptor_uri* uri,
+ const char *mime_type)
+{
+ return (rasqal_get_query_results_formatter_factory(world, name, uri, mime_type)
+ != NULL);
+}
+
+
+/**
+ * rasqal_new_query_results_formatter:
+ * @world: rasqal_world object
+ * @name: the query results format name (or NULL)
+ * @format_uri: #raptor_uri query results format uri (or NULL)
+ *
+ * Constructor - create a new rasqal_query_results_formatter object by identified format.
+ *
+ * A query results format can be named or identified by a URI, both
+ * of which are optional. The default query results format will be used
+ * if both are NULL. rasqal_query_results_formats_enumerate() returns
+ * information on the known query results names, labels and URIs.
+ *
+ * Return value: a new #rasqal_query_results_formatter object or NULL on failure
+ */
+rasqal_query_results_formatter*
+rasqal_new_query_results_formatter(rasqal_world* world, const char *name, raptor_uri* format_uri)
+{
+ rasqal_query_results_format_factory* factory;
+ rasqal_query_results_formatter* formatter;
+
+ factory=rasqal_get_query_results_formatter_factory(world, name, format_uri, NULL);
+ if(!factory)
+ return NULL;
+
+ formatter=(rasqal_query_results_formatter*)RASQAL_CALLOC(rasqal_query_results_formatter, 1, sizeof(rasqal_query_results_formatter));
+ if(!formatter)
+ return NULL;
+
+ formatter->factory=factory;
+
+ formatter->mime_type=factory->mime_type;
+
+ return formatter;
+}
+
+
+/**
+ * rasqal_new_query_results_formatter_by_mime_type:
+ * @world: rasqal_world object
+ * @mime_type: mime type name
+ *
+ * Constructor - create a new rasqal_query_results_formatter object by mime type.
+ *
+ * A query results format generates a syntax with a mime type which
+ * may be requested with this constructor.
+ *
+ * Note that there may be several formatters that generate the same
+ * MIME Type (such as SPARQL XML results format drafts) and in thot
+ * case the rasqal_new_query_results_formatter() constructor allows
+ * selecting of a specific one by name or URI.
+ *
+ * Return value: a new #rasqal_query_results_formatter object or NULL on failure
+ */
+rasqal_query_results_formatter*
+rasqal_new_query_results_formatter_by_mime_type(rasqal_world* world, const char *mime_type)
+{
+ rasqal_query_results_format_factory* factory;
+ rasqal_query_results_formatter* formatter;
+
+ if(!mime_type)
+ return NULL;
+
+ factory=rasqal_get_query_results_formatter_factory(world, NULL, NULL, mime_type);
+ if(!factory)
+ return NULL;
+
+ formatter=(rasqal_query_results_formatter*)RASQAL_CALLOC(rasqal_query_results_formatter, 1, sizeof(rasqal_query_results_formatter));
+ if(!formatter)
+ return NULL;
+
+ formatter->factory=factory;
+
+ formatter->mime_type=factory->mime_type;
+
+ return formatter;
+}
+
+
+/**
+ * rasqal_free_query_results_formatter:
+ * @formatter: #rasqal_query_results_formatter object
+ *
+ * Destructor - destroy a #rasqal_query_results_formatter object.
+ **/
+void
+rasqal_free_query_results_formatter(rasqal_query_results_formatter* formatter)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(formatter, rasqal_query_results_formatter);
+
+ RASQAL_FREE(rasqal_query_results_formatter, formatter);
+}
+
+
+static void
+rasqal_iostream_write_json_boolean(raptor_iostream* iostr,
+ const char* name, int json_bool)
+{
+ raptor_iostream_write_byte(iostr, '\"');
+ raptor_iostream_write_string(iostr, name);
+ raptor_iostream_write_counted_string(iostr, "\" : ",4);
+
+ if(json_bool)
+ raptor_iostream_write_counted_string(iostr, "true", 4);
+ else
+ raptor_iostream_write_counted_string(iostr, "false", 5);
+
+}
+
+
+/*
+ * rasqal_query_results_write_json1:
+ * @iostr: #raptor_iostream to write the query to
+ * @results: #rasqal_query_results query results format
+ * @base_uri: #raptor_uri base URI of the output format
+ *
+ * Write a JSON version of the query results format to an
+ * iostream in a format - INTERNAL.
+ *
+ * If the writing succeeds, the query results will be exhausted.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+rasqal_query_results_write_json1(raptor_iostream *iostr,
+ rasqal_query_results* results,
+ raptor_uri *base_uri)
+{
+ rasqal_query* query = rasqal_query_results_get_query(results);
+ int i;
+ int row_comma;
+ int column_comma=0;
+
+ if(!rasqal_query_results_is_bindings(results) &&
+ !rasqal_query_results_is_boolean(results)) {
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Can only write JSON format for variable binding and boolean results");
+ return 1;
+ }
+
+
+ raptor_iostream_write_counted_string(iostr, "{\n", 2);
+
+ /* Header */
+ raptor_iostream_write_counted_string(iostr, " \"head\": {\n", 12);
+
+ if(rasqal_query_results_is_bindings(results)) {
+ raptor_iostream_write_counted_string(iostr, " \"vars\": [ ", 14);
+ for(i=0; 1; i++) {
+ const unsigned char *name;
+
+ name=rasqal_query_results_get_binding_name(results, i);
+ if(!name)
+ break;
+
+ /* 'x', */
+ if(i > 0)
+ raptor_iostream_write_counted_string(iostr, ", ", 2);
+ raptor_iostream_write_byte(iostr, '\"');
+ raptor_iostream_write_string(iostr, name);
+ raptor_iostream_write_byte(iostr, '\"');
+ }
+ raptor_iostream_write_counted_string(iostr, " ]\n", 3);
+ }
+
+ /* FIXME - could add link inside 'head': */
+
+ /* End Header */
+ raptor_iostream_write_counted_string(iostr, " },\n", 5);
+
+
+ /* Boolean Results */
+ if(rasqal_query_results_is_boolean(results)) {
+ raptor_iostream_write_counted_string(iostr, " ", 2);
+ rasqal_iostream_write_json_boolean(iostr, "boolean",
+ rasqal_query_results_get_boolean(results));
+ goto results3done;
+ }
+
+ /* Variable Binding Results */
+ raptor_iostream_write_counted_string(iostr, " \"results\": {\n", 15);
+
+ raptor_iostream_write_counted_string(iostr, " ", 4);
+ rasqal_iostream_write_json_boolean(iostr, "ordered",
+ (rasqal_query_get_order_condition(query, 0) != NULL));
+ raptor_iostream_write_counted_string(iostr, ",\n", 2);
+
+ raptor_iostream_write_counted_string(iostr, " ", 4);
+ rasqal_iostream_write_json_boolean(iostr, "distinct",
+ rasqal_query_get_distinct(query));
+ raptor_iostream_write_counted_string(iostr, ",\n", 2);
+
+ raptor_iostream_write_counted_string(iostr, " \"bindings\" : [\n", 19);
+
+ row_comma=0;
+ while(!rasqal_query_results_finished(results)) {
+ if(row_comma)
+ raptor_iostream_write_counted_string(iostr, ",\n", 2);
+
+ /* Result row */
+ raptor_iostream_write_counted_string(iostr, " {\n", 8);
+
+ column_comma=0;
+ for(i=0; i<rasqal_query_results_get_bindings_count(results); i++) {
+ const unsigned char *name=rasqal_query_results_get_binding_name(results, i);
+ rasqal_literal *l=rasqal_query_results_get_binding_value(results, i);
+
+ if(column_comma)
+ raptor_iostream_write_counted_string(iostr, ",\n", 2);
+
+ /* <binding> */
+ raptor_iostream_write_counted_string(iostr, " \"", 9);
+ raptor_iostream_write_string(iostr, name);
+ raptor_iostream_write_counted_string(iostr, "\" : { ", 6);
+
+ if(!l) {
+ raptor_iostream_write_string(iostr, "\"type\": \"unbound\", \"value\": null");
+ } else switch(l->type) {
+ const unsigned char* str;
+ size_t len;
+
+ case RASQAL_LITERAL_URI:
+ raptor_iostream_write_string(iostr, "\"type\": \"uri\", \"value\": \"");
+#ifdef RAPTOR_V2_AVAILABLE
+ str = (const unsigned char*)raptor_uri_as_counted_string_v2(l->world->raptor_world_ptr, l->value.uri, &len);
+#else
+ str = (const unsigned char*)raptor_uri_as_counted_string(l->value.uri, &len);
+#endif
+ raptor_iostream_write_string_ntriples(iostr, str, len, '"');
+ raptor_iostream_write_byte(iostr, '"');
+ break;
+
+ case RASQAL_LITERAL_BLANK:
+ raptor_iostream_write_string(iostr, "\"type\": \"bnode\", \"value\": \"");
+ raptor_iostream_write_string_ntriples(iostr, (const unsigned char*)l->string,
+ l->string_len, '"');
+ raptor_iostream_write_byte(iostr, '"');
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ raptor_iostream_write_string(iostr, "\"type\": \"literal\", \"value\": \"");
+ raptor_iostream_write_string_ntriples(iostr, (const unsigned char*)l->string,
+ l->string_len, '"');
+ raptor_iostream_write_byte(iostr, '"');
+
+ if(l->language) {
+ raptor_iostream_write_string(iostr, ",\n \"xml:lang\" : \"");
+ raptor_iostream_write_string(iostr, (const unsigned char*)l->language);
+ raptor_iostream_write_byte(iostr, '"');
+ }
+
+ if(l->datatype) {
+ raptor_iostream_write_string(iostr, ",\n \"datatype\" : \"");
+#ifdef RAPTOR_V2_AVAILABLE
+ str = (const unsigned char*)raptor_uri_as_counted_string_v2(l->world->raptor_world_ptr, l->datatype, &len);
+#else
+ str = (const unsigned char*)raptor_uri_as_counted_string(l->datatype, &len);
+#endif
+ raptor_iostream_write_string_ntriples(iostr, str, len, '"');
+ raptor_iostream_write_byte(iostr, '"');
+ }
+
+ break;
+
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_VARIABLE:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Cannot turn literal type %d into XML",
+ l->type);
+ }
+
+ /* End Binding */
+ raptor_iostream_write_counted_string(iostr, " }", 2);
+ column_comma=1;
+ }
+
+ /* End Result Row */
+ raptor_iostream_write_counted_string(iostr, "\n }", 8);
+ row_comma=1;
+
+ rasqal_query_results_next(results);
+ }
+
+ raptor_iostream_write_counted_string(iostr, "\n ]\n }", 10);
+
+ results3done:
+
+ /* end sparql */
+ raptor_iostream_write_counted_string(iostr, "\n}\n", 3);
+
+ return 0;
+}
+
+
+/**
+ * rasqal_query_results_formatter_get_mime_type:
+ * @formatter: #rasqal_query_results_formatter object
+ *
+ * Get the mime type of the syntax being formatted.
+ *
+ * Return value: a shared mime type string
+ **/
+const char*
+rasqal_query_results_formatter_get_mime_type(rasqal_query_results_formatter *formatter)
+{
+ return formatter->mime_type;
+}
+
+
+/**
+ * rasqal_query_results_formatter_write:
+ * @iostr: #raptor_iostream to write the query to
+ * @formatter: #rasqal_query_results_formatter object
+ * @results: #rasqal_query_results query results format
+ * @base_uri: #raptor_uri base URI of the output format
+ *
+ * Write the query results using the given formatter to an iostream
+ *
+ * See rasqal_query_results_formats_enumerate() to get the
+ * list of syntax URIs and their description.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_results_formatter_write(raptor_iostream *iostr,
+ rasqal_query_results_formatter* formatter,
+ rasqal_query_results* results,
+ raptor_uri *base_uri)
+{
+ if(!formatter->factory->writer)
+ return 1;
+ return formatter->factory->writer(iostr, results, base_uri);
+}
+
+
+/**
+ * rasqal_query_results_formatter_read:
+ * @world: rasqal world object
+ * @iostr: #raptor_iostream to read the query from
+ * @formatter: #rasqal_query_results_formatter object
+ * @results: #rasqal_query_results query results format
+ * @base_uri: #raptor_uri base URI of the input format
+ *
+ * Read the query results using the given formatter from an iostream
+ *
+ * See rasqal_query_results_formats_enumerate() to get the
+ * list of syntax URIs and their description.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+rasqal_query_results_formatter_read(rasqal_world *world,
+ raptor_iostream *iostr,
+ rasqal_query_results_formatter* formatter,
+ rasqal_query_results* results,
+ raptor_uri *base_uri)
+{
+ rasqal_rowsource* rowsource=NULL;
+
+ if(formatter->factory->reader)
+ return formatter->factory->reader(iostr, results, base_uri);
+
+ if(!formatter->factory->get_rowsource)
+ return 1;
+
+ rowsource=formatter->factory->get_rowsource(world,
+ rasqal_query_results_get_variables_table(results),
+ iostr, base_uri);
+ if(!rowsource)
+ return 1;
+
+ while(1) {
+ rasqal_row* row=rasqal_rowsource_read_row(rowsource);
+ if(!row)
+ break;
+ rasqal_query_results_add_row(results, row);
+ }
+
+ if(rowsource)
+ rasqal_free_rowsource(rowsource);
+
+ return 0;
+}
diff --git a/src/rasqal/rasqal_row.c b/src/rasqal/rasqal_row.c
new file mode 100644
index 0000000..24b7ce0
--- /dev/null
+++ b/src/rasqal/rasqal_row.c
@@ -0,0 +1,509 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_row.c - Rasqal Query Result Row
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+
+
+static rasqal_row*
+rasqal_new_row_common(int size, int order_size)
+{
+ rasqal_row* row;
+
+ row = (rasqal_row*)RASQAL_CALLOC(rasqal_row, 1, sizeof(rasqal_row));
+ if(!row)
+ return NULL;
+
+ row->usage = 1;
+ row->size = size;
+ row->order_size = order_size;
+
+ row->values = (rasqal_literal**)RASQAL_CALLOC(array, row->size,
+ sizeof(rasqal_literal*));
+ if(!row->values) {
+ rasqal_free_row(row);
+ return NULL;
+ }
+
+ if(row->order_size > 0) {
+ row->order_values = (rasqal_literal**)RASQAL_CALLOC(array, row->order_size,
+ sizeof(rasqal_literal*));
+ if(!row->order_values) {
+ rasqal_free_row(row);
+ return NULL;
+ }
+ }
+
+ return row;
+}
+
+
+/**
+ * rasqal_new_row:
+ * @rowsource: rowsource
+ *
+ * INTERNAL - Create a new query result row at an offset into the result sequence.
+ *
+ * Return value: a new query result row or NULL on failure
+ */
+rasqal_row*
+rasqal_new_row(rasqal_rowsource* rowsource)
+{
+ int size;
+ int order_size = -1;
+ rasqal_row* row;
+
+ size = rasqal_rowsource_get_size(rowsource);
+
+ row = rasqal_new_row_common(size, order_size);
+ if(row)
+ row->rowsource = rowsource;
+
+ return row;
+}
+
+
+/**
+ * rasqal_new_row_for_size:
+ * @size: width of row
+ *
+ * INTERNAL - Create a new query result row of a given size
+ *
+ * Return value: a new query result row or NULL on failure
+ */
+rasqal_row*
+rasqal_new_row_for_size(int size)
+{
+ int order_size = 0;
+
+ return rasqal_new_row_common(size, order_size);
+}
+
+
+/**
+ * rasqal_new_row_from_row:
+ * @row: query result row
+ *
+ * INTERNAL - Copy a query result row.
+ *
+ * Return value: a copy of the query result row or NULL
+ */
+rasqal_row*
+rasqal_new_row_from_row(rasqal_row* row)
+{
+ row->usage++;
+ return row;
+}
+
+
+/**
+ * rasqal_free_row:
+ * @row: query result row
+ *
+ * INTERNAL - Free a query result row object.
+ */
+void
+rasqal_free_row(rasqal_row* row)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(row, rasqal_row);
+
+ if(--row->usage)
+ return;
+
+ if(row->values) {
+ int i;
+ for(i = 0; i < row->size; i++) {
+ if(row->values[i])
+ rasqal_free_literal(row->values[i]);
+ }
+ RASQAL_FREE(array, row->values);
+ }
+ if(row->order_values) {
+ int i;
+ for(i = 0; i < row->order_size; i++) {
+ if(row->order_values[i])
+ rasqal_free_literal(row->order_values[i]);
+ }
+ RASQAL_FREE(array, row->order_values);
+ }
+
+ RASQAL_FREE(rasqal_row, row);
+}
+
+
+/**
+ * rasqal_row_print:
+ * @row: query result row
+ * @fp: FILE* handle
+ *
+ * INTERNAL - Print a query result row.
+ */
+void
+rasqal_row_print(rasqal_row* row, FILE* fh)
+{
+ rasqal_rowsource* rowsource = row->rowsource;
+ int i;
+
+ fputs("result[", fh);
+ for(i = 0; i < row->size; i++) {
+ /* Do not use rasqal_query_results_get_binding_name(row->results, i);
+ * as it does not work for a construct result
+ */
+ const unsigned char *name = NULL;
+ rasqal_literal *value;
+
+ if(rowsource) {
+ rasqal_variable* v;
+ v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
+ if(v)
+ name = v->name;
+ }
+
+ value = row->values[i];
+ if(i > 0)
+ fputs(", ", fh);
+ if(name)
+ fprintf(fh, "%s=", name);
+
+ if(value)
+ rasqal_literal_print(value, fh);
+ else
+ fputs("NULL", fh);
+ }
+
+ if(row->order_size > 0) {
+ fputs(" with ordering values [", fh);
+
+ for(i = 0; i < row->order_size; i++) {
+ rasqal_literal *value = row->order_values[i];
+
+ if(i > 0)
+ fputs(", ", fh);
+ if(value)
+ rasqal_literal_print(value, fh);
+ else
+ fputs("NULL", fh);
+ }
+ fputs("]", fh);
+
+ }
+
+ fprintf(fh, " offset %d]", row->offset);
+}
+
+
+/**
+ * rasqal_row_set_value_at:
+ * @row: query result row
+ * @offset: offset into row (column number)
+ * @value: literal value to set
+ *
+ * INTERNAL - Set the value of a variable in a query result row
+ */
+void
+rasqal_row_set_value_at(rasqal_row* row, int offset, rasqal_literal* value)
+{
+ row->values[offset] = value;
+}
+
+
+/**
+ * rasqal_new_row_sequence:
+ * @world: world object ot use
+ * @vt: variables table to use to declare variables
+ * @row_data: row data
+ * @vars_count: number of variables in row
+ * @vars_seq_p: OUT parameter - pointer to place to store sequence of variables (or NULL)
+ *
+ * INTERNAL - Make a sequence of #rasqal_row* objects
+ * with variables defined into the @vt table and values in the sequence
+ *
+ * The @row_data parameter is an array of strings forming a table of
+ * width (vars_count * 2).
+ * The first row is a list of variable names at offset 0.
+ * The remaining rows are values where offset 0 is a literal and
+ * offset 1 is a URI string.
+ * The last row is indicated by offset 0 = NULL and offset 1 = NULL
+ *
+ * Return value: sequence of rows or NULL on failure
+ */
+raptor_sequence*
+rasqal_new_row_sequence(rasqal_world* world,
+ rasqal_variables_table* vt,
+ const char* const row_data[],
+ int vars_count,
+ raptor_sequence** vars_seq_p)
+{
+ raptor_sequence *seq = NULL;
+ raptor_sequence *vars_seq = NULL;
+ int row_i;
+ int column_i;
+ int failed = 0;
+
+#define GET_CELL(row, column, offset) \
+ row_data[((((row)*vars_count)+(column))<<1)+(offset)]
+
+ seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_row,
+ (raptor_sequence_print_handler*)rasqal_row_print);
+ if(!seq)
+ return NULL;
+
+ if(vars_seq_p) {
+ vars_seq = raptor_new_sequence(NULL,
+ (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!vars_seq) {
+ raptor_free_sequence(seq);
+ return NULL;
+ }
+ }
+
+ /* row 0 is variables */
+ row_i = 0;
+
+ for(column_i = 0; column_i < vars_count; column_i++) {
+ const char * var_name = GET_CELL(row_i, column_i, 0);
+ size_t var_name_len = strlen(var_name);
+ const unsigned char* name;
+ rasqal_variable* v;
+
+ name = (unsigned char*)RASQAL_MALLOC(cstring, var_name_len+1);
+ if(!name) {
+ failed = 1;
+ goto tidy;
+ }
+
+ strncpy((char*)name, var_name, var_name_len+1);
+ v = rasqal_variables_table_add(vt, RASQAL_VARIABLE_TYPE_NORMAL, name, NULL);
+ if(!v) {
+ failed = 1;
+ goto tidy;
+ }
+
+ if(vars_seq)
+ raptor_sequence_push(vars_seq, v);
+ }
+
+ for(row_i = 1;
+ GET_CELL(row_i, 0, 0) || GET_CELL(row_i, 0, 1);
+ row_i++) {
+ rasqal_row* row;
+
+ row = rasqal_new_row_for_size(vars_count);
+ if(!row) {
+ raptor_free_sequence(seq); seq = NULL;
+ goto tidy;
+ }
+
+ for(column_i = 0; column_i < vars_count; column_i++) {
+ rasqal_literal* l = NULL;
+
+ if(GET_CELL(row_i, column_i, 0)) {
+ /* string literal */
+ const char* str = GET_CELL(row_i, column_i, 0);
+ size_t str_len = strlen(str);
+ unsigned char *val;
+ val = (unsigned char*)RASQAL_MALLOC(cstring, str_len+1);
+ if(val) {
+ strncpy((char*)val, str, str_len+1);
+ l = rasqal_new_string_literal_node(world, val, NULL, NULL);
+ } else
+ failed = 1;
+ } else if(GET_CELL(row_i, column_i, 1)) {
+ /* URI */
+ const unsigned char* str;
+ raptor_uri* u;
+ str = (const unsigned char*)GET_CELL(row_i, column_i, 1);
+#ifdef RAPTOR_V2_AVAILABLE
+ u = raptor_new_uri_v2(world->raptor_world_ptr, str);
+#else
+ u = raptor_new_uri(str);
+#endif
+ if(u)
+ l = rasqal_new_uri_literal(world, u);
+ else
+ failed = 1;
+ } /* else invalid and l=NULL so fails */
+
+ if(!l) {
+ rasqal_free_row(row);
+ failed = 1;
+ goto tidy;
+ }
+ rasqal_row_set_value_at(row, column_i, l);
+ }
+
+ raptor_sequence_push(seq, row);
+ }
+
+ tidy:
+ if(failed) {
+ if(seq) {
+ raptor_free_sequence(seq);
+ seq = NULL;
+ }
+ if(vars_seq) {
+ raptor_free_sequence(vars_seq);
+ vars_seq = NULL;
+ }
+ } else {
+ if(vars_seq) {
+ if(vars_seq_p)
+ *vars_seq_p = vars_seq;
+ else
+ raptor_free_sequence(vars_seq);
+ }
+ }
+
+ return seq;
+}
+
+
+/**
+ * rasqal_row_to_nodes:
+ * @row: Result row
+ *
+ * INTERNAL - Turn the given result row literals into RDF strings, URIs or blank literals.
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_row_to_nodes(rasqal_row* row)
+{
+ int i;
+
+ if(!row)
+ return 1;
+
+ for(i = 0; i < row->size; i++) {
+ if(row->values[i]) {
+ rasqal_literal* new_l;
+ new_l = rasqal_literal_as_node(row->values[i]);
+ if(!new_l)
+ return -1;
+ rasqal_free_literal(row->values[i]);
+ row->values[i] = new_l;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_row_set_values_from_variables_table:
+ * @row: Result row
+ * @vars_table: Variables table
+ *
+ * INTERNAL - Set the values of all variables in the row from the given variables table
+ *
+ */
+void
+rasqal_row_set_values_from_variables_table(rasqal_row* row,
+ rasqal_variables_table* vars_table)
+{
+ int i;
+
+ for(i = 0; i < row->size; i++) {
+ rasqal_literal *l;
+ l = rasqal_variables_table_get_value(vars_table, i);
+ if(row->values[i])
+ rasqal_free_literal(row->values[i]);
+ row->values[i] = rasqal_new_literal_from_literal(l);
+ }
+}
+
+
+/**
+ * rasqal_row_set_order_size:
+ * @row: Result row
+ * @order_size: number of order conditions
+ *
+ * INTERNAL - Initialise the row with space to handle @order_size order conditions being evaluated
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_row_set_order_size(rasqal_row *row, int order_size)
+{
+ row->order_size = order_size;
+ if(row->order_size > 0) {
+ row->order_values = (rasqal_literal**)RASQAL_CALLOC(array, row->order_size,
+ sizeof(rasqal_literal*));
+ if(!row->order_values) {
+ row->order_size = -1;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * rasqal_row_expand_size:
+ * @row: Result row
+ * @size: number of variables
+ *
+ * INTERNAL - Expand the row to be able to handle @size variables
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_row_expand_size(rasqal_row *row, int size)
+{
+ rasqal_literal** nvalues;
+
+ /* do not allow row size to contract & lose data */
+ if(row->size > size)
+ return 1;
+
+ nvalues = (rasqal_literal**)RASQAL_CALLOC(array, size,
+ sizeof(rasqal_literal*));
+ if(!nvalues)
+ return 1;
+ memcpy(nvalues, row->values, sizeof(rasqal_literal*) * row->size);
+ RASQAL_FREE(array, row->values);
+ row->values = nvalues;
+
+ row->size = size;
+ return 0;
+}
+
diff --git a/src/rasqal/rasqal_rowsource.c b/src/rasqal/rasqal_rowsource.c
new file mode 100644
index 0000000..e36716f
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource.c
@@ -0,0 +1,712 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource.c - Rasqal query rowsource (row generator) class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#ifndef STANDALONE
+
+
+/**
+ * rasqal_new_rowsource_from_handler:
+ * @query: query object
+ * @user_data: pointer to context information to pass in to calls
+ * @handler: pointer to handler methods
+ * @vars_table: variables table to use for rows
+ * @flags: 0 (none defined so far)
+ *
+ * Create a new rowsource over a user-defined handler.
+ *
+ * Return value: new #rasqal_rowsource object or NULL on failure
+ **/
+rasqal_rowsource*
+rasqal_new_rowsource_from_handler(rasqal_world* world,
+ rasqal_query* query,
+ void *user_data,
+ const rasqal_rowsource_handler *handler,
+ rasqal_variables_table* vars_table,
+ int flags)
+{
+ rasqal_rowsource* rowsource;
+
+ if(!handler)
+ return NULL;
+
+ if(handler->version < 1 || handler->version > 1)
+ return NULL;
+
+ rowsource = (rasqal_rowsource*)RASQAL_CALLOC(rasqal_rowsource, 1,
+ sizeof(rasqal_rowsource));
+ if(!rowsource) {
+ if(handler->finish)
+ handler->finish(NULL, user_data);
+ return NULL;
+ }
+
+ rowsource->world = world;
+ rowsource->query = query;
+ rowsource->user_data = (void*)user_data;
+ rowsource->handler = handler;
+ rowsource->flags = flags;
+
+ rowsource->size= -1;
+
+ if(vars_table)
+ rowsource->vars_table = rasqal_new_variables_table_from_variables_table(vars_table);
+ else
+ rowsource->vars_table = NULL;
+
+ /* no free method here - the variables are owned by rowsource->vars_table */
+ rowsource->variables_sequence = raptor_new_sequence(NULL, (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!rowsource->variables_sequence) {
+ rasqal_free_rowsource(rowsource);
+ return NULL;
+ }
+
+ if(rowsource->handler->init &&
+ rowsource->handler->init(rowsource, rowsource->user_data)) {
+ RASQAL_DEBUG2("rowsource %s init failed\n", rowsource->handler->name);
+ rasqal_free_rowsource(rowsource);
+ return NULL;
+ }
+ return rowsource;
+}
+
+
+/**
+ * rasqal_free_rowsource:
+ * @rowsource: rowsource object
+ *
+ * Destructor - destroy an rowsource.
+ **/
+void
+rasqal_free_rowsource(rasqal_rowsource *rowsource)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(rowsource, rasqal_rowsource);
+
+ if(rowsource->handler->finish)
+ rowsource->handler->finish(rowsource, rowsource->user_data);
+
+ if(rowsource->vars_table)
+ rasqal_free_variables_table(rowsource->vars_table);
+
+ if(rowsource->variables_sequence)
+ raptor_free_sequence(rowsource->variables_sequence);
+
+ if(rowsource->rows_sequence)
+ raptor_free_sequence(rowsource->rows_sequence);
+
+ RASQAL_FREE(rasqal_rowsource, rowsource);
+}
+
+
+
+/**
+ * rasqal_rowsource_add_variable:
+ * @rowsource: rasqal rowsource
+ * @v: variable
+ *
+ * Add a variable to the rowsource if the variable is not already present
+ *
+ * Return value: variable offset or < 0 on failure
+ **/
+int
+rasqal_rowsource_add_variable(rasqal_rowsource *rowsource, rasqal_variable* v)
+{
+ int offset;
+
+ offset = rasqal_rowsource_get_variable_offset_by_name(rowsource, v->name);
+ if(offset >= 0)
+ return offset;
+
+ if(raptor_sequence_push(rowsource->variables_sequence, v))
+ return -1;
+
+ if(rowsource->size < 0)
+ rowsource->size = 0;
+
+ offset = rowsource->size;
+
+ rowsource->size++;
+
+ return offset;
+}
+
+
+/**
+ * rasqal_rowsource_ensure_variables:
+ * @rowsource: rasqal rowsource
+ *
+ * INTERNAL - Ensure that the variables in the rowsource are defined
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_rowsource_ensure_variables(rasqal_rowsource *rowsource)
+{
+ int rc = 0;
+
+ if(rowsource->updated_variables)
+ return 0;
+
+ rowsource->updated_variables++;
+
+ if(rowsource->handler->ensure_variables)
+ rc = rowsource->handler->ensure_variables(rowsource, rowsource->user_data);
+
+ return rc;
+}
+
+
+/**
+ * rasqal_rowsource_read_row:
+ * @rowsource: rasqal rowsource
+ *
+ * Read a query result row from the rowsource.
+ *
+ * If a row is returned, it is owned by the caller.
+ *
+ * Return value: row or NULL when no more rows are available
+ **/
+rasqal_row*
+rasqal_rowsource_read_row(rasqal_rowsource *rowsource)
+{
+ rasqal_row* row = NULL;
+
+ if(rowsource->finished)
+ return NULL;
+
+ rasqal_rowsource_ensure_variables(rowsource);
+
+ if(rowsource->handler->read_row)
+ row = rowsource->handler->read_row(rowsource, rowsource->user_data);
+ else {
+ if(!rowsource->rows_sequence) {
+ rowsource->rows_sequence = rasqal_rowsource_read_all_rows(rowsource);
+ rowsource->offset = 0;
+ }
+
+ if(rowsource->rows_sequence)
+ /* remove and return row from sequence at offset */
+ row = (rasqal_row*)raptor_sequence_delete_at(rowsource->rows_sequence,
+ rowsource->offset++);
+ }
+
+ if(!row)
+ rowsource->finished = 1;
+ else
+ rowsource->count++;
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("read row : ");
+ if(row)
+ rasqal_row_print(row, stderr);
+ else
+ fputs("NONE", stderr);
+ fputs("\n", stderr);
+#endif
+
+ return row;
+}
+
+
+/**
+ * rasqal_rowsource_get_row_count:
+ * @rowsource: rasqal rowsource
+ *
+ * Get number of rows seen from a rowsource.
+ *
+ * Return value: row count
+ **/
+int
+rasqal_rowsource_get_rows_count(rasqal_rowsource *rowsource)
+{
+ return rowsource->count;
+}
+
+
+/**
+ * rasqal_rowsource_read_all_rows:
+ * @rowsource: rasqal rowsource
+ *
+ * Read all rows from a rowsource
+ *
+ * After calling this, the rowsource will be empty of rows and finished
+ * and if a sequence is returned, it is owned by the caller.
+ *
+ * Return value: new sequence of all rows (may be size 0) or NULL on failure
+ **/
+raptor_sequence*
+rasqal_rowsource_read_all_rows(rasqal_rowsource *rowsource)
+{
+ raptor_sequence* seq;
+
+ rasqal_rowsource_ensure_variables(rowsource);
+
+ if(rowsource->handler->read_all_rows) {
+ seq = rowsource->handler->read_all_rows(rowsource, rowsource->user_data);
+ if(!seq)
+ seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_row,
+ (raptor_sequence_print_handler*)rasqal_row_print);
+ return seq;
+ }
+
+ seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_row,
+ (raptor_sequence_print_handler*)rasqal_row_print);
+ if(!seq)
+ return NULL;
+
+ while(1) {
+ rasqal_row* row = rasqal_rowsource_read_row(rowsource);
+ if(!row)
+ break;
+ raptor_sequence_push(seq, row);
+ }
+
+ return seq;
+}
+
+
+/**
+ * rasqal_rowsource_get_size:
+ * @rowsource: rasqal rowsource
+ *
+ * Get rowsource row width
+ **/
+int
+rasqal_rowsource_get_size(rasqal_rowsource *rowsource)
+{
+ rasqal_rowsource_ensure_variables(rowsource);
+
+ return rowsource->size;
+}
+
+
+/**
+ * rasqal_rowsource_get_variable_by_offset:
+ * @rowsource: rasqal rowsource
+ * @offset: integer offset into array of variables
+ *
+ * Get the variable associated with the given offset
+ *
+ * Return value: pointer to shared #rasqal_variable or NULL if out of range
+ **/
+rasqal_variable*
+rasqal_rowsource_get_variable_by_offset(rasqal_rowsource *rowsource, int offset)
+{
+ rasqal_rowsource_ensure_variables(rowsource);
+
+ if(!rowsource->variables_sequence)
+ return NULL;
+
+ return (rasqal_variable*)raptor_sequence_get_at(rowsource->variables_sequence,
+ offset);
+}
+
+
+/**
+ * rasqal_rowsource_get_variable_offset_by_name:
+ * @rowsource: rasqal rowsource
+ * @name: variable name
+ *
+ * Get the offset of a variable into the list of variables
+ *
+ * Return value: offset or <0 if not present
+ **/
+int
+rasqal_rowsource_get_variable_offset_by_name(rasqal_rowsource *rowsource,
+ const unsigned char* name)
+{
+ int offset= -1;
+ int i;
+
+ rasqal_rowsource_ensure_variables(rowsource);
+
+ if(!rowsource->variables_sequence)
+ return -1;
+
+ for(i=0; i < raptor_sequence_size(rowsource->variables_sequence); i++) {
+ rasqal_variable* v;
+ v = (rasqal_variable*)raptor_sequence_get_at(rowsource->variables_sequence, i);
+ if(!strcmp((const char*)v->name, (const char*)name)) {
+ offset = i;
+ break;
+ }
+ }
+
+ return offset;
+}
+
+
+/**
+ * rasqal_rowsource_copy_variables:
+ * @dest_rowsource: destination rowsource to copy into
+ * @src_rowsource: source rowsource to copy from
+ *
+ * INTERNAL - Copy a variables projection from one rowsource to another
+ *
+ * This adds new variables from @src_rowsource to the
+ * @dest_rowsource, it does not add duplicates.
+ **/
+void
+rasqal_rowsource_copy_variables(rasqal_rowsource *dest_rowsource,
+ rasqal_rowsource *src_rowsource)
+{
+ int i;
+
+ for(i = 0; i < src_rowsource->size; i++) {
+ rasqal_variable* v;
+ v = rasqal_rowsource_get_variable_by_offset(src_rowsource, i);
+ rasqal_rowsource_add_variable(dest_rowsource, v);
+ }
+}
+
+
+static void
+rasqal_rowsource_print_header(rasqal_rowsource* rowsource, FILE* fh)
+{
+ int i;
+
+ fputs("variables: ", fh);
+ for(i = 0; i < rowsource->size; i++) {
+ rasqal_variable* v;
+ const unsigned char *name = NULL;
+
+ v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
+ if(v)
+ name = v->name;
+ if(i > 0)
+ fputs(", ", fh);
+ if(name)
+ fputs((const char*)name, fh);
+ else
+ fputs("NULL", fh);
+ }
+ fputs("\n", fh);
+}
+
+
+/**
+ * rasqal_rowsource_print_row_sequence:
+ * @rowsource: rowsource associated with rows
+ * @seq: query result sequence of #rasqal_row
+ * @fp: FILE* handle to print to
+ *
+ * INTERNAL - Print a result set header with row values from a sequence
+ */
+void
+rasqal_rowsource_print_row_sequence(rasqal_rowsource* rowsource,
+ raptor_sequence* seq,
+ FILE* fh)
+{
+ int size = raptor_sequence_size(seq);
+ int i;
+
+ rasqal_rowsource_print_header(rowsource, fh);
+
+ for(i = 0; i < size; i++) {
+ rasqal_row *row = (rasqal_row*)raptor_sequence_get_at(seq, i);
+ rasqal_row_print(row, fh);
+ fputs("\n", fh);
+ }
+}
+
+
+/**
+ * rasqal_rowsource_reset:
+ * @rowsource: rasqal rowsource
+ *
+ * INTERNAL - Reset a rowsource to regenerate the same set of rows
+ *
+ * Return value: query or NULL
+ **/
+int
+rasqal_rowsource_reset(rasqal_rowsource* rowsource)
+{
+ rowsource->finished = 0;
+ rowsource->count = 0;
+
+ if(rowsource->handler->reset)
+ return rowsource->handler->reset(rowsource, rowsource->user_data);
+
+ return 0;
+}
+
+
+int
+rasqal_rowsource_set_preserve(rasqal_rowsource* rowsource, int preserve)
+{
+ if(rowsource->handler->set_preserve)
+ return rowsource->handler->set_preserve(rowsource,
+ rowsource->user_data, preserve);
+
+ return 0;
+}
+
+
+rasqal_rowsource*
+rasqal_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource, int offset)
+{
+ if(rowsource->handler->get_inner_rowsource)
+ return rowsource->handler->get_inner_rowsource(rowsource,
+ rowsource->user_data,
+ offset);
+ return NULL;
+}
+
+
+#define SPACES_LENGTH 80
+static const char spaces[SPACES_LENGTH+1] = " ";
+
+static void
+rasqal_rowsource_write_indent(raptor_iostream *iostr, int indent)
+{
+ while(indent > 0) {
+ int sp = (indent > SPACES_LENGTH) ? SPACES_LENGTH : indent;
+ raptor_iostream_write_bytes(iostr, spaces, sizeof(char), sp);
+ indent -= sp;
+ }
+}
+
+
+static int
+rasqal_rowsource_write_internal(rasqal_rowsource *rowsource,
+ raptor_iostream* iostr, int indent)
+{
+ const char* rs_name = rowsource->handler->name;
+ int arg_count = 0;
+ int indent_delta;
+ int offset;
+ rasqal_rowsource* inner_rowsource;
+
+ indent_delta = strlen(rs_name);
+
+ raptor_iostream_write_counted_string(iostr, rs_name, indent_delta);
+ raptor_iostream_write_counted_string(iostr, "(\n", 2);
+ indent_delta++;
+
+ indent += indent_delta;
+ rasqal_rowsource_write_indent(iostr, indent);
+
+
+ for(offset = 0;
+ (inner_rowsource = rasqal_rowsource_get_inner_rowsource(rowsource, offset));
+ offset++) {
+ if(arg_count) {
+ raptor_iostream_write_counted_string(iostr, " ,\n", 3);
+ rasqal_rowsource_write_indent(iostr, indent);
+ }
+ rasqal_rowsource_write_internal(inner_rowsource, iostr, indent);
+ arg_count++;
+ }
+
+ raptor_iostream_write_byte(iostr, '\n');
+ indent-= indent_delta;
+
+ rasqal_rowsource_write_indent(iostr, indent);
+ raptor_iostream_write_byte(iostr, ')');
+
+ return 0;
+}
+
+
+int
+rasqal_rowsource_write(rasqal_rowsource *rowsource, raptor_iostream *iostr)
+{
+ return rasqal_rowsource_write_internal(rowsource, iostr, 0);
+}
+
+
+/**
+ * rasqal_rowsource_print:
+ * @rs: the #rasqal_rowsource object
+ * @fh: the #FILE* handle to print to
+ *
+ * Print a #rasqal_rowsource in a debug format.
+ *
+ * The print debug format may change in any release.
+ *
+ **/
+void
+rasqal_rowsource_print(rasqal_rowsource *rowsource, FILE* fh)
+{
+ raptor_iostream *iostr;
+
+ iostr = raptor_new_iostream_to_file_handle(fh);
+ rasqal_rowsource_write(rowsource, iostr);
+ raptor_free_iostream(iostr);
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+#define IN_FILENAME "in.bin"
+#define OUT_BYTES_COUNT 14
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = rasqal_basename(argv[0]);
+#define TEST_ITEMS_COUNT 9
+ int i;
+
+ for(i = 0; i < 4; i++) {
+ rasqal_rowsource *rowsource;
+ size_t count;
+
+ /* for _from_file */
+ FILE *handle = NULL;
+ /* for _from_string */
+ void *string;
+ size_t string_len;
+
+ switch(i) {
+ case 0:
+#ifdef RASQAL_DEBUG
+ fprintf(stderr, "%s: Creating rowsource from afilename '%s'\n",
+ program, OUT_FILENAME);
+#endif
+ rowsource = rasqal_new_rowsource_from_filename((const char*)IN_FILENAME);
+ if(!rowsource) {
+ fprintf(stderr, "%s: Failed to create rowsource to filename '%s'\n",
+ program, OUT_FILENAME);
+ exit(1);
+ }
+ break;
+
+ case 1:
+#ifdef RASQAL_DEBUG
+ fprintf(stderr, "%s: Creating rowsource from file handle\n", program);
+#endif
+ handle = fopen((const char*)OUT_FILENAME, "wb");
+ rowsource = rasqal_new_rowsource_from_file_handle(handle);
+ if(!rowsource) {
+ fprintf(stderr, "%s: Failed to create rowsource from a file handle\n", program);
+ exit(1);
+ }
+ break;
+
+ case 2:
+#ifdef RASQAL_DEBUG
+ fprintf(stderr, "%s: Creating rowsource from a string\n", program);
+#endif
+ rowsource = rasqal_new_rowsource_from_string(&string, &string_len, NULL);
+ if(!rowsource) {
+ fprintf(stderr, "%s: Failed to create rowsource from a string\n", program);
+ exit(1);
+ }
+ break;
+
+ case 3:
+#ifdef RASQAL_DEBUG
+ fprintf(stderr, "%s: Creating rowsource from a sink\n", program);
+#endif
+ rowsource = rasqal_new_rowsource_from_sink();
+ if(!rowsource) {
+ fprintf(stderr, "%s: Failed to create rowsource from a sink\n", program);
+ exit(1);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown test case %d init\n", program, i);
+ exit(1);
+ }
+
+
+ count = rasqal_rowsource_get_rows_count(rowsource);
+ if(count != OUT_BYTES_COUNT) {
+ fprintf(stderr, "%s: I/O stream wrote %d bytes, expected %d\n", program,
+ (int)count, (int)OUT_BYTES_COUNT);
+ return 1;
+ }
+
+#ifdef RASQAL_DEBUG
+ fprintf(stderr, "%s: Freeing rowsource\n", program);
+#endif
+ rasqal_free_rowsource(rowsource);
+
+ switch(i) {
+ case 0:
+ remove(OUT_FILENAME);
+ break;
+
+ case 1:
+ fclose(handle);
+ remove(OUT_FILENAME);
+ break;
+
+ case 2:
+ if(!string) {
+ fprintf(stderr, "%s: I/O stream failed to create a string\n", program);
+ return 1;
+ }
+ if(string_len != count) {
+ fprintf(stderr, "%s: I/O stream created a string length %d, expected %d\n", program, (int)string_len, (int)count);
+ return 1;
+ }
+ rasqal_free_memory(string);
+ break;
+
+ case 3:
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown test case %d tidy\n", program, i);
+ exit(1);
+ }
+
+ }
+
+ /* keep gcc -Wall happy */
+ return(0);
+}
+
+#endif
diff --git a/src/rasqal/rasqal_rowsource_empty.c b/src/rasqal/rasqal_rowsource_empty.c
new file mode 100644
index 0000000..e9c4c14
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource_empty.c
@@ -0,0 +1,194 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource_empty.c - Rasqal empty rowsource class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#ifndef STANDALONE
+
+typedef struct
+{
+ void* undefined;
+} rasqal_empty_rowsource_context;
+
+
+static int
+rasqal_empty_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_empty_rowsource_context* con;
+ con = (rasqal_empty_rowsource_context*)user_data;
+ RASQAL_FREE(rasqal_empty_rowsource_context, con);
+
+ return 0;
+}
+
+static rasqal_row*
+rasqal_empty_rowsource_read_row(rasqal_rowsource* rowsource, void *user_data)
+{
+ /* rasqal_empty_rowsource_context* con;
+ con = (rasqal_empty_rowsource_context*)user_data; */
+ return NULL;
+}
+
+static raptor_sequence*
+rasqal_empty_rowsource_read_all_rows(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ /* rasqal_empty_rowsource_context* con;
+ con = (rasqal_empty_rowsource_context*)user_data; */
+ return NULL;
+}
+
+static const rasqal_rowsource_handler rasqal_empty_rowsource_handler = {
+ /* .version = */ 1,
+ "empty",
+ /* .init = */ NULL,
+ /* .finish = */ rasqal_empty_rowsource_finish,
+ /* .ensure_variables = */ NULL,
+ /* .read_row = */ rasqal_empty_rowsource_read_row,
+ /* .read_all_rows = */ rasqal_empty_rowsource_read_all_rows,
+ /* .reset = */ NULL,
+ /* .set_preserve = */ NULL,
+ /* .get_inner_rowsource = */ NULL
+};
+
+
+rasqal_rowsource*
+rasqal_new_empty_rowsource(rasqal_world *world, rasqal_query* query)
+{
+ rasqal_empty_rowsource_context* con;
+ int flags = 0;
+
+ if(!world || !query)
+ return NULL;
+
+ con = (rasqal_empty_rowsource_context*)RASQAL_CALLOC(rasqal_empty_rowsource_context, 1, sizeof(rasqal_empty_rowsource_context));
+ if(!con)
+ return NULL;
+
+ return rasqal_new_rowsource_from_handler(world, query,
+ con,
+ &rasqal_empty_rowsource_handler,
+ query->vars_table,
+ flags);
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = rasqal_basename(argv[0]);
+ rasqal_rowsource *rowsource = NULL;
+ rasqal_world* world = NULL;
+ rasqal_query* query = NULL;
+ rasqal_row* row = NULL;
+ int count;
+ raptor_sequence* seq = NULL;
+ int failures = 0;
+
+ world = rasqal_new_world();
+ if(!world || rasqal_world_open(world)) {
+ fprintf(stderr, "%s: rasqal_world init failed\n", program);
+ return(1);
+ }
+
+ query = rasqal_new_query(world, "sparql", NULL);
+
+ rowsource = rasqal_new_empty_rowsource(world, query);
+ if(!rowsource) {
+ fprintf(stderr, "%s: failed to create empty rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+
+ row = rasqal_rowsource_read_row(rowsource);
+ if(row) {
+ fprintf(stderr, "%s: read_row returned a row for a empty stream\n",
+ program);
+ failures++;
+ goto tidy;
+ }
+
+ count = rasqal_rowsource_get_rows_count(rowsource);
+ if(count) {
+ fprintf(stderr, "%s: read_rows returned a row count for a empty stream\n",
+ program);
+ failures++;
+ goto tidy;
+ }
+
+ seq = rasqal_rowsource_read_all_rows(rowsource);
+ if(!seq) {
+ fprintf(stderr, "%s: read_rows returned a NULL seq for a empty stream\n",
+ program);
+ failures++;
+ goto tidy;
+ }
+ if(raptor_sequence_size(seq) != 0) {
+ fprintf(stderr, "%s: read_rows returned a non-empty seq for a empty stream\n",
+ program);
+ failures++;
+ goto tidy;
+ }
+
+
+ tidy:
+ if(seq)
+ raptor_free_sequence(seq);
+ if(rowsource)
+ rasqal_free_rowsource(rowsource);
+ if(query)
+ rasqal_free_query(query);
+ if(world)
+ rasqal_free_world(world);
+
+ return failures;
+}
+
+#endif
diff --git a/src/rasqal/rasqal_rowsource_filter.c b/src/rasqal/rasqal_rowsource_filter.c
new file mode 100644
index 0000000..77b7ad6
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource_filter.c
@@ -0,0 +1,241 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource_filter.c - Rasqal filter rowsource class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#define DEBUG_FH stderr
+
+
+typedef struct
+{
+ /* inner rowsource to filter */
+ rasqal_rowsource *rowsource;
+
+ /* FILTER expression */
+ rasqal_expression* expr;
+
+ /* offset into results for current row */
+ int offset;
+
+} rasqal_filter_rowsource_context;
+
+
+static int
+rasqal_filter_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_filter_rowsource_context *con;
+
+ con = (rasqal_filter_rowsource_context*)user_data;
+
+ return 0;
+}
+
+
+static int
+rasqal_filter_rowsource_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_filter_rowsource_context* con;
+
+ con = (rasqal_filter_rowsource_context*)user_data;
+
+ rasqal_rowsource_ensure_variables(con->rowsource);
+
+ rowsource->size = 0;
+ rasqal_rowsource_copy_variables(rowsource, con->rowsource);
+
+ return 0;
+}
+
+
+static int
+rasqal_filter_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_filter_rowsource_context *con;
+ con = (rasqal_filter_rowsource_context*)user_data;
+
+ if(con->rowsource)
+ rasqal_free_rowsource(con->rowsource);
+
+ RASQAL_FREE(rasqal_filter_rowsource_context, con);
+
+ return 0;
+}
+
+
+static rasqal_row*
+rasqal_filter_rowsource_read_row(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_query *query = rowsource->query;
+ rasqal_filter_rowsource_context *con;
+ rasqal_row *row = NULL;
+
+ con = (rasqal_filter_rowsource_context*)user_data;
+
+ while(1) {
+ rasqal_literal* result;
+ int bresult = 1;
+
+ row = rasqal_rowsource_read_row(con->rowsource);
+ if(!row)
+ break;
+
+ result = rasqal_expression_evaluate_v2(rowsource->world, &query->locator,
+ con->expr, query->compare_flags);
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("filter expression result:\n");
+ if(!result)
+ fputs("type error", DEBUG_FH);
+ else
+ rasqal_literal_print(result, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+ if(!result) {
+ bresult = 0;
+ } else {
+ int error = 0;
+ bresult = rasqal_literal_as_boolean(result, &error);
+ if(error)
+ RASQAL_DEBUG1("filter boolean expression returned error\n");
+#ifdef RASQAL_DEBUG
+ else
+ RASQAL_DEBUG2("filter boolean expression result: %d\n", bresult);
+#endif
+ rasqal_free_literal(result);
+ }
+ if(bresult)
+ /* Constraint succeeded so end */
+ break;
+
+ rasqal_free_row(row); row = NULL;
+ }
+
+ if(row) {
+ int i;
+
+ for(i = 0; i < row->size; i++) {
+ rasqal_literal *l;
+ l = rasqal_variables_table_get_value(query->vars_table, i);
+ if(row->values[i])
+ rasqal_free_literal(row->values[i]);
+ row->values[i] = rasqal_new_literal_from_literal(l);
+ }
+
+ row->offset = con->offset++;
+ }
+
+ return row;
+}
+
+
+static int
+rasqal_filter_rowsource_reset(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_filter_rowsource_context *con;
+ con = (rasqal_filter_rowsource_context*)user_data;
+
+ return rasqal_rowsource_reset(con->rowsource);
+}
+
+
+static int
+rasqal_filter_rowsource_set_preserve(rasqal_rowsource* rowsource,
+ void *user_data, int preserve)
+{
+ rasqal_filter_rowsource_context *con;
+ con = (rasqal_filter_rowsource_context*)user_data;
+
+ return rasqal_rowsource_set_preserve(con->rowsource, preserve);
+}
+
+
+static rasqal_rowsource*
+rasqal_filter_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource,
+ void *user_data, int offset)
+{
+ rasqal_filter_rowsource_context *con;
+ con = (rasqal_filter_rowsource_context*)user_data;
+
+ if(offset == 0)
+ return con->rowsource;
+ return NULL;
+}
+
+
+static const rasqal_rowsource_handler rasqal_filter_rowsource_handler = {
+ /* .version = */ 1,
+ "filter",
+ /* .init = */ rasqal_filter_rowsource_init,
+ /* .finish = */ rasqal_filter_rowsource_finish,
+ /* .ensure_variables = */ rasqal_filter_rowsource_ensure_variables,
+ /* .read_row = */ rasqal_filter_rowsource_read_row,
+ /* .read_all_rows = */ NULL,
+ /* .reset = */ rasqal_filter_rowsource_reset,
+ /* .set_preserve = */ rasqal_filter_rowsource_set_preserve,
+ /* .get_inner_rowsource = */ rasqal_filter_rowsource_get_inner_rowsource
+};
+
+
+rasqal_rowsource*
+rasqal_new_filter_rowsource(rasqal_world *world,
+ rasqal_query *query,
+ rasqal_rowsource* rowsource,
+ rasqal_expression* expr)
+{
+ rasqal_filter_rowsource_context *con;
+ int flags = 0;
+
+ if(!world || !query || !rowsource || !expr)
+ return NULL;
+
+ con = (rasqal_filter_rowsource_context*)RASQAL_CALLOC(rasqal_filter_rowsource_context, 1, sizeof(rasqal_filter_rowsource_context));
+ if(!con)
+ return NULL;
+
+ con->rowsource = rowsource;
+ con->expr = expr;
+
+ return rasqal_new_rowsource_from_handler(world, query,
+ con,
+ &rasqal_filter_rowsource_handler,
+ query->vars_table,
+ flags);
+}
diff --git a/src/rasqal/rasqal_rowsource_join.c b/src/rasqal/rasqal_rowsource_join.c
new file mode 100644
index 0000000..7e63399
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource_join.c
@@ -0,0 +1,677 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource_join.c - Rasqal join rowsource class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#define DEBUG_FH stderr
+
+#ifndef STANDALONE
+
+#define INIT_RIGHT (0)
+#define READ_RIGHT (1)
+#define FINISHED (2)
+
+typedef struct
+{
+ rasqal_rowsource* left;
+
+ rasqal_rowsource* right;
+
+ /* current left row */
+ rasqal_row *left_row;
+
+ /* array to map right variables into output rows */
+ int* right_map;
+
+ /* 0 = reading from left rs, 1 = reading from right rs, 2 = finished */
+ int state;
+
+ int failed;
+
+ /* row offset for read_row() */
+ int offset;
+
+ /* join type: 0 = left outer join */
+ int join_type;
+
+ /* join expression */
+ rasqal_expression *expr;
+} rasqal_join_rowsource_context;
+
+
+static int
+rasqal_join_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_join_rowsource_context* con;
+ con = (rasqal_join_rowsource_context*)user_data;
+
+ con->failed = 0;
+
+ con->left_row = rasqal_rowsource_read_row(con->left);
+ if(!con->left_row) {
+ con->state = FINISHED;
+ return 1;
+ }
+
+ con->state = INIT_RIGHT;
+
+ if(con->expr && rasqal_expression_is_constant(con->expr)) {
+ rasqal_query *query = rowsource->query;
+ rasqal_literal* result;
+ int bresult;
+
+ result = rasqal_expression_evaluate_v2(rowsource->world, &query->locator,
+ con->expr, query->compare_flags);
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("join expression condition is constant: ");
+ if(!result)
+ fputs("type error", DEBUG_FH);
+ else
+ rasqal_literal_print(result, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+ if(!result) {
+ bresult = 0;
+ } else {
+ int error = 0;
+ bresult = rasqal_literal_as_boolean(result, &error);
+ if(error)
+ RASQAL_DEBUG1("join boolean expression returned error\n");
+#ifdef RASQAL_DEBUG
+ else
+ RASQAL_DEBUG2("join boolean expression result: %d\n", bresult);
+#endif
+ rasqal_free_literal(result);
+ }
+
+ /* free expression always */
+ rasqal_free_expression(con->expr); con->expr = NULL;
+
+ if(!bresult) {
+ /* Constraint is always false so row source is finished */
+ con->state = 2;
+ }
+ /* otherwise always true so no need to evaluate on each row
+ * and deleting con->expr will handle that
+ */
+
+ }
+
+ rasqal_rowsource_set_preserve(con->left, 1);
+ rasqal_rowsource_set_preserve(con->right, 1);
+
+ return 0;
+}
+
+
+static int
+rasqal_join_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_join_rowsource_context* con;
+ con = (rasqal_join_rowsource_context*)user_data;
+ if(con->left)
+ rasqal_free_rowsource(con->left);
+
+ if(con->right)
+ rasqal_free_rowsource(con->right);
+
+ if(con->right_map)
+ RASQAL_FREE(int, con->right_map);
+
+ if(con->expr)
+ rasqal_free_expression(con->expr);
+
+ RASQAL_FREE(rasqal_join_rowsource_context, con);
+
+ return 0;
+}
+
+
+static int
+rasqal_join_rowsource_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_join_rowsource_context* con;
+ int map_size;
+ int i;
+
+ con = (rasqal_join_rowsource_context*)user_data;
+
+ if(rasqal_rowsource_ensure_variables(con->left))
+ return 1;
+
+ if(rasqal_rowsource_ensure_variables(con->right))
+ return 1;
+
+ map_size = rasqal_rowsource_get_size(con->right);
+ con->right_map = (int*)RASQAL_MALLOC(int, sizeof(int) * map_size);
+ if(!con->right_map)
+ return 1;
+
+ rowsource->size = 0;
+
+ /* copy in variables from left rowsource */
+ rasqal_rowsource_copy_variables(rowsource, con->left);
+
+ /* add any new variables not already seen from right rowsource */
+ for(i = 0; i < map_size; i++) {
+ rasqal_variable* v;
+ int offset;
+
+ v = rasqal_rowsource_get_variable_by_offset(con->right, i);
+ if(!v)
+ break;
+ offset = rasqal_rowsource_add_variable(rowsource, v);
+ if(offset < 0)
+ return 1;
+
+ con->right_map[i] = offset;
+ }
+
+ return 0;
+}
+
+
+static rasqal_row*
+rasqal_join_rowsource_build_merged_row(rasqal_rowsource* rowsource,
+ rasqal_join_rowsource_context* con,
+ rasqal_row *right_row)
+{
+ rasqal_row *row;
+ int i;
+
+ row = rasqal_new_row_for_size(rowsource->size);
+ if(!row)
+ return NULL;
+
+ row->rowsource = rowsource;
+ row->offset = row->offset;
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("merge\n left row : ");
+ rasqal_row_print(con->left_row, stderr);
+ fputs("\n right row : ", stderr);
+ if(right_row)
+ rasqal_row_print(right_row, stderr);
+ else
+ fputs("NONE", stderr);
+ fputs("\n", stderr);
+#endif
+
+ for(i = 0; i < con->left_row->size; i++) {
+ rasqal_literal *l = con->left_row->values[i];
+ row->values[i] = rasqal_new_literal_from_literal(l);
+ }
+
+ if(right_row) {
+ for(i = 0; i < right_row->size; i++) {
+ rasqal_literal *l = right_row->values[i];
+ int dest_i = con->right_map[i];
+ if(!row->values[dest_i])
+ row->values[dest_i] = rasqal_new_literal_from_literal(l);
+ }
+
+ rasqal_free_row(right_row);
+ }
+
+#ifdef RASQAL_DEBUG
+ fputs(" result row : ", stderr);
+ if(row)
+ rasqal_row_print(row, stderr);
+ else
+ fputs("NONE", stderr);
+ fputs("\n", stderr);
+#endif
+
+ return row;
+}
+
+
+static rasqal_row*
+rasqal_join_rowsource_read_row(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_join_rowsource_context* con;
+ rasqal_row* row = NULL;
+ rasqal_query *query = rowsource->query;
+
+ con = (rasqal_join_rowsource_context*)user_data;
+
+ if(con->failed || con->state == FINISHED)
+ return NULL;
+
+ while(1) {
+ rasqal_row *right_row;
+ rasqal_literal *result;
+ int bresult;
+
+ if(con->state == INIT_RIGHT) {
+ if(!con->left_row) {
+ con->state = FINISHED;
+ return NULL;
+ }
+
+ rasqal_rowsource_reset(con->right);
+ right_row = rasqal_rowsource_read_row(con->right);
+ row = rasqal_join_rowsource_build_merged_row(rowsource, con, right_row);
+ if(right_row) {
+ con->state = READ_RIGHT;
+ } else {
+ /* con->state = INIT_RIGHT; */
+ if(row)
+ con->left_row = rasqal_rowsource_read_row(con->left);
+ }
+ if(row)
+ goto have_row;
+ }
+
+ /* else state is READ_RIGHT */
+
+ right_row = rasqal_rowsource_read_row(con->right);
+ if(!right_row) {
+ /* right table done, restart left, continue looping */
+ con->state = INIT_RIGHT;
+ con->left_row = rasqal_rowsource_read_row(con->left);
+ continue;
+ }
+
+ /* con->state = READ_RIGHT; */
+ row = rasqal_join_rowsource_build_merged_row(rowsource, con, right_row);
+
+ have_row:
+ if(!con->expr)
+ break;
+
+ result = rasqal_expression_evaluate_v2(rowsource->world, &query->locator,
+ con->expr, query->compare_flags);
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("join expression result:\n");
+ if(!result)
+ fputs("type error", DEBUG_FH);
+ else
+ rasqal_literal_print(result, DEBUG_FH);
+ fputc('\n', DEBUG_FH);
+#endif
+ if(!result) {
+ bresult = 0;
+ } else {
+ int error = 0;
+ bresult = rasqal_literal_as_boolean(result, &error);
+ if(error)
+ RASQAL_DEBUG1("filter boolean expression returned error\n");
+#ifdef RASQAL_DEBUG
+ else
+ RASQAL_DEBUG2("filter boolean expression result: %d\n", bresult);
+#endif
+ rasqal_free_literal(result);
+ }
+ if(bresult)
+ /* Constraint succeeded so return row */
+ break;
+
+ rasqal_free_row(row); row = NULL;
+ }
+
+ if(row) {
+ row->rowsource = rowsource;
+ row->offset = con->offset++;
+ }
+
+ return row;
+}
+
+
+static int
+rasqal_join_rowsource_reset(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_join_rowsource_context* con;
+ int rc;
+
+ con = (rasqal_join_rowsource_context*)user_data;
+
+ con->state = INIT_RIGHT;
+ con->failed = 0;
+
+ rc = rasqal_rowsource_reset(con->left);
+ if(rc)
+ return rc;
+
+ return rasqal_rowsource_reset(con->right);
+}
+
+
+static int
+rasqal_join_rowsource_set_preserve(rasqal_rowsource* rowsource,
+ void *user_data, int preserve)
+{
+ rasqal_join_rowsource_context *con;
+ int rc;
+
+ con = (rasqal_join_rowsource_context*)user_data;
+
+ rc = rasqal_rowsource_set_preserve(con->left, preserve);
+ if(rc)
+ return rc;
+
+ return rasqal_rowsource_set_preserve(con->right, preserve);
+}
+
+
+static rasqal_rowsource*
+rasqal_join_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource,
+ void *user_data, int offset)
+{
+ rasqal_join_rowsource_context *con;
+ con = (rasqal_join_rowsource_context*)user_data;
+
+ if(offset == 1)
+ return con->left;
+ else if(offset == 2)
+ return con->right;
+ else
+ return NULL;
+}
+
+
+static const rasqal_rowsource_handler rasqal_join_rowsource_handler = {
+ /* .version = */ 1,
+ "join",
+ /* .init = */ rasqal_join_rowsource_init,
+ /* .finish = */ rasqal_join_rowsource_finish,
+ /* .ensure_variables = */ rasqal_join_rowsource_ensure_variables,
+ /* .read_row = */ rasqal_join_rowsource_read_row,
+ /* .read_all_rows = */ NULL,
+ /* .reset = */ rasqal_join_rowsource_reset,
+ /* .set_preserve = */ rasqal_join_rowsource_set_preserve,
+ /* .get_inner_rowsource = */ rasqal_join_rowsource_get_inner_rowsource
+};
+
+
+/**
+ * rasqal_new_join_rowsource:
+ * @world: query world
+ * @query: query results object
+ * @left: left (first) rowsource
+ * @right: right (second) rowsource
+ * @join_type: 0 = left outer join
+ * @expr: join expression to filter result rows
+ *
+ * INTERNAL - create a new JOIN over two rowsources
+ *
+ * This uses the number of variables in @vt to set the rowsource size
+ * (order size is always 0) and then checks that all the rows in the
+ * sequence are the same. If not, construction fails and NULL is
+ * returned.
+ *
+ * Return value: new rowsource or NULL on failure
+ */
+rasqal_rowsource*
+rasqal_new_join_rowsource(rasqal_world *world,
+ rasqal_query* query,
+ rasqal_rowsource* left,
+ rasqal_rowsource* right,
+ int join_type,
+ rasqal_expression *expr)
+{
+ rasqal_join_rowsource_context* con;
+ int flags = 0;
+
+ if(!world || !query || !left || !right)
+ return NULL;
+
+ /* only left outer join now */
+ if(join_type != 0)
+ return NULL;
+
+ con = (rasqal_join_rowsource_context*)RASQAL_CALLOC(rasqal_join_rowsource_context, 1, sizeof(rasqal_join_rowsource_context));
+ if(!con)
+ return NULL;
+
+ con->left = left;
+ con->right = right;
+ con->join_type = join_type;
+ con->expr = expr;
+
+ return rasqal_new_rowsource_from_handler(world, query,
+ con,
+ &rasqal_join_rowsource_handler,
+ query->vars_table,
+ flags);
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+const char* const join_1_data_2x3_rows[] =
+{
+ /* 2 variable names and 3 rows */
+ "a", NULL, "b", NULL,
+ /* row 1 data */
+ "foo", NULL, "bar", NULL,
+ /* row 2 data */
+ "baz", NULL, "fez", NULL,
+ /* row 3 data */
+ "bob", NULL, "sue", NULL,
+ /* end of data */
+ NULL, NULL
+};
+
+
+const char* const join_2_data_3x4_rows[] =
+{
+ /* 3 variable names and 4 rows */
+ "b", NULL, "c", NULL, "d", NULL,
+ /* row 1 data */
+ "red", NULL, "orange", NULL, "yellow", NULL,
+ /* row 2 data */
+ "blue", NULL, "indigo", NULL, "violet", NULL,
+ /* row 3 data */
+ "black", NULL, "silver", NULL, "gold", NULL,
+ /* row 4 data */
+ "green", NULL, "tope", NULL, "bronze", NULL,
+ /* end of data */
+ NULL, NULL
+};
+
+
+#define EXPECTED_ROWS_COUNT (3 * 4)
+
+/* there is one duplicate variable 'b' */
+#define EXPECTED_COLUMNS_COUNT (2 + 3 - 1)
+const char* const join_result_vars[] = { "a" , "b" , "c", "d" };
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = rasqal_basename(argv[0]);
+ rasqal_rowsource *rowsource = NULL;
+ rasqal_rowsource *left_rs = NULL;
+ rasqal_rowsource *right_rs = NULL;
+ rasqal_world* world = NULL;
+ rasqal_query* query = NULL;
+ int count;
+ raptor_sequence* seq = NULL;
+ int failures = 0;
+ int vars_count;
+ rasqal_variables_table* vt;
+ int size;
+ int expected_count = EXPECTED_ROWS_COUNT;
+ int expected_size = EXPECTED_COLUMNS_COUNT;
+ int i;
+ raptor_sequence* vars_seq = NULL;
+
+ world = rasqal_new_world(); rasqal_world_open(world);
+
+ query = rasqal_new_query(world, "sparql", NULL);
+
+ vt = query->vars_table;
+
+ /* 2 variables and 3 rows */
+ vars_count = 2;
+ seq = rasqal_new_row_sequence(world, vt, join_1_data_2x3_rows, vars_count,
+ &vars_seq);
+ if(!seq) {
+ fprintf(stderr,
+ "%s: failed to create left sequence of %d vars\n", program,
+ vars_count);
+ failures++;
+ goto tidy;
+ }
+
+ left_rs = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
+ if(!left_rs) {
+ fprintf(stderr, "%s: failed to create left rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+ /* vars_seq and seq are now owned by left_rs */
+ vars_seq = seq = NULL;
+
+ /* 3 variables and 4 rows */
+ vars_count = 3;
+ seq = rasqal_new_row_sequence(world, vt, join_2_data_3x4_rows, vars_count,
+ &vars_seq);
+ if(!seq) {
+ fprintf(stderr,
+ "%s: failed to create right sequence of %d rows\n", program,
+ vars_count);
+ failures++;
+ goto tidy;
+ }
+
+ right_rs = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
+ if(!right_rs) {
+ fprintf(stderr, "%s: failed to create right rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+ /* vars_seq and seq are now owned by right_rs */
+ vars_seq = seq = NULL;
+
+ rowsource = rasqal_new_join_rowsource(world, query, left_rs, right_rs, 0, NULL);
+ if(!rowsource) {
+ fprintf(stderr, "%s: failed to create join rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+ /* left_rs and right_rs are now owned by rowsource */
+ left_rs = right_rs = NULL;
+
+ seq = rasqal_rowsource_read_all_rows(rowsource);
+ if(!seq) {
+ fprintf(stderr,
+ "%s: read_rows returned a NULL seq for a join rowsource\n",
+ program);
+ failures++;
+ goto tidy;
+ }
+ count = raptor_sequence_size(seq);
+ if(count != expected_count) {
+ fprintf(stderr,
+ "%s: read_rows returned %d rows for a join rowsource, expected %d\n",
+ program, count, expected_count);
+ failures++;
+ goto tidy;
+ }
+
+ size = rasqal_rowsource_get_size(rowsource);
+ if(size != expected_size) {
+ fprintf(stderr,
+ "%s: read_rows returned %d columns (variables) for a join rowsource, expected %d\n",
+ program, size, expected_size);
+ failures++;
+ goto tidy;
+ }
+ for(i = 0; i < expected_size; i++) {
+ rasqal_variable* v;
+ const char* name = NULL;
+ const char *expected_name = join_result_vars[i];
+
+ v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
+ if(!v) {
+ fprintf(stderr,
+ "%s: read_rows had NULL column (variable) #%d expected %s\n",
+ program, i, expected_name);
+ failures++;
+ goto tidy;
+ }
+ name = (const char*)v->name;
+ if(strcmp(name, expected_name)) {
+ fprintf(stderr,
+ "%s: read_rows returned column (variable) #%d %s but expected %s\n",
+ program, i, name, expected_name);
+ failures++;
+ goto tidy;
+ }
+ }
+
+
+#ifdef RASQAL_DEBUG
+ rasqal_rowsource_print_row_sequence(rowsource, seq, DEBUG_FH);
+#endif
+
+ tidy:
+ if(seq)
+ raptor_free_sequence(seq);
+ if(left_rs)
+ rasqal_free_rowsource(left_rs);
+ if(right_rs)
+ rasqal_free_rowsource(right_rs);
+ if(rowsource)
+ rasqal_free_rowsource(rowsource);
+ if(query)
+ rasqal_free_query(query);
+ if(world)
+ rasqal_free_world(world);
+
+ return failures;
+}
+
+#endif
diff --git a/src/rasqal/rasqal_rowsource_project.c b/src/rasqal/rasqal_rowsource_project.c
new file mode 100644
index 0000000..639a767
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource_project.c
@@ -0,0 +1,410 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource_project.c - Rasqal variables projection rowsource class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#define DEBUG_FH stderr
+
+
+#ifndef STANDALONE
+
+typedef struct
+{
+ /* inner rowsource to project */
+ rasqal_rowsource *rowsource;
+
+ /* variable names to project input rows to */
+ raptor_sequence* projection_variables;
+
+ /* variables projection array: [output row var index]=input row var index */
+ int* projection;
+
+} rasqal_project_rowsource_context;
+
+
+static int
+rasqal_project_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_project_rowsource_context *con;
+
+ con = (rasqal_project_rowsource_context*)user_data;
+
+ return 0;
+}
+
+
+static int
+rasqal_project_rowsource_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_project_rowsource_context* con;
+ int size;
+ int i;
+
+ con = (rasqal_project_rowsource_context*)user_data;
+
+ rasqal_rowsource_ensure_variables(con->rowsource);
+
+ rowsource->size = 0;
+
+ size = raptor_sequence_size(con->projection_variables);
+
+ con->projection = (int*)RASQAL_MALLOC(array, sizeof(int*) * size);
+ if(!con->projection)
+ return 1;
+
+ for(i = 0; i <= size; i++) {
+ rasqal_variable* v;
+ int offset;
+
+ v = (rasqal_variable*)raptor_sequence_get_at(con->projection_variables, i);
+ if(!v)
+ break;
+ offset = rasqal_rowsource_get_variable_offset_by_name(con->rowsource,
+ v->name);
+#ifdef RASQAL_DEBUG
+ if(offset < 0)
+ RASQAL_DEBUG2("Variable %s is in projection but not in input rowsource\n",
+ v->name);
+#endif
+
+ rasqal_rowsource_add_variable(rowsource, v);
+ con->projection[i] = offset;
+ }
+
+ return 0;
+}
+
+
+static int
+rasqal_project_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_project_rowsource_context *con;
+ con = (rasqal_project_rowsource_context*)user_data;
+
+ if(con->rowsource)
+ rasqal_free_rowsource(con->rowsource);
+
+ if(con->projection)
+ RASQAL_FREE(int, con->projection);
+
+ RASQAL_FREE(rasqal_project_rowsource_context, con);
+
+ return 0;
+}
+
+
+static rasqal_row*
+rasqal_project_rowsource_read_row(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_project_rowsource_context *con;
+ rasqal_row *row = NULL;
+
+ con = (rasqal_project_rowsource_context*)user_data;
+
+ row = rasqal_rowsource_read_row(con->rowsource);
+ if(row) {
+ rasqal_row* nrow;
+ int i;
+
+ nrow = rasqal_new_row_for_size(rowsource->size);
+ if(!nrow) {
+ rasqal_free_row(row);
+ row = NULL;
+ } else {
+ nrow->rowsource = rowsource;
+ nrow->offset = row->offset;
+
+ for(i = 0; i < rowsource->size; i++) {
+ int offset = con->projection[i];
+ if(offset >= 0)
+ nrow->values[i] = rasqal_new_literal_from_literal(row->values[offset]);
+ }
+ rasqal_free_row(row);
+ row = nrow;
+ }
+ }
+
+ return row;
+}
+
+
+static int
+rasqal_project_rowsource_reset(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_project_rowsource_context *con;
+ con = (rasqal_project_rowsource_context*)user_data;
+
+ return rasqal_rowsource_reset(con->rowsource);
+}
+
+
+static int
+rasqal_project_rowsource_set_preserve(rasqal_rowsource* rowsource,
+ void *user_data, int preserve)
+{
+ rasqal_project_rowsource_context *con;
+ con = (rasqal_project_rowsource_context*)user_data;
+
+ return rasqal_rowsource_set_preserve(con->rowsource, preserve);
+}
+
+
+static rasqal_rowsource*
+rasqal_project_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource,
+ void *user_data, int offset)
+{
+ rasqal_project_rowsource_context *con;
+ con = (rasqal_project_rowsource_context*)user_data;
+
+ if(offset == 0)
+ return con->rowsource;
+ return NULL;
+}
+
+
+static const rasqal_rowsource_handler rasqal_project_rowsource_handler = {
+ /* .version = */ 1,
+ "project",
+ /* .init = */ rasqal_project_rowsource_init,
+ /* .finish = */ rasqal_project_rowsource_finish,
+ /* .ensure_variables = */ rasqal_project_rowsource_ensure_variables,
+ /* .read_row = */ rasqal_project_rowsource_read_row,
+ /* .read_all_rows = */ NULL,
+ /* .reset = */ rasqal_project_rowsource_reset,
+ /* .set_preserve = */ rasqal_project_rowsource_set_preserve,
+ /* .get_inner_rowsource = */ rasqal_project_rowsource_get_inner_rowsource
+};
+
+
+rasqal_rowsource*
+rasqal_new_project_rowsource(rasqal_world *world,
+ rasqal_query *query,
+ rasqal_rowsource* rowsource,
+ raptor_sequence* projection_variables)
+{
+ rasqal_project_rowsource_context *con;
+ int flags = 0;
+
+ if(!world || !query || !rowsource || !projection_variables)
+ return NULL;
+
+ con = (rasqal_project_rowsource_context*)RASQAL_CALLOC(rasqal_project_rowsource_context, 1, sizeof(rasqal_project_rowsource_context));
+ if(!con)
+ return NULL;
+
+ con->rowsource = rowsource;
+ con->projection_variables = projection_variables;
+
+ return rasqal_new_rowsource_from_handler(world, query,
+ con,
+ &rasqal_project_rowsource_handler,
+ query->vars_table,
+ flags);
+}
+
+
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+const char* const project_1_data_4x2_rows[] =
+{
+ /* 4 variable names and 2 rows */
+ "a", NULL, "b", NULL, "c", NULL, "d", NULL,
+ /* row 1 data */
+ "foo", NULL, "bar", NULL, "baz", NULL, "fez", NULL,
+ /* row 2 data */
+ "bob", NULL, "sue", NULL, "kit", NULL, "kat", NULL,
+ /* end of data */
+ NULL, NULL
+};
+
+const char* const project_1_var_names[] = { "c", "b" };
+
+#define EXPECTED_ROWS_COUNT 2
+#define EXPECTED_COLUMNS_COUNT 2
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = rasqal_basename(argv[0]);
+ rasqal_rowsource *rowsource = NULL;
+ rasqal_rowsource *input_rs = NULL;
+ rasqal_world* world = NULL;
+ rasqal_query* query = NULL;
+ int count;
+ raptor_sequence* seq = NULL;
+ int failures = 0;
+ int vars_count;
+ rasqal_variables_table* vt;
+ int size;
+ int expected_count = EXPECTED_ROWS_COUNT;
+ int expected_size = EXPECTED_COLUMNS_COUNT;
+ int i;
+ raptor_sequence* vars_seq = NULL;
+ raptor_sequence* projection_seq = NULL;
+
+ world = rasqal_new_world(); rasqal_world_open(world);
+
+ query = rasqal_new_query(world, "sparql", NULL);
+
+ vt = query->vars_table;
+
+ /* 4 variables and 2 rows */
+ vars_count = 4;
+ seq = rasqal_new_row_sequence(world, vt, project_1_data_4x2_rows, vars_count,
+ &vars_seq);
+ if(!seq) {
+ fprintf(stderr,
+ "%s: failed to create left sequence of %d vars\n", program,
+ vars_count);
+ failures++;
+ goto tidy;
+ }
+
+ input_rs = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
+ if(!input_rs) {
+ fprintf(stderr, "%s: failed to create left rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+ /* vars_seq and seq are now owned by input_rs */
+ vars_seq = seq = NULL;
+
+ projection_seq = raptor_new_sequence(NULL, NULL);
+ for(i = 0 ; i < EXPECTED_COLUMNS_COUNT; i++) {
+ rasqal_variable* v;
+ unsigned const char* name=(unsigned const char*)project_1_var_names[i];
+ v = rasqal_variables_table_get_by_name(vt, name);
+ if(v)
+ raptor_sequence_push(projection_seq, v);
+ }
+
+ rowsource = rasqal_new_project_rowsource(world, query, input_rs, projection_seq);
+ if(!rowsource) {
+ fprintf(stderr, "%s: failed to create project rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+ /* input_rs and right_rs are now owned by rowsource */
+ input_rs = NULL;
+
+ seq = rasqal_rowsource_read_all_rows(rowsource);
+ if(!seq) {
+ fprintf(stderr,
+ "%s: read_rows returned a NULL seq for a project rowsource\n",
+ program);
+ failures++;
+ goto tidy;
+ }
+ count = raptor_sequence_size(seq);
+ if(count != expected_count) {
+ fprintf(stderr,
+ "%s: read_rows returned %d rows for a project rowsource, expected %d\n",
+ program, count, expected_count);
+ failures++;
+ goto tidy;
+ }
+
+ size = rasqal_rowsource_get_size(rowsource);
+ if(size != expected_size) {
+ fprintf(stderr,
+ "%s: read_rows returned %d columns (variables) for a project rowsource, expected %d\n",
+ program, size, expected_size);
+ failures++;
+ goto tidy;
+ }
+ for(i = 0; i < expected_size; i++) {
+ rasqal_variable* v;
+ const char* name = NULL;
+ const char *expected_name = project_1_var_names[i];
+
+ v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
+ if(!v) {
+ fprintf(stderr,
+ "%s: read_rows had NULL column (variable) #%d expected %s\n",
+ program, i, expected_name);
+ failures++;
+ goto tidy;
+ }
+ name = (const char*)v->name;
+ if(strcmp(name, expected_name)) {
+ fprintf(stderr,
+ "%s: read_rows returned column (variable) #%d %s but expected %s\n",
+ program, i, name, expected_name);
+ failures++;
+ goto tidy;
+ }
+ }
+
+#ifdef RASQAL_DEBUG
+ fprintf(DEBUG_FH, "result of projection:\n");
+ rasqal_rowsource_print_row_sequence(rowsource, seq, DEBUG_FH);
+#endif
+
+ tidy:
+ if(seq)
+ raptor_free_sequence(seq);
+ if(projection_seq)
+ raptor_free_sequence(projection_seq);
+ if(input_rs)
+ rasqal_free_rowsource(input_rs);
+ if(rowsource)
+ rasqal_free_rowsource(rowsource);
+ if(query)
+ rasqal_free_query(query);
+ if(world)
+ rasqal_free_world(world);
+
+ return failures;
+}
+
+#endif
diff --git a/src/rasqal/rasqal_rowsource_rowsequence.c b/src/rasqal/rasqal_rowsource_rowsequence.c
new file mode 100644
index 0000000..b738d0c
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource_rowsequence.c
@@ -0,0 +1,464 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource_rowsequence.c - Rasqal rowsequence rowsource class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#ifndef STANDALONE
+
+typedef struct
+{
+ raptor_sequence* seq;
+
+ /* variables for this rowsource */
+ raptor_sequence* vars_seq;
+
+ /* index into seq or <0 when finished */
+ int offset;
+
+ int failed;
+} rasqal_rowsequence_rowsource_context;
+
+
+static int
+rasqal_rowsequence_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_rowsequence_rowsource_context* con;
+ int rows_count;
+ int i;
+
+ con = (rasqal_rowsequence_rowsource_context*)user_data;
+ con->offset = 0;
+
+ con->failed = 0;
+
+ /* adjust offset of every row */
+ rows_count = raptor_sequence_size(con->seq);
+ for(i = 0; i < rows_count; i++) {
+ rasqal_row* row;
+ row = (rasqal_row*)raptor_sequence_get_at(con->seq, i);
+
+ row->rowsource = rowsource;
+ row->offset = i;
+
+ }
+
+ return 0;
+}
+
+
+static int
+rasqal_rowsequence_rowsource_finish(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_rowsequence_rowsource_context* con;
+
+ con = (rasqal_rowsequence_rowsource_context*)user_data;
+ if(con->seq)
+ raptor_free_sequence(con->seq);
+
+ RASQAL_FREE(rasqal_rowsequence_rowsource_context, con);
+
+ return 0;
+}
+
+
+static int
+rasqal_rowsequence_rowsource_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_rowsequence_rowsource_context* con;
+ int i;
+
+ con = (rasqal_rowsequence_rowsource_context*)user_data;
+
+ rowsource->size = 0;
+ for(i = 0; i < raptor_sequence_size(con->vars_seq); i++) {
+ rasqal_variable* v;
+ v = (rasqal_variable*)raptor_sequence_get_at(con->vars_seq, i);
+ rasqal_rowsource_add_variable(rowsource, v);
+ }
+
+ raptor_free_sequence(con->vars_seq);
+ con->vars_seq = NULL;
+
+ return 0;
+}
+
+
+static rasqal_row*
+rasqal_rowsequence_rowsource_read_row(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_rowsequence_rowsource_context* con;
+ rasqal_row* row = NULL;
+
+ con = (rasqal_rowsequence_rowsource_context*)user_data;
+ if(con->failed || con->offset < 0)
+ return NULL;
+
+ row = (rasqal_row*)raptor_sequence_get_at(con->seq, con->offset);
+ if(!row) {
+ /* finished */
+ con->offset = -1;
+ } else {
+ row = rasqal_new_row_from_row(row);
+ con->offset++;
+ }
+
+ return row;
+}
+
+
+static raptor_sequence*
+rasqal_rowsequence_rowsource_read_all_rows(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_rowsequence_rowsource_context* con;
+ raptor_sequence* seq;
+
+ con = (rasqal_rowsequence_rowsource_context*)user_data;
+ if(con->offset < 0)
+ return NULL;
+
+ seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_row,
+ (raptor_sequence_print_handler*)rasqal_row_print);
+ if(seq) {
+ int i;
+ int size = raptor_sequence_size(con->seq);
+ for(i = 0; i < size; i++) {
+ rasqal_row *row = (rasqal_row*)raptor_sequence_get_at(con->seq, i);
+ raptor_sequence_push(seq, rasqal_new_row_from_row(row));
+ }
+ }
+
+ return seq;
+}
+
+
+static int
+rasqal_rowsequence_rowsource_reset(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_rowsequence_rowsource_context* con;
+
+ con = (rasqal_rowsequence_rowsource_context*)user_data;
+
+ con->offset = 0;
+
+ return 0;
+}
+
+
+static const rasqal_rowsource_handler rasqal_rowsequence_rowsource_handler = {
+ /* .version = */ 1,
+ "rowsequence",
+ /* .init = */ rasqal_rowsequence_rowsource_init,
+ /* .finish = */ rasqal_rowsequence_rowsource_finish,
+ /* .ensure_variables = */ rasqal_rowsequence_rowsource_ensure_variables,
+ /* .read_row = */ rasqal_rowsequence_rowsource_read_row,
+ /* .read_all_rows = */ rasqal_rowsequence_rowsource_read_all_rows,
+ /* .reset = */ rasqal_rowsequence_rowsource_reset,
+ /* .set_preserve = */ NULL,
+ /* .get_inner_rowsource = */ NULL
+};
+
+
+/**
+ * rasqal_new_rowsequence_rowsource:
+ * @world: world object
+ * @query: query object
+ * @vt: variables table
+ * @seq: sequence of rasqal_row*
+ * @vars_seq: sequence of variables for this row
+ *
+ * INTERNAL - create a new rowsource over a sequence of rows
+ *
+ * This uses the number of variables in @vt to set the rowsource size
+ * (order size is always 0) and then checks that all the rows in the
+ * sequence are the same. If not, construction fails and NULL is
+ * returned.
+ *
+ * Return value: new rowsource or NULL on failure
+ */
+rasqal_rowsource*
+rasqal_new_rowsequence_rowsource(rasqal_world *world,
+ rasqal_query* query,
+ rasqal_variables_table* vt,
+ raptor_sequence* seq,
+ raptor_sequence* vars_seq)
+{
+ rasqal_rowsequence_rowsource_context* con;
+ int flags = 0;
+
+ if(!world || !query || !vt || !seq || !vars_seq)
+ return NULL;
+
+ if(!raptor_sequence_size(seq) || !raptor_sequence_size(vars_seq))
+ return NULL;
+
+ con = (rasqal_rowsequence_rowsource_context*)RASQAL_CALLOC(rasqal_rowsequence_rowsource_context, 1, sizeof(rasqal_rowsequence_rowsource_context));
+ if(!con)
+ return NULL;
+
+ con->seq = seq;
+ con->vars_seq = vars_seq;
+
+ return rasqal_new_rowsource_from_handler(world, query,
+ con,
+ &rasqal_rowsequence_rowsource_handler,
+ vt,
+ flags);
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+
+const char* const test_1_rows[] =
+{
+ /* 2 variable names */
+ "a", NULL, "b", NULL,
+ /* row 1 data */
+ "foo", NULL, "bar", NULL,
+ /* end of data */
+ NULL, NULL
+};
+
+
+const char* const test_3_rows[] =
+{
+ /* 4 variable names */
+ "c1", NULL, "c2", NULL, "c3", NULL, "c4", NULL,
+ /* row 1 data */
+ "red", NULL, "orange", NULL, "yellow", NULL, "green", NULL,
+ /* row 2 data */
+ "blue", NULL, "indigo", NULL, "violet", NULL, "white", NULL,
+ /* row 3 data */
+ "black", NULL, "silver", NULL, "gold", NULL, "platinum", NULL,
+ /* end of data */
+ NULL, NULL
+};
+
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = rasqal_basename(argv[0]);
+ rasqal_rowsource *rowsource = NULL;
+ raptor_sequence *seq = NULL;
+ rasqal_world* world = NULL;
+ rasqal_query* query = NULL;
+ rasqal_row* row = NULL;
+ int count;
+ int failures = 0;
+ rasqal_variables_table* vt;
+ int rows_count;
+ int i;
+ raptor_sequence* vars_seq = NULL;
+
+ world = rasqal_new_world();
+ if(!world || rasqal_world_open(world)) {
+ fprintf(stderr, "%s: rasqal_world init failed\n", program);
+ return(1);
+ }
+
+ query = rasqal_new_query(world, "sparql", NULL);
+
+ /* test 1-row rowsource (2 variables) */
+ rows_count = 1;
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG2("Testing %d-row rowsource\n", rows_count);
+#endif
+
+ vt = rasqal_new_variables_table(world);
+
+ /* add 2 variables to table and 1 row sequence */
+ seq = rasqal_new_row_sequence(world, vt, test_1_rows, 2, &vars_seq);
+ if(!seq) {
+ fprintf(stderr, "%s: failed to create sequence of %d rows\n", program,
+ rows_count);
+ failures++;
+ goto tidy;
+ }
+
+ rowsource = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
+ if(!rowsource) {
+ fprintf(stderr, "%s: failed to create %d-row sequence rowsource\n",
+ program, rows_count);
+ failures++;
+ goto tidy;
+ }
+ /* vars_seq and seq are now owned by rowsource */
+ vars_seq = seq = NULL;
+
+ row = rasqal_rowsource_read_row(rowsource);
+ if(!row) {
+ fprintf(stderr,
+ "%s: read_row returned no row for a %d-row sequence rowsource\n",
+ program, rows_count);
+ failures++;
+ goto tidy;
+ }
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("Result Row:\n ");
+ rasqal_row_print(row, stderr);
+ fputc('\n', stderr);
+#endif
+
+ rasqal_free_row(row); row = NULL;
+
+ count = rasqal_rowsource_get_rows_count(rowsource);
+ if(count != rows_count) {
+ fprintf(stderr,
+ "%s: read_rows returned count %d instead of %d for a %d-row sequence rowsource\n",
+ program, count, rows_count, rows_count);
+ failures++;
+ goto tidy;
+ }
+
+ row = rasqal_rowsource_read_row(rowsource);
+ if(row) {
+ fprintf(stderr,
+ "%s: read_row returned > %d rows for a %d-row sequence rowsource\n",
+ program, rows_count, rows_count);
+ failures++;
+ goto tidy;
+ }
+
+
+ rasqal_free_rowsource(rowsource); rowsource = NULL;
+ rasqal_free_variables_table(vt); vt = NULL;
+
+ /* test 3-row rowsource */
+ rows_count = 3;
+
+#ifdef RASQAL_DEBUG
+ RASQAL_DEBUG2("Testing %d-row rowsource\n", rows_count);
+#endif
+
+ vt = rasqal_new_variables_table(world);
+
+ /* add 4 variables to table and 3 row sequence */
+ seq = rasqal_new_row_sequence(world, vt, test_3_rows, 4, &vars_seq);
+ if(!seq) {
+ fprintf(stderr, "%s: failed to create sequence of %d rows\n",
+ program, rows_count);
+ failures++;
+ goto tidy;
+ }
+
+ rowsource = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
+ if(!rowsource) {
+ fprintf(stderr, "%s: failed to create %d-row sequence rowsource\n",
+ program, rows_count);
+ failures++;
+ goto tidy;
+ }
+ /* vars_seq and seq are now owned by rowsource */
+ vars_seq = seq = NULL;
+
+ for(i = 0; i < rows_count; i++) {
+ row = rasqal_rowsource_read_row(rowsource);
+ if(!row) {
+ fprintf(stderr,
+ "%s: read_row returned no row for row %d in a %d-row sequence rowsource\n",
+ program, i, rows_count);
+ failures++;
+ goto tidy;
+ }
+
+ #ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("Result Row:\n ");
+ rasqal_row_print(row, stderr);
+ fputc('\n', stderr);
+ #endif
+
+ rasqal_free_row(row); row = NULL;
+ }
+
+ count = rasqal_rowsource_get_rows_count(rowsource);
+ if(count != rows_count) {
+ fprintf(stderr,
+ "%s: read_rows returned count %d instead of %d for a %d-row sequence rowsource\n",
+ program, count, rows_count, rows_count);
+ failures++;
+ goto tidy;
+ }
+
+ row = rasqal_rowsource_read_row(rowsource);
+ if(row) {
+ fprintf(stderr,
+ "%s: read_row returned >%d rows for a %d-row sequence rowsource\n",
+ program, rows_count, rows_count);
+ failures++;
+ goto tidy;
+ }
+
+ rasqal_free_rowsource(rowsource); rowsource = NULL;
+ rasqal_free_variables_table(vt); vt = NULL;
+
+
+ tidy:
+ if(row)
+ rasqal_free_row(row);
+ if(seq)
+ raptor_free_sequence(seq);
+ if(rowsource)
+ rasqal_free_rowsource(rowsource);
+ if(vt)
+ rasqal_free_variables_table(vt);
+ if(query)
+ rasqal_free_query(query);
+ if(world)
+ rasqal_free_world(world);
+
+ return failures;
+}
+
+#endif
diff --git a/src/rasqal/rasqal_rowsource_sort.c b/src/rasqal/rasqal_rowsource_sort.c
new file mode 100644
index 0000000..9a9e4cd
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource_sort.c
@@ -0,0 +1,260 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource_source.c - Rasqal source rowsource class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#define DEBUG_FH stderr
+
+
+typedef struct
+{
+ /* inner rowsource to sort */
+ rasqal_rowsource *rowsource;
+
+ /* map for sorting */
+ rasqal_map* map;
+
+ /* sequence of order conditions #rasqal_expression */
+ raptor_sequence* seq;
+
+ /* number of order conditions in query->order_conditions_sequence */
+ int order_size;
+} rasqal_sort_rowsource_context;
+
+
+static int
+rasqal_sort_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_query *query = rowsource->query;
+ rasqal_sort_rowsource_context *con;
+
+ con = (rasqal_sort_rowsource_context*)user_data;
+
+ if(query->order_conditions_sequence)
+ con->order_size = raptor_sequence_size(query->order_conditions_sequence);
+ else {
+ RASQAL_DEBUG1("No order conditions for sort rowsource - passing through");
+ con->order_size = -1;
+ }
+
+ con->map = NULL;
+
+ if(con->order_size > 0 ) {
+ /* make a row:NULL map in order to sort or do distinct */
+ con->map = rasqal_engine_new_rowsort_map(query->distinct,
+ query->compare_flags,
+ query->order_conditions_sequence);
+ if(!con->map)
+ return 1;
+ }
+
+ con->seq = NULL;
+
+ return 0;
+}
+
+
+static int
+rasqal_sort_rowsource_process(rasqal_rowsource* rowsource,
+ rasqal_sort_rowsource_context* con)
+{
+ int offset = 0;
+
+ /* already processed */
+ if(con->seq)
+ return 0;
+
+ con->seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_row,
+ (raptor_sequence_print_handler*)rasqal_row_print);
+ if(!con->seq)
+ return 1;
+
+ while(1) {
+ rasqal_row* row;
+
+ row = rasqal_rowsource_read_row(con->rowsource);
+ if(!row)
+ break;
+
+ rasqal_row_set_order_size(row, con->order_size);
+
+ rasqal_engine_rowsort_calculate_order_values(rowsource->query, row);
+
+ row->offset = offset;
+
+ /* after this, row is owned by map */
+ if(!rasqal_engine_rowsort_map_add_row(con->map, row))
+ offset++;
+ }
+
+#ifdef RASQAL_DEBUG
+ if(con->map) {
+ fputs("resulting ", DEBUG_FH);
+ rasqal_map_print(con->map, DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+ }
+#endif
+
+ /* do sort/distinct: walk map in order, adding rows to sequence */
+ rasqal_engine_rowsort_map_to_sequence(con->map, con->seq);
+ rasqal_free_map(con->map); con->map = NULL;
+
+ return 0;
+}
+
+
+static int
+rasqal_sort_rowsource_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_sort_rowsource_context* con;
+ con = (rasqal_sort_rowsource_context*)user_data;
+
+ rasqal_rowsource_ensure_variables(con->rowsource);
+
+ rowsource->size = 0;
+ rasqal_rowsource_copy_variables(rowsource, con->rowsource);
+
+ return 0;
+}
+
+
+static int
+rasqal_sort_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_sort_rowsource_context *con;
+ con = (rasqal_sort_rowsource_context*)user_data;
+
+ if(con->rowsource)
+ rasqal_free_rowsource(con->rowsource);
+
+ if(con->map)
+ rasqal_free_map(con->map);
+
+ if(con->seq)
+ raptor_free_sequence(con->seq);
+
+ RASQAL_FREE(rasqal_sort_rowsource_context, con);
+
+ return 0;
+}
+
+
+static raptor_sequence*
+rasqal_sort_rowsource_read_all_rows(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_sort_rowsource_context *con;
+ raptor_sequence *seq = NULL;
+
+ con = (rasqal_sort_rowsource_context*)user_data;
+
+ /* if there were no ordering conditions, pass it all on to inner rowsource */
+ if(con->order_size <= 0)
+ return rasqal_rowsource_read_all_rows(con->rowsource);
+
+
+ /* need to sort */
+ if(rasqal_sort_rowsource_process(rowsource, con))
+ return NULL;
+
+ if(con->seq) {
+ /* pass ownership of seq back to caller */
+ seq = con->seq;
+ con->seq = NULL;
+ }
+
+ return seq;
+}
+
+
+static rasqal_rowsource*
+rasqal_sort_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource,
+ void *user_data, int offset)
+{
+ rasqal_sort_rowsource_context *con;
+ con = (rasqal_sort_rowsource_context*)user_data;
+
+ if(offset == 0)
+ return con->rowsource;
+ return NULL;
+}
+
+
+static const rasqal_rowsource_handler rasqal_sort_rowsource_handler = {
+ /* .version = */ 1,
+ "sort",
+ /* .init = */ rasqal_sort_rowsource_init,
+ /* .finish = */ rasqal_sort_rowsource_finish,
+ /* .ensure_variables = */ rasqal_sort_rowsource_ensure_variables,
+ /* .read_row = */ NULL,
+ /* .read_all_rows = */ rasqal_sort_rowsource_read_all_rows,
+ /* .reset = */ NULL,
+ /* .set_preserve = */ NULL,
+ /* .get_inner_rowsource = */ rasqal_sort_rowsource_get_inner_rowsource
+};
+
+
+rasqal_rowsource*
+rasqal_new_sort_rowsource(rasqal_world *world,
+ rasqal_query *query,
+ rasqal_rowsource *rowsource,
+ raptor_sequence *seq)
+{
+ rasqal_sort_rowsource_context *con;
+ int flags = 0;
+
+ if(!world || !query || !rowsource || !seq)
+ return NULL;
+
+ con = (rasqal_sort_rowsource_context*)RASQAL_CALLOC(rasqal_sort_rowsource_context, 1, sizeof(rasqal_sort_rowsource_context));
+ if(!con)
+ return NULL;
+
+ con->rowsource = rowsource;
+ con->seq = seq;
+
+ return rasqal_new_rowsource_from_handler(world, query,
+ con,
+ &rasqal_sort_rowsource_handler,
+ query->vars_table,
+ flags);
+}
diff --git a/src/rasqal/rasqal_rowsource_triples.c b/src/rasqal/rasqal_rowsource_triples.c
new file mode 100644
index 0000000..ac24692
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource_triples.c
@@ -0,0 +1,720 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource_triples.c - Rasqal triple pattern rowsource class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#ifndef STANDALONE
+
+typedef struct
+{
+ /* source of triple pattern matches */
+ rasqal_triples_source* triples_source;
+
+ /* sequence of triple SHARED with query */
+ raptor_sequence* triples;
+
+ /* current column being iterated */
+ int column;
+
+ /* first triple pattern in sequence to use */
+ int start_column;
+
+ /* last triple pattern in sequence to use */
+ int end_column;
+
+ /* number of triple patterns in the sequence
+ ( = end_column - start_column + 1) */
+ int triples_count;
+
+ /* An array of items, one per triple pattern in the sequence */
+ rasqal_triple_meta* triple_meta;
+
+ /* offset into results for current row */
+ int offset;
+
+ /* number of variables used in variables table */
+ int size;
+
+ /* declared in array index[index into vars table] = column */
+ int *declared_in;
+
+ /* preserve bindings when all rows are finished - for optional mostly */
+ int preserve_on_all_finished;
+} rasqal_triples_rowsource_context;
+
+
+static int
+rasqal_triples_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_triples_rowsource_context *con;
+ int column;
+ int *declared_in = NULL;
+ int rc = 0;
+ int size;
+ int i;
+
+ con = (rasqal_triples_rowsource_context*)user_data;
+
+ size = rasqal_variables_table_get_named_variables_count(rowsource->vars_table);
+ declared_in = con->declared_in;
+
+ /* Construct the ordered projection of the variables set by these triples */
+ con->size = 0;
+ for(i = 0; i < size; i++) {
+ column = declared_in[i];
+ if(column >= con->start_column && column <= con->end_column) {
+ rasqal_variable *v;
+ v = rasqal_variables_table_get(rowsource->vars_table, i);
+ raptor_sequence_push(rowsource->variables_sequence, v);
+ con->size++;
+ }
+ }
+
+ con->column = con->start_column;
+
+ for(column = con->start_column; column <= con->end_column; column++) {
+ rasqal_triple_meta *m;
+ rasqal_triple *t;
+ rasqal_variable* v;
+
+ m = &con->triple_meta[column - con->start_column];
+ if(!m) {
+ rc = 1;
+ break;
+ }
+
+ m->parts = (rasqal_triple_parts)0;
+
+ t = (rasqal_triple*)raptor_sequence_get_at(con->triples, column);
+
+ if((v = rasqal_literal_as_variable(t->subject)) &&
+ declared_in[v->offset] == column)
+ m->parts = (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_SUBJECT);
+
+ if((v = rasqal_literal_as_variable(t->predicate)) &&
+ declared_in[v->offset] == column)
+ m->parts = (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_PREDICATE);
+
+ if((v = rasqal_literal_as_variable(t->object)) &&
+ declared_in[v->offset] == column)
+ m->parts = (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_OBJECT);
+
+ if(t->origin &&
+ (v = rasqal_literal_as_variable(t->origin)) &&
+ declared_in[v->offset] == column)
+ m->parts = (rasqal_triple_parts)(m->parts | RASQAL_TRIPLE_ORIGIN);
+
+ RASQAL_DEBUG3("triple pattern column %d has parts %d\n", column, m->parts);
+
+ /* exact if there are no variables in the triple parts */
+ m->is_exact = 1;
+ if(rasqal_literal_as_variable(t->predicate) ||
+ rasqal_literal_as_variable(t->subject) ||
+ rasqal_literal_as_variable(t->object))
+ m->is_exact = 0;
+
+ }
+
+ return rc;
+}
+
+
+static int
+rasqal_triples_rowsource_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_triples_rowsource_context* con;
+ con = (rasqal_triples_rowsource_context*)user_data;
+
+ rowsource->size = con->size;
+
+ return 0;
+}
+
+
+static int
+rasqal_triples_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_triples_rowsource_context *con;
+ int i;
+
+ con = (rasqal_triples_rowsource_context*)user_data;
+
+ for(i = con->start_column; i <= con->end_column; i++) {
+ rasqal_triple_meta *m;
+ m = &con->triple_meta[i - con->start_column];
+ rasqal_reset_triple_meta(m);
+ }
+
+ if(con->triple_meta)
+ RASQAL_FREE(rasqal_triple_meta, con->triple_meta);
+
+ RASQAL_FREE(rasqal_triples_rowsource_context, con);
+
+ return 0;
+}
+
+
+static rasqal_engine_error
+rasqal_triples_rowsource_get_next_row(rasqal_rowsource* rowsource,
+ rasqal_triples_rowsource_context *con)
+{
+ rasqal_query *query = rowsource->query;
+ rasqal_engine_error error = RASQAL_ENGINE_OK;
+
+ while(con->column >= con->start_column) {
+ rasqal_triple_meta *m;
+ rasqal_triple *t;
+
+ m = &con->triple_meta[con->column - con->start_column];
+ t = (rasqal_triple*)raptor_sequence_get_at(con->triples, con->column);
+
+ error = RASQAL_ENGINE_OK;
+
+ if(!m) {
+ /* error recovery - no match */
+ con->column--;
+ error = RASQAL_ENGINE_FAILED;
+ goto done;
+ }
+
+ if(m->executed) {
+ RASQAL_DEBUG2("triples match already executed in column %d\n",
+ con->column);
+ con->column--;
+ continue;
+ }
+
+ if(m->is_exact) {
+ /* exact triple match wanted */
+
+ if(!rasqal_triples_source_triple_present(con->triples_source, t)) {
+ /* failed */
+ RASQAL_DEBUG2("exact match failed for column %d\n", con->column);
+ con->column--;
+ }
+#ifdef RASQAL_DEBUG
+ else
+ RASQAL_DEBUG2("exact match OK for column %d\n", con->column);
+#endif
+
+ RASQAL_DEBUG2("end of exact triples match for column %d\n", con->column);
+ m->executed = 1;
+
+ } else {
+ /* triple pattern match wanted */
+ int parts;
+
+ if(!m->triples_match) {
+ /* Column has no triples match so create a new query */
+ m->triples_match = rasqal_new_triples_match(query,
+ con->triples_source,
+ m, t);
+ if(!m->triples_match) {
+ rasqal_log_error_simple(rowsource->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Failed to make a triple match for column%d",
+ con->column);
+ /* failed to match */
+ con->column--;
+ error = RASQAL_ENGINE_FAILED;
+ goto done;
+ }
+ RASQAL_DEBUG2("made new triples match for column %d\n", con->column);
+ }
+
+
+ if(rasqal_triples_match_is_end(m->triples_match)) {
+ RASQAL_DEBUG2("end of pattern triples match for column %d\n",
+ con->column);
+ m->executed = 1;
+
+ if(con->preserve_on_all_finished &&
+ con->column == con->end_column) {
+ int is_finished = 1;
+ int i;
+
+ RASQAL_DEBUG1("CHECKING ALL TRIPLE PATTERNS FINISHED\n");
+
+ for(i = con->start_column; i < con->end_column; i++) {
+ rasqal_triple_meta *m2;
+ m2 = &con->triple_meta[con->column - con->start_column];
+ if(!rasqal_triples_match_is_end(m2->triples_match)) {
+ is_finished = 0;
+ break;
+ }
+ }
+ if(is_finished) {
+ RASQAL_DEBUG1("end of all pattern triples matches\n");
+ con->column--;
+ error = RASQAL_ENGINE_FINISHED;
+ goto done;
+ }
+ }
+
+ rasqal_reset_triple_meta(m);
+
+ con->column--;
+ continue;
+ }
+
+ if(m->parts) {
+ parts = rasqal_triples_match_bind_match(m->triples_match, m->bindings,
+ m->parts);
+ RASQAL_DEBUG3("bind_match for column %d returned parts %d\n",
+ con->column, parts);
+ if(!parts)
+ error = RASQAL_ENGINE_FINISHED;
+ } else {
+ RASQAL_DEBUG2("Nothing to bind_match for column %d\n", con->column);
+ }
+
+ rasqal_triples_match_next_match(m->triples_match);
+ if(error == RASQAL_ENGINE_FINISHED)
+ continue;
+
+ }
+
+ if(con->column == con->end_column) {
+ /* Done all conjunctions */
+
+ /* exact match, so column must have ended */
+ if(m->is_exact)
+ con->column--;
+
+ /* return with result */
+ error = RASQAL_ENGINE_OK;
+ goto done;
+ } else if(con->column >= con->start_column)
+ con->column++;
+
+ }
+
+ if(con->column < con->start_column)
+ error = RASQAL_ENGINE_FINISHED;
+
+ done:
+ return error;
+}
+
+
+static rasqal_row*
+rasqal_triples_rowsource_read_row(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_triples_rowsource_context *con;
+ int i;
+ rasqal_row* row = NULL;
+ rasqal_engine_error error = RASQAL_ENGINE_OK;
+
+ con = (rasqal_triples_rowsource_context*)user_data;
+
+ error = rasqal_triples_rowsource_get_next_row(rowsource, con);
+ RASQAL_DEBUG2("rasqal_triples_rowsource_get_next_row() returned %d\n", error);
+
+ if(error != RASQAL_ENGINE_OK)
+ goto done;
+
+#ifdef RASQAL_DEBUG
+ if(1) {
+ int values_returned = 0;
+ /* Count actual bound values */
+ for(i = 0; i < con->size; i++) {
+ rasqal_variable* v;
+ v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
+ if(v->value)
+ values_returned++;
+ }
+ RASQAL_DEBUG2("Solution binds %d values\n", values_returned);
+ }
+#endif
+
+ row = rasqal_new_row(rowsource);
+ if(!row) {
+ error = RASQAL_ENGINE_FAILED;
+ goto done;
+ }
+
+ for(i = 0; i < row->size; i++) {
+ rasqal_variable* v;
+ v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
+ if(row->values[i])
+ rasqal_free_literal(row->values[i]);
+ row->values[i] = rasqal_new_literal_from_literal(v->value);
+ }
+
+ row->offset = con->offset++;
+
+ done:
+ if(error != RASQAL_ENGINE_OK) {
+ if(row) {
+ rasqal_free_row(row);
+ row = NULL;
+ }
+ }
+
+ return row;
+}
+
+
+static raptor_sequence*
+rasqal_triples_rowsource_read_all_rows(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_triples_rowsource_context *con;
+ raptor_sequence *seq = NULL;
+
+ con = (rasqal_triples_rowsource_context*)user_data;
+
+ return seq;
+}
+
+
+static int
+rasqal_triples_rowsource_reset(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_triples_rowsource_context *con;
+ int column;
+
+ con = (rasqal_triples_rowsource_context*)user_data;
+
+ con->column = con->start_column;
+ for(column = con->start_column; column <= con->end_column; column++) {
+ rasqal_triple_meta *m;
+
+ m = &con->triple_meta[column - con->start_column];
+ rasqal_reset_triple_meta(m);
+ }
+
+ return 0;
+}
+
+
+static int
+rasqal_triples_rowsource_set_preserve(rasqal_rowsource* rowsource,
+ void *user_data, int preserve)
+{
+ rasqal_triples_rowsource_context *con;
+
+ con = (rasqal_triples_rowsource_context*)user_data;
+ con->preserve_on_all_finished = preserve;
+
+ return 0;
+}
+
+
+static const rasqal_rowsource_handler rasqal_triples_rowsource_handler = {
+ /* .version = */ 1,
+ "triple pattern",
+ /* .init = */ rasqal_triples_rowsource_init,
+ /* .finish = */ rasqal_triples_rowsource_finish,
+ /* .ensure_variables = */ rasqal_triples_rowsource_ensure_variables,
+ /* .read_row = */ rasqal_triples_rowsource_read_row,
+ /* .read_all_rows = */ rasqal_triples_rowsource_read_all_rows,
+ /* .reset = */ rasqal_triples_rowsource_reset,
+ /* .set_preserve = */ rasqal_triples_rowsource_set_preserve,
+ /* .get_inner_rowsource = */ NULL
+};
+
+
+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,
+ int *declared_in)
+{
+ rasqal_triples_rowsource_context *con;
+ int flags = 0;
+
+ if(!world || !query || !triples_source || !triples)
+ return NULL;
+
+ con = (rasqal_triples_rowsource_context*)RASQAL_CALLOC(rasqal_triples_rowsource_context, 1, sizeof(rasqal_triples_rowsource_context));
+ if(!con)
+ return NULL;
+
+ con->triples_source = triples_source;
+ con->triples = triples;
+ con->start_column = start_column;
+ con->end_column = end_column;
+ con->column = -1;
+ con->declared_in = declared_in;
+
+ con->triples_count = con->end_column - con->start_column + 1;
+
+ con->triple_meta = (rasqal_triple_meta*)RASQAL_CALLOC(rasqal_triple_meta,
+ con->triples_count,
+ sizeof(rasqal_triple_meta));
+ if(!con->triple_meta) {
+ rasqal_triples_rowsource_finish(NULL, con);
+ return NULL;
+ }
+
+ return rasqal_new_rowsource_from_handler(world, query,
+ con,
+ &rasqal_triples_rowsource_handler,
+ query->vars_table,
+ flags);
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+#define QUERY_LANGUAGE "sparql"
+#define QUERY_FORMAT "\
+SELECT ?s ?p ?o \
+FROM <%s> \
+WHERE { ?s ?p ?o }\
+"
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = rasqal_basename(argv[0]);
+ rasqal_rowsource *rowsource = NULL;
+ rasqal_world *world;
+ rasqal_query *query;
+ const char *query_language_name = QUERY_LANGUAGE;
+ const char *query_format = QUERY_FORMAT;
+ unsigned char *query_string;
+ int failures = 0;
+ int start_column;
+ int end_column;
+ int rc;
+ raptor_sequence* triples;
+ rasqal_triples_source* triples_source;
+ raptor_uri *base_uri = NULL;
+ unsigned char *data_string = NULL;
+ unsigned char *uri_string = NULL;
+ /* <http://example.org#subject> <http://example.org#predicate> "object" . */
+#define SUBJECT_URI_STRING (const unsigned char*)"http://example.org#subject"
+#define PREDICATE_URI_STRING (const unsigned char*)"http://example.org#predicate"
+#define OBJECT_STRING "object"
+ raptor_uri* s_uri = NULL;
+ raptor_uri* p_uri = NULL;
+ int size;
+ int *declared_in;
+
+ if(argc != 2) {
+ fprintf(stderr, "USAGE: %s data-filename\n", program);
+ return(1);
+ }
+
+ world = rasqal_new_world();
+ if(!world || rasqal_world_open(world)) {
+ fprintf(stderr, "%s: rasqal_world init failed\n", program);
+ return(1);
+ }
+
+ query = rasqal_new_query(world, "sparql", NULL);
+
+ data_string = raptor_uri_filename_to_uri_string(argv[1]);
+ query_string = (unsigned char*)RASQAL_MALLOC(cstring, strlen((const char*)data_string)+strlen(query_format)+1);
+ sprintf((char*)query_string, query_format, data_string);
+ raptor_free_memory(data_string);
+
+ uri_string = raptor_uri_filename_to_uri_string("");
+#ifdef RAPTOR_V2_AVAILABLE
+ base_uri = raptor_new_uri_v2(world->raptor_world_ptr, uri_string);
+#else
+ base_uri = raptor_new_uri(uri_string);
+#endif
+ raptor_free_memory(uri_string);
+
+ query = rasqal_new_query(world, query_language_name, NULL);
+ if(!query) {
+ fprintf(stderr, "%s: creating query in language %s FAILED\n", program,
+ query_language_name);
+ failures++;
+ goto tidy;
+ }
+
+ printf("%s: preparing %s query\n", program, query_language_name);
+ rc = rasqal_query_prepare(query, query_string, base_uri);
+ if(rc) {
+ fprintf(stderr, "%s: failed to prepare query '%s'\n", program,
+ query_string);
+ failures++;
+ goto tidy;
+ }
+
+ RASQAL_FREE(cstring, query_string);
+ query_string = NULL;
+
+ triples = rasqal_query_get_triple_sequence(query);
+ start_column = 0;
+ end_column = 0;
+
+ triples_source = rasqal_new_triples_source(query);
+
+ size = rasqal_variables_table_get_named_variables_count(query->vars_table);
+ declared_in = rasqal_query_triples_build_declared_in(query, size,
+ start_column,
+ end_column);
+ if(!declared_in) {
+ fprintf(stderr, "%s: failed to create declared_in\n", program);
+ failures++;
+ goto tidy;
+ }
+
+ rowsource = rasqal_new_triples_rowsource(world, query, triples_source,
+ triples, start_column, end_column,
+ declared_in);
+ if(!rowsource) {
+ fprintf(stderr, "%s: failed to create triples rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+
+ while(1) {
+ rasqal_row* row;
+ rasqal_literal *s;
+ rasqal_literal *p;
+ rasqal_literal *o;
+
+ row = rasqal_rowsource_read_row(rowsource);
+ if(!row)
+ break;
+
+ #ifdef RASQAL_DEBUG
+ RASQAL_DEBUG1("Result Row:\n ");
+ rasqal_row_print(row, stderr);
+ fputc('\n', stderr);
+ #endif
+
+#ifdef RAPTOR_V2_AVAILABLE
+ s_uri = raptor_new_uri_v2(world->raptor_world_ptr, SUBJECT_URI_STRING);
+ p_uri = raptor_new_uri_v2(world->raptor_world_ptr, PREDICATE_URI_STRING);
+#else
+ s_uri = raptor_new_uri(SUBJECT_URI_STRING);
+ p_uri = raptor_new_uri(PREDICATE_URI_STRING);
+#endif
+
+ s = row->values[0];
+ if(!s ||
+ (s && s->type != RASQAL_LITERAL_URI) ||
+#ifdef RAPTOR_V2_AVAILABLE
+ !raptor_uri_equals_v2(world->raptor_world_ptr, s->value.uri, s_uri)
+#else
+ !raptor_uri_equals(s->value.uri, s_uri)
+#endif
+ ) {
+ fprintf(stderr, "%s: 's' is bound to %s not URI %s\n", program,
+ rasqal_literal_as_string(s),
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, s_uri)
+#else
+ raptor_uri_as_string(s_uri)
+#endif
+ );
+ failures++;
+ }
+ p = row->values[1];
+ if(!p ||
+ (p && p->type != RASQAL_LITERAL_URI) ||
+#ifdef RAPTOR_V2_AVAILABLE
+ !raptor_uri_equals_v2(world->raptor_world_ptr, p->value.uri, p_uri)
+#else
+ !raptor_uri_equals(p->value.uri, p_uri)
+#endif
+ ) {
+ fprintf(stderr, "%s: 'p' is bound to %s not URI %s\n", program,
+ rasqal_literal_as_string(p),
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, p_uri)
+#else
+ raptor_uri_as_string(p_uri)
+#endif
+ );
+ failures++;
+ }
+ o = row->values[2];
+ if(!o ||
+ (o && o->type != RASQAL_LITERAL_STRING) ||
+ strcmp((const char*)o->string, OBJECT_STRING)) {
+ fprintf(stderr, "%s: 'o' is bound to %s not string '%s'\n", program,
+ rasqal_literal_as_string(o), OBJECT_STRING);
+ failures++;
+ }
+
+ rasqal_free_row(row);
+ if(failures)
+ break;
+ }
+
+ tidy:
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, base_uri);
+ if(s_uri)
+ raptor_free_uri_v2(world->raptor_world_ptr, s_uri);
+ if(p_uri)
+ raptor_free_uri_v2(world->raptor_world_ptr, p_uri);
+#else
+ raptor_free_uri(base_uri);
+ if(s_uri)
+ raptor_free_uri(s_uri);
+ if(p_uri)
+ raptor_free_uri(p_uri);
+#endif
+
+ if(declared_in)
+ RASQAL_FREE(intarray, declared_in);
+ if(triples_source)
+ rasqal_free_triples_source(triples_source);
+ if(rowsource)
+ rasqal_free_rowsource(rowsource);
+ if(query)
+ rasqal_free_query(query);
+ if(world)
+ rasqal_free_world(world);
+
+ return failures;
+}
+
+#endif
diff --git a/src/rasqal/rasqal_rowsource_union.c b/src/rasqal/rasqal_rowsource_union.c
new file mode 100644
index 0000000..a1c3370
--- /dev/null
+++ b/src/rasqal/rasqal_rowsource_union.c
@@ -0,0 +1,579 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_rowsource_union.c - Rasqal union rowsource class
+ *
+ * Copyright (C) 2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <raptor.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#define DEBUG_FH stderr
+
+#ifndef STANDALONE
+
+typedef struct
+{
+ rasqal_rowsource* left;
+
+ rasqal_rowsource* right;
+
+ /* array of size (number of variables in @right) with this row offset value */
+ int* right_map;
+
+ /* 0 = reading from left rs, 1 = reading from right rs, 2 = finished */
+ int state;
+
+ int failed;
+
+ /* row offset for read_row() */
+ int offset;
+} rasqal_union_rowsource_context;
+
+
+static int
+rasqal_union_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_union_rowsource_context* con;
+ con = (rasqal_union_rowsource_context*)user_data;
+ con->state = 0;
+
+ con->failed = 0;
+
+ return 0;
+}
+
+
+static int
+rasqal_union_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_union_rowsource_context* con;
+ con = (rasqal_union_rowsource_context*)user_data;
+ if(con->left)
+ rasqal_free_rowsource(con->left);
+
+ if(con->right)
+ rasqal_free_rowsource(con->right);
+
+ if(con->right_map)
+ RASQAL_FREE(int, con->right_map);
+
+ RASQAL_FREE(rasqal_union_rowsource_context, con);
+
+ return 0;
+}
+
+
+static int
+rasqal_union_rowsource_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_union_rowsource_context* con;
+ int map_size;
+ int i;
+
+ con = (rasqal_union_rowsource_context*)user_data;
+
+ if(rasqal_rowsource_ensure_variables(con->left))
+ return 1;
+
+ if(rasqal_rowsource_ensure_variables(con->right))
+ return 1;
+
+ map_size = rasqal_rowsource_get_size(con->right);
+ con->right_map = (int*)RASQAL_MALLOC(int, sizeof(int) * map_size);
+ if(!con->right_map)
+ return 1;
+
+ rowsource->size = 0;
+
+ /* copy in variables from left rowsource */
+ rasqal_rowsource_copy_variables(rowsource, con->left);
+
+ /* add any new variables not already seen from right rowsource */
+ for(i = 0; i < map_size; i++) {
+ rasqal_variable* v;
+ int offset;
+
+ v = rasqal_rowsource_get_variable_by_offset(con->right, i);
+ if(!v)
+ break;
+ offset = rasqal_rowsource_add_variable(rowsource, v);
+ if(offset < 0)
+ return 1;
+
+ con->right_map[i] = offset;
+ }
+
+ return 0;
+}
+
+
+static void
+rasqal_union_rowsource_adjust_right_row(rasqal_union_rowsource_context* con,
+ rasqal_row *row)
+{
+ rasqal_rowsource *rowsource = con->right;
+ int i;
+
+ for(i = rowsource->size - 1; i >= 0; i--) {
+ int offset = con->right_map[i];
+ row->values[offset] = row->values[i];
+ row->values[i] = NULL;
+ }
+}
+
+
+static rasqal_row*
+rasqal_union_rowsource_read_row(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_union_rowsource_context* con;
+ rasqal_row* row = NULL;
+
+ con = (rasqal_union_rowsource_context*)user_data;
+
+ if(con->failed || con->state > 1)
+ return NULL;
+
+ if(con->state == 0) {
+ row = rasqal_rowsource_read_row(con->left);
+ if(!row)
+ con->state = 1;
+ else {
+ /* otherwise: rows from left are correct order but wrong size */
+ if(rasqal_row_expand_size(row, rowsource->size))
+ return NULL;
+ }
+ }
+ if(!row && con->state == 1) {
+ row = rasqal_rowsource_read_row(con->right);
+ if(!row)
+ /* finished */
+ con->state = 2;
+ else {
+ if(rasqal_row_expand_size(row, rowsource->size))
+ return NULL;
+ /* transform row from right to match new projection */
+ rasqal_union_rowsource_adjust_right_row(con, row);
+ }
+ }
+
+ if(row) {
+ row->rowsource = rowsource;
+ row->offset = con->offset++;
+ }
+
+ return row;
+}
+
+
+static raptor_sequence*
+rasqal_union_rowsource_read_all_rows(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_union_rowsource_context* con;
+ raptor_sequence* seq1 = NULL;
+ raptor_sequence* seq2 = NULL;
+ int left_size;
+ int right_size;
+ int i;
+
+ con = (rasqal_union_rowsource_context*)user_data;
+
+ if(con->failed)
+ return NULL;
+
+ seq1 = rasqal_rowsource_read_all_rows(con->left);
+ if(!seq1) {
+ con->failed = 1;
+ return NULL;
+ }
+
+ seq2 = rasqal_rowsource_read_all_rows(con->right);
+ if(!seq2) {
+ con->failed = 1;
+ raptor_free_sequence(seq1);
+ return NULL;
+ }
+
+#ifdef RASQAL_DEBUG
+ fprintf(DEBUG_FH, "left rowsource (%d vars):\n",
+ rasqal_rowsource_get_size(con->left));
+ rasqal_rowsource_print_row_sequence(con->left, seq1, DEBUG_FH);
+
+ fprintf(DEBUG_FH, "right rowsource (%d vars):\n",
+ rasqal_rowsource_get_size(con->right));
+ rasqal_rowsource_print_row_sequence(con->right, seq2, DEBUG_FH);
+#endif
+
+ /* transform rows from left to match new projection */
+ left_size = raptor_sequence_size(seq1);
+ for(i = 0; i < left_size; i++) {
+ rasqal_row *row = (rasqal_row*)raptor_sequence_get_at(seq1, i);
+ /* rows from left are correct order but wrong size */
+ rasqal_row_expand_size(row, rowsource->size);
+ row->rowsource = rowsource;
+ }
+ /* transform rows from right to match new projection */
+ right_size = raptor_sequence_size(seq2);
+ for(i = 0; i < right_size; i++) {
+ rasqal_row *row = (rasqal_row*)raptor_sequence_get_at(seq2, i);
+ /* rows from right need resizing and adjusting by offset */
+ rasqal_row_expand_size(row, rowsource->size);
+ rasqal_union_rowsource_adjust_right_row(con, row);
+ row->offset += left_size;
+ row->rowsource = rowsource;
+ }
+
+ if(raptor_sequence_join(seq1, seq2)) {
+ raptor_free_sequence(seq1);
+ seq1 = NULL;
+ }
+ raptor_free_sequence(seq2);
+
+ con->state = 2;
+ return seq1;
+}
+
+
+static int
+rasqal_union_rowsource_reset(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_union_rowsource_context* con;
+ int rc;
+
+ con = (rasqal_union_rowsource_context*)user_data;
+
+ con->state = 0;
+ con->failed = 0;
+
+ rc = rasqal_rowsource_reset(con->left);
+ if(rc)
+ return rc;
+
+ return rasqal_rowsource_reset(con->right);
+}
+
+
+static int
+rasqal_union_rowsource_set_preserve(rasqal_rowsource* rowsource,
+ void *user_data, int preserve)
+{
+ rasqal_union_rowsource_context* con;
+ int rc;
+
+ con = (rasqal_union_rowsource_context*)user_data;
+
+ con->state = 0;
+ con->failed = 0;
+
+ rc = rasqal_rowsource_set_preserve(con->left, preserve);
+ if(rc)
+ return rc;
+
+ return rasqal_rowsource_set_preserve(con->right, preserve);
+}
+
+
+static rasqal_rowsource*
+rasqal_union_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource,
+ void *user_data, int offset)
+{
+ rasqal_union_rowsource_context *con;
+ con = (rasqal_union_rowsource_context*)user_data;
+
+ if(offset == 1)
+ return con->left;
+ else if(offset == 2)
+ return con->right;
+ else
+ return NULL;
+}
+
+
+static const rasqal_rowsource_handler rasqal_union_rowsource_handler = {
+ /* .version = */ 1,
+ "union",
+ /* .init = */ rasqal_union_rowsource_init,
+ /* .finish = */ rasqal_union_rowsource_finish,
+ /* .ensure_variables = */ rasqal_union_rowsource_ensure_variables,
+ /* .read_row = */ rasqal_union_rowsource_read_row,
+ /* .read_all_rows = */ rasqal_union_rowsource_read_all_rows,
+ /* .reset = */ rasqal_union_rowsource_reset,
+ /* .set_preserve = */ rasqal_union_rowsource_set_preserve,
+ /* .get_inner_rowsource = */ rasqal_union_rowsource_get_inner_rowsource
+};
+
+
+/**
+ * rasqal_new_union_rowsource:
+ * @world: world object
+ * @query: query object
+ * @left: left (first) rowsource
+ * @right: right (second) rowsource
+ *
+ * INTERNAL - create a new UNION over two rowsources
+ *
+ * This uses the number of variables in @vt to set the rowsource size
+ * (order size is always 0) and then checks that all the rows in the
+ * sequence are the same. If not, construction fails and NULL is
+ * returned.
+ *
+ * Return value: new rowsource or NULL on failure
+ */
+rasqal_rowsource*
+rasqal_new_union_rowsource(rasqal_world *world,
+ rasqal_query* query,
+ rasqal_rowsource* left,
+ rasqal_rowsource* right)
+{
+ rasqal_union_rowsource_context* con;
+ int flags = 0;
+
+ if(!world || !query || !left || !right)
+ return NULL;
+
+ con = (rasqal_union_rowsource_context*)RASQAL_CALLOC(rasqal_union_rowsource_context, 1, sizeof(rasqal_union_rowsource_context));
+ if(!con)
+ return NULL;
+
+ con->left = left;
+ con->right = right;
+
+ return rasqal_new_rowsource_from_handler(world, query,
+ con,
+ &rasqal_union_rowsource_handler,
+ query->vars_table,
+ flags);
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+const char* const union_1_data_2x3_rows[] =
+{
+ /* 2 variable names and 3 rows */
+ "a", NULL, "b", NULL,
+ /* row 1 data */
+ "foo", NULL, "bar", NULL,
+ /* row 2 data */
+ "baz", NULL, "fez", NULL,
+ /* row 3 data */
+ "bob", NULL, "sue", NULL,
+ /* end of data */
+ NULL, NULL
+};
+
+
+const char* const union_2_data_3x4_rows[] =
+{
+ /* 3 variable names and 4 rows */
+ "b", NULL, "c", NULL, "d", NULL,
+ /* row 1 data */
+ "red", NULL, "orange", NULL, "yellow", NULL,
+ /* row 2 data */
+ "blue", NULL, "indigo", NULL, "violet", NULL,
+ /* row 3 data */
+ "black", NULL, "silver", NULL, "gold", NULL,
+ /* row 4 data */
+ "green", NULL, "tope", NULL, "bronze", NULL,
+ /* end of data */
+ NULL, NULL
+};
+
+
+#define EXPECTED_ROWS_COUNT (3 + 4)
+
+/* there is one duplicate variable 'b' */
+#define EXPECTED_COLUMNS_COUNT (2 + 3 - 1)
+const char* const union_result_vars[] = { "a" , "b" , "c", "d" };
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = rasqal_basename(argv[0]);
+ rasqal_rowsource *rowsource = NULL;
+ rasqal_rowsource *left_rs = NULL;
+ rasqal_rowsource *right_rs = NULL;
+ rasqal_world* world = NULL;
+ rasqal_query* query = NULL;
+ int count;
+ raptor_sequence* seq = NULL;
+ int failures = 0;
+ int vars_count;
+ rasqal_variables_table* vt;
+ int size;
+ int expected_count = EXPECTED_ROWS_COUNT;
+ int expected_size = EXPECTED_COLUMNS_COUNT;
+ int i;
+ raptor_sequence* vars_seq = NULL;
+
+ world = rasqal_new_world(); rasqal_world_open(world);
+
+ query = rasqal_new_query(world, "sparql", NULL);
+
+ vt = query->vars_table;
+
+ /* 2 variables and 3 rows */
+ vars_count = 2;
+ seq = rasqal_new_row_sequence(world, vt, union_1_data_2x3_rows, vars_count,
+ &vars_seq);
+ if(!seq) {
+ fprintf(stderr,
+ "%s: failed to create left sequence of %d vars\n", program,
+ vars_count);
+ failures++;
+ goto tidy;
+ }
+
+ left_rs = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
+ if(!left_rs) {
+ fprintf(stderr, "%s: failed to create left rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+ /* vars_seq and seq are now owned by left_rs */
+ vars_seq = seq = NULL;
+
+ /* 3 variables and 4 rows */
+ vars_count = 3;
+ seq = rasqal_new_row_sequence(world, vt, union_2_data_3x4_rows, vars_count,
+ &vars_seq);
+ if(!seq) {
+ fprintf(stderr,
+ "%s: failed to create right sequence of %d rows\n", program,
+ vars_count);
+ failures++;
+ goto tidy;
+ }
+
+ right_rs = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
+ if(!right_rs) {
+ fprintf(stderr, "%s: failed to create right rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+ /* vars_seq and seq are now owned by right_rs */
+ vars_seq = seq = NULL;
+
+ rowsource = rasqal_new_union_rowsource(world, query, left_rs, right_rs);
+ if(!rowsource) {
+ fprintf(stderr, "%s: failed to create union rowsource\n", program);
+ failures++;
+ goto tidy;
+ }
+ /* left_rs and right_rs are now owned by rowsource */
+ left_rs = right_rs = NULL;
+
+ seq = rasqal_rowsource_read_all_rows(rowsource);
+ if(!seq) {
+ fprintf(stderr,
+ "%s: read_rows returned a NULL seq for a union rowsource\n",
+ program);
+ failures++;
+ goto tidy;
+ }
+ count = raptor_sequence_size(seq);
+ if(count != expected_count) {
+ fprintf(stderr,
+ "%s: read_rows returned %d rows for a union rowsource, expected %d\n",
+ program, count, expected_count);
+ failures++;
+ goto tidy;
+ }
+
+ size = rasqal_rowsource_get_size(rowsource);
+ if(size != expected_size) {
+ fprintf(stderr,
+ "%s: read_rows returned %d columns (variables) for a union rowsource, expected %d\n",
+ program, size, expected_size);
+ failures++;
+ goto tidy;
+ }
+ for(i = 0; i < expected_size; i++) {
+ rasqal_variable* v;
+ const char* name = NULL;
+ const char *expected_name = union_result_vars[i];
+
+ v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
+ if(!v) {
+ fprintf(stderr,
+ "%s: read_rows had NULL column (variable) #%d expected %s\n",
+ program, i, expected_name);
+ failures++;
+ goto tidy;
+ }
+ name = (const char*)v->name;
+ if(strcmp(name, expected_name)) {
+ fprintf(stderr,
+ "%s: read_rows returned column (variable) #%d %s but expected %s\n",
+ program, i, name, expected_name);
+ failures++;
+ goto tidy;
+ }
+ }
+
+#ifdef RASQAL_DEBUG
+ rasqal_rowsource_print_row_sequence(rowsource, seq, DEBUG_FH);
+#endif
+
+ tidy:
+ if(seq)
+ raptor_free_sequence(seq);
+ if(left_rs)
+ rasqal_free_rowsource(left_rs);
+ if(right_rs)
+ rasqal_free_rowsource(right_rs);
+ if(rowsource)
+ rasqal_free_rowsource(rowsource);
+ if(query)
+ rasqal_free_query(query);
+ if(world)
+ rasqal_free_world(world);
+
+ return failures;
+}
+
+#endif
diff --git a/src/rasqal/rasqal_skiplist.c b/src/rasqal/rasqal_skiplist.c
new file mode 100644
index 0000000..a261ca2
--- /dev/null
+++ b/src/rasqal/rasqal_skiplist.c
@@ -0,0 +1,604 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_skiplist.c - Skip list
+ *
+ * Copyright (C) 2005-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2005-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#ifndef HAVE_SRANDOMDEV
+/* for time() as a random seed */
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#endif
+
+/* Rasqal includes */
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+typedef struct rasqal_skiplist_node_s rasqal_skiplist_node;
+
+struct rasqal_skiplist_s {
+ /* list header */
+ rasqal_skiplist_node* head;
+
+ /* current level of list */
+ int level;
+
+ /* number of entries in list */
+ int size;
+
+ /* flags from bitor of enum rasqal_skiplist_flags values */
+ int flags;
+
+ /* random bits management for choosing level */
+ unsigned int random_bits;
+ unsigned int random_bits_left;
+
+ /* item comparison function returning for A<B: <0, A=B: 0, A>B: >0 */
+ rasqal_compare_fn* compare_fn;
+
+ /* item free item (key, value pair) function */
+ rasqal_kv_free_fn* free_fn;
+
+ /* print (key,value) functions */
+ raptor_sequence_print_handler* print_key_fn;
+ raptor_sequence_print_handler* print_value_fn;
+};
+
+
+/* levels range from (0 .. RASQAL_SKIPLIST_MAX_LEVEL) */
+#define RASQAL_SKIPLIST_MAX_LEVEL 15
+
+#define RASQAL_SKIPLIST_NIL NULL
+
+#define BITS_IN_RANDOM 31
+
+
+struct rasqal_skiplist_node_s {
+ void* key;
+ void* value;
+ /* skip list forward array.
+ * Note: This MUST remain at the end of the struct as it is variable size
+ */
+ struct rasqal_skiplist_node_s* forward[1];
+};
+
+
+static int rasqal_skiplist_get_random_level(rasqal_skiplist *list);
+static void rasqal_skiplist_node_print(rasqal_skiplist* list, rasqal_skiplist_node* node, FILE *fh);
+
+
+#ifndef STANDALONE_NOTYET
+
+
+void
+rasqal_skiplist_init_with_seed(unsigned long seed)
+{
+ srandom(seed);
+}
+
+
+void
+rasqal_skiplist_init(void)
+{
+#ifdef HAVE_SRANDOMDEV
+ srandomdev();
+#else
+ srandom((unsigned long)time(NULL));
+#endif
+}
+
+
+void
+rasqal_skiplist_finish(void)
+{
+ /* NOP */
+}
+
+
+/**
+ * rasqal_new_skiplist:
+ * @compare_fn: function to compare two keys
+ * @free_fn: function to delete a (key, value) item pair (or NULL)
+ * @print_key_fn: function to print a key function
+ * @print_value_fn: function to print a key function
+ * @flags: set to RASQAL_SKIPLIST_FLAG_DUPLICATES to allow duplicates
+ *
+ * Constructor - Create a new Rasqal skiplist.
+ *
+ * Return value: a new #rasqal_skiplist or NULL on failure.
+ */
+rasqal_skiplist*
+rasqal_new_skiplist(rasqal_compare_fn* compare_fn,
+ rasqal_kv_free_fn* free_fn,
+ raptor_sequence_print_handler* print_key_fn,
+ raptor_sequence_print_handler* print_value_fn,
+ int flags)
+{
+ int i;
+ rasqal_skiplist* list;
+
+ list=(rasqal_skiplist*)RASQAL_CALLOC(rasqal_skiplist, 1, sizeof(rasqal_skiplist));
+ if(!list)
+ return NULL;
+
+ list->compare_fn=compare_fn;
+ list->print_key_fn=print_key_fn;
+ list->print_value_fn=print_value_fn;
+
+ list->head=(rasqal_skiplist_node*)RASQAL_MALLOC(rasqal_skiplist_node,
+ sizeof(rasqal_skiplist_node) + RASQAL_SKIPLIST_MAX_LEVEL*sizeof(rasqal_skiplist_node* ));
+ if(!list->head) {
+ RASQAL_FREE(rasqal_skiplist, list);
+ return NULL;
+ }
+
+ for(i = 0; i <= RASQAL_SKIPLIST_MAX_LEVEL; i++)
+ list->head->forward[i] = RASQAL_SKIPLIST_NIL;
+ list->level = 0;
+
+ list->size = 0;
+
+ list->random_bits=random();
+ list->random_bits_left= BITS_IN_RANDOM;
+
+ list->flags=flags;
+
+ return list;
+}
+
+
+static void
+rasqal_free_skiplist_node(rasqal_skiplist* list, rasqal_skiplist_node* node)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(list, rasqal_skiplist);
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(node, rasqal_skiplist_node);
+
+ if(list->free_fn)
+ list->free_fn(node->key, node->value);
+ RASQAL_FREE(rasqal_skiplist_node, node);
+}
+
+
+/**
+ * rasqal_free_skiplist - Destructor - Destroy a Rasqal skiplist object
+ * @list: #rasqal_skiplist object
+ *
+ */
+void
+rasqal_free_skiplist(rasqal_skiplist* list)
+{
+ rasqal_skiplist_node* node;
+
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(list, rasqal_skiplist);
+
+ node=list->head;
+ for(node = node->forward[0]; node != RASQAL_SKIPLIST_NIL; ) {
+ rasqal_skiplist_node* next = node->forward[0];
+ rasqal_free_skiplist_node(list, node);
+ node=next;
+ }
+
+ if(list->head)
+ rasqal_free_skiplist_node(list, list->head);
+
+ RASQAL_FREE(rasqal_skiplist, list);
+}
+
+
+static int
+rasqal_skiplist_get_random_level(rasqal_skiplist *list)
+{
+ int level = 0;
+ int b;
+ do {
+ b = list->random_bits & 3;
+ if(!b)
+ level++;
+ list->random_bits>>=2;
+ if(!--list->random_bits_left) {
+ list->random_bits = random();
+ list->random_bits_left = BITS_IN_RANDOM >>1;
+ };
+ } while (!b);
+
+ return (level > RASQAL_SKIPLIST_MAX_LEVEL ? RASQAL_SKIPLIST_MAX_LEVEL : level);
+};
+
+
+/**
+ * rasqal_skiplist_insert - Add a (key, value) pair to a skiplist
+ * @list: #rasqal_skiplist object
+ * @key: pointer to key
+ * @value: pointer to value
+ *
+ * If duplicates are not allowed, adding a duplicate (key, value)
+ * pair will fail.
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_skiplist_insert(rasqal_skiplist* list,
+ void* key, void* value)
+{
+ int i;
+ int new_level;
+ rasqal_skiplist_node* update[RASQAL_SKIPLIST_MAX_LEVEL+1];
+ rasqal_skiplist_node* node;
+
+ node=list->head;
+ for(i = list->level; i>=0; i--) {
+ while(node->forward[i] != RASQAL_SKIPLIST_NIL &&
+ list->compare_fn(node->forward[i]->key, key) < 0)
+ node=node->forward[i];
+ update[i] = node;
+ }
+ node=node->forward[0];
+
+ if(!(list->flags & RASQAL_SKIPLIST_FLAG_DUPLICATES)) {
+ if(node != RASQAL_SKIPLIST_NIL && !list->compare_fn(node->key, key))
+ /* found duplicate key and they are not allowed */
+ return 1;
+ }
+
+ new_level = rasqal_skiplist_get_random_level(list);
+
+ if(new_level > list->level) {
+ for(i = list->level + 1; i <= new_level; i++)
+ update[i] = list->head;
+ list->level = new_level;
+ }
+
+ node=(rasqal_skiplist_node*)RASQAL_MALLOC(rasqal_skiplist_node,
+ sizeof(rasqal_skiplist_node) +
+ new_level * sizeof(rasqal_skiplist_node*));
+ if(!node)
+ return 1;
+ node->key = key;
+ node->value = value;
+
+ for(i = 0; i <= new_level; i++) {
+ node->forward[i] = update[i]->forward[i];
+ update[i]->forward[i] = node;
+ }
+
+ list->size++;
+
+ return 0;
+}
+
+
+/**
+ * rasqal_skiplist_delete - Delete a (key, value) pair from a skiplist
+ * @list: #rasqal_skiplist object
+ * @key: pointer to key
+ * @value: pointer to value
+ *
+ * Return value: non-0 on failure
+ */
+int
+rasqal_skiplist_delete(rasqal_skiplist* list, void* key)
+{
+ int i;
+ rasqal_skiplist_node* update[RASQAL_SKIPLIST_MAX_LEVEL+1];
+ rasqal_skiplist_node* node;
+
+ node=list->head;
+ for(i = list->level; i>=0; i--) {
+ while(node->forward[i] != RASQAL_SKIPLIST_NIL &&
+ list->compare_fn(node->forward[i]->key, key) < 0)
+ node=node->forward[i];
+ update[i] = node;
+ }
+ node=node->forward[0];
+
+ if(node == RASQAL_SKIPLIST_NIL || list->compare_fn(node->key, key))
+ /* failed to find key */
+ return 1;
+
+ for(i = 0; i <= list->level; i++) {
+ if(update[i]->forward[i] != node)
+ break;
+ update[i]->forward[i] = node->forward[i];
+ }
+
+ rasqal_free_skiplist_node(list, node);
+
+ while((list->level > 0) &&
+ (list->head->forward[list->level] == RASQAL_SKIPLIST_NIL))
+ list->level--;
+
+ list->size--;
+
+ return 0;
+}
+
+
+/**
+ * rasqal_skiplist_find - Find a value in a skiplist for a given key
+ * @list: #rasqal_skiplist object
+ * @key: pointer to key
+ *
+ * Return value: value pointer or NULL if not found
+ */
+void*
+rasqal_skiplist_find(rasqal_skiplist* list, void* key)
+{
+ int i;
+ rasqal_skiplist_node* node=list->head;
+
+ for(i = list->level; i>=0; i--) {
+ while(node->forward[i] != RASQAL_SKIPLIST_NIL &&
+ list->compare_fn(node->forward[i]->key, key) < 0)
+ node=node->forward[i];
+ }
+
+ node=node->forward[0];
+ if(node != RASQAL_SKIPLIST_NIL && !list->compare_fn(node->key, key)) {
+ return node->value;
+ }
+
+ /* failed to find key */
+ return NULL;
+}
+
+
+static void
+rasqal_skiplist_node_print(rasqal_skiplist* list,
+ rasqal_skiplist_node* node, FILE *fh)
+{
+ fputs("{", fh);
+ if(!node->key)
+ fputs("NULL", fh);
+ else if(list->print_key_fn)
+ list->print_key_fn(node->key, fh);
+ else
+ fprintf(fh, "key %p", node->key);
+
+ fputs(" : ", fh);
+
+ if(!node->value)
+ fputs("NULL", fh);
+ else if(list->print_value_fn)
+ list->print_value_fn(node->value, fh);
+ else
+ fprintf(fh, "data %p", node->value);
+
+ fputs("}", fh);
+}
+
+
+/**
+ * rasqal_skiplist_print - Print a Rasqal skiplist in a debug format
+ * @list: the #rasqal_skiplist object
+ * @fh: the #FILE* handle to print to
+ *
+ * The print debug format may change in any release.
+ *
+ */
+void
+rasqal_skiplist_print(rasqal_skiplist* list, FILE* fh)
+{
+ rasqal_skiplist_node* node;
+ int first=1;
+
+ fprintf(fh, "skiplist(size=%d, duplicates=%s) [[ ", list->size,
+ (list->flags & RASQAL_SKIPLIST_FLAG_DUPLICATES) ? "yes" : "no");
+ node=list->head;
+ for(node = node->forward[0]; node != RASQAL_SKIPLIST_NIL; ) {
+ if(!first)
+ fputs(", ", fh);
+ rasqal_skiplist_node_print(list, node, fh);
+ first=0;
+ node=node->forward[0];
+ }
+
+ fputs(" ]]", fh);
+}
+
+
+void
+rasqal_skiplist_dump(rasqal_skiplist* list, FILE *fh)
+{
+ rasqal_skiplist_node* node;
+ int i;
+ int first=1;
+
+ fprintf(fh, "skiplist(size=%d, duplicates=%s) [[ ", list->size,
+ (list->flags & RASQAL_SKIPLIST_FLAG_DUPLICATES) ? "yes" : "no");
+ node=list->head;
+ for(i = list->level; i>=0; i--) {
+ int count=0;
+ while(node->forward[i] != RASQAL_SKIPLIST_NIL) {
+ count++;
+ node=node->forward[i];
+ }
+ if(!first)
+ fputs(", ", fh);
+ fprintf(fh, "L%d: %d node%s", i, count, ((count == 1) ? "" : "s"));
+ first=0;
+ }
+ fputs(" ]]", fh);
+}
+
+
+/**
+ * rasqal_skiplist_get_size - Get the number of items in a skiplist
+ * @list: #rasqal_skiplist object
+ *
+ * Return value: the number of items in the skiplist (0 or more)
+ */
+unsigned int
+rasqal_skiplist_get_size(rasqal_skiplist* list)
+{
+ return list->size;
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+
+static int
+rasqal_skiplist_int_compare(const void *a, const void *b)
+{
+ int* int_a=(int*)a;
+ int* int_b=(int*)b;
+
+ return *int_a - *int_b;
+}
+
+static void
+rasqal_skiplist_int_print(void *int_p, FILE *fh)
+{
+ fprintf(fh,"%d", *(int*)int_p);
+}
+
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+#define DEFAULT_TEST_SIZE 100
+
+int
+main(int argc, char *argv[])
+{
+ const char *program=rasqal_basename(argv[0]);
+ int size;
+ int* keys;
+ int* values;
+ rasqal_skiplist* list;
+ int i;
+ int result_size;
+
+ rasqal_skiplist_init_with_seed(1234567890);
+
+ if(argc < 1 || argc > 2) {
+ fprintf(stderr, "%s: USAGE: %s [<size>]\n", program, program);
+ exit(1);
+ }
+
+ if(argc == 2)
+ size = atoi(argv[1]);
+ else
+ size = DEFAULT_TEST_SIZE;
+
+ list=rasqal_new_skiplist(rasqal_skiplist_int_compare,
+ NULL,
+ rasqal_skiplist_int_print,
+ rasqal_skiplist_int_print,
+ 0);
+ if(!list) {
+ fprintf(stderr, "%s: Creating new skiplist failed\n", program);
+ exit(1);
+ }
+
+ keys = (int*)RASQAL_CALLOC(intarray, size, sizeof(int));
+ values = (int*)RASQAL_CALLOC(intarray, size, sizeof(int));
+ if(!keys || !values) {
+ fprintf(stderr, "%s: Out of memory\n", program);
+ exit(1);
+ }
+
+ for(i = 0; i < size; i++) {
+ keys[i] = random();
+ values[i] = i;
+ }
+ fprintf(stdout, "%s: Testing with %d random-keyed items\n", program, size);
+
+ for(i = 0; i < size; i++) {
+ if(rasqal_skiplist_insert(list, &keys[i], &values[i])) {
+ fprintf(stderr, "%s: insert failed for %d:%d ", program,
+ keys[i], values[i]);
+ fputs("\n", stderr);
+ }
+ }
+
+ if(rasqal_skiplist_get_size(list) != size) {
+ fprintf(stderr, "%s: skiplist has %d items, expected %d\n", program,
+ rasqal_skiplist_get_size(list), size);
+ exit(1);
+ }
+
+ for(i=0; i < size; i++) {
+ int* result=(int*)rasqal_skiplist_find(list, &keys[i]);
+ if(!result) {
+ fprintf(stderr, "%s: find failed to find key %d\n",
+ program, keys[i]);
+ exit(1);
+ }
+ }
+
+ result_size=size;
+ for(i=0; i < size; i++) {
+ if(rasqal_skiplist_delete(list, &keys[i])) {
+ fprintf(stderr, "%s: delete failed with key '%d'\n",
+ program, keys[i]);
+ exit(1);
+ }
+
+ result_size--;
+
+ if(rasqal_skiplist_get_size(list) != result_size) {
+ fprintf(stderr, "%s: after deleting, skiplist has %d items, expected %d\n",
+ program, rasqal_skiplist_get_size(list), result_size);
+ exit(1);
+ }
+ }
+
+ rasqal_free_skiplist(list);
+
+ RASQAL_FREE(intarray, values);
+ RASQAL_FREE(intarray, keys);
+
+ rasqal_skiplist_finish();
+
+ /* keep gcc -Wall happy */
+ return 0;
+}
+
+#endif
diff --git a/src/rasqal/rasqal_sparql_xml.c b/src/rasqal/rasqal_sparql_xml.c
new file mode 100644
index 0000000..0b050c6
--- /dev/null
+++ b/src/rasqal/rasqal_sparql_xml.c
@@ -0,0 +1,1067 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_sparql_xml.c - SPARQL Results XML Format
+ *
+ * Copyright (C) 2007-2008, David Beckett http://www.dajobe.org/
+ *
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+
+#include <raptor.h>
+
+/* Rasqal includes */
+#include <rasqal.h>
+#include <rasqal_internal.h>
+
+
+static int rasqal_query_results_write_sparql_xml(raptor_iostream *iostr, rasqal_query_results* results, raptor_uri *base_uri);
+static rasqal_rowsource* rasqal_query_results_get_rowsource_sparql_xml(rasqal_world *world, rasqal_variables_table* vars_table, raptor_iostream *iostr, raptor_uri *base_uri);
+
+
+#if RASQAL_DEBUG > 1
+#define TRACE_XML 1
+#else
+#undef TRACE_XML
+#endif
+
+
+#ifndef FILE_READ_BUF_SIZE
+#ifdef BUFSIZ
+#define FILE_READ_BUF_SIZE BUFSIZ
+#else
+#define FILE_READ_BUF_SIZE 1024
+#endif
+#endif
+
+
+
+/*
+ * rasqal_query_results_write_sparql_xml:
+ * @iostr: #raptor_iostream to write the query results to
+ * @results: #rasqal_query_results query results input
+ * @base_uri: #raptor_uri base URI of the output format
+ *
+ * Write the fourth version of the SPARQL XML query results format to an
+ * iostream in a format - INTERNAL.
+ *
+ * If the writing succeeds, the query results will be exhausted.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+rasqal_query_results_write_sparql_xml(raptor_iostream *iostr,
+ rasqal_query_results* results,
+ raptor_uri *base_uri)
+{
+ int rc=1;
+ rasqal_query* query = rasqal_query_results_get_query(results);
+#ifndef RAPTOR_V2_AVAILABLE
+ const raptor_uri_handler *uri_handler;
+ void *uri_context;
+#endif
+ raptor_xml_writer* xml_writer=NULL;
+ raptor_namespace *res_ns=NULL;
+ raptor_namespace_stack *nstack=NULL;
+ raptor_xml_element *sparql_element=NULL;
+ raptor_xml_element *results_element=NULL;
+ raptor_xml_element *result_element=NULL;
+ raptor_xml_element *element1=NULL;
+ raptor_xml_element *binding_element=NULL;
+ raptor_xml_element *variable_element=NULL;
+ raptor_qname **attrs=NULL;
+ int i;
+
+ if(!rasqal_query_results_is_bindings(results) &&
+ !rasqal_query_results_is_boolean(results)) {
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Can only write XML format v3 for variable binding and boolean results");
+ return 1;
+ }
+
+
+#ifdef RAPTOR_V2_AVAILABLE
+ nstack = raptor_new_namespaces_v2(query->world->raptor_world_ptr,
+ (raptor_simple_message_handler)rasqal_query_simple_error, query,
+ 1);
+
+#else
+ raptor_uri_get_handler(&uri_handler, &uri_context);
+ nstack = raptor_new_namespaces(uri_handler, uri_context,
+ (raptor_simple_message_handler)rasqal_query_simple_error, query,
+ 1);
+#endif
+ if(!nstack)
+ return 1;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ xml_writer = raptor_new_xml_writer_v2(query->world->raptor_world_ptr,
+ nstack,
+ iostr,
+ (raptor_simple_message_handler)rasqal_query_simple_error, query,
+ 1);
+#else
+ xml_writer = raptor_new_xml_writer(nstack,
+ uri_handler, uri_context,
+ iostr,
+ (raptor_simple_message_handler)rasqal_query_simple_error, query,
+ 1);
+#endif
+ if(!xml_writer)
+ goto tidy;
+
+ res_ns=raptor_new_namespace(nstack,
+ NULL,
+ (const unsigned char*)"http://www.w3.org/2005/sparql-results#",
+ 0);
+ if(!res_ns)
+ goto tidy;
+
+ sparql_element=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"sparql",
+ NULL, base_uri);
+ if(!sparql_element)
+ goto tidy;
+
+ if(rasqal_query_results_is_bindings(results)) {
+ /* FIXME - consider when to write the XSD. Need the XSD URI too. */
+#if 0
+ raptor_namespace* xsi_ns;
+ xsi_ns=raptor_new_namespace(nstack,
+ (const unsigned char*)"xsi",
+ (const unsigned char*)"http://www.w3.org/2001/XMLSchema-instance",
+ 0);
+ raptor_xml_element_declare_namespace(sparql_element, xsi_ns);
+
+ attrs=(raptor_qname **)raptor_alloc_memory(sizeof(raptor_qname*));
+ attrs[0]=raptor_new_qname_from_namespace_local_name(xsi_ns,
+ (const unsigned char*)"schemaLocation",
+ (const unsigned char*)"http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd");
+ raptor_xml_element_set_attributes(sparql_element, attrs, 1);
+#endif
+ }
+
+ raptor_xml_writer_start_element(xml_writer, sparql_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ /* <head> */
+ element1=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"head",
+ NULL, base_uri);
+ if(!element1)
+ goto tidy;
+
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 2);
+ raptor_xml_writer_start_element(xml_writer, element1);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ if(rasqal_query_results_is_bindings(results)) {
+ for(i=0; 1; i++) {
+ const unsigned char *name;
+ name=rasqal_query_results_get_binding_name(results, i);
+ if(!name)
+ break;
+
+ /* <variable name="x"/> */
+ variable_element=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"variable",
+ NULL, base_uri);
+ if(!variable_element)
+ goto tidy;
+
+ attrs=(raptor_qname **)raptor_alloc_memory(sizeof(raptor_qname*));
+ if(!attrs)
+ goto tidy;
+#ifdef RAPTOR_V2_AVAILABLE
+ attrs[0] = raptor_new_qname_from_namespace_local_name_v2(query->world->raptor_world_ptr,
+ res_ns,
+ (const unsigned char*)"name",
+ (const unsigned char*)name); /* attribute value */
+#else
+ attrs[0] = raptor_new_qname_from_namespace_local_name(res_ns,
+ (const unsigned char*)"name",
+ (const unsigned char*)name); /* attribute value */
+#endif
+ if(!attrs[0]) {
+ raptor_free_memory((void*)attrs);
+ goto tidy;
+ }
+
+ raptor_xml_element_set_attributes(variable_element, attrs, 1);
+
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 4);
+ raptor_xml_writer_empty_element(xml_writer, variable_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ raptor_free_xml_element(variable_element);
+ variable_element=NULL;
+ }
+ }
+
+ /* FIXME - could add <link> inside <head> */
+
+
+ /* </head> */
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 2);
+ raptor_xml_writer_end_element(xml_writer, element1);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ raptor_free_xml_element(element1);
+ element1=NULL;
+
+
+ /* Boolean Results */
+ if(rasqal_query_results_is_boolean(results)) {
+ result_element=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"boolean",
+ NULL, base_uri);
+ if(!result_element)
+ goto tidy;
+
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 2);
+ raptor_xml_writer_start_element(xml_writer, result_element);
+ if(rasqal_query_results_get_boolean(results))
+ raptor_xml_writer_raw(xml_writer, RASQAL_XSD_BOOLEAN_TRUE);
+ else
+ raptor_xml_writer_raw(xml_writer, RASQAL_XSD_BOOLEAN_FALSE);
+ raptor_xml_writer_end_element(xml_writer, result_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ goto results3done;
+ }
+
+
+ /* Variable Binding Results */
+
+ /* <results> */
+ results_element=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"results",
+ NULL, base_uri);
+ if(!results_element)
+ goto tidy;
+
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 2);
+ raptor_xml_writer_start_element(xml_writer, results_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+
+ /* declare result element for later multiple use */
+ result_element=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"result",
+ NULL, base_uri);
+ if(!result_element)
+ goto tidy;
+
+ while(!rasqal_query_results_finished(results)) {
+ /* <result> */
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 4);
+ raptor_xml_writer_start_element(xml_writer, result_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ for(i=0; i<rasqal_query_results_get_bindings_count(results); i++) {
+ const unsigned char *name=rasqal_query_results_get_binding_name(results, i);
+ rasqal_literal *l=rasqal_query_results_get_binding_value(results, i);
+
+ /* <binding> */
+ binding_element=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"binding",
+ NULL, base_uri);
+ if(!binding_element)
+ goto tidy;
+
+ attrs=(raptor_qname **)raptor_alloc_memory(sizeof(raptor_qname*));
+ if(!attrs)
+ goto tidy;
+#ifdef RAPTOR_V2_AVAILABLE
+ attrs[0] = raptor_new_qname_from_namespace_local_name_v2(query->world->raptor_world_ptr,
+ res_ns,
+ (const unsigned char*)"name",
+ name);
+
+#else
+ attrs[0] = raptor_new_qname_from_namespace_local_name(res_ns,
+ (const unsigned char*)"name",
+ name);
+#endif
+ if(!attrs[0]) {
+ raptor_free_memory((void*)attrs);
+ goto tidy;
+ }
+
+ raptor_xml_element_set_attributes(binding_element, attrs, 1);
+
+
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 6);
+ raptor_xml_writer_start_element(xml_writer, binding_element);
+
+ if(!l) {
+ element1=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"unbound",
+ NULL, base_uri);
+ if(!element1)
+ goto tidy;
+ raptor_xml_writer_empty_element(xml_writer, element1);
+
+ } else switch(l->type) {
+ case RASQAL_LITERAL_URI:
+ element1=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"uri",
+ NULL, base_uri);
+ if(!element1)
+ goto tidy;
+
+ raptor_xml_writer_start_element(xml_writer, element1);
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_xml_writer_cdata(xml_writer, (const unsigned char*)raptor_uri_as_string_v2(query->world->raptor_world_ptr, l->value.uri));
+#else
+ raptor_xml_writer_cdata(xml_writer, (const unsigned char*)raptor_uri_as_string(l->value.uri));
+#endif
+ raptor_xml_writer_end_element(xml_writer, element1);
+
+ break;
+
+ case RASQAL_LITERAL_BLANK:
+ element1=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"bnode",
+ NULL, base_uri);
+ if(!element1)
+ goto tidy;
+
+ raptor_xml_writer_start_element(xml_writer, element1);
+ raptor_xml_writer_cdata(xml_writer, (const unsigned char*)l->string);
+ raptor_xml_writer_end_element(xml_writer, element1);
+ break;
+
+ case RASQAL_LITERAL_STRING:
+ element1=raptor_new_xml_element_from_namespace_local_name(res_ns,
+ (const unsigned char*)"literal",
+ NULL, base_uri);
+ if(!element1)
+ goto tidy;
+
+ if(l->language || l->datatype) {
+ attrs=(raptor_qname **)raptor_alloc_memory(sizeof(raptor_qname*));
+ if(!attrs)
+ goto tidy;
+
+ if(l->language)
+ attrs[0]=raptor_new_qname(nstack,
+ (const unsigned char*)"xml:lang",
+ (const unsigned char*)l->language,
+ (raptor_simple_message_handler)rasqal_query_simple_error, query);
+ else
+#ifdef RAPTOR_V2_AVAILABLE
+ attrs[0] = raptor_new_qname_from_namespace_local_name_v2(query->world->raptor_world_ptr,
+ res_ns,
+ (const unsigned char*)"datatype",
+ (const unsigned char*)raptor_uri_as_string_v2(query->world->raptor_world_ptr,
+ l->datatype));
+#else
+ attrs[0] = raptor_new_qname_from_namespace_local_name(res_ns,
+ (const unsigned char*)"datatype",
+ (const unsigned char*)raptor_uri_as_string(l->datatype));
+#endif
+ if(!attrs[0]) {
+ raptor_free_memory((void*)attrs);
+ goto tidy;
+ }
+
+ raptor_xml_element_set_attributes(element1, attrs, 1);
+ }
+
+
+ raptor_xml_writer_start_element(xml_writer, element1);
+
+
+ raptor_xml_writer_cdata_counted(xml_writer,
+ (const unsigned char*)l->string,
+ l->string_len);
+
+ raptor_xml_writer_end_element(xml_writer, element1);
+
+ break;
+ case RASQAL_LITERAL_PATTERN:
+ case RASQAL_LITERAL_QNAME:
+ case RASQAL_LITERAL_INTEGER:
+ case RASQAL_LITERAL_BOOLEAN:
+ case RASQAL_LITERAL_DOUBLE:
+ case RASQAL_LITERAL_FLOAT:
+ case RASQAL_LITERAL_VARIABLE:
+ case RASQAL_LITERAL_DECIMAL:
+ case RASQAL_LITERAL_DATETIME:
+
+ case RASQAL_LITERAL_UNKNOWN:
+ default:
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Cannot turn literal type %d into XML",
+ l->type);
+ goto tidy;
+ }
+
+ if(element1) {
+ raptor_free_xml_element(element1);
+ element1=NULL;
+ }
+
+ /* </binding> */
+ raptor_xml_writer_end_element(xml_writer, binding_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ raptor_free_xml_element(binding_element);
+ binding_element=NULL;
+ }
+
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 4);
+ raptor_xml_writer_end_element(xml_writer, result_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ rasqal_query_results_next(results);
+ }
+
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" ", 2);
+ raptor_xml_writer_end_element(xml_writer, results_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ results3done:
+
+ rc=0;
+
+ raptor_xml_writer_end_element(xml_writer, sparql_element);
+ raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
+
+ tidy:
+ if(element1)
+ raptor_free_xml_element(element1);
+ if(variable_element)
+ raptor_free_xml_element(variable_element);
+ if(binding_element)
+ raptor_free_xml_element(binding_element);
+ if(result_element)
+ raptor_free_xml_element(result_element);
+ if(results_element)
+ raptor_free_xml_element(results_element);
+ if(sparql_element)
+ raptor_free_xml_element(sparql_element);
+ if(res_ns)
+ raptor_free_namespace(res_ns);
+ if(xml_writer)
+ raptor_free_xml_writer(xml_writer);
+ if(nstack)
+ raptor_free_namespaces(nstack);
+
+ return rc;
+}
+
+
+const char* const sparql_xml_element_names[]=
+{
+ "!",
+ /* In rough order they appear */
+ "sparql",
+ "head",
+ "binding",
+ "variable",
+ "results",
+ "result",
+ "bnode",
+ "literal",
+ "uri",
+ NULL
+};
+
+
+typedef enum
+{
+ STATE_unknown,
+ /* In same order as above */
+ STATE_sparql,
+ STATE_head,
+ STATE_binding,
+ STATE_variable,
+ STATE_results,
+ STATE_result,
+ STATE_bnode,
+ STATE_literal,
+ STATE_uri,
+ STATE_first = STATE_sparql,
+ STATE_last = STATE_uri
+} rasqal_sparql_xml_read_state;
+
+
+typedef struct
+{
+ rasqal_world* world;
+ rasqal_rowsource* rowsource;
+
+ int failed;
+#ifdef TRACE_XML
+ int trace;
+#endif
+
+ /* Input fields */
+ raptor_uri* base_uri;
+ raptor_iostream* iostr;
+
+ /* SAX2 fields */
+ raptor_sax2* sax2;
+ raptor_locator locator;
+ int depth; /* element depth */
+ raptor_error_handlers error_handlers; /* SAX2 error handler */
+
+ /* SPARQL XML Results parsing */
+ rasqal_sparql_xml_read_state state; /* state */
+ /* state-based fields for turning XML into rasqal literals, rows */
+ const char* name; /* variable name (from binding/@name) */
+ size_t name_length;
+ char* value; /* URI string, literal string or blank node ID */
+ size_t value_len;
+ const char* datatype; /* literal datatype URI string from literal/@datatype */
+ const char* language; /* literal language from literal/@xml:lang */
+ rasqal_row* row; /* current result row */
+ int offset; /* current result row number */
+ int result_offset; /* current <result> column number */
+ unsigned char buffer[FILE_READ_BUF_SIZE]; /* iostream read buffer */
+
+ /* Output fields */
+ raptor_sequence* results_sequence; /* saved result rows */
+
+ /* Variables table allocated for variables in the result set */
+ rasqal_variables_table* vars_table;
+ int variables_count;
+} rasqal_rowsource_sparql_xml_context;
+
+
+#ifdef TRACE_XML
+static void
+pad(FILE* fh, int depth)
+{
+ int i;
+ for(i=0; i< depth; i++)
+ fputs(" ", fh);
+}
+#endif
+
+static void
+rasqal_sparql_xml_sax2_start_element_handler(void *user_data,
+ raptor_xml_element *xml_element)
+{
+ rasqal_rowsource_sparql_xml_context* con;
+ int i;
+ raptor_qname* name;
+ rasqal_sparql_xml_read_state state=STATE_unknown;
+ int attr_count;
+
+ con=(rasqal_rowsource_sparql_xml_context*)user_data;
+
+ name=raptor_xml_element_get_name(xml_element);
+
+ for(i=STATE_first; i <= STATE_last; i++) {
+ if(!strcmp((const char*)raptor_qname_get_local_name(name),
+ sparql_xml_element_names[i])) {
+ state=(rasqal_sparql_xml_read_state)i;
+ con->state=state;
+ }
+ }
+
+ if(state == STATE_unknown) {
+ fprintf(stderr, "UNKNOWN element %s\n", raptor_qname_get_local_name(name));
+ con->failed++;
+ }
+
+#ifdef TRACE_XML
+ if(con->trace) {
+ pad(stderr, con->depth);
+ fprintf(stderr, "Element %s (%d)\n", raptor_qname_get_local_name(name),
+ state);
+ }
+#endif
+
+ attr_count=raptor_xml_element_get_attributes_count(xml_element);
+ con->name=NULL;
+ con->datatype=NULL;
+ con->language=NULL;
+
+ if(attr_count > 0) {
+ raptor_qname** attrs=raptor_xml_element_get_attributes(xml_element);
+ for(i=0; i < attr_count; i++) {
+#ifdef TRACE_XML
+ if(con->trace) {
+ pad(stderr, con->depth+1);
+ fprintf(stderr, "Attribute %s='%s'\n",
+ raptor_qname_get_local_name(attrs[i]),
+ raptor_qname_get_value(attrs[i]));
+ }
+#endif
+ if(!strcmp((const char*)raptor_qname_get_local_name(attrs[i]),
+ "name"))
+ con->name=(const char*)raptor_qname_get_counted_value(attrs[i],
+ &con->name_length);
+ else if(!strcmp((const char*)raptor_qname_get_local_name(attrs[i]),
+ "datatype"))
+ con->datatype=(const char*)raptor_qname_get_value(attrs[i]);
+ }
+ }
+ if(raptor_xml_element_get_language(xml_element)) {
+ con->language=(const char*)raptor_xml_element_get_language(xml_element);
+#ifdef TRACE_XML
+ if(con->trace) {
+ pad(stderr, con->depth+1);
+ fprintf(stderr, "xml:lang '%s'\n", con->language);
+ }
+#endif
+ }
+
+ switch(state) {
+ case STATE_variable:
+ if(1) {
+ unsigned char* var_name;
+ rasqal_variable *v;
+
+ var_name = (unsigned char*)RASQAL_MALLOC(cstring, con->name_length+1);
+ strncpy((char*)var_name, con->name, con->name_length+1);
+
+ v = rasqal_variables_table_add(con->vars_table,
+ RASQAL_VARIABLE_TYPE_NORMAL,
+ var_name, NULL);
+ if(v)
+ rasqal_rowsource_add_variable(con->rowsource, v);
+ }
+ break;
+
+ case STATE_result:
+ if(1) {
+ con->row=rasqal_new_row(con->rowsource);
+ RASQAL_DEBUG2("Made new row %d\n", con->offset);
+ con->offset++;
+ }
+ break;
+
+ case STATE_binding:
+ con->result_offset = rasqal_rowsource_get_variable_offset_by_name(con->rowsource, (const unsigned char*)con->name);
+ break;
+
+ case STATE_sparql:
+ case STATE_head:
+ case STATE_results:
+ case STATE_literal:
+ case STATE_bnode:
+ case STATE_uri:
+ case STATE_unknown:
+ default:
+ break;
+ }
+
+ con->depth++;
+}
+
+
+static void
+rasqal_sparql_xml_sax2_characters_handler(void *user_data,
+ raptor_xml_element* xml_element,
+ const unsigned char *s, int len)
+{
+ rasqal_rowsource_sparql_xml_context* con;
+ con=(rasqal_rowsource_sparql_xml_context*)user_data;
+
+#ifdef TRACE_XML
+ if(con->trace) {
+ pad(stderr, con->depth);
+ fputs("Text '", stderr);
+ fwrite(s, sizeof(char), len, stderr);
+ fprintf(stderr, "' (%d bytes)\n", len);
+ }
+#endif
+
+ if(con->state == STATE_literal ||
+ con->state == STATE_uri ||
+ con->state == STATE_bnode) {
+ con->value_len=len;
+ con->value=(char*)RASQAL_MALLOC(cstring, len+1);
+ memcpy(con->value, s, len);
+ con->value[len]='\0';
+ }
+}
+
+
+static void
+rasqal_sparql_xml_sax2_end_element_handler(void *user_data,
+ raptor_xml_element* xml_element)
+{
+ rasqal_rowsource_sparql_xml_context* con;
+ raptor_qname* name;
+ int i;
+ rasqal_sparql_xml_read_state state=STATE_unknown;
+
+ con=(rasqal_rowsource_sparql_xml_context*)user_data;
+
+ name=raptor_xml_element_get_name(xml_element);
+
+ for(i=STATE_first; i <= STATE_last; i++) {
+ if(!strcmp((const char*)raptor_qname_get_local_name(name),
+ sparql_xml_element_names[i])) {
+ state=(rasqal_sparql_xml_read_state)i;
+ con->state=state;
+ }
+ }
+
+ if(state == STATE_unknown) {
+ fprintf(stderr, "UNKNOWN element %s\n", raptor_qname_get_local_name(name));
+ con->failed++;
+ }
+
+ con->depth--;
+#ifdef TRACE_XML
+ if(con->trace) {
+ pad(stderr, con->depth);
+ fprintf(stderr, "End Element %s (%d)\n", raptor_qname_get_local_name(name),
+ con->state);
+ }
+#endif
+
+ switch(con->state) {
+ case STATE_head:
+ /* Only now is the full number of variables known */
+ con->variables_count = rasqal_variables_table_get_named_variables_count(con->vars_table);
+ con->rowsource->size = con->variables_count;
+ break;
+
+ case STATE_literal:
+ if(1) {
+ rasqal_literal* l;
+ unsigned char* lvalue;
+ raptor_uri* datatype_uri=NULL;
+ char* language_str=NULL;
+
+ lvalue=(unsigned char*)RASQAL_MALLOC(cstring, con->value_len+1);
+ strncpy((char*)lvalue, con->value, con->value_len+1);
+ if(con->datatype)
+#ifdef RAPTOR_V2_AVAILABLE
+ datatype_uri = raptor_new_uri_v2(con->world->raptor_world_ptr, (const unsigned char*)con->datatype);
+#else
+ datatype_uri = raptor_new_uri((const unsigned char*)con->datatype);
+#endif
+ if(con->language) {
+ language_str=(char*)RASQAL_MALLOC(cstring, strlen(con->language)+1);
+ strcpy(language_str, con->language);
+ }
+ l=rasqal_new_string_literal_node(con->world, lvalue, language_str, datatype_uri);
+ rasqal_row_set_value_at(con->row, con->result_offset, l);
+ RASQAL_DEBUG3("Saving row result %d string value at offset %d\n",
+ con->offset, con->result_offset);
+ }
+ break;
+
+ case STATE_bnode:
+ if(1) {
+ rasqal_literal* l;
+ unsigned char* lvalue;
+ lvalue=(unsigned char*)RASQAL_MALLOC(cstring, con->value_len+1);
+ strncpy((char*)lvalue, con->value, con->value_len+1);
+ l=rasqal_new_simple_literal(con->world, RASQAL_LITERAL_BLANK, lvalue);
+ rasqal_row_set_value_at(con->row, con->result_offset, l);
+ RASQAL_DEBUG3("Saving row result %d bnode value at offset %d\n",
+ con->offset, con->result_offset);
+ }
+ break;
+
+ case STATE_uri:
+ if(1) {
+ raptor_uri* uri;
+ rasqal_literal* l;
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_new_uri_v2(con->world->raptor_world_ptr, (const unsigned char*)con->value);
+#else
+ uri = raptor_new_uri((const unsigned char*)con->value);
+#endif
+ l = rasqal_new_uri_literal(con->world, uri);
+ rasqal_row_set_value_at(con->row, con->result_offset, l);
+ RASQAL_DEBUG3("Saving row result %d uri value at offset %d\n",
+ con->offset, con->result_offset);
+ }
+ break;
+
+ case STATE_result:
+ if(con->row) {
+ RASQAL_DEBUG2("Saving row result %d\n", con->offset);
+ raptor_sequence_push(con->results_sequence, con->row);
+ }
+ con->row=NULL;
+ break;
+
+ case STATE_unknown:
+ case STATE_sparql:
+ case STATE_variable:
+ case STATE_results:
+ case STATE_binding:
+ default:
+ break;
+ }
+
+ if(con->value) {
+ RASQAL_FREE(cstring, con->value);
+ con->value=NULL;
+ }
+}
+
+
+/* Local handlers for turning sparql XML read from an iostream into rows */
+
+static int
+rasqal_rowsource_sparql_xml_init(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_rowsource_sparql_xml_context* con;
+
+ con=(rasqal_rowsource_sparql_xml_context*)user_data;
+
+ con->rowsource=rowsource;
+ con->state=STATE_unknown;
+
+#ifdef TRACE_XML
+ con->trace=1;
+#endif
+ con->depth=0;
+
+ raptor_sax2_parse_start(con->sax2, con->base_uri);
+
+ return 0;
+}
+
+static int
+rasqal_rowsource_sparql_xml_finish(rasqal_rowsource* rowsource, void *user_data)
+{
+ rasqal_rowsource_sparql_xml_context* con;
+
+ con=(rasqal_rowsource_sparql_xml_context*)user_data;
+
+ if(con->base_uri)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(con->world->raptor_world_ptr, con->base_uri);
+#else
+ raptor_free_uri(con->base_uri);
+#endif
+
+ if(con->sax2)
+ raptor_free_sax2(con->sax2);
+
+ if(con->results_sequence)
+ raptor_free_sequence(con->results_sequence);
+
+ if(con->vars_table)
+ rasqal_free_variables_table(con->vars_table);
+
+ RASQAL_FREE(rasqal_rowsource_sparql_xml_context, con);
+
+ return 0;
+}
+
+
+static void
+rasqal_rowsource_sparql_xml_process(rasqal_rowsource_sparql_xml_context* con)
+{
+ if(raptor_sequence_size(con->results_sequence) && con->variables_count > 0)
+ return;
+
+ /* do some parsing - need some results */
+ while(!raptor_iostream_read_eof(con->iostr)) {
+ size_t read_len;
+
+ read_len=raptor_iostream_read_bytes(con->iostr, (char*)con->buffer,
+ 1, FILE_READ_BUF_SIZE);
+ if(read_len > 0) {
+ RASQAL_DEBUG2("processing %d bytes\n", (int)read_len);
+ raptor_sax2_parse_chunk(con->sax2, con->buffer, read_len, 0);
+ con->locator.byte += read_len;
+ }
+
+ if(read_len < FILE_READ_BUF_SIZE) {
+ /* finished */
+ raptor_sax2_parse_chunk(con->sax2, NULL, 0, 1);
+ break;
+ }
+
+ /* end with variables sequence done AND at least one row */
+ if(con->variables_count > 0 &&
+ raptor_sequence_size(con->results_sequence) > 0)
+ break;
+ }
+
+}
+
+
+static int
+rasqal_rowsource_sparql_xml_ensure_variables(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_rowsource_sparql_xml_context* con;
+
+ con = (rasqal_rowsource_sparql_xml_context*)user_data;
+
+ rasqal_rowsource_sparql_xml_process(con);
+
+ return con->failed;
+}
+
+
+static rasqal_row*
+rasqal_rowsource_sparql_xml_read_row(rasqal_rowsource* rowsource,
+ void *user_data)
+{
+ rasqal_rowsource_sparql_xml_context* con;
+ rasqal_row* row=NULL;
+
+ con=(rasqal_rowsource_sparql_xml_context*)user_data;
+
+ rasqal_rowsource_sparql_xml_process(con);
+
+ if(!con->failed && raptor_sequence_size(con->results_sequence) > 0) {
+ RASQAL_DEBUG1("getting row from stored sequence\n");
+ row=(rasqal_row*)raptor_sequence_unshift(con->results_sequence);
+ }
+
+ return row;
+}
+
+
+static const rasqal_rowsource_handler rasqal_rowsource_sparql_xml_handler={
+ /* .version = */ 1,
+ "SPARQL XML",
+ /* .init = */ rasqal_rowsource_sparql_xml_init,
+ /* .finish = */ rasqal_rowsource_sparql_xml_finish,
+ /* .ensure_variables = */ rasqal_rowsource_sparql_xml_ensure_variables,
+ /* .read_row = */ rasqal_rowsource_sparql_xml_read_row,
+ /* .read_all_rows = */ NULL,
+ /* .get_query = */ NULL
+};
+
+
+
+/*
+ * rasqal_query_results_getrowsource_sparql_xml:
+ * @world: rasqal world object
+ * @iostr: #raptor_iostream to read the query results from
+ * @base_uri: #raptor_uri base URI of the input format
+ *
+ * Read the fourth version of the SPARQL XML query results format from an
+ * iostream in a format returning a rwosurce - INTERNAL.
+ *
+ * Return value: a new rasqal_rowsource or NULL on failure
+ **/
+static rasqal_rowsource*
+rasqal_query_results_get_rowsource_sparql_xml(rasqal_world *world,
+ rasqal_variables_table* vars_table,
+ raptor_iostream *iostr,
+ raptor_uri *base_uri)
+{
+ rasqal_rowsource_sparql_xml_context* con;
+
+ con=(rasqal_rowsource_sparql_xml_context*)RASQAL_CALLOC(rasqal_rowsource_sparql_xml_context, 1, sizeof(rasqal_rowsource_sparql_xml_context));
+ if(!con)
+ return NULL;
+
+ con->world=world;
+#ifdef RAPTOR_V2_AVAILABLE
+ con->base_uri = base_uri ? raptor_uri_copy_v2(world->raptor_world_ptr, base_uri) : NULL;
+#else
+ con->base_uri = base_uri ? raptor_uri_copy(base_uri) : NULL;
+#endif
+ con->iostr=iostr;
+
+ con->locator.uri=base_uri;
+
+ con->error_handlers.locator=&con->locator;
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_error_handlers_init_v2(world->raptor_world_ptr, &con->error_handlers);
+#else
+ raptor_error_handlers_init(&con->error_handlers);
+#endif
+
+ con->sax2=raptor_new_sax2(con, &con->error_handlers);
+ if(!con->sax2)
+ return NULL;
+
+ raptor_sax2_set_start_element_handler(con->sax2,
+ rasqal_sparql_xml_sax2_start_element_handler);
+ raptor_sax2_set_characters_handler(con->sax2,
+ rasqal_sparql_xml_sax2_characters_handler);
+ raptor_sax2_set_characters_handler(con->sax2,
+ (raptor_sax2_characters_handler)rasqal_sparql_xml_sax2_characters_handler);
+
+ raptor_sax2_set_end_element_handler(con->sax2,
+ rasqal_sparql_xml_sax2_end_element_handler);
+
+ con->results_sequence=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_row, (raptor_sequence_print_handler*)rasqal_row_print);
+
+ con->vars_table = rasqal_new_variables_table_from_variables_table(vars_table);
+
+ return rasqal_new_rowsource_from_handler(world, NULL,
+ con,
+ &rasqal_rowsource_sparql_xml_handler,
+ con->vars_table,
+ 0);
+}
+
+
+
+int
+rasqal_init_result_format_sparql_xml(rasqal_world* world)
+{
+ rasqal_query_results_formatter_func writer_fn=NULL;
+ rasqal_query_results_formatter_func reader_fn=NULL;
+ rasqal_query_results_get_rowsource_func get_rowsource_fn=NULL;
+ int rc=0;
+
+ /*
+ * SPARQL XML Results 2007-06-14
+ * http://www.w3.org/TR/2006/WD-rdf-sparql-XMLres-20070614/
+ */
+ writer_fn=&rasqal_query_results_write_sparql_xml;
+ reader_fn=NULL,
+ get_rowsource_fn=&rasqal_query_results_get_rowsource_sparql_xml;
+ rc+= rasqal_query_results_format_register_factory(world,
+ "xml",
+ "SPARQL Query Results Format 2007-06-14",
+ (unsigned char*)"http://www.w3.org/2005/sparql-results#",
+ writer_fn, reader_fn, get_rowsource_fn,
+ "application/sparql-results+xml")
+ != 0;
+ rc+= rasqal_query_results_format_register_factory(world,
+ NULL,
+ NULL,
+ (unsigned char*)"http://www.w3.org/TR/2006/WD-rdf-sparql-XMLres-20070614/",
+ writer_fn, reader_fn, get_rowsource_fn,
+ "application/sparql-results+xml")
+ != 0;
+ return rc;
+}
+
diff --git a/src/rasqal/rasqal_triples_source.c b/src/rasqal/rasqal_triples_source.c
new file mode 100644
index 0000000..02750c2
--- /dev/null
+++ b/src/rasqal/rasqal_triples_source.c
@@ -0,0 +1,236 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_triples_source.c - Rasqal triples source matching TP against triples
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+/**
+ * rasqal_set_triples_source_factory:
+ * @world: rasqal_world object
+ * @register_fn: registration function
+ * @user_data: user data for registration
+ *
+ * Register the factory to return triple sources.
+ *
+ * Registers the factory that returns triples sources. Note that
+ * there is only one of these per runtime.
+ *
+ * The rasqal_triples_source_factory factory method new_triples_source is
+ * called with the user data for some query and rasqal_triples_source.
+ *
+ **/
+RASQAL_EXTERN_C
+void
+rasqal_set_triples_source_factory(rasqal_world* world, void (*register_fn)(rasqal_triples_source_factory *factory), void* user_data)
+{
+ world->triples_source_factory.user_data=user_data;
+ register_fn(&world->triples_source_factory);
+}
+
+
+/**
+ * rasqal_new_triples_source:
+ * @query: query
+ *
+ * INTERNAL - Create a new triples source
+ *
+ * Return value: a new triples source or NULL on failure
+ */
+rasqal_triples_source*
+rasqal_new_triples_source(rasqal_query* query)
+{
+ rasqal_triples_source_factory* rtsf = &query->world->triples_source_factory;
+ rasqal_triples_source* rts;
+ int rc=0;
+
+ rts = (rasqal_triples_source*)RASQAL_CALLOC(rasqal_triples_source, 1,
+ sizeof(rasqal_triples_source));
+ if(!rts)
+ return NULL;
+
+ rts->user_data = RASQAL_CALLOC(user_data, 1, rtsf->user_data_size);
+ if(!rts->user_data) {
+ RASQAL_FREE(rasqal_triples_source, rts);
+ return NULL;
+ }
+ rts->query = query;
+
+ rc = rtsf->new_triples_source(query, rtsf->user_data, rts->user_data, rts);
+ if(rc) {
+ if(rc > 0) {
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "Failed to make triples source.");
+ } else {
+ rasqal_log_error_simple(query->world, RAPTOR_LOG_LEVEL_ERROR,
+ &query->locator,
+ "No data to query.");
+ }
+ RASQAL_FREE(user_data, rts->user_data);
+ RASQAL_FREE(rasqal_triples_source, rts);
+ return NULL;
+ }
+
+ return rts;
+}
+
+
+void
+rasqal_free_triples_source(rasqal_triples_source *rts)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(rts, rasqal_triples_source);
+
+ if(rts->user_data) {
+ rts->free_triples_source(rts->user_data);
+ RASQAL_FREE(user_data, rts->user_data);
+ rts->user_data=NULL;
+ }
+
+ RASQAL_FREE(rasqal_triples_source, rts);
+}
+
+
+int
+rasqal_triples_source_triple_present(rasqal_triples_source *rts,
+ rasqal_triple *t)
+{
+ return rts->triple_present(rts, rts->user_data, t);
+}
+
+
+static void
+rasqal_free_triples_match(rasqal_triples_match* rtm)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(rtm, rasqal_triples_match);
+
+ rtm->finish(rtm, rtm->user_data);
+ RASQAL_FREE(rasqal_triples_match, rtm);
+}
+
+
+rasqal_triples_match*
+rasqal_new_triples_match(rasqal_query* query,
+ rasqal_triples_source* triples_source,
+ rasqal_triple_meta *m, rasqal_triple *t)
+{
+ rasqal_triples_match* rtm;
+
+ if(!triples_source)
+ return NULL;
+
+ rtm = (rasqal_triples_match *)RASQAL_CALLOC(rasqal_triples_match, 1,
+ sizeof(rasqal_triples_match));
+ if(rtm) {
+ rtm->world = query->world;
+ if(triples_source->init_triples_match(rtm, triples_source,
+ triples_source->user_data,
+ m, t)) {
+ rasqal_free_triples_match(rtm);
+ rtm = NULL;
+ }
+ }
+
+ return rtm;
+}
+
+
+/* methods */
+int
+rasqal_triples_match_bind_match(struct rasqal_triples_match_s* rtm,
+ rasqal_variable *bindings[4],
+ rasqal_triple_parts parts)
+{
+ return rtm->bind_match(rtm, rtm->user_data, bindings, parts);
+}
+
+
+void
+rasqal_triples_match_next_match(struct rasqal_triples_match_s* rtm)
+{
+ rtm->next_match(rtm, rtm->user_data);
+}
+
+
+int
+rasqal_triples_match_is_end(struct rasqal_triples_match_s* rtm)
+{
+ return rtm->is_end(rtm, rtm->user_data);
+}
+
+
+/**
+ * rasqal_reset_triple_meta:
+ * @m: Triple pattern metadata
+ *
+ * INTERNAL - reset the metadata associated with a triple pattern
+ *
+ * Return value: number of parts of the triple that were reset (0..4)
+ **/
+int
+rasqal_reset_triple_meta(rasqal_triple_meta* m)
+{
+ int resets=0;
+
+ if(m->triples_match) {
+ rasqal_free_triples_match(m->triples_match);
+ m->triples_match=NULL;
+ }
+
+ if(m->bindings[0] && (m->parts & RASQAL_TRIPLE_SUBJECT)) {
+ rasqal_variable_set_value(m->bindings[0], NULL);
+ resets++;
+ }
+ if(m->bindings[1] && (m->parts & RASQAL_TRIPLE_PREDICATE)) {
+ rasqal_variable_set_value(m->bindings[1], NULL);
+ resets++;
+ }
+ if(m->bindings[2] && (m->parts & RASQAL_TRIPLE_OBJECT)) {
+ rasqal_variable_set_value(m->bindings[2], NULL);
+ resets++;
+ }
+ if(m->bindings[3] && (m->parts & RASQAL_TRIPLE_ORIGIN)) {
+ rasqal_variable_set_value(m->bindings[3], NULL);
+ resets++;
+ }
+
+ m->executed=0;
+
+ return resets;
+}
diff --git a/src/rasqal/rasqal_variable.c b/src/rasqal/rasqal_variable.c
new file mode 100644
index 0000000..7b1e5f7
--- /dev/null
+++ b/src/rasqal/rasqal_variable.c
@@ -0,0 +1,688 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rasqal_variable.c - Rasqal variable support
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#ifdef RASQAL_REGEX_PCRE
+#include <pcre.h>
+#endif
+
+#ifdef RASQAL_REGEX_POSIX
+#include <sys/types.h>
+#include <regex.h>
+#endif
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+
+#ifndef STANDALONE
+
+
+/**
+ * rasqal_new_variable_typed:
+ * @rq: #rasqal_query to associate the variable with
+ * @type: variable type defined by enumeration rasqal_variable_type
+ * @name: variable name
+ * @value: variable #rasqal_literal value (or NULL)
+ *
+ * Constructor - Create a new typed Rasqal variable.
+ *
+ * The variable must be associated with a query, since variable
+ * names are only significant with a single query.
+ *
+ * The @name and @value become owned by the rasqal_variable structure
+ *
+ * Return value: a new #rasqal_variable or NULL on failure.
+ **/
+rasqal_variable*
+rasqal_new_variable_typed(rasqal_query* rq,
+ rasqal_variable_type type,
+ unsigned char *name, rasqal_literal *value)
+{
+ return rasqal_variables_table_add(rq->vars_table, type, name, value);
+}
+
+
+/**
+ * rasqal_new_variable:
+ * @rq: #rasqal_query to associate the variable with
+ * @name: variable name
+ * @value: variable #rasqal_literal value (or NULL)
+ *
+ * Constructor - Create a new Rasqal normal variable.
+ *
+ * The variable must be associated with a query, since variable
+ * names are only significant with a single query.
+ *
+ * This creates a regular variable that can be returned of type
+ * RASQAL_VARIABLE_TYPE_NORMAL. Use rasqal_new_variable_typed
+ * to create other variables.
+ *
+ * The @name and @value become owned by the rasqal_variable structure
+ *
+ * Return value: a new #rasqal_variable or NULL on failure.
+ **/
+rasqal_variable*
+rasqal_new_variable(rasqal_query* rq,
+ unsigned char *name, rasqal_literal *value)
+{
+ return rasqal_variables_table_add(rq->vars_table, RASQAL_VARIABLE_TYPE_NORMAL,
+ name, value);
+}
+
+
+/**
+ * rasqal_new_variable_from_variable:
+ * @v: #rasqal_variable to copy
+ *
+ * Copy Constructor - Create a new Rasqal variable from an existing one
+ *
+ * This does a deep copy of all variable fields
+ *
+ * Return value: a new #rasqal_variable or NULL on failure.
+ **/
+rasqal_variable*
+rasqal_new_variable_from_variable(rasqal_variable* v)
+{
+ rasqal_variable* new_v;
+ size_t name_len;
+ unsigned char *new_name;
+
+ new_v = (rasqal_variable*)RASQAL_CALLOC(rasqal_variable, 1,
+ sizeof(rasqal_variable));
+ if(!new_v)
+ return NULL;
+
+ name_len = strlen((const char*)v->name);
+ new_name = (unsigned char*)RASQAL_MALLOC(cstring, name_len+1);
+ if(!new_name) {
+ RASQAL_FREE(rasqal_variable, new_v);
+ return NULL;
+ }
+ memcpy(new_name, v->name, name_len+1);
+
+ new_v->name= new_name;
+ new_v->value= rasqal_new_literal_from_literal(v->value);
+ new_v->offset= v->offset;
+ new_v->type= v->type;
+ new_v->expression= rasqal_new_expression_from_expression(v->expression);
+
+ return new_v;
+}
+
+/**
+ * rasqal_free_variable:
+ * @v: #rasqal_variable object
+ *
+ * Destructor - Destroy a Rasqal variable object.
+ *
+ **/
+void
+rasqal_free_variable(rasqal_variable* v)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(v, rasqal_variable);
+
+ if(v->name)
+ RASQAL_FREE(cstring, (void*)v->name);
+ if(v->value)
+ rasqal_free_literal(v->value);
+ if(v->expression)
+ rasqal_free_expression(v->expression);
+ RASQAL_FREE(rasqal_variable, v);
+}
+
+
+/**
+ * rasqal_variable_write:
+ * @v: the #rasqal_variable object
+ * @iostr: the #raptor_iostream handle to write to
+ *
+ * Write a Rasqal variable to an iostream in a debug format.
+ *
+ * The write debug format may change in any release.
+ *
+ **/
+void
+rasqal_variable_write(rasqal_variable* v, raptor_iostream* iostr)
+{
+ if(v->type == RASQAL_VARIABLE_TYPE_ANONYMOUS)
+ raptor_iostream_write_counted_string(iostr, "anon-variable(", 14);
+ else
+ raptor_iostream_write_counted_string(iostr, "variable(", 9);
+ raptor_iostream_write_string(iostr, v->name);
+ if(v->expression) {
+ raptor_iostream_write_byte(iostr, '=');
+ rasqal_expression_write(v->expression, iostr);
+ }
+ if(v->value) {
+ raptor_iostream_write_byte(iostr, '=');
+ rasqal_literal_write(v->value, iostr);
+ }
+ raptor_iostream_write_byte(iostr, ')');
+}
+
+
+/**
+ * rasqal_variable_print:
+ * @v: the #rasqal_variable object
+ * @fh: the #FILE* handle to print to
+ *
+ * Print a Rasqal variable in a debug format.
+ *
+ * The print debug format may change in any release.
+ *
+ **/
+void
+rasqal_variable_print(rasqal_variable* v, FILE* fh)
+{
+ if(v->type == RASQAL_VARIABLE_TYPE_ANONYMOUS)
+ fprintf(fh, "anon-variable(%s", v->name);
+ else
+ fprintf(fh, "variable(%s", v->name);
+ if(v->expression) {
+ fputc('=', fh);
+ rasqal_expression_print(v->expression, fh);
+ }
+ if(v->value) {
+ fputc('=', fh);
+ rasqal_literal_print(v->value, fh);
+ }
+ fputc(')', fh);
+}
+
+
+/**
+ * rasqal_variable_set_value:
+ * @v: the #rasqal_variable object
+ * @l: the #rasqal_literal value to set (or NULL)
+ *
+ * Set the value of a Rasqal variable.
+ *
+ * The variable value is an input parameter and is copied in, not shared.
+ * If the variable value is NULL, any existing value is deleted.
+ *
+ **/
+void
+rasqal_variable_set_value(rasqal_variable* v, rasqal_literal* l)
+{
+ if(v->value)
+ rasqal_free_literal(v->value);
+ v->value = l;
+
+#ifdef RASQAL_DEBUG
+ if(!v->name)
+ RASQAL_FATAL1("variable has no name");
+ RASQAL_DEBUG2("setting variable %s to value ", v->name);
+ if(v->value)
+ rasqal_literal_print(v->value, stderr);
+ else
+ fputs("(NULL)", stderr);
+ fputc('\n', stderr);
+#endif
+}
+
+
+
+/*
+ * A table of variables with optional binding values
+ *
+ * variables are named or anonymous (cannot be selected).
+ */
+struct rasqal_variables_table_s {
+ rasqal_world* world;
+
+ /* usage/reference count */
+ int usage;
+
+ /* The variables of size @variables_count + @anon_variables_count
+ * shared pointers into @variables_sequence and @anon_variables_sequence
+ */
+ rasqal_variable** variables;
+
+ /* Named variables (owner) */
+ raptor_sequence* variables_sequence;
+ int variables_count;
+
+ /* Anonymous variables (owner) */
+ raptor_sequence* anon_variables_sequence;
+ int anon_variables_count;
+
+ /* array of variable names. The array is allocated here but the
+ * pointers are into the #variables_sequence above. It is only
+ * allocated if rasqal_variables_table_get_names() is called
+ * on demand, otherwise is NULL.
+ */
+ const unsigned char** variable_names;
+};
+
+
+
+rasqal_variables_table*
+rasqal_new_variables_table(rasqal_world* world)
+{
+ rasqal_variables_table* vt;
+
+ vt = (rasqal_variables_table*)RASQAL_CALLOC(rasqal_variables_table, 1,
+ sizeof(rasqal_variables_table));
+ if(!vt)
+ return NULL;
+
+ vt->usage = 1;
+ vt->world = world;
+
+ vt->variables_sequence = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_variable, (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!vt->variables_sequence)
+ goto tidy;
+
+ vt->anon_variables_sequence = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_variable, (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!vt->anon_variables_sequence)
+ goto tidy;
+
+ vt->variable_names = NULL;
+
+ return vt;
+
+ tidy:
+ rasqal_free_variables_table(vt);
+ vt = NULL;
+
+ return vt;
+}
+
+
+rasqal_variables_table*
+rasqal_new_variables_table_from_variables_table(rasqal_variables_table* vt)
+{
+ vt->usage++;
+ return vt;
+}
+
+
+void
+rasqal_free_variables_table(rasqal_variables_table* vt)
+{
+ RASQAL_ASSERT_OBJECT_POINTER_RETURN(vt, rasqal_variables_table);
+
+ if(--vt->usage)
+ return;
+
+ if(vt->variables)
+ RASQAL_FREE(vararray, vt->variables);
+
+ if(vt->anon_variables_sequence)
+ raptor_free_sequence(vt->anon_variables_sequence);
+
+ if(vt->variables_sequence)
+ raptor_free_sequence(vt->variables_sequence);
+
+ if(vt->variable_names)
+ RASQAL_FREE(cstrings, vt->variable_names);
+
+ RASQAL_FREE(rasqal_variables_table, vt);
+}
+
+
+/**
+ * rasqal_variables_table_add:
+ * @vt: #rasqal_variables_table to associate the variable with
+ * @type: variable type defined by enumeration rasqal_variable_type
+ * @name: variable name
+ * @value: variable #rasqal_literal value (or NULL)
+ *
+ * Constructor - Add a variable to the variables table
+ *
+ * The @name and @value become owned by the rasqal_variable structure
+ *
+ * Return value: a new #rasqal_variable or NULL on failure.
+ **/
+rasqal_variable*
+rasqal_variables_table_add(rasqal_variables_table* vt,
+ rasqal_variable_type type,
+ const unsigned char *name, rasqal_literal *value)
+{
+ int i;
+ rasqal_variable* v;
+ raptor_sequence* seq = NULL;
+ int* count_p = NULL;
+
+ if(!vt)
+ return NULL;
+
+ switch(type) {
+ case RASQAL_VARIABLE_TYPE_ANONYMOUS:
+ seq = vt->anon_variables_sequence;
+ count_p = &vt->anon_variables_count;
+ break;
+ case RASQAL_VARIABLE_TYPE_NORMAL:
+ seq = vt->variables_sequence;
+ count_p = &vt->variables_count;
+ break;
+
+ case RASQAL_VARIABLE_TYPE_UNKNOWN:
+ default:
+ RASQAL_DEBUG2("Unknown variable type %d", type);
+ return NULL;
+ }
+
+ for(i = 0; i < raptor_sequence_size(seq); i++) {
+ v = (rasqal_variable*)raptor_sequence_get_at(seq, i);
+ if(!strcmp((const char*)v->name, (const char*)name)) {
+ /* name already present, do not need a copy */
+ RASQAL_FREE(cstring, name);
+ return v;
+ }
+ }
+
+
+ v = (rasqal_variable*)RASQAL_CALLOC(rasqal_variable, 1,
+ sizeof(rasqal_variable));
+ if(v) {
+ v->type= type;
+ v->name= name;
+ v->value= value;
+ if(count_p)
+ v->offset= (*count_p);
+
+ if(seq && raptor_sequence_push(seq, v))
+ return NULL;
+
+ if(type == RASQAL_VARIABLE_TYPE_ANONYMOUS) {
+ /* new anon variable: add base offset */
+ v->offset += vt->variables_count;
+ } else {
+ /* new normal variable: move all anon variable offsets up 1 */
+ for(i = 0; i < vt->anon_variables_count; i++) {
+ rasqal_variable* anon_v;
+ anon_v = (rasqal_variable*)raptor_sequence_get_at(vt->anon_variables_sequence, i);
+ anon_v->offset++;
+ }
+ }
+
+
+ /* Increment count and free var names only after sequence push succeeded */
+ if(count_p)
+ (*count_p)++;
+
+ if(vt->variable_names) {
+ RASQAL_FREE(cstrings, vt->variable_names);
+ vt->variable_names = NULL;
+ }
+ } else {
+ RASQAL_FREE(cstring, name);
+ if(value)
+ rasqal_free_literal(value);
+ }
+
+ return v;
+}
+
+
+
+rasqal_variable*
+rasqal_variables_table_get(rasqal_variables_table* vt, int idx)
+{
+ raptor_sequence* seq = NULL;
+
+ if(idx < 0)
+ return NULL;
+
+ if(idx < vt->variables_count)
+ seq = vt->variables_sequence;
+ else {
+ idx -= vt->variables_count;
+ seq = vt->anon_variables_sequence;
+ }
+
+ return (rasqal_variable*)raptor_sequence_get_at(seq, idx);
+}
+
+
+rasqal_literal*
+rasqal_variables_table_get_value(rasqal_variables_table* vt, int idx)
+{
+ rasqal_variable* v;
+ v = rasqal_variables_table_get(vt, idx);
+ if(!v)
+ return NULL;
+ return v->value;
+}
+
+
+rasqal_variable*
+rasqal_variables_table_get_by_name(rasqal_variables_table* vt,
+ const unsigned char *name)
+{
+ int i;
+ rasqal_variable* v;
+
+ for(i = 0; (v = rasqal_variables_table_get(vt, i)); i++) {
+ if(!strcmp((const char*)v->name, (const char*)name))
+ return v;
+ }
+ return NULL;
+}
+
+
+int
+rasqal_variables_table_has(rasqal_variables_table* vt,
+ const unsigned char *name)
+{
+ return (rasqal_variables_table_get_by_name(vt, name) != NULL);
+}
+
+
+int
+rasqal_variables_table_set(rasqal_variables_table* vt,
+ const unsigned char *name, rasqal_literal* value)
+{
+ rasqal_variable* v;
+
+ v = rasqal_variables_table_get_by_name(vt, name);
+ if(!v)
+ return 1;
+
+ rasqal_variable_set_value(v, value);
+ return 0;
+}
+
+
+int
+rasqal_variables_table_get_named_variables_count(rasqal_variables_table* vt)
+{
+ return vt->variables_count;
+}
+
+
+int
+rasqal_variables_table_get_anonymous_variables_count(rasqal_variables_table* vt)
+{
+ return vt->anon_variables_count;
+}
+
+
+int
+rasqal_variables_table_get_total_variables_count(rasqal_variables_table* vt)
+{
+ return vt->variables_count + vt->anon_variables_count;
+}
+
+
+raptor_sequence*
+rasqal_variables_table_get_named_variables_sequence(rasqal_variables_table* vt)
+{
+ return vt->variables_sequence;
+}
+
+
+raptor_sequence*
+rasqal_variables_table_get_anonymous_variables_sequence(rasqal_variables_table* vt)
+{
+ return vt->anon_variables_sequence;
+}
+
+
+const unsigned char**
+rasqal_variables_table_get_names(rasqal_variables_table* vt)
+{
+ int size = vt->variables_count;
+
+ if(!vt->variable_names && size) {
+ int i;
+
+ vt->variable_names = (const unsigned char**)RASQAL_CALLOC(cstrings, sizeof(unsigned char*), (size+1));
+ if(!vt->variable_names)
+ return NULL;
+
+ for(i = 0; i < size; i++) {
+ rasqal_variable* v;
+ v = (rasqal_variable*)raptor_sequence_get_at(vt->variables_sequence, i);
+ vt->variable_names[i] = v->name;
+ }
+ }
+
+ return vt->variable_names;
+}
+
+#endif /* not STANDALONE */
+
+
+
+#ifdef STANDALONE
+#include <stdio.h>
+
+int main(int argc, char *argv[]);
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = rasqal_basename(argv[0]);
+ rasqal_world* world = NULL;
+ rasqal_variables_table* vt = NULL;
+#define NUM_VARS 3
+ const char* var_names[NUM_VARS] = {"normal-null", "normal-value", "anon"};
+ unsigned char* names[NUM_VARS];
+ rasqal_variable* vars[NUM_VARS];
+ rasqal_literal *value = NULL;
+ int i;
+ int rc = 0;
+
+ world = rasqal_new_world();
+ if(!world || rasqal_world_open(world)) {
+ fprintf(stderr, "%s: rasqal_world init failed\n", program);
+ rc = 1;
+ goto tidy;
+ }
+
+ vt = rasqal_new_variables_table(world);
+ if(!vt) {
+ fprintf(stderr, "%s: Failed to make variables table\n", program);
+ rc = 1;
+ goto tidy;
+ }
+
+ for(i = 0; i < NUM_VARS; i++) {
+ size_t len = strlen(var_names[i]);
+ names[i] = (unsigned char*)malloc(len+1);
+ strncpy((char*)names[i], var_names[i], len+1);
+ }
+
+ vars[0] = rasqal_variables_table_add(vt, RASQAL_VARIABLE_TYPE_NORMAL,
+ names[0], NULL);
+ if(!vars[0]) {
+ fprintf(stderr, "%s: Failed to make normal variable with NULL value\n",
+ program);
+ rc = 1;
+ goto tidy;
+ } else {
+ /* now owned by vars[0] owned by vt */
+ names[0] = NULL;
+ }
+ /* vars[0] now owned by vt */
+
+ value = rasqal_new_double_literal(world, 42.0);
+ if(!value) {
+ fprintf(stderr, "%s: Failed to make double literal\n", program);
+ rc = 1;
+ goto tidy;
+ }
+ vars[1] = rasqal_variables_table_add(vt, RASQAL_VARIABLE_TYPE_NORMAL,
+ names[1], value);
+ if(!vars[1]) {
+ fprintf(stderr, "%s: Failed to make normal variable with literal value\n",
+ program);
+ rc = 1;
+ goto tidy;
+ } else {
+ /* now owned by vars[1] owned by vt */
+ names[1] = NULL;
+ value = NULL;
+ }
+ /* vars[1] now owned by vt */
+
+ vars[2] = rasqal_variables_table_add(vt, RASQAL_VARIABLE_TYPE_ANONYMOUS,
+ names[2], NULL);
+ if(!vars[2]) {
+ fprintf(stderr, "%s: Failed to make anonymous variable with NULL value\n",
+ program);
+ rc = 1;
+ goto tidy;
+ } else {
+ /* now owned by vars[2] owned by vt */
+ names[2] = NULL;
+ }
+ /* vars[2] now owned by vt */
+
+ tidy:
+ for(i = 0; i < NUM_VARS; i++) {
+ if(names[i])
+ free(names[i]);
+ }
+
+ if(value)
+ rasqal_free_literal(value);
+ if(vt)
+ rasqal_free_variables_table(vt);
+
+ if(world)
+ rasqal_free_world(world);
+
+ return 0;
+}
+#endif
diff --git a/src/rasqal/rasqal_xsd_datatypes.c b/src/rasqal/rasqal_xsd_datatypes.c
new file mode 100644
index 0000000..e79f060
--- /dev/null
+++ b/src/rasqal/rasqal_xsd_datatypes.c
@@ -0,0 +1,981 @@
+/*
+ * rasqal_xsd_datatypes.c - Rasqal XML Schema Datatypes support
+ *
+ * Copyright (C) 2005-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2005-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+#include <limits.h>
+
+#include "rasqal.h"
+#include "rasqal_internal.h"
+
+#if 0
+/* libxml2 datatypes */
+#ifdef HAVE_LIBXML_XMLSCHEMAS_H
+#include <libxml/xmlschemas.h>
+#include <libxml/xmlschemastypes.h>
+#include <libxml/schemasInternals.h>
+#endif
+#endif
+
+
+/*
+ *
+ * References
+ *
+ * XPath Functions and Operators
+ * http://www.w3.org/TR/xpath-functions/
+ *
+ * Datatypes hierarchy
+ * http://www.w3.org/TR/xpath-functions/#datatypes
+ *
+ * Casting
+ * http://www.w3.org/TR/xpath-functions/#casting-from-primitive-to-primitive
+ *
+ */
+
+
+#if 0
+#define RASQAL_XPFO_BASE_URI "http://www.w3.org/2004/07/xpath-functions"
+
+#define RASQAL_SPARQL_OP_NAMESPACE_URI "http://www.w3.org/2001/sw/DataAccess/operations"
+
+#define RASQAL_XSD_DATATYPES_SIZE 7
+
+typedef enum {
+ DT_dateTime,
+ DT_time,
+ DT_date,
+ DT_string,
+ DT_numeric,
+ DT_double,
+ DT_integer,
+} rasqal_xsd_datatype_id;
+#endif
+
+
+static int
+rasqal_xsd_check_boolean_format(const unsigned char* string, int flags)
+{
+ /* FIXME
+ * Strictly only {true, false, 1, 0} are allowed according to
+ * http://www.w3.org/TR/xmlschema-2/#boolean
+ */
+ if(!strcmp((const char*)string, "true") ||
+ !strcmp((const char*)string, "TRUE") ||
+ !strcmp((const char*)string, "1") ||
+ !strcmp((const char*)string, "false") ||
+ !strcmp((const char*)string, "FALSE") ||
+ !strcmp((const char*)string, "0"))
+ return 1;
+
+ return 0;
+}
+
+
+#define ADVANCE_OR_DIE(p) if(!*(++p)) return 0;
+
+
+/**
+ * rasqal_xsd_check_dateTime_format:
+ * @string: lexical form string
+ * flags: flags
+ *
+ * INTERNAL - Check an XSD dateTime lexical form
+ *
+ * Return value: non-0 if the string is valid
+ */
+static int
+rasqal_xsd_check_dateTime_format(const unsigned char* string, int flags)
+{
+ /* This should be correct according to
+ * http://www.w3.org/TR/xmlschema-2/#dateTime
+ */
+ return rasqal_xsd_datetime_check(string);
+}
+
+
+/**
+ * rasqal_xsd_check_decimal_format:
+ * @string: lexical form string
+ * flags: flags
+ *
+ * INTERNAL - Check an XSD decimal lexical form
+ *
+ * Return value: non-0 if the string is valid
+ */
+static int
+rasqal_xsd_check_decimal_format(const unsigned char* string, int flags)
+{
+ const char* p;
+
+ /* This should be correct according to
+ * http://www.w3.org/TR/xmlschema-2/#decimal
+ */
+ p=(const char*)string;
+ if(*p == '+' || *p == '-') {
+ ADVANCE_OR_DIE(p);
+ }
+
+ while(*p && isdigit(*p))
+ p++;
+ if(!*p)
+ return 1;
+ /* Fail if first non-digit is not '.' */
+ if(*p != '.')
+ return 0;
+ p++;
+
+ while(*p && isdigit(*p))
+ p++;
+ /* Fail if anything other than a digit seen before NUL */
+ if(*p)
+ return 0;
+
+ return 1;
+}
+
+
+/**
+ * rasqal_xsd_check_double_format:
+ * @string: lexical form string
+ * flags: flags
+ *
+ * INTERNAL - Check an XSD double lexical form
+ *
+ * Return value: non-0 if the string is valid
+ */
+static int
+rasqal_xsd_check_double_format(const unsigned char* string, int flags)
+{
+ /* FIXME validate using
+ * http://www.w3.org/TR/xmlschema-2/#double
+ */
+ double d=0.0;
+ char* eptr=NULL;
+
+ d=strtod((const char*)string, &eptr);
+ if((unsigned char*)eptr != string && *eptr=='\0')
+ return 1;
+
+ return 0;
+}
+
+
+/**
+ * rasqal_xsd_check_float_format:
+ * @string: lexical form string
+ * flags: flags
+ *
+ * INTERNAL - Check an XSD float lexical form
+ *
+ * Return value: non-0 if the string is valid
+ */
+static int
+rasqal_xsd_check_float_format(const unsigned char* string, int flags)
+{
+ /* FIXME validate using
+ * http://www.w3.org/TR/xmlschema-2/#float
+ */
+ double d=0.0;
+ char* eptr=NULL;
+
+ d=strtod((const char*)string, &eptr);
+ if((unsigned char*)eptr != string && *eptr=='\0')
+ return 1;
+
+ return 0;
+}
+
+
+/**
+ * rasqal_xsd_check_integer_format:
+ * @string: lexical form string
+ * flags: flags
+ *
+ * INTERNAL - Check an XSD integer lexical form
+ *
+ * Return value: non-0 if the string is valid
+ */
+static int
+rasqal_xsd_check_integer_format(const unsigned char* string, int flags)
+{
+ long int v;
+ char* eptr=NULL;
+
+ /* This should be correct according to
+ * http://www.w3.org/TR/xmlschema-2/#integer
+ */
+
+ v=(int)strtol((const char*)string, &eptr, 10);
+
+ if((unsigned char*)eptr != string && *eptr=='\0')
+ return 1;
+
+ return 0;
+}
+
+
+
+
+/**
+ * rasqal_xsd_format_double:
+ * @d: double
+ * @len_p: pointer to length of result or NULL
+ *
+ * INTERNAL - Format a new an xsd:double correctly
+ *
+ * Return value: new string or NULL on failure
+ */
+unsigned char*
+rasqal_xsd_format_double(double d, size_t *len_p)
+{
+ size_t e_index = 0;
+ size_t trailing_zero_start = 0;
+ size_t exponent_start;
+ size_t len=0;
+ unsigned char* buf=NULL;
+
+ if(d == 0.0f) {
+ len=5;
+ buf=(unsigned char*)RASQAL_MALLOC(cstring, len+1);
+ if(!buf)
+ return NULL;
+
+ strncpy((char*)buf, "0.0e0", len+1);
+ if(len_p)
+ *len_p=len;
+ return buf;
+ }
+
+ len=20;
+ buf=(unsigned char*)RASQAL_MALLOC(cstring, len+1);
+ if(!buf)
+ return NULL;
+
+ snprintf((char*)buf, len, "%1.14e", d);
+
+ /* find the 'e' and start of mantissa trailing zeros */
+
+ for( ; buf[e_index]; ++e_index) {
+ if(e_index > 0 && buf[e_index] == '0' && buf[e_index-1] != '0')
+ trailing_zero_start = e_index;
+ else if(buf[e_index] == 'e')
+ break;
+ }
+
+ if(buf[trailing_zero_start-1] == '.')
+ ++trailing_zero_start;
+
+ /* write an 'e' where the trailing zeros started */
+ buf[trailing_zero_start] = 'e';
+ if(buf[e_index+1] == '-') {
+ buf[trailing_zero_start+1] = '-';
+ ++trailing_zero_start;
+ }
+
+ exponent_start = e_index+2;
+ while(buf[exponent_start] == '0')
+ ++exponent_start;
+
+ len = strlen((const char*)buf);
+ if(exponent_start == len) {
+ len=trailing_zero_start+2;
+ buf[len-1] = '0';
+ buf[len] = '\0';
+ } else {
+ /* copy the exponent (minus leading zeros) after the new E */
+ memmove(buf+trailing_zero_start+1, buf+exponent_start,
+ len-trailing_zero_start);
+ len = strlen((const char*)buf);
+ }
+
+ if(len_p)
+ *len_p=len;
+
+ return buf;
+}
+
+
+typedef rasqal_literal* (*rasqal_extension_fn)(raptor_uri* name, raptor_sequence *args, char **error_p);
+
+
+typedef struct {
+ const unsigned char *name;
+ int min_nargs;
+ int max_nargs;
+ rasqal_extension_fn fn;
+ raptor_uri* uri;
+} rasqal_xsd_datatype_fn_info;
+
+
+#define XSD_INTEGER_DERIVED_COUNT 12
+#define XSD_INTEGER_DERIVED_FIRST (RASQAL_LITERAL_LAST_XSD+1)
+#define XSD_INTEGER_DERIVED_LAST (RASQAL_LITERAL_LAST_XSD + XSD_INTEGER_DERIVED_COUNT-1)
+
+/* atomic XSD literals + 12 types derived from xsd:integer plus a NULL */
+#define SPARQL_XSD_NAMES_COUNT (RASQAL_LITERAL_LAST_XSD+1 + XSD_INTEGER_DERIVED_COUNT)
+
+
+static const char* const sparql_xsd_names[SPARQL_XSD_NAMES_COUNT+1]=
+{
+ NULL, /* RASQAL_LITERAL_UNKNOWN */
+ NULL, /* ...BLANK */
+ NULL, /* ...URI */
+ "string",
+ "boolean",
+ "integer", /* may type-promote to xsd:decimal */
+ "double",
+ "float",
+ "decimal",
+ "dateTime",
+ /* all of the following always type-promote to xsd:integer */
+ "nonPositiveInteger", "negativeInteger",
+ "long", "int", "short", "byte",
+ "nonNegativeInteger", "unsignedLong", "postiveInteger",
+ "unsignedInt", "unsignedShort", "unsignedByte",
+ NULL
+};
+
+
+static int (*const sparql_xsd_checkfns[RASQAL_LITERAL_LAST_XSD-RASQAL_LITERAL_FIRST_XSD+1])(const unsigned char* string, int flags) =
+{
+ NULL, /* RASQAL_LITERAL_STRING */
+ rasqal_xsd_check_boolean_format, /* RASQAL_LITERAL_BOOLEAN */
+ rasqal_xsd_check_integer_format, /* RASQAL_LITERAL_INTEGER */
+ rasqal_xsd_check_double_format, /* RASQAL_LITERAL_DOUBLE */
+ rasqal_xsd_check_float_format, /* RASQAL_LITERAL_FLOAT */
+ rasqal_xsd_check_decimal_format, /* RASQAL_LITERAL_DECIMAL */
+ rasqal_xsd_check_dateTime_format /* RASQAL_LITERAL_DATETIME */
+};
+
+int
+rasqal_xsd_init(rasqal_world* world)
+{
+ int i;
+
+#ifdef RAPTOR_V2_AVAILABLE
+ world->xsd_namespace_uri = raptor_new_uri_v2(world->raptor_world_ptr, raptor_xmlschema_datatypes_namespace_uri);
+#else
+ world->xsd_namespace_uri = raptor_new_uri(raptor_xmlschema_datatypes_namespace_uri);
+#endif
+ if(!world->xsd_namespace_uri)
+ return 1;
+
+ world->xsd_datatype_uris=
+ (raptor_uri**)RASQAL_CALLOC(ptrarray,
+ SPARQL_XSD_NAMES_COUNT+1,
+ sizeof(raptor_uri*));
+ if(!world->xsd_datatype_uris)
+ return 1;
+
+ for(i=RASQAL_LITERAL_FIRST_XSD; i < SPARQL_XSD_NAMES_COUNT; i++) {
+ world->xsd_datatype_uris[i] =
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_new_uri_from_uri_local_name_v2(world->raptor_world_ptr, world->xsd_namespace_uri,
+ (const unsigned char *)sparql_xsd_names[i]);
+#else
+ raptor_new_uri_from_uri_local_name(world->xsd_namespace_uri,
+ (const unsigned char *)sparql_xsd_names[i]);
+#endif
+ if(!world->xsd_datatype_uris[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void
+rasqal_xsd_finish(rasqal_world* world)
+{
+ if(world->xsd_datatype_uris) {
+ int i;
+
+ for(i=RASQAL_LITERAL_FIRST_XSD; i < SPARQL_XSD_NAMES_COUNT; i++) {
+ if(world->xsd_datatype_uris[i])
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, world->xsd_datatype_uris[i]);
+#else
+ raptor_free_uri(world->xsd_datatype_uris[i]);
+#endif
+ }
+
+ RASQAL_FREE(table, world->xsd_datatype_uris);
+ world->xsd_datatype_uris = NULL;
+ }
+
+ if(world->xsd_namespace_uri) {
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, world->xsd_namespace_uri);
+#else
+ raptor_free_uri(world->xsd_namespace_uri);
+#endif
+ world->xsd_namespace_uri = NULL;
+ }
+}
+
+
+
+rasqal_literal_type
+rasqal_xsd_datatype_uri_to_type(rasqal_world* world, raptor_uri* uri)
+{
+ int i;
+ rasqal_literal_type native_type=RASQAL_LITERAL_UNKNOWN;
+
+ if(!uri || !world->xsd_datatype_uris)
+ return native_type;
+
+ for(i=(int)RASQAL_LITERAL_FIRST_XSD; i <= (int)RASQAL_LITERAL_LAST_XSD; i++) {
+ if(
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_equals_v2(world->raptor_world_ptr, uri, world->xsd_datatype_uris[i])
+#else
+ raptor_uri_equals(uri, world->xsd_datatype_uris[i])
+#endif
+ )
+ {
+ native_type=(rasqal_literal_type)i;
+ break;
+ }
+ }
+ return native_type;
+}
+
+
+rasqal_literal_type
+rasqal_xsd_datatype_uri_parent_type(rasqal_world* world, raptor_uri* uri)
+{
+ int i;
+ rasqal_literal_type parent_type=RASQAL_LITERAL_UNKNOWN;
+
+ if(!uri || !world->xsd_datatype_uris)
+ return parent_type;
+
+ /* xsd:integer parent is xsd:decimal */
+ if(
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_equals_v2(world->raptor_world_ptr, uri,
+ world->xsd_datatype_uris[RASQAL_LITERAL_INTEGER])
+#else
+ raptor_uri_equals(uri,
+ world->xsd_datatype_uris[RASQAL_LITERAL_INTEGER])
+#endif
+ )
+ return RASQAL_LITERAL_DECIMAL;
+
+ /* a pile of things have parent of xsd:integer */
+ for(i=(int)XSD_INTEGER_DERIVED_FIRST; i <= (int)XSD_INTEGER_DERIVED_LAST; i++) {
+ if(
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_equals_v2(world->raptor_world_ptr, uri, world->xsd_datatype_uris[i])
+#else
+ raptor_uri_equals(uri, world->xsd_datatype_uris[i])
+#endif
+ )
+ {
+ parent_type=RASQAL_LITERAL_INTEGER;
+ break;
+ }
+ }
+
+ return parent_type;
+}
+
+
+raptor_uri*
+rasqal_xsd_datatype_type_to_uri(rasqal_world* world, rasqal_literal_type type)
+{
+ if(world->xsd_datatype_uris &&
+ type >= RASQAL_LITERAL_FIRST_XSD && type <= (int)RASQAL_LITERAL_LAST_XSD)
+ return world->xsd_datatype_uris[(int)type];
+ return NULL;
+}
+
+
+/**
+ * rasqal_xsd_datatype_check:
+ * @native_type: rasqal XSD type
+ * @string: string
+ * @flags: check flags
+ *
+ * INTERNAL - check a string as a valid lexical form of an XSD datatype
+ *
+ * Return value: non-0 if the string is valid
+ */
+int
+rasqal_xsd_datatype_check(rasqal_literal_type native_type,
+ const unsigned char* string, int flags)
+{
+ /* calculate check function index in sparql_xsd_checkfns table */
+ int checkidx=native_type-RASQAL_LITERAL_FIRST_XSD;
+
+ /* test for index out of bounds and check function not defined */
+ if(checkidx < 0 || checkidx >= (int)(sizeof(sparql_xsd_checkfns)/sizeof(*sparql_xsd_checkfns)) ||
+ !sparql_xsd_checkfns[checkidx])
+ return 1;
+
+ return sparql_xsd_checkfns[checkidx](string, flags);
+}
+
+
+const char*
+rasqal_xsd_datatype_label(rasqal_literal_type native_type)
+{
+ return sparql_xsd_names[native_type];
+}
+
+
+int
+rasqal_xsd_is_datatype_uri(rasqal_world* world, raptor_uri* uri)
+{
+ return (rasqal_xsd_datatype_uri_to_type(world, uri) != RASQAL_LITERAL_UNKNOWN);
+}
+
+
+int
+rasqal_xsd_datatype_is_numeric(rasqal_literal_type type)
+{
+ return (type >= RASQAL_LITERAL_BOOLEAN && type <= RASQAL_LITERAL_DECIMAL);
+}
+
+
+
+#if 0
+static rasqal_literal*
+rasqal_xsd_datatypes_date_less_than(raptor_uri* name, raptor_sequence *args,
+ char **error_p) {
+ int error=0;
+ int b;
+ rasqal_literal* l1;
+ rasqal_literal* l2;
+
+ if(raptor_sequence_size(args) != 2)
+ return NULL;
+
+ l1=(rasqal_literal*)raptor_sequence_get_at(args, 0);
+ l2=(rasqal_literal*)raptor_sequence_get_at(args, 1);
+
+ b=(rasqal_literal_compare(l1, l2, 0, &error) < 0);
+ if(error)
+ return NULL;
+
+ return rasqal_new_boolean_literal(b);
+}
+
+
+static rasqal_literal*
+rasqal_xsd_datatypes_date_greater_than(raptor_uri* name, raptor_sequence *args,
+ char **error_p) {
+ int error=0;
+ int b;
+ rasqal_literal* l1;
+ rasqal_literal* l2;
+
+ if(raptor_sequence_size(args) != 2)
+ return NULL;
+
+ l1=(rasqal_literal*)raptor_sequence_get_at(args, 0);
+ l2=(rasqal_literal*)raptor_sequence_get_at(args, 1);
+
+ b=(rasqal_literal_compare(l1, l2, 0, &error) > 0);
+ if(error)
+ return NULL;
+
+ return rasqal_new_boolean_literal(b);
+}
+
+
+static rasqal_literal*
+rasqal_xsd_datatypes_date_equal(raptor_uri* name, raptor_sequence *args,
+ char **error_p) {
+ int error=0;
+ int b;
+ rasqal_literal* l1;
+ rasqal_literal* l2;
+
+ if(raptor_sequence_size(args) != 2)
+ return NULL;
+
+ l1=(rasqal_literal*)raptor_sequence_get_at(args, 0);
+ l2=(rasqal_literal*)raptor_sequence_get_at(args, 1);
+
+ b=(rasqal_literal_compare(l1, l2, 0, &error) == 0);
+ if(error)
+ return NULL;
+
+ return rasqal_new_boolean_literal(b);
+}
+
+
+#define RASQAL_XSD_DATATYPE_FNS_SIZE 9
+static rasqal_xsd_datatype_fn_info rasqal_xsd_datatype_fns[RASQAL_XSD_DATATYPE_FNS_SIZE]={
+ { (const unsigned char*)"date-less-than", 1, 1, rasqal_xsd_datatypes_date_less_than },
+ { (const unsigned char*)"dateTime-less-than", 1, 1, rasqal_xsd_datatypes_date_less_than },
+ { (const unsigned char*)"time-less-than", 1, 1, rasqal_xsd_datatypes_date_less_than },
+ { (const unsigned char*)"date-greater-than", 1, 1, rasqal_xsd_datatypes_date_greater_than },
+ { (const unsigned char*)"dateTime-greater-than", 1, 1, rasqal_xsd_datatypes_date_greater_than },
+ { (const unsigned char*)"time-greater-than", 1, 1, rasqal_xsd_datatypes_date_greater_than },
+ { (const unsigned char*)"date-equal", 1, 1, rasqal_xsd_datatypes_date_equal },
+ { (const unsigned char*)"dateTime-equal", 1, 1, rasqal_xsd_datatypes_date_equal },
+ { (const unsigned char*)"time-equal", 1, 1, rasqal_xsd_datatypes_date_equal }
+};
+
+
+
+static raptor_uri* raptor_xpfo_base_uri=NULL;
+static raptor_uri* rasqal_sparql_op_namespace_uri=NULL;
+
+
+static void
+rasqal_init_datatypes(void) {
+ int i;
+
+ raptor_xpfo_base_uri=raptor_new_uri((const unsigned char*)RASQAL_XPFO_BASE_URI);
+ rasqal_sparql_op_namespace_uri=raptor_new_uri((const unsigned char*)RASQAL_SPARQL_OP_NAMESPACE_URI);
+
+ for(i=0; i< RASQAL_XSD_DATATYPES_SIZE; i++) {
+ rasqal_xsd_datatypes[i].uri=raptor_new_uri_from_uri_local_name(raptor_xpfo_base_uri,
+ (const unsigned char*)rasqal_xsd_datatypes[i].name);
+ }
+
+ for(i=0; i< RASQAL_XSD_DATATYPE_FNS_SIZE; i++) {
+ rasqal_xsd_datatype_fns[i].uri=raptor_new_uri_from_uri_local_name(rasqal_sparql_op_namespace_uri,
+ rasqal_xsd_datatype_fns[i].name);
+ }
+
+}
+
+
+static void
+rasqal_finish_datatypes(void) {
+ int i;
+
+ for(i=0; i< RASQAL_XSD_DATATYPES_SIZE; i++)
+ if(rasqal_xsd_datatypes[i].uri)
+ raptor_free_uri(rasqal_xsd_datatypes[i].uri);
+
+ for(i=0; i< RASQAL_XSD_DATATYPE_FNS_SIZE; i++)
+ if(rasqal_xsd_datatype_fns[i].uri)
+ raptor_free_uri(rasqal_xsd_datatype_fns[i].uri);
+
+ if(raptor_xpfo_base_uri)
+ raptor_free_uri(raptor_xpfo_base_uri);
+
+ if(rasqal_sparql_op_namespace_uri)
+ raptor_free_uri(rasqal_sparql_op_namespace_uri);
+}
+#endif
+
+
+/*
+ *
+ * Facets
+ *
+ * Ordered
+ * [Definition:] A value space, and hence a datatype, is said to be
+ * ordered if there exists an order-relation defined for that
+ * value space.
+ * -- http://www.w3.org/TR/xmlschema-2/#dt-ordered
+ *
+ * Bounded
+ * [Definition:] A datatype is bounded if its value space has either
+ * an inclusive upper bound or an exclusive upper bound and either
+ * an inclusive lower bound or an exclusive lower bound.
+ * -- http://www.w3.org/TR/xmlschema-2/#dt-bounded
+ *
+ * Cardinality
+ * [Definition:] Every value space has associated with it the concept
+ * of cardinality. Some value spaces are finite, some are countably
+ * infinite while still others could conceivably be uncountably infinite
+ * (although no value space defined by this specification is
+ * uncountable infinite). A datatype is said to have the cardinality of
+ * its value space.
+ * -- http://www.w3.org/TR/xmlschema-2/#dt-cardinality
+ *
+ * Numeric
+ * [Definition:] A datatype is said to be numeric if its values are
+ * conceptually quantities (in some mathematical number system).
+ * -- http://www.w3.org/TR/xmlschema-2/#dt-numeric
+ */
+
+
+
+/*
+ * Types: dateTime, date, time
+ * http://www.w3.org/TR/xmlschema-2/#dateTime
+ * http://www.w3.org/TR/xmlschema-2/#date
+ * http://www.w3.org/TR/xmlschema-2/#time
+ * all (partial ordered, bounded, countably infinite, not numeric)
+ *
+ * Functions (all operators)
+ * op:date-equal, op:date-less-than, op:date-greater-than
+ *
+ * ??? dateTime equiv???
+ * op:dateTime-equal, op:dateTime-less-than, op:dateTime-greater-than
+ *
+ * ??? time equiv???
+ * op:time-equal, op:time-less-than, op:time-greater-than
+ */
+
+
+
+/*
+ * Type: string
+ * (not ordered, not bounded, countably infinite, not numeric)
+ *
+ * fn:contains
+ * Indicates whether one xs:string contains another xs:string. A
+ * collation may be specified.
+ *
+ * fn:starts-with
+ * Indicates whether the value of one xs:string begins with the
+ * collation units of another xs:string. A collation may be
+ * specified.
+ *
+ * fn:ends-with
+ * Indicates whether the value of one xs:string ends with the
+ * collation units of another xs:string. A collation may be
+ * specified.
+ *
+ * fn:substring-before
+ * Returns the collation units of one xs:string that precede in
+ * that xs:string the collation units of another xs:string. A
+ * collation may be specified.
+ *
+ * fn:substring-after
+ * Returns the collation units of xs:string that follow in that
+ * xs:string the collation units of another xs:string. A collation
+ * may be specified.
+ *
+ * fn:string-length
+ * Returns the length of the argument.
+ *
+ * fn:upper-case
+ * Returns the upper-cased value of the argument.
+ *
+ * fn:lower-case
+ * Returns the lower-cased value of the argument.
+ *
+ * fn:matches (input, pattern)
+ * fn:matches (input, pattern, flags)
+ *
+ * Returns an xs:boolean value that indicates whether the
+ * value of the first argument is matched by the regular expression that
+ * is the value of the second argument.
+ *
+ * flags = string of s,m,i,x char combinations ("" when omitted)
+ *
+ * Regular expressions: Perl5 syntax as defined in "Functions and
+ * Operators".
+ *
+ * http://www.w3.org/TR/xpath-functions/#func-contains
+ * http://www.w3.org/TR/xpath-functions/#func-starts-with
+ * http://www.w3.org/TR/xpath-functions/#func-ends-with
+ * http://www.w3.org/TR/xpath-functions/#func-substring-before
+ * http://www.w3.org/TR/xpath-functions/#func-substring-after
+ * http://www.w3.org/TR/xpath-functions/#func-string-length
+ * http://www.w3.org/TR/xpath-functions/#func-upper-case
+ * http://www.w3.org/TR/xpath-functions/#func-lower-case
+ * http://www.w3.org/TR/xpath-functions/#func-matches
+ *
+ * ??? no equality comparison fn:compare???
+ * fn:compare($comparand1 as xs:string, $comparand2 as xs:string) as xs:integer
+ * fn:compare($comparand1 as xs:string, $comparand2 as xs:string,
+ * $collation as xs:string) as xs:integer
+ * [[This function, invoked with the first signature, backs up the
+ * "eq", "ne", "gt", "lt", "le" and "ge" operators on string
+ * values.]]
+ *
+ */
+
+#if 0
+typedef struct
+{
+ unsigned char *string;
+ size_t length;
+} rasqal_xsd_string;
+#endif
+
+
+/*
+ * Type: double
+ * (partial ordered, bounded, countably infinite, numeric)
+ *
+ * Type: decimal
+ * (total ordered, not bounded, countably infinite, numeric)
+ *
+ * Derived Type: integer (derived from decimal)
+ * (total ordered, not bounded, countably infinite, numeric)
+ *
+ * Functions:
+ * 1 arguments
+ * op:numeric-unary-plus
+ * op:numeric-unary-minus
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-unary-plus
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-unary-minus
+ *
+ * 2 arguments
+ * op:numeric-equal
+ * op:numeric-less-than
+ * op:numeric-greater-than
+ * op:numeric-add
+ * op:numeric-subtract
+ * op:numeric-multiply
+ * op:numeric-divide
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-equal
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-less-than
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-greater-than
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-add
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-subtract
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-multiply
+ * http://www.w3.org/TR/xpath-functions/#func-numeric-divide
+ *
+ * [[The parameters and return types for the above operators are the
+ * basic numeric types: xs:integer, xs:decimal, xs:float and
+ * xs:double, and types derived from them. The word "numeric" in
+ * function signatures signifies these four types. For simplicity,
+ * each operator is defined to operate on operands of the same type
+ * and to return the same type. The exceptions are op:numeric-divide,
+ * which returns an xs:decimal if called with two xs:integer operands
+ * and op:numeric-integer-divide which always returns an xs:integer.]]
+ * -- http://www.w3.org/TR/xpath-functions/#op.numeric
+ *
+ *
+ * Numeric type promotion
+ * http://www.w3.org/TR/xpath20/#dt-type-promotion
+ *
+ * [[xs:decimal (or any type derived by restriction from xs:decimal,
+ * including xs:integer) can be promoted to either of the types
+ * xs:float or xs:double.]]
+ *
+ * For here that means xs:integer to xs:double and xs:decimal to xs:double
+ *
+ * [[A function that expects a parameter $p of type xs:decimal can be
+ * invoked with a value of type xs:integer. This is an example of
+ * subtype substitution. The value retains its original type. Within
+ * the body of the function, $p instance of xs:integer returns
+ * true.]]
+ *
+ *
+ * B.2 Operator Mapping
+ * http://www.w3.org/TR/xpath20/#mapping
+ *
+ * [[When referring to a type, the term numeric denotes the types
+ * xs:integer, xs:decimal, xs:float, and xs:double]]
+ *
+ * [[If the result type of an operator is listed as numeric, it means
+ * "the first type in the ordered list (xs:integer, xs:decimal,
+ * xs:float, xs:double) into which all operands can be converted by
+ * subtype substitution and numeric type promotion."]]
+ *
+ */
+
+
+
+#ifdef STANDALONE
+#include <stdio.h>
+
+int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[])
+{
+
+#if 0
+ raptor_uri *xsd_uri;
+ raptor_uri *dateTime_uri;
+ rasqal_literal *l1, *l2;
+ int fn_i;
+ raptor_uri* fn_uri;
+ const unsigned char *fn_name;
+ rasqal_extension_fn fn;
+ raptor_sequence *fn_args;
+ char *error;
+ rasqal_literal *fn_result;
+ rasqal_world *world;
+
+ world=rasqal_new_world();
+ if(!world || rasqal_world_open(world)) {
+ fprintf(stderr, "%s: rasqal_world init failed\n", program);
+ return(1);
+ }
+
+ xsd_uri=raptor_new_uri(raptor_xmlschema_datatypes_namespace_uri);
+ dateTime_uri=raptor_new_uri_from_uri_local_name(xsd_uri, (const unsigned char*)"dateTime");
+
+ rasqal_init_datatypes();
+
+ fn_args=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_literal, (raptor_sequence_print_handler*)rasqal_literal_print);
+ l1=rasqal_new_string_literal((unsigned char*)strdup("2004-05-04"), NULL, raptor_uri_copy(dateTime_uri), NULL);
+ raptor_sequence_push(fn_args, l1);
+ l2=rasqal_new_string_literal((unsigned char*)strdup("2003-01-02"), NULL, raptor_uri_copy(dateTime_uri), NULL);
+ raptor_sequence_push(fn_args, l2);
+
+ fn_i=0;
+ fn_name=rasqal_xsd_datatype_fns[fn_i].name;
+ fn=rasqal_xsd_datatype_fns[fn_i].fn;
+ fn_uri=rasqal_xsd_datatype_fns[fn_i].uri;
+
+ error=NULL;
+ fn_result=fn(fn_uri, fn_args, &error);
+ raptor_free_sequence(fn_args);
+
+ if(!fn_result) {
+ if(error)
+ fprintf(stderr, "function %s failed with error %s\n", fn_name, error);
+ else
+ fprintf(stderr, "function %s unknown error\n", fn_name);
+ } else {
+ fprintf(stderr, "function %s returned result: ", fn_name);
+ rasqal_literal_print(fn_result, stderr);
+ fputc('\n', stderr);
+ }
+
+
+ if(fn_result)
+ rasqal_free_literal(fn_result);
+
+ rasqal_finish_datatypes();
+
+ raptor_free_uri(xsd_uri);
+ raptor_free_uri(dateTime_uri);
+
+ rasqal_free_world(world);
+#endif
+
+ return 0;
+}
+#endif
diff --git a/src/rasqal/rdql_common.h b/src/rasqal/rdql_common.h
new file mode 100644
index 0000000..5546264
--- /dev/null
+++ b/src/rasqal/rdql_common.h
@@ -0,0 +1,63 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rdql_common.h - RDQL lexer/parser shared internals
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-2004, 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.
+ *
+ */
+
+#ifndef RDQL_COMMON_H
+#define RDQL_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* rdql_parser.y */
+int rdql_syntax_error(rasqal_query *rq, const char *message, ...) RASQAL_PRINTF_FORMAT(2, 3);
+int rdql_syntax_warning(rasqal_query *rq, const char *message, ...) RASQAL_PRINTF_FORMAT(2, 3);
+
+int rdql_query_lex(void);
+
+
+struct rasqal_rdql_query_language_s {
+ /* STATIC lexer */
+ yyscan_t scanner;
+
+ int scanner_set;
+
+ /* for error reporting */
+ unsigned int lineno;
+
+ /* count of errors in current query parse */
+ int error_count;
+
+ /* expression tree for AND ... */
+ rasqal_expression* constraint_expression;
+};
+
+
+typedef struct rasqal_rdql_query_language_s rasqal_rdql_query_language;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/rasqal/rdql_lexer.l b/src/rasqal/rdql_lexer.l
new file mode 100644
index 0000000..b53e80e
--- /dev/null
+++ b/src/rasqal/rdql_lexer.l
@@ -0,0 +1,1238 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rdql_lexer.l - Rasqal RDQL lexer - making tokens for rdql grammar generator
+ *
+ * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-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.
+ *
+ * To generate the C files from this source, rather than use the
+ * shipped rdql_lexer.c/.h needs a patched version of flex 2.5.31 such
+ * as the one available in Debian GNU/Linux. Details below
+ * near the %option descriptions.
+ *
+ */
+
+
+/* recognise 8-bits */
+%option 8bit
+%option warn nodefault
+
+/* all symbols prefixed by this */
+%option prefix="rdql_lexer_"
+
+/* This is not needed, flex is invoked -ordql_lexer.c */
+%option outfile="rdql_lexer.c"
+
+/* Emit a C header file for prototypes
+ * Only available in flex 2.5.13 or newer.
+ * It was renamed to header-file in flex 2.5.19
+ */
+%option header-file="rdql_lexer.h"
+
+/* Do not emit #include <unistd.h>
+ * Only available in flex 2.5.7 or newer.
+ * Broken in flex 2.5.31 without patches.
+ */
+%option nounistd
+
+/* Never interactive */
+/* No isatty() check */
+%option never-interactive
+
+/* Batch scanner */
+%option batch
+
+/* Never use yyunput */
+%option nounput
+
+/* Supply our own alloc/realloc/free functions */
+%option noyyalloc noyyrealloc noyyfree
+
+/* Re-entrant scanner */
+%option reentrant
+
+
+%x PATTERN ID
+
+ /* definitions */
+
+%{
+
+/* NOTE: These headers are NOT included here. They are inserted by fix-flex
+ * since otherwise it appears far too late in the generated C
+ */
+
+/*
+#ifdef HAVE_CONFIG_H
+#include <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#include <rasqal.h>
+#include <rasqal_internal.h>
+
+#include <rdql_parser.h>
+
+#include <rdql_common.h>
+
+
+
+static int rdql_skip_c_comment(rasqal_query *rq);
+
+static unsigned char* rdql_copy_name(rasqal_query *rq, const unsigned char *text, size_t len);
+static unsigned char* rdql_copy_qname(rasqal_query *rq, const unsigned char *text, size_t len);
+static int rdql_copy_regex_token(rasqal_query *rq, YYSTYPE* lval, unsigned char delim);
+static int rdql_copy_string_token(rasqal_query *rq, YYSTYPE* lval, const unsigned char *text, size_t len, int delim);
+
+#ifdef RASQAL_DEBUG
+const char * rdql_token_print(rasqal_world* world, int token, YYSTYPE *lval);
+#endif
+
+int rdql_lexer_lex (YYSTYPE *rdql_parser_lval, yyscan_t yyscanner);
+#define YY_DECL int rdql_lexer_lex (YYSTYPE *rdql_parser_lval, yyscan_t yyscanner)
+
+#ifdef __cplusplus
+#define INPUT_FN yyinput
+#else
+#define INPUT_FN input
+#endif
+
+/* Remove the re-fill function since it should never be called */
+#define YY_INPUT(buf,result,max_size) { return YY_NULL; }
+
+
+/* Missing rdql_lexer.c/h prototypes */
+int rdql_lexer_get_column(yyscan_t yyscanner);
+void rdql_lexer_set_column(int column_no , yyscan_t yyscanner);
+
+static void rdql_lexer_cleanup(yyscan_t yyscanner);
+
+#ifdef HAVE_SETJMP
+static jmp_buf rdql_lexer_fatal_error_longjmp_env;
+
+/* fatal error handler declaration */
+#define YY_FATAL_ERROR(msg) do { \
+ rdql_lexer_fatal_error(msg, yyscanner); \
+ longjmp(rdql_lexer_fatal_error_longjmp_env, 1); \
+} while(0)
+#else
+#define YY_FATAL_ERROR(msg) do { \
+ rdql_lexer_fatal_error(msg, yyscanner); \
+ abort(); \
+} while(0)
+#endif
+
+static void rdql_lexer_fatal_error(yyconst char *msg, yyscan_t yyscanner);
+
+%}
+
+LANGUAGETOKEN [A-Za-z][-A-Z_a-z0-9]*
+/* See
+ * http://www.w3.org/TR/xml11/#NT-NameStartChar and
+ * http://www.w3.org/TR/xml11/#NT-NameChar
+ */
+PREFIX [A-Za-z\\\x80-\xff][-A-Z_a-z\\\x80-\xff0-9]*
+NAME [A-Za-z_\\\x80-\xff][-A-Z_a-z\\\x80-\xff0-9]*
+QNAME {PREFIX}:{NAME}*
+/* The initial char conditions are to ensure this doesn't grab < or <= */
+QUOTEDURI \<[A-Za-z][^>]+\>
+
+%%
+ /* rules */
+
+%{
+
+ int c;
+ rasqal_query *rq=(rasqal_query*)yyextra;
+ rasqal_rdql_query_language *rqe=(rasqal_rdql_query_language*)rq->context;
+
+#ifdef HAVE_SETJMP
+ if(setjmp(rdql_lexer_fatal_error_longjmp_env))
+ return 1;
+#endif
+
+%}
+
+"//"[^\r\n]*(\r\n|\r|\n) { /* C++ comment */
+ rqe->lineno++;
+}
+
+"/*" { int lines=rdql_skip_c_comment(rq);
+ if(lines < 0)
+ yyterminate();
+ rqe->lineno += lines;
+ }
+
+\r\n|\r|\n { rqe->lineno++; }
+
+[\ \t\v]+ { /* eat up other whitespace */
+ ;
+}
+
+"SELECT"|"select" { return SELECT; }
+"SOURCE"|"source" { return SOURCE; }
+"FROM"|"from" { return FROM; }
+"WHERE"|"where" { return WHERE; }
+"AND"|"and" { return AND; }
+"USING"|"using" { return USING; }
+"FOR"|"for" { return FOR; }
+
+"," { return ','; }
+"(" { return '('; }
+")" { return ')'; }
+"?" { BEGIN(ID); return '?'; }
+
+"||" { return SC_OR; }
+"&&" { return SC_AND; }
+
+"EQ"|"eq" { return STR_EQ; }
+"NE"|"NE" { return STR_NE; }
+
+"=~"|"~~" { BEGIN(PATTERN); return STR_MATCH; }
+"!~" { BEGIN(PATTERN); return STR_NMATCH; }
+
+<PATTERN>[ \t\v]+ {
+ ;
+}
+
+<PATTERN>\r\n|\r|\n { rqe->lineno++; }
+
+
+<PATTERN>. { /* first non whitespace */
+ if(!rdql_copy_regex_token(rq, rdql_parser_lval, *yytext)) {
+ BEGIN(INITIAL);
+ return PATTERN_LITERAL;
+ }
+ BEGIN(INITIAL);
+ yyterminate();
+ };
+
+
+"==" { return EQ; }
+"!=" { return NEQ; }
+"<"/[^A-Za-z=] { return LT; }
+">" { return GT; }
+"<=" { return LE; }
+">=" { return GE; }
+
+"+" { return '+'; }
+"-" { return '-'; }
+"*" { return '*'; }
+"/" { return '/'; }
+"%" { return '%'; }
+"~" { return '~'; }
+"!" { return '!'; }
+
+[0-9]+["lL"]? { c=yytext[yyleng-1];
+ if (c== 'l' || c == 'L')
+ yytext[yyleng-1]='\0';
+ rdql_parser_lval->literal=rasqal_new_integer_literal(rq->world, RASQAL_LITERAL_INTEGER, atoi(yytext));
+ return INTEGER_LITERAL;
+}
+
+0[xX][0-9a-fA-F]+ { int i;
+ int n;
+
+ if(yytext[yyleng+1] == 'x')
+ n=sscanf(yytext+2, "%x", &i);
+ else
+ n=sscanf(yytext+2, "%X", &i);
+ if(n != 1) {
+ rdql_syntax_error(rq, "RDQL syntax error - Illegal hex constant %c%c%c",
+ yytext[0], yytext[1], yytext[2]);
+ yyterminate();
+ }
+ rdql_parser_lval->literal=rasqal_new_integer_literal(rq->world, RASQAL_LITERAL_INTEGER, i);
+ return INTEGER_LITERAL;
+}
+
+[0-9]+"."[0-9]*[eE][+-]?[0-9]+[fFdD]?|"."[0-9]+[eE][+-]?[0-9]+[fFdD]?|[0-9]+[eE][+-]?[0-9]+[fFdD]?|[0-9]+[eE][+-]?[0-9]+[fFdD]?|[0-9]+"."[0-9]* {
+ rdql_parser_lval->literal=rasqal_new_typed_literal(rq->world, RASQAL_LITERAL_DOUBLE, (const unsigned char*)yytext);
+ if(!rdql_parser_lval->literal)
+ yyterminate();
+ return FLOATING_POINT_LITERAL;
+}
+
+'([^'\\\n\r]|\\[^\n\r])*'(@{LANGUAGETOKEN})?(^^({QUOTEDURI}|{QNAME}))? { /*' */
+ if(!rdql_copy_string_token(rq, rdql_parser_lval,
+ (const unsigned char*)yytext+1, yyleng-1, '\''))
+ return STRING_LITERAL;
+ yyterminate();
+}
+
+\"([^"\\\n\r]|\\[^\n\r])*\"(@{LANGUAGETOKEN})?(^^({QUOTEDURI}|{QNAME}))? { /* " */
+ if(!rdql_copy_string_token(rq, rdql_parser_lval,
+ (const unsigned char*)yytext+1, yyleng-1, '"'))
+ return STRING_LITERAL;
+ yyterminate();
+}
+
+"true"|"false" { rdql_parser_lval->literal=rasqal_new_boolean_literal(rq->world, *yytext== 't');
+ return BOOLEAN_LITERAL; }
+
+"null" { rdql_parser_lval->literal=NULL;
+ return NULL_LITERAL; }
+
+<*>{NAME} { rdql_parser_lval->name=rdql_copy_name(rq, (const unsigned char*)yytext, yyleng);
+ if(!rdql_parser_lval->name)
+ yyterminate();
+ BEGIN(INITIAL);
+ return IDENTIFIER; }
+<ID>(.|\n) { BEGIN(INITIAL);
+ rdql_syntax_error(rq, "RDQL syntax error - missing variable name after ?");
+ yyterminate();
+ }
+
+{QNAME} { rdql_parser_lval->name=rdql_copy_qname(rq, (const unsigned char*)yytext, yyleng);
+ if(!rdql_parser_lval->name)
+ yyterminate();
+ return QNAME_LITERAL; }
+
+\<{QNAME}\> { rdql_parser_lval->name=rdql_copy_qname(rq, (const unsigned char*)yytext+1, yyleng-2);
+ if(!rdql_parser_lval->name)
+ yyterminate();
+ rdql_syntax_warning(rq, "Obsolete RDQL <qname> syntax found in \"%s\"", (const unsigned char*)yytext);
+ return QNAME_LITERAL; }
+
+{QUOTEDURI} { if(yyleng == 2)
+#ifdef RAPTOR_V2_AVAILABLE
+ rdql_parser_lval->uri = raptor_uri_copy_v2(rq->world->raptor_world_ptr, rq->base_uri);
+#else
+ rdql_parser_lval->uri = raptor_uri_copy(rq->base_uri);
+#endif
+ else {
+ yytext[yyleng-1]='\0';
+#ifdef RAPTOR_V2_AVAILABLE
+ rdql_parser_lval->uri = raptor_new_uri_relative_to_base_v2(rq->world->raptor_world_ptr, rq->base_uri, (const unsigned char*)yytext+1);
+#else
+ rdql_parser_lval->uri = raptor_new_uri_relative_to_base(rq->base_uri, (const unsigned char*)yytext+1);
+#endif
+ }
+ return URI_LITERAL; }
+
+\# { while((c=INPUT_FN(yyscanner)) != '\n' && c)
+ ;
+ }
+
+. { if (!*yytext)
+ return EOF;
+
+ rdql_syntax_error(rq, "RDQL syntax error at '%s'", yytext);
+ yyterminate();
+ }
+
+%%
+ /* user code */
+
+int
+yywrap (yyscan_t yyscanner) {
+ return 1;
+}
+
+
+static unsigned char *
+rdql_copy_name(rasqal_query *rq, const unsigned char *text, size_t len) {
+ size_t dest_len=0;
+ unsigned char *s;
+
+ s=rasqal_escaped_name_to_utf8_string((unsigned char*)text, len,
+ &dest_len,
+ (raptor_simple_message_handler)rdql_syntax_error, rq);
+ if(!s)
+ return s;
+
+ if(!raptor_xml_name_check(s, dest_len, 11))
+ rdql_syntax_warning(rq, "Invalid RDQL name \"%s\"", s);
+
+ return s;
+}
+
+
+static unsigned char *
+rdql_copy_qname(rasqal_query *rq, const unsigned char *text, size_t len) {
+ unsigned char *p;
+ size_t dest_len=0;
+ unsigned char *s;
+
+ s=rasqal_escaped_name_to_utf8_string((unsigned char*)text, len,
+ &dest_len,
+ (raptor_simple_message_handler)rdql_syntax_error, rq);
+ if(!s)
+ return s;
+
+ p=(unsigned char*)strchr((const char*)s, ':');
+ if(!raptor_xml_name_check(s, p-s, 11))
+ rdql_syntax_warning(rq, "Invalid RDQL name \"%s\"", s);
+ if(!raptor_xml_name_check(p+1, dest_len-((p+1)-s), 11))
+ rdql_syntax_warning(rq, "Invalid RDQL name \"%s\"", p+1);
+
+ return s;
+}
+
+
+static int
+rdql_copy_regex_token(rasqal_query* rq, YYSTYPE* lval, unsigned char delim) {
+ rasqal_rdql_query_language *rqe=(rasqal_rdql_query_language*)rq->context;
+ yyscan_t yyscanner=rqe->scanner;
+ unsigned int ind=0;
+ size_t buffer_len=0;
+ unsigned char *buffer=NULL;
+ size_t flags_len=0;
+ unsigned char *flags=NULL;
+ int c;
+
+ if(delim == 'm') {
+ /* Handle pattern literal m/foo/ */
+ c=INPUT_FN(yyscanner);
+ if(c == EOF) {
+ rdql_syntax_error(rq, "RDQL syntax error - EOF in regex");
+ return 1;
+ }
+ delim=(unsigned char)c;
+ }
+
+ while((c=INPUT_FN(yyscanner)) && c != EOF && c != delim) {
+ /* May add 2 chars - \' */
+ if(ind+2 > buffer_len) {
+ unsigned char *new_buffer;
+ size_t new_buffer_len=buffer_len <<1;
+
+ if(new_buffer_len<10)
+ new_buffer_len=10;
+ new_buffer=(unsigned char *)RASQAL_CALLOC(cstring, 1, new_buffer_len+1);
+ if(buffer_len) {
+ strncpy((char*)new_buffer, (const char*)buffer, buffer_len);
+ RASQAL_FREE(cstring, buffer);
+ }
+ buffer=new_buffer;
+ buffer_len=new_buffer_len;
+ }
+ buffer[ind++]=c;
+ if(c == '\\') {
+ c=INPUT_FN(yyscanner);
+ buffer[ind++]=c;
+ }
+ }
+
+ if(!buffer) {
+ buffer_len=0;
+ buffer=(unsigned char *)RASQAL_CALLOC(cstring, 1, buffer_len+1);
+ }
+ buffer[ind]='\0';
+
+ if(c == EOF) {
+ rdql_syntax_error(rq, "RDQL syntax error - EOF in regex");
+ return 1;
+ }
+
+ /* flags */
+ ind=0;
+ while((c=INPUT_FN(yyscanner)) && c != EOF && isalpha(c)) {
+ if(ind+1 > flags_len) {
+ unsigned char *new_flags;
+ size_t new_flags_len=flags_len + 5;
+
+ if(new_flags_len<5)
+ new_flags_len=5;
+ new_flags=(unsigned char *)RASQAL_CALLOC(cstring, 1, new_flags_len+1);
+ if(flags_len) {
+ strncpy((char*)new_flags, (const char*)flags, flags_len);
+ RASQAL_FREE(cstring, flags);
+ }
+ flags=new_flags;
+ flags_len=new_flags_len;
+ }
+ flags[ind++]=c;
+ }
+ if(flags)
+ flags[ind]='\0';
+
+ lval->literal=rasqal_new_pattern_literal(rq->world, buffer, (const char*)flags);
+ return 0;
+}
+
+
+static int
+rdql_copy_string_token(rasqal_query* rq, YYSTYPE* lval,
+ const unsigned char *text, size_t len, int delim) {
+ unsigned int i;
+ const unsigned char *s;
+ unsigned char *d;
+ unsigned char *string=(unsigned char *)RASQAL_MALLOC(cstring, len+1);
+ char *language=NULL;
+ unsigned char *dt=NULL;
+ raptor_uri *dt_uri=NULL;
+ unsigned char *dt_qname=NULL;
+
+ for(s=text, d=string, i=0; i<len; s++, i++) {
+ unsigned char c=*s;
+
+ if(c == '\\' ) {
+ s++; i++;
+ c=*s;
+ if(c == 'n')
+ *d++= '\n';
+ else if(c == 'r')
+ *d++= '\r';
+ else if(c == 't')
+ *d++= '\t';
+ else if(c == '\\' || c == delim)
+ *d++=c;
+ else if (c == 'u' || c == 'U') {
+ int ulen=(c == 'u') ? 4 : 8;
+ unsigned long unichar=0;
+ int n;
+
+ s++; i++;
+ if(i+ulen > len) {
+ printf("\\%c over end of line", c);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+
+ n=sscanf((const char*)s, ((ulen == 4) ? "%04lx" : "%08lx"), &unichar);
+ if(n != 1) {
+ rdql_syntax_error(rq, "RDQL syntax error - Illegal Unicode escape '%c%s...'", c, s);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+
+ s+= ulen-1;
+ i+= ulen-1;
+
+ if(unichar > 0x10ffff) {
+ rdql_syntax_error(rq, "RDQL syntax error - Illegal Unicode character with code point #x%lX.", unichar);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+
+ d+=raptor_unicode_char_to_utf8(unichar, d);
+ } else {
+ /* Ignore \x where x isn't the one of: \n \r \t \\ (delim) \u \U */
+ rdql_syntax_warning(rq, "Unknown RDQL string escape \\%c in \"%s\"", c, text);
+ *d++=c;
+ }
+ } else if(c== delim) {
+ *d++='\0';
+
+ /* skip delim */
+ s++; i++;
+
+ c=*s++; i++;
+ if(c=='@') {
+ language=(char*)d;
+ while(i<=len) {
+ c=*s++; i++;
+ if(!isalpha(c) && !isdigit(c) && c != '-')
+ break;
+ *d++=c;
+ }
+ *d++='\0';
+ }
+ if(c=='^') {
+ /* skip second char of ^^ */
+ s++; i++;
+
+ dt=d;
+ while(i++<=len)
+ *d++=*s++;
+ /* *d='\0' below */
+ } else if (language)
+ *d='\0';
+
+ break;
+ } else
+ *d++=c;
+ } /* end of for */
+
+ *d='\0';
+
+ if(language) {
+ char *new_language=(char *)RASQAL_MALLOC(cstring, strlen((const char*)language)+1);
+ strcpy(new_language, language);
+ language=new_language;
+ }
+
+ if(dt) {
+ /* dt can be a URI or qname */
+ if(*dt == '<') {
+ dt[strlen((const char*)dt)-1]='\0';
+#ifdef RAPTOR_V2_AVAILABLE
+ dt_uri = raptor_new_uri_v2(rq->world->raptor_world_ptr, dt+1);
+#else
+ dt_uri = raptor_new_uri(dt+1);
+#endif
+ } else {
+ size_t dt_qname_len=strlen((const char*)dt);
+
+ if(!raptor_xml_name_check(dt, dt_qname_len, 11))
+ rdql_syntax_warning(rq, "Invalid RDQL name \"%s\"", dt);
+
+ /* the qname is expanded later */
+ dt_qname=(unsigned char *)RASQAL_MALLOC(cstring, dt_qname_len+1);
+ strcpy((char*)dt_qname, (const char*)dt);
+ }
+ }
+
+#if RASQAL_DEBUG >3
+ fprintf(stderr, "string='%s', language='%s'\n",
+ string, (language ? language : ""));
+ fprintf(stderr, "dt uri='%s',qname='%s'\n",
+ (dt_uri ? (const char*)raptor_uri_as_string(dt_uri) : ""),
+ (dt_qname ? (const char*)dt_qname : ""));
+#endif
+
+ lval->literal=rasqal_new_string_literal(rq->world, string, language, dt_uri, dt_qname);
+
+ return 0;
+}
+
+
+static int
+rdql_skip_c_comment(rasqal_query *rq) {
+ rasqal_rdql_query_language *rqe=(rasqal_rdql_query_language*)rq->context;
+ yyscan_t yyscanner=rqe->scanner;
+ int lines=0;
+ int c;
+
+ while(1) {
+ while ((c=INPUT_FN(yyscanner)) != '*' && c!= EOF) {
+ if(c == '\r' || c == '\n')
+ lines++;
+ }
+ if( c == '*') {
+ while ((c=INPUT_FN(yyscanner)) == '*') {
+ if(c == '\r' || c == '\n')
+ lines++;
+ }
+
+ if(c == '/')
+ break;
+ }
+ if (c == EOF) {
+ rdql_syntax_error(rq, "RDQL syntax error - EOF in comment");
+ lines= -1;
+ break;
+ }
+ }
+ return lines;
+}
+
+
+/*
+ * rdql_lexer_fatal_error:
+ *
+ * INTERNAL - replacement for the generated error handler.
+ * Uses rasqal_query_fatal_error() when possible.
+ */
+static void rdql_lexer_fatal_error(yyconst char *msg, yyscan_t yyscanner)
+{
+ rasqal_query *rq=NULL;
+
+ if(yyscanner)
+ rq=(rasqal_query *)rdql_lexer_get_extra(yyscanner);
+
+ if(rq) {
+ /* avoid "format not a string literal and no format arguments" warning with %s */
+ rq->failed=1;
+ rasqal_log_error_simple(rq->world, RAPTOR_LOG_LEVEL_FATAL,
+ &rq->locator, "%s", msg);
+ } else
+ (void)fprintf(stderr, "%s\n", msg);
+
+ abort();
+}
+
+
+/* Define LEXER_ALLOC_TRACKING to enable allocated memory tracking
+ * - fixes lexer memory leak when ensure_buffer_stack fails
+ */
+
+#ifdef LEXER_ALLOC_TRACKING
+typedef struct {
+ /* Number of void* slots allocated */
+ int lexer_allocs_size;
+ /* Allocted void* slots follow in memory after this header */
+} lexer_alloc_tracker_header;
+
+/* Initial alloc tracker slot array size - 2 seems to be enough for almost all cases */
+static const int initial_lexer_allocs_size=2;
+#endif
+
+
+/*
+ * rdql_lexer_cleanup:
+ * @yyscanner:
+ *
+ * INTERNAL - Clean up unfreed lexer allocs if LEXER_ALLOC_TRACKING is enabled.
+ */
+static void rdql_lexer_cleanup(yyscan_t yyscanner)
+{
+#ifdef LEXER_ALLOC_TRACKING
+ rasqal_query *rq;
+ lexer_alloc_tracker_header *tracker;
+ void **lexer_allocs;
+ int i;
+
+ if(!yyscanner)
+ return;
+
+ rq=(rasqal_query *)rdql_lexer_get_extra(yyscanner);
+ if(!rq)
+ return;
+
+ tracker=(lexer_alloc_tracker_header *)rq->lexer_user_data;
+ if(!tracker)
+ return;
+ lexer_allocs=(void**)&tracker[1];
+
+ for(i=0; i<tracker->lexer_allocs_size; ++i) {
+ if(lexer_allocs[i])
+ free(lexer_allocs[i]);
+ lexer_allocs[i]=NULL;
+ }
+ free(rq->lexer_user_data);
+ rq->lexer_user_data=NULL;
+#endif
+}
+
+
+/*
+ * rdql_lexer_alloc:
+ * @size
+ * @yyscanner
+ *
+ * INTERNAL - alloc replacement.
+ * Tracks allocated cells if LEXER_ALLOC_TRACKING is enabled.
+ */
+void *rdql_lexer_alloc(yy_size_t size, yyscan_t yyscanner)
+{
+#ifdef LEXER_ALLOC_TRACKING
+ rasqal_query *rq;
+ lexer_alloc_tracker_header *tracker;
+ void **lexer_allocs;
+ int i;
+ void *ptr;
+
+ /* yyscanner not initialized -> probably initializing yyscanner itself
+ * -> just malloc without tracking
+ */
+ if(!yyscanner)
+ return malloc(size);
+
+ rq=(rasqal_query *)rdql_lexer_get_extra(yyscanner);
+ if(!rq)
+ YY_FATAL_ERROR("lexer_alloc: yyscanner extra not initialized");
+
+ /* try to allocate tracker if it does not exist */
+ tracker=(lexer_alloc_tracker_header *)rq->lexer_user_data;
+ if(!tracker) {
+ /* allocate tracker header + array of void* slots */
+ tracker=(lexer_alloc_tracker_header*)calloc(1, sizeof(lexer_alloc_tracker_header)+initial_lexer_allocs_size*sizeof(void*));
+ if(!tracker)
+ YY_FATAL_ERROR("lexer_alloc: cannot allocate tracker");
+ tracker->lexer_allocs_size=initial_lexer_allocs_size;
+ rq->lexer_user_data=(void *)tracker;
+ }
+ lexer_allocs=(void**)&tracker[1];
+
+ /* allocate memory */
+ ptr=malloc(size);
+
+ /* find a free slot for ptr */
+ for(i=0; i<tracker->lexer_allocs_size; ++i) {
+ if(!lexer_allocs[i]) {
+ lexer_allocs[i]=ptr;
+ break;
+ }
+ }
+
+ /* no free slots -> grow tracker slot array */
+ if(i>=tracker->lexer_allocs_size) {
+ int j;
+ void **dest;
+ tracker=(lexer_alloc_tracker_header*)calloc(1, sizeof(lexer_alloc_tracker_header)+i*2*sizeof(void*));
+ if(!tracker) {
+ if(ptr)
+ free(ptr);
+ YY_FATAL_ERROR("lexer_alloc: cannot grow tracker");
+ }
+ tracker->lexer_allocs_size=i*2;
+
+ /* copy data from old tracker */
+ dest=(void**)&tracker[1];
+ for(j=0; j<i; ++j) {
+ dest[j]=lexer_allocs[j];
+ }
+
+ /* set new item to first free slot */
+ dest[j]=ptr;
+
+ /* free old tracker and replace with new one */
+ free(rq->lexer_user_data);
+ rq->lexer_user_data=tracker;
+ }
+
+ return ptr;
+#else
+ return malloc(size);
+#endif
+}
+
+
+/*
+ * rdql_lexer_realloc:
+ *
+ * INTERNAL - realloc replacement
+ * Tracks allocated cells if LEXER_ALLOC_TRACKING is enabled.
+ */
+void *rdql_lexer_realloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
+{
+#ifdef LEXER_ALLOC_TRACKING
+ rasqal_query *rq;
+ lexer_alloc_tracker_header *tracker;
+ void **lexer_allocs;
+ int i;
+ void *newptr;
+
+ if(!yyscanner)
+ YY_FATAL_ERROR("lexer_realloc: yyscanner not initialized");
+
+ rq=(rasqal_query *)rdql_lexer_get_extra(yyscanner);
+ if(!rq)
+ YY_FATAL_ERROR("lexer_realloc: yyscanner extra not initialized");
+
+ tracker=(lexer_alloc_tracker_header *)rq->lexer_user_data;
+ if(!tracker)
+ YY_FATAL_ERROR("lexer_realloc: no alloc tracker");
+ lexer_allocs=(void**)&tracker[1];
+
+ /* find the old slot for ptr */
+ for(i=0; i<tracker->lexer_allocs_size; ++i) {
+ if(lexer_allocs[i]==ptr)
+ break;
+ }
+
+ /* no old slot -> error */
+ if(i>=tracker->lexer_allocs_size)
+ YY_FATAL_ERROR("lexer_realloc: cell not in tracker");
+
+ /* realloc */
+ newptr=realloc((char*)ptr, size);
+
+ /* replace entry in tracker */
+ lexer_allocs[i]=newptr;
+
+ return newptr;
+#else
+ return realloc((char*)ptr, size);
+#endif
+}
+
+
+/*
+ * rdql_lexer_free:
+ *
+ * INTERNAL - free replacement.
+ * Checks for NULL pointer to be freed unlike the default lexer free function.
+ * Tracks allocated cells if LEXER_ALLOC_TRACKING is enabled.
+ */
+void rdql_lexer_free(void *ptr, yyscan_t yyscanner)
+{
+#ifdef LEXER_ALLOC_TRACKING
+ rasqal_query *rq;
+ lexer_alloc_tracker_header *tracker;
+ void **lexer_allocs;
+ int i;
+
+ /* do not free NULL */
+ if(!ptr)
+ return;
+
+ /* free ptr even if we would encounter an error */
+ free(ptr);
+
+ /* yyscanner is allocated with rdql_lexer_alloc() but it's never stored in the tracker
+ * - we need yyscanner to access the tracker */
+ if(!yyscanner || ptr==yyscanner)
+ return;
+
+ rq=(rasqal_query *)rdql_lexer_get_extra(yyscanner);
+ if(!rq)
+ return;
+
+ tracker=(lexer_alloc_tracker_header *)rq->lexer_user_data;
+ if(!tracker)
+ return;
+ lexer_allocs=(void**)&tracker[1];
+
+ /* find the slot for ptr */
+ for(i=0; i<tracker->lexer_allocs_size; ++i) {
+ if(lexer_allocs[i]==ptr)
+ break;
+ }
+
+ /* no slot -> error */
+ if(i>=tracker->lexer_allocs_size)
+ YY_FATAL_ERROR("lexer_free: cell not in tracker");
+
+ /* remove entry from tracker */
+ lexer_allocs[i]=NULL;
+#else
+ if(ptr)
+ free(ptr);
+#endif
+}
+
+
+#ifdef RASQAL_DEBUG
+
+const char *
+rdql_token_print(rasqal_world* world, int token, YYSTYPE *lval)
+{
+ static char buffer[2048];
+
+ if(!token)
+ return "<<EOF>>";
+
+ switch(token) {
+ case SELECT:
+ return "SELECT";
+
+ case SOURCE:
+ return "SOURCE";
+
+ case FROM:
+ return "FROM";
+
+ case WHERE:
+ return "WHERE";
+
+ case AND:
+ return "AND";
+
+ case FOR:
+ return "FOR";
+
+ case ',':
+ return ",";
+
+ case '(':
+ return "(";
+
+ case ')':
+ return "(";
+
+ case '?':
+ return "?";
+
+ case USING:
+ return "USING";
+
+ case SC_AND:
+ return "SC_AND";
+
+ case SC_OR:
+ return "SC_OR";
+
+ case STR_NMATCH:
+ return "STR_NMATCH";
+
+ case STR_MATCH:
+ return "STR_MATCH";
+
+ case STR_NE:
+ return "STR_NE";
+
+ case STR_EQ:
+ return "STR_EQ";
+
+ case GE:
+ return "GE";
+
+ case LE:
+ return "LE";
+
+ case GT:
+ return "GT";
+
+ case LT:
+ return "LT";
+
+ case NEQ:
+ return "NEQ";
+
+ case EQ:
+ return "EQ";
+
+ case '%':
+ return "%";
+
+ case '/':
+ return "/";
+
+ case '*':
+ return "*";
+
+ case '-':
+ return "-";
+
+ case '+':
+ return "+";
+
+ case '!':
+ return "!";
+
+ case '~':
+ return "~";
+
+ case INTEGER_LITERAL:
+ sprintf(buffer, "INTEGER_LITERAL(%d)", lval->literal->value.integer);
+ return buffer;
+
+ case FLOATING_POINT_LITERAL:
+ sprintf(buffer, "FLOATING_POINT_LITERAL(%g)", lval->floating);
+ return buffer;
+
+ case STRING_LITERAL:
+ if(lval->literal->language) {
+ if(lval->literal->datatype)
+ sprintf(buffer, "STRING_LITERAL(\"%s\"@%s^^%s)",
+ lval->literal->string, lval->literal->language,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, lval->literal->datatype)
+#else
+ raptor_uri_as_string(lval->literal->datatype)
+#endif
+ );
+ else
+ sprintf(buffer, "STRING_LITERAL(\"%s\"@%s)",
+ lval->literal->string, lval->literal->language);
+ } else {
+ if(lval->literal->datatype)
+ sprintf(buffer, "STRING_LITERAL(\"%s\"^^%s)",
+ lval->literal->string,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, lval->literal->datatype)
+#else
+ raptor_uri_as_string(lval->literal->datatype)
+#endif
+ );
+ else
+ sprintf(buffer, "STRING_LITERAL(\"%s\")", lval->literal->string);
+ }
+ return buffer;
+
+ case PATTERN_LITERAL:
+ sprintf(buffer, "PATTERN_LITERAL(%s,%s)", lval->literal->string,
+ (lval->literal->flags ? (char*)lval->literal->flags : "-"));
+ return buffer;
+
+ case BOOLEAN_LITERAL:
+ return (lval->literal->value.integer ? "BOOLEAN_LITERAL(true)" : "BOOLEAN_LITERAL(false)");
+
+ case NULL_LITERAL:
+ return "NULL_LITERAL";
+
+ case URI_LITERAL:
+ sprintf(buffer, "URI_LITERAL(%s)",
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, lval->uri)
+#else
+ raptor_uri_as_string(lval->uri)
+#endif
+
+ );
+ return buffer;
+
+ case QNAME_LITERAL:
+ sprintf(buffer, "QNAME_LITERAL(%s)", lval->name);
+ return buffer;
+
+ case IDENTIFIER:
+ sprintf(buffer, "IDENTIFIER(%s)", lval->name);
+ return buffer;
+
+ default:
+ RASQAL_DEBUG2("UNKNOWN token %d - add a new case\n", token);
+ abort();
+ }
+}
+#endif
+
+
+
+#ifdef STANDALONE
+static void
+rdql_token_free(rasqal_world* world, int token, YYSTYPE *lval)
+{
+ if(!token)
+ return;
+
+ switch(token) {
+ case STRING_LITERAL:
+ case PATTERN_LITERAL:
+ rasqal_free_literal(lval->literal);
+ break;
+ case URI_LITERAL:
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, lval->uri);
+#else
+ raptor_free_uri(lval->uri);
+#endif
+ break;
+ case IDENTIFIER:
+ RASQAL_FREE(cstring, lval->name);
+ break;
+ case QNAME_LITERAL:
+ if(lval->name)
+ RASQAL_FREE(cstring, lval->name);
+ break;
+ default:
+ break;
+ }
+}
+
+
+#define FILE_READ_BUF_SIZE 2048
+
+int
+main(int argc, char *argv[])
+{
+ const char *program=rasqal_basename(argv[0]);
+ char *query_string=NULL;
+ rasqal_query rq;
+ rasqal_rdql_query_language rdql;
+ yyscan_t scanner;
+ int token=EOF;
+ YYSTYPE lval;
+ const unsigned char *uri_string;
+ const char *filename=NULL;
+ char *buf=NULL;
+ size_t len;
+ void *buffer;
+ rasqal_world *world;
+
+ world=rasqal_new_world();
+ if(!world || rasqal_world_open(world))
+ exit(1);
+
+ if(argc > 1) {
+ FILE *fh;
+ query_string=(char*)RASQAL_CALLOC(cstring, FILE_READ_BUF_SIZE, 1);
+ filename=argv[1];
+ fh=fopen(filename, "r");
+ if(fh) {
+ fread(query_string, FILE_READ_BUF_SIZE, 1, fh);
+ fclose(fh);
+ } else {
+ fprintf(stderr, "%s: Cannot open file %s - %s\n", program, filename,
+ strerror(errno));
+ exit(1);
+ }
+ } else {
+ filename="<stdin>";
+ query_string=(char*)RASQAL_CALLOC(cstring, FILE_READ_BUF_SIZE, 1);
+ fread(query_string, FILE_READ_BUF_SIZE, 1, stdin);
+ }
+
+ memset(&rq, 0, sizeof(rasqal_query));
+ rq.world=world;
+ memset(&rdql, 0, sizeof(rasqal_rdql_query_language));
+
+ yylex_init(&rdql.scanner);
+ scanner=rdql.scanner;
+
+#if 0
+ /* set
+ * %option debug
+ * above first before enabling this
+ */
+ rdql_lexer_set_debug(1, scanner);
+#endif
+
+ len= strlen((const char*)query_string);
+ buf= (char *)RASQAL_MALLOC(cstring, len+3);
+ strncpy(buf, query_string, len);
+ buf[len]= ' ';
+ buf[len+1]= buf[len+2]='\0'; /* YY_END_OF_BUFFER_CHAR; */
+ buffer= rdql_lexer__scan_buffer(buf, len+3, scanner);
+
+ rdql_lexer_set_extra(&rq, scanner);
+
+ /* Initialise enough of the rasqal_query and locator to get error messages */
+ rq.context=&rdql;
+ rdql.lineno=1;
+ rq.locator.file=filename;
+ rq.locator.column= -1;
+
+ uri_string=raptor_uri_filename_to_uri_string(filename);
+#ifdef RAPTOR_V2_AVAILABLE
+ rq.base_uri = raptor_new_uri_v2(world->raptor_world_ptr, uri_string);
+#else
+ rq.base_uri = raptor_new_uri(uri_string);
+#endif
+ raptor_free_memory((void*)uri_string);
+
+ while(1) {
+ memset(&lval, 0, sizeof(YYSTYPE));
+ if(rdql_lexer_get_text(scanner) != NULL)
+ printf("yyinput '%s'\n", rdql_lexer_get_text(scanner));
+ token=yylex(&lval, scanner);
+#ifdef RASQAL_DEBUG
+ printf("token %s\n", rdql_token_print(world, token, &lval));
+#else
+ printf("token %d\n", token);
+#endif
+ rdql_token_free(world, token, &lval);
+ if(!token || token == EOF)
+ break;
+ }
+
+ if(buf)
+ RASQAL_FREE(cstring, buf);
+
+ yylex_destroy(scanner);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, rq.base_uri);
+#else
+ raptor_free_uri(rq.base_uri);
+#endif
+
+ RASQAL_FREE(cstring, query_string);
+
+ rasqal_free_world(world);
+
+ if(rq.failed)
+ return 1;
+
+ return 0;
+}
+#endif
diff --git a/src/rasqal/rdql_parser.y b/src/rasqal/rdql_parser.y
new file mode 100644
index 0000000..fe75a19
--- /dev/null
+++ b/src/rasqal/rdql_parser.y
@@ -0,0 +1,937 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * rdql_parser.y - Rasqal RDQL parser - over tokens from rdql grammar lexer
+ *
+ * Copyright (C) 2003-2008, David Beckett http://purl.org/net/dajobe/
+ * Copyright (C) 2003-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 <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <rasqal.h>
+#include <rasqal_internal.h>
+
+#include <rdql_parser.h>
+
+#define YY_DECL int rdql_lexer_lex (YYSTYPE *rdql_parser_lval, yyscan_t yyscanner)
+#define YY_NO_UNISTD_H 1
+#include <rdql_lexer.h>
+
+#include <rdql_common.h>
+
+
+/* Make verbose error messages for syntax errors */
+/*
+#ifdef RASQAL_DEBUG
+#define YYERROR_VERBOSE 1
+#endif
+*/
+#define YYERROR_VERBOSE 1
+
+/* Slow down the grammar operation and watch it work */
+#if RASQAL_DEBUG > 2
+#define YYDEBUG 1
+#endif
+
+/* the lexer does not seem to track this */
+#undef RASQAL_RDQL_USE_ERROR_COLUMNS
+
+/* Missing rdql_lexer.c/h prototypes */
+int rdql_lexer_get_column(yyscan_t yyscanner);
+/* Not used here */
+/* void rdql_lexer_set_column(int column_no , yyscan_t yyscanner);*/
+
+
+/* What the lexer wants */
+extern int rdql_lexer_lex (YYSTYPE *rdql_parser_lval, yyscan_t scanner);
+#define YYLEX_PARAM ((rasqal_rdql_query_language*)(((rasqal_query*)rq)->context))->scanner
+
+/* Pure parser argument (a void*) */
+#define YYPARSE_PARAM rq
+
+/* Make the yyerror below use the rdf_parser */
+#undef yyerror
+#define yyerror(message) rdql_query_error((rasqal_query*)rq, message)
+
+/* Make lex/yacc interface as small as possible */
+#undef yylex
+#define yylex rdql_lexer_lex
+
+
+static int rdql_parse(rasqal_query* rq);
+static void rdql_query_error(rasqal_query* rq, const char *message);
+
+%}
+
+
+/* directives */
+
+
+%pure-parser
+
+
+/* Interface between lexer and parser */
+%union {
+ raptor_sequence *seq;
+ rasqal_variable *variable;
+ rasqal_literal *literal;
+ rasqal_triple *triple;
+ rasqal_expression *expr;
+ double floating;
+ raptor_uri *uri;
+ unsigned char *name;
+}
+
+
+/*
+ * No conflicts
+ */
+%expect 0
+
+
+/* word symbols */
+%token SELECT SOURCE FROM WHERE AND FOR
+
+/* expression delimitors */
+
+%token ',' '(' ')'
+%token '?'
+%token USING
+
+
+/* SC booleans */
+%left SC_OR "||"
+%left SC_AND "&&"
+
+/* string operations */
+%left STR_EQ "eq"
+%left STR_NE "ne"
+%left STR_MATCH "=~"
+%left STR_NMATCH "!~"
+
+/* operations */
+%left EQ "="
+%left NEQ "!="
+%left LT "<"
+%left GT ">"
+%left LE "<="
+%left GE ">="
+
+/* arithmetic operations */
+%left '+' '-' '*' '/' '%'
+
+/* unary operations */
+%left '~' '!'
+
+/* literals */
+%token <literal> FLOATING_POINT_LITERAL "floating point literal"
+%token <literal> STRING_LITERAL "string literal"
+%token <literal> INTEGER_LITERAL "integer literal"
+%token <literal> PATTERN_LITERAL "pattern literal"
+%token <literal> BOOLEAN_LITERAL "boolean literal"
+%token <literal> NULL_LITERAL "null"
+%token <uri> URI_LITERAL "URI literal"
+%token <name> QNAME_LITERAL "QName literal"
+
+%token <name> IDENTIFIER "identifier"
+
+
+%type <seq> SelectClause SourceClause UsingClause
+%type <seq> VarList TriplePatternList PrefixDeclList URIList
+
+%type <expr> Expression ConditionalAndExpression ValueLogical
+%type <expr> EqualityExpression RelationalExpression NumericExpression
+%type <expr> AdditiveExpression MultiplicativeExpression UnaryExpression
+%type <expr> UnaryExpressionNotPlusMinus
+%type <expr> ConstraintClause CommaAndConstraintClause
+
+%type <literal> VarOrLiteral VarOrURI
+
+%type <variable> Var
+%type <triple> TriplePattern
+%type <literal> PatternLiteral Literal
+
+%destructor {
+ if($$)
+ rasqal_free_literal($$);
+} FLOATING_POINT_LITERAL STRING_LITERAL INTEGER_LITERAL PATTERN_LITERAL BOOLEAN_LITERAL NULL_LITERAL
+
+%destructor {
+ if($$)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(((rasqal_query*)rq)->world->raptor_world_ptr, $$);
+#else
+ raptor_free_uri($$);
+#endif
+} URI_LITERAL
+
+%destructor {
+ if($$)
+ RASQAL_FREE(cstring, $$);
+} QNAME_LITERAL IDENTIFIER
+
+%%
+
+
+Document : Query
+;
+
+
+Query : SELECT SelectClause SourceClause WHERE TriplePatternList ConstraintClause UsingClause
+{
+ ((rasqal_query*)rq)->selects=$2;
+ ((rasqal_query*)rq)->verb=RASQAL_QUERY_VERB_SELECT;
+
+ if($3) {
+ int i;
+
+ for(i=0; i < raptor_sequence_size($3); i++) {
+ raptor_uri* uri=(raptor_uri*)raptor_sequence_get_at($3, i);
+ rasqal_query_add_data_graph((rasqal_query*)rq, uri, NULL, RASQAL_DATA_GRAPH_BACKGROUND);
+ }
+ raptor_free_sequence($3);
+ }
+
+ /* ignoring $5 (sequence of triples): set in TriplePatternList to
+ * ((rasqal_query*)rq)->triples=$5;
+ */
+
+ /* $6 (expression): ConstraintClause */
+ if($6) {
+ rasqal_rdql_query_language* rdql=(rasqal_rdql_query_language*)((rasqal_query*)rq)->context;
+ rdql->constraint_expression=$6;
+ }
+
+ /* ignoring $7 set in UsingClause ? */
+}
+;
+
+VarList : VarList ',' Var
+{
+ $$=$1;
+ raptor_sequence_push($$, $3);
+}
+| VarList Var
+{
+ $$=$1;
+ raptor_sequence_push($$, $2);
+}
+| Var
+{
+ /* The variables are freed from the rasqal_query field variables */
+ $$=raptor_new_sequence(NULL, (raptor_sequence_print_handler*)rasqal_variable_print);
+ raptor_sequence_push($$, $1);
+}
+;
+
+
+SelectClause : VarList
+{
+ $$=$1;
+}
+| '*'
+{
+ $$=NULL;
+ ((rasqal_query*)rq)->wildcard=1;
+}
+;
+
+SourceClause : SOURCE URIList
+{
+ $$=$2;
+}
+| FROM URIList
+{
+ $$=$2;
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+/* Inlined into SourceClause: SourceSelector : URL */
+
+
+/* Jena RDQL allows optional ',' */
+TriplePatternList : TriplePatternList ',' TriplePattern
+{
+ $$=$1;
+ raptor_sequence_push($$, $3);
+}
+| TriplePatternList TriplePattern
+{
+ $$=$1;
+ raptor_sequence_push($$, $2);
+}
+| TriplePattern
+{
+ $$=((rasqal_query*)rq)->triples;
+ raptor_sequence_push($$, $1);
+}
+;
+
+/* Inlined:
+ TriplePatternClause : WHERE TriplePatternList
+*/
+
+
+/* FIXME - maybe a better way to do this optional COMMA? */
+TriplePattern : '(' VarOrURI ',' VarOrURI ',' VarOrLiteral ')'
+{
+ $$=rasqal_new_triple($2, $4, $6);
+}
+| '(' VarOrURI VarOrURI ',' VarOrLiteral ')'
+{
+ $$=rasqal_new_triple($2, $3, $5);
+}
+| '(' VarOrURI ',' VarOrURI VarOrLiteral ')'
+{
+ $$=rasqal_new_triple($2, $4, $5);
+}
+| '(' VarOrURI VarOrURI VarOrLiteral ')'
+{
+ $$=rasqal_new_triple($2, $3, $4);
+}
+;
+
+
+/* Was:
+ConstraintClause : AND Expression ( ( ',' | AND ) Expression )*
+*/
+
+ConstraintClause : AND CommaAndConstraintClause
+{
+ $$=$2;
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+CommaAndConstraintClause : CommaAndConstraintClause ',' Expression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_AND, $1, $3);
+}
+| CommaAndConstraintClause AND Expression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_AND, $1, $3);
+}
+| Expression
+{
+ $$=$1;
+}
+;
+
+
+
+UsingClause : USING PrefixDeclList
+{
+ $$=$2;
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+PrefixDeclList : IDENTIFIER FOR URI_LITERAL ',' PrefixDeclList
+{
+ $$=((rasqal_query*)rq)->prefixes;
+ raptor_sequence_shift($$, rasqal_new_prefix(((rasqal_query*)rq)->world, $1, $3));
+}
+| IDENTIFIER FOR URI_LITERAL PrefixDeclList
+{
+ $$=((rasqal_query*)rq)->prefixes;
+ raptor_sequence_shift($$, rasqal_new_prefix(((rasqal_query*)rq)->world, $1, $3));
+}
+| IDENTIFIER FOR URI_LITERAL
+{
+ $$=((rasqal_query*)rq)->prefixes;
+ raptor_sequence_push($$, rasqal_new_prefix(((rasqal_query*)rq)->world, $1, $3));
+}
+;
+
+
+Expression : ConditionalAndExpression SC_OR Expression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_OR, $1, $3);
+}
+| ConditionalAndExpression
+{
+ $$=$1;
+}
+;
+
+ConditionalAndExpression: ValueLogical SC_AND ConditionalAndExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_AND, $1, $3);
+;
+}
+| ValueLogical
+{
+ $$=$1;
+}
+;
+
+ValueLogical : EqualityExpression STR_EQ EqualityExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_STR_EQ, $1, $3);
+}
+| EqualityExpression STR_NE EqualityExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_STR_NEQ, $1, $3);
+}
+| EqualityExpression STR_MATCH PatternLiteral
+{
+ $$=rasqal_new_string_op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_STR_MATCH, $1, $3);
+}
+| EqualityExpression STR_NMATCH PatternLiteral
+{
+ $$=rasqal_new_string_op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_STR_NMATCH, $1, $3);
+}
+| EqualityExpression
+{
+ $$=$1;
+}
+;
+
+EqualityExpression : RelationalExpression EQ RelationalExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_EQ, $1, $3);
+}
+| RelationalExpression NEQ RelationalExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_NEQ, $1, $3);
+}
+| RelationalExpression
+{
+ $$=$1;
+}
+;
+
+RelationalExpression : NumericExpression LT NumericExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_LT, $1, $3);
+}
+| NumericExpression GT NumericExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_GT, $1, $3);
+}
+| NumericExpression LE NumericExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_LE, $1, $3);
+}
+| NumericExpression GE NumericExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_GE, $1, $3);
+}
+| NumericExpression
+{
+ $$=$1;
+}
+;
+
+NumericExpression : AdditiveExpression
+{
+ $$=$1;
+}
+;
+
+
+AdditiveExpression : MultiplicativeExpression '+' AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_PLUS, $1, $3);
+}
+| MultiplicativeExpression '-' AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_MINUS, $1, $3);
+}
+| MultiplicativeExpression
+{
+ $$=$1;
+}
+;
+
+MultiplicativeExpression : UnaryExpression '*' MultiplicativeExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_STAR, $1, $3);
+}
+| UnaryExpression '/' MultiplicativeExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_SLASH, $1, $3);
+}
+| UnaryExpression '%' MultiplicativeExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_REM, $1, $3);
+}
+| UnaryExpression
+{
+ $$=$1;
+}
+;
+
+UnaryExpression : '+' UnaryExpression
+{
+ $$=$2;
+}
+| '-' UnaryExpression
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_UMINUS, $2);
+}
+| UnaryExpressionNotPlusMinus
+{
+ $$=$1;
+}
+;
+
+UnaryExpressionNotPlusMinus : '~' UnaryExpression
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_TILDE, $2);
+}
+| '!' UnaryExpression
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_BANG, $2);
+}
+| Var
+{
+ rasqal_literal *l=rasqal_new_variable_literal(((rasqal_query*)rq)->world, $1);
+ $$=rasqal_new_literal_expression(((rasqal_query*)rq)->world, l);
+}
+| Literal
+{
+ $$=rasqal_new_literal_expression(((rasqal_query*)rq)->world, $1);
+}
+| '(' Expression ')'
+{
+ $$=$2;
+}
+;
+
+VarOrURI : Var
+{
+ $$=rasqal_new_variable_literal(((rasqal_query*)rq)->world, $1);
+}
+| URI_LITERAL
+{
+ $$=rasqal_new_uri_literal(((rasqal_query*)rq)->world, $1);
+}
+| QNAME_LITERAL
+{
+ $$=rasqal_new_simple_literal(((rasqal_query*)rq)->world, RASQAL_LITERAL_QNAME, $1);
+}
+;
+
+VarOrLiteral : Var
+{
+ $$=rasqal_new_variable_literal(((rasqal_query*)rq)->world, $1);
+}
+| Literal
+{
+ $$=$1;
+}
+;
+
+Var : '?' IDENTIFIER
+{
+ $$=rasqal_new_variable((rasqal_query*)rq, $2, NULL);
+}
+;
+
+PatternLiteral: PATTERN_LITERAL
+{
+ $$=$1;
+}
+;
+
+Literal : URI_LITERAL
+{
+ $$=rasqal_new_uri_literal(((rasqal_query*)rq)->world, $1);
+}
+| INTEGER_LITERAL
+{
+ $$=$1;
+}
+| FLOATING_POINT_LITERAL
+{
+ $$=$1;
+}
+| STRING_LITERAL
+{
+ $$=$1;
+}
+| BOOLEAN_LITERAL
+{
+ $$=$1;
+}
+| NULL_LITERAL
+{
+ $$=$1;
+} | QNAME_LITERAL
+{
+ $$=rasqal_new_simple_literal(((rasqal_query*)rq)->world, RASQAL_LITERAL_QNAME, $1);
+}
+
+;
+
+URIList : URI_LITERAL ',' URIList
+{
+ $$=$3;
+ raptor_sequence_shift($$, $1);
+}
+| URI_LITERAL
+{
+#ifdef RAPTOR_V2_AVAILABLE
+ $$=raptor_new_sequence_with_handler_context((raptor_sequence_free_handler_v2*)raptor_free_uri_v2, (raptor_sequence_print_handler_v2*)raptor_uri_print_v2, (void*)((rasqal_query*)rq)->world->raptor_world_ptr);
+#else
+ $$=raptor_new_sequence((raptor_sequence_free_handler*)raptor_free_uri, (raptor_sequence_print_handler*)raptor_sequence_print_uri);
+#endif
+ raptor_sequence_push($$, $1);
+}
+;
+
+%%
+
+
+/* Support functions */
+
+
+/* This is declared in rdql_lexer.h but never used, so we always get
+ * a warning unless this dummy code is here. Used once below in an error case.
+ */
+static int yy_init_globals (yyscan_t yyscanner ) { return 0; };
+
+
+
+/**
+ * rasqal_rdql_query_language_init - Initialise the RDQL query language
+ *
+ * Return value: non 0 on failure
+ **/
+static int
+rasqal_rdql_query_language_init(rasqal_query* rdf_query, const char *name) {
+ /* rasqal_rdql_query_language* rdql=(rasqal_rdql_query_language*)rdf_query->context; */
+
+ /* Initialise rdf, rdfs, owl and xsd prefixes and namespaces */
+ raptor_namespaces_start_namespace_full(rdf_query->namespaces,
+ (const unsigned char*)"rdf",
+ (const unsigned char*)RAPTOR_RDF_MS_URI,0);
+ raptor_namespaces_start_namespace_full(rdf_query->namespaces,
+ (const unsigned char*)"rdfs",
+ (const unsigned char*)RAPTOR_RDF_SCHEMA_URI,0);
+ raptor_namespaces_start_namespace_full(rdf_query->namespaces,
+ (const unsigned char*)"xsd",
+ (const unsigned char*)RAPTOR_XMLSCHEMA_DATATYPES_URI, 0);
+ raptor_namespaces_start_namespace_full(rdf_query->namespaces,
+ (const unsigned char*)"owl",
+ (const unsigned char*)RAPTOR_OWL_URI, 0);
+
+ rdf_query->compare_flags = RASQAL_COMPARE_URI;
+
+ return 0;
+}
+
+
+/**
+ * rasqal_rdql_query_language_terminate - Free the RDQL query language
+ *
+ * Return value: non 0 on failure
+ **/
+static void
+rasqal_rdql_query_language_terminate(rasqal_query* rdf_query) {
+ rasqal_rdql_query_language* rdql=(rasqal_rdql_query_language*)rdf_query->context;
+
+ if(rdql->scanner_set) {
+ rdql_lexer_lex_destroy(rdql->scanner);
+ rdql->scanner_set=0;
+ }
+
+}
+
+
+static int
+rasqal_rdql_query_language_prepare(rasqal_query* rdf_query) {
+ rasqal_rdql_query_language* rdql=(rasqal_rdql_query_language*)rdf_query->context;
+ int rc;
+ rasqal_graph_pattern *gp;
+
+ if(!rdf_query->query_string)
+ return 1;
+
+ rdql->constraint_expression=NULL;
+
+ rc=rdql_parse(rdf_query);
+ if(rc)
+ return rc;
+
+ rdf_query->query_graph_pattern=rasqal_new_graph_pattern_from_sequence(rdf_query, NULL, RASQAL_GRAPH_PATTERN_OPERATOR_GROUP);
+
+ gp=rasqal_new_basic_graph_pattern(rdf_query, rdf_query->triples,
+ 0, raptor_sequence_size(rdf_query->triples)-1);
+
+ rasqal_graph_pattern_add_sub_graph_pattern(rdf_query->query_graph_pattern,
+ gp);
+
+ /* Add a FILTER graph pattern if there is a constraint expression */
+ if(rdql->constraint_expression) {
+ rasqal_graph_pattern* cgp;
+ cgp=rasqal_new_filter_graph_pattern(rdf_query, rdql->constraint_expression);
+ if(cgp)
+ rasqal_graph_pattern_add_sub_graph_pattern(rdf_query->query_graph_pattern,
+ cgp);
+ rdql->constraint_expression=NULL;
+ }
+
+ /* Only now can we handle the prefixes and qnames */
+ if(rasqal_query_declare_prefixes(rdf_query) ||
+ rasqal_query_expand_triple_qnames(rdf_query) ||
+ rasqal_query_expand_query_constraints_qnames(rdf_query))
+ return 1;
+
+ /* RDQL: Expand 'SELECT *' */
+ if(rasqal_query_expand_wildcards(rdf_query))
+ return 1;
+
+ return 0;
+}
+
+
+static int
+rdql_parse(rasqal_query* rq) {
+ rasqal_rdql_query_language* rqe=(rasqal_rdql_query_language*)rq->context;
+ raptor_locator *locator=&rq->locator;
+ void *buffer;
+
+ if(!rq->query_string)
+ return yy_init_globals(NULL); /* 0 but a way to use yy_init_globals */
+
+ locator->line=1;
+ locator->column= -1; /* No column info */
+ locator->byte= -1; /* No bytes info */
+
+#if RASQAL_DEBUG > 2
+ rdql_parser_debug=1;
+#endif
+
+ rqe->lineno=1;
+
+ rdql_lexer_lex_init(&rqe->scanner);
+ rqe->scanner_set=1;
+
+ rdql_lexer_set_extra(((rasqal_query*)rq), rqe->scanner);
+
+ buffer= rdql_lexer__scan_buffer((char*)rq->query_string, rq->query_string_length, rqe->scanner);
+
+ rqe->error_count=0;
+
+ rdql_parser_parse(rq);
+
+ rdql_lexer_lex_destroy(rqe->scanner);
+ rqe->scanner_set=0;
+
+ /* Parsing failed */
+ if(rq->failed)
+ return 1;
+
+ return 0;
+}
+
+
+void
+rdql_query_error(rasqal_query *rq, const char *msg) {
+ rasqal_rdql_query_language* rqe=(rasqal_rdql_query_language*)rq->context;
+
+ if(rqe->error_count++)
+ return;
+
+ rq->locator.line=rqe->lineno;
+#ifdef RASQAL_RDQL_USE_ERROR_COLUMNS
+ /* rq->locator.column=rdql_lexer_get_column(yyscanner);*/
+#endif
+
+ rq->failed=1;
+ rasqal_log_error_simple(rq->world, RAPTOR_LOG_LEVEL_FATAL,
+ &rq->locator, "%s", msg);
+
+ return;
+}
+
+
+int
+rdql_syntax_error(rasqal_query *rq, const char *message, ...)
+{
+ rasqal_rdql_query_language *rqe=(rasqal_rdql_query_language*)rq->context;
+ va_list arguments;
+
+ if(rqe->error_count++)
+ return 0;
+
+ rq->locator.line=rqe->lineno;
+#ifdef RASQAL_RDQL_USE_ERROR_COLUMNS
+ /* rp->locator.column=rdql_lexer_get_column(yyscanner);*/
+#endif
+
+ va_start(arguments, message);
+ rq->failed=1;
+ rasqal_log_error_varargs(rq->world, RAPTOR_LOG_LEVEL_FATAL, &rq->locator,
+ message, arguments);
+ va_end(arguments);
+
+ return 0;
+}
+
+
+int
+rdql_syntax_warning(rasqal_query *rq, const char *message, ...)
+{
+ rasqal_rdql_query_language *rqe=(rasqal_rdql_query_language*)rq->context;
+ va_list arguments;
+
+ rq->locator.line=rqe->lineno;
+#ifdef RASQAL_RDQL_USE_ERROR_COLUMNS
+ /* rq->locator.column=rdql_lexer_get_column(yyscanner);*/
+#endif
+
+ va_start(arguments, message);
+ rasqal_log_error_varargs(rq->world, RAPTOR_LOG_LEVEL_WARNING, &rq->locator,
+ message, arguments);
+ va_end(arguments);
+
+ return (0);
+}
+
+
+static void
+rasqal_rdql_query_language_register_factory(rasqal_query_language_factory *factory)
+{
+ factory->context_length = sizeof(rasqal_rdql_query_language);
+
+ factory->init = rasqal_rdql_query_language_init;
+ factory->terminate = rasqal_rdql_query_language_terminate;
+ factory->prepare = rasqal_rdql_query_language_prepare;
+}
+
+
+int
+rasqal_init_query_language_rdql(rasqal_world* world) {
+ /* http://www.w3.org/Submission/2004/SUBM-RDQL-20040109/ */
+
+ return rasqal_query_language_register_factory(world,
+ "rdql",
+ "RDF Data Query Language (RDQL)",
+ NULL,
+ (const unsigned char*)"http://jena.hpl.hp.com/2003/07/query/RDQL",
+ &rasqal_rdql_query_language_register_factory);
+}
+
+
+
+#ifdef STANDALONE
+#include <stdio.h>
+#include <locale.h>
+
+#define RDQL_FILE_BUF_SIZE 2048
+
+int
+main(int argc, char *argv[])
+{
+ const char *program=rasqal_basename(argv[0]);
+ char query_string[RDQL_FILE_BUF_SIZE];
+ rasqal_query *query;
+ FILE *fh;
+ int rc;
+ const char *filename=NULL;
+ raptor_uri* base_uri=NULL;
+ unsigned char *uri_string;
+ rasqal_world *world;
+
+#if RASQAL_DEBUG > 2
+ rdql_parser_debug=1;
+#endif
+
+ if(argc > 1) {
+ filename=argv[1];
+ fh = fopen(argv[1], "r");
+ if(!fh) {
+ fprintf(stderr, "%s: Cannot open file %s - %s\n", program, filename,
+ strerror(errno));
+ exit(1);
+ }
+ } else {
+ filename="<stdin>";
+ fh = stdin;
+ }
+
+ memset(query_string, 0, RDQL_FILE_BUF_SIZE);
+ rc=fread(query_string, RDQL_FILE_BUF_SIZE, 1, fh);
+ if(rc < RDQL_FILE_BUF_SIZE) {
+ if(ferror(fh)) {
+ fprintf(stderr, "%s: file '%s' read failed - %s\n",
+ program, filename, strerror(errno));
+ fclose(fh);
+ return(1);
+ }
+ }
+
+ if(argc>1)
+ fclose(fh);
+
+ world=rasqal_new_world();
+ if(!world || rasqal_world_open(world))
+ exit(1);
+
+ query=rasqal_new_query(world, "rdql", NULL);
+
+ uri_string=raptor_uri_filename_to_uri_string(filename);
+#ifdef RAPTOR_V2_AVAILABLE
+ base_uri = raptor_new_uri_v2(world->raptor_world_ptr, uri_string);
+#else
+ base_uri = raptor_new_uri(uri_string);
+#endif
+
+ rc=rasqal_query_prepare(query, (const unsigned char*)query_string, base_uri);
+
+ rasqal_query_print(query, stdout);
+
+ rasqal_free_query(query);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, base_uri);
+#else
+ raptor_free_uri(base_uri);
+#endif
+
+ raptor_free_memory(uri_string);
+
+ rasqal_free_world(world);
+
+ return rc;
+}
+#endif
diff --git a/src/rasqal/sparql_common.h b/src/rasqal/sparql_common.h
new file mode 100644
index 0000000..f84301d
--- /dev/null
+++ b/src/rasqal/sparql_common.h
@@ -0,0 +1,63 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * sparql_common.h - SPARQL lexer/parser shared internals
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2004-2004, 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.
+ *
+ */
+
+#ifndef SPARQL_COMMON_H
+#define SPARQL_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* sparql_parser.y */
+int sparql_syntax_error(rasqal_query *rq, const char *message, ...) RASQAL_PRINTF_FORMAT(2, 3);
+int sparql_syntax_warning(rasqal_query *rq, const char *message, ...) RASQAL_PRINTF_FORMAT(2, 3);
+
+int sparql_query_lex(void);
+
+
+struct rasqal_sparql_query_language_s {
+ /* STATIC lexer */
+ yyscan_t scanner;
+
+ int scanner_set;
+
+ /* for error reporting */
+ unsigned int lineno;
+
+ /* SPARQL extended */
+ int extended;
+
+ /* count of errors in current query parse */
+ int error_count;
+};
+
+
+typedef struct rasqal_sparql_query_language_s rasqal_sparql_query_language;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/rasqal/sparql_lexer.l b/src/rasqal/sparql_lexer.l
new file mode 100644
index 0000000..cf8db7b
--- /dev/null
+++ b/src/rasqal/sparql_lexer.l
@@ -0,0 +1,1610 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * sparql_lexer.l - Rasqal SPARQL lexer - making tokens for sparql grammar generator
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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.
+ *
+ * To generate the C files from this source, rather than use the
+ * shipped sparql_lexer.c/.h needs a patched version of flex 2.5.31 such
+ * as the one available in Debian GNU/Linux. Details below
+ * near the %option descriptions.
+ *
+ * SPARQL defined in http://www.w3.org/TR/rdf-sparql-query/
+ * http://www.w3.org/TR/2005/WD-rdf-sparql-query-20050419/
+ *
+ * Editor's draft of above http://www.w3.org/2001/sw/DataAccess/rq23/
+ */
+
+
+/* recognise 8-bits */
+%option 8bit
+%option warn nodefault
+
+/* all symbols prefixed by this */
+%option prefix="sparql_lexer_"
+
+/* This is not needed, flex is invoked -osparql_lexer.c */
+%option outfile="sparql_lexer.c"
+
+/* Emit a C header file for prototypes
+ * Only available in flex 2.5.13 or newer.
+ * It was renamed to header-file in flex 2.5.19
+ */
+%option header-file="sparql_lexer.h"
+
+/* Do not emit #include <unistd.h>
+ * Only available in flex 2.5.7 or newer.
+ * Broken in flex 2.5.31 without patches.
+ */
+%option nounistd
+
+/* Never interactive */
+/* No isatty() check */
+%option never-interactive
+
+/* Batch scanner */
+%option batch
+
+/* Never use yyunput */
+%option nounput
+
+/* Supply our own alloc/realloc/free functions */
+%option noyyalloc noyyrealloc noyyfree
+
+/* Re-entrant scanner */
+%option reentrant
+
+
+%x ID SPID PREF LITERAL LITERAL2
+
+ /* definitions */
+
+%{
+
+/* NOTE: These headers are NOT included here. They are inserted by fix-flex
+ * since otherwise it appears far too late in the generated C
+ */
+
+/*
+#ifdef HAVE_CONFIG_H
+#include <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#include <rasqal.h>
+#include <rasqal_internal.h>
+
+#include <sparql_parser.h>
+
+#include <sparql_common.h>
+
+
+
+static int sparql_skip_c_comment(rasqal_query *rq);
+
+/*
+ * Extra checks beyond valid Namespaces in XML 1.1 name
+ *
+ * SPARQL_NAME_CHECK_VARNAME (token VARNAME)
+ * No '.' allowed.
+ * No '-' allowed.
+ *
+ * SPARQL_NAME_CHECK_PREFIX (token NCNAME_PREFIX)
+ * No '_' allowed as the first character.
+ * No '.' allowed as the last character.
+ *
+ * SPARQL_NAME_CHECK_NCNAME (token NCNAME)
+ * [0-9] allowed as the first character
+ * No '.' allowed as the first character.
+ * No '.' allowed as the last character.
+ *
+*/
+typedef enum {
+ SPARQL_NAME_CHECK_NO_UL_FIRST = 1,
+ SPARQL_NAME_CHECK_NO_DOT_LAST = 2,
+ SPARQL_NAME_CHECK_NO_DOT_MINUS = 4,
+ SPARQL_NAME_CHECK_ALLOW_09_FIRST = 8,
+
+ SPARQL_NAME_CHECK_VARNAME = SPARQL_NAME_CHECK_NO_DOT_MINUS,
+ SPARQL_NAME_CHECK_PREFIX = SPARQL_NAME_CHECK_NO_UL_FIRST | SPARQL_NAME_CHECK_NO_DOT_LAST,
+ SPARQL_NAME_CHECK_NCNAME = SPARQL_NAME_CHECK_NO_DOT_LAST | SPARQL_NAME_CHECK_ALLOW_09_FIRST
+} sparql_name_check_flags;
+
+
+static int rasqal_sparql_name_check(unsigned char *string, size_t length, sparql_name_check_flags check_flags);
+static unsigned char *sparql_copy_name(rasqal_query *rq, const unsigned char *text, size_t len, sparql_name_check_flags check_flags);
+static raptor_uri* sparql_copy_qname(rasqal_query *rq, const unsigned char *text, size_t len);
+static int sparql_copy_string_token(rasqal_query *rq, YYSTYPE* lval, const unsigned char *text, size_t len, int delim);
+
+#ifdef RASQAL_DEBUG
+const char * sparql_token_print(rasqal_world* world, int token, YYSTYPE *lval);
+#endif
+
+int sparql_lexer_lex (YYSTYPE *sparql_parser_lval, yyscan_t yyscanner);
+#define YY_DECL int sparql_lexer_lex (YYSTYPE *sparql_parser_lval, yyscan_t yyscanner)
+
+#ifdef __cplusplus
+#define INPUT_FN yyinput
+#else
+#define INPUT_FN input
+#endif
+
+/* Remove the re-fill function since it should never be called */
+#define YY_INPUT(buf,result,max_size) { return YY_NULL; }
+
+
+/* Missing sparql_lexer.c/h prototypes */
+int sparql_lexer_get_column(yyscan_t yyscanner);
+void sparql_lexer_set_column(int column_no , yyscan_t yyscanner);
+
+static void sparql_lexer_cleanup(yyscan_t yyscanner);
+
+#ifdef HAVE_SETJMP
+static jmp_buf sparql_lexer_fatal_error_longjmp_env;
+
+/* fatal error handler declaration */
+#define YY_FATAL_ERROR(msg) do { \
+ sparql_lexer_fatal_error(msg, yyscanner); \
+ longjmp(sparql_lexer_fatal_error_longjmp_env, 1); \
+} while(0)
+#else
+#define YY_FATAL_ERROR(msg) do { \
+ sparql_lexer_fatal_error(msg, yyscanner); \
+ abort(); \
+} while(0)
+#endif
+
+static void sparql_lexer_fatal_error(yyconst char *msg, yyscan_t yyscanner);
+
+/* Fatal error handler that returns EOF instead of abort()/longjmp()
+ * so that parser can clean up properly */
+#define YY_FATAL_ERROR_EOF(msg) do { \
+ sparql_lexer_fatal_error(msg, yyscanner); \
+ yyterminate(); \
+} while(0)
+%}
+
+LANGUAGETOKEN [A-Za-z][-A-Z_a-z0-9]*
+
+
+/*
+ * rq23 is http://www.w3.org/2001/sw/DataAccess/rq23/
+ * CVS ID 1.420 2005/07/12 15:38:40
+ */
+
+
+/* [85] NCCHAR1p ::= [A-Z] | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] |
+ * [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] |
+ * [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] |
+ * [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] |
+ * [#x10000-#xEFFFF]
+ *
+ * This is an XML 1.1 NameStartChar
+ * http://www.w3.org/TR/2004/REC-xml11-20040204/#NT-NameStartChar
+ * except
+ * No '_' allowed.
+ */
+NCCHAR1p [A-Za-z\\\x80-\xff]
+
+/* [86] NCCHAR1 ::= NCCHAR1p | '_'
+ * This is an XML 1.1 NameStartChar
+ * http://www.w3.org/TR/2004/REC-xml11-20040204/#NT-NameStartChar
+ */
+NCCHAR1 [A-Za-z\\\x80-\xff_]
+
+NCCHAR2 [A-Za-z\\\x80-\xff_0-9]
+
+/* [87] VARNAME ::= ( NCCHAR1 | _ )
+ * ( NCCHAR1 | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )*
+ *
+ * This is an Namespaces in XML 1.1 Name except:
+ * No '.' allowed.
+ * No '-' allowed.
+ */
+VARNAME ({NCCHAR1}|[0-9])({NCCHAR1}|[0-9])*
+
+/* [88] NCCHAR ::=
+ * NCCHAR1 | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
+ *
+ * This is XML 1.1 NameChar
+ * http://www.w3.org/TR/2004/REC-xml11-20040204/#NT-NameChar
+ * except:
+ * No '.' allowed.
+ */
+NCCHAR {NCCHAR1}|"-"|[0-9]
+
+/* [89] NCNAME_PREFIX ::= NCCHAR1p ((NCCHAR|".")* NCCHAR)?
+ *
+ * This is an Namespaces in XML 1.1 Name except:
+ * No '_' allowed as the first character.
+ * No '.' allowed as the last character.
+ */
+NCNAME_PREFIX {NCCHAR1p}(({NCCHAR}|".")*{NCCHAR})?
+
+/* [90] NCNAME ::= NCCHAR1 ((NCCHAR|".")* NCCHAR)?
+ *
+ * This is an Namespaces in XML 1.1 Name except:
+ * No '.' allowed as the last character.
+ */
+NCNAME {NCCHAR1}(({NCCHAR}|".")*{NCCHAR})?
+
+/* SPARQL allows [0-9] after a : in the
+ * W3C Candidate Recommendation 14 June 2007
+ * as an at risk feature that may be removed.
+ */
+NCNAME2 {NCCHAR2}(({NCCHAR}|".")*{NCCHAR})?
+
+/* rq23 [67] QNAME_NS ::= NCNAME_PREFIX? ':'
+ * Inlined into in rule <PREF>{NCNAME_PREFIX}":" below
+ */
+
+/* rq23 [68] QNAME ::= NCNAME_PREFIX? ':' NCNAME? */
+QNAME {NCNAME_PREFIX}?":"{NCNAME2}?
+
+/* rq23 [69] BNODE_LABEL (renamed to BNAME) ::= '_:' NCNAME */
+BNAME "_:"{NCNAME2}
+
+/* a blank node name written inside a URI - this is an illegal
+ * URI form and for convienence
+ */
+BNAME2 "<_:"{NCNAME2}">"
+
+/* The initial char conditions are to ensure this doesn't grab < or <=
+ * as operators. starting with <_: is caught by BNAME2 above.
+ **/
+QUOTEDURI \<[^><= ][^>]*\>|"<>"
+
+INTEGER [0-9]+
+DECIMAL [0-9]+"."[0-9]*|"."[0-9]+
+DOUBLE [0-9]+"."[0-9]*{EXPONENT}|"."([0-9])+{EXPONENT}|([0-9])+{EXPONENT}
+EXPONENT [eE][+-]?[0-9]+
+
+
+%%
+ /* rules */
+
+%{
+
+ int c;
+ rasqal_query *rq=(rasqal_query*)yyextra;
+ rasqal_sparql_query_language *rqe=(rasqal_sparql_query_language*)rq->context;
+
+#ifdef HAVE_SETJMP
+ if(setjmp(sparql_lexer_fatal_error_longjmp_env))
+ return 1;
+#endif
+
+%}
+
+"//"[^\r\n]*(\r\n|\r|\n) { /* C++ comment */
+ rqe->lineno++;
+}
+
+"/*" { int lines=sparql_skip_c_comment(rq);
+ if(lines < 0)
+ yyterminate();
+ rqe->lineno += lines;
+ }
+
+\r\n|\r|\n { rqe->lineno++; }
+
+[\ \t\v]+ { /* eat up other whitespace */
+ ;
+}
+
+[Ss][Ee][Ll][Ee][Cc][Tt] { return SELECT; }
+[Ff][Rr][Oo][Mm] { return FROM; }
+[Ww][Hh][Ee][Rr][Ee] { return WHERE; }
+[Pp][Rr][Ee][Ff][Ii][Xx] { BEGIN(PREF);
+ return PREFIX; }
+[Dd][Ee][Ss][Cc][Rr][Ii][Bb][Ee] { return DESCRIBE; }
+[Cc][Oo][Nn][Ss][Tt][Rr][Uu][Cc][Tt] { return CONSTRUCT; }
+[Aa][Ss][Kk] { return ASK; }
+[Dd][Ii][Ss][Tt][Ii][Nn][Cc][Tt] { return DISTINCT; }
+[Rr][Ee][Dd][Uu][Cc][Ee][Dd] { return REDUCED; }
+[Ll][Ii][Mm][Ii][Tt] { return LIMIT; }
+[Uu][Nn][Ii][Oo][Nn] { return UNION; }
+[Oo][Pp][Tt][Ii][Oo][Nn][Aa][Ll] { return OPTIONAL; }
+[Bb][Aa][Ss][Ee] { return BASE; }
+[Bb][Oo][Uu][Nn][Dd] { return BOUND; }
+[Ss][Tt][Rr] { return STR; }
+[Ll][Aa][Nn][Gg] { return LANG; }
+[Dd][Aa][Tt][Aa][Tt][Yy][Pp][Ee] { return DATATYPE; }
+[Ii][Ss][UuIi][Rr][Ii] { return ISURI; } /* isURI and isIRI */
+[Ii][Ss][Bb][Ll][Aa][Nn][Kk] { return ISBLANK; }
+[Ii][Ss][Ll][Ii][Tt][Ee][Rr][Aa][Ll] { return ISLITERAL; }
+[Gg][Rr][Aa][Pp][Hh] { return GRAPH; }
+[Nn][Aa][Mm][Ee][Dd] { return NAMED; }
+[Ff][Ii][Ll][Tt][Ee][Rr] { return FILTER; }
+[Oo][Ff][Ff][Ss][Ee][Tt] { return OFFSET; }
+[Oo][Rr][Dd][Ee][Rr] { return ORDER; }
+[Bb][Yy] { return BY; }
+[Rr][Ee][Gg][Ee][Xx] { return REGEX; }
+[Aa][Ss][Cc] { return ASC; }
+[Dd][Ee][Ss][Cc] { return DESC; }
+[Ll][Aa][Nn][Gg][Mm][Aa][Tt][Cc][Hh][Ee][Ss] { return LANGMATCHES; }
+[Ee][Xx][Pp][Ll][Aa][Ii][Nn] { return EXPLAIN; }
+[Gg][Rr][Oo][Uu][Pp] { return GROUP; }
+[Cc][Oo][Uu][Nn][Tt] { return COUNT; }
+[Aa][Ss] { BEGIN(SPID); return AS; }
+[Dd][Ee][Ll][Ee][Tt][Ee] { return DELETE; }
+[Ii][Nn][Ss][Ee][Rr][Tt] { return INSERT; }
+[Ss][Aa][Mm][Ee][Tt][Ee][Rr][Mm] { return SAMETERM; }
+
+"a" { return A; }
+
+"," { return ','; }
+"(" { return '('; }
+")" { return ')'; }
+"[" { return '['; }
+"]" { return ']'; }
+"?" { BEGIN(ID); return '?'; }
+"$" { BEGIN(ID); return '$'; }
+"{" { return '{'; }
+"}" { return '}'; }
+"." { return '.'; }
+";" { return ';'; }
+
+"||" { return SC_OR; }
+"&&" { return SC_AND; }
+
+"=" { return EQ; }
+"!=" { return NEQ; }
+"<"/[^A-Za-z=>] { return LT; }
+">" { return GT; }
+"<=" { return LE; }
+">=" { return GE; }
+
+"*" { return '*'; }
+"/" { return '/'; }
+"!" { return '!'; }
+
+
+[-+]?{INTEGER} { c=*yytext;
+ sparql_parser_lval->literal=rasqal_new_typed_literal(rq->world, RASQAL_LITERAL_INTEGER, (const unsigned char*)yytext);
+ if(!sparql_parser_lval->literal)
+ YY_FATAL_ERROR_EOF("rasqal_new_typed_literal failed");
+ return (c=='+' ? INTEGER_POSITIVE_LITERAL : (c == '-' ? INTEGER_NEGATIVE_LITERAL : INTEGER_LITERAL));
+}
+
+[-+]?{DECIMAL} {
+ c=*yytext;
+
+ if(!rasqal_xsd_datatype_check(RASQAL_LITERAL_DECIMAL, (const unsigned char*)yytext, 0)) {
+ sparql_syntax_error(rq, "SPARQL syntax error - Illegal decimal constant %s", yytext);
+ yyterminate();
+ }
+ sparql_parser_lval->literal=rasqal_new_decimal_literal(rq->world, (const unsigned char*)yytext);
+ if(!sparql_parser_lval->literal)
+ YY_FATAL_ERROR_EOF("rasqal_new_decimal_literal failed");
+ return (c=='+' ? DECIMAL_POSITIVE_LITERAL : (c == '-' ? DECIMAL_NEGATIVE_LITERAL : DECIMAL_LITERAL));
+}
+
+[-+]?{DOUBLE} {
+ c=*yytext;
+ if(!rasqal_xsd_datatype_check(RASQAL_LITERAL_DOUBLE, (const unsigned char*)yytext, 0)) {
+ sparql_syntax_error(rq, "SPARQL syntax error - Illegal double constant %s", yytext);
+ yyterminate();
+ }
+ sparql_parser_lval->literal=rasqal_new_typed_literal(rq->world, RASQAL_LITERAL_DOUBLE, (const unsigned char*)yytext);
+ if(!sparql_parser_lval->literal)
+ YY_FATAL_ERROR_EOF("rasqal_new_typed_literal failed");
+ return (c=='+' ? DOUBLE_POSITIVE_LITERAL : (c == '-' ? DOUBLE_NEGATIVE_LITERAL : DOUBLE_LITERAL));
+}
+
+"+" { return '+'; }
+"-" { return '-'; }
+
+'([^'\\\n\r]|\\[^\n\r])*'(@{LANGUAGETOKEN})?(^^({QUOTEDURI}|{QNAME}))? { /*' */
+ if(sparql_copy_string_token(rq, sparql_parser_lval,
+ (const unsigned char*)yytext+1, yyleng-1, '\''))
+ YY_FATAL_ERROR_EOF("sparql_copy_string_token failed");
+ return STRING_LITERAL; }
+
+\"([^"\\\n\r]|\\[^\n\r])*\"(@{LANGUAGETOKEN})?(^^({QUOTEDURI}|{QNAME}))? { /* " */
+ if(sparql_copy_string_token(rq, sparql_parser_lval,
+ (const unsigned char*)yytext+1, yyleng-1, '"'))
+ YY_FATAL_ERROR_EOF("sparql_copy_string_token failed");
+ return STRING_LITERAL; }
+
+\"\"\" { BEGIN(LITERAL); }
+
+<LITERAL>(.|\n)*\"\"\"(^^({QUOTEDURI}|{QNAME}))? { if(sparql_copy_string_token(rq, sparql_parser_lval,
+ (unsigned char*)yytext, yyleng, '"')) /* ' */
+ YY_FATAL_ERROR_EOF("sparql_copy_string_token failed");
+ BEGIN(INITIAL);
+ return STRING_LITERAL; }
+
+<LITERAL>(.|\n) { BEGIN(INITIAL);
+ if (!*yytext)
+ return EOF;
+
+ sparql_syntax_error(rq, "syntax error at %c - \"\"\"string was not terminated", *yytext);
+ yyterminate(); }
+
+
+\'\'\' { BEGIN(LITERAL2); }
+
+<LITERAL2>(.|\n)*\'\'\'(^^({QUOTEDURI}|{QNAME}))? { if(sparql_copy_string_token(rq, sparql_parser_lval,
+ (unsigned char*)yytext, yyleng, '\''))
+ YY_FATAL_ERROR_EOF("sparql_copy_string_token failed");
+ BEGIN(INITIAL);
+ return STRING_LITERAL; }
+
+<LITERAL2>(.|\n) { BEGIN(INITIAL);
+ if (!*yytext)
+ return EOF;
+
+ sparql_syntax_error(rq, "syntax error at %c - '''string was not terminated", *yytext);
+ yyterminate(); }
+
+
+[Tt][Rr][Uu][Ee] { sparql_parser_lval->literal=rasqal_new_boolean_literal(rq->world, 1);
+ if(!sparql_parser_lval->literal)
+ YY_FATAL_ERROR_EOF("rasqal_new_boolean_literal failed");
+ return BOOLEAN_LITERAL; }
+
+[Ff][Aa][Ll][Ss][Ee] { sparql_parser_lval->literal=rasqal_new_boolean_literal(rq->world, 0);
+ if(!sparql_parser_lval->literal)
+ YY_FATAL_ERROR_EOF("rasqal_new_boolean_literal failed");
+ return BOOLEAN_LITERAL; }
+
+<ID>{VARNAME} { sparql_parser_lval->name=sparql_copy_name(rq, (const unsigned char*)yytext, yyleng, SPARQL_NAME_CHECK_VARNAME);
+ if(!sparql_parser_lval->name)
+ YY_FATAL_ERROR_EOF("sparql_copy_name failed");
+ BEGIN(INITIAL);
+ return IDENTIFIER; }
+<ID>(.|\n) { BEGIN(INITIAL);
+ sparql_syntax_error(rq, "SPARQL syntax error - missing variable name after ?");
+ yyterminate();
+}
+
+<SPID>[\ \t\v]+ { /* eat up leading whitespace */
+ ;
+}
+<SPID>{VARNAME} { sparql_parser_lval->name=sparql_copy_name(rq, (const unsigned char*)yytext, yyleng, SPARQL_NAME_CHECK_VARNAME);
+ if(!sparql_parser_lval->name)
+ YY_FATAL_ERROR_EOF("sparql_copy_name failed");
+ BEGIN(INITIAL);
+ return IDENTIFIER; }
+
+<SPID>(.|\n) { BEGIN(INITIAL);
+ sparql_syntax_error(rq, "SPARQL syntax error - missing variable name after ?");
+ yyterminate();
+}
+
+<PREF>[\ \t\v]+ { /* eat up leading whitespace */ }
+<PREF>{NCNAME_PREFIX}":" { BEGIN(INITIAL);
+ sparql_parser_lval->name=sparql_copy_name(rq, (const unsigned char*)yytext, yyleng-1, SPARQL_NAME_CHECK_PREFIX);
+ if(!sparql_parser_lval->name)
+ YY_FATAL_ERROR_EOF("sparql_copy_name failed");
+ return IDENTIFIER; }
+<PREF>":" { BEGIN(INITIAL);
+ sparql_parser_lval->name=NULL;
+ return IDENTIFIER; }
+
+<PREF>(.|\n) { BEGIN(INITIAL);
+ if (!*yytext)
+ return EOF;
+
+ sparql_syntax_error(rq, "SPARQL syntax error at '%c'", *yytext);
+ yyterminate();
+}
+
+{QNAME}\(? {
+ int have_brace=(yytext[yyleng-1]=='(');
+ if(have_brace)
+ yyleng--;
+ sparql_parser_lval->uri=sparql_copy_qname(rq, (const unsigned char*)yytext, yyleng);
+ if(!sparql_parser_lval->uri)
+ YY_FATAL_ERROR_EOF("sparql_copy_qname failed");
+ return have_brace ? URI_LITERAL_BRACE : URI_LITERAL;
+}
+
+{BNAME} { sparql_parser_lval->name=sparql_copy_name(rq, (unsigned char*)yytext+2, yyleng-2, SPARQL_NAME_CHECK_NCNAME);
+ return BLANK_LITERAL;
+}
+
+{BNAME2} { sparql_parser_lval->name=sparql_copy_name(rq, (unsigned char*)yytext+3, yyleng-4, SPARQL_NAME_CHECK_NCNAME);
+ return BLANK_LITERAL;
+}
+
+{QUOTEDURI}\(? {
+ int have_brace=(yytext[yyleng-1]=='(');
+ if(have_brace)
+ yyleng--;
+ if(yyleng == 2)
+#ifdef RAPTOR_V2_AVAILABLE
+ sparql_parser_lval->uri = raptor_uri_copy_v2(rq->world->raptor_world_ptr, rq->base_uri);
+#else
+ sparql_parser_lval->uri = raptor_uri_copy(rq->base_uri);
+#endif
+ else {
+ unsigned char* uri_string;
+
+ yytext[yyleng-1]='\0';
+ uri_string=rasqal_escaped_name_to_utf8_string((unsigned char*)yytext+1,
+ yyleng-1,
+ NULL,
+ (raptor_simple_message_handler)sparql_syntax_error, rq);
+ if(!uri_string)
+ YY_FATAL_ERROR_EOF("rasqal_escaped_name_to_utf8_string failed");
+
+#ifdef RAPTOR_V2_AVAILABLE
+ sparql_parser_lval->uri = raptor_new_uri_relative_to_base_v2(rq->world->raptor_world_ptr, rq->base_uri, uri_string);
+#else
+ sparql_parser_lval->uri = raptor_new_uri_relative_to_base(rq->base_uri, uri_string);
+#endif
+ RASQAL_FREE(cstring, uri_string);
+ if(!sparql_parser_lval->uri)
+ YY_FATAL_ERROR_EOF("raptor_new_uri_relative_to_base failed");
+ }
+ return have_brace ? URI_LITERAL_BRACE : URI_LITERAL; }
+
+\#[^\r\n]*(\r\n|\r|\n) { /* # comment */
+ rqe->lineno++;
+ }
+
+. { if (!*yytext)
+ return EOF;
+
+ sparql_syntax_error(rq, "SPARQL syntax error at '%c'", *yytext);
+ yyterminate();
+ }
+
+%%
+ /* user code */
+
+int
+yywrap (yyscan_t yyscanner) {
+ return 1;
+}
+
+
+static int
+rasqal_sparql_name_check(unsigned char *string, size_t length,
+ sparql_name_check_flags check_flags)
+{
+ int rc=0;
+ int c= -1;
+#if RASQAL_DEBUG > 2
+ RASQAL_DEBUG1("Checking name '");
+ if(length)
+ fwrite(string, length, sizeof(unsigned char), stderr);
+ fprintf(stderr, "' (length %d), flags %d\n", (int)length, (int)check_flags);
+#endif
+
+ if(!length)
+ return 1;
+
+ if(check_flags && SPARQL_NAME_CHECK_ALLOW_09_FIRST &&
+ (*string >= '0' && *string <= '9')) {
+ c=*string;
+ *string='X';
+ }
+
+ if(!raptor_xml_name_check(string, length, 11)) /* 11 = XML 1.1 */
+ goto done;
+
+ if((check_flags & SPARQL_NAME_CHECK_NO_UL_FIRST) && *string == '_')
+ goto done;
+
+ if((check_flags & SPARQL_NAME_CHECK_NO_DOT_LAST) && string[length-1] == '.')
+ goto done;
+
+ if(check_flags & SPARQL_NAME_CHECK_NO_DOT_MINUS) {
+ int i;
+ for(i=0; i < (int)length; i++)
+ if(string[i] == '.' || string[i] == '-')
+ goto done;
+ }
+ rc=1;
+
+ done:
+ if(c >=0)
+ *string=c;
+ return rc;
+}
+
+
+static unsigned char *
+sparql_copy_name(rasqal_query *rq, const unsigned char *text, size_t len,
+ sparql_name_check_flags check_flags) {
+ size_t dest_len=0;
+ unsigned char *s;
+
+ s=rasqal_escaped_name_to_utf8_string((unsigned char*)text, len,
+ &dest_len,
+ (raptor_simple_message_handler)sparql_syntax_error, rq);
+ if(!s)
+ return s;
+
+ if(!rasqal_sparql_name_check(s, dest_len, check_flags))
+ sparql_syntax_error(rq, "Invalid SPARQL name \"%s\"", s);
+
+ return s;
+}
+
+
+static raptor_uri*
+sparql_copy_qname(rasqal_query *rq, const unsigned char *text, size_t len) {
+ unsigned char *p;
+ size_t dest_len=0;
+ unsigned char *s;
+ raptor_uri* uri=NULL;
+
+ s=rasqal_escaped_name_to_utf8_string((unsigned char*)text, len,
+ &dest_len,
+ (raptor_simple_message_handler)sparql_syntax_error, rq);
+ if(!s)
+ return NULL;
+
+ p=(unsigned char*)strchr((const char*)s, ':');
+ if(!rasqal_sparql_name_check(s, p-s, SPARQL_NAME_CHECK_PREFIX))
+ sparql_syntax_error(rq, "Invalid SPARQL prefix name \"%s\"", s);
+ if(!rasqal_sparql_name_check(p+1, dest_len-((p+1)-s), SPARQL_NAME_CHECK_NCNAME))
+ sparql_syntax_error(rq, "Invalid SPARQL local name \"%s\"", p+1);
+
+#ifdef STANDALONE
+ /* lexer test cannot declare namespaces - so just ignore expansion */
+# ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_new_uri_relative_to_base_v2(rq->world->raptor_world_ptr, rq->base_uri, s);
+# else
+ uri = raptor_new_uri_relative_to_base(rq->base_uri, s);
+# endif
+#else
+ if(!rq->namespaces) {
+ sparql_syntax_error(rq, "SPARQL syntax error - no namespaces declared");
+ return NULL;
+ }
+
+ uri=raptor_qname_string_to_uri(rq->namespaces,
+ s, dest_len,
+ (raptor_simple_message_handler)rasqal_query_simple_error, rq);
+#endif
+ RASQAL_FREE(cstring, s);
+
+ return uri;
+}
+
+
+static int
+sparql_copy_string_token(rasqal_query* rq, YYSTYPE* lval,
+ const unsigned char *text, size_t len, int delim) {
+ unsigned int i;
+ const unsigned char *s;
+ unsigned char *d;
+ unsigned char *string;
+ char *language=NULL;
+ unsigned char *dt=NULL;
+ raptor_uri *dt_uri=NULL;
+ unsigned char *dt_qname=NULL;
+
+ string=(unsigned char *)RASQAL_MALLOC(cstring, len+1);
+ if(!string)
+ return 1;
+
+ for(s=text, d=string, i=0; i<len; s++, i++) {
+ unsigned char c=*s;
+
+ if(c == '\\' ) {
+ s++; i++;
+ c=*s;
+ if(c == 'n')
+ *d++= '\n';
+ else if(c == 'r')
+ *d++= '\r';
+ else if(c == 't')
+ *d++= '\t';
+ else if(c == '\\' || c == delim)
+ *d++=c;
+ else if (c == 'u' || c == 'U') {
+ int ulen=(c == 'u') ? 4 : 8;
+ unsigned long unichar=0;
+ int n;
+
+ s++; i++;
+ if(i+ulen > len) {
+ printf("\\%c over end of line", c);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+
+ n=sscanf((const char*)s, ((ulen == 4) ? "%04lx" : "%08lx"), &unichar);
+ if(n != 1) {
+ sparql_syntax_error(rq, "SPARQL syntax error - Illegal Uncode escape '%c%s...'", c, s);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+
+ s+= ulen-1;
+ i+= ulen-1;
+
+ if(unichar > 0x10ffff) {
+ sparql_syntax_error(rq, "SPARQL syntax error - Illegal Unicode character with code point #x%lX.", unichar);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+
+ d+=raptor_unicode_char_to_utf8(unichar, d);
+ } else {
+ /* Ignore \x where x isn't the one of: \n \r \t \\ (delim) \u \U */
+ sparql_syntax_warning(rq, "Unknown SPARQL string escape \\%c in \"%s\"", c, text);
+ *d++=c;
+ }
+ } else if(c== delim) {
+ *d++='\0';
+
+ /* skip delims (', ", ''' or """) */
+ while(c == delim) {
+ c=*s++; i++;
+ }
+
+ if(c=='@') {
+ language=(char*)d;
+ while(i<=len) {
+ c=*s++; i++;
+ if(!isalpha(c) && !isdigit(c) && c!= '-')
+ break;
+ *d++=c;
+ }
+ *d++='\0';
+ }
+ if(c=='^') {
+ /* skip second char of ^^ */
+ s++; i++;
+
+ dt=d;
+ while(i++<=len)
+ *d++=*s++;
+ /* *d='\0' below */
+ } else if (language)
+ *d='\0';
+
+ break;
+ } else
+ *d++=c;
+ } /* end of for */
+
+ *d='\0';
+
+ if(language) {
+ char *new_language=(char *)RASQAL_MALLOC(cstring, strlen((const char*)language)+1);
+ if(!new_language) {
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+ strcpy(new_language, language);
+ language=new_language;
+ }
+
+ if(dt) {
+ /* dt can be a URI or qname */
+ if(*dt == '<') {
+ dt[strlen((const char*)dt)-1]='\0';
+#ifdef RAPTOR_V2_AVAILABLE
+ dt_uri = raptor_new_uri_v2(rq->world->raptor_world_ptr, dt+1);
+#else
+ dt_uri = raptor_new_uri(dt+1);
+#endif
+ if(!dt_uri) {
+ if(language)
+ RASQAL_FREE(cstring, language);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+ } else {
+ unsigned char *dt_p;
+ size_t dest_len=0;
+ unsigned char *dt_s;
+
+ dt_s=rasqal_escaped_name_to_utf8_string(dt,
+ strlen((const char*)dt),
+ &dest_len,
+ (raptor_simple_message_handler)sparql_syntax_error, rq);
+ if(!dt_s) {
+ if(language)
+ RASQAL_FREE(cstring, language);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+
+ dt_p=(unsigned char*)strchr((const char*)dt_s, ':');
+ if(!rasqal_sparql_name_check(dt_s, dt_p-dt_s, SPARQL_NAME_CHECK_PREFIX))
+ sparql_syntax_error(rq, "Invalid SPARQL prefix name \"%s\"", dt_s);
+ if(!rasqal_sparql_name_check(dt_p+1, dest_len-((dt_p+1)-dt_s),
+ SPARQL_NAME_CHECK_NCNAME))
+ sparql_syntax_error(rq, "Invalid SPARQL local name \"%s\"", dt_p+1);
+
+#ifdef STANDALONE
+ /* lexer test cannot declare namespaces - so just ignore expansion */
+ dt_qname=dt_s;
+#else
+ if(!rq->namespaces) {
+ sparql_syntax_error(rq, "SPARQL syntax error - no namespaces declared");
+ RASQAL_FREE(cstring, dt_s);
+ if(language)
+ RASQAL_FREE(cstring, language);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+
+ dt_uri=raptor_qname_string_to_uri(rq->namespaces,
+ dt_s, dest_len,
+ (raptor_simple_message_handler)rasqal_query_simple_error, rq);
+ RASQAL_FREE(cstring, dt_s);
+
+ if(!dt_uri) {
+ if(language)
+ RASQAL_FREE(cstring, language);
+ RASQAL_FREE(cstring, string);
+ return 1;
+ }
+#endif
+ }
+ }
+
+#if RASQAL_DEBUG >3
+ fprintf(stderr, "string='%s', language='%s'\n",
+ string, (language ? language : ""));
+ fprintf(stderr, "datatype uri='%s'\n",
+ (dt_uri ? (const char*)raptor_uri_as_string(dt_uri) : ""));
+#endif
+
+ lval->literal=rasqal_new_string_literal(rq->world, string, language, dt_uri, dt_qname);
+ if(!lval->literal)
+ return 1;
+
+ return 0;
+}
+
+
+static int
+sparql_skip_c_comment(rasqal_query *rq) {
+ rasqal_sparql_query_language *rqe=(rasqal_sparql_query_language*)rq->context;
+ yyscan_t yyscanner=rqe->scanner;
+ int lines=0;
+ int c;
+ int lastc= -1;
+
+ while(1) {
+ while ((c=INPUT_FN(yyscanner)) != '*' && c!= EOF) {
+ if(c == '\r' || (c == '\n' && lastc != '\r'))
+ lines++;
+ lastc= c;
+ }
+ if( c == '*') {
+ while ((c=INPUT_FN(yyscanner)) == '*') {
+ if(c == '\r' || (c == '\n' && lastc != '\r'))
+ lines++;
+ lastc= c;
+ }
+
+ if(c == '/')
+ break;
+ }
+ if (c == EOF) {
+ sparql_syntax_error(rq, "SPARQL syntax error - EOF in comment");
+ lines= -1;
+ break;
+ }
+ lastc= c;
+ }
+ return lines;
+}
+
+
+/*
+ * sparql_lexer_fatal_error:
+ * @msg:
+ * @yyscanner:
+ *
+ * INTERNAL - replacement for the generated error handler.
+ * Uses rasqal_query_fatal_error() when possible.
+ */
+static void sparql_lexer_fatal_error(yyconst char *msg, yyscan_t yyscanner)
+{
+ rasqal_query *rq=NULL;
+
+ if(yyscanner)
+ rq=(rasqal_query *)sparql_lexer_get_extra(yyscanner);
+
+ if(rq) {
+ /* avoid "format not a string literal and no format arguments" warning with %s */
+ rq->failed=1;
+ rasqal_log_error_simple(rq->world, RAPTOR_LOG_LEVEL_FATAL,
+ &rq->locator, "%s", msg);
+ } else {
+ fputs(msg, stderr);
+ fputc('\n', stderr);
+ }
+}
+
+
+/* Define LEXER_ALLOC_TRACKING to enable allocated memory tracking
+ * - fixes lexer memory leak when ensure_buffer_stack fails
+ */
+
+#ifdef LEXER_ALLOC_TRACKING
+typedef struct {
+ /* Number of void* slots allocated */
+ int lexer_allocs_size;
+ /* Allocted void* slots follow in memory after this header */
+} lexer_alloc_tracker_header;
+
+/* Initial alloc tracker slot array size - 2 seems to be enough for almost all cases */
+static const int initial_lexer_allocs_size=2;
+#endif
+
+/*
+ * sparql_lexer_cleanup:
+ * @yyscanner:
+ *
+ * INTERNAL - Clean up unfreed lexer allocs if LEXER_ALLOC_TRACKING is enabled.
+ */
+static void sparql_lexer_cleanup(yyscan_t yyscanner)
+{
+#ifdef LEXER_ALLOC_TRACKING
+ rasqal_query *rq;
+ lexer_alloc_tracker_header *tracker;
+ void **lexer_allocs;
+ int i;
+
+ if(!yyscanner)
+ return;
+
+ rq=(rasqal_query *)sparql_lexer_get_extra(yyscanner);
+ if(!rq)
+ return;
+
+ tracker=(lexer_alloc_tracker_header *)rq->lexer_user_data;
+ if(!tracker)
+ return;
+ lexer_allocs=(void**)&tracker[1];
+
+ for(i=0; i<tracker->lexer_allocs_size; ++i) {
+ if(lexer_allocs[i])
+ free(lexer_allocs[i]);
+ lexer_allocs[i]=NULL;
+ }
+ free(rq->lexer_user_data);
+ rq->lexer_user_data=NULL;
+#endif
+}
+
+
+/*
+ * sparql_lexer_alloc:
+ * @size
+ * @yyscanner
+ *
+ * INTERNAL - alloc replacement.
+ * Tracks allocated cells if LEXER_ALLOC_TRACKING is enabled.
+ */
+void *sparql_lexer_alloc(yy_size_t size, yyscan_t yyscanner)
+{
+#ifdef LEXER_ALLOC_TRACKING
+ rasqal_query *rq;
+ lexer_alloc_tracker_header *tracker;
+ void **lexer_allocs;
+ int i;
+ void *ptr;
+
+ /* yyscanner not initialized -> probably initializing yyscanner itself
+ * -> just malloc without tracking
+ */
+ if(!yyscanner)
+ return malloc(size);
+
+ rq=(rasqal_query *)sparql_lexer_get_extra(yyscanner);
+ if(!rq)
+ YY_FATAL_ERROR("lexer_alloc: yyscanner extra not initialized");
+
+ /* try to allocate tracker if it does not exist */
+ tracker=(lexer_alloc_tracker_header *)rq->lexer_user_data;
+ if(!tracker) {
+ /* allocate tracker header + array of void* slots */
+ tracker=(lexer_alloc_tracker_header*)calloc(1, sizeof(lexer_alloc_tracker_header)+initial_lexer_allocs_size*sizeof(void*));
+ if(!tracker)
+ YY_FATAL_ERROR("lexer_alloc: cannot allocate tracker");
+ tracker->lexer_allocs_size=initial_lexer_allocs_size;
+ rq->lexer_user_data=(void *)tracker;
+ }
+ lexer_allocs=(void**)&tracker[1];
+
+ /* allocate memory */
+ ptr=malloc(size);
+
+ /* find a free slot for ptr */
+ for(i=0; i<tracker->lexer_allocs_size; ++i) {
+ if(!lexer_allocs[i]) {
+ lexer_allocs[i]=ptr;
+ break;
+ }
+ }
+
+ /* no free slots -> grow tracker slot array */
+ if(i>=tracker->lexer_allocs_size) {
+ int j;
+ void **dest;
+ tracker=(lexer_alloc_tracker_header*)calloc(1, sizeof(lexer_alloc_tracker_header)+i*2*sizeof(void*));
+ if(!tracker) {
+ if(ptr)
+ free(ptr);
+ YY_FATAL_ERROR("lexer_alloc: cannot grow tracker");
+ }
+ tracker->lexer_allocs_size=i*2;
+
+ /* copy data from old tracker */
+ dest=(void**)&tracker[1];
+ for(j=0; j<i; ++j) {
+ dest[j]=lexer_allocs[j];
+ }
+
+ /* set new item to first free slot */
+ dest[j]=ptr;
+
+ /* free old tracker and replace with new one */
+ free(rq->lexer_user_data);
+ rq->lexer_user_data=tracker;
+ }
+
+ return ptr;
+#else
+ return malloc(size);
+#endif
+}
+
+
+/*
+ * sparql_lexer_realloc:
+ *
+ * INTERNAL - realloc replacement
+ * Tracks allocated cells if LEXER_ALLOC_TRACKING is enabled.
+ */
+void *sparql_lexer_realloc(void *ptr, yy_size_t size, yyscan_t yyscanner)
+{
+#ifdef LEXER_ALLOC_TRACKING
+ rasqal_query *rq;
+ lexer_alloc_tracker_header *tracker;
+ void **lexer_allocs;
+ int i;
+ void *newptr;
+
+ if(!yyscanner)
+ YY_FATAL_ERROR("lexer_realloc: yyscanner not initialized");
+
+ rq=(rasqal_query *)sparql_lexer_get_extra(yyscanner);
+ if(!rq)
+ YY_FATAL_ERROR("lexer_realloc: yyscanner extra not initialized");
+
+ tracker=(lexer_alloc_tracker_header *)rq->lexer_user_data;
+ if(!tracker)
+ YY_FATAL_ERROR("lexer_realloc: no alloc tracker");
+ lexer_allocs=(void**)&tracker[1];
+
+ /* find the old slot for ptr */
+ for(i=0; i<tracker->lexer_allocs_size; ++i) {
+ if(lexer_allocs[i]==ptr)
+ break;
+ }
+
+ /* no old slot -> error */
+ if(i>=tracker->lexer_allocs_size)
+ YY_FATAL_ERROR("lexer_realloc: cell not in tracker");
+
+ /* realloc */
+ newptr=realloc((char*)ptr, size);
+
+ /* replace entry in tracker */
+ lexer_allocs[i]=newptr;
+
+ return newptr;
+#else
+ return realloc((char*)ptr, size);
+#endif
+}
+
+
+/*
+ * sparql_lexer_free:
+ *
+ * INTERNAL - free replacement.
+ * Checks for NULL pointer to be freed unlike the default lexer free function.
+ * Tracks allocated cells if LEXER_ALLOC_TRACKING is enabled.
+ */
+void sparql_lexer_free(void *ptr, yyscan_t yyscanner)
+{
+#ifdef LEXER_ALLOC_TRACKING
+ rasqal_query *rq;
+ lexer_alloc_tracker_header *tracker;
+ void **lexer_allocs;
+ int i;
+
+ /* do not free NULL */
+ if(!ptr)
+ return;
+
+ /* free ptr even if we would encounter an error */
+ free(ptr);
+
+ /* yyscanner is allocated with sparql_lexer_alloc() but it's never stored in the tracker
+ * - we need yyscanner to access the tracker */
+ if(!yyscanner || ptr==yyscanner)
+ return;
+
+ rq=(rasqal_query *)sparql_lexer_get_extra(yyscanner);
+ if(!rq)
+ return;
+
+ tracker=(lexer_alloc_tracker_header *)rq->lexer_user_data;
+ if(!tracker)
+ return;
+ lexer_allocs=(void**)&tracker[1];
+
+ /* find the slot for ptr */
+ for(i=0; i<tracker->lexer_allocs_size; ++i) {
+ if(lexer_allocs[i]==ptr)
+ break;
+ }
+
+ /* no slot -> error */
+ if(i>=tracker->lexer_allocs_size)
+ YY_FATAL_ERROR("lexer_free: cell not in tracker");
+
+ /* remove entry from tracker */
+ lexer_allocs[i]=NULL;
+#else
+ if(ptr)
+ free(ptr);
+#endif
+}
+
+
+#ifdef RASQAL_DEBUG
+
+const char *
+sparql_token_print(rasqal_world* world, int token, YYSTYPE *lval)
+{
+ static char buffer[2048];
+
+ if(!token)
+ return "<<EOF>>";
+
+ switch(token) {
+ case SELECT:
+ return "SELECT";
+
+ case FROM:
+ return "FROM";
+
+ case WHERE:
+ return "WHERE";
+
+ case PREFIX:
+ return "PREFIX";
+
+ case DESCRIBE:
+ return "DESCRIBE";
+
+ case CONSTRUCT:
+ return "CONSTRUCT";
+
+ case ASK:
+ return "ASK";
+
+ case DISTINCT:
+ return "DISTINCT";
+
+ case LIMIT:
+ return "LIMIT";
+
+ case UNION:
+ return "UNION";
+
+ case OPTIONAL:
+ return "OPTIONAL";
+
+ case BASE:
+ return "BASE";
+
+ case BOUND:
+ return "BOUND";
+
+ case STR:
+ return "STR";
+
+ case LANG:
+ return "LANG";
+
+ case DATATYPE:
+ return "DATATYPE";
+
+ case ISURI:
+ return "ISURI";
+
+ case ISBLANK:
+ return "ISBLANK";
+
+ case ISLITERAL:
+ return "ISLITERAL";
+
+ case GRAPH:
+ return "GRAPH";
+
+ case NAMED:
+ return "NAMED";
+
+ case FILTER:
+ return "FILTER";
+
+ case OFFSET:
+ return "OFFSET";
+
+ case A:
+ return "a";
+
+ case ORDER:
+ return "ORDER";
+
+ case BY:
+ return "BY";
+
+ case REGEX:
+ return "REGEX";
+
+ case ASC:
+ return "ASC[";
+
+ case DESC:
+ return "DESC[";
+
+ case LANGMATCHES:
+ return "LANGMATCHES";
+
+ case ',':
+ return ",";
+
+ case '(':
+ return "(";
+
+ case ')':
+ return ")";
+
+ case '[':
+ return "[";
+
+ case ']':
+ return "]";
+
+ case '{':
+ return "{";
+
+ case '}':
+ return "}";
+
+ case '.':
+ return ".";
+
+ case ';':
+ return ";";
+
+ case '?':
+ return "?";
+
+ case '$':
+ return "$";
+
+ case SC_AND:
+ return "SC_AND";
+
+ case SC_OR:
+ return "SC_OR";
+
+ case GE:
+ return "GE";
+
+ case LE:
+ return "LE";
+
+ case GT:
+ return "GT";
+
+ case LT:
+ return "LT";
+
+ case NEQ:
+ return "NEQ";
+
+ case EQ:
+ return "EQ";
+
+ case '/':
+ return "/";
+
+ case '*':
+ return "*";
+
+ case '-':
+ return "-";
+
+ case '+':
+ return "+";
+
+ case '!':
+ return "!";
+
+ case EXPLAIN:
+ return "EXPLAIN";
+
+ case GROUP:
+ return "GROUP";
+
+ case COUNT:
+ return "COUNT";
+
+ case AS:
+ return "AS";
+
+ case INTEGER_LITERAL:
+ case INTEGER_POSITIVE_LITERAL:
+ case INTEGER_NEGATIVE_LITERAL:
+ sprintf(buffer, "INTEGER_LITERAL(%d)", lval->literal->value.integer);
+ return buffer;
+
+ case DOUBLE_LITERAL:
+ case DOUBLE_POSITIVE_LITERAL:
+ case DOUBLE_NEGATIVE_LITERAL:
+ sprintf(buffer, "DOUBLE_LITERAL(%g)", lval->floating);
+ return buffer;
+
+ case STRING_LITERAL:
+ if(lval->literal->language) {
+ if(lval->literal->datatype)
+ sprintf(buffer, "STRING_LITERAL(\"%s\"@%s^^%s)",
+ lval->literal->string, lval->literal->language,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, lval->literal->datatype)
+#else
+ raptor_uri_as_string(lval->literal->datatype)
+#endif
+ );
+ else
+ sprintf(buffer, "STRING_LITERAL(\"%s\"@%s)",
+ lval->literal->string, lval->literal->language);
+ } else {
+ if(lval->literal->datatype)
+ sprintf(buffer, "STRING_LITERAL(\"%s\"^^%s)",
+ lval->literal->string,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, lval->literal->datatype)
+#else
+ raptor_uri_as_string(lval->literal->datatype)
+#endif
+ );
+ else
+ sprintf(buffer, "STRING_LITERAL(\"%s\")", lval->literal->string);
+ }
+ return buffer;
+
+ case BOOLEAN_LITERAL:
+ return (lval->literal->value.integer ? "BOOLEAN_LITERAL(true)" : "BOOLEAN_LITERAL(false)");
+
+ case URI_LITERAL:
+ sprintf(buffer, "URI_LITERAL(%s)",
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, lval->uri)
+#else
+ raptor_uri_as_string(lval->uri)
+#endif
+ );
+ return buffer;
+
+ case QNAME_LITERAL:
+ sprintf(buffer, "QNAME_LITERAL(%s)", lval->name);
+ return buffer;
+
+ case URI_LITERAL_BRACE:
+ sprintf(buffer, "URI_LITERAL_BRACE(%s)",
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_as_string_v2(world->raptor_world_ptr, lval->uri)
+#else
+ raptor_uri_as_string(lval->uri)
+#endif
+ );
+ return buffer;
+
+ case QNAME_LITERAL_BRACE:
+ sprintf(buffer, "QNAME_LITERAL_BRACE(%s)", lval->name);
+ return buffer;
+
+ case IDENTIFIER:
+ sprintf(buffer, "IDENTIFIER(%s)", lval->name);
+ return buffer;
+
+ case BLANK_LITERAL:
+ sprintf(buffer, "BLANK_LITERAL(%s)", lval->name);
+ return buffer;
+
+ case DECIMAL_LITERAL:
+ case DECIMAL_POSITIVE_LITERAL:
+ case DECIMAL_NEGATIVE_LITERAL:
+ sprintf(buffer, "DECIMAL_LITERAL(%s)", lval->literal->string);
+ return buffer;
+
+ default:
+ RASQAL_DEBUG2("UNKNOWN token %d - add a new case\n", token);
+ abort();
+ }
+}
+#endif
+
+
+
+#ifdef STANDALONE
+static void
+sparql_token_free(rasqal_world* world, int token, YYSTYPE *lval)
+{
+ if(!token)
+ return;
+
+ switch(token) {
+ case STRING_LITERAL:
+ rasqal_free_literal(lval->literal);
+ break;
+ case URI_LITERAL:
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, lval->uri);
+#else
+ raptor_free_uri(lval->uri);
+#endif
+ break;
+ case IDENTIFIER:
+ case BLANK_LITERAL:
+ RASQAL_FREE(cstring, lval->name);
+ break;
+ case QNAME_LITERAL:
+ if(lval->name)
+ RASQAL_FREE(cstring, lval->name);
+ break;
+ default:
+ break;
+ }
+}
+
+
+#define FILE_READ_BUF_SIZE 2048
+
+int
+main(int argc, char *argv[])
+{
+ const char *program=rasqal_basename(argv[0]);
+ char *query_string=NULL;
+ rasqal_query rq;
+ rasqal_sparql_query_language sparql;
+ yyscan_t scanner;
+ int token=EOF;
+ YYSTYPE lval;
+ const unsigned char *uri_string;
+ const char *filename=NULL;
+ char *buf=NULL;
+ size_t len;
+ void *buffer;
+ rasqal_world *world;
+
+ world=rasqal_new_world();
+ if(!world || rasqal_world_open(world))
+ exit(1);
+
+ if(argc > 1) {
+ FILE *fh;
+ query_string=(char*)RASQAL_CALLOC(cstring, FILE_READ_BUF_SIZE, 1);
+ filename=argv[1];
+ fh=fopen(filename, "r");
+ if(fh) {
+ fread(query_string, FILE_READ_BUF_SIZE, 1, fh);
+ fclose(fh);
+ } else {
+ fprintf(stderr, "%s: Cannot open file %s - %s\n", program, filename,
+ strerror(errno));
+ exit(1);
+ }
+ } else {
+ filename="<stdin>";
+ query_string=(char*)RASQAL_CALLOC(cstring, FILE_READ_BUF_SIZE, 1);
+ fread(query_string, FILE_READ_BUF_SIZE, 1, stdin);
+ }
+
+ memset(&rq, 0, sizeof(rasqal_query));
+ rq.world=world;
+ memset(&sparql, 0, sizeof(rasqal_sparql_query_language));
+
+ yylex_init(&sparql.scanner);
+ scanner=sparql.scanner;
+
+ len= strlen((const char*)query_string);
+ buf= (char *)RASQAL_MALLOC(cstring, len+3);
+ strncpy(buf, query_string, len);
+ buf[len]= ' ';
+ buf[len+1]= buf[len+2]='\0'; /* YY_END_OF_BUFFER_CHAR; */
+ buffer= sparql_lexer__scan_buffer(buf, len+3, scanner);
+
+ sparql_lexer_set_extra(&rq, scanner);
+
+ /* Initialise enough of the rasqal_query and locator to get error messages */
+ rq.context=&sparql;
+ sparql.lineno=1;
+ rq.locator.file=filename;
+ rq.locator.column= -1;
+
+ uri_string=raptor_uri_filename_to_uri_string(filename);
+#ifdef RAPTOR_V2_AVAILABLE
+ rq.base_uri = raptor_new_uri_v2(world->raptor_world_ptr, uri_string);
+#else
+ rq.base_uri = raptor_new_uri(uri_string);
+#endif
+ raptor_free_memory((void*)uri_string);
+
+ while(1) {
+ memset(&lval, 0, sizeof(YYSTYPE));
+ if(sparql_lexer_get_text(scanner) != NULL)
+ printf("yyinput '%s'\n", sparql_lexer_get_text(scanner));
+ token=yylex(&lval, scanner);
+#ifdef RASQAL_DEBUG
+ printf("token %s\n", sparql_token_print(world, token, &lval));
+#else
+ printf("token %d\n", token);
+#endif
+ sparql_token_free(world, token, &lval);
+ if(!token || token == EOF)
+ break;
+ }
+
+ if(buf)
+ RASQAL_FREE(cstring, buf);
+
+ yylex_destroy(scanner);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, rq.base_uri);
+#else
+ raptor_free_uri(rq.base_uri);
+#endif
+
+ RASQAL_FREE(cstring, query_string);
+
+ rasqal_free_world(world);
+
+ if(rq.failed)
+ return 1;
+
+ return 0;
+}
+#endif
diff --git a/src/rasqal/sparql_parser.y b/src/rasqal/sparql_parser.y
new file mode 100644
index 0000000..7723dd0
--- /dev/null
+++ b/src/rasqal/sparql_parser.y
@@ -0,0 +1,3068 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * sparql_parser.y - Rasqal SPARQL parser over tokens from sparql_lexer.l
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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.
+ *
+ * References:
+ * SPARQL Query Language for RDF, W3C Recommendation 15 January 2008
+ * http://www.w3.org/TR/2008/REC-rdf-sparql-query-20080115/
+ *
+ */
+
+%{
+#ifdef HAVE_CONFIG_H
+#include <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <rasqal.h>
+#include <rasqal_internal.h>
+
+#include <sparql_parser.h>
+
+#define YY_DECL int sparql_lexer_lex (YYSTYPE *sparql_parser_lval, yyscan_t yyscanner)
+#define YY_NO_UNISTD_H 1
+#include <sparql_lexer.h>
+
+#include <sparql_common.h>
+
+
+#if 0
+#undef RASQAL_DEBUG
+#define RASQAL_DEBUG 2
+#endif
+
+
+#define DEBUG_FH stderr
+
+/* Make verbose error messages for syntax errors */
+#define YYERROR_VERBOSE 1
+
+/* Fail with an debug error message if RASQAL_DEBUG > 1 */
+#if RASQAL_DEBUG > 1
+#define YYERROR_MSG(msg) do { fputs("** YYERROR ", DEBUG_FH); fputs(msg, DEBUG_FH); fputc('\n', DEBUG_FH); YYERROR; } while(0)
+#else
+#define YYERROR_MSG(ignore) YYERROR
+#endif
+
+/* Slow down the grammar operation and watch it work */
+#if RASQAL_DEBUG > 2
+#define YYDEBUG 1
+#endif
+
+/* the lexer does not seem to track this */
+#undef RASQAL_SPARQL_USE_ERROR_COLUMNS
+
+/* Missing sparql_lexer.c/h prototypes */
+int sparql_lexer_get_column(yyscan_t yyscanner);
+/* Not used here */
+/* void sparql_lexer_set_column(int column_no , yyscan_t yyscanner);*/
+
+
+/* What the lexer wants */
+extern int sparql_lexer_lex (YYSTYPE *sparql_parser_lval, yyscan_t scanner);
+#define YYLEX_PARAM ((rasqal_sparql_query_language*)(((rasqal_query*)rq)->context))->scanner
+
+/* Pure parser argument (a void*) */
+#define YYPARSE_PARAM rq
+
+/* Make the yyerror below use the rdf_parser */
+#undef yyerror
+#define yyerror(message) sparql_query_error((rasqal_query*)rq, message)
+
+/* Make lex/yacc interface as small as possible */
+#undef yylex
+#define yylex sparql_lexer_lex
+
+
+static int sparql_parse(rasqal_query* rq);
+static void sparql_query_error(rasqal_query* rq, const char *message);
+static void sparql_query_error_full(rasqal_query *rq, const char *message, ...) RASQAL_PRINTF_FORMAT(2, 3);
+
+%}
+
+
+/* directives */
+
+
+%pure-parser
+
+
+/* Interface between lexer and parser */
+%union {
+ raptor_sequence *seq;
+ rasqal_variable *variable;
+ rasqal_literal *literal;
+ rasqal_triple *triple;
+ rasqal_expression *expr;
+ rasqal_graph_pattern *graph_pattern;
+ double floating;
+ raptor_uri *uri;
+ unsigned char *name;
+ rasqal_formula *formula;
+}
+
+
+/*
+ * shift/reduce conflicts
+ * FIXME: document this
+ */
+%expect 4
+
+/* word symbols */
+%token SELECT FROM WHERE
+%token OPTIONAL DESCRIBE CONSTRUCT ASK DISTINCT REDUCED LIMIT UNION
+%token PREFIX BASE BOUND
+%token GRAPH NAMED FILTER OFFSET ORDER BY REGEX ASC DESC LANGMATCHES
+%token A "a"
+%token STR "str"
+%token LANG "lang"
+%token DATATYPE "datatype"
+%token ISURI "isUri"
+%token ISBLANK "isBlank"
+%token ISLITERAL "isLiteral"
+%token SAMETERM "sameTerm"
+/* LAQRS */
+%token EXPLAIN GROUP COUNT AS
+%token DELETE INSERT
+
+
+/* expression delimiters */
+
+%token ',' '(' ')' '[' ']' '{' '}'
+%token '?' '$'
+
+/* SC booleans */
+%left SC_OR
+%left SC_AND
+
+/* operations */
+%left EQ
+%left NEQ
+%left LT
+%left GT
+%left LE
+%left GE
+
+
+/* arithmetic operations */
+%left '+' '-' '*' '/'
+
+/* unary operations */
+
+/* literals */
+%token <literal> STRING_LITERAL "string literal"
+%token <literal> DOUBLE_LITERAL "double literal"
+%token <literal> DOUBLE_POSITIVE_LITERAL "double positive literal"
+%token <literal> DOUBLE_NEGATIVE_LITERAL "double negative literal"
+%token <literal> INTEGER_LITERAL "integer literal"
+%token <literal> INTEGER_POSITIVE_LITERAL "integer positive literal"
+%token <literal> INTEGER_NEGATIVE_LITERAL "integer negative literal"
+%token <literal> DECIMAL_LITERAL "decimal literal"
+%token <literal> DECIMAL_POSITIVE_LITERAL "decimal positive literal"
+%token <literal> DECIMAL_NEGATIVE_LITERAL "decimal negative literal"
+%token <literal> BOOLEAN_LITERAL "boolean literal"
+
+%token <uri> URI_LITERAL "URI literal"
+%token <uri> URI_LITERAL_BRACE "URI literal ("
+
+%token <name> QNAME_LITERAL "QName literal"
+%token <name> QNAME_LITERAL_BRACE "QName literal ("
+%token <name> BLANK_LITERAL "blank node literal"
+%token <name> IDENTIFIER "identifier"
+
+
+%type <seq> SelectQuery ConstructQuery DescribeQuery
+%type <seq> SelectExpressionList VarOrIRIrefList ArgList ConstructTriplesOpt
+%type <seq> ConstructTemplate OrderConditionList
+%type <seq> GraphNodeListNotEmpty SelectExpressionListTail
+
+%type <formula> TriplesSameSubject
+%type <formula> PropertyList PropertyListTailOpt PropertyListNotEmpty
+%type <formula> ObjectList ObjectTail Collection
+%type <formula> VarOrTerm Verb Object GraphNode TriplesNode
+%type <formula> BlankNodePropertyList
+%type <formula> TriplesBlock TriplesBlockOpt
+
+%type <graph_pattern> GroupGraphPattern
+%type <graph_pattern> GraphGraphPattern OptionalGraphPattern
+%type <graph_pattern> GroupOrUnionGraphPattern GroupOrUnionGraphPatternList
+%type <graph_pattern> GraphPatternNotTriples
+%type <graph_pattern> GraphPatternListOpt GraphPatternList GraphPatternListFilter
+
+%type <expr> Expression ConditionalOrExpression ConditionalAndExpression
+%type <expr> RelationalExpression AdditiveExpression
+%type <expr> MultiplicativeExpression UnaryExpression
+%type <expr> BuiltInCall RegexExpression FunctionCall
+%type <expr> BrackettedExpression PrimaryExpression
+%type <expr> OrderCondition Filter Constraint SelectExpression
+%type <expr> AggregateExpression CountAggregateExpression
+
+%type <literal> GraphTerm IRIref BlankNode
+%type <literal> VarOrIRIref
+%type <literal> IRIrefBrace SourceSelector
+%type <literal> NumericLiteral NumericLiteralUnsigned
+%type <literal> NumericLiteralPositive NumericLiteralNegative
+
+%type <variable> Var VarName SelectTerm
+
+
+%destructor {
+ if($$)
+ rasqal_free_literal($$);
+}
+STRING_LITERAL
+DOUBLE_LITERAL INTEGER_LITERAL DECIMAL_LITERAL
+DOUBLE_POSITIVE_LITERAL DOUBLE_NEGATIVE_LITERAL
+INTEGER_POSITIVE_LITERAL INTEGER_NEGATIVE_LITERAL
+DECIMAL_POSITIVE_LITERAL DECIMAL_NEGATIVE_LITERAL
+BOOLEAN_LITERAL
+
+%destructor {
+ if($$)
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(((rasqal_query*)rq)->world->raptor_world_ptr, $$);
+#else
+ raptor_free_uri($$);
+#endif
+}
+URI_LITERAL URI_LITERAL_BRACE
+
+%destructor {
+ if($$)
+ RASQAL_FREE(cstring, $$);
+}
+QNAME_LITERAL QNAME_LITERAL_BRACE BLANK_LITERAL IDENTIFIER
+
+%destructor {
+ if($$)
+ raptor_free_sequence($$);
+}
+SelectQuery ConstructQuery DescribeQuery
+SelectExpressionList VarOrIRIrefList ArgList ConstructTriplesOpt
+ConstructTemplate OrderConditionList
+GraphNodeListNotEmpty SelectExpressionListTail
+
+%destructor {
+ if($$)
+ rasqal_free_formula($$);
+}
+TriplesSameSubject
+PropertyList PropertyListTailOpt PropertyListNotEmpty
+ObjectList ObjectTail Collection
+VarOrTerm Verb Object GraphNode TriplesNode
+BlankNodePropertyList
+TriplesBlock TriplesBlockOpt
+
+%destructor {
+ if($$)
+ rasqal_free_graph_pattern($$);
+}
+GroupGraphPattern
+GraphGraphPattern OptionalGraphPattern
+GroupOrUnionGraphPattern GroupOrUnionGraphPatternList
+GraphPatternNotTriples
+GraphPatternListOpt GraphPatternList GraphPatternListFilter
+
+%destructor {
+ if($$)
+ rasqal_free_expression($$);
+}
+Expression ConditionalOrExpression ConditionalAndExpression
+RelationalExpression AdditiveExpression
+MultiplicativeExpression UnaryExpression
+BuiltInCall RegexExpression FunctionCall
+BrackettedExpression PrimaryExpression
+OrderCondition Filter Constraint SelectExpression
+AggregateExpression CountAggregateExpression
+
+%destructor {
+ if($$)
+ rasqal_free_literal($$);
+}
+GraphTerm IRIref BlankNode
+VarOrIRIref
+IRIrefBrace SourceSelector
+NumericLiteral NumericLiteralUnsigned
+NumericLiteralPositive NumericLiteralNegative
+
+%destructor {
+ if($$)
+ rasqal_free_variable($$);
+}
+Var VarName SelectTerm
+
+
+%%
+
+/* Below here, grammar terms are numbered from
+ * http://www.w3.org/TR/2005/WD-rdf-sparql-query-20051123/
+ * except where noted
+ */
+
+/* SPARQL Grammar: [1] Query */
+Query: Prologue ExplainOpt ReportFormat
+{
+}
+;
+
+/* LAQRS */
+ExplainOpt: EXPLAIN
+{
+ rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)(((rasqal_query*)rq)->context);
+
+ if(sparql->extended)
+ ((rasqal_query*)rq)->explain=1;
+ else
+ sparql_syntax_error((rasqal_query*)rq, "EXPLAIN cannot be used with SPARQL");
+}
+|
+{
+ /* nothing to do */
+}
+;
+
+
+/* NEW Grammar Term pulled out of [1] Query */
+ReportFormat: SelectQuery
+{
+ ((rasqal_query*)rq)->selects=$1;
+ ((rasqal_query*)rq)->verb=RASQAL_QUERY_VERB_SELECT;
+}
+| ConstructQuery
+{
+ ((rasqal_query*)rq)->constructs=$1;
+ ((rasqal_query*)rq)->verb=RASQAL_QUERY_VERB_CONSTRUCT;
+}
+| DescribeQuery
+{
+ ((rasqal_query*)rq)->describes=$1;
+ ((rasqal_query*)rq)->verb=RASQAL_QUERY_VERB_DESCRIBE;
+}
+| AskQuery
+{
+ ((rasqal_query*)rq)->verb=RASQAL_QUERY_VERB_ASK;
+}
+| DeleteQuery
+{
+ ((rasqal_query*)rq)->verb=RASQAL_QUERY_VERB_DELETE;
+}
+| InsertQuery
+{
+ ((rasqal_query*)rq)->verb=RASQAL_QUERY_VERB_INSERT;
+}
+;
+
+
+/* SPARQL Grammar: [2] Prologue */
+Prologue: BaseDeclOpt PrefixDeclListOpt
+{
+ /* nothing to do */
+}
+;
+
+
+/* SPARQL Grammar: [3] BaseDecl */
+BaseDeclOpt: BASE URI_LITERAL
+{
+ rasqal_query_set_base_uri((rasqal_query*)rq, $2);
+}
+| /* empty */
+{
+ /* nothing to do */
+}
+;
+
+
+/* SPARQL Grammar: [4] PrefixDecl renamed to include optional list */
+PrefixDeclListOpt: PrefixDeclListOpt PREFIX IDENTIFIER URI_LITERAL
+{
+ raptor_sequence *seq=((rasqal_query*)rq)->prefixes;
+ unsigned const char* prefix_string=$3;
+ size_t l=0;
+
+ if(prefix_string)
+ l=strlen((const char*)prefix_string);
+
+ if(raptor_namespaces_find_namespace(((rasqal_query*)rq)->namespaces, prefix_string, l)) {
+ /* A prefix may be defined only once */
+ sparql_syntax_warning(((rasqal_query*)rq),
+ "PREFIX %s can be defined only once.",
+ prefix_string ? (const char*)prefix_string : ":");
+ RASQAL_FREE(cstring, prefix_string);
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(((rasqal_query*)rq)->world->raptor_world_ptr, $4);
+#else
+ raptor_free_uri($4);
+#endif
+ } else {
+ rasqal_prefix *p=rasqal_new_prefix(((rasqal_query*)rq)->world, prefix_string, $4);
+ if(!p)
+ YYERROR_MSG("PrefixDeclOpt: failed to create new prefix");
+ if(raptor_sequence_push(seq, p))
+ YYERROR_MSG("PrefixDeclOpt: cannot push prefix to seq");
+ if(rasqal_query_declare_prefix(((rasqal_query*)rq), p)) {
+ YYERROR_MSG("PrefixDeclOpt: cannot declare prefix");
+ }
+ }
+}
+| /* empty */
+{
+ /* nothing to do, rq->prefixes already initialised */
+}
+;
+
+
+/* SPARQL Grammar: [5] SelectQuery */
+SelectQuery: SELECT DISTINCT SelectExpressionList
+ DatasetClauseListOpt WhereClauseOpt SolutionModifier
+{
+ $$=$3;
+ ((rasqal_query*)rq)->distinct=1;
+}
+| SELECT REDUCED SelectExpressionList
+ DatasetClauseListOpt WhereClauseOpt SolutionModifier
+{
+ $$=$3;
+ ((rasqal_query*)rq)->distinct=2;
+}
+| SELECT SelectExpressionList
+ DatasetClauseListOpt WhereClauseOpt SolutionModifier
+{
+ $$=$2;
+}
+;
+
+
+/* NEW Grammar Term pulled out of [5] SelectQuery
+ * A list of SelectTerm OR a NULL list and a wildcard
+ */
+SelectExpressionList: SelectExpressionListTail
+{
+ $$=$1;
+}
+| '*'
+{
+ $$=NULL;
+ ((rasqal_query*)rq)->wildcard=1;
+}
+;
+
+
+/* NEW Grammar Term pulled out of [5] SelectQuery
+ * Non-empty list of SelectTerm with optional commas
+ */
+SelectExpressionListTail: SelectExpressionListTail SelectTerm
+{
+ $$=$1;
+ if(raptor_sequence_push($$, $2)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("SelectExpressionListTail 1: sequence push failed");
+ }
+}
+| SelectExpressionListTail ',' SelectTerm
+{
+ $$=$1;
+ if(raptor_sequence_push($$, $3)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("SelectExpressionListTail 2: sequence push failed");
+ }
+}
+| SelectTerm
+{
+ /* The variables are freed from the raptor_query field variables */
+ $$=raptor_new_sequence(NULL, (raptor_sequence_print_handler*)rasqal_variable_print);
+ if(!$$)
+ YYERROR_MSG("SelectExpressionListTail 3: failed to create sequence");
+ if(raptor_sequence_push($$, $1)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("SelectExpressionListTail 3: sequence push failed");
+ }
+}
+;
+
+
+/* NEW Grammar Term pulled out of [5] SelectQuery
+ * A variable (?x) or a select expression assigned to a name (x) with AS
+ */
+SelectTerm: Var
+{
+ $$=$1;
+}
+| SelectExpression AS VarName
+{
+ rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)(((rasqal_query*)rq)->context);
+
+ $$=NULL;
+ if(!sparql->extended)
+ sparql_syntax_error((rasqal_query*)rq, "SELECT expression AS Variable cannot be used with SPARQL");
+ else {
+ if(rasqal_expression_mentions_variable($1, $3)) {
+ sparql_query_error_full((rasqal_query*)rq, "SELECT expression contains the AS variable name '%s'", $3->name);
+ } else {
+ $$=$3;
+ $3->expression=$1;
+ }
+
+ }
+}
+;
+
+
+/* NEW Grammar Term pulled out of [5] SelectQuery */
+SelectExpression: AggregateExpression
+{
+ $$=$1;
+}
+| '(' AggregateExpression ')'
+{
+ $$=$2;
+}
+| '(' Expression ')'
+{
+ $$=$2;
+}
+;
+
+
+AggregateExpression: CountAggregateExpression
+{
+ $$=$1;
+}
+;
+
+
+CountAggregateExpression: COUNT '(' Expression ')'
+{
+ rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)(((rasqal_query*)rq)->context);
+
+ if(!sparql->extended) {
+ sparql_syntax_error((rasqal_query*)rq, "COUNT cannot be used with SPARQL");
+ $$=NULL;
+ } else {
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_COUNT, $3);
+ if(!$$)
+ YYERROR_MSG("CountAggregateExpression 1: cannot create expr");
+ }
+}
+| COUNT '(' '*' ')'
+{
+ rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)(((rasqal_query*)rq)->context);
+
+ if(!sparql->extended) {
+ sparql_syntax_error((rasqal_query*)rq, "COUNT cannot be used with SPARQL");
+ $$=NULL;
+ } else {
+ rasqal_expression* vs=rasqal_new_0op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_VARSTAR);
+ if(!vs)
+ YYERROR_MSG("CountAggregateExpression 2: cannot create varstar expr");
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_COUNT, vs);
+ if(!$$)
+ YYERROR_MSG("CountAggregateExpression 2: cannot create expr");
+ }
+}
+;
+
+
+/* SPARQL Grammar: [6] ConstructQuery */
+ConstructQuery: CONSTRUCT ConstructTemplate
+ DatasetClauseListOpt WhereClauseOpt SolutionModifier
+{
+ $$=$2;
+}
+;
+
+
+/* SPARQL Grammar: [7] DescribeQuery */
+DescribeQuery: DESCRIBE VarOrIRIrefList
+ DatasetClauseListOpt WhereClauseOpt SolutionModifier
+{
+ $$=$2;
+}
+| DESCRIBE '*'
+ DatasetClauseListOpt WhereClauseOpt SolutionModifier
+{
+ $$=NULL;
+}
+;
+
+
+/* NEW Grammar Term pulled out of [7] DescribeQuery */
+VarOrIRIrefList: VarOrIRIrefList VarOrIRIref
+{
+ $$=$1;
+ if(raptor_sequence_push($$, $2)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("VarOrIRIrefList 1: sequence push failed");
+ }
+}
+| VarOrIRIrefList ',' VarOrIRIref
+{
+ $$=$1;
+ if(raptor_sequence_push($$, $3)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("VarOrIRIrefList 2: sequence push failed");
+ }
+}
+| VarOrIRIref
+{
+ $$=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_literal, (raptor_sequence_print_handler*)rasqal_literal_print);
+ if(!$$)
+ YYERROR_MSG("VarOrIRIrefList 3: cannot create seq");
+ if(raptor_sequence_push($$, $1)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("VarOrIRIrefList 3: sequence push failed");
+ }
+}
+;
+
+
+/* SPARQL Grammar: [8] AskQuery */
+AskQuery: ASK
+ DatasetClauseListOpt WhereClauseOpt
+{
+ /* nothing to do */
+}
+;
+
+
+/* LAQRS */
+DeleteQuery: DELETE
+ DatasetClauseListOpt WhereClauseOpt
+{
+ rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)(((rasqal_query*)rq)->context);
+
+ if(!sparql->extended)
+ sparql_syntax_error((rasqal_query*)rq, "DELETE cannot be used with SPARQL");
+}
+;
+
+
+/* LAQRS */
+InsertQuery: INSERT
+ DatasetClauseListOpt WhereClauseOpt
+{
+ rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)(((rasqal_query*)rq)->context);
+
+ if(!sparql->extended)
+ sparql_syntax_error((rasqal_query*)rq, "INSERT cannot be used with SPARQL");
+}
+;
+
+
+/* SPARQL Grammar: [9] DatasetClause */
+DatasetClauseListOpt: DatasetClauseListOpt FROM DefaultGraphClause
+| DatasetClauseListOpt FROM NamedGraphClause
+| /* empty */
+;
+
+
+/* SPARQL Grammar: [10] DefaultGraphClause */
+DefaultGraphClause: SourceSelector
+{
+ if($1) {
+ raptor_uri* uri=rasqal_literal_as_uri($1);
+ if(rasqal_query_add_data_graph((rasqal_query*)rq, uri, NULL,
+ RASQAL_DATA_GRAPH_BACKGROUND)) {
+ rasqal_free_literal($1);
+ YYERROR_MSG("DefaultGraphClause: rasqal_query_add_data_graph failed");
+ }
+ rasqal_free_literal($1);
+ }
+}
+;
+
+
+/* SPARQL Grammar: [11] NamedGraphClause */
+NamedGraphClause: NAMED SourceSelector
+{
+ if($2) {
+ raptor_uri* uri=rasqal_literal_as_uri($2);
+ if(rasqal_query_add_data_graph((rasqal_query*)rq, uri, uri,
+ RASQAL_DATA_GRAPH_NAMED)) {
+ rasqal_free_literal($2);
+ YYERROR_MSG("NamedGraphClause: rasqal_query_add_data_graph failed");
+ }
+ rasqal_free_literal($2);
+ }
+}
+;
+
+
+/* SPARQL Grammar: [12] SourceSelector */
+SourceSelector: IRIref
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [13] WhereClause - remained for clarity */
+WhereClauseOpt: WHERE GroupGraphPattern
+{
+ ((rasqal_query*)rq)->query_graph_pattern=$2;
+}
+| GroupGraphPattern
+{
+ ((rasqal_query*)rq)->query_graph_pattern=$1;
+}
+| /* empty */
+;
+
+
+/* SPARQL Grammar: [14] SolutionModifier */
+SolutionModifier: GroupClauseOpt OrderClauseOpt LimitOffsetClausesOpt
+;
+
+
+/* LAQRS */
+GroupClauseOpt: GROUP BY OrderConditionList
+{
+ rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)(((rasqal_query*)rq)->context);
+
+ if(!sparql->extended)
+ sparql_syntax_error((rasqal_query*)rq, "GROUP BY cannot be used with SPARQL");
+ else if(((rasqal_query*)rq)->verb == RASQAL_QUERY_VERB_ASK) {
+ sparql_query_error((rasqal_query*)rq, "GROUP BY cannot be used with ASK");
+ } else {
+ raptor_sequence *seq=$3;
+ ((rasqal_query*)rq)->group_conditions_sequence=seq;
+ if(seq) {
+ int i;
+
+ for(i=0; i < raptor_sequence_size(seq); i++) {
+ rasqal_expression* e=(rasqal_expression*)raptor_sequence_get_at(seq, i);
+ if(e->op == RASQAL_EXPR_ORDER_COND_ASC)
+ e->op = RASQAL_EXPR_GROUP_COND_ASC;
+ else
+ e->op = RASQAL_EXPR_GROUP_COND_DESC;
+ }
+ }
+ }
+}
+| /* empty */
+;
+
+
+/* SPARQL Grammar: [15] LimitOffsetClauses */
+LimitOffsetClausesOpt: LimitClause OffsetClause
+| OffsetClause LimitClause
+| LimitClause
+| OffsetClause
+| /* empty */
+{
+}
+;
+
+
+/* SPARQL Grammar: [16] OrderClause - remained for clarity */
+OrderClauseOpt: ORDER BY OrderConditionList
+{
+ if(((rasqal_query*)rq)->verb == RASQAL_QUERY_VERB_ASK) {
+ sparql_query_error((rasqal_query*)rq, "ORDER BY cannot be used with ASK");
+ } else {
+ ((rasqal_query*)rq)->order_conditions_sequence=$3;
+ }
+}
+| /* empty */
+;
+
+
+/* NEW Grammar Term pulled out of [16] OrderClauseOpt */
+OrderConditionList: OrderConditionList OrderCondition
+{
+ $$=$1;
+ if($2)
+ if(raptor_sequence_push($$, $2)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("OrderConditionList 1: sequence push failed");
+ }
+}
+| OrderCondition
+{
+ $$=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_expression, (raptor_sequence_print_handler*)rasqal_expression_print);
+ if(!$$) {
+ if($1)
+ rasqal_free_expression($1);
+ YYERROR_MSG("OrderConditionList 2: cannot create sequence");
+ }
+ if($1)
+ if(raptor_sequence_push($$, $1)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("OrderConditionList 2: sequence push failed");
+ }
+}
+;
+
+
+/* SPARQL Grammar: [17] OrderCondition */
+OrderCondition: ASC BrackettedExpression
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ORDER_COND_ASC, $2);
+ if(!$$)
+ YYERROR_MSG("OrderCondition 1: cannot create expr");
+}
+| DESC BrackettedExpression
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ORDER_COND_DESC, $2);
+ if(!$$)
+ YYERROR_MSG("OrderCondition 2: cannot create expr");
+}
+| FunctionCall
+{
+ /* The direction of ordering is ascending by default */
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ORDER_COND_ASC, $1);
+ if(!$$)
+ YYERROR_MSG("OrderCondition 3: cannot create expr");
+}
+| Var
+{
+ rasqal_literal* l;
+ rasqal_expression *e;
+ l=rasqal_new_variable_literal(((rasqal_query*)rq)->world, $1);
+ if(!l)
+ YYERROR_MSG("OrderCondition 4: cannot create lit");
+ e=rasqal_new_literal_expression(((rasqal_query*)rq)->world, l);
+ if(!e)
+ YYERROR_MSG("OrderCondition 4: cannot create lit expr");
+
+ /* The direction of ordering is ascending by default */
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ORDER_COND_ASC, e);
+ if(!$$)
+ YYERROR_MSG("OrderCondition 1: cannot create expr");
+}
+| BrackettedExpression
+{
+ /* The direction of ordering is ascending by default */
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ORDER_COND_ASC, $1);
+ if(!$$)
+ YYERROR_MSG("OrderCondition 5: cannot create expr");
+}
+| BuiltInCall
+{
+ /* The direction of ordering is ascending by default */
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ORDER_COND_ASC, $1);
+ if(!$$)
+ YYERROR_MSG("OrderCondition 6: cannot create expr");
+}
+;
+
+
+/* SPARQL Grammar: [18] LimitClause - remained for clarity */
+LimitClause: LIMIT INTEGER_LITERAL
+{
+ if(((rasqal_query*)rq)->verb == RASQAL_QUERY_VERB_ASK) {
+ sparql_query_error((rasqal_query*)rq, "LIMIT cannot be used with ASK");
+ } else {
+ if($2 != NULL) {
+ ((rasqal_query*)rq)->limit=$2->value.integer;
+ rasqal_free_literal($2);
+ }
+ }
+
+}
+;
+
+
+/* SPARQL Grammar: [19] OffsetClause - remained for clarity */
+OffsetClause: OFFSET INTEGER_LITERAL
+{
+ if(((rasqal_query*)rq)->verb == RASQAL_QUERY_VERB_ASK) {
+ sparql_query_error((rasqal_query*)rq, "LIMIT cannot be used with ASK");
+ } else {
+ if($2 != NULL) {
+ ((rasqal_query*)rq)->offset=$2->value.integer;
+ rasqal_free_literal($2);
+ }
+ }
+}
+;
+
+
+/* SPARQL Grammar: [20] GroupGraphPattern
+ * TriplesBlockOpt: formula or NULL (on success or error)
+ * GraphPatternListOpt: always 1 Group GP or NULL (on error)
+ */
+GroupGraphPattern: '{' TriplesBlockOpt GraphPatternListOpt '}'
+{
+ rasqal_graph_pattern *formula_gp=NULL;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "GroupGraphPattern\n TriplesBlockOpt=");
+ if($2)
+ rasqal_formula_print($2, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, ", GraphpatternListOpt=");
+ if($3)
+ rasqal_graph_pattern_print($3, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+
+ if(!$2 && !$3) {
+ $$=rasqal_new_2_group_graph_pattern((rasqal_query*)rq, NULL, NULL);
+ if(!$$)
+ YYERROR_MSG("GroupGraphPattern: cannot create group gp");
+ } else {
+ if($2) {
+ formula_gp=rasqal_new_basic_graph_pattern_from_formula((rasqal_query*)rq, $2);
+ if(!formula_gp) {
+ if($3)
+ rasqal_free_graph_pattern($3);
+ YYERROR_MSG("GroupGraphPattern: cannot create formula_gp");
+ }
+ }
+
+ if($3) {
+ $$=$3;
+ if(formula_gp && raptor_sequence_shift($$->graph_patterns, formula_gp)) {
+ rasqal_free_graph_pattern($$);
+ $$=NULL;
+ YYERROR_MSG("GroupGraphPattern: sequence push failed");
+ }
+ } else
+ $$=formula_gp;
+ }
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after graph pattern=");
+ if($$)
+ rasqal_graph_pattern_print($$, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+;
+
+
+/* Pulled out of SPARQL Grammar: [20] GroupGraphPattern */
+TriplesBlockOpt: TriplesBlock
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "TriplesBlockOpt 1\n TriplesBlock=");
+ if($1)
+ rasqal_formula_print($1, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n\n", DEBUG_FH);
+#endif
+
+ $$=$1;
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+
+/* Pulled out of SPARQL Grammar: [20] GroupGraphPattern
+ * GraphPatternListOpt: always 1 Group GP or NULL
+ * GraphPatternList: always 1 Group GP or NULL (on error)
+ *
+ * Result: always 1 Group GP or NULL (on error)
+ */
+GraphPatternListOpt: GraphPatternListOpt GraphPatternList
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "GraphPatternListOpt\n GraphPatternListOpt=");
+ if($1)
+ rasqal_graph_pattern_print($1, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, ", GraphPatternList=");
+ if($2)
+ rasqal_graph_pattern_print($2, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ $$= ($1 ? $1 : $2);
+ if($1 && $2) {
+ $$=$1;
+ if(rasqal_graph_patterns_join($$, $2)) {
+ rasqal_free_graph_pattern($$);
+ rasqal_free_graph_pattern($2);
+ $$=NULL;
+ YYERROR_MSG("ConstructTriplesOpt: sequence join failed");
+ }
+ rasqal_free_graph_pattern($2);
+ }
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after grouping graph pattern=");
+ if($$)
+ rasqal_graph_pattern_print($$, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+| GraphPatternList
+{
+ $$=$1;
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+
+/* Pulled out of SPARQL Grammar: [20] GroupGraphPattern
+ * GraphPatternListFilter: always 1 GP or NULL (on error)
+ * TriplesBlockOpt: formula or NULL (on success or error)
+ *
+ * Result: always 1 Group GP or NULL (on success or error)
+ */
+GraphPatternList: GraphPatternListFilter DotOptional TriplesBlockOpt
+{
+ rasqal_graph_pattern *formula_gp=NULL;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "GraphPatternList\n GraphPatternListFilter=");
+ if($1)
+ rasqal_graph_pattern_print($1, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, ", TriplesBlockOpt=");
+ if($3)
+ rasqal_formula_print($3, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ if($3) {
+ formula_gp=rasqal_new_basic_graph_pattern_from_formula((rasqal_query*)rq, $3);
+ if(!formula_gp) {
+ if($1)
+ rasqal_free_graph_pattern($1);
+ YYERROR_MSG("GraphPatternList: cannot create formula_gp");
+ }
+ }
+ $$=rasqal_new_2_group_graph_pattern((rasqal_query*)rq, $1, formula_gp);
+ if(!$$)
+ YYERROR_MSG("GraphPatternList: cannot create sequence");
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after graph pattern=");
+ if($$)
+ rasqal_graph_pattern_print($$, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+;
+
+
+/* Pulled out of SPARQL Grammar: [20] GroupGraphPattern
+ * GraphPatternNotTriples: always 1 GP or NULL (on error)
+ *
+ * Result: always 1 GP or NULL (on error)
+ */
+GraphPatternListFilter: GraphPatternNotTriples
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "GraphPatternListFilter 1\n GraphPatternNotTriples=");
+ if($1)
+ rasqal_graph_pattern_print($1, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n\n", DEBUG_FH);
+#endif
+
+ $$=$1;
+}
+| Filter
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "GraphPatternListFilter 2\n Filter=");
+ if($1)
+ rasqal_expression_print($1, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+ $$=rasqal_new_filter_graph_pattern((rasqal_query*)rq, $1);
+ if(!$$)
+ YYERROR_MSG("GraphPatternListFilter 2: cannot create graph pattern");
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after graph pattern=");
+ if($$)
+ rasqal_graph_pattern_print($$, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+;
+
+
+/* NEW Grammar Term */
+DotOptional: '.'
+| /* empty */
+;
+
+
+/* SPARQL Grammar: [21] TriplesBlock */
+TriplesBlock: TriplesSameSubject '.' TriplesBlockOpt
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "TriplesBlock\n TriplesSameSubject=");
+ if($1)
+ rasqal_formula_print($1, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, ", TriplesBlockOpt=");
+ if($3)
+ rasqal_formula_print($3, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n", DEBUG_FH);
+#endif
+
+
+ $$= ($1 ? $1 : $3);
+ if($1 && $3) {
+ /* $1 and $3 are freed as necessary */
+ $$=rasqal_formula_join($1, $3);
+ if(!$1)
+ YYERROR_MSG("TriplesBlock: formula join failed");
+ }
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after joining formula=");
+ rasqal_formula_print($$, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+| TriplesSameSubject
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [22] GraphPatternNotTriples */
+GraphPatternNotTriples: OptionalGraphPattern
+{
+ $$=$1;
+}
+| GroupOrUnionGraphPattern
+{
+ $$=$1;
+}
+| GraphGraphPattern
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [23] OptionalGraphPattern */
+OptionalGraphPattern: OPTIONAL GroupGraphPattern
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "PatternElementForms 4\n graphpattern=");
+ if($2)
+ rasqal_graph_pattern_print($2, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n\n", DEBUG_FH);
+#endif
+
+ $$=NULL;
+
+ if($2) {
+ raptor_sequence *seq;
+
+ seq=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_graph_pattern, (raptor_sequence_print_handler*)rasqal_graph_pattern_print);
+ if(!seq) {
+ rasqal_free_graph_pattern($2);
+ YYERROR_MSG("OptionalGraphPattern 1: cannot create sequence");
+ } else {
+ if(raptor_sequence_push(seq, $2)) {
+ raptor_free_sequence(seq);
+ YYERROR_MSG("OptionalGraphPattern 2: sequence push failed");
+ } else {
+ $$=rasqal_new_graph_pattern_from_sequence((rasqal_query*)rq,
+ seq,
+ RASQAL_GRAPH_PATTERN_OPERATOR_OPTIONAL);
+ if(!$$)
+ YYERROR_MSG("OptionalGraphPattern: cannot create graph pattern");
+ }
+ }
+ }
+}
+;
+
+
+/* SPARQL Grammar: [24] GraphGraphPattern */
+GraphGraphPattern: GRAPH VarOrIRIref GroupGraphPattern
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "GraphGraphPattern 2\n varoruri=");
+ rasqal_literal_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, ", graphpattern=");
+ if($3)
+ rasqal_graph_pattern_print($3, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fputs("\n\n", DEBUG_FH);
+#endif
+
+ if($3) {
+ rasqal_graph_pattern_set_origin($3, $2);
+ $3->op = RASQAL_GRAPH_PATTERN_OPERATOR_GRAPH;
+ }
+
+ rasqal_free_literal($2);
+ $$=$3;
+}
+;
+
+
+/* SPARQL Grammar: [25] GroupOrUnionGraphPattern */
+GroupOrUnionGraphPattern: GroupGraphPattern UNION GroupOrUnionGraphPatternList
+{
+ $$=$3;
+ if(raptor_sequence_shift($$->graph_patterns, $1)) {
+ rasqal_free_graph_pattern($$);
+ $$=NULL;
+ YYERROR_MSG("GroupOrUnionGraphPattern: sequence push failed");
+ }
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "UnionGraphPattern\n graphpattern=");
+ rasqal_graph_pattern_print($$, DEBUG_FH);
+ fputs("\n\n", DEBUG_FH);
+#endif
+}
+| GroupGraphPattern
+{
+ $$=$1;
+}
+;
+
+/* NEW Grammar Term pulled out of [25] GroupOrUnionGraphPattern */
+GroupOrUnionGraphPatternList: GroupOrUnionGraphPatternList UNION GroupGraphPattern
+{
+ $$=$1;
+ if($3)
+ if(raptor_sequence_push($$->graph_patterns, $3)) {
+ rasqal_free_graph_pattern($$);
+ $$=NULL;
+ YYERROR_MSG("GroupOrUnionGraphPatternList 1: sequence push failed");
+ }
+}
+| GroupGraphPattern
+{
+ raptor_sequence *seq;
+ seq=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_graph_pattern, (raptor_sequence_print_handler*)rasqal_graph_pattern_print);
+ if(!seq) {
+ if($1)
+ rasqal_free_graph_pattern($1);
+ YYERROR_MSG("GroupOrUnionGraphPatternList 2: cannot create sequence");
+ }
+ if($1)
+ if(raptor_sequence_push(seq, $1)) {
+ raptor_free_sequence(seq);
+ YYERROR_MSG("GroupOrUnionGraphPatternList 2: sequence push failed");
+ }
+ $$=rasqal_new_graph_pattern_from_sequence((rasqal_query*)rq,
+ seq,
+ RASQAL_GRAPH_PATTERN_OPERATOR_UNION);
+ if(!$$)
+ YYERROR_MSG("GroupOrUnionGraphPatternList 1: cannot create gp");
+}
+;
+
+
+/* SPARQL Grammar: [26] Filter */
+Filter: FILTER Constraint
+{
+ $$=$2;
+}
+;
+
+
+/* SPARQL Grammar: [27] Constraint */
+Constraint: BrackettedExpression
+{
+ $$=$1;
+}
+| BuiltInCall
+{
+ $$=$1;
+}
+| FunctionCall
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [28] FunctionCall */
+FunctionCall: IRIrefBrace ArgList ')'
+{
+ raptor_uri* uri=rasqal_literal_as_uri($1);
+
+ if(!$2) {
+ $2=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_expression, (raptor_sequence_print_handler*)rasqal_expression_print);
+ if(!$2) {
+ rasqal_free_literal($1);
+ YYERROR_MSG("FunctionCall: cannot create sequence");
+ }
+ }
+
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_uri_copy_v2(((rasqal_query*)rq)->world->raptor_world_ptr, uri);
+#else
+ uri = raptor_uri_copy(uri);
+#endif
+
+ if(raptor_sequence_size($2) == 1 &&
+ rasqal_xsd_is_datatype_uri(((rasqal_query*)rq)->world, uri)) {
+ rasqal_expression* e=(rasqal_expression*)raptor_sequence_pop($2);
+ $$=rasqal_new_cast_expression(((rasqal_query*)rq)->world, uri, e);
+ raptor_free_sequence($2);
+ } else {
+ $$=rasqal_new_function_expression(((rasqal_query*)rq)->world, uri, $2);
+ }
+ rasqal_free_literal($1);
+
+ if(!$$)
+ YYERROR_MSG("FunctionCall: cannot create expr");
+}
+;
+
+
+/* SPARQL Grammar: [29] ArgList */
+ArgList: ArgList ',' Expression
+{
+ $$=$1;
+ if($3)
+ if(raptor_sequence_push($$, $3)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("ArgList 1: sequence push failed");
+ }
+}
+| Expression
+{
+ $$=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_expression, (raptor_sequence_print_handler*)rasqal_expression_print);
+ if(!$$) {
+ if($1)
+ rasqal_free_expression($1);
+ YYERROR_MSG("ArgList 2: cannot create sequence");
+ }
+ if($1)
+ if(raptor_sequence_push($$, $1)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("ArgList 2: sequence push failed");
+ }
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+
+/* SPARQL Grammar: [30] ConstructTemplate */
+ConstructTemplate: '{' ConstructTriplesOpt '}'
+{
+ $$=$2;
+}
+;
+
+
+/* SPARQL Grammar: [31] ConstructTriples renamed for clarity */
+ConstructTriplesOpt: TriplesSameSubject '.' ConstructTriplesOpt
+{
+ $$=NULL;
+
+ if($1) {
+ $$=$1->triples;
+ $1->triples=NULL;
+ rasqal_free_formula($1);
+ }
+
+ if($3) {
+ if(!$$) {
+ $$=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_triple, (raptor_sequence_print_handler*)rasqal_triple_print);
+ if(!$$) {
+ raptor_free_sequence($3);
+ YYERROR_MSG("ConstructTriplesOpt: cannot create sequence");
+ }
+ }
+
+ if(raptor_sequence_join($$, $3)) {
+ raptor_free_sequence($3);
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("ConstructTriplesOpt: sequence join failed");
+ }
+ raptor_free_sequence($3);
+ }
+
+ }
+| TriplesSameSubject
+{
+ $$=NULL;
+
+ if($1) {
+ $$=$1->triples;
+ $1->triples=NULL;
+ rasqal_free_formula($1);
+ }
+
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+
+/* SPARQL Grammar: [32] TriplesSameSubject */
+TriplesSameSubject: VarOrTerm PropertyListNotEmpty
+{
+ int i;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "TriplesSameSubject 1\n subject=");
+ rasqal_formula_print($1, DEBUG_FH);
+ if($2) {
+ fprintf(DEBUG_FH, "\n propertyList=");
+ rasqal_formula_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+ } else
+ fprintf(DEBUG_FH, "\n and empty propertyList\n");
+#endif
+
+ if($2) {
+ raptor_sequence *seq=$2->triples;
+ rasqal_literal *subject=$1->value;
+
+ /* non-empty property list, handle it */
+ for(i=0; i < raptor_sequence_size(seq); i++) {
+ rasqal_triple* t2=(rasqal_triple*)raptor_sequence_get_at(seq, i);
+ if(t2->subject)
+ continue;
+ t2->subject=rasqal_new_literal_from_literal(subject);
+ }
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after substitution propertyList=");
+ rasqal_formula_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+#endif
+ }
+
+ $$=rasqal_formula_join($1, $2);
+ if(!$$)
+ YYERROR_MSG("TriplesSameSubject 1: formula join failed");
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after joining formula=");
+ rasqal_formula_print($$, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+| TriplesNode PropertyList
+{
+ int i;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "TriplesSameSubject 2\n subject=");
+ rasqal_formula_print($1, DEBUG_FH);
+ if($2) {
+ fprintf(DEBUG_FH, "\n propertyList=");
+ rasqal_formula_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+ } else
+ fprintf(DEBUG_FH, "\n and empty propertyList\n");
+#endif
+
+ if($2) {
+ raptor_sequence *seq=$2->triples;
+ rasqal_literal *subject=$1->value;
+
+ /* non-empty property list, handle it */
+ for(i=0; i < raptor_sequence_size(seq); i++) {
+ rasqal_triple* t2=(rasqal_triple*)raptor_sequence_get_at(seq, i);
+ if(t2->subject)
+ continue;
+ t2->subject=rasqal_new_literal_from_literal(subject);
+ }
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after substitution propertyList=");
+ rasqal_formula_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+#endif
+ }
+
+ $$=rasqal_formula_join($1, $2);
+ if(!$$)
+ YYERROR_MSG("TriplesSameSubject 2: formula join failed");
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after joining formula=");
+ rasqal_formula_print($$, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+;
+
+
+/* SPARQL Grammar: [33] PropertyListNotEmpty */
+PropertyListNotEmpty: Verb ObjectList PropertyListTailOpt
+{
+ int i;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "PropertyList 1\n Verb=");
+ rasqal_formula_print($1, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n ObjectList=");
+ rasqal_formula_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n PropertyListTail=");
+ if($3 != NULL)
+ rasqal_formula_print($3, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+#endif
+
+ if($2 == NULL) {
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " empty ObjectList not processed\n");
+#endif
+ } else if($1 && $2) {
+ raptor_sequence *seq=$2->triples;
+ rasqal_literal *predicate=$1->value;
+ rasqal_formula *formula;
+ rasqal_triple *t2;
+
+ formula=rasqal_new_formula();
+ if(!formula) {
+ rasqal_free_formula($1);
+ rasqal_free_formula($2);
+ if($3)
+ rasqal_free_formula($3);
+ YYERROR_MSG("PropertyList 1: cannot create formula");
+ }
+ formula->triples=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_triple, (raptor_sequence_print_handler*)rasqal_triple_print);
+ if(!formula->triples) {
+ rasqal_free_formula(formula);
+ rasqal_free_formula($1);
+ rasqal_free_formula($2);
+ if($3)
+ rasqal_free_formula($3);
+ YYERROR_MSG("PropertyList 1: cannot create sequence");
+ }
+
+ /* non-empty property list, handle it */
+ for(i=0; i<raptor_sequence_size(seq); i++) {
+ t2=(rasqal_triple*)raptor_sequence_get_at(seq, i);
+ if(!t2->predicate)
+ t2->predicate=(rasqal_literal*)rasqal_new_literal_from_literal(predicate);
+ }
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after substitution ObjectList=");
+ raptor_sequence_print(seq, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+#endif
+
+ while(raptor_sequence_size(seq)) {
+ t2=(rasqal_triple*)raptor_sequence_unshift(seq);
+ if(raptor_sequence_push(formula->triples, t2)) {
+ rasqal_free_formula(formula);
+ rasqal_free_formula($1);
+ rasqal_free_formula($2);
+ if($3)
+ rasqal_free_formula($3);
+ YYERROR_MSG("PropertyList 1: sequence push failed");
+ }
+ }
+
+ $3=rasqal_formula_join(formula, $3);
+ if(!$3) {
+ rasqal_free_formula($1);
+ rasqal_free_formula($2);
+ YYERROR_MSG("PropertyList 1: formula join failed");
+ }
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after appending ObjectList=");
+ rasqal_formula_print($3, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+
+ rasqal_free_formula($2);
+ }
+
+ if($1)
+ rasqal_free_formula($1);
+
+ $$=$3;
+}
+;
+
+
+/* NEW Grammar Term pulled out of [33] PropertyListNotEmpty */
+PropertyListTailOpt: ';' PropertyList
+{
+ $$=$2;
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+
+/* SPARQL Grammar: [34] PropertyList */
+PropertyList: PropertyListNotEmpty
+{
+ $$=$1;
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+
+/* SPARQL Grammar: [35] ObjectList */
+ObjectList: Object ObjectTail
+{
+ rasqal_formula *formula;
+ rasqal_triple *triple;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "ObjectList 1\n");
+ fprintf(DEBUG_FH, " Object=\n");
+ rasqal_formula_print($1, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+ if($2) {
+ fprintf(DEBUG_FH, " ObjectTail=");
+ rasqal_formula_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+ } else
+ fprintf(DEBUG_FH, " and empty ObjectTail\n");
+#endif
+
+ formula=rasqal_new_formula();
+ if(!formula) {
+ rasqal_free_formula($1);
+ if($2)
+ rasqal_free_formula($2);
+ YYERROR_MSG("ObjectList: cannot create formula");
+ }
+
+ formula->triples=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_triple, (raptor_sequence_print_handler*)rasqal_triple_print);
+ if(!formula->triples) {
+ rasqal_free_formula(formula);
+ rasqal_free_formula($1);
+ if($2)
+ rasqal_free_formula($2);
+ YYERROR_MSG("ObjectList: cannot create sequence");
+ }
+
+ triple=rasqal_new_triple(NULL, NULL, $1->value);
+ $1->value=NULL; /* value now owned by triple */
+ if(!triple) {
+ rasqal_free_formula(formula);
+ rasqal_free_formula($1);
+ if($2)
+ rasqal_free_formula($2);
+ YYERROR_MSG("ObjectList: cannot create triple");
+ }
+
+ if(raptor_sequence_push(formula->triples, triple)) {
+ rasqal_free_formula(formula);
+ rasqal_free_formula($1);
+ if($2)
+ rasqal_free_formula($2);
+ YYERROR_MSG("ObjectList: sequence push failed");
+ }
+
+ $$=rasqal_formula_join(formula, $1);
+ if(!$$) {
+ if($2)
+ rasqal_free_formula($2);
+ YYERROR_MSG("ObjectList: formula join $1 failed");
+ }
+
+ $$=rasqal_formula_join($$, $2);
+ if(!$$)
+ YYERROR_MSG("ObjectList: formula join $2 failed");
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " objectList is now ");
+ if($$)
+ raptor_sequence_print($$->triples, DEBUG_FH);
+ else
+ fputs("NULL", DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+;
+
+
+/* NEW Grammar Term pulled out of [35] ObjectList */
+ObjectTail: ',' ObjectList
+{
+ $$=$2;
+}
+| /* empty */
+{
+ $$=NULL;
+}
+;
+
+
+/* SPARQL Grammar: [36] Object */
+Object: GraphNode
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [37] Verb */
+Verb: VarOrIRIref
+{
+ $$=rasqal_new_formula();
+ if(!$$) {
+ if($1)
+ rasqal_free_literal($1);
+ YYERROR_MSG("Verb 1: cannot create formula");
+ }
+ $$->value=$1;
+}
+| A
+{
+ raptor_uri *uri;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "verb Verb=rdf:type (a)\n");
+#endif
+
+#ifdef RAPTOR_V2_AVAILABLE
+ uri = raptor_new_uri_for_rdf_concept_v2(((rasqal_query*)rq)->world->raptor_world_ptr, "type");
+#else
+ uri = raptor_new_uri_for_rdf_concept("type");
+#endif
+ if(!uri)
+ YYERROR_MSG("Verb 2: uri for rdf concept type failed");
+ $$=rasqal_new_formula();
+ if(!$$) {
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(((rasqal_query*)rq)->world->raptor_world_ptr, uri);
+#else
+ raptor_free_uri(uri);
+#endif
+ YYERROR_MSG("Verb 2: cannot create formula");
+ }
+ $$->value=rasqal_new_uri_literal(((rasqal_query*)rq)->world, uri);
+ if(!$$->value) {
+ rasqal_free_formula($$);
+ $$=NULL;
+ YYERROR_MSG("Verb 2: cannot create uri literal");
+ }
+}
+;
+
+
+/* SPARQL Grammar: [38] TriplesNode */
+TriplesNode: Collection
+{
+ $$=$1;
+}
+| BlankNodePropertyList
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [39] BlankNodePropertyList */
+BlankNodePropertyList: '[' PropertyListNotEmpty ']'
+{
+ int i;
+ const unsigned char *id;
+
+ if($2 == NULL) {
+ $$=rasqal_new_formula();
+ if(!$$)
+ YYERROR_MSG("BlankNodePropertyList: cannot create formula");
+ } else {
+ $$=$2;
+ if($$->value) {
+ rasqal_free_literal($$->value);
+ $$->value=NULL;
+ }
+ }
+
+ id=rasqal_query_generate_bnodeid((rasqal_query*)rq, NULL);
+ if(!id) {
+ rasqal_free_formula($$);
+ $$=NULL;
+ YYERROR_MSG("BlankNodeProperyList: cannot create bnodeid");
+ }
+
+ $$->value=rasqal_new_simple_literal(((rasqal_query*)rq)->world, RASQAL_LITERAL_BLANK, id);
+ if(!$$->value) {
+ rasqal_free_formula($$);
+ $$=NULL;
+ YYERROR_MSG("BlankNodePropertyList: cannot create literal");
+ }
+
+ if($2 == NULL) {
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "TriplesNode\n PropertyList=");
+ rasqal_formula_print($$, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+#endif
+ } else {
+ raptor_sequence *seq=$2->triples;
+
+ /* non-empty property list, handle it */
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "TriplesNode\n PropertyList=");
+ raptor_sequence_print(seq, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+#endif
+
+ for(i=0; i<raptor_sequence_size(seq); i++) {
+ rasqal_triple* t2=(rasqal_triple*)raptor_sequence_get_at(seq, i);
+ if(t2->subject)
+ continue;
+
+ t2->subject=(rasqal_literal*)rasqal_new_literal_from_literal($$->value);
+ }
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after substitution formula=");
+ rasqal_formula_print($$, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+ }
+}
+;
+
+
+/* SPARQL Grammar: [40] Collection (allowing empty case) */
+Collection: '(' GraphNodeListNotEmpty ')'
+{
+ int i;
+ rasqal_query* rdf_query=(rasqal_query*)rq;
+ rasqal_literal* first_identifier=NULL;
+ rasqal_literal* rest_identifier=NULL;
+ rasqal_literal* object=NULL;
+ rasqal_literal* blank=NULL;
+
+#if RASQAL_DEBUG > 1
+ char const *errmsg;
+ #define YYERR_MSG_GOTO(label,msg) do { errmsg = msg; goto label; } while(0)
+#else
+ #define YYERR_MSG_GOTO(label,ignore) goto label
+#endif
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "Collection\n GraphNodeListNotEmpty=");
+ raptor_sequence_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+#endif
+
+ $$=rasqal_new_formula();
+ if(!$$)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create formula");
+
+ $$->triples=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_triple, (raptor_sequence_print_handler*)rasqal_triple_print);
+ if(!$$->triples)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create sequence");
+
+ first_identifier = rasqal_new_uri_literal(rdf_query->world,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_copy_v2(rdf_query->world->raptor_world_ptr, rdf_query->world->rdf_first_uri)
+#else
+ raptor_uri_copy(rdf_query->world->rdf_first_uri)
+#endif
+ );
+ if(!first_identifier)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot first_identifier");
+
+ rest_identifier = rasqal_new_uri_literal(rdf_query->world,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_copy_v2(rdf_query->world->raptor_world_ptr, rdf_query->world->rdf_rest_uri)
+#else
+ raptor_uri_copy(rdf_query->world->rdf_rest_uri)
+#endif
+ );
+ if(!rest_identifier)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create rest_identifier");
+
+ object = rasqal_new_uri_literal(rdf_query->world,
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_uri_copy_v2(rdf_query->world->raptor_world_ptr, rdf_query->world->rdf_nil_uri)
+#else
+ raptor_uri_copy(rdf_query->world->rdf_nil_uri)
+#endif
+ );
+ if(!object)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create nil object");
+
+ for(i=raptor_sequence_size($2)-1; i>=0; i--) {
+ rasqal_formula* f=(rasqal_formula*)raptor_sequence_get_at($2, i);
+ rasqal_triple *t2;
+ const unsigned char *blank_id=NULL;
+
+ blank_id=rasqal_query_generate_bnodeid(rdf_query, NULL);
+ if(!blank_id)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create bnodeid");
+
+ blank=rasqal_new_simple_literal(((rasqal_query*)rq)->world, RASQAL_LITERAL_BLANK, blank_id);
+ if(!blank)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create bnode");
+
+ /* Move existing formula triples */
+ if(f->triples)
+ if(raptor_sequence_join($$->triples, f->triples))
+ YYERR_MSG_GOTO(err_Collection, "Collection: sequence join failed");
+
+ /* add new triples we needed */
+ t2=rasqal_new_triple(rasqal_new_literal_from_literal(blank),
+ rasqal_new_literal_from_literal(first_identifier),
+ rasqal_new_literal_from_literal(f->value));
+ if(!t2)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create triple");
+
+ if(raptor_sequence_push($$->triples, t2))
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create triple");
+
+ t2=rasqal_new_triple(rasqal_new_literal_from_literal(blank),
+ rasqal_new_literal_from_literal(rest_identifier),
+ rasqal_new_literal_from_literal(object));
+ if(!t2)
+ YYERR_MSG_GOTO(err_Collection, "Collection: cannot create triple 2");
+
+ if(raptor_sequence_push($$->triples, t2))
+ YYERR_MSG_GOTO(err_Collection, "Collection: sequence push 2 failed");
+
+ rasqal_free_literal(object);
+ object=blank;
+ blank=NULL;
+ }
+
+ $$->value=object;
+
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " after substitution collection=");
+ rasqal_formula_print($$, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+
+ rasqal_free_literal(first_identifier);
+ rasqal_free_literal(rest_identifier);
+
+ break; /* success */
+
+ err_Collection:
+
+ if(blank)
+ rasqal_free_literal(blank);
+ if(object)
+ rasqal_free_literal(object);
+ if(rest_identifier)
+ rasqal_free_literal(rest_identifier);
+ if(first_identifier)
+ rasqal_free_literal(first_identifier);
+ if($2)
+ raptor_free_sequence($2);
+ if($$) {
+ rasqal_free_formula($$);
+ $$=NULL;
+ }
+ YYERROR_MSG(errmsg);
+}
+;
+
+
+/* NEW Grammar Term pulled out of [40] Collection */
+/* Sequence of formula */
+GraphNodeListNotEmpty: GraphNodeListNotEmpty GraphNode
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "GraphNodeListNotEmpty 1\n");
+ if($2) {
+ fprintf(DEBUG_FH, " GraphNode=");
+ rasqal_formula_print($2, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+ } else
+ fprintf(DEBUG_FH, " and empty GraphNode\n");
+ if($1) {
+ fprintf(DEBUG_FH, " GraphNodeListNotEmpty=");
+ raptor_sequence_print($1, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+ } else
+ fprintf(DEBUG_FH, " and empty GraphNodeListNotEmpty\n");
+#endif
+
+ if(!$2)
+ $$=NULL;
+ else {
+ /* FIXME: does not work:
+ * $$ not initialized
+ * $1 not freed
+ * also could need a test case */
+ if(raptor_sequence_push($$, $2)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("GraphNodeListNotEmpty 1: sequence push failed");
+ }
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " itemList is now ");
+ raptor_sequence_print($$, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+ }
+
+}
+| GraphNode
+{
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, "GraphNodeListNotEmpty 2\n");
+ if($1) {
+ fprintf(DEBUG_FH, " GraphNode=");
+ rasqal_formula_print($1, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n");
+ } else
+ fprintf(DEBUG_FH, " and empty GraphNode\n");
+#endif
+
+ if(!$1)
+ $$=NULL;
+ else {
+ $$=raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_formula, (raptor_sequence_print_handler*)rasqal_formula_print);
+ if(!$$) {
+ rasqal_free_formula($1);
+ YYERROR_MSG("GraphNodeListNotEmpty 2: cannot create sequence");
+ }
+ if(raptor_sequence_push($$, $1)) {
+ raptor_free_sequence($$);
+ $$=NULL;
+ YYERROR_MSG("GraphNodeListNotEmpty 2: sequence push failed");
+ }
+ }
+#if RASQAL_DEBUG > 1
+ fprintf(DEBUG_FH, " GraphNodeListNotEmpty is now ");
+ raptor_sequence_print($$, DEBUG_FH);
+ fprintf(DEBUG_FH, "\n\n");
+#endif
+}
+;
+
+
+/* SPARQL Grammar: [41] GraphNode */
+GraphNode: VarOrTerm
+{
+ $$=$1;
+}
+| TriplesNode
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar Term: [42] VarOrTerm */
+VarOrTerm: Var
+{
+ $$=rasqal_new_formula();
+ if(!$$)
+ YYERROR_MSG("VarOrTerm 1: cannot create formula");
+ $$->value=rasqal_new_variable_literal(((rasqal_query*)rq)->world, $1);
+ if(!$$->value) {
+ rasqal_free_formula($$);
+ $$=NULL;
+ YYERROR_MSG("VarOrTerm 1: cannot create literal");
+ }
+}
+| GraphTerm
+{
+ $$=rasqal_new_formula();
+ if(!$$) {
+ if($1)
+ rasqal_free_literal($1);
+ YYERROR_MSG("VarOrTerm 2: cannot create formula");
+ }
+ $$->value=$1;
+}
+;
+
+/* SPARQL Grammar: [43] VarOrIRIref */
+VarOrIRIref: Var
+{
+ $$=rasqal_new_variable_literal(((rasqal_query*)rq)->world, $1);
+ if(!$$)
+ YYERROR_MSG("VarOrIRIref: cannot create literal");
+}
+| IRIref
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [44] Var */
+Var: '?' VarName
+{
+ $$=$2;
+}
+| '$' VarName
+{
+ $$=$2;
+}
+;
+
+/* NEW Grammar Term made from SPARQL Grammar: [44] Var */
+VarName: IDENTIFIER
+{
+ $$=rasqal_new_variable((rasqal_query*)rq, $1, NULL);
+ if(!$$)
+ YYERROR_MSG("VarName: cannot create var");
+}
+;
+
+
+
+/* SPARQL Grammar: [45] GraphTerm */
+GraphTerm: IRIref
+{
+ $$=$1;
+}
+| STRING_LITERAL
+{
+ $$=$1;
+}
+| NumericLiteral
+{
+ $$=$1;
+}
+| BOOLEAN_LITERAL
+{
+ $$=$1;
+}
+| BlankNode
+{
+ $$=$1;
+}
+| '(' ')'
+{
+#ifdef RAPTOR_V2_AVAILABLE
+ $$=rasqal_new_uri_literal(((rasqal_query*)rq)->world, raptor_uri_copy_v2(((rasqal_query*)rq)->world->raptor_world_ptr, ((rasqal_query*)rq)->world->rdf_nil_uri));
+#else
+ $$=rasqal_new_uri_literal(((rasqal_query*)rq)->world, raptor_uri_copy(((rasqal_query*)rq)->world->rdf_nil_uri));
+#endif
+ if(!$$)
+ YYERROR_MSG("GraphTerm: cannot create literal");
+}
+;
+
+/* SPARQL Grammar: [46] Expression */
+Expression: ConditionalOrExpression
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [47] ConditionalOrExpression */
+ConditionalOrExpression: ConditionalOrExpression SC_OR ConditionalAndExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_OR, $1, $3);
+ if(!$$)
+ YYERROR_MSG("ConditionalOrExpression: cannot create expr");
+}
+| ConditionalAndExpression
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [48] ConditionalAndExpression */
+ConditionalAndExpression: ConditionalAndExpression SC_AND RelationalExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_AND, $1, $3);
+ if(!$$)
+ YYERROR_MSG("ConditionalAndExpression: cannot create expr");
+;
+}
+| RelationalExpression
+{
+ $$=$1;
+}
+;
+
+/* SPARQL Grammar: [49] ValueLogical - merged into RelationalExpression */
+
+/* SPARQL Grammar: [50] RelationalExpression */
+RelationalExpression: AdditiveExpression EQ AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_EQ, $1, $3);
+ if(!$$)
+ YYERROR_MSG("RelationalExpression 1: cannot create expr");
+}
+| AdditiveExpression NEQ AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_NEQ, $1, $3);
+ if(!$$)
+ YYERROR_MSG("RelationalExpression 2: cannot create expr");
+}
+| AdditiveExpression LT AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_LT, $1, $3);
+ if(!$$)
+ YYERROR_MSG("RelationalExpression 3: cannot create expr");
+}
+| AdditiveExpression GT AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_GT, $1, $3);
+ if(!$$)
+ YYERROR_MSG("RelationalExpression 4: cannot create expr");
+}
+| AdditiveExpression LE AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_LE, $1, $3);
+ if(!$$)
+ YYERROR_MSG("RelationalExpression 5: cannot create expr");
+}
+| AdditiveExpression GE AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_GE, $1, $3);
+ if(!$$)
+ YYERROR_MSG("RelationalExpression 6: cannot create expr");
+}
+| AdditiveExpression
+{
+ $$=$1;
+}
+;
+
+/* SPARQL Grammar: [51] NumericExpression - merged into AdditiveExpression */
+
+/* SPARQL Grammar: [52] AdditiveExpression */
+AdditiveExpression: MultiplicativeExpression '+' AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_PLUS, $1, $3);
+ if(!$$)
+ YYERROR_MSG("AdditiveExpression 1: cannot create expr");
+}
+| MultiplicativeExpression '-' AdditiveExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_MINUS, $1, $3);
+ if(!$$)
+ YYERROR_MSG("AdditiveExpression 2: cannot create expr");
+}
+| MultiplicativeExpression NumericLiteralPositive
+{
+ rasqal_expression *e=rasqal_new_literal_expression(((rasqal_query*)rq)->world, $2);
+ if(!e) {
+ rasqal_free_expression($1);
+ YYERROR_MSG("AdditiveExpression 3: cannot create expr");
+ }
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_PLUS, $1, e);
+ if(!$$)
+ YYERROR_MSG("AdditiveExpression 4: cannot create expr");
+}
+| MultiplicativeExpression NumericLiteralNegative
+{
+ rasqal_expression *e=rasqal_new_literal_expression(((rasqal_query*)rq)->world, $2);
+ if(!e) {
+ rasqal_free_expression($1);
+ YYERROR_MSG("AdditiveExpression 5: cannot create expr");
+ }
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_PLUS, $1, e);
+ if(!$$)
+ YYERROR_MSG("AdditiveExpression 6: cannot create expr");
+}
+| MultiplicativeExpression
+{
+ $$=$1;
+}
+;
+
+/* SPARQL Grammar: [53] MultiplicativeExpression */
+MultiplicativeExpression: UnaryExpression '*' MultiplicativeExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_STAR, $1, $3);
+ if(!$$)
+ YYERROR_MSG("MultiplicativeExpression 1: cannot create expr");
+}
+| UnaryExpression '/' MultiplicativeExpression
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_SLASH, $1, $3);
+ if(!$$)
+ YYERROR_MSG("MultiplicativeExpression 2: cannot create expr");
+}
+| UnaryExpression
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [54] UnaryExpression */
+UnaryExpression: '!' PrimaryExpression
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_BANG, $2);
+ if(!$$)
+ YYERROR_MSG("UnaryExpression 1: cannot create expr");
+}
+| '+' PrimaryExpression
+{
+ $$=$2;
+}
+| '-' PrimaryExpression
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_UMINUS, $2);
+ if(!$$)
+ YYERROR_MSG("UnaryExpression 3: cannot create expr");
+}
+| PrimaryExpression
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [55] PrimaryExpression
+ * == BrackettedExpression | BuiltInCall | IRIrefOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | Var
+ * == BrackettedExpression | BuiltInCall | IRIref ArgList? | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | Var
+ * == BrackettedExpression | BuiltInCall | FunctionCall |
+ * approximately GraphTerm | Var
+ *
+*/
+PrimaryExpression: BrackettedExpression
+{
+ $$=$1;
+}
+| BuiltInCall
+{
+ $$=$1;
+}
+| FunctionCall
+{
+ /* Grammar has IRIrefOrFunction here which is "IRIref ArgList?"
+ * and essentially shorthand for FunctionCall | IRIref. The Rasqal
+ * SPARQL lexer distinguishes these for us with IRIrefBrace.
+ * IRIref is covered below by GraphTerm.
+ */
+ $$=$1;
+}
+| GraphTerm
+{
+ $$=rasqal_new_literal_expression(((rasqal_query*)rq)->world, $1);
+ if(!$$)
+ YYERROR_MSG("PrimaryExpression 4: cannot create expr");
+}
+| Var
+{
+ rasqal_literal *l=rasqal_new_variable_literal(((rasqal_query*)rq)->world, $1);
+ if(!l)
+ YYERROR_MSG("PrimaryExpression 5: cannot create literal");
+ $$=rasqal_new_literal_expression(((rasqal_query*)rq)->world, l);
+ if(!$$)
+ YYERROR_MSG("PrimaryExpression 5: cannot create expr");
+}
+;
+
+
+/* SPARQL Grammar: [56] BrackettedExpression */
+BrackettedExpression: '(' Expression ')'
+{
+ $$=$2;
+}
+;
+
+
+/* SPARQL Grammar: [57] BuiltInCall */
+BuiltInCall: STR '(' Expression ')'
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_STR, $3);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 1: cannot create expr");
+}
+| LANG '(' Expression ')'
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_LANG, $3);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 2: cannot create expr");
+}
+| LANGMATCHES '(' Expression ',' Expression ')'
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_LANGMATCHES, $3, $5);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 3: cannot create expr");
+}
+| DATATYPE '(' Expression ')'
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_DATATYPE, $3);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 4: cannot create expr");
+}
+| BOUND '(' Var ')'
+{
+ rasqal_literal *l;
+ rasqal_expression *e;
+ l=rasqal_new_variable_literal(((rasqal_query*)rq)->world, $3);
+ if(!l)
+ YYERROR_MSG("BuiltInCall 5: cannot create literal");
+ e=rasqal_new_literal_expression(((rasqal_query*)rq)->world, l);
+ if(!e)
+ YYERROR_MSG("BuiltInCall 6: cannot create literal expr");
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_BOUND, e);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 7: cannot create expr");
+}
+| SAMETERM '(' Expression ',' Expression ')'
+{
+ $$=rasqal_new_2op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_SAMETERM, $3, $5);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 8: cannot create expr");
+}
+| ISURI '(' Expression ')'
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ISURI, $3);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 9: cannot create expr");
+}
+| ISBLANK '(' Expression ')'
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ISBLANK, $3);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 10: cannot create expr");
+}
+| ISLITERAL '(' Expression ')'
+{
+ $$=rasqal_new_1op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_ISLITERAL, $3);
+ if(!$$)
+ YYERROR_MSG("BuiltInCall 11: cannot create expr");
+}
+| RegexExpression
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [58] RegexExpression */
+RegexExpression: REGEX '(' Expression ',' Expression ')'
+{
+ $$=rasqal_new_3op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_REGEX, $3, $5, NULL);
+ if(!$$)
+ YYERROR_MSG("RegexExpression 1: cannot create expr");
+}
+| REGEX '(' Expression ',' Expression ',' Expression ')'
+{
+ $$=rasqal_new_3op_expression(((rasqal_query*)rq)->world, RASQAL_EXPR_REGEX, $3, $5, $7);
+ if(!$$)
+ YYERROR_MSG("RegexExpression 2: cannot create expr");
+}
+;
+
+/* SPARQL Grammar: [59] IRIrefOrFunction - not necessary in this
+ grammar as the IRIref ambiguity is determined in lexer with the
+ help of the IRIrefBrace token below */
+
+/* NEW Grammar Term made from SPARQL Grammar: [64] IRIref + '(' expanded */
+IRIrefBrace: URI_LITERAL_BRACE
+{
+ $$=rasqal_new_uri_literal(((rasqal_query*)rq)->world, $1);
+ if(!$$)
+ YYERROR_MSG("IRIrefBrace 1: cannot create literal");
+}
+| QNAME_LITERAL_BRACE
+{
+ $$=rasqal_new_simple_literal(((rasqal_query*)rq)->world, RASQAL_LITERAL_QNAME, $1);
+ if(!$$)
+ YYERROR_MSG("IRIrefBrace 2: cannot create literal");
+ if(rasqal_literal_expand_qname((rasqal_query*)rq, $$)) {
+ sparql_query_error_full((rasqal_query*)rq,
+ "QName %s cannot be expanded", $1);
+ rasqal_free_literal($$);
+ $$=NULL;
+ YYERROR_MSG("IRIrefBrace 2: cannot expand qname");
+ }
+}
+;
+
+
+/* SPARQL Grammar: [60] RDFLiteral - merged into GraphTerm */
+
+/* SPARQL Grammar: [61] NumericLiteral */
+NumericLiteral: NumericLiteralUnsigned
+{
+ $$=$1;
+}
+| NumericLiteralPositive
+{
+ $$=$1;
+}
+| NumericLiteralNegative
+{
+ $$=$1;
+}
+;
+
+/* SPARQL Grammer: [62] NumericLiteralUnsigned */
+NumericLiteralUnsigned: INTEGER_LITERAL
+{
+ $$=$1;
+}
+| DECIMAL_LITERAL
+{
+ $$=$1;
+}
+| DOUBLE_LITERAL
+{
+ $$=$1;
+}
+;
+
+
+ /* SPARQL Grammer: [63] NumericLiteralPositive */
+NumericLiteralPositive: INTEGER_POSITIVE_LITERAL
+{
+ $$=$1;
+}
+| DECIMAL_POSITIVE_LITERAL
+{
+ $$=$1;
+}
+| DOUBLE_POSITIVE_LITERAL
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [64] NumericLiteralNegative */
+NumericLiteralNegative: INTEGER_NEGATIVE_LITERAL
+{
+ $$=$1;
+}
+| DECIMAL_NEGATIVE_LITERAL
+{
+ $$=$1;
+}
+| DOUBLE_NEGATIVE_LITERAL
+{
+ $$=$1;
+}
+;
+
+
+/* SPARQL Grammar: [62] BooleanLiteral - merged into GraphTerm */
+
+/* SPARQL Grammar: [63] String - merged into GraphTerm */
+
+/* SPARQL Grammar: [64] IRIref */
+IRIref: URI_LITERAL
+{
+ $$=rasqal_new_uri_literal(((rasqal_query*)rq)->world, $1);
+ if(!$$)
+ YYERROR_MSG("IRIref 1: cannot create literal");
+}
+| QNAME_LITERAL
+{
+ $$=rasqal_new_simple_literal(((rasqal_query*)rq)->world, RASQAL_LITERAL_QNAME, $1);
+ if(!$$)
+ YYERROR_MSG("IRIref 2: cannot create literal");
+ if(rasqal_literal_expand_qname((rasqal_query*)rq, $$)) {
+ sparql_query_error_full((rasqal_query*)rq,
+ "QName %s cannot be expanded", $1);
+ rasqal_free_literal($$);
+ $$=NULL;
+ YYERROR_MSG("IRIrefBrace 2: cannot expand qname");
+ }
+}
+;
+
+
+/* SPARQL Grammar: [65] QName - made into terminal QNAME_LITERAL */
+
+/* SPARQL Grammar: [66] BlankNode */
+BlankNode: BLANK_LITERAL
+{
+ $$=rasqal_new_simple_literal(((rasqal_query*)rq)->world, RASQAL_LITERAL_BLANK, $1);
+ if(!$$)
+ YYERROR_MSG("BlankNode 1: cannot create literal");
+} | '[' ']'
+{
+ const unsigned char *id=rasqal_query_generate_bnodeid((rasqal_query*)rq, NULL);
+ if(!id)
+ YYERROR_MSG("BlankNode 2: cannot create bnodeid");
+ $$=rasqal_new_simple_literal(((rasqal_query*)rq)->world, RASQAL_LITERAL_BLANK, id);
+ if(!$$)
+ YYERROR_MSG("BlankNode 2: cannot create literal");
+}
+;
+
+/* SPARQL Grammar: [67] Q_IRI_REF onwards are all lexer items
+ * with similar names or are inlined.
+ */
+
+
+
+
+%%
+
+
+/* Support functions */
+
+
+/* This is declared in sparql_lexer.h but never used, so we always get
+ * a warning unless this dummy code is here. Used once below in an error case.
+ */
+static int yy_init_globals (yyscan_t yyscanner ) { return 0; };
+
+
+/**
+ * rasqal_sparql_query_language_init - Initialise the SPARQL query language parser
+ *
+ * Return value: non 0 on failure
+ **/
+static int
+rasqal_sparql_query_language_init(rasqal_query* rdf_query, const char *name) {
+ rasqal_sparql_query_language* rqe=(rasqal_sparql_query_language*)rdf_query->context;
+
+ rdf_query->compare_flags = RASQAL_COMPARE_XQUERY;
+
+ rqe->extended = (strcmp(name, "laqrs") == 0);
+ return 0;
+}
+
+
+/**
+ * rasqal_sparql_query_language_terminate - Free the SPARQL query language parser
+ *
+ * Return value: non 0 on failure
+ **/
+static void
+rasqal_sparql_query_language_terminate(rasqal_query* rdf_query) {
+ rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)rdf_query->context;
+
+ if(sparql && sparql->scanner_set) {
+ sparql_lexer_lex_destroy(sparql->scanner);
+ sparql->scanner_set=0;
+ }
+
+}
+
+
+static int
+rasqal_sparql_query_language_prepare(rasqal_query* rdf_query) {
+ /* rasqal_sparql_query_language* sparql=(rasqal_sparql_query_language*)rdf_query->context; */
+ int rc;
+
+ if(!rdf_query->query_string)
+ return 1;
+
+ rc=sparql_parse(rdf_query);
+ if(rc)
+ return rc;
+
+ /* FIXME - should check remaining query parts */
+ if(rasqal_sequence_has_qname(rdf_query->triples) ||
+ rasqal_sequence_has_qname(rdf_query->constructs) ||
+ rasqal_query_constraints_has_qname(rdf_query)) {
+ sparql_query_error(rdf_query, "SPARQL query has unexpanded QNames");
+ return 1;
+ }
+
+ /* SPARQL: Turn [] into anonymous variables */
+ if(rasqal_query_build_anonymous_variables(rdf_query))
+ return 1;
+
+ /* SPARQL: Expand 'SELECT *' */
+ if(rasqal_query_expand_wildcards(rdf_query))
+ return 1;
+
+ return 0;
+}
+
+
+static int
+sparql_parse(rasqal_query* rq) {
+ rasqal_sparql_query_language* rqe=(rasqal_sparql_query_language*)rq->context;
+ raptor_locator *locator=&rq->locator;
+ void *buffer;
+
+ if(!rq->query_string)
+ return yy_init_globals(NULL); /* 0 but a way to use yy_init_globals */
+
+ locator->line=1;
+ locator->column= -1; /* No column info */
+ locator->byte= -1; /* No bytes info */
+
+#if RASQAL_DEBUG > 2
+ sparql_parser_debug=1;
+#endif
+
+ rqe->lineno=1;
+
+ if(sparql_lexer_lex_init(&rqe->scanner))
+ return 1;
+ rqe->scanner_set=1;
+
+ sparql_lexer_set_extra(((rasqal_query*)rq), rqe->scanner);
+
+ buffer= sparql_lexer__scan_buffer((char*)rq->query_string, rq->query_string_length, rqe->scanner);
+
+ rqe->error_count=0;
+
+ sparql_parser_parse(rq);
+
+ sparql_lexer_lex_destroy(rqe->scanner);
+ rqe->scanner_set=0;
+
+ /* Parsing failed */
+ if(rq->failed)
+ return 1;
+
+ return 0;
+}
+
+
+static void
+sparql_query_error(rasqal_query *rq, const char *msg) {
+ rasqal_sparql_query_language* rqe=(rasqal_sparql_query_language*)rq->context;
+
+ if(rqe->error_count++)
+ return;
+
+ rq->locator.line=rqe->lineno;
+#ifdef RASQAL_SPARQL_USE_ERROR_COLUMNS
+ /* rq->locator.column=sparql_lexer_get_column(yyscanner);*/
+#endif
+
+ rq->failed=1;
+ rasqal_log_error_simple(((rasqal_query*)rq)->world, RAPTOR_LOG_LEVEL_ERROR, &rq->locator,
+ "%s", msg);
+}
+
+
+static void
+sparql_query_error_full(rasqal_query *rq, const char *message, ...) {
+ va_list arguments;
+ rasqal_sparql_query_language* rqe=(rasqal_sparql_query_language*)rq->context;
+
+ if(rqe->error_count++)
+ return;
+
+ rq->locator.line=rqe->lineno;
+#ifdef RASQAL_SPARQL_USE_ERROR_COLUMNS
+ /* rq->locator.column=sparql_lexer_get_column(yyscanner);*/
+#endif
+
+ va_start(arguments, message);
+
+ rq->failed=1;
+ rasqal_log_error_varargs(((rasqal_query*)rq)->world, RAPTOR_LOG_LEVEL_ERROR, &rq->locator,
+ message, arguments);
+
+ va_end(arguments);
+}
+
+
+int
+sparql_syntax_error(rasqal_query *rq, const char *message, ...)
+{
+ rasqal_sparql_query_language *rqe=(rasqal_sparql_query_language*)rq->context;
+ va_list arguments;
+
+ if(rqe->error_count++)
+ return 0;
+
+ rq->locator.line=rqe->lineno;
+#ifdef RASQAL_SPARQL_USE_ERROR_COLUMNS
+ /* rp->locator.column=sparql_lexer_get_column(yyscanner);*/
+#endif
+
+ va_start(arguments, message);
+ rq->failed=1;
+ rasqal_log_error_varargs(((rasqal_query*)rq)->world, RAPTOR_LOG_LEVEL_ERROR, &rq->locator,
+ message, arguments);
+ va_end(arguments);
+
+ return 0;
+}
+
+
+int
+sparql_syntax_warning(rasqal_query *rq, const char *message, ...)
+{
+ rasqal_sparql_query_language *rqe=(rasqal_sparql_query_language*)rq->context;
+ va_list arguments;
+
+ rq->locator.line=rqe->lineno;
+#ifdef RASQAL_SPARQL_USE_ERROR_COLUMNS
+ /* rq->locator.column=sparql_lexer_get_column(yyscanner);*/
+#endif
+
+ va_start(arguments, message);
+ rasqal_log_error_varargs(((rasqal_query*)rq)->world, RAPTOR_LOG_LEVEL_WARNING, &rq->locator,
+ message, arguments);
+ va_end(arguments);
+
+ return (0);
+}
+
+
+static int
+rasqal_sparql_query_language_iostream_write_escaped_counted_string(rasqal_query* query,
+ raptor_iostream* iostr,
+ const unsigned char* string,
+ size_t len)
+{
+ const char delim='"';
+
+ raptor_iostream_write_byte(iostr, delim);
+ if(raptor_iostream_write_string_ntriples(iostr, string, len, delim))
+ return 1;
+
+ raptor_iostream_write_byte(iostr, delim);
+
+ return 0;
+}
+
+
+static void
+rasqal_sparql_query_language_register_factory(rasqal_query_language_factory *factory)
+{
+ factory->context_length = sizeof(rasqal_sparql_query_language);
+
+ factory->init = rasqal_sparql_query_language_init;
+ factory->terminate = rasqal_sparql_query_language_terminate;
+ factory->prepare = rasqal_sparql_query_language_prepare;
+ factory->iostream_write_escaped_counted_string = rasqal_sparql_query_language_iostream_write_escaped_counted_string;
+}
+
+
+int
+rasqal_init_query_language_sparql(rasqal_world* world) {
+ return rasqal_query_language_register_factory(world,
+ "sparql",
+ "SPARQL W3C DAWG RDF Query Language",
+ NULL,
+ (const unsigned char*)"http://www.w3.org/TR/rdf-sparql-query/",
+ &rasqal_sparql_query_language_register_factory);
+}
+
+int
+rasqal_init_query_language_laqrs(rasqal_world* world) {
+ return rasqal_query_language_register_factory(world,
+ "laqrs",
+ "LAQRS adds to Querying RDF in SPARQL",
+ NULL,
+ NULL,
+ &rasqal_sparql_query_language_register_factory);
+}
+
+
+#ifdef STANDALONE
+#include <stdio.h>
+#include <locale.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef HAVE_GETOPT
+#include <rasqal_getopt.h>
+#endif
+
+#ifdef NEED_OPTIND_DECLARATION
+extern int optind;
+extern char *optarg;
+#endif
+
+#define GETOPT_STRING "di:"
+
+#define SPARQL_FILE_BUF_SIZE 2048
+
+int
+main(int argc, char *argv[])
+{
+ const char *program=rasqal_basename(argv[0]);
+ char query_string[SPARQL_FILE_BUF_SIZE];
+ rasqal_query *query;
+ FILE *fh;
+ int rc;
+ const char *filename=NULL;
+ raptor_uri* base_uri=NULL;
+ unsigned char *uri_string;
+ const char* query_languages[2]={"sparql", "laqrs"};
+ const char* query_language;
+ int usage=0;
+ int fh_opened_here=0;
+ rasqal_world *world;
+
+ query_language=query_languages[0];
+
+ while(!usage) {
+ int c = getopt (argc, argv, GETOPT_STRING);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ case '?': /* getopt() - unknown option */
+ usage=1;
+ break;
+
+ case 'd':
+#if RASQAL_DEBUG > 2
+ sparql_parser_debug=1;
+#endif
+ break;
+
+ case 'i':
+ if(optarg) {
+ if(!strcmp(optarg, "laqrs")) {
+ query_language=query_languages[1];
+ } else if(!strcmp(optarg, "sparql")) {
+ query_language=query_languages[0];
+ } else {
+ fprintf(stderr, "-i laqrs or -i sparql only\n");
+ usage=1;
+ }
+ }
+ break;
+ }
+ }
+
+ if((argc-optind)>1) {
+ fprintf(stderr, "%s: Too many arguments.\n", program);
+ usage=1;
+ }
+
+ if(usage) {
+ fprintf(stderr, "SPARQL/LAQRS parser test for Rasqal %s\n",
+ rasqal_version_string);
+ fprintf(stderr, "USAGE: %s [OPTIONS] [QUERY-FILE]\n", program);
+ fprintf(stderr, "OPTIONS:\n");
+#if RASQAL_DEBUG > 2
+ fprintf(stderr, " -d Bison parser debugging\n");
+#endif
+ fprintf(stderr, " -i LANGUAGE Set query language\n");
+ exit(1);
+ }
+
+ if(optind == argc-1) {
+ filename=argv[optind];
+ fh = fopen(argv[optind], "r");
+ if(!fh) {
+ fprintf(stderr, "%s: Cannot open file %s - %s\n", program, filename,
+ strerror(errno));
+ exit(1);
+ }
+ fh_opened_here=1;
+ } else {
+ filename="<stdin>";
+ fh = stdin;
+ }
+
+ memset(query_string, 0, SPARQL_FILE_BUF_SIZE);
+ rc=fread(query_string, SPARQL_FILE_BUF_SIZE, 1, fh);
+ if(rc < SPARQL_FILE_BUF_SIZE) {
+ if(ferror(fh)) {
+ fprintf(stderr, "%s: file '%s' read failed - %s\n",
+ program, filename, strerror(errno));
+ fclose(fh);
+ return(1);
+ }
+ }
+
+ if(fh_opened_here)
+ fclose(fh);
+
+ world=rasqal_new_world();
+ if(!world || rasqal_world_open(world))
+ exit(1);
+
+ query=rasqal_new_query(world, query_language, NULL);
+
+ uri_string=raptor_uri_filename_to_uri_string(filename);
+#ifdef RAPTOR_V2_AVAILABLE
+ base_uri = raptor_new_uri_v2(world->raptor_world_ptr, uri_string);
+#else
+ base_uri = raptor_new_uri(uri_string);
+#endif
+
+ rc=rasqal_query_prepare(query, (const unsigned char*)query_string, base_uri);
+
+ rasqal_query_print(query, stdout);
+
+ rasqal_free_query(query);
+
+#ifdef RAPTOR_V2_AVAILABLE
+ raptor_free_uri_v2(world->raptor_world_ptr, base_uri);
+#else
+ raptor_free_uri(base_uri);
+#endif
+
+ raptor_free_memory(uri_string);
+
+ rasqal_free_world(world);
+
+ return rc;
+}
+#endif
diff --git a/src/rasqal/strcasecmp.c b/src/rasqal/strcasecmp.c
new file mode 100644
index 0000000..0565b26
--- /dev/null
+++ b/src/rasqal/strcasecmp.c
@@ -0,0 +1,118 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * strcasecmp.c - strcasecmp compatibility
+ *
+ * This file is in the public domain.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <rasqal_config.h>
+#endif
+
+#ifdef WIN32
+#include <win32_rasqal_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+int rasqal_strcasecmp(const char* s1, const char* s2);
+int rasqal_strncasecmp(const char* s1, const char* s2, size_t n);
+
+
+int
+rasqal_strcasecmp(const char* s1, const char* s2)
+{
+ register int c1, c2;
+
+ while(*s1 && *s2) {
+ c1 = tolower(*s1);
+ c2 = tolower(*s2);
+ if (c1 != c2)
+ return (c1 - c2);
+ s1++;
+ s2++;
+ }
+ return (int) (*s1 - *s2);
+}
+
+
+int
+rasqal_strncasecmp(const char* s1, const char* s2, size_t n)
+{
+ register int c1, c2;
+
+ while(*s1 && *s2 && n) {
+ c1 = tolower(*s1);
+ c2 = tolower(*s2);
+ if (c1 != c2)
+ return (c1 - c2);
+ s1++;
+ s2++;
+ n--;
+ }
+ return 0;
+}
+
+
+
+#ifdef STANDALONE
+
+#include <stdio.h>
+
+/* one more prototype */
+int main(int argc, char *argv[]);
+
+
+
+static int
+assert_strcasecmp (const char *s1, const char *s2, int expected)
+{
+ int result=strcasecmp(s1, s2);
+ result=(result>0) ? 1 : ((result <0) ? -1 : 0);
+
+ if (result != expected)
+ {
+ fprintf(stderr, "FAIL strcasecmp (%s, %s) gave %d != %d\n",
+ s1, s2, result, expected);
+ return 1;
+ }
+ return 0;
+}
+
+
+static int
+assert_strncasecmp (const char *s1, const char *s2, size_t size, int expected)
+{
+ int result=strncasecmp(s1, s2, size);
+ result=(result>0) ? 1 : ((result <0) ? -1 : 0);
+
+ if (result != expected)
+ {
+ fprintf(stderr, "FAIL strncasecmp (%s, %s, %d) gave %d != %d\n",
+ s1, s2, (unsigned int)size, result, expected);
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int failures=0;
+
+ failures += assert_strcasecmp("foo", "foo", 0);
+ failures += assert_strcasecmp("foo", "FOO", 0);
+ failures += assert_strcasecmp("foo", "BaR", 1);
+
+ failures += assert_strncasecmp("foo", "foobar", 3, 0);
+ failures += assert_strncasecmp("foo", "FOOxyz", 3, 0);
+ failures += assert_strncasecmp("foo", "BaRfoo", 3, 1);
+
+ return failures;
+}
+
+#endif
diff --git a/src/rasqal/win32_rasqal_config.h b/src/rasqal/win32_rasqal_config.h
new file mode 100644
index 0000000..a3c26e9
--- /dev/null
+++ b/src/rasqal/win32_rasqal_config.h
@@ -0,0 +1,129 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * win32_config.h - Rasqal WIN32 hard-coded config
+ *
+ * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
+ * 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.
+ *
+ */
+
+
+#ifndef WIN32_CONFIG_H
+#define WIN32_CONFIG_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+
+/* getopt is not in standard win32 C library - define if we have it */
+/* #define HAVE_GETOPT_H 1 */
+
+#define HAVE_STDLIB_H 1
+
+#define HAVE_STRICMP 1
+
+/* MS names for these functions */
+#define vsnprintf _vsnprintf
+#define snprintf _snprintf
+#define access _access
+#define stricmp _stricmp
+#define strnicmp _strnicmp
+
+#include <float.h>
+#define isnan _isnan
+
+/* This is a SPARQL token define */
+#undef OPTIONAL
+
+#define HAVE_C99_VSNPRINTF 1
+
+/* for access() which is POSIX but doesn't seem to have the defines in VC */
+#ifndef R_OK
+#define R_OK 4
+#endif
+
+/* __func__ doesn't exist in Visual Studio 6 */
+#define __func__ ""
+
+/*
+ * Defines that come from config.h
+ */
+
+/* Release version as a decimal */
+#define RASQAL_VERSION_DECIMAL 917
+
+/* Major version number */
+#define RASQAL_VERSION_MAJOR 0
+
+/* Minor version number */
+#define RASQAL_VERSION_MINOR 9
+
+/* Release version number */
+#define RASQAL_VERSION_RELEASE 17
+
+/* Version number of package */
+#define VERSION "0.9.17"
+
+#include <windows.h>
+#include <io.h>
+#include <memory.h>
+
+/* This is a SPARQL token define */
+#ifdef OPTIONAL
+#undef OPTIONAL
+#endif
+
+/* bison: output uses ERROR in an enum which breaks if this is defined */
+#ifdef ERROR
+#undef ERROR
+#endif
+
+/* flex: const is available */
+#define YY_USE_CONST
+/* looks like the .c files define this anyway */
+/* #define YY_NO_UNISTD_H */
+
+#undef RASQAL_INLINE
+#define RASQAL_INLINE __inline
+
+/* Building RDQL query */
+#define RASQAL_QUERY_RDQL 1
+
+/* Building SPARQL query */
+#define RASQAL_QUERY_SPARQL 1
+
+/* Use raptor to provide triples */
+#define RAPTOR_TRIPLES_SOURCE_RAPTOR 1
+
+/* Use redland to provide triples */
+/* #define RAPTOR_TRIPLES_SOURCE_REDLAND 1 */
+
+/* Use PCRE regex library */
+#define RASQAL_REGEX_PCRE 1
+
+#ifdef _DEBUG
+#define RASQAL_DEBUG 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]