comparison SqliteDBLink.cpp @ 94:93981e675d67

Full support for bulkcommits.
author Tom Fredrik Blenning Klaussen <bfg@bfgconsult.no>
date Tue, 22 Oct 2013 14:11:50 +0200
parents 308a718812ba
children 7c935d3d5b74
comparison
equal deleted inserted replaced
93:308a718812ba 94:93981e675d67
7 #include <QtSql/QSqlQuery> 7 #include <QtSql/QSqlQuery>
8 #include <QtSql/QSqlRecord> 8 #include <QtSql/QSqlRecord>
9 9
10 #include "Exception/SQLException.hpp" 10 #include "Exception/SQLException.hpp"
11 #include "Exception/IOException.hpp" 11 #include "Exception/IOException.hpp"
12
13 #include <cassert>
12 14
13 const QString SqliteDBLink::connectionName("SqliteDBLink"); 15 const QString SqliteDBLink::connectionName("SqliteDBLink");
14 16
15 17
16 SqliteDBLink::SqliteDBLink(const QString& dbPath) 18 SqliteDBLink::SqliteDBLink(const QString& dbPath)
43 45
44 preparedTryAddQuery = new QSqlQuery(db); 46 preparedTryAddQuery = new QSqlQuery(db);
45 preparedTryAddQuery->prepare("INSERT INTO files (path, size, mtime, checksum)" 47 preparedTryAddQuery->prepare("INSERT INTO files (path, size, mtime, checksum)"
46 " VALUES (:path, :size, :mtime, :checksum)"); 48 " VALUES (:path, :size, :mtime, :checksum)");
47 49
50 preparedUpdateQuery = new QSqlQuery(db);
51 preparedUpdateQuery->prepare(
52 "UPDATE files "
53 "SET size=:size, mtime=:mtime, checksum=:checksum "
54 "WHERE path=:path");
48 } 55 }
49 56
50 SqliteDBLink::~SqliteDBLink() 57 SqliteDBLink::~SqliteDBLink()
51 { 58 {
52 delete preparedSizePrefixQuery; 59 delete preparedSizePrefixQuery;
53 delete preparedSizeQuery; 60 delete preparedSizeQuery;
61 delete preparedTryAddQuery;
62 delete preparedUpdateQuery;
54 db.close(); 63 db.close();
55 } 64 }
56 65
57 bool SqliteDBLink::exists(const QString& path) 66 bool SqliteDBLink::exists(const QString& path)
58 { 67 {
116 { 125 {
117 if (lazy) { 126 if (lazy) {
118 operations.push_back(Operation(dbinfo, Update)); 127 operations.push_back(Operation(dbinfo, Update));
119 } 128 }
120 else { 129 else {
121 QSqlQuery query(db); 130 preparedUpdateQuery->bindValue(":path", dbinfo.path());
122 query.prepare("UPDATE files " 131 preparedUpdateQuery->bindValue(":size", dbinfo.size());
123 "SET size=:size, mtime=:mtime, checksum=:checksum " 132 preparedUpdateQuery->bindValue(":mtime", dbinfo.mtime());
124 "WHERE path=:path"); 133 preparedUpdateQuery->bindValue(":checksum", dbinfo.checksum());
125 query.bindValue(":path", dbinfo.path()); 134 if (!preparedUpdateQuery->exec()) {
126 query.bindValue(":size", dbinfo.size()); 135 throw SQLException(*preparedUpdateQuery);
127 query.bindValue(":mtime", dbinfo.mtime());
128 query.bindValue(":checksum", dbinfo.checksum());
129 if (!query.exec()) {
130 throw SQLException(query);
131 } 136 }
132 } 137 }
133 } 138 }
134 139
135 void SqliteDBLink::addFile(const DBInfo& dbinfo, bool lazy) 140 void SqliteDBLink::addFile(const DBInfo& dbinfo, bool lazy)
252 } 257 }
253 258
254 return values; 259 return values;
255 } 260 }
256 261
262 void SqliteDBLink::executeOperation(QVariantList& paths,
263 QVariantList& sizes,
264 QVariantList& mtimes,
265 QVariantList& checksums,
266 OperationType operation)
267 {
268 assert(paths.size() == sizes.size());
269 assert(paths.size() == mtimes.size());
270 assert(paths.size() == checksums.size());
271 QSqlQuery* query;
272 switch (operation) {
273 case Add:
274 query = preparedTryAddQuery;
275 break;
276 case Update:
277 query = preparedUpdateQuery;
278 break;
279 case None:
280 assert(paths.size() == 0);
281 return;
282 }
283 query->bindValue("path", paths);
284 query->bindValue("size", sizes);
285 query->bindValue("mtime", mtimes);
286 query->bindValue("checksum", checksums);
287
288 if (!query->execBatch())
289 throw SQLException(*query);
290
291 paths.clear();
292 sizes.clear();
293 mtimes.clear();
294 checksums.clear();
295 }
296
257 bool SqliteDBLink::commit() 297 bool SqliteDBLink::commit()
258 { 298 {
259 int n = 0; 299 int n = 0;
260 int max = operations.size(); 300 OperationType last = None;
301 QVariantList paths, sizes, mtimes, hashes;
302
261 foreach(const Operation& operation, operations) { 303 foreach(const Operation& operation, operations) {
304 if (operation.second != last) {
305 executeOperation(paths, sizes, mtimes, hashes, last);
306 }
307
262 switch (operation.second) { 308 switch (operation.second) {
263 case Add: 309 case Add:
264 addFile(operation.first); 310 case Update:
311 paths.push_back(operation.first.path());
312 sizes.push_back(operation.first.size());
313 mtimes.push_back(operation.first.mtime());
314 hashes.push_back(operation.first.checksum());
315 case None:
265 break; 316 break;
266 case Update: 317 }
267 updateFile(operation.first); 318 last = operation.second;
268 } 319 }
320 if (last != None) {
321 executeOperation(paths, sizes, mtimes, hashes, last);
322 }
323
324 QSqlQuery whatToUpdate(db);
325 whatToUpdate.prepare("SELECT path FROM files WHERE checksum is NULL AND size in (SELECT size FROM files WHERE size <> 0 GROUP BY size HAVING count(*) > 1 ORDER BY SIZE) ORDER BY size");
326
327 if (!whatToUpdate.exec()) {
328 throw SQLException(whatToUpdate);
329 }
330
331 int pathIndex = whatToUpdate.record().indexOf("path");
332 QStringList updatePaths;
333 while (whatToUpdate.next()) {
334 updatePaths << whatToUpdate.value(pathIndex).toString();
335 }
336 int max = updatePaths.size();
337 QSqlQuery updateChecksum(db);
338 updateChecksum.prepare("UPDATE files "
339 "SET checksum=:checksum "
340 "WHERE path=:path");
341
342 foreach (const QString& path, updatePaths) {
343 QByteArray ohash = computeHash(path);
269 emit progressUpdate(++n, max); 344 emit progressUpdate(++n, max);
345 updateChecksum.bindValue("checksum", ohash);
346 updateChecksum.bindValue("path", path);
347 if (!updateChecksum.exec())
348 throw SQLException(updateChecksum);
349
270 } 350 }
271 return true; 351 return true;
272 } 352 }