diff options
Diffstat (limited to 'src/svnqt/cache/LogCache.cpp')
-rw-r--r-- | src/svnqt/cache/LogCache.cpp | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/src/svnqt/cache/LogCache.cpp b/src/svnqt/cache/LogCache.cpp new file mode 100644 index 0000000..6356c6f --- /dev/null +++ b/src/svnqt/cache/LogCache.cpp @@ -0,0 +1,468 @@ +#include "LogCache.hpp" + +#include <qdir.h> +#include <qsql.h> +#include <qsqldatabase.h> +#if QT_VERSION < 0x040000 +#include <qthreadstorage.h> +#else +#include <QMutex> +#include <QThreadStorage> +#include <QSqlError> +#include <QSqlQuery> +#include <QVariant> +#endif +#include <qmap.h> + +#include "svnqt/path.hpp" +#include "svnqt/cache/DatabaseException.hpp" + +#ifndef NO_SQLITE3 +#include "sqlite3/qsql_sqlite3.h" +#define SQLTYPE "QSQLITE3" +#else +#define SQLTYPE "QSQLITE" +#endif + +#define SQLMAIN "logmain-logcache" +#define SQLMAINTABLE "logdb" + +namespace svn { +namespace cache { + +LogCache* LogCache::mSelf = 0; + +class ThreadDBStore +{ +public: + ThreadDBStore(){ +#if QT_VERSION < 0x040000 + m_DB=0; +#else + m_DB=QSqlDatabase(); +#endif + } + ~ThreadDBStore(){ +#if QT_VERSION < 0x040000 + m_DB=0; +#else + m_DB=QSqlDatabase(); +#endif + QSqlDatabase::removeDatabase(key); + QMap<QString,QString>::Iterator it; + for (it=reposCacheNames.begin();it!=reposCacheNames.end();++it) { +#if QT_VERSION < 0x040000 + QSqlDatabase::removeDatabase(it.data()); +#else + QSqlDatabase::removeDatabase(it.value()); +#endif + } + } + + QDataBase m_DB; + QString key; + QMap<QString,QString> reposCacheNames; +}; + +class LogCacheData +{ + +protected: + QMutex m_singleDbMutex; + +public: + LogCacheData(){} + ~LogCacheData(){ + if (m_mainDB.hasLocalData()) { + m_mainDB.setLocalData(0L); + } + } + + bool checkReposDb(QDataBase aDb) + { +#if QT_VERSION < 0x040000 + if (!aDb) { + return false; + } + if (!aDb->open()) { + return false; + } +#else + if (!aDb.open()) { + return false; + } +#endif + + QSqlQuery _q(QString::null, aDb); +#if QT_VERSION < 0x040000 + QStringList list = aDb->tables(); +#else + QStringList list = aDb.tables(); +#endif + +#if QT_VERSION < 0x040000 + if (list.find("logentries")==list.end()) { + aDb->transaction(); +#else + if (list.indexOf("logentries")==-1) { + aDb.transaction(); +#endif + _q.exec("CREATE TABLE \"logentries\" (\"revision\" INTEGER UNIQUE,\"date\" INTEGER,\"author\" TEXT, \"message\" TEXT)"); +#if QT_VERSION < 0x040000 + aDb->commit(); +#else + aDb.commit(); +#endif + } +#if QT_VERSION < 0x040000 + if (list.find("changeditems")==list.end()) { + aDb->transaction(); +#else + if (list.indexOf("changeditems")==-1) { + aDb.transaction(); +#endif + _q.exec("CREATE TABLE \"changeditems\" (\"revision\" INTEGER,\"changeditem\" TEXT,\"action\" TEXT,\"copyfrom\" TEXT,\"copyfromrev\" INTEGER, PRIMARY KEY(revision,changeditem,action))"); +#if QT_VERSION < 0x040000 + aDb->commit(); +#else + aDb.commit(); +#endif + } +#if QT_VERSION < 0x040000 + list = aDb->tables(); + if (list.find("logentries")==list.end() || list.find("changeditems")==list.end()) { +#else + list = aDb.tables(); + if (list.indexOf("logentries")==-1 || list.indexOf("changeditems")==-1) { +#endif + return false; + } + return true; + } + + QString createReposDB(const svn::Path&reposroot) { + QMutexLocker locker( &m_singleDbMutex ); + + QDataBase _mdb = getMainDB(); + + QSqlQuery query1(QString::null,_mdb); + QString q("insert into "+QString(SQLMAINTABLE)+" (reposroot) VALUES('"+reposroot+"')"); +#if QT_VERSION < 0x040000 + _mdb->transaction(); +#else + _mdb.transaction(); +#endif + + query1.exec(q); +#if QT_VERSION < 0x040000 + _mdb->commit(); +#else + _mdb.commit(); +#endif + QSqlQuery query(QString::null,_mdb); + query.prepare(s_reposSelect); + query.bindValue(0,reposroot.native()); + query.exec(); + QString db; +#if QT_VERSION < 0x040000 + if (query.lastError().type()==QSqlError::None && query.next()) { +#else + if (query.lastError().type()==QSqlError::NoError && query.next()) { +#endif + db = query.value(0).toString(); + } + else { + qDebug("Error select_01: %s (%s)",query.lastError().text().TOUTF8().data(), + query.lastQuery().TOUTF8().data()); + } + if (!db.isEmpty()) { + QString fulldb = m_BasePath+"/"+db+".db"; + QDataBase _db = QSqlDatabase::addDatabase(SQLTYPE,"tmpdb"); +#if QT_VERSION < 0x040000 + _db->setDatabaseName(fulldb); +#else + _db.setDatabaseName(fulldb); +#endif + if (!checkReposDb(_db)) { + } + QSqlDatabase::removeDatabase("tmpdb"); + } + return db; + } + + QDataBase getReposDB(const svn::Path&reposroot) { +#if QT_VERSION < 0x040000 + if (!getMainDB()) { + return 0; +#else + if (!getMainDB().isValid()) { + return QDataBase(); +#endif + } + bool checkDone = false; + // make sure path is correct eg. without traling slashes. + QString dbFile; + QSqlQuery c(QString::null,getMainDB()); + c.prepare(s_reposSelect); + c.bindValue(0,reposroot.native()); + c.exec(); + +#if QT_VERSION < 0x040000 + //qDebug("Check for path: "+reposroot.native()); +#endif + + // only the first one + if ( c.next() ) { +#if QT_VERSION < 0x040000 +/* qDebug( c.value(0).toString() + ": " + + c.value(0).toString() );*/ +#endif + dbFile = c.value(0).toString(); + } + if (dbFile.isEmpty()) { + dbFile = createReposDB(reposroot); + if (dbFile.isEmpty()) { +#if QT_VERSION < 0x040000 + return 0; +#else + return QSqlDatabase(); +#endif + } + checkDone=true; + } + if (m_mainDB.localData()->reposCacheNames.find(dbFile)!=m_mainDB.localData()->reposCacheNames.end()) { + return QSqlDatabase::database(m_mainDB.localData()->reposCacheNames[dbFile]); + } + int i = 0; + QString _key = dbFile; + while (QSqlDatabase::contains(_key)) { + _key = QString("%1-%2").arg(dbFile).arg(i++); + } +// qDebug("The repository key is now: %s",_key.TOUTF8().data()); + QDataBase _db = QSqlDatabase::addDatabase(SQLTYPE,_key); +#if QT_VERSION < 0x040000 + if (!_db) { + return 0; + } +#endif + QString fulldb = m_BasePath+"/"+dbFile+".db"; +#if QT_VERSION < 0x040000 + _db->setDatabaseName(fulldb); +#else + _db.setDatabaseName(fulldb); +#endif +// qDebug("try database open %s",fulldb.TOUTF8().data()); + if (!checkReposDb(_db)) { + qDebug("no DB opened"); +#if QT_VERSION < 0x040000 + _db = 0; +#else + _db = QSqlDatabase(); +#endif + } else { + qDebug("Insert into map"); + m_mainDB.localData()->reposCacheNames[dbFile]=_key; + } + return _db; + } + + QDataBase getMainDB()const + { + if (!m_mainDB.hasLocalData()) { + unsigned i=0; + QString _key = SQLMAIN; + while (QSqlDatabase::contains(_key)) { + _key.sprintf("%s-%i",SQLMAIN,i++); + } + qDebug("The key is now: %s",_key.TOUTF8().data()); + + QDataBase db = QSqlDatabase::addDatabase(SQLTYPE,_key); +#if QT_VERSION < 0x040000 + db->setDatabaseName(m_BasePath+"/maindb.db"); + if (!db->open()) { +#else + db.setDatabaseName(m_BasePath+"/maindb.db"); + if (!db.open()) { +#endif +#if QT_VERSION < 0x040000 + qWarning("Failed to open main database: " + db->lastError().text()); +#endif + } else { + m_mainDB.setLocalData(new ThreadDBStore); + m_mainDB.localData()->key = _key; + m_mainDB.localData()->m_DB = db; + } + } + if (m_mainDB.hasLocalData()) { + return m_mainDB.localData()->m_DB; + } else { +#if QT_VERSION < 0x040000 + return 0; +#else + return QSqlDatabase(); +#endif + } + } + QString m_BasePath; + + mutable QThreadStorage<ThreadDBStore*> m_mainDB; + + static const QString s_reposSelect; +}; + + +QString LogCache::s_CACHE_FOLDER="logcache"; +const QString LogCacheData::s_reposSelect=QString("SELECT id from ")+QString(SQLMAINTABLE)+QString(" where reposroot=? ORDER by id DESC"); + +/*! + \fn svn::cache::LogCache::LogCache() + */ +LogCache::LogCache() +{ + m_BasePath = QDir::HOMEDIR()+"/.svnqt"; + setupCachePath(); +} + +LogCache::LogCache(const QString&aBasePath) +{ + if (mSelf) { + delete mSelf; + } + mSelf=this; + if (aBasePath.isEmpty()) { + m_BasePath=QDir::HOMEDIR()+"/.svnqt"; + } else { + m_BasePath=aBasePath; + } + setupCachePath(); +} + + +LogCache::~LogCache() +{ +} + +/*! + \fn svn::cache::LogCache::setupCachePath() + */ +void LogCache::setupCachePath() +{ + m_CacheData = new LogCacheData; + m_CacheData->m_BasePath=m_BasePath; + QDir d; + if (!d.exists(m_BasePath)) { + d.mkdir(m_BasePath); + } + m_BasePath=m_BasePath+"/"+s_CACHE_FOLDER; + if (!d.exists(m_BasePath)) { + d.mkdir(m_BasePath); + } + m_CacheData->m_BasePath=m_BasePath; + if (d.exists(m_BasePath)) { + setupMainDb(); + } +} + +void LogCache::setupMainDb() +{ +#ifndef NO_SQLITE3 + if (!QSqlDatabase::isDriverAvailable(SQLTYPE)) { + QSqlDatabase::registerSqlDriver(SQLTYPE,new QSqlDriverCreator<QSQLite3Driver>); + } +#endif + QDataBase mainDB = m_CacheData->getMainDB(); +#if QT_VERSION < 0x040000 + if (!mainDB || !mainDB->open()) { + qWarning("Failed to open main database: " + (mainDB?mainDB->lastError().text():"No database object.")); +#else + if (!mainDB.isValid()) { + qWarning("Failed to open main database."); +#endif + } else { + QSqlQuery q(QString::null, mainDB); +#if QT_VERSION < 0x040000 + mainDB->transaction(); +#else + mainDB.transaction(); +#endif + if (!q.exec("CREATE TABLE IF NOT EXISTS \""+QString(SQLMAINTABLE)+"\" (\"reposroot\" TEXT,\"id\" INTEGER PRIMARY KEY NOT NULL);")) { +#if QT_VERSION < 0x040000 + qWarning("Failed create main database: " + mainDB->lastError().text()); +#endif + } +#if QT_VERSION < 0x040000 + mainDB->commit(); +#else + mainDB.commit(); +#endif + } +} + +} +} + + +/*! + \fn svn::cache::LogCache::self() + */ +svn::cache::LogCache* svn::cache::LogCache::self() +{ + if (!mSelf) { + mSelf=new LogCache(); + } + return mSelf; +} + + +/*! + \fn svn::cache::LogCache::reposDb() + */ +QDataBase svn::cache::LogCache::reposDb(const QString&aRepository) +{ +// qDebug("reposDB"); + return m_CacheData->getReposDB(aRepository); +} + + +/*! + \fn svn::cache::LogCache::cachedRepositories()const + */ +QStringList svn::cache::LogCache::cachedRepositories()const +{ + static QString s_q(QString("select \"reposroot\" from ")+QString(SQLMAINTABLE)+QString("order by reposroot")); + QDataBase mainDB = m_CacheData->getMainDB(); + QStringList _res; +#if QT_VERSION < 0x040000 + if (!mainDB || !mainDB->open()) { +#else + if (!mainDB.isValid()) { +#endif + qWarning("Failed to open main database."); + return _res; + } + QSqlQuery cur(QString::null,mainDB); + cur.prepare(s_q); + if (!cur.exec()) { + qDebug(cur.lastError().text().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not retrieve values: ")+cur.lastError().text()); + return _res; + } + while (cur.next()) { + _res.append(cur.value(0).toString()); + } + + return _res; +} + +bool svn::cache::LogCache::valid()const +{ + QDataBase mainDB = m_CacheData->getMainDB(); +#if QT_VERSION < 0x040000 + if (!mainDB || !mainDB->open()) { +#else + if (!mainDB.isValid()) { +#endif + return false; + } + return true; +} |