File indexing completed on 2024-05-12 05:44:35
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2009 by Rajko Albrecht ral@alwins-world.de * 0003 * https://kde.org/applications/development/org.kde.kdesvn * 0004 * * 0005 * This program is free software; you can redistribute it and/or * 0006 * modify it under the terms of the GNU Lesser General Public * 0007 * License as published by the Free Software Foundation; either * 0008 * version 2.1 of the License, or (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0013 * Lesser General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU Lesser General Public * 0016 * License along with this program (in the file LGPL.txt); if not, * 0017 * write to the Free Software Foundation, Inc., 51 Franklin St, * 0018 * Fifth Floor, Boston, MA 02110-1301 USA * 0019 * * 0020 * This software consists of voluntary contributions made by many * 0021 * individuals. For exact contribution history, see the revision * 0022 * history and logs, available at https://commits.kde.org/kdesvn. * 0023 ***************************************************************************/ 0024 #include "ReposLog.h" 0025 0026 #include "LogCache.h" 0027 #include "svnqt/cache/DatabaseException.h" 0028 #include "svnqt/client.h" 0029 #include "svnqt/client_parameter.h" 0030 #include "svnqt/context_listener.h" 0031 #include "svnqt/info_entry.h" 0032 #include "svnqt/svnqttypes.h" 0033 0034 #include <QBuffer> 0035 #include <QDataStream> 0036 #include <QFileInfo> 0037 #include <QSqlDatabase> 0038 #include <QSqlError> 0039 #include <QSqlQuery> 0040 #include <QVariant> 0041 #define Q_LLONG qlonglong 0042 0043 class DatabaseLocker 0044 { 0045 public: 0046 DatabaseLocker(QSqlDatabase *db) 0047 : m_commited(false) 0048 , m_db(db) 0049 { 0050 m_db->transaction(); 0051 } 0052 ~DatabaseLocker() 0053 { 0054 if (!m_commited) { 0055 m_db->rollback(); 0056 } 0057 } 0058 0059 void commit() 0060 { 0061 if (m_commited) { 0062 return; 0063 } 0064 m_db->commit(); 0065 m_commited = true; 0066 } 0067 0068 protected: 0069 bool m_commited; 0070 QSqlDatabase *m_db; 0071 }; 0072 0073 /*! 0074 \fn svn::cache::ReposLog::ReposLog(svn::Client*aClient,const QString&) 0075 */ 0076 svn::cache::ReposLog::ReposLog(const svn::ClientP &aClient, const QString &aRepository) 0077 : m_Client(aClient) 0078 , m_Database() 0079 , m_ReposRoot(aRepository) 0080 , m_latestHead(svn::Revision::UNDEFINED) 0081 { 0082 if (!aRepository.isEmpty()) { 0083 m_Database = LogCache::self()->reposDb(aRepository); 0084 } 0085 } 0086 0087 /*! 0088 \fn svn::cache::ReposLog::latestHeadRev() 0089 */ 0090 svn::Revision svn::cache::ReposLog::latestHeadRev() 0091 { 0092 if (!m_Client || m_ReposRoot.isEmpty()) { 0093 return svn::Revision::UNDEFINED; 0094 } 0095 if (!m_Database.isValid()) { 0096 m_Database = LogCache::self()->reposDb(m_ReposRoot); 0097 if (!m_Database.isValid()) { 0098 return svn::Revision::UNDEFINED; 0099 } 0100 } 0101 /// no catch - exception has go trough... 0102 // qDebug("Getting headrev"); 0103 const svn::InfoEntries e = m_Client->info(m_ReposRoot, svn::DepthEmpty, svn::Revision::HEAD, svn::Revision::HEAD); 0104 if (e.count() < 1 || e[0].reposRoot().isEmpty()) { 0105 return svn::Revision::UNDEFINED; 0106 } 0107 // qDebug("Getting headrev done"); 0108 return e[0].revision(); 0109 } 0110 0111 /*! 0112 \fn svn::cache::ReposLog::latestCachedRev() 0113 */ 0114 svn::Revision svn::cache::ReposLog::latestCachedRev() 0115 { 0116 if (m_ReposRoot.isEmpty()) { 0117 return svn::Revision::UNDEFINED; 0118 } 0119 if (!m_Database.isValid()) { 0120 m_Database = LogCache::self()->reposDb(m_ReposRoot); 0121 if (!m_Database.isValid()) { 0122 return svn::Revision::UNDEFINED; 0123 } 0124 } 0125 static const QLatin1String q("select revision from 'logentries' order by revision DESC limit 1"); 0126 QSqlQuery _q(QString(), m_Database); 0127 if (!_q.exec(q)) { 0128 // qDebug() << _q.lastError().text(); 0129 return svn::Revision::UNDEFINED; 0130 } 0131 int _r; 0132 if (_q.isActive() && _q.next()) { 0133 // qDebug("Sel result: %s",_q.value(0).toString().toUtf8().data()); 0134 _r = _q.value(0).toInt(); 0135 } else { 0136 // qDebug() << _q.lastError().text(); 0137 return svn::Revision::UNDEFINED; 0138 } 0139 return _r; 0140 } 0141 0142 qlonglong svn::cache::ReposLog::count() const 0143 { 0144 if (!m_Database.isValid()) { 0145 m_Database = LogCache::self()->reposDb(m_ReposRoot); 0146 if (!m_Database.isValid()) { 0147 return svn::Revision::UNDEFINED; 0148 } 0149 } 0150 static const QLatin1String q("select count(*) from 'logentries'"); 0151 QSqlQuery _q(QString(), m_Database); 0152 if (!_q.exec(q)) { 0153 // qDebug() << _q.lastError().text(); 0154 return -1; 0155 } 0156 qlonglong _r; 0157 QVariant v; 0158 if (_q.isActive() && _q.next()) { 0159 // qDebug("Sel result: %s",_q.value(0).toString().toUtf8().data()); 0160 v = _q.value(0); 0161 if (v.canConvert(QVariant::LongLong)) { 0162 bool ok = false; 0163 _r = v.toLongLong(&ok); 0164 if (ok) { 0165 return _r; 0166 } 0167 } 0168 } 0169 return -1; 0170 } 0171 0172 qlonglong svn::cache::ReposLog::fileSize() const 0173 { 0174 if (!m_Database.isValid()) { 0175 m_Database = LogCache::self()->reposDb(m_ReposRoot); 0176 if (!m_Database.isValid()) { 0177 return -1; 0178 } 0179 } 0180 QFileInfo fi(m_Database.databaseName()); 0181 if (fi.exists()) { 0182 return fi.size(); 0183 } 0184 return -1; 0185 } 0186 0187 qlonglong svn::cache::ReposLog::itemCount() const 0188 { 0189 if (!m_Database.isValid()) { 0190 m_Database = LogCache::self()->reposDb(m_ReposRoot); 0191 if (!m_Database.isValid()) { 0192 return -1; 0193 } 0194 } 0195 static const QLatin1String q("select count(*) from 'changeditems'"); 0196 QSqlQuery _q(QString(), m_Database); 0197 if (!_q.exec(q)) { 0198 // qDebug() << _q.lastError().text(); 0199 return -1; 0200 } 0201 qlonglong _r; 0202 QVariant v; 0203 if (_q.isActive() && _q.next()) { 0204 // qDebug("Sel result: %s",_q.value(0).toString().toUtf8().data()); 0205 v = _q.value(0); 0206 if (v.canConvert(QVariant::LongLong)) { 0207 bool ok = false; 0208 _r = v.toLongLong(&ok); 0209 if (ok) { 0210 return _r; 0211 } 0212 } 0213 } 0214 return -1; 0215 } 0216 0217 bool svn::cache::ReposLog::checkFill(svn::Revision &start, svn::Revision &end, bool checkHead) 0218 { 0219 if (!m_Database.isValid()) { 0220 m_Database = LogCache::self()->reposDb(m_ReposRoot); 0221 if (!m_Database.isValid()) { 0222 return false; 0223 } 0224 } 0225 ContextP cp = m_Client->getContext(); 0226 // long long icount=0; 0227 0228 svn::Revision _latest = latestCachedRev(); 0229 // //qDebug("Latest cached rev: %i",_latest.revnum()); 0230 // //qDebug("End revision is: %s",end.toString().toUtf8().data()); 0231 0232 if (checkHead && _latest.revnum() >= latestHeadRev().revnum()) { 0233 return true; 0234 } 0235 0236 start = date2numberRev(start); 0237 end = date2numberRev(end); 0238 0239 // both should now one of START, HEAD or NUMBER 0240 if (start == svn::Revision::HEAD || (end == svn::Revision::NUMBER && start == svn::Revision::NUMBER && start.revnum() > end.revnum())) { 0241 svn::Revision tmp = start; 0242 start = end; 0243 end = tmp; 0244 } 0245 svn::Revision _rstart = _latest.revnum() + 1; 0246 svn::Revision _rend = end; 0247 if (_rend == svn::Revision::UNDEFINED) { 0248 // //qDebug("Setting end to Head"); 0249 _rend = svn::Revision::HEAD; 0250 } 0251 // no catch - exception should go outside. 0252 if (_rstart == 0) { 0253 _rstart = 1; 0254 } 0255 // //qDebug("Getting log %s -> %s",_rstart.toString().toUtf8().data(),_rend.toString().toUtf8().data()); 0256 if (_rend == svn::Revision::HEAD) { 0257 _rend = latestHeadRev(); 0258 } 0259 0260 if (_rend == svn::Revision::HEAD || _rend.revnum() > _latest.revnum()) { 0261 LogEntriesMap _internal; 0262 // //qDebug("Retrieving from network."); 0263 LogParameter params; 0264 0265 if (!m_Client->log( 0266 params.targets(m_ReposRoot).revisionRange(_rstart, _rend).peg(svn::Revision::UNDEFINED).discoverChangedPathes(true).strictNodeHistory(false), 0267 _internal)) { 0268 return false; 0269 } 0270 0271 DatabaseLocker l(&m_Database); 0272 for (const LogEntry &le : qAsConst(_internal)) { 0273 _insertLogEntry(le); 0274 if (cp && cp->getListener()) { 0275 // cp->getListener()->contextProgress(++icount,_internal.size()); 0276 if (cp->getListener()->contextCancel()) { 0277 throw DatabaseException(QStringLiteral("Could not retrieve values: User cancel.")); 0278 } 0279 } 0280 } 0281 l.commit(); 0282 } 0283 return true; 0284 } 0285 0286 bool svn::cache::ReposLog::fillCache(const svn::Revision &_end) 0287 { 0288 svn::Revision end = _end; 0289 svn::Revision start = latestCachedRev().revnum() + 1; 0290 return checkFill(start, end, false); 0291 } 0292 0293 /*! 0294 \fn svn::cache::ReposLog::simpleLog(const svn::Revision&start,const svn::Revision&end,LogEntriesMap&target) 0295 */ 0296 bool svn::cache::ReposLog::simpleLog(LogEntriesMap &target, const svn::Revision &_start, const svn::Revision &_end, bool noNetwork, const StringArray &exclude) 0297 { 0298 if (!m_Client || m_ReposRoot.isEmpty()) { 0299 return false; 0300 } 0301 target.clear(); 0302 ContextP cp = m_Client->getContext(); 0303 0304 svn::Revision end = _end; 0305 svn::Revision start = _start; 0306 if (!noNetwork) { 0307 if (!checkFill(start, end, true)) { 0308 return false; 0309 } 0310 } else { 0311 end = date2numberRev(end, noNetwork); 0312 start = date2numberRev(start, noNetwork); 0313 } 0314 0315 if (end == svn::Revision::HEAD) { 0316 end = latestCachedRev(); 0317 } 0318 if (start == svn::Revision::HEAD) { 0319 start = latestCachedRev(); 0320 } 0321 0322 QSqlQuery bcount(m_Database); 0323 bcount.prepare(QStringLiteral("select count(*) from logentries where revision<=? and revision>=?")); 0324 bcount.bindValue(0, Q_LLONG(end.revnum())); 0325 bcount.bindValue(1, Q_LLONG(start.revnum())); 0326 if (!bcount.exec()) { 0327 // qDebug() << bcount.lastError().text(); 0328 throw svn::cache::DatabaseException(QLatin1String("Could not retrieve count: ") + bcount.lastError().text()); 0329 } 0330 if (!bcount.next() || bcount.value(0).toLongLong() < 1) { 0331 // we didn't found logs with this parameters 0332 return false; 0333 } 0334 0335 QSqlQuery bcur(m_Database); 0336 bcur.setForwardOnly(true); 0337 bcur.prepare(QStringLiteral("select revision,author,date,message from logentries where revision<=? and revision>=?")); 0338 bcur.bindValue(0, Q_LLONG(end.revnum())); 0339 bcur.bindValue(1, Q_LLONG(start.revnum())); 0340 0341 if (!bcur.exec()) { 0342 throw svn::cache::DatabaseException(QLatin1String("Could not retrieve values: ") + bcur.lastError().text()); 0343 } 0344 0345 QString sItems(QStringLiteral("select changeditem,action,copyfrom,copyfromrev from changeditems where revision=?")); 0346 for (const QString &ex : exclude.data()) { 0347 sItems += QLatin1String(" and changeditem not like '") + ex + QLatin1String("%'"); 0348 } 0349 QSqlQuery cur(m_Database); 0350 cur.setForwardOnly(true); 0351 cur.prepare(sItems); 0352 0353 while (bcur.next()) { 0354 const Q_LLONG revision = bcur.value(0).toLongLong(); 0355 cur.bindValue(0, revision); 0356 0357 if (!cur.exec()) { 0358 // qDebug() << cur.lastError().text(); 0359 throw svn::cache::DatabaseException( 0360 QStringLiteral("Could not retrieve revision values: %1, %2").arg(cur.lastError().text(), cur.lastError().nativeErrorCode())); 0361 } 0362 target[revision].revision = revision; 0363 target[revision].author = bcur.value(1).toString(); 0364 target[revision].date = bcur.value(2).toLongLong(); 0365 target[revision].message = bcur.value(3).toString(); 0366 while (cur.next()) { 0367 LogChangePathEntry lcp; 0368 QString ac = cur.value(1).toString(); 0369 lcp.action = ac[0].toLatin1(); 0370 lcp.copyFromPath = cur.value(2).toString(); 0371 lcp.path = cur.value(0).toString(); 0372 lcp.copyFromRevision = cur.value(3).toLongLong(); 0373 target[revision].changedPaths.push_back(lcp); 0374 } 0375 if (cp && cp->getListener()) { 0376 if (cp->getListener()->contextCancel()) { 0377 throw svn::cache::DatabaseException(QStringLiteral("Could not retrieve values: User cancel.")); 0378 } 0379 } 0380 } 0381 return true; 0382 } 0383 0384 /*! 0385 \fn svn::cache::ReposLog::date2numberRev(const svn::Revision&) 0386 */ 0387 svn::Revision svn::cache::ReposLog::date2numberRev(const svn::Revision &aRev, bool noNetwork) 0388 { 0389 if (aRev != svn::Revision::DATE) { 0390 return aRev; 0391 } 0392 if (!m_Database.isValid()) { 0393 return svn::Revision::UNDEFINED; 0394 } 0395 QSqlQuery query(QStringLiteral("select revision,date from logentries order by revision desc limit 1"), m_Database); 0396 0397 if (query.lastError().type() != QSqlError::NoError) { 0398 // qDebug() << query.lastError().text(); 0399 } 0400 bool must_remote = !noNetwork; 0401 if (query.next()) { 0402 if (query.value(1).toLongLong() >= aRev.date()) { 0403 must_remote = false; 0404 } 0405 } 0406 if (must_remote) { 0407 const svn::InfoEntries e = (m_Client->info(m_ReposRoot, svn::DepthEmpty, aRev, aRev)); 0408 ; 0409 if (e.count() < 1 || e[0].reposRoot().isEmpty()) { 0410 return aRev; 0411 } 0412 return e[0].revision(); 0413 } 0414 query.prepare(QStringLiteral("select revision from logentries where date<? order by revision desc")); 0415 query.bindValue(0, Q_LLONG(aRev.date())); 0416 if (query.exec() && query.next()) { 0417 return query.value(0).toInt(); 0418 } 0419 // not found... 0420 if (noNetwork) { 0421 return svn::Revision::UNDEFINED; 0422 } 0423 const svn::InfoEntries e = (m_Client->info(m_ReposRoot, svn::DepthEmpty, svn::Revision::HEAD, svn::Revision::HEAD)); 0424 ; 0425 if (e.count() < 1 || e[0].reposRoot().isEmpty()) { 0426 return svn::Revision::UNDEFINED; 0427 } 0428 return e[0].revision(); 0429 } 0430 0431 /*! 0432 \fn svn::cache::ReposLog::insertLogEntry(const svn::LogEntry&) 0433 */ 0434 bool svn::cache::ReposLog::_insertLogEntry(const svn::LogEntry &aEntry) 0435 { 0436 qlonglong j = aEntry.revision; 0437 static const QLatin1String qEntry("insert into logentries (revision,date,author,message) values (?,?,?,?)"); 0438 static const QLatin1String qPathes("insert into changeditems (revision,changeditem,action,copyfrom,copyfromrev) values (?,?,?,?,?)"); 0439 QSqlQuery _q(QString(), m_Database); 0440 _q.prepare(qEntry); 0441 _q.bindValue(0, j); 0442 _q.bindValue(1, aEntry.date); 0443 _q.bindValue(2, aEntry.author); 0444 _q.bindValue(3, aEntry.message); 0445 if (!_q.exec()) { 0446 // qDebug("Could not insert values: %s",_q.lastError().text().toUtf8().data()); 0447 // qDebug() << _q.lastQuery(); 0448 throw svn::cache::DatabaseException( 0449 QStringLiteral("_insertLogEntry_0: Could not insert values: %1, %2").arg(_q.lastError().text(), _q.lastError().nativeErrorCode())); 0450 } 0451 _q.prepare(qPathes); 0452 for (const LogChangePathEntry &cp : aEntry.changedPaths) { 0453 _q.bindValue(0, j); 0454 _q.bindValue(1, cp.path); 0455 _q.bindValue(2, QString(QLatin1Char(cp.action))); 0456 _q.bindValue(3, cp.copyFromPath); 0457 _q.bindValue(4, Q_LLONG(cp.copyFromRevision)); 0458 if (!_q.exec()) { 0459 // qDebug("Could not insert values: %s",_q.lastError().text().toUtf8().data()); 0460 // qDebug() << _q.lastQuery(); 0461 throw svn::cache::DatabaseException(QStringLiteral("Could not insert values: %1, %2").arg(_q.lastError().text(), _q.lastError().nativeErrorCode())); 0462 } 0463 } 0464 if (!aEntry.m_MergedInRevisions.isEmpty()) { 0465 static const QLatin1String qMerges("insert into mergeditems(revision,mergeditems) values(?,?)"); 0466 _q.prepare(qMerges); 0467 QByteArray _merges; 0468 QBuffer buffer(&_merges); 0469 buffer.open(QIODevice::ReadWrite); 0470 QDataStream af(&buffer); 0471 af << aEntry.m_MergedInRevisions; 0472 buffer.close(); 0473 _q.bindValue(0, j); 0474 _q.bindValue(1, _merges); 0475 if (!_q.exec()) { 0476 // qDebug("Could not insert values: %s",_q.lastError().text().toUtf8().data()); 0477 // qDebug() << _q.lastQuery(); 0478 throw svn::cache::DatabaseException(QStringLiteral("Could not insert values: %1, %2").arg(_q.lastError().text(), _q.lastError().nativeErrorCode())); 0479 } 0480 } 0481 return true; 0482 } 0483 0484 bool svn::cache::ReposLog::insertLogEntry(const svn::LogEntry &aEntry) 0485 { 0486 DatabaseLocker l(&m_Database); 0487 if (!_insertLogEntry(aEntry)) { 0488 return false; 0489 } 0490 l.commit(); 0491 return true; 0492 } 0493 0494 /*! 0495 \fn svn::cache::ReposLog::log(const svn::Path&,const svn::Revision&start, const svn::Revision&end,const svn::Revision&peg,svn::LogEntriesMap&target, bool 0496 strictNodeHistory,int limit)) 0497 */ 0498 bool svn::cache::ReposLog::log(const svn::Path &what, 0499 const svn::Revision &_start, 0500 const svn::Revision &_end, 0501 const svn::Revision &_peg, 0502 svn::LogEntriesMap &target, 0503 bool strictNodeHistory, 0504 int limit) 0505 { 0506 Q_UNUSED(strictNodeHistory); 0507 static const QLatin1String s_q( 0508 "select logentries.revision,logentries.author,logentries.date,logentries.message from logentries where logentries.revision in (select " 0509 "changeditems.revision from changeditems where (changeditems.changeditem='%1' or changeditems.changeditem GLOB '%2/*') %3 GROUP BY " 0510 "changeditems.revision) ORDER BY logentries.revision DESC"); 0511 0512 static const QLatin1String s_e("select changeditem,action,copyfrom,copyfromrev from changeditems where changeditems.revision='%1'"); 0513 static const QLatin1String s_m("select mergeditems from mergeditems where mergeditems.revision='%1'"); 0514 0515 svn::Revision peg = date2numberRev(_peg, true); 0516 QString query_string = 0517 QString(s_q).arg(what.native(), what.native(), (peg == svn::Revision::UNDEFINED ? QString() : QStringLiteral(" AND revision<=%1").arg(peg.revnum()))); 0518 if (peg == svn::Revision::UNDEFINED) { 0519 peg = latestCachedRev(); 0520 } 0521 if (!itemExists(peg, what)) { 0522 throw svn::cache::DatabaseException(QStringLiteral("Entry '%1' does not exists at revision %2").arg(what.native(), peg.toString())); 0523 } 0524 if (limit > 0) { 0525 query_string += QStringLiteral(" LIMIT %1").arg(limit); 0526 } 0527 QSqlQuery _q(m_Database); 0528 QSqlQuery _q2(m_Database); 0529 _q.setForwardOnly(true); 0530 _q.prepare(query_string); 0531 if (!_q.exec()) { 0532 // qDebug("Could not select values: %s",_q.lastError().text().toUtf8().data()); 0533 // qDebug() << _q.lastQuery(); 0534 throw svn::cache::DatabaseException(QStringLiteral("Could not select values: %1, %2").arg(_q.lastError().text(), _q.lastError().nativeErrorCode())); 0535 } 0536 while (_q.next()) { 0537 Q_LLONG revision = _q.value(0).toLongLong(); 0538 target[revision].revision = revision; 0539 target[revision].author = _q.value(1).toString(); 0540 target[revision].date = _q.value(2).toLongLong(); 0541 target[revision].message = _q.value(3).toString(); 0542 query_string = QString(s_e).arg(revision); 0543 _q2.setForwardOnly(true); 0544 _q2.prepare(query_string); 0545 if (!_q2.exec()) { 0546 // qDebug("Could not select values: %s",_q2.lastError().text().toUtf8().data()); 0547 } else { 0548 while (_q2.next()) { 0549 target[revision].changedPaths.push_back( 0550 LogChangePathEntry(_q2.value(0).toString(), _q2.value(1).toChar().toLatin1(), _q2.value(2).toString(), _q2.value(3).toLongLong())); 0551 } 0552 } 0553 query_string = QString(s_m).arg(revision); 0554 _q2.prepare(query_string); 0555 if (!_q2.exec()) { 0556 // qDebug("Could not select values: %s",_q2.lastError().text().toUtf8().data()); 0557 } else { 0558 if (_q2.next()) { 0559 QByteArray byteArray = _q2.value(0).toByteArray(); 0560 QBuffer buffer(&byteArray); 0561 QDataStream in(&buffer); 0562 in >> target[revision].m_MergedInRevisions; 0563 } 0564 } 0565 } 0566 return true; 0567 } 0568 0569 /*! 0570 \fn svn::cache::ReposLog::itemExists(const svn::Revision&,const QString&) 0571 */ 0572 bool svn::cache::ReposLog::itemExists(const svn::Revision &peg, const svn::Path &path) 0573 { 0574 /// @todo this moment I have no idea how to check real with all moves and deletes of parent folders without a hell of sql statements so we make it quite 0575 /// simple: it exists if we found it. 0576 0577 Q_UNUSED(peg); 0578 Q_UNUSED(path); 0579 0580 #if 0 0581 static QString _s1("select revision from changeditems where changeditem='%1' and action='A' and revision<=%2 order by revision desc limit 1"); 0582 QSqlQuery _q(QString(), m_Database); 0583 QString query_string = QString(_s1).arg(path.native()).arg(peg.revnum()); 0584 if (!_q.exec(query_string)) { 0585 //qDebug("Could not select values: %s",_q.lastError().text().toUtf8().data()); 0586 //qDebug(_q.lastQuery().toUtf8().data()); 0587 throw svn::cache::DatabaseException(QString("Could not select values: ") + _q.lastError().text(), _q.lastError().number()); 0588 } 0589 //qDebug(_q.lastQuery().toUtf8().data()); 0590 0591 svn::Path _p = path; 0592 static QString _s2("select revision from changeditem where changeditem in (%1) and action='D' and revision>%2 and revision<=%3 order by revision desc limit 1"); 0593 QStringList p_list; 0594 while (_p.length() > 0) { 0595 p_list.append(QString("'%1'").arg(_p.native())); 0596 _p.removeLast(); 0597 } 0598 query_string = QString(_s2).arg(p_list.join(",")).arg(); 0599 #endif 0600 return true; 0601 } 0602 0603 bool svn::cache::ReposLog::isValid() const 0604 { 0605 if (!m_Database.isValid()) { 0606 m_Database = LogCache::self()->reposDb(m_ReposRoot); 0607 if (!m_Database.isValid()) { 0608 return false; 0609 } 0610 } 0611 return true; 0612 } 0613 0614 void svn::cache::ReposLog::cleanLogEntries() 0615 { 0616 if (!isValid()) { 0617 return; 0618 } 0619 DatabaseLocker l(&m_Database); 0620 QSqlQuery _q(QString(), m_Database); 0621 if (!_q.exec(QStringLiteral("delete from logentries"))) { 0622 return; 0623 } 0624 if (!_q.exec(QStringLiteral("delete from changeditems"))) { 0625 return; 0626 } 0627 if (!_q.exec(QStringLiteral("delete from mergeditems"))) { 0628 return; 0629 } 0630 0631 l.commit(); 0632 _q.exec(QStringLiteral("vacuum")); 0633 }