| 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@644 | 26 // Rather than including <redland.h> -- for some reason redland.h | 
| Chris@644 | 27 // includes <rasqal.h>, while the rasqal header actually gets | 
| Chris@644 | 28 // installed as <rasqal/rasqal.h> which breaks the inclusion all over | 
| Chris@644 | 29 // the place unless a very clever include path is set | 
| Chris@644 | 30 #include <raptor.h> | 
| Chris@644 | 31 #include <rasqal/rasqal.h> | 
| Chris@644 | 32 #include <librdf.h> | 
| Chris@480 | 33 | 
| Chris@492 | 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@480 | 41 class WredlandWorldWrapper | 
| Chris@480 | 42 { | 
| Chris@480 | 43 public: | 
| Chris@492 | 44     WredlandWorldWrapper(); | 
| Chris@492 | 45     ~WredlandWorldWrapper(); | 
| Chris@480 | 46 | 
| Chris@492 | 47     bool isOK() const; | 
| Chris@480 | 48 | 
| Chris@492 | 49     bool loadUriIntoDefaultModel(QString uriString, QString &errorString); | 
| Chris@480 | 50 | 
| Chris@480 | 51     librdf_world *getWorld() { return m_world; } | 
| Chris@480 | 52     const librdf_world *getWorld() const { return m_world; } | 
| Chris@480 | 53 | 
| Chris@492 | 54     librdf_model *getDefaultModel() { return m_defaultModel; } | 
| Chris@492 | 55     const librdf_model *getDefaultModel() const { return m_defaultModel; } | 
| Chris@492 | 56 | 
| Chris@492 | 57     librdf_model *getModel(QString fromUri); | 
| Chris@492 | 58     void freeModel(QString forUri); | 
| Chris@480 | 59 | 
| Chris@480 | 60 private: | 
| Chris@492 | 61     QMutex m_mutex; | 
| Chris@492 | 62 | 
| Chris@480 | 63     librdf_world *m_world; | 
| Chris@492 | 64     librdf_storage *m_defaultStorage; | 
| Chris@492 | 65     librdf_model *m_defaultModel; | 
| Chris@480 | 66 | 
| Chris@492 | 67     std::set<QString> m_defaultModelUris; | 
| Chris@492 | 68 | 
| Chris@492 | 69     std::map<QString, librdf_storage *> m_ownStorageUris; | 
| Chris@492 | 70     std::map<QString, librdf_model *> m_ownModelUris; | 
| Chris@492 | 71 | 
| Chris@492 | 72     bool loadUri(librdf_model *model, QString uri, QString &errorString); | 
| Chris@480 | 73 }; | 
| Chris@480 | 74 | 
| Chris@492 | 75 WredlandWorldWrapper::WredlandWorldWrapper() : | 
| Chris@492 | 76     m_world(0), m_defaultStorage(0), m_defaultModel(0) | 
| Chris@492 | 77 { | 
| Chris@492 | 78     m_world = librdf_new_world(); | 
| Chris@492 | 79     if (!m_world) { | 
| Chris@492 | 80         cerr << "SimpleSPARQLQuery: ERROR: Failed to create LIBRDF world!" << endl; | 
| Chris@492 | 81         return; | 
| Chris@492 | 82     } | 
| Chris@492 | 83     librdf_world_open(m_world); | 
| Chris@492 | 84 | 
| Chris@492 | 85     m_defaultStorage = librdf_new_storage(m_world, "trees", NULL, NULL); | 
| Chris@492 | 86     if (!m_defaultStorage) { | 
| Chris@495 | 87         std::cerr << "SimpleSPARQLQuery: WARNING: Failed to initialise Redland trees datastore, falling back to memory store" << std::endl; | 
| Chris@492 | 88         m_defaultStorage = librdf_new_storage(m_world, NULL, NULL, NULL); | 
| Chris@492 | 89         if (!m_defaultStorage) { | 
| Chris@492 | 90             std::cerr << "SimpleSPARQLQuery: ERROR: Failed to initialise Redland memory datastore" << std::endl; | 
| Chris@492 | 91             return; | 
| Chris@492 | 92         } | 
| Chris@492 | 93     } | 
| Chris@492 | 94     m_defaultModel = librdf_new_model(m_world, m_defaultStorage, NULL); | 
| Chris@492 | 95     if (!m_defaultModel) { | 
| Chris@492 | 96         std::cerr << "SimpleSPARQLQuery: ERROR: Failed to initialise Redland data model" << std::endl; | 
| Chris@492 | 97         return; | 
| Chris@492 | 98     } | 
| Chris@492 | 99 } | 
| Chris@492 | 100 | 
| Chris@492 | 101 WredlandWorldWrapper::~WredlandWorldWrapper() | 
| Chris@492 | 102 { | 
| Chris@505 | 103 /*!!! This is a static singleton; destroying it while there are | 
| Chris@505 | 104       queries outstanding can be problematic, it appears, and since | 
| Chris@505 | 105       the storage is non-persistent there shouldn't be any need to | 
| Chris@505 | 106       destroy it explicitly, except for the sake of tidiness. | 
| Chris@505 | 107 | 
| Chris@492 | 108     while (!m_ownModelUris.empty()) { | 
| Chris@492 | 109         librdf_free_model(m_ownModelUris.begin()->second); | 
| Chris@492 | 110         m_ownModelUris.erase(m_ownModelUris.begin()); | 
| Chris@492 | 111     } | 
| Chris@492 | 112     while (!m_ownStorageUris.empty()) { | 
| Chris@492 | 113         librdf_free_storage(m_ownStorageUris.begin()->second); | 
| Chris@492 | 114         m_ownStorageUris.erase(m_ownStorageUris.begin()); | 
| Chris@492 | 115     } | 
| Chris@492 | 116     if (m_defaultModel) librdf_free_model(m_defaultModel); | 
| Chris@492 | 117     if (m_defaultStorage) librdf_free_storage(m_defaultStorage); | 
| Chris@492 | 118     if (m_world) librdf_free_world(m_world); | 
| Chris@505 | 119 */ | 
| Chris@492 | 120 } | 
| Chris@492 | 121 | 
| Chris@492 | 122 bool | 
| Chris@492 | 123 WredlandWorldWrapper::isOK() const { | 
| Chris@492 | 124     return (m_defaultModel != 0); | 
| Chris@492 | 125 } | 
| Chris@492 | 126 | 
| Chris@492 | 127 bool | 
| Chris@492 | 128 WredlandWorldWrapper::loadUriIntoDefaultModel(QString uriString, QString &errorString) | 
| Chris@492 | 129 { | 
| Chris@492 | 130     QMutexLocker locker(&m_mutex); | 
| Chris@492 | 131 | 
| Chris@492 | 132     if (m_defaultModelUris.find(uriString) != m_defaultModelUris.end()) { | 
| Chris@492 | 133         return true; | 
| Chris@492 | 134     } | 
| Chris@492 | 135 | 
| Chris@492 | 136     if (loadUri(m_defaultModel, uriString, errorString)) { | 
| Chris@492 | 137         m_defaultModelUris.insert(uriString); | 
| Chris@492 | 138         return true; | 
| Chris@492 | 139     } else { | 
| Chris@492 | 140         return false; | 
| Chris@492 | 141     } | 
| Chris@492 | 142 } | 
| Chris@492 | 143 | 
| Chris@492 | 144 librdf_model * | 
| Chris@492 | 145 WredlandWorldWrapper::getModel(QString fromUri) | 
| Chris@492 | 146 { | 
| Chris@492 | 147     QMutexLocker locker(&m_mutex); | 
| Chris@492 | 148     if (fromUri == "") { | 
| Chris@492 | 149         return getDefaultModel(); | 
| Chris@492 | 150     } | 
| Chris@492 | 151     if (m_ownModelUris.find(fromUri) != m_ownModelUris.end()) { | 
| Chris@492 | 152         return m_ownModelUris[fromUri]; | 
| Chris@492 | 153     } | 
| Chris@492 | 154     librdf_storage *storage = librdf_new_storage(m_world, "trees", NULL, NULL); | 
| Chris@492 | 155     if (!storage) { // don't warn here, we probably already did it in main ctor | 
| Chris@492 | 156         storage = librdf_new_storage(m_world, NULL, NULL, NULL); | 
| Chris@492 | 157     } | 
| Chris@492 | 158     librdf_model *model = librdf_new_model(m_world, storage, NULL); | 
| Chris@492 | 159     if (!model) { | 
| Chris@492 | 160         std::cerr << "SimpleSPARQLQuery: ERROR: Failed to create new model" << std::endl; | 
| Chris@492 | 161         librdf_free_storage(storage); | 
| Chris@492 | 162         return 0; | 
| Chris@492 | 163     } | 
| Chris@492 | 164     QString err; | 
| Chris@492 | 165     if (!loadUri(model, fromUri, err)) { | 
| Chris@686 | 166         std::cerr << "SimpleSPARQLQuery: ERROR: Failed to parse into new model: " << err << std::endl; | 
| Chris@492 | 167         librdf_free_model(model); | 
| Chris@492 | 168         librdf_free_storage(storage); | 
| Chris@492 | 169         m_ownModelUris[fromUri] = 0; | 
| Chris@492 | 170         return 0; | 
| Chris@492 | 171     } | 
| Chris@492 | 172     m_ownModelUris[fromUri] = model; | 
| Chris@492 | 173     m_ownStorageUris[fromUri] = storage; | 
| Chris@492 | 174     return model; | 
| Chris@492 | 175 } | 
| Chris@492 | 176 | 
| Chris@492 | 177 void | 
| Chris@492 | 178 WredlandWorldWrapper::freeModel(QString forUri) | 
| Chris@492 | 179 { | 
| Chris@493 | 180 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@690 | 181     SVDEBUG << "SimpleSPARQLQuery::freeModel: Model uri = \"" << forUri << "\"" << endl; | 
| Chris@493 | 182 #endif | 
| Chris@493 | 183 | 
| Chris@492 | 184     QMutexLocker locker(&m_mutex); | 
| Chris@492 | 185     if (forUri == "") { | 
| Chris@690 | 186         SVDEBUG << "SimpleSPARQLQuery::freeModel: ERROR: Can't free default model" << endl; | 
| Chris@492 | 187         return; | 
| Chris@492 | 188     } | 
| Chris@492 | 189     if (m_ownModelUris.find(forUri) == m_ownModelUris.end()) { | 
| Chris@493 | 190 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@690 | 191         SVDEBUG << "SimpleSPARQLQuery::freeModel: NOTE: Unknown or already-freed model (uri = \"" << forUri << "\")" << endl; | 
| Chris@493 | 192 #endif | 
| Chris@492 | 193         return; | 
| Chris@492 | 194     } | 
| Chris@492 | 195 | 
| Chris@492 | 196     librdf_model *model = m_ownModelUris[forUri]; | 
| Chris@492 | 197     if (model) librdf_free_model(model); | 
| Chris@492 | 198     m_ownModelUris.erase(forUri); | 
| Chris@492 | 199 | 
| Chris@492 | 200     if (m_ownStorageUris.find(forUri) != m_ownStorageUris.end()) { | 
| Chris@492 | 201         librdf_storage *storage = m_ownStorageUris[forUri]; | 
| Chris@492 | 202         if (storage) librdf_free_storage(storage); | 
| Chris@492 | 203         m_ownStorageUris.erase(forUri); | 
| Chris@492 | 204     } | 
| Chris@492 | 205 } | 
| Chris@492 | 206 | 
| Chris@492 | 207 bool | 
| Chris@492 | 208 WredlandWorldWrapper::loadUri(librdf_model *model, QString uri, QString &errorString) | 
| Chris@492 | 209 { | 
| Chris@492 | 210     librdf_uri *luri = librdf_new_uri | 
| Chris@492 | 211         (m_world, (const unsigned char *)uri.toUtf8().data()); | 
| Chris@492 | 212     if (!luri) { | 
| Chris@492 | 213         errorString = "Failed to construct librdf_uri!"; | 
| Chris@492 | 214         return false; | 
| Chris@492 | 215     } | 
| Chris@492 | 216 | 
| Chris@492 | 217     librdf_parser *parser = librdf_new_parser(m_world, "guess", NULL, NULL); | 
| Chris@492 | 218     if (!parser) { | 
| Chris@492 | 219         errorString = "Failed to initialise Redland parser"; | 
| Chris@492 | 220         return false; | 
| Chris@492 | 221     } | 
| Chris@507 | 222 | 
| Chris@507 | 223 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@686 | 224     std::cerr << "About to parse \"" << uri << "\"" << std::endl; | 
| Chris@507 | 225 #endif | 
| Chris@492 | 226 | 
| Chris@492 | 227     Profiler p("SimpleSPARQLQuery: Parse URI into LIBRDF model"); | 
| Chris@492 | 228 | 
| Chris@492 | 229     if (librdf_parser_parse_into_model(parser, luri, NULL, model)) { | 
| Chris@492 | 230 | 
| Chris@492 | 231         errorString = QString("Failed to parse RDF from URI \"%1\"") | 
| Chris@492 | 232             .arg(uri); | 
| Chris@492 | 233         librdf_free_parser(parser); | 
| Chris@492 | 234         return false; | 
| Chris@492 | 235 | 
| Chris@492 | 236     } else { | 
| Chris@492 | 237 | 
| Chris@492 | 238         librdf_free_parser(parser); | 
| Chris@492 | 239         return true; | 
| Chris@492 | 240     } | 
| Chris@492 | 241 } | 
| Chris@492 | 242 | 
| Chris@492 | 243 | 
| Chris@439 | 244 class SimpleSPARQLQuery::Impl | 
| Chris@439 | 245 { | 
| Chris@439 | 246 public: | 
| Chris@489 | 247     Impl(SimpleSPARQLQuery::QueryType, QString query); | 
| Chris@439 | 248     ~Impl(); | 
| Chris@439 | 249 | 
| Chris@489 | 250     static bool addSourceToModel(QString sourceUri); | 
| Chris@492 | 251     static void closeSingleSource(QString sourceUri); | 
| Chris@489 | 252 | 
| Chris@439 | 253     void setProgressReporter(ProgressReporter *reporter) { m_reporter = reporter; } | 
| Chris@439 | 254     bool wasCancelled() const { return m_cancelled; } | 
| Chris@439 | 255 | 
| Chris@439 | 256     ResultList execute(); | 
| Chris@439 | 257 | 
| Chris@439 | 258     bool isOK() const; | 
| Chris@439 | 259     QString getErrorString() const; | 
| Chris@439 | 260 | 
| Chris@439 | 261 protected: | 
| Chris@480 | 262     static QMutex m_mutex; | 
| Chris@480 | 263 | 
| Chris@526 | 264     static WredlandWorldWrapper *m_redland; | 
| Chris@480 | 265 | 
| Chris@480 | 266     ResultList executeDirectParser(); | 
| Chris@480 | 267     ResultList executeDatastore(); | 
| Chris@492 | 268     ResultList executeFor(QString modelUri); | 
| Chris@480 | 269 | 
| Chris@489 | 270     QueryType m_type; | 
| Chris@439 | 271     QString m_query; | 
| Chris@439 | 272     QString m_errorString; | 
| Chris@439 | 273     ProgressReporter *m_reporter; | 
| Chris@439 | 274     bool m_cancelled; | 
| Chris@439 | 275 }; | 
| Chris@439 | 276 | 
| Chris@526 | 277 WredlandWorldWrapper *SimpleSPARQLQuery::Impl::m_redland = 0; | 
| Chris@480 | 278 | 
| Chris@480 | 279 QMutex SimpleSPARQLQuery::Impl::m_mutex; | 
| Chris@480 | 280 | 
| Chris@489 | 281 SimpleSPARQLQuery::SimpleSPARQLQuery(QueryType type, QString query) : | 
| Chris@489 | 282     m_impl(new Impl(type, query)) | 
| Chris@480 | 283 { | 
| Chris@480 | 284 } | 
| Chris@439 | 285 | 
| Chris@439 | 286 SimpleSPARQLQuery::~SimpleSPARQLQuery() | 
| Chris@439 | 287 { | 
| Chris@439 | 288     delete m_impl; | 
| Chris@439 | 289 } | 
| Chris@439 | 290 | 
| Chris@439 | 291 void | 
| Chris@439 | 292 SimpleSPARQLQuery::setProgressReporter(ProgressReporter *reporter) | 
| Chris@439 | 293 { | 
| Chris@439 | 294     m_impl->setProgressReporter(reporter); | 
| Chris@439 | 295 } | 
| Chris@439 | 296 | 
| Chris@439 | 297 bool | 
| Chris@439 | 298 SimpleSPARQLQuery::wasCancelled() const | 
| Chris@439 | 299 { | 
| Chris@439 | 300     return m_impl->wasCancelled(); | 
| Chris@439 | 301 } | 
| Chris@439 | 302 | 
| Chris@439 | 303 SimpleSPARQLQuery::ResultList | 
| Chris@439 | 304 SimpleSPARQLQuery::execute() | 
| Chris@439 | 305 { | 
| Chris@439 | 306     return m_impl->execute(); | 
| Chris@439 | 307 } | 
| Chris@439 | 308 | 
| Chris@439 | 309 bool | 
| Chris@439 | 310 SimpleSPARQLQuery::isOK() const | 
| Chris@439 | 311 { | 
| Chris@439 | 312     return m_impl->isOK(); | 
| Chris@439 | 313 } | 
| Chris@439 | 314 | 
| Chris@439 | 315 QString | 
| Chris@439 | 316 SimpleSPARQLQuery::getErrorString() const | 
| Chris@439 | 317 { | 
| Chris@439 | 318     return m_impl->getErrorString(); | 
| Chris@439 | 319 } | 
| Chris@439 | 320 | 
| Chris@489 | 321 bool | 
| Chris@489 | 322 SimpleSPARQLQuery::addSourceToModel(QString sourceUri) | 
| Chris@480 | 323 { | 
| Chris@489 | 324     return SimpleSPARQLQuery::Impl::addSourceToModel(sourceUri); | 
| Chris@480 | 325 } | 
| Chris@480 | 326 | 
| Chris@492 | 327 void | 
| Chris@492 | 328 SimpleSPARQLQuery::closeSingleSource(QString sourceUri) | 
| Chris@492 | 329 { | 
| Chris@492 | 330     SimpleSPARQLQuery::Impl::closeSingleSource(sourceUri); | 
| Chris@492 | 331 } | 
| Chris@492 | 332 | 
| Chris@489 | 333 SimpleSPARQLQuery::Impl::Impl(QueryType type, QString query) : | 
| Chris@489 | 334     m_type(type), | 
| Chris@439 | 335     m_query(query), | 
| Chris@439 | 336     m_reporter(0), | 
| Chris@439 | 337     m_cancelled(false) | 
| Chris@439 | 338 { | 
| Chris@439 | 339 } | 
| Chris@439 | 340 | 
| Chris@439 | 341 SimpleSPARQLQuery::Impl::~Impl() | 
| Chris@439 | 342 { | 
| Chris@439 | 343 } | 
| Chris@439 | 344 | 
| Chris@439 | 345 bool | 
| Chris@439 | 346 SimpleSPARQLQuery::Impl::isOK() const | 
| Chris@439 | 347 { | 
| Chris@439 | 348     return (m_errorString == ""); | 
| Chris@439 | 349 } | 
| Chris@439 | 350 | 
| Chris@439 | 351 QString | 
| Chris@439 | 352 SimpleSPARQLQuery::Impl::getErrorString() const | 
| Chris@439 | 353 { | 
| Chris@439 | 354     return m_errorString; | 
| Chris@439 | 355 } | 
| Chris@439 | 356 | 
| Chris@439 | 357 SimpleSPARQLQuery::ResultList | 
| Chris@439 | 358 SimpleSPARQLQuery::Impl::execute() | 
| Chris@439 | 359 { | 
| Chris@439 | 360     ResultList list; | 
| Chris@439 | 361 | 
| Chris@490 | 362     QMutexLocker locker(&m_mutex); | 
| Chris@480 | 363 | 
| Chris@526 | 364     if (!m_redland) { | 
| Chris@526 | 365         m_redland = new WredlandWorldWrapper(); | 
| Chris@526 | 366     } | 
| Chris@526 | 367 | 
| Chris@526 | 368     if (!m_redland->isOK()) { | 
| Chris@492 | 369         cerr << "ERROR: SimpleSPARQLQuery::execute: Failed to initialise Redland datastore" << endl; | 
| Chris@492 | 370         return list; | 
| Chris@440 | 371     } | 
| Chris@480 | 372 | 
| Chris@489 | 373     if (m_type == QueryFromSingleSource) { | 
| Chris@480 | 374         return executeDirectParser(); | 
| Chris@480 | 375     } else { | 
| Chris@480 | 376         return executeDatastore(); | 
| Chris@480 | 377     } | 
| Chris@492 | 378 | 
| Chris@492 | 379 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@492 | 380     if (m_errorString != "") { | 
| Chris@492 | 381         std::cerr << "SimpleSPARQLQuery::execute: error returned: \"" | 
| Chris@686 | 382                   << m_errorString << "\"" << std::endl; | 
| Chris@492 | 383     } | 
| Chris@492 | 384 #endif | 
| Chris@480 | 385 } | 
| Chris@480 | 386 | 
| Chris@480 | 387 SimpleSPARQLQuery::ResultList | 
| Chris@480 | 388 SimpleSPARQLQuery::Impl::executeDirectParser() | 
| Chris@480 | 389 { | 
| Chris@492 | 390 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@690 | 391     SVDEBUG << "SimpleSPARQLQuery::executeDirectParser: Query is: \"" << m_query << "\"" << endl; | 
| Chris@492 | 392 #endif | 
| Chris@492 | 393 | 
| Chris@480 | 394     ResultList list; | 
| Chris@480 | 395 | 
| Chris@480 | 396     Profiler profiler("SimpleSPARQLQuery::executeDirectParser"); | 
| Chris@480 | 397 | 
| Chris@492 | 398     static QRegExp fromRE("from\\s+<([^>]+)>", Qt::CaseInsensitive); | 
| Chris@492 | 399     QString fromUri; | 
| Chris@492 | 400 | 
| Chris@492 | 401     if (fromRE.indexIn(m_query) < 0) { | 
| Chris@690 | 402         SVDEBUG << "SimpleSPARQLQuery::executeDirectParser: Query contains no FROM clause, nothing to parse from" << endl; | 
| Chris@492 | 403         return list; | 
| Chris@492 | 404     } else { | 
| Chris@492 | 405         fromUri = fromRE.cap(1); | 
| Chris@492 | 406 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@690 | 407         SVDEBUG << "SimpleSPARQLQuery::executeDirectParser: FROM URI is <" | 
| Chris@687 | 408                   << fromUri << ">" << endl; | 
| Chris@440 | 409 #endif | 
| Chris@439 | 410     } | 
| Chris@439 | 411 | 
| Chris@492 | 412     return executeFor(fromUri); | 
| Chris@439 | 413 } | 
| Chris@440 | 414 | 
| Chris@480 | 415 SimpleSPARQLQuery::ResultList | 
| Chris@480 | 416 SimpleSPARQLQuery::Impl::executeDatastore() | 
| Chris@480 | 417 { | 
| Chris@492 | 418 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@690 | 419     SVDEBUG << "SimpleSPARQLQuery::executeDatastore: Query is: \"" << m_query << "\"" << endl; | 
| Chris@492 | 420 #endif | 
| Chris@492 | 421 | 
| Chris@480 | 422     ResultList list; | 
| Chris@489 | 423 | 
| Chris@480 | 424     Profiler profiler("SimpleSPARQLQuery::executeDatastore"); | 
| Chris@480 | 425 | 
| Chris@492 | 426     return executeFor(""); | 
| Chris@492 | 427 } | 
| Chris@492 | 428 | 
| Chris@492 | 429 SimpleSPARQLQuery::ResultList | 
| Chris@492 | 430 SimpleSPARQLQuery::Impl::executeFor(QString modelUri) | 
| Chris@492 | 431 { | 
| Chris@492 | 432     ResultList list; | 
| Chris@492 | 433     librdf_query *query; | 
| Chris@492 | 434 | 
| Chris@493 | 435 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@480 | 436     static std::map<QString, int> counter; | 
| Chris@480 | 437     if (counter.find(m_query) == counter.end()) counter[m_query] = 1; | 
| Chris@480 | 438     else ++counter[m_query]; | 
| Chris@480 | 439     std::cerr << "Counter for this query: " << counter[m_query] << std::endl; | 
| Chris@686 | 440     std::cerr << "Base URI is: \"" << modelUri << "\"" << std::endl; | 
| Chris@493 | 441 #endif | 
| Chris@480 | 442 | 
| Chris@480 | 443     { | 
| Chris@480 | 444         Profiler p("SimpleSPARQLQuery: Prepare LIBRDF query"); | 
| Chris@480 | 445         query = librdf_new_query | 
| Chris@526 | 446             (m_redland->getWorld(), "sparql", NULL, | 
| Chris@489 | 447              (const unsigned char *)m_query.toUtf8().data(), NULL); | 
| Chris@480 | 448     } | 
| Chris@480 | 449 | 
| Chris@480 | 450     if (!query) { | 
| Chris@480 | 451         m_errorString = "Failed to construct query"; | 
| Chris@480 | 452         return list; | 
| Chris@480 | 453     } | 
| Chris@480 | 454 | 
| Chris@480 | 455     librdf_query_results *results; | 
| Chris@480 | 456     { | 
| Chris@480 | 457         Profiler p("SimpleSPARQLQuery: Execute LIBRDF query"); | 
| Chris@526 | 458         results = librdf_query_execute(query, m_redland->getModel(modelUri)); | 
| Chris@480 | 459     } | 
| Chris@480 | 460 | 
| Chris@480 | 461     if (!results) { | 
| Chris@511 | 462         m_errorString = "RDF query failed"; | 
| Chris@480 | 463         librdf_free_query(query); | 
| Chris@480 | 464         return list; | 
| Chris@480 | 465     } | 
| Chris@480 | 466 | 
| Chris@480 | 467     if (!librdf_query_results_is_bindings(results)) { | 
| Chris@511 | 468         m_errorString = "RDF query returned non-bindings results"; | 
| Chris@480 | 469         librdf_free_query_results(results); | 
| Chris@480 | 470         librdf_free_query(query); | 
| Chris@480 | 471         return list; | 
| Chris@480 | 472     } | 
| Chris@480 | 473 | 
| Chris@480 | 474     int resultCount = 0; | 
| Chris@480 | 475     int resultTotal = librdf_query_results_get_count(results); // probably wrong | 
| Chris@480 | 476     m_cancelled = false; | 
| Chris@480 | 477 | 
| Chris@480 | 478     while (!librdf_query_results_finished(results)) { | 
| Chris@480 | 479 | 
| Chris@480 | 480         int count = librdf_query_results_get_bindings_count(results); | 
| Chris@480 | 481 | 
| Chris@480 | 482         KeyValueMap resultmap; | 
| Chris@480 | 483 | 
| Chris@480 | 484         for (int i = 0; i < count; ++i) { | 
| Chris@480 | 485 | 
| Chris@480 | 486             const char *name = | 
| Chris@480 | 487                 librdf_query_results_get_binding_name(results, i); | 
| Chris@480 | 488 | 
| Chris@490 | 489             if (!name) { | 
| Chris@490 | 490                 std::cerr << "WARNING: Result " << i << " of query has no name" << std::endl; | 
| Chris@490 | 491                 continue; | 
| Chris@490 | 492             } | 
| Chris@490 | 493 | 
| Chris@480 | 494             librdf_node *node = | 
| Chris@480 | 495                 librdf_query_results_get_binding_value(results, i); | 
| Chris@480 | 496 | 
| Chris@480 | 497             QString key = (const char *)name; | 
| Chris@480 | 498 | 
| Chris@480 | 499             if (!node) { | 
| Chris@492 | 500 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@686 | 501                 std::cerr << i << ". " << key << " -> (nil)" << std::endl; | 
| Chris@492 | 502 #endif | 
| Chris@480 | 503                 resultmap[key] = Value(); | 
| Chris@480 | 504                 continue; | 
| Chris@480 | 505             } | 
| Chris@480 | 506 | 
| Chris@480 | 507             ValueType type = LiteralValue; | 
| Chris@481 | 508             QString text; | 
| Chris@481 | 509 | 
| Chris@481 | 510             if (librdf_node_is_resource(node)) { | 
| Chris@481 | 511 | 
| Chris@481 | 512                 type = URIValue; | 
| Chris@481 | 513                 librdf_uri *uri = librdf_node_get_uri(node); | 
| Chris@490 | 514                 const char *us = (const char *)librdf_uri_as_string(uri); | 
| Chris@490 | 515 | 
| Chris@490 | 516                 if (!us) { | 
| Chris@490 | 517                     std::cerr << "WARNING: Result " << i << " of query claims URI type, but has null URI" << std::endl; | 
| Chris@490 | 518                 } else { | 
| Chris@490 | 519                     text = us; | 
| Chris@490 | 520                 } | 
| Chris@481 | 521 | 
| Chris@481 | 522             } else if (librdf_node_is_literal(node)) { | 
| Chris@481 | 523 | 
| Chris@481 | 524                 type = LiteralValue; | 
| Chris@490 | 525 | 
| Chris@490 | 526                 const char *lit = (const char *)librdf_node_get_literal_value(node); | 
| Chris@490 | 527                 if (!lit) { | 
| Chris@490 | 528                     std::cerr << "WARNING: Result " << i << " of query claims literal type, but has no literal" << std::endl; | 
| Chris@490 | 529                 } else { | 
| Chris@490 | 530                     text = lit; | 
| Chris@490 | 531                 } | 
| Chris@481 | 532 | 
| Chris@481 | 533             } else if (librdf_node_is_blank(node)) { | 
| Chris@481 | 534 | 
| Chris@481 | 535                 type = BlankValue; | 
| Chris@481 | 536 | 
| Chris@494 | 537                 const char *lit = (const char *)librdf_node_get_literal_value(node); | 
| Chris@494 | 538                 if (lit) text = lit; | 
| Chris@494 | 539 | 
| Chris@481 | 540             } else { | 
| Chris@481 | 541 | 
| Chris@480 | 542                 cerr << "SimpleSPARQLQuery: LIBRDF query returned unknown node type (not resource, literal, or blank)" << endl; | 
| Chris@480 | 543             } | 
| Chris@480 | 544 | 
| Chris@480 | 545 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@686 | 546             cerr << i << ". " << key << " -> " << text << " (type " << type << ")" << endl; | 
| Chris@480 | 547 #endif | 
| Chris@480 | 548 | 
| Chris@480 | 549             resultmap[key] = Value(type, text); | 
| Chris@480 | 550 | 
| Chris@492 | 551 //            librdf_free_node(node); | 
| Chris@480 | 552         } | 
| Chris@480 | 553 | 
| Chris@480 | 554         list.push_back(resultmap); | 
| Chris@480 | 555 | 
| Chris@480 | 556         librdf_query_results_next(results); | 
| Chris@480 | 557 | 
| Chris@480 | 558         resultCount++; | 
| Chris@480 | 559 | 
| Chris@480 | 560         if (m_reporter) { | 
| Chris@480 | 561             if (resultCount >= resultTotal) { | 
| Chris@480 | 562                 if (m_reporter->isDefinite()) m_reporter->setDefinite(false); | 
| Chris@480 | 563                 m_reporter->setProgress(resultCount); | 
| Chris@480 | 564             } else { | 
| Chris@480 | 565                 m_reporter->setProgress((resultCount * 100) / resultTotal); | 
| Chris@480 | 566             } | 
| Chris@480 | 567 | 
| Chris@480 | 568             if (m_reporter->wasCancelled()) { | 
| Chris@480 | 569                 m_cancelled = true; | 
| Chris@480 | 570                 break; | 
| Chris@480 | 571             } | 
| Chris@480 | 572         } | 
| Chris@480 | 573     } | 
| Chris@480 | 574 | 
| Chris@480 | 575     librdf_free_query_results(results); | 
| Chris@480 | 576     librdf_free_query(query); | 
| Chris@480 | 577 | 
| Chris@481 | 578 #ifdef DEBUG_SIMPLE_SPARQL_QUERY | 
| Chris@690 | 579     SVDEBUG << "SimpleSPARQLQuery::executeDatastore: All results retrieved (" << resultCount << " of them)" << endl; | 
| Chris@481 | 580 #endif | 
| Chris@480 | 581 | 
| Chris@480 | 582     return list; | 
| Chris@489 | 583 } | 
| Chris@489 | 584 | 
| Chris@489 | 585 bool | 
| Chris@489 | 586 SimpleSPARQLQuery::Impl::addSourceToModel(QString sourceUri) | 
| Chris@489 | 587 { | 
| Chris@489 | 588     QString err; | 
| Chris@489 | 589 | 
| Chris@490 | 590     QMutexLocker locker(&m_mutex); | 
| Chris@489 | 591 | 
| Chris@527 | 592     if (!m_redland) { | 
| Chris@527 | 593         m_redland = new WredlandWorldWrapper(); | 
| Chris@527 | 594     } | 
| Chris@527 | 595 | 
| Chris@526 | 596     if (!m_redland->isOK()) { | 
| Chris@492 | 597         std::cerr << "SimpleSPARQLQuery::addSourceToModel: Failed to initialise Redland datastore" << std::endl; | 
| Chris@492 | 598         return false; | 
| Chris@489 | 599     } | 
| Chris@489 | 600 | 
| Chris@526 | 601     if (!m_redland->loadUriIntoDefaultModel(sourceUri, err)) { | 
| Chris@686 | 602         std::cerr << "SimpleSPARQLQuery::addSourceToModel: Failed to add source URI \"" << sourceUri << ": " << err << std::endl; | 
| Chris@489 | 603         return false; | 
| Chris@489 | 604     } | 
| Chris@489 | 605     return true; | 
| Chris@480 | 606 } | 
| Chris@480 | 607 | 
| Chris@492 | 608 void | 
| Chris@492 | 609 SimpleSPARQLQuery::Impl::closeSingleSource(QString sourceUri) | 
| Chris@492 | 610 { | 
| Chris@492 | 611     QMutexLocker locker(&m_mutex); | 
| Chris@492 | 612 | 
| Chris@526 | 613     m_redland->freeModel(sourceUri); | 
| Chris@492 | 614 } | 
| Chris@492 | 615 | 
| Chris@440 | 616 SimpleSPARQLQuery::Value | 
| Chris@489 | 617 SimpleSPARQLQuery::singleResultQuery(QueryType type, | 
| Chris@480 | 618                                      QString query, QString binding) | 
| Chris@440 | 619 { | 
| Chris@489 | 620     SimpleSPARQLQuery q(type, query); | 
| Chris@440 | 621     ResultList results = q.execute(); | 
| Chris@440 | 622     if (!q.isOK()) { | 
| Chris@690 | 623         SVDEBUG << "SimpleSPARQLQuery::singleResultQuery: ERROR: " | 
| Chris@686 | 624              << q.getErrorString() << endl; | 
| Chris@440 | 625         return Value(); | 
| Chris@440 | 626     } | 
| Chris@440 | 627     if (results.empty()) { | 
| Chris@440 | 628         return Value(); | 
| Chris@440 | 629     } | 
| Chris@440 | 630     for (int i = 0; i < results.size(); ++i) { | 
| Chris@440 | 631         if (results[i].find(binding) != results[i].end() && | 
| Chris@440 | 632             results[i][binding].type != NoValue) { | 
| Chris@440 | 633             return results[i][binding]; | 
| Chris@440 | 634         } | 
| Chris@440 | 635     } | 
| Chris@440 | 636     return Value(); | 
| Chris@440 | 637 } | 
| Chris@440 | 638 | 
| Chris@440 | 639 | 
| Chris@440 | 640 |