ctkPluginDatabase.cpp

Go to the documentation of this file.
00001 /*=============================================================================
00002 
00003   Library: CTK
00004 
00005   Copyright (c) 2010 German Cancer Research Center,
00006     Division of Medical and Biological Informatics
00007 
00008   Licensed under the Apache License, Version 2.0 (the "License");
00009   you may not use this file except in compliance with the License.
00010   You may obtain a copy of the License at
00011 
00012     http://www.apache.org/licenses/LICENSE-2.0
00013 
00014   Unless required by applicable law or agreed to in writing, software
00015   distributed under the License is distributed on an "AS IS" BASIS,
00016   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00017   See the License for the specific language governing permissions and
00018   limitations under the License.
00019 
00020 =============================================================================*/
00021 
00022 #include "ctkPluginDatabase_p.h"
00023 #include "ctkPluginDatabaseException.h"
00024 #include "ctkPlugin.h"
00025 #include "ctkPluginConstants.h"
00026 #include "ctkPluginException.h"
00027 #include "ctkPluginArchive_p.h"
00028 #include "ctkPluginStorage_p.h"
00029 #include "ctkServiceException.h"
00030 
00031 #include <QApplication>
00032 #include <QFileInfo>
00033 #include <QUrl>
00034 #include <QServiceManager>
00035 
00036 #include <QDebug>
00037 
00038 //database name
00039 #define PLUGINDATABASE "pluginfw.db"
00040 
00041 //database table names
00042 #define PLUGINS_TABLE "Plugins"
00043 #define PLUGIN_RESOURCES_TABLE "PluginResources"
00044 
00045 //separator
00046 #define PLUGINDATABASE_PATH_SEPARATOR "//"
00047 
00048 
00049 
00050 enum TBindIndexes
00051 {
00052   EBindIndex=0,
00053   EBindIndex1,
00054   EBindIndex2,
00055   EBindIndex3,
00056   EBindIndex4,
00057   EBindIndex5,
00058   EBindIndex6,
00059   EBindIndex7
00060 };
00061 
00062 ctkPluginDatabase::ctkPluginDatabase(ctkPluginStorage* storage)
00063 :m_isDatabaseOpen(false), m_inTransaction(false), m_PluginStorage(storage)
00064 {
00065 }
00066 
00067 ctkPluginDatabase::~ctkPluginDatabase()
00068 {
00069     close();
00070 }
00071 
00072 void ctkPluginDatabase::open()
00073 {
00074   if (m_isDatabaseOpen)
00075     return;
00076 
00077   QString path;
00078 
00079   //Create full path to database
00080   if(m_databasePath.isEmpty ())
00081       m_databasePath = getDatabasePath();
00082 
00083   path = m_databasePath;
00084   QFileInfo dbFileInfo(path);
00085   if (!dbFileInfo.dir().exists())
00086   {
00087     if(!QDir::root().mkpath(dbFileInfo.path()))
00088     {
00089       close();
00090       QString errorText("Could not create database directory: %1");
00091       throw ctkPluginDatabaseException(errorText.arg(dbFileInfo.path()), ctkPluginDatabaseException::DB_CREATE_DIR_ERROR);
00092     }
00093   }
00094 
00095   m_connectionName = dbFileInfo.completeBaseName();
00096   QSqlDatabase database;
00097   if (QSqlDatabase::contains(m_connectionName))
00098   {
00099     database = QSqlDatabase::database(m_connectionName);
00100   }
00101   else
00102   {
00103     database = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
00104     database.setDatabaseName(path);
00105   }
00106 
00107   if (!database.isValid())
00108   {
00109     close();
00110     throw ctkPluginDatabaseException(QString("Invalid database connection: %1").arg(m_connectionName),
00111                                   ctkPluginDatabaseException::DB_CONNECTION_INVALID);
00112   }
00113 
00114   //Create or open database
00115   if (!database.isOpen())
00116   {
00117     if (!database.open())
00118     {
00119       close();
00120       throw ctkPluginDatabaseException(QString("Could not open database. ") + database.lastError().text(),
00121                                     ctkPluginDatabaseException::DB_SQL_ERROR);
00122     }
00123   }
00124   m_isDatabaseOpen = true;
00125 
00126   //Check if the sqlite version supports foreign key constraints
00127   QSqlQuery query(database);
00128   if (!query.exec("PRAGMA foreign_keys"))
00129   {
00130     close();
00131     throw ctkPluginDatabaseException(QString("Check for foreign key support failed."),
00132                                   ctkPluginDatabaseException::DB_SQL_ERROR);
00133   }
00134 
00135   if (!query.next())
00136   {
00137     close();
00138     throw ctkPluginDatabaseException(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"),
00139                                   ctkPluginDatabaseException::DB_SQL_ERROR);
00140   }
00141   query.finish();
00142   query.clear();
00143 
00144   //Enable foreign key support
00145   if (!query.exec("PRAGMA foreign_keys = ON"))
00146   {
00147     close();
00148     throw ctkPluginDatabaseException(QString("Enabling foreign key support failed."),
00149                                   ctkPluginDatabaseException::DB_SQL_ERROR);
00150   }
00151   query.finish();
00152 
00153 
00154   //Check database structure (tables) and recreate tables if neccessary
00155   //If one of the tables is missing remove all tables and recreate them
00156   //This operation is required in order to avoid data coruption
00157   if (!checkTables())
00158   {
00159     if (dropTables())
00160     {
00161       createTables();
00162     }
00163     else
00164     {
00165       //dropTables() should've handled error message
00166       //and warning
00167       close();
00168     }
00169   }
00170 
00171   //Update database based on the recorded timestamps
00172   updateDB();
00173 }
00174 
00175 void ctkPluginDatabase::updateDB()
00176 {
00177   checkConnection();
00178 
00179   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
00180   QSqlQuery query(database);
00181 
00182   beginTransaction(&query, Write);
00183 
00184   QString statement = "SELECT ID, Location, LocalPath, Timestamp, SymbolicName, Version FROM Plugins WHERE State != ?";
00185   QList<QVariant> bindValues;
00186   bindValues.append(ctkPlugin::UNINSTALLED);
00187 
00188   QList<qlonglong> outdatedIds;
00189   QList<QPair<QString,QString> > outdatedPlugins;
00190   QStringList outdatedServiceNames;
00191   try
00192   {
00193     executeQuery(&query, statement, bindValues);
00194 
00195     while (query.next())
00196     {
00197       QFileInfo pluginInfo(query.value(EBindIndex2).toString());
00198       if (pluginInfo.lastModified() > QDateTime::fromString(query.value(EBindIndex3).toString(), Qt::ISODate))
00199       {
00200         outdatedIds.append(query.value(EBindIndex).toLongLong());
00201         outdatedPlugins.append(qMakePair(query.value(EBindIndex1).toString(), query.value(EBindIndex2).toString()));
00202         outdatedServiceNames.append(query.value(EBindIndex4).toString() + "_" + query.value(EBindIndex5).toString());
00203       }
00204     }
00205   }
00206   catch (...)
00207   {
00208     rollbackTransaction(&query);
00209     throw;
00210   }
00211 
00212   query.finish();
00213   query.clear();
00214 
00215   try
00216   {
00217     statement = "DELETE FROM Plugins WHERE ID=?";
00218     QListIterator<qlonglong> idIter(outdatedIds);
00219     while (idIter.hasNext())
00220     {
00221       bindValues.clear();
00222       bindValues.append(idIter.next());
00223       executeQuery(&query, statement, bindValues);
00224     }
00225   }
00226   catch (...)
00227   {
00228     rollbackTransaction(&query);
00229     throw;
00230   }
00231 
00232   try
00233   {
00234     QtMobility::QServiceManager serviceManager;
00235     QStringListIterator serviceNameIter(outdatedServiceNames);
00236     while (serviceNameIter.hasNext())
00237     {
00238       QString serviceName = serviceNameIter.next();
00239       serviceManager.removeService(serviceName);
00240       QtMobility::QServiceManager::Error error = serviceManager.error();
00241       if (!(error == QtMobility::QServiceManager::NoError ||
00242             error == QtMobility::QServiceManager::ComponentNotFound))
00243       {
00244         throw ctkServiceException(QString("Removing service named ") + serviceName +
00245                                " failed: " + QString::number(serviceManager.error()));
00246       }
00247     }
00248   }
00249   catch (...)
00250   {
00251     rollbackTransaction(&query);
00252     throw;
00253   }
00254 
00255   commitTransaction(&query);
00256 
00257   QListIterator<QPair<QString,QString> > locationIter(outdatedPlugins);
00258   while (locationIter.hasNext())
00259   {
00260     const QPair<QString,QString>& locations = locationIter.next();
00261     insertPlugin(QUrl(locations.first), locations.second, false);
00262   }
00263 }
00264 
00265 
00266 ctkPluginArchive* ctkPluginDatabase::insertPlugin(const QUrl& location, const QString& localPath, bool createArchive)
00267 {
00268   checkConnection();
00269 
00270   // Assemble the data for the sql record
00271   QFileInfo fileInfo(localPath);
00272   const QString lastModified = fileInfo.lastModified().toString(Qt::ISODate);
00273 
00274   QString resourcePrefix = fileInfo.baseName();
00275   if (resourcePrefix.startsWith("lib"))
00276   {
00277     resourcePrefix = resourcePrefix.mid(3);
00278   }
00279   resourcePrefix.replace("_", ".");
00280 
00281   resourcePrefix = QString(":/") + resourcePrefix + "/";
00282 
00283   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
00284   QSqlQuery query(database);
00285 
00286   beginTransaction(&query, Write);
00287 
00288   QString statement = "INSERT INTO Plugins(Location,LocalPath,SymbolicName,Version,State,Timestamp) VALUES(?,?,?,?,?,?)";
00289 
00290   QList<QVariant> bindValues;
00291   bindValues.append(location.toString());
00292   bindValues.append(localPath);
00293   bindValues.append(QString("na"));
00294   bindValues.append(QString("na"));
00295   bindValues.append(ctkPlugin::INSTALLED);
00296   bindValues.append(lastModified);
00297 
00298   qlonglong pluginId = -1;
00299   try
00300   {
00301     executeQuery(&query, statement, bindValues);
00302     QVariant lastId = query.lastInsertId();
00303     if (lastId.isValid())
00304     {
00305       pluginId = lastId.toLongLong();
00306     }
00307   }
00308   catch (...)
00309   {
00310     rollbackTransaction(&query);
00311     throw;
00312   }
00313 
00314   // Load the plugin and cache the resources
00315   QPluginLoader pluginLoader;
00316   pluginLoader.setFileName(localPath);
00317   if (!pluginLoader.load())
00318   {
00319     rollbackTransaction(&query);
00320     throw ctkPluginException(QString("The plugin could not be loaded: %1").arg(localPath));
00321   }
00322 
00323   QDirIterator dirIter(resourcePrefix, QDirIterator::Subdirectories);
00324   while (dirIter.hasNext())
00325   {
00326     QString resourcePath = dirIter.next();
00327     if (QFileInfo(resourcePath).isDir()) continue;
00328 
00329     QFile resourceFile(resourcePath);
00330     resourceFile.open(QIODevice::ReadOnly);
00331     QByteArray resourceData = resourceFile.readAll();
00332     resourceFile.close();
00333 
00334     statement = "INSERT INTO PluginResources(PluginID, ResourcePath, Resource) VALUES(?,?,?)";
00335     bindValues.clear();
00336     bindValues.append(QVariant::fromValue<qlonglong>(pluginId));
00337     bindValues.append(resourcePath.mid(resourcePrefix.size()-1));
00338     bindValues.append(resourceData);
00339 
00340     try
00341     {
00342       executeQuery(&query, statement, bindValues);
00343     }
00344     catch (...)
00345     {
00346       rollbackTransaction(&query);
00347       throw;
00348     }
00349   }
00350 
00351   pluginLoader.unload();
00352 
00353   try
00354   {
00355     ctkPluginArchive* archive = new ctkPluginArchive(m_PluginStorage, location, localPath,
00356                                                pluginId);;
00357 
00358     statement = "UPDATE Plugins SET SymbolicName=?,Version=? WHERE ID=?";
00359     QString versionString = archive->getAttribute(PluginConstants::PLUGIN_VERSION);
00360     bindValues.clear();
00361     bindValues.append(archive->getAttribute(PluginConstants::PLUGIN_SYMBOLICNAME));
00362     bindValues.append(versionString.isEmpty() ? "0.0.0" : versionString);
00363     bindValues.append(pluginId);
00364 
00365     if (!createArchive)
00366     {
00367       delete archive;
00368       archive = 0;
00369     }
00370 
00371     executeQuery(&query, statement, bindValues);
00372 
00373     commitTransaction(&query);
00374 
00375     return archive;
00376   }
00377   catch (...)
00378   {
00379       rollbackTransaction(&query);
00380       throw;
00381   }
00382 
00383 }
00384 
00385 QStringList ctkPluginDatabase::findResourcesPath(long pluginId, const QString& path) const
00386 {
00387   checkConnection();
00388 
00389   QString statement = "SELECT SUBSTR(ResourcePath,?) FROM PluginResources WHERE PluginID=? AND SUBSTR(ResourcePath,1,?)=?";
00390 
00391   QString resourcePath = path.startsWith('/') ? path : QString("/") + path;
00392   if (!resourcePath.endsWith('/'))
00393     resourcePath += "/";
00394 
00395   QList<QVariant> bindValues;
00396   bindValues.append(resourcePath.size()+1);
00397   bindValues.append(qlonglong(pluginId));
00398   bindValues.append(resourcePath.size());
00399   bindValues.append(resourcePath);
00400 
00401   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
00402   QSqlQuery query(database);
00403 
00404   executeQuery(&query, statement, bindValues);
00405 
00406   QStringList paths;
00407   while (query.next())
00408   {
00409     QString currPath = query.value(EBindIndex).toString();
00410     int slashIndex = currPath.indexOf('/');
00411     if (slashIndex > 0)
00412     {
00413       currPath = currPath.left(slashIndex+1);
00414     }
00415 
00416     paths << currPath;
00417   }
00418 
00419   return paths;
00420 }
00421 
00422 void ctkPluginDatabase::removeArchive(const ctkPluginArchive *pa)
00423 {
00424   checkConnection();
00425 
00426   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
00427   QSqlQuery query(database);
00428 
00429   QString statement = "DELETE FROM Plugins WHERE ID=?";
00430 
00431   QList<QVariant> bindValues;
00432   bindValues.append(pa->getPluginId());
00433 
00434   executeQuery(&query, statement, bindValues);
00435 }
00436 
00437 void ctkPluginDatabase::executeQuery(QSqlQuery *query, const QString &statement, const QList<QVariant> &bindValues) const
00438 {
00439   Q_ASSERT(query != 0);
00440 
00441   bool success = false;
00442   enum {Prepare =0 , Execute=1};
00443 
00444   for (int stage=Prepare; stage <= Execute; ++stage)
00445   {
00446     if ( stage == Prepare)
00447       success = query->prepare(statement);
00448     else // stage == Execute
00449       success = query->exec();
00450 
00451     if (!success)
00452     {
00453       QString errorText = "Problem: Could not %1 statement: %2\n"
00454               "Reason: %3\n"
00455               "Parameters: %4\n";
00456       QString parameters;
00457       if (bindValues.count() > 0)
00458       {
00459         for (int i = 0; i < bindValues.count(); ++i)
00460         {
00461           parameters.append(QString("\n\t[") + QString::number(i) + "]: " + bindValues.at(i).toString());
00462         }
00463       }
00464       else
00465       {
00466         parameters = "None";
00467       }
00468 
00469       ctkPluginDatabaseException::Type errorType;
00470       int result = query->lastError().number();
00471       if (result == 26 || result == 11) //SQLILTE_NOTADB || SQLITE_CORRUPT
00472       {
00473         qWarning() << "ctkPluginFramework:- Database file is corrupt or invalid:" << getDatabasePath();
00474         errorType = ctkPluginDatabaseException::DB_FILE_INVALID;
00475       }
00476       else if (result == 8) //SQLITE_READONLY
00477         errorType = ctkPluginDatabaseException::DB_WRITE_ERROR;
00478       else
00479         errorType = ctkPluginDatabaseException::DB_SQL_ERROR;
00480 
00481       query->finish();
00482       query->clear();
00483 
00484       throw ctkPluginDatabaseException(errorText.arg(stage == Prepare ? "prepare":"execute")
00485                   .arg(statement).arg(query->lastError().text()).arg(parameters), errorType);
00486     }
00487 
00488     if (stage == Prepare)
00489     {
00490       foreach(const QVariant &bindValue, bindValues)
00491         query->addBindValue(bindValue);
00492     }
00493   }
00494 }
00495 
00496 
00497 void ctkPluginDatabase::close()
00498 {
00499   if (m_isDatabaseOpen)
00500   {
00501     QSqlDatabase database = QSqlDatabase::database(m_connectionName, false);
00502     if (database.isValid())
00503     {
00504       if(database.isOpen())
00505       {
00506         database.close();
00507         m_isDatabaseOpen = false;
00508         return;
00509       }
00510     }
00511     else
00512     {
00513       throw ctkPluginDatabaseException(QString("Problem closing database: Invalid connection %1").arg(m_connectionName));
00514     }
00515   }
00516 }
00517 
00518 
00519 void ctkPluginDatabase::setDatabasePath(const QString &databasePath)
00520 {
00521     m_databasePath = QDir::toNativeSeparators(databasePath);
00522 }
00523 
00524 
00525 QString ctkPluginDatabase::getDatabasePath() const
00526 {
00527     QString path;
00528     if(m_databasePath.isEmpty())
00529     {
00530       QSettings settings(QSettings::UserScope, "commontk", QApplication::applicationName());
00531       path = settings.value("PluginDB/Path").toString();
00532       if (path.isEmpty())
00533       {
00534         path = QDir::currentPath();
00535         if (path.lastIndexOf(PLUGINDATABASE_PATH_SEPARATOR) != path.length() -1)
00536         {
00537           path.append(PLUGINDATABASE_PATH_SEPARATOR);
00538         }
00539         path.append(PLUGINDATABASE);
00540       }
00541       path = QDir::toNativeSeparators(path);
00542     }
00543     else
00544     {
00545       path = m_databasePath;
00546     }
00547 
00548     return path;
00549 }
00550 
00551 
00552 QByteArray ctkPluginDatabase::getPluginResource(long pluginId, const QString& res) const
00553 {
00554   checkConnection();
00555 
00556   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
00557   QSqlQuery query(database);
00558 
00559   QString statement = "SELECT Resource FROM PluginResources WHERE PluginID=? AND ResourcePath=?";
00560 
00561   QString resourcePath = res.startsWith('/') ? res : QString("/") + res;
00562   QList<QVariant> bindValues;
00563   bindValues.append(qlonglong(pluginId));
00564   bindValues.append(resourcePath);
00565 
00566   executeQuery(&query, statement, bindValues);
00567 
00568   if (query.next())
00569   {
00570     return query.value(EBindIndex).toByteArray();
00571   }
00572 
00573   return QByteArray();
00574 }
00575 
00576 
00577 void ctkPluginDatabase::createTables()
00578 {
00579     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
00580     QSqlQuery query(database);
00581 
00582     //Begin Transaction
00583     beginTransaction(&query, Write);
00584 
00585     QString statement("CREATE TABLE Plugins("
00586                       "ID INTEGER PRIMARY KEY,"
00587                       "Location TEXT NOT NULL UNIQUE,"
00588                       "LocalPath TEXT NOT NULL UNIQUE,"
00589                       "SymbolicName TEXT NOT NULL,"
00590                       "Version TEXT NOT NULL,"
00591                       "State INTEGER NOT NULL,"
00592                       "Timestamp TEXT NOT NULL)");
00593     try
00594     {
00595       executeQuery(&query, statement);
00596     }
00597     catch (...)
00598     {
00599       rollbackTransaction(&query);
00600       throw;
00601     }
00602 
00603     statement = "CREATE TABLE PluginResources("
00604                 "PluginID INTEGER NOT NULL,"
00605                 "ResourcePath TEXT NOT NULL, "
00606                 "Resource BLOB NOT NULL,"
00607                 "FOREIGN KEY(PluginID) REFERENCES Plugins(ID) ON DELETE CASCADE)";
00608     try
00609     {
00610       executeQuery(&query, statement);
00611     }
00612     catch (...)
00613     {
00614       rollbackTransaction(&query);
00615       throw;
00616     }
00617 
00618     try
00619     {
00620       commitTransaction(&query);
00621     }
00622     catch (...)
00623     {
00624       rollbackTransaction(&query);
00625       throw;
00626     }
00627 
00628 }
00629 
00630 
00631 bool ctkPluginDatabase::checkTables() const
00632 {
00633   bool bTables(false);
00634   QStringList tables = QSqlDatabase::database(m_connectionName).tables();
00635   if (tables.contains(PLUGINS_TABLE)
00636       && tables.contains(PLUGIN_RESOURCES_TABLE))
00637   {
00638     bTables = true;
00639   }
00640   return bTables;
00641 }
00642 
00643 
00644 bool ctkPluginDatabase::dropTables()
00645 {
00646   //Execute transaction for deleting the database tables
00647   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
00648   QSqlQuery query(database);
00649   QStringList expectedTables;
00650   expectedTables << PLUGINS_TABLE << PLUGIN_RESOURCES_TABLE;
00651 
00652   if (database.tables().count() > 0)
00653   {
00654     beginTransaction(&query, Write);
00655     QStringList actualTables = database.tables();
00656 
00657     foreach(const QString expectedTable, expectedTables)
00658     {
00659       if (actualTables.contains(expectedTable))
00660       {
00661         try
00662         {
00663           executeQuery(&query, QString("DROP TABLE ") + expectedTable);
00664         }
00665         catch (...)
00666         {
00667           rollbackTransaction(&query);
00668           throw;
00669         }
00670       }
00671       try
00672       {
00673         commitTransaction(&query);
00674       }
00675       catch (...)
00676       {
00677         rollbackTransaction(&query);
00678         throw;
00679       }
00680     }
00681   }
00682 }
00683 
00684 
00685 bool ctkPluginDatabase::isOpen() const
00686 {
00687   return m_isDatabaseOpen;
00688 }
00689 
00690 
00691 void ctkPluginDatabase::checkConnection() const
00692 {
00693   if(!m_isDatabaseOpen)
00694   {
00695     throw ctkPluginDatabaseException("Database not open.", ctkPluginDatabaseException::DB_NOT_OPEN_ERROR);
00696   }
00697 
00698   if (!QSqlDatabase::database(m_connectionName).isValid())
00699   {
00700     throw ctkPluginDatabaseException(QString("Database connection invalid: %1").arg(m_connectionName),
00701                                   ctkPluginDatabaseException::DB_CONNECTION_INVALID);
00702   }
00703 }
00704 
00705 
00706 void ctkPluginDatabase::beginTransaction(QSqlQuery *query, TransactionType type)
00707 {
00708   bool success;
00709   if (type == Read)
00710       success = query->exec(QLatin1String("BEGIN"));
00711   else
00712       success = query->exec(QLatin1String("BEGIN IMMEDIATE"));
00713 
00714   if (!success) {
00715       int result = query->lastError().number();
00716       if (result == 26 || result == 11) //SQLITE_NOTADB || SQLITE_CORRUPT
00717       {
00718         throw ctkPluginDatabaseException(QString("ctkPluginFramework: Database file is corrupt or invalid: %1").arg(getDatabasePath()),
00719                                       ctkPluginDatabaseException::DB_FILE_INVALID);
00720       }
00721       else if (result == 8) //SQLITE_READONLY
00722       {
00723         throw ctkPluginDatabaseException(QString("ctkPluginFramework: Insufficient permissions to write to database: %1").arg(getDatabasePath()),
00724                                       ctkPluginDatabaseException::DB_WRITE_ERROR);
00725       }
00726       else
00727         throw ctkPluginDatabaseException(QString("ctkPluginFramework: ") + query->lastError().text(),
00728                                       ctkPluginDatabaseException::DB_SQL_ERROR);
00729   }
00730 
00731 }
00732 
00733 
00734 void ctkPluginDatabase::commitTransaction(QSqlQuery *query)
00735 {
00736   Q_ASSERT(query != 0);
00737   query->finish();
00738   query->clear();
00739   if (!query->exec(QLatin1String("COMMIT")))
00740   {
00741     throw ctkPluginDatabaseException(QString("ctkPluginFramework: ") + query->lastError().text(),
00742                                   ctkPluginDatabaseException::DB_SQL_ERROR);
00743   }
00744 }
00745 
00746 
00747 void ctkPluginDatabase::rollbackTransaction(QSqlQuery *query)
00748 {
00749   Q_ASSERT(query !=0);
00750   query->finish();
00751   query->clear();
00752 
00753   if (!query->exec(QLatin1String("ROLLBACK")))
00754   {
00755     throw ctkPluginDatabaseException(QString("ctkPluginFramework: ") + query->lastError().text(),
00756                                   ctkPluginDatabaseException::DB_SQL_ERROR);
00757   }
00758 }
00759 
00760 QList<ctkPluginArchive*> ctkPluginDatabase::getPluginArchives() const
00761 {
00762   checkConnection();
00763 
00764   QSqlQuery query(QSqlDatabase::database(m_connectionName));
00765   QString statement("SELECT ID, Location, LocalPath FROM Plugins WHERE State != ?");
00766   QList<QVariant> bindValues;
00767   bindValues.append(ctkPlugin::UNINSTALLED);
00768 
00769   executeQuery(&query, statement, bindValues);
00770 
00771   QList<ctkPluginArchive*> archives;
00772   while (query.next())
00773   {
00774     const long id = query.value(EBindIndex).toLongLong();
00775     const QUrl location(query.value(EBindIndex1).toString());
00776     const QString localPath(query.value(EBindIndex2).toString());
00777 
00778     if (id <= 0 || location.isEmpty() || localPath.isEmpty())
00779     {
00780       throw ctkPluginDatabaseException(QString("Database integrity corrupted, row %1 contains empty values.").arg(id),
00781                                     ctkPluginDatabaseException::DB_FILE_INVALID);
00782     }
00783 
00784     try
00785     {
00786       ctkPluginArchive* pa = new ctkPluginArchive(m_PluginStorage, location, localPath, id);
00787       archives.append(pa);
00788     }
00789     catch (const ctkPluginException& exc)
00790     {
00791       qWarning() << exc;
00792     }
00793   }
00794 
00795   return archives;
00796 
00797 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines