You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesvn/src/svnqt/cache/LogCache.cpp

337 lines
9.0 KiB

#include "LogCache.hpp"
#include <tqdir.h>
#include <tqsql.h>
#include <tqsqldatabase.h>
#include <tqthreadstorage.h>
#include <tqmap.h>
#include "svnqt/path.hpp"
#include "svnqt/cache/DatabaseException.hpp"
#ifndef NO_SQLITE3
#define SQLTYPE "TQSQLITE3"
#else
#define SQLTYPE "TQSQLITE"
#endif
#define SQLMAIN "logmain-logcache"
#define SQLMAINTABLE "logdb"
namespace svn {
namespace cache {
LogCache* LogCache::mSelf = 0;
class ThreadDBStore
{
public:
ThreadDBStore(){
m_DB=0;
}
~ThreadDBStore(){
m_DB=0;
TQSqlDatabase::removeDatabase(key);
TQMap<TQString,TQString>::Iterator it;
for (it=reposCacheNames.begin();it!=reposCacheNames.end();++it) {
TQSqlDatabase::removeDatabase(it.data());
}
}
TQDataBase m_DB;
TQString key;
TQMap<TQString,TQString> reposCacheNames;
};
class LogCacheData
{
protected:
TQMutex m_singleDbMutex;
public:
LogCacheData(){}
~LogCacheData(){
if (m_mainDB.hasLocalData()) {
m_mainDB.setLocalData(0L);
}
}
bool checkReposDb(TQDataBase aDb)
{
if (!aDb) {
return false;
}
if (!aDb->open()) {
return false;
}
TQSqlQuery _q(TQString(), aDb);
TQStringList list = aDb->tables();
if (list.find("logentries")==list.end()) {
aDb->transaction();
_q.exec("CREATE TABLE \"logentries\" (\"revision\" INTEGER UNIQUE,\"date\" INTEGER,\"author\" TEXT, \"message\" TEXT)");
aDb->commit();
}
if (list.find("changeditems")==list.end()) {
aDb->transaction();
_q.exec("CREATE TABLE \"changeditems\" (\"revision\" INTEGER,\"changeditem\" TEXT,\"action\" TEXT,\"copyfrom\" TEXT,\"copyfromrev\" INTEGER, PRIMARY KEY(revision,changeditem,action))");
aDb->commit();
}
list = aDb->tables();
if (list.find("logentries")==list.end() || list.find("changeditems")==list.end()) {
return false;
}
return true;
}
TQString createReposDB(const svn::Path&reposroot) {
TQMutexLocker locker( &m_singleDbMutex );
TQDataBase _mdb = getMainDB();
TQSqlQuery query1(TQString(),_mdb);
TQString q("insert into "+TQString(SQLMAINTABLE)+" (reposroot) VALUES('"+reposroot+"')");
_mdb->transaction();
query1.exec(q);
_mdb->commit();
TQSqlQuery query(TQString(),_mdb);
query.prepare(s_reposSelect);
query.bindValue(0,reposroot.native());
query.exec();
TQString db;
if (query.lastError().type()==TQSqlError::None && query.next()) {
db = query.value(0).toString();
}
else {
tqDebug("Error select_01: %s (%s)",query.lastError().text().TOUTF8().data(),
query.lastQuery().TOUTF8().data());
}
if (!db.isEmpty()) {
TQString fulldb = m_BasePath+"/"+db+".db";
TQDataBase _db = TQSqlDatabase::addDatabase(SQLTYPE,"tmpdb");
_db->setDatabaseName(fulldb);
if (!checkReposDb(_db)) {
}
TQSqlDatabase::removeDatabase("tmpdb");
}
return db;
}
TQDataBase getReposDB(const svn::Path&reposroot) {
if (!getMainDB()) {
return 0;
}
bool checkDone = false;
// make sure path is correct eg. without traling slashes.
TQString dbFile;
TQSqlQuery c(TQString(),getMainDB());
c.prepare(s_reposSelect);
c.bindValue(0,reposroot.native());
c.exec();
//tqDebug("Check for path: "+reposroot.native());
// only the first one
if ( c.next() ) {
/* tqDebug( c.value(0).toString() + ": " +
c.value(0).toString() );*/
dbFile = c.value(0).toString();
}
if (dbFile.isEmpty()) {
dbFile = createReposDB(reposroot);
if (dbFile.isEmpty()) {
return 0;
}
checkDone=true;
}
if (m_mainDB.localData()->reposCacheNames.find(dbFile)!=m_mainDB.localData()->reposCacheNames.end()) {
return TQSqlDatabase::database(m_mainDB.localData()->reposCacheNames[dbFile]);
}
int i = 0;
TQString _key = dbFile;
while (TQSqlDatabase::contains(_key)) {
_key = TQString("%1-%2").arg(dbFile).arg(i++);
}
// tqDebug("The repository key is now: %s",_key.TOUTF8().data());
TQDataBase _db = TQSqlDatabase::addDatabase(SQLTYPE,_key);
if (!_db) {
return 0;
}
TQString fulldb = m_BasePath+"/"+dbFile+".db";
_db->setDatabaseName(fulldb);
// tqDebug("try database open %s",fulldb.TOUTF8().data());
if (!checkReposDb(_db)) {
tqDebug("no DB opened");
_db = 0;
} else {
tqDebug("Insert into map");
m_mainDB.localData()->reposCacheNames[dbFile]=_key;
}
return _db;
}
TQDataBase getMainDB()const
{
if (!m_mainDB.hasLocalData()) {
unsigned i=0;
TQString _key = SQLMAIN;
while (TQSqlDatabase::contains(_key)) {
_key.sprintf("%s-%i",SQLMAIN,i++);
}
tqDebug("The key is now: %s",_key.TOUTF8().data());
TQDataBase db = TQSqlDatabase::addDatabase(SQLTYPE,_key);
db->setDatabaseName(m_BasePath+"/maindb.db");
if (!db->open()) {
tqWarning("Failed to open main database: %s", db->lastError().text().TOUTF8().data());
} 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 {
return 0;
}
}
TQString m_BasePath;
mutable TQThreadStorage<ThreadDBStore*> m_mainDB;
static const TQString s_reposSelect;
};
TQString LogCache::s_CACHE_FOLDER="logcache";
const TQString LogCacheData::s_reposSelect=TQString("SELECT id from ")+TQString(SQLMAINTABLE)+TQString(" where reposroot=? ORDER by id DESC");
/*!
\fn svn::cache::LogCache::LogCache()
*/
LogCache::LogCache()
{
m_BasePath = TQDir::HOMEDIR()+"/.svnqt";
setupCachePath();
}
LogCache::LogCache(const TQString&aBasePath)
{
if (mSelf) {
delete mSelf;
}
mSelf=this;
if (aBasePath.isEmpty()) {
m_BasePath=TQDir::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;
TQDir 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()
{
TQDataBase mainDB = m_CacheData->getMainDB();
if (!mainDB || !mainDB->open()) {
tqWarning("Failed to open main database: %s", (mainDB?mainDB->lastError().text().TOUTF8().data():"No database object."));
} else {
TQSqlQuery q(TQString(), mainDB);
mainDB->transaction();
if (!q.exec("CREATE TABLE IF NOT EXISTS \""+TQString(SQLMAINTABLE)+"\" (\"reposroot\" TEXT,\"id\" INTEGER PRIMARY KEY NOT NULL);")) {
tqWarning("Failed create main database: %s", mainDB->lastError().text().TOUTF8().data());
}
mainDB->commit();
}
}
}
}
/*!
\fn svn::cache::LogCache::self()
*/
svn::cache::LogCache* svn::cache::LogCache::self()
{
if (!mSelf) {
mSelf=new LogCache();
}
return mSelf;
}
/*!
\fn svn::cache::LogCache::reposDb()
*/
TQDataBase svn::cache::LogCache::reposDb(const TQString&aRepository)
{
// tqDebug("reposDB");
return m_CacheData->getReposDB(aRepository);
}
/*!
\fn svn::cache::LogCache::cachedRepositories()const
*/
TQStringList svn::cache::LogCache::cachedRepositories()const
{
static TQString s_q(TQString("select \"reposroot\" from ")+TQString(SQLMAINTABLE)+TQString("order by reposroot"));
TQDataBase mainDB = m_CacheData->getMainDB();
TQStringList _res;
if (!mainDB || !mainDB->open()) {
tqWarning("Failed to open main database.");
return _res;
}
TQSqlQuery cur(TQString(),mainDB);
cur.prepare(s_q);
if (!cur.exec()) {
tqDebug("%s", cur.lastError().text().TOUTF8().data());
throw svn::cache::DatabaseException(TQString("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
{
TQDataBase mainDB = m_CacheData->getMainDB();
if (!mainDB || !mainDB->open()) {
return false;
}
return true;
}