Chris@439
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@439
|
2
|
Chris@439
|
3 /*
|
Chris@439
|
4 Sonic Visualiser
|
Chris@439
|
5 An audio file viewer and annotation editor.
|
Chris@439
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@439
|
7 This file copyright 2008 QMUL.
|
Chris@439
|
8
|
Chris@439
|
9 This program is free software; you can redistribute it and/or
|
Chris@439
|
10 modify it under the terms of the GNU General Public License as
|
Chris@439
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@439
|
12 License, or (at your option) any later version. See the file
|
Chris@439
|
13 COPYING included with this distribution for more information.
|
Chris@439
|
14 */
|
Chris@439
|
15
|
Chris@439
|
16 #include "SimpleSPARQLQuery.h"
|
Chris@439
|
17 #include "base/ProgressReporter.h"
|
Chris@480
|
18 #include "base/Profiler.h"
|
Chris@480
|
19
|
Chris@480
|
20 #include <QMutex>
|
Chris@480
|
21 #include <QMutexLocker>
|
Chris@481
|
22 #include <QRegExp>
|
Chris@480
|
23
|
Chris@480
|
24 #include <set>
|
Chris@439
|
25
|
Chris@440
|
26 #ifdef USE_NEW_RASQAL_API
|
Chris@440
|
27 #include <rasqal/rasqal.h>
|
Chris@440
|
28 #else
|
Chris@439
|
29 #include <rasqal.h>
|
Chris@440
|
30 #endif
|
Chris@439
|
31
|
Chris@480
|
32 #include <redland.h>
|
Chris@480
|
33
|
Chris@490
|
34 #define DEBUG_SIMPLE_SPARQL_QUERY 1
|
Chris@461
|
35
|
Chris@439
|
36 #include <iostream>
|
Chris@439
|
37
|
Chris@439
|
38 using std::cerr;
|
Chris@439
|
39 using std::endl;
|
Chris@439
|
40
|
Chris@440
|
41 #ifdef USE_NEW_RASQAL_API
|
Chris@440
|
42 class WrasqalWorldWrapper // wrong but wromantic, etc
|
Chris@440
|
43 {
|
Chris@440
|
44 public:
|
Chris@481
|
45 WrasqalWorldWrapper() :
|
Chris@481
|
46 m_world(0)
|
Chris@481
|
47 {
|
Chris@481
|
48 m_world = rasqal_new_world();
|
Chris@481
|
49 if (!m_world) {
|
Chris@481
|
50 cerr << "SimpleSPARQLQuery: ERROR: Failed to create RASQAL world!" << endl;
|
Chris@481
|
51 return;
|
Chris@481
|
52 }
|
Chris@481
|
53 /*!!! This appears to be new for 0.9.17?
|
Chris@481
|
54 if (rasqal_world_open(m_world)) {
|
Chris@481
|
55 cerr << "SimpleSPARQLQuery: ERROR: Failed to open RASQAL world!" << endl;
|
Chris@481
|
56 return;
|
Chris@481
|
57 }
|
Chris@481
|
58 */
|
Chris@481
|
59 }
|
Chris@481
|
60 ~WrasqalWorldWrapper()
|
Chris@481
|
61 {
|
Chris@481
|
62 rasqal_free_world(m_world);
|
Chris@481
|
63 }
|
Chris@440
|
64
|
Chris@489
|
65 bool isOK() const { return (m_world != 0); }
|
Chris@489
|
66
|
Chris@480
|
67 rasqal_world *getWorld() { return m_world; }
|
Chris@480
|
68 const rasqal_world *getWorld() const { return m_world; }
|
Chris@440
|
69
|
Chris@440
|
70 private:
|
Chris@440
|
71 rasqal_world *m_world;
|
Chris@440
|
72 };
|
Chris@440
|
73 #endif
|
Chris@440
|
74
|
Chris@480
|
75 class WredlandWorldWrapper
|
Chris@480
|
76 {
|
Chris@480
|
77 public:
|
Chris@480
|
78 WredlandWorldWrapper() :
|
Chris@480
|
79 m_world(0), m_storage(0), m_model(0)
|
Chris@480
|
80 {
|
Chris@480
|
81 m_world = librdf_new_world();
|
Chris@481
|
82 if (!m_world) {
|
Chris@481
|
83 cerr << "SimpleSPARQLQuery: ERROR: Failed to create LIBRDF world!" << endl;
|
Chris@481
|
84 return;
|
Chris@481
|
85 }
|
Chris@480
|
86 librdf_world_open(m_world);
|
Chris@481
|
87 m_storage = librdf_new_storage(m_world, "trees", NULL, NULL);
|
Chris@480
|
88 if (!m_storage) {
|
Chris@481
|
89 std::cerr << "SimpleSPARQLQuery: ERROR: Failed to initialise Redland trees datastore, falling back to memory store" << std::endl;
|
Chris@480
|
90 m_storage = librdf_new_storage(m_world, NULL, NULL, NULL);
|
Chris@480
|
91 if (!m_storage) {
|
Chris@480
|
92 std::cerr << "SimpleSPARQLQuery: ERROR: Failed to initialise Redland memory datastore" << std::endl;
|
Chris@480
|
93 return;
|
Chris@480
|
94 }
|
Chris@480
|
95 }
|
Chris@480
|
96 m_model = librdf_new_model(m_world, m_storage, NULL);
|
Chris@480
|
97 if (!m_model) {
|
Chris@480
|
98 std::cerr << "SimpleSPARQLQuery: ERROR: Failed to initialise Redland data model" << std::endl;
|
Chris@480
|
99 return;
|
Chris@480
|
100 }
|
Chris@480
|
101 }
|
Chris@480
|
102
|
Chris@480
|
103 ~WredlandWorldWrapper()
|
Chris@480
|
104 {
|
Chris@480
|
105 while (!m_parsedUris.empty()) {
|
Chris@480
|
106 librdf_free_uri(m_parsedUris.begin()->second);
|
Chris@480
|
107 m_parsedUris.erase(m_parsedUris.begin());
|
Chris@480
|
108 }
|
Chris@480
|
109 if (m_model) librdf_free_model(m_model);
|
Chris@480
|
110 if (m_storage) librdf_free_storage(m_storage);
|
Chris@480
|
111 if (m_world) librdf_free_world(m_world);
|
Chris@480
|
112 }
|
Chris@480
|
113
|
Chris@480
|
114 bool isOK() const { return (m_model != 0); }
|
Chris@480
|
115
|
Chris@480
|
116 librdf_uri *getUri(QString uriString, QString &errorString)
|
Chris@480
|
117 {
|
Chris@480
|
118 if (m_parsedUris.find(uriString) != m_parsedUris.end()) {
|
Chris@480
|
119 return m_parsedUris[uriString];
|
Chris@480
|
120 }
|
Chris@480
|
121
|
Chris@480
|
122 librdf_uri *uri = librdf_new_uri
|
Chris@480
|
123 (m_world, (const unsigned char *)uriString.toUtf8().data());
|
Chris@480
|
124 if (!uri) {
|
Chris@480
|
125 errorString = "Failed to construct librdf_uri!";
|
Chris@480
|
126 return 0;
|
Chris@480
|
127 }
|
Chris@480
|
128
|
Chris@480
|
129 librdf_parser *parser = librdf_new_parser(m_world, "guess", NULL, NULL);
|
Chris@480
|
130 if (!parser) {
|
Chris@480
|
131 errorString = "Failed to initialise Redland parser";
|
Chris@480
|
132 return 0;
|
Chris@480
|
133 }
|
Chris@480
|
134
|
Chris@480
|
135 std::cerr << "About to parse \"" << uriString.toStdString() << "\"" << std::endl;
|
Chris@480
|
136
|
Chris@480
|
137 Profiler p("SimpleSPARQLQuery: Parse URI into LIBRDF model");
|
Chris@480
|
138
|
Chris@480
|
139 if (librdf_parser_parse_into_model(parser, uri, NULL, m_model)) {
|
Chris@480
|
140
|
Chris@480
|
141 errorString = QString("Failed to parse RDF from URI \"%1\"")
|
Chris@480
|
142 .arg(uriString);
|
Chris@480
|
143 librdf_free_parser(parser);
|
Chris@490
|
144 // librdf_free_uri(uri);
|
Chris@480
|
145 return 0;
|
Chris@480
|
146
|
Chris@480
|
147 } else {
|
Chris@480
|
148
|
Chris@480
|
149 librdf_free_parser(parser);
|
Chris@480
|
150 m_parsedUris[uriString] = uri;
|
Chris@480
|
151 return uri;
|
Chris@480
|
152 }
|
Chris@480
|
153 }
|
Chris@480
|
154
|
Chris@480
|
155 librdf_world *getWorld() { return m_world; }
|
Chris@480
|
156 const librdf_world *getWorld() const { return m_world; }
|
Chris@480
|
157
|
Chris@480
|
158 librdf_model *getModel() { return m_model; }
|
Chris@480
|
159 const librdf_model *getModel() const { return m_model; }
|
Chris@480
|
160
|
Chris@480
|
161 private:
|
Chris@480
|
162 librdf_world *m_world;
|
Chris@480
|
163 librdf_storage *m_storage;
|
Chris@480
|
164 librdf_model *m_model;
|
Chris@480
|
165
|
Chris@480
|
166 QMutex m_mutex;
|
Chris@480
|
167 std::map<QString, librdf_uri *> m_parsedUris;
|
Chris@480
|
168 };
|
Chris@480
|
169
|
Chris@439
|
170 class SimpleSPARQLQuery::Impl
|
Chris@439
|
171 {
|
Chris@439
|
172 public:
|
Chris@489
|
173 Impl(SimpleSPARQLQuery::QueryType, QString query);
|
Chris@439
|
174 ~Impl();
|
Chris@439
|
175
|
Chris@489
|
176 static bool addSourceToModel(QString sourceUri);
|
Chris@489
|
177
|
Chris@439
|
178 void setProgressReporter(ProgressReporter *reporter) { m_reporter = reporter; }
|
Chris@439
|
179 bool wasCancelled() const { return m_cancelled; }
|
Chris@439
|
180
|
Chris@439
|
181 ResultList execute();
|
Chris@439
|
182
|
Chris@439
|
183 bool isOK() const;
|
Chris@439
|
184 QString getErrorString() const;
|
Chris@439
|
185
|
Chris@439
|
186 protected:
|
Chris@439
|
187 static void errorHandler(void *, raptor_locator *, const char *);
|
Chris@439
|
188
|
Chris@480
|
189 static QMutex m_mutex;
|
Chris@480
|
190
|
Chris@440
|
191 #ifdef USE_NEW_RASQAL_API
|
Chris@480
|
192 static WrasqalWorldWrapper *m_rasqal;
|
Chris@440
|
193 #else
|
Chris@480
|
194 static bool m_rasqalInitialised;
|
Chris@440
|
195 #endif
|
Chris@480
|
196
|
Chris@480
|
197 static WredlandWorldWrapper *m_redland;
|
Chris@480
|
198
|
Chris@480
|
199 ResultList executeDirectParser();
|
Chris@480
|
200 ResultList executeDatastore();
|
Chris@480
|
201
|
Chris@489
|
202 QueryType m_type;
|
Chris@439
|
203 QString m_query;
|
Chris@439
|
204 QString m_errorString;
|
Chris@439
|
205 ProgressReporter *m_reporter;
|
Chris@439
|
206 bool m_cancelled;
|
Chris@439
|
207 };
|
Chris@439
|
208
|
Chris@440
|
209 #ifdef USE_NEW_RASQAL_API
|
Chris@480
|
210 WrasqalWorldWrapper *SimpleSPARQLQuery::Impl::m_rasqal = 0;
|
Chris@440
|
211 #else
|
Chris@480
|
212 bool SimpleSPARQLQuery::Impl::m_rasqalInitialised = false;
|
Chris@440
|
213 #endif
|
Chris@440
|
214
|
Chris@480
|
215 WredlandWorldWrapper *SimpleSPARQLQuery::Impl::m_redland = 0;
|
Chris@480
|
216
|
Chris@480
|
217 QMutex SimpleSPARQLQuery::Impl::m_mutex;
|
Chris@480
|
218
|
Chris@489
|
219 SimpleSPARQLQuery::SimpleSPARQLQuery(QueryType type, QString query) :
|
Chris@489
|
220 m_impl(new Impl(type, query))
|
Chris@480
|
221 {
|
Chris@480
|
222 }
|
Chris@439
|
223
|
Chris@439
|
224 SimpleSPARQLQuery::~SimpleSPARQLQuery()
|
Chris@439
|
225 {
|
Chris@439
|
226 delete m_impl;
|
Chris@439
|
227 }
|
Chris@439
|
228
|
Chris@439
|
229 void
|
Chris@439
|
230 SimpleSPARQLQuery::setProgressReporter(ProgressReporter *reporter)
|
Chris@439
|
231 {
|
Chris@439
|
232 m_impl->setProgressReporter(reporter);
|
Chris@439
|
233 }
|
Chris@439
|
234
|
Chris@439
|
235 bool
|
Chris@439
|
236 SimpleSPARQLQuery::wasCancelled() const
|
Chris@439
|
237 {
|
Chris@439
|
238 return m_impl->wasCancelled();
|
Chris@439
|
239 }
|
Chris@439
|
240
|
Chris@439
|
241 SimpleSPARQLQuery::ResultList
|
Chris@439
|
242 SimpleSPARQLQuery::execute()
|
Chris@439
|
243 {
|
Chris@439
|
244 return m_impl->execute();
|
Chris@439
|
245 }
|
Chris@439
|
246
|
Chris@439
|
247 bool
|
Chris@439
|
248 SimpleSPARQLQuery::isOK() const
|
Chris@439
|
249 {
|
Chris@439
|
250 return m_impl->isOK();
|
Chris@439
|
251 }
|
Chris@439
|
252
|
Chris@439
|
253 QString
|
Chris@439
|
254 SimpleSPARQLQuery::getErrorString() const
|
Chris@439
|
255 {
|
Chris@439
|
256 return m_impl->getErrorString();
|
Chris@439
|
257 }
|
Chris@439
|
258
|
Chris@489
|
259 bool
|
Chris@489
|
260 SimpleSPARQLQuery::addSourceToModel(QString sourceUri)
|
Chris@480
|
261 {
|
Chris@489
|
262 return SimpleSPARQLQuery::Impl::addSourceToModel(sourceUri);
|
Chris@480
|
263 }
|
Chris@480
|
264
|
Chris@489
|
265 SimpleSPARQLQuery::Impl::Impl(QueryType type, QString query) :
|
Chris@489
|
266 m_type(type),
|
Chris@439
|
267 m_query(query),
|
Chris@439
|
268 m_reporter(0),
|
Chris@439
|
269 m_cancelled(false)
|
Chris@439
|
270 {
|
Chris@461
|
271 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
|
Chris@461
|
272 std::cerr << "SimpleSPARQLQuery::Impl: Query is: \"" << query.toStdString() << "\"" << std::endl;
|
Chris@461
|
273 #endif
|
Chris@439
|
274 }
|
Chris@439
|
275
|
Chris@439
|
276 SimpleSPARQLQuery::Impl::~Impl()
|
Chris@439
|
277 {
|
Chris@439
|
278 }
|
Chris@439
|
279
|
Chris@439
|
280 bool
|
Chris@439
|
281 SimpleSPARQLQuery::Impl::isOK() const
|
Chris@439
|
282 {
|
Chris@439
|
283 return (m_errorString == "");
|
Chris@439
|
284 }
|
Chris@439
|
285
|
Chris@439
|
286 QString
|
Chris@439
|
287 SimpleSPARQLQuery::Impl::getErrorString() const
|
Chris@439
|
288 {
|
Chris@439
|
289 return m_errorString;
|
Chris@439
|
290 }
|
Chris@439
|
291
|
Chris@439
|
292 void
|
Chris@439
|
293 SimpleSPARQLQuery::Impl::errorHandler(void *data,
|
Chris@439
|
294 raptor_locator *locator,
|
Chris@439
|
295 const char *message)
|
Chris@439
|
296 {
|
Chris@439
|
297 SimpleSPARQLQuery::Impl *impl = (SimpleSPARQLQuery::Impl *)data;
|
Chris@439
|
298
|
Chris@481
|
299 char buffer[256];
|
Chris@481
|
300 raptor_format_locator(buffer, 255, locator);
|
Chris@481
|
301 QString loc(buffer);
|
Chris@481
|
302 if (loc != "") {
|
Chris@481
|
303 impl->m_errorString = QString("%1 - %2").arg(loc).arg(message);
|
Chris@481
|
304 } else {
|
Chris@481
|
305 impl->m_errorString = message;
|
Chris@481
|
306 }
|
Chris@439
|
307
|
Chris@439
|
308 cerr << "SimpleSPARQLQuery: ERROR: " << impl->m_errorString.toStdString() << endl;
|
Chris@439
|
309 }
|
Chris@439
|
310
|
Chris@439
|
311 SimpleSPARQLQuery::ResultList
|
Chris@439
|
312 SimpleSPARQLQuery::Impl::execute()
|
Chris@439
|
313 {
|
Chris@439
|
314 ResultList list;
|
Chris@439
|
315
|
Chris@490
|
316 QMutexLocker locker(&m_mutex);
|
Chris@480
|
317
|
Chris@489
|
318 if (m_type == QueryFromModel) {
|
Chris@489
|
319 if (!m_redland) {
|
Chris@489
|
320 // There can be no results, because no sources have been
|
Chris@489
|
321 // added to the model yet (m_redland is only created when
|
Chris@489
|
322 // addSourceToModel is called)
|
Chris@489
|
323 cerr << "SimpleSPARQLQuery::execute: NOTE: No sources have been added to data model yet, so no results are possible" << endl;
|
Chris@489
|
324 return list;
|
Chris@481
|
325 }
|
Chris@481
|
326 }
|
Chris@481
|
327
|
Chris@489
|
328 if (m_type == QueryFromSingleSource) {
|
Chris@489
|
329 #ifdef USE_NEW_RASQAL_API
|
Chris@489
|
330 if (!m_rasqal) {
|
Chris@489
|
331 m_rasqal = new WrasqalWorldWrapper();
|
Chris@489
|
332 if (!m_rasqal->isOK()) {
|
Chris@489
|
333 cerr << "ERROR: SimpleSPARQLQuery::execute: Failed to initialise Rasqal query engine" << endl;
|
Chris@489
|
334 delete m_rasqal;
|
Chris@489
|
335 m_rasqal = 0;
|
Chris@489
|
336 return list;
|
Chris@480
|
337 }
|
Chris@480
|
338 }
|
Chris@480
|
339 #else
|
Chris@480
|
340 if (!m_rasqalInitialised) {
|
Chris@480
|
341 rasqal_init();
|
Chris@480
|
342 m_rasqalInitialised = true;
|
Chris@480
|
343 }
|
Chris@480
|
344 #endif
|
Chris@440
|
345 }
|
Chris@480
|
346
|
Chris@489
|
347 if (m_type == QueryFromSingleSource) {
|
Chris@480
|
348 return executeDirectParser();
|
Chris@480
|
349 } else {
|
Chris@480
|
350 return executeDatastore();
|
Chris@480
|
351 }
|
Chris@480
|
352 }
|
Chris@480
|
353
|
Chris@480
|
354 SimpleSPARQLQuery::ResultList
|
Chris@480
|
355 SimpleSPARQLQuery::Impl::executeDirectParser()
|
Chris@480
|
356 {
|
Chris@480
|
357 ResultList list;
|
Chris@480
|
358
|
Chris@480
|
359 Profiler profiler("SimpleSPARQLQuery::executeDirectParser");
|
Chris@480
|
360
|
Chris@480
|
361 #ifdef USE_NEW_RASQAL_API
|
Chris@480
|
362 rasqal_query *query = rasqal_new_query(m_rasqal->getWorld(), "sparql", NULL);
|
Chris@480
|
363 #else
|
Chris@439
|
364 rasqal_query *query = rasqal_new_query("sparql", NULL);
|
Chris@440
|
365 #endif
|
Chris@439
|
366 if (!query) {
|
Chris@439
|
367 m_errorString = "Failed to construct query";
|
Chris@439
|
368 cerr << "SimpleSPARQLQuery: ERROR: " << m_errorString.toStdString() << endl;
|
Chris@439
|
369 return list;
|
Chris@439
|
370 }
|
Chris@439
|
371
|
Chris@439
|
372 rasqal_query_set_error_handler(query, this, errorHandler);
|
Chris@439
|
373 rasqal_query_set_fatal_error_handler(query, this, errorHandler);
|
Chris@439
|
374
|
Chris@480
|
375 {
|
Chris@480
|
376 Profiler p("SimpleSPARQLQuery: Prepare RASQAL query");
|
Chris@480
|
377
|
Chris@480
|
378 if (rasqal_query_prepare
|
Chris@480
|
379 (query, (const unsigned char *)m_query.toUtf8().data(), NULL)) {
|
Chris@480
|
380 cerr << "SimpleSPARQLQuery: Failed to prepare query" << endl;
|
Chris@480
|
381 rasqal_free_query(query);
|
Chris@480
|
382 return list;
|
Chris@480
|
383 }
|
Chris@439
|
384 }
|
Chris@439
|
385
|
Chris@480
|
386 rasqal_query_results *results;
|
Chris@480
|
387
|
Chris@480
|
388 {
|
Chris@480
|
389 Profiler p("SimpleSPARQLQuery: Execute RASQAL query");
|
Chris@480
|
390 results = rasqal_query_execute(query);
|
Chris@480
|
391 }
|
Chris@439
|
392
|
Chris@439
|
393 // cerr << "Query executed" << endl;
|
Chris@439
|
394
|
Chris@439
|
395 if (!results) {
|
Chris@439
|
396 cerr << "SimpleSPARQLQuery: RASQAL query failed" << endl;
|
Chris@439
|
397 rasqal_free_query(query);
|
Chris@439
|
398 return list;
|
Chris@439
|
399 }
|
Chris@439
|
400
|
Chris@439
|
401 if (!rasqal_query_results_is_bindings(results)) {
|
Chris@439
|
402 cerr << "SimpleSPARQLQuery: RASQAL query has wrong result type (not bindings)" << endl;
|
Chris@439
|
403 rasqal_free_query_results(results);
|
Chris@439
|
404 rasqal_free_query(query);
|
Chris@439
|
405 return list;
|
Chris@439
|
406 }
|
Chris@439
|
407
|
Chris@439
|
408 int resultCount = 0;
|
Chris@439
|
409 int resultTotal = rasqal_query_results_get_count(results); // probably wrong
|
Chris@439
|
410 m_cancelled = false;
|
Chris@439
|
411
|
Chris@439
|
412 while (!rasqal_query_results_finished(results)) {
|
Chris@439
|
413
|
Chris@439
|
414 int count = rasqal_query_results_get_bindings_count(results);
|
Chris@439
|
415
|
Chris@439
|
416 KeyValueMap resultmap;
|
Chris@439
|
417
|
Chris@439
|
418 for (int i = 0; i < count; ++i) {
|
Chris@439
|
419
|
Chris@439
|
420 const unsigned char *name =
|
Chris@439
|
421 rasqal_query_results_get_binding_name(results, i);
|
Chris@439
|
422
|
Chris@490
|
423 if (!name) {
|
Chris@490
|
424 std::cerr << "WARNING: Result " << i << " of query has no name" << std::endl;
|
Chris@490
|
425 continue;
|
Chris@490
|
426 }
|
Chris@490
|
427
|
Chris@439
|
428 rasqal_literal *literal =
|
Chris@439
|
429 rasqal_query_results_get_binding_value(results, i);
|
Chris@439
|
430
|
Chris@439
|
431 QString key = (const char *)name;
|
Chris@439
|
432
|
Chris@439
|
433 if (!literal) {
|
Chris@439
|
434 resultmap[key] = Value();
|
Chris@439
|
435 continue;
|
Chris@439
|
436 }
|
Chris@439
|
437
|
Chris@439
|
438 ValueType type = LiteralValue;
|
Chris@490
|
439 if (literal->type == RASQAL_LITERAL_BLANK) type = BlankValue;
|
Chris@490
|
440 else if (literal->type == RASQAL_LITERAL_URI) type = URIValue;
|
Chris@439
|
441
|
Chris@490
|
442 QString text;
|
Chris@490
|
443 const char *lit = (const char *)rasqal_literal_as_string(literal);
|
Chris@490
|
444 if (!lit) {
|
Chris@490
|
445 std::cerr << "WARNING: Result " << i << " of query has null value" << std::endl;
|
Chris@490
|
446 } else {
|
Chris@490
|
447 text = lit;
|
Chris@490
|
448 }
|
Chris@439
|
449
|
Chris@461
|
450 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
|
Chris@449
|
451 std::cerr << i << ". " << key.toStdString() << " -> " << text.toStdString() << " (type " << type << ")" << std::endl;
|
Chris@461
|
452 #endif
|
Chris@449
|
453
|
Chris@439
|
454 resultmap[key] = Value(type, text);
|
Chris@439
|
455 }
|
Chris@439
|
456
|
Chris@439
|
457 list.push_back(resultmap);
|
Chris@439
|
458
|
Chris@439
|
459 rasqal_query_results_next(results);
|
Chris@439
|
460
|
Chris@439
|
461 resultCount++;
|
Chris@439
|
462
|
Chris@439
|
463 if (m_reporter) {
|
Chris@439
|
464 if (resultCount >= resultTotal) {
|
Chris@439
|
465 if (m_reporter->isDefinite()) m_reporter->setDefinite(false);
|
Chris@439
|
466 m_reporter->setProgress(resultCount);
|
Chris@439
|
467 } else {
|
Chris@439
|
468 m_reporter->setProgress((resultCount * 100) / resultTotal);
|
Chris@439
|
469 }
|
Chris@439
|
470
|
Chris@439
|
471 if (m_reporter->wasCancelled()) {
|
Chris@439
|
472 m_cancelled = true;
|
Chris@439
|
473 break;
|
Chris@439
|
474 }
|
Chris@439
|
475 }
|
Chris@439
|
476 }
|
Chris@439
|
477
|
Chris@439
|
478 rasqal_free_query_results(results);
|
Chris@439
|
479 rasqal_free_query(query);
|
Chris@439
|
480
|
Chris@439
|
481 return list;
|
Chris@439
|
482 }
|
Chris@440
|
483
|
Chris@480
|
484 SimpleSPARQLQuery::ResultList
|
Chris@480
|
485 SimpleSPARQLQuery::Impl::executeDatastore()
|
Chris@480
|
486 {
|
Chris@480
|
487 ResultList list;
|
Chris@489
|
488
|
Chris@480
|
489 Profiler profiler("SimpleSPARQLQuery::executeDatastore");
|
Chris@480
|
490
|
Chris@481
|
491 /*!!!
|
Chris@480
|
492 static std::map<QString, int> counter;
|
Chris@480
|
493 if (counter.find(m_query) == counter.end()) counter[m_query] = 1;
|
Chris@480
|
494 else ++counter[m_query];
|
Chris@480
|
495 std::cerr << "Counter for this query: " << counter[m_query] << std::endl;
|
Chris@481
|
496 std::cerr << "Base URI is: \"" << m_fromUri.toStdString() << "\"" << std::endl;
|
Chris@481
|
497 */
|
Chris@480
|
498
|
Chris@480
|
499 librdf_query *query;
|
Chris@480
|
500
|
Chris@480
|
501 {
|
Chris@480
|
502 Profiler p("SimpleSPARQLQuery: Prepare LIBRDF query");
|
Chris@480
|
503 query = librdf_new_query
|
Chris@480
|
504 (m_redland->getWorld(), "sparql", NULL,
|
Chris@489
|
505 (const unsigned char *)m_query.toUtf8().data(), NULL);
|
Chris@480
|
506 }
|
Chris@480
|
507
|
Chris@480
|
508 if (!query) {
|
Chris@480
|
509 m_errorString = "Failed to construct query";
|
Chris@480
|
510 return list;
|
Chris@480
|
511 }
|
Chris@480
|
512
|
Chris@480
|
513 librdf_query_results *results;
|
Chris@480
|
514 {
|
Chris@480
|
515 Profiler p("SimpleSPARQLQuery: Execute LIBRDF query");
|
Chris@480
|
516 results = librdf_query_execute(query, m_redland->getModel());
|
Chris@480
|
517 }
|
Chris@480
|
518
|
Chris@480
|
519 if (!results) {
|
Chris@480
|
520 cerr << "SimpleSPARQLQuery: LIBRDF query failed" << endl;
|
Chris@480
|
521 librdf_free_query(query);
|
Chris@480
|
522 return list;
|
Chris@480
|
523 }
|
Chris@480
|
524
|
Chris@480
|
525 if (!librdf_query_results_is_bindings(results)) {
|
Chris@480
|
526 cerr << "SimpleSPARQLQuery: LIBRDF query has wrong result type (not bindings)" << endl;
|
Chris@480
|
527 librdf_free_query_results(results);
|
Chris@480
|
528 librdf_free_query(query);
|
Chris@480
|
529 return list;
|
Chris@480
|
530 }
|
Chris@480
|
531
|
Chris@480
|
532 int resultCount = 0;
|
Chris@480
|
533 int resultTotal = librdf_query_results_get_count(results); // probably wrong
|
Chris@480
|
534 m_cancelled = false;
|
Chris@480
|
535
|
Chris@480
|
536 while (!librdf_query_results_finished(results)) {
|
Chris@480
|
537
|
Chris@480
|
538 int count = librdf_query_results_get_bindings_count(results);
|
Chris@480
|
539
|
Chris@480
|
540 KeyValueMap resultmap;
|
Chris@480
|
541
|
Chris@480
|
542 for (int i = 0; i < count; ++i) {
|
Chris@480
|
543
|
Chris@480
|
544 const char *name =
|
Chris@480
|
545 librdf_query_results_get_binding_name(results, i);
|
Chris@480
|
546
|
Chris@490
|
547 if (!name) {
|
Chris@490
|
548 std::cerr << "WARNING: Result " << i << " of query has no name" << std::endl;
|
Chris@490
|
549 continue;
|
Chris@490
|
550 }
|
Chris@490
|
551
|
Chris@480
|
552 librdf_node *node =
|
Chris@480
|
553 librdf_query_results_get_binding_value(results, i);
|
Chris@480
|
554
|
Chris@480
|
555 QString key = (const char *)name;
|
Chris@480
|
556
|
Chris@480
|
557 if (!node) {
|
Chris@480
|
558 resultmap[key] = Value();
|
Chris@480
|
559 continue;
|
Chris@480
|
560 }
|
Chris@480
|
561
|
Chris@480
|
562 ValueType type = LiteralValue;
|
Chris@481
|
563 QString text;
|
Chris@481
|
564
|
Chris@481
|
565 if (librdf_node_is_resource(node)) {
|
Chris@481
|
566
|
Chris@481
|
567 type = URIValue;
|
Chris@481
|
568 librdf_uri *uri = librdf_node_get_uri(node);
|
Chris@490
|
569 const char *us = (const char *)librdf_uri_as_string(uri);
|
Chris@490
|
570
|
Chris@490
|
571 if (!us) {
|
Chris@490
|
572 std::cerr << "WARNING: Result " << i << " of query claims URI type, but has null URI" << std::endl;
|
Chris@490
|
573 } else {
|
Chris@490
|
574 text = us;
|
Chris@490
|
575 }
|
Chris@481
|
576
|
Chris@481
|
577 } else if (librdf_node_is_literal(node)) {
|
Chris@481
|
578
|
Chris@481
|
579 type = LiteralValue;
|
Chris@490
|
580
|
Chris@490
|
581 const char *lit = (const char *)librdf_node_get_literal_value(node);
|
Chris@490
|
582 if (!lit) {
|
Chris@490
|
583 std::cerr << "WARNING: Result " << i << " of query claims literal type, but has no literal" << std::endl;
|
Chris@490
|
584 } else {
|
Chris@490
|
585 text = lit;
|
Chris@490
|
586 }
|
Chris@481
|
587
|
Chris@481
|
588 } else if (librdf_node_is_blank(node)) {
|
Chris@481
|
589
|
Chris@481
|
590 type = BlankValue;
|
Chris@481
|
591
|
Chris@481
|
592 } else {
|
Chris@481
|
593
|
Chris@480
|
594 cerr << "SimpleSPARQLQuery: LIBRDF query returned unknown node type (not resource, literal, or blank)" << endl;
|
Chris@480
|
595 }
|
Chris@480
|
596
|
Chris@480
|
597 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
|
Chris@481
|
598 cerr << i << ". " << key.toStdString() << " -> " << text.toStdString() << " (type " << type << ")" << endl;
|
Chris@480
|
599 #endif
|
Chris@480
|
600
|
Chris@480
|
601 resultmap[key] = Value(type, text);
|
Chris@480
|
602
|
Chris@480
|
603 librdf_free_node(node);
|
Chris@480
|
604 }
|
Chris@480
|
605
|
Chris@480
|
606 list.push_back(resultmap);
|
Chris@480
|
607
|
Chris@480
|
608 librdf_query_results_next(results);
|
Chris@480
|
609
|
Chris@480
|
610 resultCount++;
|
Chris@480
|
611
|
Chris@480
|
612 if (m_reporter) {
|
Chris@480
|
613 if (resultCount >= resultTotal) {
|
Chris@480
|
614 if (m_reporter->isDefinite()) m_reporter->setDefinite(false);
|
Chris@480
|
615 m_reporter->setProgress(resultCount);
|
Chris@480
|
616 } else {
|
Chris@480
|
617 m_reporter->setProgress((resultCount * 100) / resultTotal);
|
Chris@480
|
618 }
|
Chris@480
|
619
|
Chris@480
|
620 if (m_reporter->wasCancelled()) {
|
Chris@480
|
621 m_cancelled = true;
|
Chris@480
|
622 break;
|
Chris@480
|
623 }
|
Chris@480
|
624 }
|
Chris@480
|
625 }
|
Chris@480
|
626
|
Chris@480
|
627 librdf_free_query_results(results);
|
Chris@480
|
628 librdf_free_query(query);
|
Chris@480
|
629
|
Chris@481
|
630 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
|
Chris@481
|
631 cerr << "All results retrieved (" << resultCount << " of them)" << endl;
|
Chris@481
|
632 #endif
|
Chris@480
|
633
|
Chris@480
|
634 return list;
|
Chris@489
|
635 }
|
Chris@489
|
636
|
Chris@489
|
637 bool
|
Chris@489
|
638 SimpleSPARQLQuery::Impl::addSourceToModel(QString sourceUri)
|
Chris@489
|
639 {
|
Chris@489
|
640 QString err;
|
Chris@489
|
641
|
Chris@490
|
642 QMutexLocker locker(&m_mutex);
|
Chris@489
|
643
|
Chris@489
|
644 if (!m_redland) {
|
Chris@489
|
645 m_redland = new WredlandWorldWrapper();
|
Chris@489
|
646 if (!m_redland->isOK()) {
|
Chris@489
|
647 cerr << "ERROR: SimpleSPARQLQuery::addSourceToModel: Failed to initialise Redland datastore" << endl;
|
Chris@489
|
648 delete m_redland;
|
Chris@489
|
649 m_redland = 0;
|
Chris@489
|
650 return false;
|
Chris@489
|
651 }
|
Chris@489
|
652 }
|
Chris@489
|
653
|
Chris@489
|
654 librdf_uri *uri = m_redland->getUri(sourceUri, err);
|
Chris@489
|
655
|
Chris@489
|
656 if (!uri) {
|
Chris@489
|
657 std::cerr << "SimpleSPARQLQuery::addSourceToModel: Failed to add source URI \"" << sourceUri.toStdString() << ": " << err.toStdString() << std::endl;
|
Chris@489
|
658 return false;
|
Chris@489
|
659 }
|
Chris@489
|
660 return true;
|
Chris@480
|
661 }
|
Chris@480
|
662
|
Chris@440
|
663 SimpleSPARQLQuery::Value
|
Chris@489
|
664 SimpleSPARQLQuery::singleResultQuery(QueryType type,
|
Chris@480
|
665 QString query, QString binding)
|
Chris@440
|
666 {
|
Chris@489
|
667 SimpleSPARQLQuery q(type, query);
|
Chris@440
|
668 ResultList results = q.execute();
|
Chris@440
|
669 if (!q.isOK()) {
|
Chris@440
|
670 cerr << "SimpleSPARQLQuery::singleResultQuery: ERROR: "
|
Chris@440
|
671 << q.getErrorString().toStdString() << endl;
|
Chris@440
|
672 return Value();
|
Chris@440
|
673 }
|
Chris@440
|
674 if (results.empty()) {
|
Chris@440
|
675 return Value();
|
Chris@440
|
676 }
|
Chris@440
|
677 for (int i = 0; i < results.size(); ++i) {
|
Chris@440
|
678 if (results[i].find(binding) != results[i].end() &&
|
Chris@440
|
679 results[i][binding].type != NoValue) {
|
Chris@440
|
680 return results[i][binding];
|
Chris@440
|
681 }
|
Chris@440
|
682 }
|
Chris@440
|
683 return Value();
|
Chris@440
|
684 }
|
Chris@440
|
685
|
Chris@440
|
686
|
Chris@440
|
687
|