File indexing completed on 2024-04-14 14:53:35

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003-2017 Jarosław Staniek <staniek@kde.org>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this program; see the file COPYING.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "KDbTransaction.h"
0021 #include "KDbConnection.h"
0022 #include "KDbTransactionData.h"
0023 #include "KDbTransactionGuard.h"
0024 #include "kdb_debug.h"
0025 
0026 #ifdef KDB_TRANSACTIONS_DEBUG
0027 //helper for debugging
0028 int KDbTransaction_globalcount = 0;
0029 
0030 KDB_EXPORT int KDbTransaction::globalCount()
0031 {
0032     return KDbTransaction_globalcount;
0033 }
0034 
0035 int KDbTransactionData_globalcount = 0;
0036 
0037 KDB_EXPORT int KDbTransactionData::globalCount()
0038 {
0039     return KDbTransactionData_globalcount;
0040 }
0041 #endif
0042 
0043 class Q_DECL_HIDDEN KDbTransactionData::Private
0044 {
0045 public:
0046     Private(KDbConnection *c) : connection(c)
0047     {
0048         Q_ASSERT(connection);
0049     }
0050     KDbConnection *connection;
0051     bool active = true;
0052     int refcount = 1;
0053 };
0054 
0055 KDbTransactionData::KDbTransactionData(KDbConnection *connection)
0056     : d(new Private(connection))
0057 {
0058 #ifdef KDB_TRANSACTIONS_DEBUG
0059     KDbTransaction_globalcount++; // because of refcount is initialized to 1
0060     KDbTransactionData_globalcount++;
0061     transactionsDebug() << "-- globalcount ==" << KDbTransactionData_globalcount;
0062 #endif
0063 }
0064 
0065 KDbTransactionData::~KDbTransactionData()
0066 {
0067 #ifdef KDB_TRANSACTIONS_DEBUG
0068     KDbTransactionData_globalcount--;
0069     transactionsDebug() << "-- globalcount ==" << KDbTransactionData_globalcount;
0070 #endif
0071     delete d;
0072 }
0073 
0074 void KDbTransactionData::ref()
0075 {
0076     d->refcount++;
0077 }
0078 
0079 void KDbTransactionData::deref()
0080 {
0081     d->refcount--;
0082 }
0083 
0084 int KDbTransactionData::refcount() const
0085 {
0086     return d->refcount;
0087 }
0088 
0089 bool KDbTransactionData::isActive() const
0090 {
0091     return d->active;
0092 }
0093 
0094 void KDbTransactionData::setActive(bool set)
0095 {
0096     d->active = set;
0097 }
0098 
0099 KDbConnection *KDbTransactionData::connection()
0100 {
0101     return d->connection;
0102 }
0103 
0104 const KDbConnection *KDbTransactionData::connection() const
0105 {
0106     return d->connection;
0107 }
0108 
0109 //---------------------------------------------------
0110 
0111 KDbTransaction::KDbTransaction()
0112         : m_data(nullptr)
0113 {
0114 }
0115 
0116 KDbTransaction::KDbTransaction(const KDbTransaction& trans)
0117         : m_data(trans.m_data)
0118 {
0119     if (m_data) {
0120         m_data->ref();
0121 #ifdef KDB_TRANSACTIONS_DEBUG
0122         KDbTransaction_globalcount++;
0123 #endif
0124     }
0125 }
0126 
0127 KDbTransaction::~KDbTransaction()
0128 {
0129     if (m_data) {
0130         m_data->deref();
0131 #ifdef KDB_TRANSACTIONS_DEBUG
0132         KDbTransaction_globalcount--;
0133 #endif
0134         transactionsDebug() << "m_data->refcount==" << m_data->refcount();
0135         if (m_data->refcount() == 0)
0136             delete m_data;
0137     } else {
0138         transactionsDebug() << "null";
0139     }
0140 #ifdef KDB_TRANSACTIONS_DEBUG
0141     transactionsDebug() << "-- globalcount == " << KDbTransaction_globalcount;
0142 #endif
0143 }
0144 
0145 KDbTransaction& KDbTransaction::operator=(const KDbTransaction & trans)
0146 {
0147     if (this != &trans) {
0148         if (m_data) {
0149             m_data->deref();
0150 #ifdef KDB_TRANSACTIONS_DEBUG
0151             KDbTransaction_globalcount--;
0152 #endif
0153             transactionsDebug() << "m_data->refcount==" << m_data->refcount();
0154             if (m_data->refcount() == 0)
0155                 delete m_data;
0156         }
0157         m_data = trans.m_data;
0158         if (m_data) {
0159             m_data->ref();
0160 #ifdef KDB_TRANSACTIONS_DEBUG
0161             KDbTransaction_globalcount++;
0162 #endif
0163         }
0164     }
0165     return *this;
0166 }
0167 
0168 bool KDbTransaction::operator==(const KDbTransaction& other) const
0169 {
0170     return m_data == other.m_data;
0171 }
0172 
0173 KDbConnection* KDbTransaction::connection()
0174 {
0175     return m_data ? m_data->connection() : nullptr;
0176 }
0177 
0178 const KDbConnection* KDbTransaction::connection() const
0179 {
0180     return const_cast<KDbTransaction*>(this)->connection();
0181 }
0182 
0183 bool KDbTransaction::isActive() const
0184 {
0185     return m_data && m_data->isActive();
0186 }
0187 
0188 bool KDbTransaction::isNull() const
0189 {
0190     return m_data == nullptr;
0191 }
0192 
0193 //---------------------------------------------------
0194 
0195 class Q_DECL_HIDDEN KDbTransactionGuard::Private
0196 {
0197 public:
0198     Private() {}
0199     KDbTransaction transaction;
0200     bool doNothing = false;
0201 };
0202 
0203 KDbTransactionGuard::KDbTransactionGuard(KDbConnection *connection)
0204     : KDbTransactionGuard()
0205 {
0206     if (connection) {
0207         d->transaction = connection->beginTransaction();
0208     }
0209 }
0210 
0211 KDbTransactionGuard::KDbTransactionGuard(const KDbTransaction &transaction)
0212     : KDbTransactionGuard()
0213 {
0214     d->transaction = transaction;
0215 }
0216 
0217 KDbTransactionGuard::KDbTransactionGuard()
0218     : d(new Private)
0219 {
0220 }
0221 
0222 KDbTransactionGuard::~KDbTransactionGuard()
0223 {
0224     if (!d->doNothing && d->transaction.isActive()) {
0225         const bool result = rollback();
0226 #ifdef KDB_TRANSACTIONS_DEBUG
0227         transactionsDebug() << "~KDbTransactionGuard is rolling back transaction:" << result;
0228 #else
0229         Q_UNUSED(result)
0230 #endif
0231     }
0232     delete d;
0233 }
0234 
0235 void KDbTransactionGuard::setTransaction(const KDbTransaction& transaction)
0236 {
0237     d->transaction = transaction;
0238 }
0239 
0240 bool KDbTransactionGuard::commit(KDbTransaction::CommitOptions options)
0241 {
0242     if (d->transaction.connection()) {
0243         return d->transaction.connection()->commitTransaction(d->transaction, options);
0244     }
0245     return false;
0246 }
0247 
0248 bool KDbTransactionGuard::rollback(KDbTransaction::CommitOptions options)
0249 {
0250     if (d->transaction.connection()) {
0251         return d->transaction.connection()->rollbackTransaction(d->transaction, options);
0252     }
0253     return false;
0254 }
0255 
0256 void KDbTransactionGuard::doNothing()
0257 {
0258     d->doNothing = true;
0259 }
0260 
0261 const KDbTransaction KDbTransactionGuard::transaction() const
0262 {
0263     return d->transaction;
0264 }