From: APTX Date: Wed, 5 Jun 2013 12:32:50 +0000 (+0200) Subject: Add support for nested database transactions. X-Git-Url: https://gitweb.tyo.aptx.org/?a=commitdiff_plain;h=f5922f9e41bcfd7d8a917a5eba9de5e5078ff362;p=localmylist.git Add support for nested database transactions. --- diff --git a/localmylist/database.cpp b/localmylist/database.cpp index c98070f..20c16e1 100644 --- a/localmylist/database.cpp +++ b/localmylist/database.cpp @@ -9,15 +9,41 @@ #include #include +#include + namespace LocalMyList { struct DatabaseInternal { + DatabaseInternal() : transactionLevel(0) {} + QSqlDatabase db; QHash preparedQueries; + int transactionLevel; QThread *thread; + + bool transactionInternal(std::function transaction, std::function savepoint) + { + if (transactionLevel) + { + if (!savepoint()) + { + qDebug() << "Savepoint Transaction Error:" << db.lastError(); + return false; + } + } + else + { + if (!transaction()) + { + qDebug() << "Transaction Error:" << db.lastError(); + return false; + } + } + return true; + } }; Database::Database(const QString &connectionName) : d(0) @@ -56,33 +82,56 @@ bool Database::transaction() { Q_ASSERT_X(d->thread == QThread::currentThread(), "threads", "DB used from different thread"); - bool success = d->db.transaction(); - if (success) - return true; - qDebug() << "Transaction Error:" << d->db.lastError(); - return false; + + if (!d->transactionInternal( + [this]{ return d->db.transaction(); }, + [this]{ return exec("SAVEPOINT transaction_level_" + QString::number(d->transactionLevel)); })) + { + return false; + } + + ++d->transactionLevel; + return true; } bool Database::commit() { Q_ASSERT_X(d->thread == QThread::currentThread(), "threads", "DB used from different thread"); - bool success = d->db.commit(); - if (success) - return true; - qDebug() << "Commit Error:" << d->db.lastError(); - return false; + if (!d->transactionLevel) + return false; + + --d->transactionLevel; + + if (!d->transactionInternal( + [this]{ return d->db.commit(); }, + [this]{ return exec("RELEASE SAVEPOINT transaction_level_" + QString::number(d->transactionLevel)); })) + { + d->transactionLevel = 0; + return false; + } + + return true; } bool Database::rollback() { Q_ASSERT_X(d->thread == QThread::currentThread(), "threads", "DB used from different thread"); - bool success = d->db.rollback(); - if (success) - return true; -qDebug() << "Commit Error:" << d->db.lastError(); -return false; + if (!d->transactionLevel) + return false; + + --d->transactionLevel; + + if (!d->transactionInternal( + [this]{ return d->db.rollback(); }, + [this]{ return exec("ROLLBACK TO SAVEPOINT transaction_level_" + QString::number(d->transactionLevel)); })) + { + d->transactionLevel = 0; + return false; + } + + return true; } OpenFileData Database::firstUnwatchedByExactTitle(const QString &title) @@ -1584,6 +1633,7 @@ void Database::disconnect() return; d->preparedQueries.clear(); + d->transactionLevel = 0; auto subscribedNotifications = d->db.driver()->subscribedToNotifications(); foreach (const QString ¬ification, subscribedNotifications)