ctkPluginDatabase.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) 2010 German Cancer Research Center,
  4. Division of Medical and Biological Informatics
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =============================================================================*/
  15. #include "ctkPluginDatabase_p.h"
  16. #include "ctkPluginDatabaseException.h"
  17. #include "ctkPlugin.h"
  18. #include "ctkPluginConstants.h"
  19. #include "ctkPluginException.h"
  20. #include "ctkPluginArchive_p.h"
  21. #include "ctkPluginStorage_p.h"
  22. #include "ctkServiceException.h"
  23. #include <QApplication>
  24. #include <QFileInfo>
  25. #include <QUrl>
  26. #include <QServiceManager>
  27. #include <QDebug>
  28. //database name
  29. #define PLUGINDATABASE "pluginfw.db"
  30. //database table names
  31. #define PLUGINS_TABLE "Plugins"
  32. #define PLUGIN_RESOURCES_TABLE "PluginResources"
  33. //separator
  34. #define PLUGINDATABASE_PATH_SEPARATOR "//"
  35. namespace ctk {
  36. enum TBindIndexes
  37. {
  38. EBindIndex=0,
  39. EBindIndex1,
  40. EBindIndex2,
  41. EBindIndex3,
  42. EBindIndex4,
  43. EBindIndex5,
  44. EBindIndex6,
  45. EBindIndex7
  46. };
  47. PluginDatabase::PluginDatabase(PluginStorage* storage)
  48. :m_isDatabaseOpen(false), m_inTransaction(false), m_PluginStorage(storage)
  49. {
  50. }
  51. PluginDatabase::~PluginDatabase()
  52. {
  53. close();
  54. }
  55. void PluginDatabase::open()
  56. {
  57. if (m_isDatabaseOpen)
  58. return;
  59. QString path;
  60. //Create full path to database
  61. if(m_databasePath.isEmpty ())
  62. m_databasePath = getDatabasePath();
  63. path = m_databasePath;
  64. QFileInfo dbFileInfo(path);
  65. if (!dbFileInfo.dir().exists())
  66. {
  67. if(!QDir::root().mkpath(dbFileInfo.path()))
  68. {
  69. close();
  70. QString errorText("Could not create database directory: %1");
  71. throw PluginDatabaseException(errorText.arg(dbFileInfo.path()), PluginDatabaseException::DB_CREATE_DIR_ERROR);
  72. }
  73. }
  74. m_connectionName = dbFileInfo.completeBaseName();
  75. QSqlDatabase database;
  76. if (QSqlDatabase::contains(m_connectionName))
  77. {
  78. database = QSqlDatabase::database(m_connectionName);
  79. }
  80. else
  81. {
  82. database = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
  83. database.setDatabaseName(path);
  84. }
  85. if (!database.isValid())
  86. {
  87. close();
  88. throw PluginDatabaseException(QString("Invalid database connection: %1").arg(m_connectionName),
  89. PluginDatabaseException::DB_CONNECTION_INVALID);
  90. }
  91. //Create or open database
  92. if (!database.isOpen())
  93. {
  94. if (!database.open())
  95. {
  96. close();
  97. throw PluginDatabaseException(QString("Could not open database. ") + database.lastError().text(),
  98. PluginDatabaseException::DB_SQL_ERROR);
  99. }
  100. }
  101. m_isDatabaseOpen = true;
  102. //Check if the sqlite version supports foreign key constraints
  103. QSqlQuery query(database);
  104. if (!query.exec("PRAGMA foreign_keys"))
  105. {
  106. close();
  107. throw PluginDatabaseException(QString("Check for foreign key support failed."),
  108. PluginDatabaseException::DB_SQL_ERROR);
  109. }
  110. if (!query.next())
  111. {
  112. close();
  113. throw PluginDatabaseException(QString("SQLite db does not support foreign keys. It is either older than 3.6.19 or was compiled with SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER"),
  114. PluginDatabaseException::DB_SQL_ERROR);
  115. }
  116. query.finish();
  117. query.clear();
  118. //Enable foreign key support
  119. if (!query.exec("PRAGMA foreign_keys = ON"))
  120. {
  121. close();
  122. throw PluginDatabaseException(QString("Enabling foreign key support failed."),
  123. PluginDatabaseException::DB_SQL_ERROR);
  124. }
  125. query.finish();
  126. //Check database structure (tables) and recreate tables if neccessary
  127. //If one of the tables is missing remove all tables and recreate them
  128. //This operation is required in order to avoid data coruption
  129. if (!checkTables())
  130. {
  131. if (dropTables())
  132. {
  133. createTables();
  134. }
  135. else
  136. {
  137. //dropTables() should've handled error message
  138. //and warning
  139. close();
  140. }
  141. }
  142. //Update database based on the recorded timestamps
  143. updateDB();
  144. }
  145. void PluginDatabase::updateDB()
  146. {
  147. checkConnection();
  148. QSqlDatabase database = QSqlDatabase::database(m_connectionName);
  149. QSqlQuery query(database);
  150. beginTransaction(&query, Write);
  151. QString statement = "SELECT ID, Location, LocalPath, Timestamp, SymbolicName, Version FROM Plugins WHERE State != ?";
  152. QList<QVariant> bindValues;
  153. bindValues.append(Plugin::UNINSTALLED);
  154. QList<qlonglong> outdatedIds;
  155. QList<QPair<QString,QString> > outdatedPlugins;
  156. QStringList outdatedServiceNames;
  157. try
  158. {
  159. executeQuery(&query, statement, bindValues);
  160. while (query.next())
  161. {
  162. QFileInfo pluginInfo(query.value(EBindIndex2).toString());
  163. if (pluginInfo.lastModified() > QDateTime::fromString(query.value(EBindIndex3).toString(), Qt::ISODate))
  164. {
  165. outdatedIds.append(query.value(EBindIndex).toLongLong());
  166. outdatedPlugins.append(qMakePair(query.value(EBindIndex1).toString(), query.value(EBindIndex2).toString()));
  167. outdatedServiceNames.append(query.value(EBindIndex4).toString() + "_" + query.value(EBindIndex5).toString());
  168. }
  169. }
  170. }
  171. catch (...)
  172. {
  173. rollbackTransaction(&query);
  174. throw;
  175. }
  176. query.finish();
  177. query.clear();
  178. try
  179. {
  180. statement = "DELETE FROM Plugins WHERE ID=?";
  181. QListIterator<qlonglong> idIter(outdatedIds);
  182. while (idIter.hasNext())
  183. {
  184. bindValues.clear();
  185. bindValues.append(idIter.next());
  186. executeQuery(&query, statement, bindValues);
  187. }
  188. }
  189. catch (...)
  190. {
  191. rollbackTransaction(&query);
  192. throw;
  193. }
  194. try
  195. {
  196. QtMobility::QServiceManager serviceManager;
  197. QStringListIterator serviceNameIter(outdatedServiceNames);
  198. while (serviceNameIter.hasNext())
  199. {
  200. QString serviceName = serviceNameIter.next();
  201. serviceManager.removeService(serviceName);
  202. QtMobility::QServiceManager::Error error = serviceManager.error();
  203. if (!(error == QtMobility::QServiceManager::NoError ||
  204. error == QtMobility::QServiceManager::ComponentNotFound))
  205. {
  206. throw ServiceException(QString("Removing service named ") + serviceName +
  207. " failed: " + QString::number(serviceManager.error()));
  208. }
  209. }
  210. }
  211. catch (...)
  212. {
  213. rollbackTransaction(&query);
  214. throw;
  215. }
  216. commitTransaction(&query);
  217. QListIterator<QPair<QString,QString> > locationIter(outdatedPlugins);
  218. while (locationIter.hasNext())
  219. {
  220. const QPair<QString,QString>& locations = locationIter.next();
  221. insertPlugin(QUrl(locations.first), locations.second, false);
  222. }
  223. }
  224. PluginArchive* PluginDatabase::insertPlugin(const QUrl& location, const QString& localPath, bool createArchive)
  225. {
  226. checkConnection();
  227. // Assemble the data for the sql record
  228. QFileInfo fileInfo(localPath);
  229. const QString lastModified = fileInfo.lastModified().toString(Qt::ISODate);
  230. QString resourcePrefix = fileInfo.baseName();
  231. if (resourcePrefix.startsWith("lib"))
  232. {
  233. resourcePrefix = resourcePrefix.mid(3);
  234. }
  235. resourcePrefix.replace("_", ".");
  236. resourcePrefix = QString(":/") + resourcePrefix + "/";
  237. QSqlDatabase database = QSqlDatabase::database(m_connectionName);
  238. QSqlQuery query(database);
  239. beginTransaction(&query, Write);
  240. QString statement = "INSERT INTO Plugins(Location,LocalPath,SymbolicName,Version,State,Timestamp) VALUES(?,?,?,?,?,?)";
  241. QList<QVariant> bindValues;
  242. bindValues.append(location.toString());
  243. bindValues.append(localPath);
  244. bindValues.append(QString("na"));
  245. bindValues.append(QString("na"));
  246. bindValues.append(Plugin::INSTALLED);
  247. bindValues.append(lastModified);
  248. qlonglong pluginId = -1;
  249. try
  250. {
  251. executeQuery(&query, statement, bindValues);
  252. QVariant lastId = query.lastInsertId();
  253. if (lastId.isValid())
  254. {
  255. pluginId = lastId.toLongLong();
  256. }
  257. }
  258. catch (...)
  259. {
  260. rollbackTransaction(&query);
  261. throw;
  262. }
  263. // Load the plugin and cache the resources
  264. QPluginLoader pluginLoader;
  265. pluginLoader.setFileName(localPath);
  266. if (!pluginLoader.load())
  267. {
  268. rollbackTransaction(&query);
  269. throw PluginException(QString("The plugin could not be loaded: %1").arg(localPath));
  270. }
  271. QDirIterator dirIter(resourcePrefix, QDirIterator::Subdirectories);
  272. while (dirIter.hasNext())
  273. {
  274. QString resourcePath = dirIter.next();
  275. if (QFileInfo(resourcePath).isDir()) continue;
  276. QFile resourceFile(resourcePath);
  277. resourceFile.open(QIODevice::ReadOnly);
  278. QByteArray resourceData = resourceFile.readAll();
  279. resourceFile.close();
  280. statement = "INSERT INTO PluginResources(PluginID, ResourcePath, Resource) VALUES(?,?,?)";
  281. bindValues.clear();
  282. bindValues.append(QVariant::fromValue<qlonglong>(pluginId));
  283. bindValues.append(resourcePath.mid(resourcePrefix.size()-1));
  284. bindValues.append(resourceData);
  285. try
  286. {
  287. executeQuery(&query, statement, bindValues);
  288. }
  289. catch (...)
  290. {
  291. rollbackTransaction(&query);
  292. throw;
  293. }
  294. }
  295. pluginLoader.unload();
  296. try
  297. {
  298. PluginArchive* archive = new PluginArchive(m_PluginStorage, location, localPath,
  299. pluginId);;
  300. statement = "UPDATE Plugins SET SymbolicName=?,Version=? WHERE ID=?";
  301. QString versionString = archive->getAttribute(PluginConstants::PLUGIN_VERSION);
  302. bindValues.clear();
  303. bindValues.append(archive->getAttribute(PluginConstants::PLUGIN_SYMBOLICNAME));
  304. bindValues.append(versionString.isEmpty() ? "0.0.0" : versionString);
  305. bindValues.append(pluginId);
  306. if (!createArchive)
  307. {
  308. delete archive;
  309. archive = 0;
  310. }
  311. executeQuery(&query, statement, bindValues);
  312. commitTransaction(&query);
  313. return archive;
  314. }
  315. catch (...)
  316. {
  317. rollbackTransaction(&query);
  318. throw;
  319. }
  320. }
  321. QStringList PluginDatabase::findResourcesPath(long pluginId, const QString& path) const
  322. {
  323. checkConnection();
  324. QString statement = "SELECT SUBSTR(ResourcePath,?) FROM PluginResources WHERE PluginID=? AND SUBSTR(ResourcePath,1,?)=?";
  325. QString resourcePath = path.startsWith('/') ? path : QString("/") + path;
  326. if (!resourcePath.endsWith('/'))
  327. resourcePath += "/";
  328. QList<QVariant> bindValues;
  329. bindValues.append(resourcePath.size()+1);
  330. bindValues.append(qlonglong(pluginId));
  331. bindValues.append(resourcePath.size());
  332. bindValues.append(resourcePath);
  333. QSqlDatabase database = QSqlDatabase::database(m_connectionName);
  334. QSqlQuery query(database);
  335. executeQuery(&query, statement, bindValues);
  336. QStringList paths;
  337. while (query.next())
  338. {
  339. QString currPath = query.value(EBindIndex).toString();
  340. int slashIndex = currPath.indexOf('/');
  341. if (slashIndex > 0)
  342. {
  343. currPath = currPath.left(slashIndex+1);
  344. }
  345. paths << currPath;
  346. }
  347. return paths;
  348. }
  349. void PluginDatabase::removeArchive(const PluginArchive *pa)
  350. {
  351. checkConnection();
  352. QSqlDatabase database = QSqlDatabase::database(m_connectionName);
  353. QSqlQuery query(database);
  354. QString statement = "DELETE FROM Plugins WHERE ID=?";
  355. QList<QVariant> bindValues;
  356. bindValues.append(pa->getPluginId());
  357. executeQuery(&query, statement, bindValues);
  358. }
  359. void PluginDatabase::executeQuery(QSqlQuery *query, const QString &statement, const QList<QVariant> &bindValues) const
  360. {
  361. Q_ASSERT(query != 0);
  362. bool success = false;
  363. enum {Prepare =0 , Execute=1};
  364. for (int stage=Prepare; stage <= Execute; ++stage)
  365. {
  366. if ( stage == Prepare)
  367. success = query->prepare(statement);
  368. else // stage == Execute
  369. success = query->exec();
  370. if (!success)
  371. {
  372. QString errorText = "Problem: Could not %1 statement: %2\n"
  373. "Reason: %3\n"
  374. "Parameters: %4\n";
  375. QString parameters;
  376. if (bindValues.count() > 0)
  377. {
  378. for (int i = 0; i < bindValues.count(); ++i)
  379. {
  380. parameters.append(QString("\n\t[") + QString::number(i) + "]: " + bindValues.at(i).toString());
  381. }
  382. }
  383. else
  384. {
  385. parameters = "None";
  386. }
  387. PluginDatabaseException::Type errorType;
  388. int result = query->lastError().number();
  389. if (result == 26 || result == 11) //SQLILTE_NOTADB || SQLITE_CORRUPT
  390. {
  391. qWarning() << "PluginFramework:- Database file is corrupt or invalid:" << getDatabasePath();
  392. errorType = PluginDatabaseException::DB_FILE_INVALID;
  393. }
  394. else if (result == 8) //SQLITE_READONLY
  395. errorType = PluginDatabaseException::DB_WRITE_ERROR;
  396. else
  397. errorType = PluginDatabaseException::DB_SQL_ERROR;
  398. query->finish();
  399. query->clear();
  400. throw PluginDatabaseException(errorText.arg(stage == Prepare ? "prepare":"execute")
  401. .arg(statement).arg(query->lastError().text()).arg(parameters), errorType);
  402. }
  403. if (stage == Prepare)
  404. {
  405. foreach(const QVariant &bindValue, bindValues)
  406. query->addBindValue(bindValue);
  407. }
  408. }
  409. }
  410. void PluginDatabase::close()
  411. {
  412. if (m_isDatabaseOpen)
  413. {
  414. QSqlDatabase database = QSqlDatabase::database(m_connectionName, false);
  415. if (database.isValid())
  416. {
  417. if(database.isOpen())
  418. {
  419. database.close();
  420. m_isDatabaseOpen = false;
  421. return;
  422. }
  423. }
  424. else
  425. {
  426. throw PluginDatabaseException(QString("Problem closing database: Invalid connection %1").arg(m_connectionName));
  427. }
  428. }
  429. }
  430. void PluginDatabase::setDatabasePath(const QString &databasePath)
  431. {
  432. m_databasePath = QDir::toNativeSeparators(databasePath);
  433. }
  434. QString PluginDatabase::getDatabasePath() const
  435. {
  436. QString path;
  437. if(m_databasePath.isEmpty())
  438. {
  439. QSettings settings(QSettings::UserScope, "commontk", QApplication::applicationName());
  440. path = settings.value("PluginDB/Path").toString();
  441. if (path.isEmpty())
  442. {
  443. path = QDir::currentPath();
  444. if (path.lastIndexOf(PLUGINDATABASE_PATH_SEPARATOR) != path.length() -1)
  445. {
  446. path.append(PLUGINDATABASE_PATH_SEPARATOR);
  447. }
  448. path.append(PLUGINDATABASE);
  449. }
  450. path = QDir::toNativeSeparators(path);
  451. }
  452. else
  453. {
  454. path = m_databasePath;
  455. }
  456. return path;
  457. }
  458. QByteArray PluginDatabase::getPluginResource(long pluginId, const QString& res) const
  459. {
  460. checkConnection();
  461. QSqlDatabase database = QSqlDatabase::database(m_connectionName);
  462. QSqlQuery query(database);
  463. QString statement = "SELECT Resource FROM PluginResources WHERE PluginID=? AND ResourcePath=?";
  464. QString resourcePath = res.startsWith('/') ? res : QString("/") + res;
  465. QList<QVariant> bindValues;
  466. bindValues.append(qlonglong(pluginId));
  467. bindValues.append(resourcePath);
  468. executeQuery(&query, statement, bindValues);
  469. if (query.next())
  470. {
  471. return query.value(EBindIndex).toByteArray();
  472. }
  473. return QByteArray();
  474. }
  475. void PluginDatabase::createTables()
  476. {
  477. QSqlDatabase database = QSqlDatabase::database(m_connectionName);
  478. QSqlQuery query(database);
  479. //Begin Transaction
  480. beginTransaction(&query, Write);
  481. QString statement("CREATE TABLE Plugins("
  482. "ID INTEGER PRIMARY KEY,"
  483. "Location TEXT NOT NULL UNIQUE,"
  484. "LocalPath TEXT NOT NULL UNIQUE,"
  485. "SymbolicName TEXT NOT NULL,"
  486. "Version TEXT NOT NULL,"
  487. "State INTEGER NOT NULL,"
  488. "Timestamp TEXT NOT NULL)");
  489. try
  490. {
  491. executeQuery(&query, statement);
  492. }
  493. catch (...)
  494. {
  495. rollbackTransaction(&query);
  496. throw;
  497. }
  498. statement = "CREATE TABLE PluginResources("
  499. "PluginID INTEGER NOT NULL,"
  500. "ResourcePath TEXT NOT NULL, "
  501. "Resource BLOB NOT NULL,"
  502. "FOREIGN KEY(PluginID) REFERENCES Plugins(ID) ON DELETE CASCADE)";
  503. try
  504. {
  505. executeQuery(&query, statement);
  506. }
  507. catch (...)
  508. {
  509. rollbackTransaction(&query);
  510. throw;
  511. }
  512. try
  513. {
  514. commitTransaction(&query);
  515. }
  516. catch (...)
  517. {
  518. rollbackTransaction(&query);
  519. throw;
  520. }
  521. }
  522. bool PluginDatabase::checkTables() const
  523. {
  524. bool bTables(false);
  525. QStringList tables = QSqlDatabase::database(m_connectionName).tables();
  526. if (tables.contains(PLUGINS_TABLE)
  527. && tables.contains(PLUGIN_RESOURCES_TABLE))
  528. {
  529. bTables = true;
  530. }
  531. return bTables;
  532. }
  533. bool PluginDatabase::dropTables()
  534. {
  535. //Execute transaction for deleting the database tables
  536. QSqlDatabase database = QSqlDatabase::database(m_connectionName);
  537. QSqlQuery query(database);
  538. QStringList expectedTables;
  539. expectedTables << PLUGINS_TABLE << PLUGIN_RESOURCES_TABLE;
  540. if (database.tables().count() > 0)
  541. {
  542. beginTransaction(&query, Write);
  543. QStringList actualTables = database.tables();
  544. foreach(const QString expectedTable, expectedTables)
  545. {
  546. if (actualTables.contains(expectedTable))
  547. {
  548. try
  549. {
  550. executeQuery(&query, QString("DROP TABLE ") + expectedTable);
  551. }
  552. catch (...)
  553. {
  554. rollbackTransaction(&query);
  555. throw;
  556. }
  557. }
  558. try
  559. {
  560. commitTransaction(&query);
  561. }
  562. catch (...)
  563. {
  564. rollbackTransaction(&query);
  565. throw;
  566. }
  567. }
  568. }
  569. }
  570. bool PluginDatabase::isOpen() const
  571. {
  572. return m_isDatabaseOpen;
  573. }
  574. void PluginDatabase::checkConnection() const
  575. {
  576. if(!m_isDatabaseOpen)
  577. {
  578. throw PluginDatabaseException("Database not open.", PluginDatabaseException::DB_NOT_OPEN_ERROR);
  579. }
  580. if (!QSqlDatabase::database(m_connectionName).isValid())
  581. {
  582. throw PluginDatabaseException(QString("Database connection invalid: %1").arg(m_connectionName),
  583. PluginDatabaseException::DB_CONNECTION_INVALID);
  584. }
  585. }
  586. void PluginDatabase::beginTransaction(QSqlQuery *query, TransactionType type)
  587. {
  588. bool success;
  589. if (type == Read)
  590. success = query->exec(QLatin1String("BEGIN"));
  591. else
  592. success = query->exec(QLatin1String("BEGIN IMMEDIATE"));
  593. if (!success) {
  594. int result = query->lastError().number();
  595. if (result == 26 || result == 11) //SQLITE_NOTADB || SQLITE_CORRUPT
  596. {
  597. throw PluginDatabaseException(QString("PluginFramework: Database file is corrupt or invalid: %1").arg(getDatabasePath()),
  598. PluginDatabaseException::DB_FILE_INVALID);
  599. }
  600. else if (result == 8) //SQLITE_READONLY
  601. {
  602. throw PluginDatabaseException(QString("PluginFramework: Insufficient permissions to write to database: %1").arg(getDatabasePath()),
  603. PluginDatabaseException::DB_WRITE_ERROR);
  604. }
  605. else
  606. throw PluginDatabaseException(QString("PluginFramework: ") + query->lastError().text(),
  607. PluginDatabaseException::DB_SQL_ERROR);
  608. }
  609. }
  610. void PluginDatabase::commitTransaction(QSqlQuery *query)
  611. {
  612. Q_ASSERT(query != 0);
  613. query->finish();
  614. query->clear();
  615. if (!query->exec(QLatin1String("COMMIT")))
  616. {
  617. throw PluginDatabaseException(QString("PluginFramework: ") + query->lastError().text(),
  618. PluginDatabaseException::DB_SQL_ERROR);
  619. }
  620. }
  621. void PluginDatabase::rollbackTransaction(QSqlQuery *query)
  622. {
  623. Q_ASSERT(query !=0);
  624. query->finish();
  625. query->clear();
  626. if (!query->exec(QLatin1String("ROLLBACK")))
  627. {
  628. throw PluginDatabaseException(QString("PluginFramework: ") + query->lastError().text(),
  629. PluginDatabaseException::DB_SQL_ERROR);
  630. }
  631. }
  632. QList<PluginArchive*> PluginDatabase::getPluginArchives() const
  633. {
  634. checkConnection();
  635. QSqlQuery query(QSqlDatabase::database(m_connectionName));
  636. QString statement("SELECT ID, Location, LocalPath FROM Plugins WHERE State != ?");
  637. QList<QVariant> bindValues;
  638. bindValues.append(Plugin::UNINSTALLED);
  639. executeQuery(&query, statement, bindValues);
  640. QList<PluginArchive*> archives;
  641. while (query.next())
  642. {
  643. const long id = query.value(EBindIndex).toLongLong();
  644. const QUrl location(query.value(EBindIndex1).toString());
  645. const QString localPath(query.value(EBindIndex2).toString());
  646. if (id <= 0 || location.isEmpty() || localPath.isEmpty())
  647. {
  648. throw PluginDatabaseException(QString("Database integrity corrupted, row %1 contains empty values.").arg(id),
  649. PluginDatabaseException::DB_FILE_INVALID);
  650. }
  651. try
  652. {
  653. PluginArchive* pa = new PluginArchive(m_PluginStorage, location, localPath, id);
  654. archives.append(pa);
  655. }
  656. catch (const PluginException& exc)
  657. {
  658. qWarning() << exc;
  659. }
  660. }
  661. return archives;
  662. }
  663. }