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@461
|
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 QMutexLocker locker(&m_mutex);
|
Chris@480
|
119
|
Chris@480
|
120 if (m_parsedUris.find(uriString) != m_parsedUris.end()) {
|
Chris@480
|
121 return m_parsedUris[uriString];
|
Chris@480
|
122 }
|
Chris@480
|
123
|
Chris@480
|
124 librdf_uri *uri = librdf_new_uri
|
Chris@480
|
125 (m_world, (const unsigned char *)uriString.toUtf8().data());
|
Chris@480
|
126 if (!uri) {
|
Chris@480
|
127 errorString = "Failed to construct librdf_uri!";
|
Chris@480
|
128 return 0;
|
Chris@480
|
129 }
|
Chris@480
|
130
|
Chris@480
|
131 librdf_parser *parser = librdf_new_parser(m_world, "guess", NULL, NULL);
|
Chris@480
|
132 if (!parser) {
|
Chris@480
|
133 errorString = "Failed to initialise Redland parser";
|
Chris@480
|
134 return 0;
|
Chris@480
|
135 }
|
Chris@480
|
136
|
Chris@480
|
137 std::cerr << "About to parse \"" << uriString.toStdString() << "\"" << std::endl;
|
Chris@480
|
138
|
Chris@480
|
139 Profiler p("SimpleSPARQLQuery: Parse URI into LIBRDF model");
|
Chris@480
|
140
|
Chris@480
|
141 if (librdf_parser_parse_into_model(parser, uri, NULL, m_model)) {
|
Chris@480
|
142
|
Chris@480
|
143 errorString = QString("Failed to parse RDF from URI \"%1\"")
|
Chris@480
|
144 .arg(uriString);
|
Chris@480
|
145 librdf_free_parser(parser);
|
Chris@480
|
146 librdf_free_uri(uri);
|
Chris@480
|
147 return 0;
|
Chris@480
|
148
|
Chris@480
|
149 } else {
|
Chris@480
|
150
|
Chris@480
|
151 librdf_free_parser(parser);
|
Chris@480
|
152 m_parsedUris[uriString] = uri;
|
Chris@480
|
153 return uri;
|
Chris@480
|
154 }
|
Chris@480
|
155 }
|
Chris@480
|
156
|
Chris@480
|
157 librdf_world *getWorld() { return m_world; }
|
Chris@480
|
158 const librdf_world *getWorld() const { return m_world; }
|
Chris@480
|
159
|
Chris@480
|
160 librdf_model *getModel() { return m_model; }
|
Chris@480
|
161 const librdf_model *getModel() const { return m_model; }
|
Chris@480
|
162
|
Chris@480
|
163 private:
|
Chris@480
|
164 librdf_world *m_world;
|
Chris@480
|
165 librdf_storage *m_storage;
|
Chris@480
|
166 librdf_model *m_model;
|
Chris@480
|
167
|
Chris@480
|
168 QMutex m_mutex;
|
Chris@480
|
169 std::map<QString, librdf_uri *> m_parsedUris;
|
Chris@480
|
170 };
|
Chris@480
|
171
|
Chris@439
|
172 class SimpleSPARQLQuery::Impl
|
Chris@439
|
173 {
|
Chris@439
|
174 public:
|
Chris@489
|
175 Impl(SimpleSPARQLQuery::QueryType, QString query);
|
Chris@439
|
176 ~Impl();
|
Chris@439
|
177
|
Chris@489
|
178 static bool addSourceToModel(QString sourceUri);
|
Chris@489
|
179
|
Chris@439
|
180 void setProgressReporter(ProgressReporter *reporter) { m_reporter = reporter; }
|
Chris@439
|
181 bool wasCancelled() const { return m_cancelled; }
|
Chris@439
|
182
|
Chris@439
|
183 ResultList execute();
|
Chris@439
|
184
|
Chris@439
|
185 bool isOK() const;
|
Chris@439
|
186 QString getErrorString() const;
|
Chris@439
|
187
|
Chris@439
|
188 protected:
|
Chris@439
|
189 static void errorHandler(void *, raptor_locator *, const char *);
|
Chris@439
|
190
|
Chris@480
|
191 static QMutex m_mutex;
|
Chris@480
|
192
|
Chris@440
|
193 #ifdef USE_NEW_RASQAL_API
|
Chris@480
|
194 static WrasqalWorldWrapper *m_rasqal;
|
Chris@440
|
195 #else
|
Chris@480
|
196 static bool m_rasqalInitialised;
|
Chris@440
|
197 #endif
|
Chris@480
|
198
|
Chris@480
|
199 static WredlandWorldWrapper *m_redland;
|
Chris@480
|
200
|
Chris@480
|
201 ResultList executeDirectParser();
|
Chris@480
|
202 ResultList executeDatastore();
|
Chris@480
|
203
|
Chris@489
|
204 QueryType m_type;
|
Chris@439
|
205 QString m_query;
|
Chris@439
|
206 QString m_errorString;
|
Chris@439
|
207 ProgressReporter *m_reporter;
|
Chris@439
|
208 bool m_cancelled;
|
Chris@439
|
209 };
|
Chris@439
|
210
|
Chris@440
|
211 #ifdef USE_NEW_RASQAL_API
|
Chris@480
|
212 WrasqalWorldWrapper *SimpleSPARQLQuery::Impl::m_rasqal = 0;
|
Chris@440
|
213 #else
|
Chris@480
|
214 bool SimpleSPARQLQuery::Impl::m_rasqalInitialised = false;
|
Chris@440
|
215 #endif
|
Chris@440
|
216
|
Chris@480
|
217 WredlandWorldWrapper *SimpleSPARQLQuery::Impl::m_redland = 0;
|
Chris@480
|
218
|
Chris@480
|
219 QMutex SimpleSPARQLQuery::Impl::m_mutex;
|
Chris@480
|
220
|
Chris@489
|
221 SimpleSPARQLQuery::SimpleSPARQLQuery(QueryType type, QString query) :
|
Chris@489
|
222 m_impl(new Impl(type, query))
|
Chris@480
|
223 {
|
Chris@480
|
224 }
|
Chris@439
|
225
|
Chris@439
|
226 SimpleSPARQLQuery::~SimpleSPARQLQuery()
|
Chris@439
|
227 {
|
Chris@439
|
228 delete m_impl;
|
Chris@439
|
229 }
|
Chris@439
|
230
|
Chris@439
|
231 void
|
Chris@439
|
232 SimpleSPARQLQuery::setProgressReporter(ProgressReporter *reporter)
|
Chris@439
|
233 {
|
Chris@439
|
234 m_impl->setProgressReporter(reporter);
|
Chris@439
|
235 }
|
Chris@439
|
236
|
Chris@439
|
237 bool
|
Chris@439
|
238 SimpleSPARQLQuery::wasCancelled() const
|
Chris@439
|
239 {
|
Chris@439
|
240 return m_impl->wasCancelled();
|
Chris@439
|
241 }
|
Chris@439
|
242
|
Chris@439
|
243 SimpleSPARQLQuery::ResultList
|
Chris@439
|
244 SimpleSPARQLQuery::execute()
|
Chris@439
|
245 {
|
Chris@439
|
246 return m_impl->execute();
|
Chris@439
|
247 }
|
Chris@439
|
248
|
Chris@439
|
249 bool
|
Chris@439
|
250 SimpleSPARQLQuery::isOK() const
|
Chris@439
|
251 {
|
Chris@439
|
252 return m_impl->isOK();
|
Chris@439
|
253 }
|
Chris@439
|
254
|
Chris@439
|
255 QString
|
Chris@439
|
256 SimpleSPARQLQuery::getErrorString() const
|
Chris@439
|
257 {
|
Chris@439
|
258 return m_impl->getErrorString();
|
Chris@439
|
259 }
|
Chris@439
|
260
|
Chris@489
|
261 bool
|
Chris@489
|
262 SimpleSPARQLQuery::addSourceToModel(QString sourceUri)
|
Chris@480
|
263 {
|
Chris@489
|
264 return SimpleSPARQLQuery::Impl::addSourceToModel(sourceUri);
|
Chris@480
|
265 }
|
Chris@480
|
266
|
Chris@489
|
267 SimpleSPARQLQuery::Impl::Impl(QueryType type, QString query) :
|
Chris@489
|
268 m_type(type),
|
Chris@439
|
269 m_query(query),
|
Chris@439
|
270 m_reporter(0),
|
Chris@439
|
271 m_cancelled(false)
|
Chris@439
|
272 {
|
Chris@461
|
273 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
|
Chris@461
|
274 std::cerr << "SimpleSPARQLQuery::Impl: Query is: \"" << query.toStdString() << "\"" << std::endl;
|
Chris@461
|
275 #endif
|
Chris@439
|
276 }
|
Chris@439
|
277
|
Chris@439
|
278 SimpleSPARQLQuery::Impl::~Impl()
|
Chris@439
|
279 {
|
Chris@439
|
280 }
|
Chris@439
|
281
|
Chris@439
|
282 bool
|
Chris@439
|
283 SimpleSPARQLQuery::Impl::isOK() const
|
Chris@439
|
284 {
|
Chris@439
|
285 return (m_errorString == "");
|
Chris@439
|
286 }
|
Chris@439
|
287
|
Chris@439
|
288 QString
|
Chris@439
|
289 SimpleSPARQLQuery::Impl::getErrorString() const
|
Chris@439
|
290 {
|
Chris@439
|
291 return m_errorString;
|
Chris@439
|
292 }
|
Chris@439
|
293
|
Chris@439
|
294 void
|
Chris@439
|
295 SimpleSPARQLQuery::Impl::errorHandler(void *data,
|
Chris@439
|
296 raptor_locator *locator,
|
Chris@439
|
297 const char *message)
|
Chris@439
|
298 {
|
Chris@439
|
299 SimpleSPARQLQuery::Impl *impl = (SimpleSPARQLQuery::Impl *)data;
|
Chris@439
|
300
|
Chris@481
|
301 char buffer[256];
|
Chris@481
|
302 raptor_format_locator(buffer, 255, locator);
|
Chris@481
|
303 QString loc(buffer);
|
Chris@481
|
304 if (loc != "") {
|
Chris@481
|
305 impl->m_errorString = QString("%1 - %2").arg(loc).arg(message);
|
Chris@481
|
306 } else {
|
Chris@481
|
307 impl->m_errorString = message;
|
Chris@481
|
308 }
|
Chris@439
|
309
|
Chris@439
|
310 cerr << "SimpleSPARQLQuery: ERROR: " << impl->m_errorString.toStdString() << endl;
|
Chris@439
|
311 }
|
Chris@439
|
312
|
Chris@439
|
313 SimpleSPARQLQuery::ResultList
|
Chris@439
|
314 SimpleSPARQLQuery::Impl::execute()
|
Chris@439
|
315 {
|
Chris@439
|
316 ResultList list;
|
Chris@439
|
317
|
Chris@480
|
318 m_mutex.lock();
|
Chris@480
|
319
|
Chris@489
|
320 if (m_type == QueryFromModel) {
|
Chris@489
|
321 if (!m_redland) {
|
Chris@489
|
322 // There can be no results, because no sources have been
|
Chris@489
|
323 // added to the model yet (m_redland is only created when
|
Chris@489
|
324 // addSourceToModel is called)
|
Chris@489
|
325 cerr << "SimpleSPARQLQuery::execute: NOTE: No sources have been added to data model yet, so no results are possible" << endl;
|
Chris@489
|
326 m_mutex.unlock();
|
Chris@489
|
327 return list;
|
Chris@481
|
328 }
|
Chris@481
|
329 }
|
Chris@481
|
330
|
Chris@489
|
331 if (m_type == QueryFromSingleSource) {
|
Chris@489
|
332 #ifdef USE_NEW_RASQAL_API
|
Chris@489
|
333 if (!m_rasqal) {
|
Chris@489
|
334 m_rasqal = new WrasqalWorldWrapper();
|
Chris@489
|
335 if (!m_rasqal->isOK()) {
|
Chris@489
|
336 cerr << "ERROR: SimpleSPARQLQuery::execute: Failed to initialise Rasqal query engine" << endl;
|
Chris@489
|
337 delete m_rasqal;
|
Chris@489
|
338 m_rasqal = 0;
|
Chris@489
|
339 m_mutex.unlock();
|
Chris@489
|
340 return list;
|
Chris@480
|
341 }
|
Chris@480
|
342 }
|
Chris@480
|
343 #else
|
Chris@480
|
344 if (!m_rasqalInitialised) {
|
Chris@480
|
345 rasqal_init();
|
Chris@480
|
346 m_rasqalInitialised = true;
|
Chris@480
|
347 }
|
Chris@480
|
348 #endif
|
Chris@440
|
349 }
|
Chris@480
|
350
|
Chris@480
|
351 m_mutex.unlock();
|
Chris@480
|
352
|
Chris@489
|
353 if (m_type == QueryFromSingleSource) {
|
Chris@480
|
354 return executeDirectParser();
|
Chris@480
|
355 } else {
|
Chris@480
|
356 return executeDatastore();
|
Chris@480
|
357 }
|
Chris@480
|
358 }
|
Chris@480
|
359
|
Chris@480
|
360 SimpleSPARQLQuery::ResultList
|
Chris@480
|
361 SimpleSPARQLQuery::Impl::executeDirectParser()
|
Chris@480
|
362 {
|
Chris@480
|
363 ResultList list;
|
Chris@480
|
364
|
Chris@480
|
365 Profiler profiler("SimpleSPARQLQuery::executeDirectParser");
|
Chris@480
|
366
|
Chris@480
|
367 #ifdef USE_NEW_RASQAL_API
|
Chris@480
|
368 rasqal_query *query = rasqal_new_query(m_rasqal->getWorld(), "sparql", NULL);
|
Chris@480
|
369 #else
|
Chris@439
|
370 rasqal_query *query = rasqal_new_query("sparql", NULL);
|
Chris@440
|
371 #endif
|
Chris@439
|
372 if (!query) {
|
Chris@439
|
373 m_errorString = "Failed to construct query";
|
Chris@439
|
374 cerr << "SimpleSPARQLQuery: ERROR: " << m_errorString.toStdString() << endl;
|
Chris@439
|
375 return list;
|
Chris@439
|
376 }
|
Chris@439
|
377
|
Chris@439
|
378 rasqal_query_set_error_handler(query, this, errorHandler);
|
Chris@439
|
379 rasqal_query_set_fatal_error_handler(query, this, errorHandler);
|
Chris@439
|
380
|
Chris@480
|
381 {
|
Chris@480
|
382 Profiler p("SimpleSPARQLQuery: Prepare RASQAL query");
|
Chris@480
|
383
|
Chris@480
|
384 if (rasqal_query_prepare
|
Chris@480
|
385 (query, (const unsigned char *)m_query.toUtf8().data(), NULL)) {
|
Chris@480
|
386 cerr << "SimpleSPARQLQuery: Failed to prepare query" << endl;
|
Chris@480
|
387 rasqal_free_query(query);
|
Chris@480
|
388 return list;
|
Chris@480
|
389 }
|
Chris@439
|
390 }
|
Chris@439
|
391
|
Chris@480
|
392 rasqal_query_results *results;
|
Chris@480
|
393
|
Chris@480
|
394 {
|
Chris@480
|
395 Profiler p("SimpleSPARQLQuery: Execute RASQAL query");
|
Chris@480
|
396 results = rasqal_query_execute(query);
|
Chris@480
|
397 }
|
Chris@439
|
398
|
Chris@439
|
399 // cerr << "Query executed" << endl;
|
Chris@439
|
400
|
Chris@439
|
401 if (!results) {
|
Chris@439
|
402 cerr << "SimpleSPARQLQuery: RASQAL query failed" << endl;
|
Chris@439
|
403 rasqal_free_query(query);
|
Chris@439
|
404 return list;
|
Chris@439
|
405 }
|
Chris@439
|
406
|
Chris@439
|
407 if (!rasqal_query_results_is_bindings(results)) {
|
Chris@439
|
408 cerr << "SimpleSPARQLQuery: RASQAL query has wrong result type (not bindings)" << endl;
|
Chris@439
|
409 rasqal_free_query_results(results);
|
Chris@439
|
410 rasqal_free_query(query);
|
Chris@439
|
411 return list;
|
Chris@439
|
412 }
|
Chris@439
|
413
|
Chris@439
|
414 int resultCount = 0;
|
Chris@439
|
415 int resultTotal = rasqal_query_results_get_count(results); // probably wrong
|
Chris@439
|
416 m_cancelled = false;
|
Chris@439
|
417
|
Chris@439
|
418 while (!rasqal_query_results_finished(results)) {
|
Chris@439
|
419
|
Chris@439
|
420 int count = rasqal_query_results_get_bindings_count(results);
|
Chris@439
|
421
|
Chris@439
|
422 KeyValueMap resultmap;
|
Chris@439
|
423
|
Chris@439
|
424 for (int i = 0; i < count; ++i) {
|
Chris@439
|
425
|
Chris@439
|
426 const unsigned char *name =
|
Chris@439
|
427 rasqal_query_results_get_binding_name(results, i);
|
Chris@439
|
428
|
Chris@439
|
429 rasqal_literal *literal =
|
Chris@439
|
430 rasqal_query_results_get_binding_value(results, i);
|
Chris@439
|
431
|
Chris@439
|
432 QString key = (const char *)name;
|
Chris@439
|
433
|
Chris@439
|
434 if (!literal) {
|
Chris@439
|
435 resultmap[key] = Value();
|
Chris@439
|
436 continue;
|
Chris@439
|
437 }
|
Chris@439
|
438
|
Chris@439
|
439 ValueType type = LiteralValue;
|
Chris@439
|
440 if (literal->type == RASQAL_LITERAL_URI) type = URIValue;
|
Chris@439
|
441 else if (literal->type == RASQAL_LITERAL_BLANK) type = BlankValue;
|
Chris@439
|
442
|
Chris@439
|
443 QString text = (const char *)rasqal_literal_as_string(literal);
|
Chris@439
|
444
|
Chris@461
|
445 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
|
Chris@449
|
446 std::cerr << i << ". " << key.toStdString() << " -> " << text.toStdString() << " (type " << type << ")" << std::endl;
|
Chris@461
|
447 #endif
|
Chris@449
|
448
|
Chris@439
|
449 resultmap[key] = Value(type, text);
|
Chris@439
|
450 }
|
Chris@439
|
451
|
Chris@439
|
452 list.push_back(resultmap);
|
Chris@439
|
453
|
Chris@439
|
454 rasqal_query_results_next(results);
|
Chris@439
|
455
|
Chris@439
|
456 resultCount++;
|
Chris@439
|
457
|
Chris@439
|
458 if (m_reporter) {
|
Chris@439
|
459 if (resultCount >= resultTotal) {
|
Chris@439
|
460 if (m_reporter->isDefinite()) m_reporter->setDefinite(false);
|
Chris@439
|
461 m_reporter->setProgress(resultCount);
|
Chris@439
|
462 } else {
|
Chris@439
|
463 m_reporter->setProgress((resultCount * 100) / resultTotal);
|
Chris@439
|
464 }
|
Chris@439
|
465
|
Chris@439
|
466 if (m_reporter->wasCancelled()) {
|
Chris@439
|
467 m_cancelled = true;
|
Chris@439
|
468 break;
|
Chris@439
|
469 }
|
Chris@439
|
470 }
|
Chris@439
|
471 }
|
Chris@439
|
472
|
Chris@439
|
473 rasqal_free_query_results(results);
|
Chris@439
|
474 rasqal_free_query(query);
|
Chris@439
|
475
|
Chris@439
|
476 return list;
|
Chris@439
|
477 }
|
Chris@440
|
478
|
Chris@480
|
479 SimpleSPARQLQuery::ResultList
|
Chris@480
|
480 SimpleSPARQLQuery::Impl::executeDatastore()
|
Chris@480
|
481 {
|
Chris@480
|
482 ResultList list;
|
Chris@489
|
483
|
Chris@480
|
484 Profiler profiler("SimpleSPARQLQuery::executeDatastore");
|
Chris@480
|
485
|
Chris@481
|
486 /*!!!
|
Chris@480
|
487 static std::map<QString, int> counter;
|
Chris@480
|
488 if (counter.find(m_query) == counter.end()) counter[m_query] = 1;
|
Chris@480
|
489 else ++counter[m_query];
|
Chris@480
|
490 std::cerr << "Counter for this query: " << counter[m_query] << std::endl;
|
Chris@481
|
491 std::cerr << "Base URI is: \"" << m_fromUri.toStdString() << "\"" << std::endl;
|
Chris@481
|
492 */
|
Chris@480
|
493
|
Chris@480
|
494 librdf_query *query;
|
Chris@480
|
495
|
Chris@480
|
496 {
|
Chris@480
|
497 Profiler p("SimpleSPARQLQuery: Prepare LIBRDF query");
|
Chris@480
|
498 query = librdf_new_query
|
Chris@480
|
499 (m_redland->getWorld(), "sparql", NULL,
|
Chris@489
|
500 (const unsigned char *)m_query.toUtf8().data(), NULL);
|
Chris@480
|
501 }
|
Chris@480
|
502
|
Chris@480
|
503 if (!query) {
|
Chris@480
|
504 m_errorString = "Failed to construct query";
|
Chris@480
|
505 return list;
|
Chris@480
|
506 }
|
Chris@480
|
507
|
Chris@480
|
508 librdf_query_results *results;
|
Chris@480
|
509 {
|
Chris@480
|
510 Profiler p("SimpleSPARQLQuery: Execute LIBRDF query");
|
Chris@480
|
511 results = librdf_query_execute(query, m_redland->getModel());
|
Chris@480
|
512 }
|
Chris@480
|
513
|
Chris@480
|
514 if (!results) {
|
Chris@480
|
515 cerr << "SimpleSPARQLQuery: LIBRDF query failed" << endl;
|
Chris@480
|
516 librdf_free_query(query);
|
Chris@480
|
517 return list;
|
Chris@480
|
518 }
|
Chris@480
|
519
|
Chris@480
|
520 if (!librdf_query_results_is_bindings(results)) {
|
Chris@480
|
521 cerr << "SimpleSPARQLQuery: LIBRDF query has wrong result type (not bindings)" << endl;
|
Chris@480
|
522 librdf_free_query_results(results);
|
Chris@480
|
523 librdf_free_query(query);
|
Chris@480
|
524 return list;
|
Chris@480
|
525 }
|
Chris@480
|
526
|
Chris@480
|
527 int resultCount = 0;
|
Chris@480
|
528 int resultTotal = librdf_query_results_get_count(results); // probably wrong
|
Chris@480
|
529 m_cancelled = false;
|
Chris@480
|
530
|
Chris@480
|
531 while (!librdf_query_results_finished(results)) {
|
Chris@480
|
532
|
Chris@480
|
533 int count = librdf_query_results_get_bindings_count(results);
|
Chris@480
|
534
|
Chris@480
|
535 KeyValueMap resultmap;
|
Chris@480
|
536
|
Chris@480
|
537 for (int i = 0; i < count; ++i) {
|
Chris@480
|
538
|
Chris@480
|
539 const char *name =
|
Chris@480
|
540 librdf_query_results_get_binding_name(results, i);
|
Chris@480
|
541
|
Chris@480
|
542 librdf_node *node =
|
Chris@480
|
543 librdf_query_results_get_binding_value(results, i);
|
Chris@480
|
544
|
Chris@480
|
545 QString key = (const char *)name;
|
Chris@480
|
546
|
Chris@480
|
547 if (!node) {
|
Chris@480
|
548 resultmap[key] = Value();
|
Chris@480
|
549 continue;
|
Chris@480
|
550 }
|
Chris@480
|
551
|
Chris@480
|
552 ValueType type = LiteralValue;
|
Chris@481
|
553 QString text;
|
Chris@481
|
554
|
Chris@481
|
555 if (librdf_node_is_resource(node)) {
|
Chris@481
|
556
|
Chris@481
|
557 type = URIValue;
|
Chris@481
|
558 librdf_uri *uri = librdf_node_get_uri(node);
|
Chris@481
|
559 text = (const char *)librdf_uri_as_string(uri);
|
Chris@481
|
560
|
Chris@481
|
561 } else if (librdf_node_is_literal(node)) {
|
Chris@481
|
562
|
Chris@481
|
563 type = LiteralValue;
|
Chris@481
|
564 text = (const char *)librdf_node_get_literal_value(node);
|
Chris@481
|
565
|
Chris@481
|
566 } else if (librdf_node_is_blank(node)) {
|
Chris@481
|
567
|
Chris@481
|
568 type = BlankValue;
|
Chris@481
|
569
|
Chris@481
|
570 } else {
|
Chris@481
|
571
|
Chris@480
|
572 cerr << "SimpleSPARQLQuery: LIBRDF query returned unknown node type (not resource, literal, or blank)" << endl;
|
Chris@480
|
573 }
|
Chris@480
|
574
|
Chris@480
|
575 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
|
Chris@481
|
576 cerr << i << ". " << key.toStdString() << " -> " << text.toStdString() << " (type " << type << ")" << endl;
|
Chris@480
|
577 #endif
|
Chris@480
|
578
|
Chris@480
|
579 resultmap[key] = Value(type, text);
|
Chris@480
|
580
|
Chris@480
|
581 librdf_free_node(node);
|
Chris@480
|
582 }
|
Chris@480
|
583
|
Chris@480
|
584 list.push_back(resultmap);
|
Chris@480
|
585
|
Chris@480
|
586 librdf_query_results_next(results);
|
Chris@480
|
587
|
Chris@480
|
588 resultCount++;
|
Chris@480
|
589
|
Chris@480
|
590 if (m_reporter) {
|
Chris@480
|
591 if (resultCount >= resultTotal) {
|
Chris@480
|
592 if (m_reporter->isDefinite()) m_reporter->setDefinite(false);
|
Chris@480
|
593 m_reporter->setProgress(resultCount);
|
Chris@480
|
594 } else {
|
Chris@480
|
595 m_reporter->setProgress((resultCount * 100) / resultTotal);
|
Chris@480
|
596 }
|
Chris@480
|
597
|
Chris@480
|
598 if (m_reporter->wasCancelled()) {
|
Chris@480
|
599 m_cancelled = true;
|
Chris@480
|
600 break;
|
Chris@480
|
601 }
|
Chris@480
|
602 }
|
Chris@480
|
603 }
|
Chris@480
|
604
|
Chris@480
|
605 librdf_free_query_results(results);
|
Chris@480
|
606 librdf_free_query(query);
|
Chris@480
|
607
|
Chris@481
|
608 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
|
Chris@481
|
609 cerr << "All results retrieved (" << resultCount << " of them)" << endl;
|
Chris@481
|
610 #endif
|
Chris@480
|
611
|
Chris@480
|
612 return list;
|
Chris@489
|
613 }
|
Chris@489
|
614
|
Chris@489
|
615 bool
|
Chris@489
|
616 SimpleSPARQLQuery::Impl::addSourceToModel(QString sourceUri)
|
Chris@489
|
617 {
|
Chris@489
|
618 QString err;
|
Chris@489
|
619
|
Chris@489
|
620 m_mutex.lock();
|
Chris@489
|
621
|
Chris@489
|
622 if (!m_redland) {
|
Chris@489
|
623 m_redland = new WredlandWorldWrapper();
|
Chris@489
|
624 if (!m_redland->isOK()) {
|
Chris@489
|
625 cerr << "ERROR: SimpleSPARQLQuery::addSourceToModel: Failed to initialise Redland datastore" << endl;
|
Chris@489
|
626 delete m_redland;
|
Chris@489
|
627 m_redland = 0;
|
Chris@489
|
628 m_mutex.unlock();
|
Chris@489
|
629 return false;
|
Chris@489
|
630 }
|
Chris@489
|
631 }
|
Chris@489
|
632
|
Chris@489
|
633 m_mutex.unlock();
|
Chris@489
|
634
|
Chris@489
|
635 librdf_uri *uri = m_redland->getUri(sourceUri, err);
|
Chris@489
|
636
|
Chris@489
|
637 if (!uri) {
|
Chris@489
|
638 std::cerr << "SimpleSPARQLQuery::addSourceToModel: Failed to add source URI \"" << sourceUri.toStdString() << ": " << err.toStdString() << std::endl;
|
Chris@489
|
639 return false;
|
Chris@489
|
640 }
|
Chris@489
|
641 return true;
|
Chris@480
|
642 }
|
Chris@480
|
643
|
Chris@440
|
644 SimpleSPARQLQuery::Value
|
Chris@489
|
645 SimpleSPARQLQuery::singleResultQuery(QueryType type,
|
Chris@480
|
646 QString query, QString binding)
|
Chris@440
|
647 {
|
Chris@489
|
648 SimpleSPARQLQuery q(type, query);
|
Chris@440
|
649 ResultList results = q.execute();
|
Chris@440
|
650 if (!q.isOK()) {
|
Chris@440
|
651 cerr << "SimpleSPARQLQuery::singleResultQuery: ERROR: "
|
Chris@440
|
652 << q.getErrorString().toStdString() << endl;
|
Chris@440
|
653 return Value();
|
Chris@440
|
654 }
|
Chris@440
|
655 if (results.empty()) {
|
Chris@440
|
656 return Value();
|
Chris@440
|
657 }
|
Chris@440
|
658 for (int i = 0; i < results.size(); ++i) {
|
Chris@440
|
659 if (results[i].find(binding) != results[i].end() &&
|
Chris@440
|
660 results[i][binding].type != NoValue) {
|
Chris@440
|
661 return results[i][binding];
|
Chris@440
|
662 }
|
Chris@440
|
663 }
|
Chris@440
|
664 return Value();
|
Chris@440
|
665 }
|
Chris@440
|
666
|
Chris@440
|
667
|
Chris@440
|
668
|