annotate rdf/SimpleSPARQLQuery.cpp @ 489:82ab61fa9223

* Reorganise our sparql queries on the basis that Redland must be available, not only optional. So for anything querying the pool of data about plugins, we use a single datastore and model which is initialised at the outset by PluginRDFIndexer and then queried directly; for anything that "reads from a file" (e.g. loading annotations) we query directly using Rasqal, going to the datastore when we need additional plugin-related information. This may improve performance, but mostly it simplifies the code and fixes a serious issue with RDF import in the previous versions (namely that multiple sequential RDF imports would end up sharing the same RDF data pool!)
author Chris Cannam
date Fri, 21 Nov 2008 16:12:29 +0000
parents a82645e788fc
children c3fb8258e34d
rev   line source
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