1 /***************************************************************************
2 * Copyright (C) 2005-2009 by Rajko Albrecht ral@alwins-world.de *
3 * http://kdesvn.alwins-world.de/ *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU Lesser General Public *
7 * License as published by the Free Software Foundation; either *
8 * version 2.1 of the License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 * Lesser General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Lesser General Public *
16 * License along with this program (in the file LGPL.txt); if not, *
17 * write to the Free Software Foundation, Inc., 51 Franklin St, *
18 * Fifth Floor, Boston, MA 02110-1301 USA *
19 * *
20 * This software consists of voluntary contributions made by many *
21 * individuals. For exact contribution history, see the revision *
22 * history and logs, available at http://kdesvn.alwins-world.de. *
23 ***************************************************************************/
24 #include "ReposLog.h"
25
26 #include "LogCache.h"
27 #include "svnqt/info_entry.h"
28 #include "svnqt/svnqttypes.h"
29 #include "svnqt/client.h"
30 #include "svnqt/context_listener.h"
31 #include "svnqt/cache/DatabaseException.h"
32 #include "svnqt/client_parameter.h"
33
34 #include <QDataStream>
35 #include <QSqlDatabase>
36 #include <QSqlError>
37 #include <QSqlQuery>
38 #include <QVariant>
39 #include <QFileInfo>
40 #include <QBuffer>
41 #define Q_LLONG qlonglong
42
43 class DatabaseLocker
44 {
45 public:
DatabaseLocker(QSqlDatabase * db)46 DatabaseLocker(QSqlDatabase *db)
47 : m_commited(false)
48 , m_db(db)
49 {
50 m_db->transaction();
51 }
~DatabaseLocker()52 ~DatabaseLocker()
53 {
54 if (!m_commited) {
55 m_db->rollback();
56 }
57 }
58
commit()59 void commit()
60 {
61 if (m_commited) {
62 return;
63 }
64 m_db->commit();
65 m_commited = true;
66 }
67
68 protected:
69 bool m_commited;
70 QSqlDatabase *m_db;
71 };
72
73 /*!
74 \fn svn::cache::ReposLog::ReposLog(svn::Client*aClient,const QString&)
75 */
ReposLog(const svn::ClientP & aClient,const QString & aRepository)76 svn::cache::ReposLog::ReposLog(const svn::ClientP &aClient, const QString &aRepository)
77 : m_Client(aClient)
78 , m_Database()
79 , m_ReposRoot(aRepository)
80 , m_latestHead(svn::Revision::UNDEFINED)
81 {
82 if (!aRepository.isEmpty()) {
83 m_Database = LogCache::self()->reposDb(aRepository);
84 }
85 }
86
87 /*!
88 \fn svn::cache::ReposLog::latestHeadRev()
89 */
latestHeadRev()90 svn::Revision svn::cache::ReposLog::latestHeadRev()
91 {
92 if (!m_Client || m_ReposRoot.isEmpty()) {
93 return svn::Revision::UNDEFINED;
94 }
95 if (!m_Database.isValid()) {
96 m_Database = LogCache::self()->reposDb(m_ReposRoot);
97 if (!m_Database.isValid()) {
98 return svn::Revision::UNDEFINED;
99 }
100 }
101 /// no catch - exception has go trough...
102 //qDebug("Getting headrev");
103 svn::InfoEntries e = m_Client->info(m_ReposRoot, svn::DepthEmpty, svn::Revision::HEAD, svn::Revision::HEAD);
104 if (e.count() < 1 || e[0].reposRoot().isEmpty()) {
105 return svn::Revision::UNDEFINED;
106 }
107 //qDebug("Getting headrev done");
108 return e[0].revision();
109 }
110
111 /*!
112 \fn svn::cache::ReposLog::latestCachedRev()
113 */
latestCachedRev()114 svn::Revision svn::cache::ReposLog::latestCachedRev()
115 {
116 if (m_ReposRoot.isEmpty()) {
117 return svn::Revision::UNDEFINED;
118 }
119 if (!m_Database.isValid()) {
120 m_Database = LogCache::self()->reposDb(m_ReposRoot);
121 if (!m_Database.isValid()) {
122 return svn::Revision::UNDEFINED;
123 }
124 }
125 static const QLatin1String q("select revision from 'logentries' order by revision DESC limit 1");
126 QSqlQuery _q(QString(), m_Database);
127 if (!_q.exec(q)) {
128 //qDebug() << _q.lastError().text();
129 return svn::Revision::UNDEFINED;
130 }
131 int _r;
132 if (_q.isActive() && _q.next()) {
133 //qDebug("Sel result: %s",_q.value(0).toString().toUtf8().data());
134 _r = _q.value(0).toInt();
135 } else {
136 //qDebug() << _q.lastError().text();
137 return svn::Revision::UNDEFINED;
138 }
139 return _r;
140 }
141
count() const142 qlonglong svn::cache::ReposLog::count()const
143 {
144 if (!m_Database.isValid()) {
145 m_Database = LogCache::self()->reposDb(m_ReposRoot);
146 if (!m_Database.isValid()) {
147 return svn::Revision::UNDEFINED;
148 }
149 }
150 static const QLatin1String q("select count(*) from 'logentries'");
151 QSqlQuery _q(QString(), m_Database);
152 if (!_q.exec(q)) {
153 //qDebug() << _q.lastError().text();
154 return -1;
155 }
156 qlonglong _r;
157 QVariant v;
158 if (_q.isActive() && _q.next()) {
159 //qDebug("Sel result: %s",_q.value(0).toString().toUtf8().data());
160 v = _q.value(0);
161 if (v.canConvert(QVariant::LongLong)) {
162 bool ok = false;
163 _r = v.toLongLong(&ok);
164 if (ok) {
165 return _r;
166 }
167 }
168 }
169 return -1;
170 }
171
fileSize() const172 qlonglong svn::cache::ReposLog::fileSize()const
173 {
174 if (!m_Database.isValid()) {
175 m_Database = LogCache::self()->reposDb(m_ReposRoot);
176 if (!m_Database.isValid()) {
177 return -1;
178 }
179 }
180 QFileInfo fi(m_Database.databaseName());
181 if (fi.exists()) {
182 return fi.size();
183 }
184 return -1;
185 }
186
itemCount() const187 qlonglong svn::cache::ReposLog::itemCount()const
188 {
189 if (!m_Database.isValid()) {
190 m_Database = LogCache::self()->reposDb(m_ReposRoot);
191 if (!m_Database.isValid()) {
192 return -1;
193 }
194 }
195 static const QLatin1String q("select count(*) from 'changeditems'");
196 QSqlQuery _q(QString(), m_Database);
197 if (!_q.exec(q)) {
198 //qDebug() << _q.lastError().text();
199 return -1;
200 }
201 qlonglong _r;
202 QVariant v;
203 if (_q.isActive() && _q.next()) {
204 //qDebug("Sel result: %s",_q.value(0).toString().toUtf8().data());
205 v = _q.value(0);
206 if (v.canConvert(QVariant::LongLong)) {
207 bool ok = false;
208 _r = v.toLongLong(&ok);
209 if (ok) {
210 return _r;
211 }
212 }
213 }
214 return -1;
215 }
216
checkFill(svn::Revision & start,svn::Revision & end,bool checkHead)217 bool svn::cache::ReposLog::checkFill(svn::Revision &start, svn::Revision &end, bool checkHead)
218 {
219 if (!m_Database.isValid()) {
220 m_Database = LogCache::self()->reposDb(m_ReposRoot);
221 if (!m_Database.isValid()) {
222 return false;
223 }
224 }
225 ContextP cp = m_Client->getContext();
226 // long long icount=0;
227
228 svn::Revision _latest = latestCachedRev();
229 // //qDebug("Latest cached rev: %i",_latest.revnum());
230 // //qDebug("End revision is: %s",end.toString().toUtf8().data());
231
232 if (checkHead && _latest.revnum() >= latestHeadRev().revnum()) {
233 return true;
234 }
235
236 start = date2numberRev(start);
237 end = date2numberRev(end);
238
239 // both should now one of START, HEAD or NUMBER
240 if (start == svn::Revision::HEAD || (end == svn::Revision::NUMBER && start == svn::Revision::NUMBER && start.revnum() > end.revnum())) {
241 svn::Revision tmp = start;
242 start = end;
243 end = tmp;
244 }
245 svn::Revision _rstart = _latest.revnum() + 1;
246 svn::Revision _rend = end;
247 if (_rend == svn::Revision::UNDEFINED) {
248 // //qDebug("Setting end to Head");
249 _rend = svn::Revision::HEAD;
250 }
251 // no catch - exception should go outside.
252 if (_rstart == 0) {
253 _rstart = 1;
254 }
255 // //qDebug("Getting log %s -> %s",_rstart.toString().toUtf8().data(),_rend.toString().toUtf8().data());
256 if (_rend == svn::Revision::HEAD) {
257 _rend = latestHeadRev();
258 }
259
260 if (_rend == svn::Revision::HEAD || _rend.revnum() > _latest.revnum()) {
261 LogEntriesMap _internal;
262 // //qDebug("Retrieving from network.");
263 LogParameter params;
264
265 if (!m_Client->log(params.targets(m_ReposRoot).revisionRange(_rstart, _rend).peg(svn::Revision::UNDEFINED).discoverChangedPathes(true).strictNodeHistory(false), _internal)) {
266 return false;
267 }
268 LogEntriesMap::ConstIterator it = _internal.constBegin();
269
270 DatabaseLocker l(&m_Database);
271 for (; it != _internal.constEnd(); ++it) {
272 _insertLogEntry((*it));
273 if (cp && cp->getListener()) {
274 //cp->getListener()->contextProgress(++icount,_internal.size());
275 if (cp->getListener()->contextCancel()) {
276 throw DatabaseException(QStringLiteral("Could not retrieve values: User cancel."));
277 }
278 }
279 }
280 l.commit();
281 }
282 return true;
283 }
284
fillCache(const svn::Revision & _end)285 bool svn::cache::ReposLog::fillCache(const svn::Revision &_end)
286 {
287 svn::Revision end = _end;
288 svn::Revision start = latestCachedRev().revnum() + 1;
289 return checkFill(start, end, false);
290 }
291
292 /*!
293 \fn svn::cache::ReposLog::simpleLog(const svn::Revision&start,const svn::Revision&end,LogEntriesMap&target)
294 */
simpleLog(LogEntriesMap & target,const svn::Revision & _start,const svn::Revision & _end,bool noNetwork,const StringArray & exclude)295 bool svn::cache::ReposLog::simpleLog(LogEntriesMap &target, const svn::Revision &_start, const svn::Revision &_end, bool noNetwork, const StringArray &exclude)
296 {
297 if (!m_Client || m_ReposRoot.isEmpty()) {
298 return false;
299 }
300 target.clear();
301 ContextP cp = m_Client->getContext();
302
303 svn::Revision end = _end;
304 svn::Revision start = _start;
305 if (!noNetwork) {
306 if (!checkFill(start, end, true)) {
307 return false;
308 }
309 } else {
310 end = date2numberRev(end, noNetwork);
311 start = date2numberRev(start, noNetwork);
312 }
313
314 if (end == svn::Revision::HEAD) {
315 end = latestCachedRev();
316 }
317 if (start == svn::Revision::HEAD) {
318 start = latestCachedRev();
319 }
320
321 QSqlQuery bcount(m_Database);
322 bcount.prepare(QStringLiteral("select count(*) from logentries where revision<=? and revision>=?"));
323 bcount.bindValue(0, Q_LLONG(end.revnum()));
324 bcount.bindValue(1, Q_LLONG(start.revnum()));
325 if (!bcount.exec()) {
326 //qDebug() << bcount.lastError().text();
327 throw svn::cache::DatabaseException(QLatin1String("Could not retrieve count: ") + bcount.lastError().text());
328 return false;
329 }
330 if (!bcount.next() || bcount.value(0).toLongLong() < 1) {
331 // we didn't found logs with this parameters
332 return false;
333 }
334
335 QSqlQuery bcur(m_Database);
336 bcur.setForwardOnly(true);
337 bcur.prepare(QStringLiteral("select revision,author,date,message from logentries where revision<=? and revision>=?"));
338 bcur.bindValue(0, Q_LLONG(end.revnum()));
339 bcur.bindValue(1, Q_LLONG(start.revnum()));
340
341 if (!bcur.exec()) {
342 throw svn::cache::DatabaseException(QLatin1String("Could not retrieve values: ") + bcur.lastError().text());
343 return false;
344 }
345
346 QString sItems(QStringLiteral("select changeditem,action,copyfrom,copyfromrev from changeditems where revision=?"));
347 for (int i = 0; i < exclude.size(); ++i) {
348 sItems += QLatin1String(" and changeditem not like '") + exclude[i] + QLatin1String("%'");
349 }
350 QSqlQuery cur(m_Database);
351 cur.setForwardOnly(true);
352 cur.prepare(sItems);
353
354 while (bcur.next()) {
355 const Q_LLONG revision = bcur.value(0).toLongLong();
356 cur.bindValue(0, revision);
357
358 if (!cur.exec()) {
359 //qDebug() << cur.lastError().text();
360 throw svn::cache::DatabaseException(QStringLiteral("Could not retrieve revision values: %1, %2")
361 .arg(cur.lastError().text(),
362 cur.lastError().nativeErrorCode()));
363 return false;
364 }
365 target[revision].revision = revision;
366 target[revision].author = bcur.value(1).toString();
367 target[revision].date = bcur.value(2).toLongLong();
368 target[revision].message = bcur.value(3).toString();
369 while (cur.next()) {
370 LogChangePathEntry lcp;
371 QString ac = cur.value(1).toString();
372 lcp.action = ac[0].toLatin1();
373 lcp.copyFromPath = cur.value(2).toString();
374 lcp.path = cur.value(0).toString();
375 lcp.copyFromRevision = cur.value(3).toLongLong();
376 target[revision].changedPaths.push_back(lcp);
377 }
378 if (cp && cp->getListener()) {
379 if (cp->getListener()->contextCancel()) {
380 throw svn::cache::DatabaseException(QStringLiteral("Could not retrieve values: User cancel."));
381 return false;
382 }
383 }
384 }
385 return true;
386 }
387
388 /*!
389 \fn svn::cache::ReposLog::date2numberRev(const svn::Revision&)
390 */
date2numberRev(const svn::Revision & aRev,bool noNetwork)391 svn::Revision svn::cache::ReposLog::date2numberRev(const svn::Revision &aRev, bool noNetwork)
392 {
393 if (aRev != svn::Revision::DATE) {
394 return aRev;
395 }
396 if (!m_Database.isValid()) {
397 return svn::Revision::UNDEFINED;
398 }
399 QSqlQuery query(QStringLiteral("select revision,date from logentries order by revision desc limit 1"), m_Database);
400
401 if (query.lastError().type() != QSqlError::NoError) {
402 //qDebug() << query.lastError().text();
403 }
404 bool must_remote = !noNetwork;
405 if (query.next()) {
406 if (query.value(1).toLongLong() >= aRev.date()) {
407 must_remote = false;
408 }
409 }
410 if (must_remote) {
411 svn::InfoEntries e = (m_Client->info(m_ReposRoot, svn::DepthEmpty, aRev, aRev));;
412 if (e.count() < 1 || e[0].reposRoot().isEmpty()) {
413 return aRev;
414 }
415 return e[0].revision();
416 }
417 query.prepare(QStringLiteral("select revision from logentries where date<? order by revision desc"));
418 query.bindValue(0, Q_LLONG(aRev.date()));
419 if (query.exec() && query.next()) {
420 return query.value(0).toInt();
421 }
422 // not found...
423 if (noNetwork) {
424 return svn::Revision::UNDEFINED;
425 }
426 svn::InfoEntries e = (m_Client->info(m_ReposRoot, svn::DepthEmpty, svn::Revision::HEAD, svn::Revision::HEAD));;
427 if (e.count() < 1 || e[0].reposRoot().isEmpty()) {
428 return svn::Revision::UNDEFINED;
429 }
430 return e[0].revision();
431 }
432
433 /*!
434 \fn svn::cache::ReposLog::insertLogEntry(const svn::LogEntry&)
435 */
_insertLogEntry(const svn::LogEntry & aEntry)436 bool svn::cache::ReposLog::_insertLogEntry(const svn::LogEntry &aEntry)
437 {
438 qlonglong j = aEntry.revision;
439 static const QLatin1String qEntry("insert into logentries (revision,date,author,message) values (?,?,?,?)");
440 static const QLatin1String qPathes("insert into changeditems (revision,changeditem,action,copyfrom,copyfromrev) values (?,?,?,?,?)");
441 QSqlQuery _q(QString(), m_Database);
442 _q.prepare(qEntry);
443 _q.bindValue(0, j);
444 _q.bindValue(1, aEntry.date);
445 _q.bindValue(2, aEntry.author);
446 _q.bindValue(3, aEntry.message);
447 if (!_q.exec()) {
448 //qDebug("Could not insert values: %s",_q.lastError().text().toUtf8().data());
449 //qDebug() << _q.lastQuery();
450 throw svn::cache::DatabaseException(QStringLiteral("_insertLogEntry_0: Could not insert values: %1, %2").arg(_q.lastError().text(), _q.lastError().nativeErrorCode()));
451 }
452 _q.prepare(qPathes);
453 svn::LogChangePathEntries::ConstIterator cpit = aEntry.changedPaths.begin();
454 for (; cpit != aEntry.changedPaths.end(); ++cpit) {
455 _q.bindValue(0, j);
456 _q.bindValue(1, (*cpit).path);
457 _q.bindValue(2, QString(QLatin1Char((*cpit).action)));
458 _q.bindValue(3, (*cpit).copyFromPath);
459 _q.bindValue(4, Q_LLONG((*cpit).copyFromRevision));
460 if (!_q.exec()) {
461 //qDebug("Could not insert values: %s",_q.lastError().text().toUtf8().data());
462 //qDebug() << _q.lastQuery();
463 throw svn::cache::DatabaseException(QStringLiteral("Could not insert values: %1, %2").arg(_q.lastError().text(), _q.lastError().nativeErrorCode()));
464 }
465 }
466 if (!aEntry.m_MergedInRevisions.isEmpty()) {
467 static const QLatin1String qMerges("insert into mergeditems(revision,mergeditems) values(?,?)");
468 _q.prepare(qMerges);
469 QByteArray _merges;
470 QBuffer buffer(&_merges);
471 buffer.open(QIODevice::ReadWrite);
472 QDataStream af(&buffer);
473 af << aEntry.m_MergedInRevisions;
474 buffer.close();
475 _q.bindValue(0, j);
476 _q.bindValue(1, _merges);
477 if (!_q.exec()) {
478 //qDebug("Could not insert values: %s",_q.lastError().text().toUtf8().data());
479 //qDebug() << _q.lastQuery();
480 throw svn::cache::DatabaseException(QStringLiteral("Could not insert values: %1, %2").arg(_q.lastError().text(), _q.lastError().nativeErrorCode()));
481 }
482 }
483 return true;
484 }
485
insertLogEntry(const svn::LogEntry & aEntry)486 bool svn::cache::ReposLog::insertLogEntry(const svn::LogEntry &aEntry)
487 {
488 DatabaseLocker l(&m_Database);
489 if (!_insertLogEntry(aEntry)) {
490 return false;
491 }
492 l.commit();
493 return true;
494 }
495
496 /*!
497 \fn svn::cache::ReposLog::log(const svn::Path&,const svn::Revision&start, const svn::Revision&end,const svn::Revision&peg,svn::LogEntriesMap&target, bool strictNodeHistory,int limit))
498 */
log(const svn::Path & what,const svn::Revision & _start,const svn::Revision & _end,const svn::Revision & _peg,svn::LogEntriesMap & target,bool strictNodeHistory,int limit)499 bool svn::cache::ReposLog::log(const svn::Path &what, const svn::Revision &_start, const svn::Revision &_end, const svn::Revision &_peg, svn::LogEntriesMap &target, bool strictNodeHistory, int limit)
500 {
501 Q_UNUSED(strictNodeHistory);
502 static const QLatin1String s_q("select logentries.revision,logentries.author,logentries.date,logentries.message from logentries where logentries.revision in (select changeditems.revision from changeditems where (changeditems.changeditem='%1' or changeditems.changeditem GLOB '%2/*') %3 GROUP BY changeditems.revision) ORDER BY logentries.revision DESC");
503
504 static const QLatin1String s_e("select changeditem,action,copyfrom,copyfromrev from changeditems where changeditems.revision='%1'");
505 static const QLatin1String s_m("select mergeditems from mergeditems where mergeditems.revision='%1'");
506
507 svn::Revision peg = date2numberRev(_peg, true);
508 QString query_string = QString(s_q).arg(what.native(), what.native(), (peg == svn::Revision::UNDEFINED ? QString() : QStringLiteral(" AND revision<=%1").arg(peg.revnum())));
509 if (peg == svn::Revision::UNDEFINED) {
510 peg = latestCachedRev();
511 }
512 if (!itemExists(peg, what)) {
513 throw svn::cache::DatabaseException(QStringLiteral("Entry '%1' does not exists at revision %2").arg(what.native(), peg.toString()));
514 }
515 if (limit > 0) {
516 query_string += QStringLiteral(" LIMIT %1").arg(limit);
517 }
518 QSqlQuery _q(m_Database);
519 QSqlQuery _q2(m_Database);
520 _q.setForwardOnly(true);
521 _q.prepare(query_string);
522 if (!_q.exec()) {
523 //qDebug("Could not select values: %s",_q.lastError().text().toUtf8().data());
524 //qDebug() << _q.lastQuery();
525 throw svn::cache::DatabaseException(QStringLiteral("Could not select values: %1, %2").arg(_q.lastError().text(), _q.lastError().nativeErrorCode()));
526 }
527 while (_q.next()) {
528 Q_LLONG revision = _q.value(0).toLongLong();
529 target[revision].revision = revision;
530 target[revision].author = _q.value(1).toString();
531 target[revision].date = _q.value(2).toLongLong();
532 target[revision].message = _q.value(3).toString();
533 query_string = QString(s_e).arg(revision);
534 _q2.setForwardOnly(true);
535 _q2.prepare(query_string);
536 if (!_q2.exec()) {
537 //qDebug("Could not select values: %s",_q2.lastError().text().toUtf8().data());
538 } else {
539 while (_q2.next()) {
540 target[revision].changedPaths.push_back(
541 LogChangePathEntry(_q2.value(0).toString(),
542 _q2.value(1).toChar().toLatin1(),
543 _q2.value(2).toString(),
544 _q2.value(3).toLongLong()
545 )
546 );
547 }
548 }
549 query_string = QString(s_m).arg(revision);
550 _q2.prepare(query_string);
551 if (!_q2.exec()) {
552 //qDebug("Could not select values: %s",_q2.lastError().text().toUtf8().data());
553 } else {
554 if (_q2.next()) {
555 QByteArray byteArray = _q2.value(0).toByteArray();
556 QBuffer buffer(&byteArray);
557 QDataStream in(&buffer);
558 in >> target[revision].m_MergedInRevisions;
559 }
560 }
561 }
562 return true;
563 }
564
565 /*!
566 \fn svn::cache::ReposLog::itemExists(const svn::Revision&,const QString&)
567 */
itemExists(const svn::Revision & peg,const svn::Path & path)568 bool svn::cache::ReposLog::itemExists(const svn::Revision &peg, const svn::Path &path)
569 {
570 /// @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 simple: it exists if we found it.
571
572 Q_UNUSED(peg);
573 Q_UNUSED(path);
574
575 #if 0
576 static QString _s1("select revision from changeditems where changeditem='%1' and action='A' and revision<=%2 order by revision desc limit 1");
577 QSqlQuery _q(QString(), m_Database);
578 QString query_string = QString(_s1).arg(path.native()).arg(peg.revnum());
579 if (!_q.exec(query_string)) {
580 //qDebug("Could not select values: %s",_q.lastError().text().toUtf8().data());
581 //qDebug(_q.lastQuery().toUtf8().data());
582 throw svn::cache::DatabaseException(QString("Could not select values: ") + _q.lastError().text(), _q.lastError().number());
583 }
584 //qDebug(_q.lastQuery().toUtf8().data());
585
586 svn::Path _p = path;
587 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");
588 QStringList p_list;
589 while (_p.length() > 0) {
590 p_list.append(QString("'%1'").arg(_p.native()));
591 _p.removeLast();
592 }
593 query_string = QString(_s2).arg(p_list.join(",")).arg();
594 #endif
595 return true;
596 }
597
isValid() const598 bool svn::cache::ReposLog::isValid()const
599 {
600 if (!m_Database.isValid()) {
601 m_Database = LogCache::self()->reposDb(m_ReposRoot);
602 if (!m_Database.isValid()) {
603 return false;
604 }
605 }
606 return true;
607 }
608
cleanLogEntries()609 void svn::cache::ReposLog::cleanLogEntries()
610 {
611
612 if (!isValid()) {
613 return;
614 }
615 DatabaseLocker l(&m_Database);
616 QSqlQuery _q(QString(), m_Database);
617 if (!_q.exec(QStringLiteral("delete from logentries"))) {
618 return;
619 }
620 if (!_q.exec(QStringLiteral("delete from changeditems"))) {
621 return;
622 }
623 if (!_q.exec(QStringLiteral("delete from mergeditems"))) {
624 return;
625 }
626
627 l.commit();
628 _q.exec(QStringLiteral("vacuum"));
629 }
630