1 : /* SLV2
2 : * Copyright (C) 2007-2009 Dave Robillard <http://drobilla.net>
3 : *
4 : * This library is free software; you can redistribute it and/or modify it
5 : * under the terms of the GNU General Public License as published by the Free
6 : * Software Foundation; either version 2 of the License, or (at your option)
7 : * any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 : * for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License along
15 : * with this program; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #define _XOPEN_SOURCE 500
20 : #include <assert.h>
21 : #include <librdf.h>
22 : #include <limits.h>
23 : #include <locale.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include "slv2/types.h"
27 : #include "slv2/collections.h"
28 : #include "slv2/plugin.h"
29 : #include "slv2/query.h"
30 : #include "slv2/util.h"
31 : #include "slv2_internal.h"
32 :
33 :
34 : static const char* slv2_query_prefixes =
35 : "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
36 : "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"
37 : "PREFIX doap: <http://usefulinc.com/ns/doap#>\n"
38 : "PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n"
39 : "PREFIX lv2: <http://lv2plug.in/ns/lv2core#>\n"
40 : "PREFIX lv2ev: <http://lv2plug.in/ns/ext/event#>\n";
41 :
42 :
43 : /** Create a new SLV2Value from a librdf_node, or return NULL if impossible */
44 : SLV2Value
45 : slv2_value_from_librdf_node(SLV2World world, librdf_node* node)
46 51 : {
47 51 : SLV2Value result = NULL;
48 :
49 51 : librdf_uri* datatype_uri = NULL;
50 51 : SLV2ValueType type = SLV2_VALUE_STRING;
51 :
52 51 : switch (librdf_node_get_type(node)) {
53 : case LIBRDF_NODE_TYPE_RESOURCE:
54 25 : type = SLV2_VALUE_URI;
55 25 : result = slv2_value_new_librdf_uri(world, librdf_node_get_uri(node));
56 25 : break;
57 : case LIBRDF_NODE_TYPE_LITERAL:
58 25 : datatype_uri = librdf_node_get_literal_value_datatype_uri(node);
59 25 : if (datatype_uri) {
60 8 : if (!strcmp((const char*)librdf_uri_as_string(datatype_uri),
61 : "http://www.w3.org/2001/XMLSchema#integer"))
62 6 : type = SLV2_VALUE_INT;
63 2 : else if (!strcmp((const char*)librdf_uri_as_string(datatype_uri),
64 : "http://www.w3.org/2001/XMLSchema#decimal"))
65 2 : type = SLV2_VALUE_FLOAT;
66 : else
67 0 : fprintf(stderr, "Unknown datatype %s\n", librdf_uri_as_string(datatype_uri));
68 : }
69 25 : result = slv2_value_new(world, type, (const char*)librdf_node_get_literal_value(node));
70 25 : break;
71 : case LIBRDF_NODE_TYPE_BLANK:
72 1 : type = SLV2_VALUE_STRING;
73 1 : result = slv2_value_new(world, type, (const char*)librdf_node_get_blank_identifier(node));
74 1 : break;
75 : case LIBRDF_NODE_TYPE_UNKNOWN:
76 : default:
77 0 : fprintf(stderr, "Unknown RDF node type %d\n", librdf_node_get_type(node));
78 : break;
79 : }
80 :
81 51 : return result;
82 : }
83 :
84 :
85 : SLV2Values
86 : slv2_query_get_variable_bindings(SLV2World world,
87 : SLV2Results results,
88 : int variable)
89 45 : {
90 45 : SLV2Values result = NULL;
91 :
92 45 : if (!librdf_query_results_finished(results->rdf_results))
93 42 : result = slv2_values_new();
94 :
95 133 : while (!librdf_query_results_finished(results->rdf_results)) {
96 43 : librdf_node* node = librdf_query_results_get_binding_value(results->rdf_results, variable);
97 :
98 43 : if (node == NULL) {
99 0 : fprintf(stderr, "SLV2 ERROR: Variable %d bound to NULL.\n", variable);
100 0 : librdf_query_results_next(results->rdf_results);
101 0 : continue;
102 : }
103 :
104 43 : SLV2Value val = slv2_value_from_librdf_node(world, node);
105 43 : if (val)
106 43 : raptor_sequence_push(result, val);
107 :
108 43 : librdf_free_node(node);
109 43 : librdf_query_results_next(results->rdf_results);
110 : }
111 :
112 45 : return result;
113 : }
114 :
115 :
116 : unsigned
117 : slv2_results_size(SLV2Results results)
118 2 : {
119 2 : size_t count = 0;
120 :
121 5 : while (!slv2_results_finished(results)) {
122 1 : ++count;
123 1 : slv2_results_next(results);
124 : }
125 :
126 2 : return count;
127 : }
128 :
129 :
130 : SLV2Results
131 : slv2_plugin_query_sparql(SLV2Plugin plugin,
132 : const char* sparql_str)
133 61 : {
134 61 : slv2_plugin_load_if_necessary(plugin);
135 :
136 61 : librdf_uri* base_uri = slv2_value_as_librdf_uri(plugin->plugin_uri);
137 :
138 61 : char* query_str = slv2_strjoin(slv2_query_prefixes, sparql_str, NULL);
139 :
140 : //printf("******** Query \n%s********\n", query_str);
141 :
142 : librdf_query* query = librdf_new_query(plugin->world->world, "sparql", NULL,
143 61 : (const unsigned char*)query_str, base_uri);
144 :
145 61 : if (!query) {
146 0 : fprintf(stderr, "ERROR: Could not create query\n");
147 0 : return NULL;
148 : }
149 :
150 : // FIXME: locale kludges to work around librdf bug
151 61 : char* locale = strdup(setlocale(LC_NUMERIC, NULL));
152 :
153 61 : setlocale(LC_NUMERIC, "POSIX");
154 61 : librdf_query_results* results = librdf_query_execute(query, plugin->rdf);
155 61 : setlocale(LC_NUMERIC, locale);
156 :
157 61 : free(locale);
158 :
159 61 : librdf_free_query(query);
160 61 : free(query_str);
161 :
162 61 : SLV2Results ret = (SLV2Results)malloc(sizeof(struct _SLV2Results));
163 61 : ret->world = plugin->world;
164 61 : ret->rdf_results = results;
165 :
166 61 : return ret;
167 : }
168 :
169 :
170 : void
171 : slv2_results_free(SLV2Results results)
172 61 : {
173 61 : librdf_free_query_results(results->rdf_results);
174 61 : free(results);
175 61 : }
176 :
177 :
178 : bool
179 : slv2_results_finished(SLV2Results results)
180 9 : {
181 9 : return librdf_query_results_finished(results->rdf_results);
182 : }
183 :
184 :
185 : SLV2Value
186 : slv2_results_get_binding_value(SLV2Results results, unsigned index)
187 6 : {
188 6 : return slv2_value_from_librdf_node(results->world,
189 : librdf_query_results_get_binding_value(
190 : results->rdf_results, index));
191 : }
192 :
193 :
194 : SLV2Value
195 : slv2_results_get_binding_value_by_name(SLV2Results results, const char* name)
196 2 : {
197 2 : return slv2_value_from_librdf_node(results->world,
198 : librdf_query_results_get_binding_value_by_name(
199 : results->rdf_results, name));
200 : }
201 :
202 :
203 : const char*
204 : slv2_results_get_binding_name(SLV2Results results, unsigned index)
205 2 : {
206 2 : return librdf_query_results_get_binding_name(results->rdf_results, index);
207 : }
208 :
209 :
210 : void
211 : slv2_results_next(SLV2Results results)
212 3 : {
213 3 : librdf_query_results_next(results->rdf_results);
214 3 : }
215 :
216 :
217 : /** Query a single variable */
218 : SLV2Values
219 : slv2_plugin_query_variable(SLV2Plugin plugin,
220 : const char* sparql_str,
221 : unsigned variable)
222 45 : {
223 45 : assert(variable < INT_MAX);
224 :
225 45 : SLV2Results results = slv2_plugin_query_sparql(plugin, sparql_str);
226 :
227 : SLV2Values ret = slv2_query_get_variable_bindings(plugin->world,
228 45 : results, (int)variable);
229 :
230 45 : slv2_results_free(results);
231 :
232 45 : return ret;
233 : }
234 :
235 :
236 : /** Run a query and count number of matches.
237 : *
238 : * More efficient than slv2_plugin_simple_query if you're only interested
239 : * in the number of results (ie slv2_plugin_num_ports).
240 : *
241 : * Note the result of this function is probably meaningless unless the query
242 : * is a SELECT DISTINCT.
243 : */
244 : unsigned
245 : slv2_plugin_query_count(SLV2Plugin plugin,
246 : const char* sparql_str)
247 2 : {
248 2 : SLV2Results results = slv2_plugin_query_sparql(plugin, sparql_str);
249 :
250 2 : unsigned ret = 0;
251 :
252 2 : if (results) {
253 2 : ret = slv2_results_size(results);
254 2 : slv2_results_free(results);
255 : }
256 :
257 2 : return ret;
258 : }
259 :
|