extracted transactions to ManagesTransactions

Transactions extracted to the Concerns::ManagesTransactions base class.

 - bugfix includes
 - logConnected()/logDisconnected() code wrapped in TINYORM_MYSQL_PING
 - hitTransactionalCounters() extracted to Concerns::CountsQueries
 - convertNamedToPositionalBindings() extracted to Concerns::LogsQueries
This commit is contained in:
silverqx
2022-01-14 21:26:02 +01:00
parent ff0697e1a5
commit bbfca1594e
11 changed files with 442 additions and 301 deletions

View File

@@ -16,6 +16,7 @@ function(tiny_sources out_headers out_sources)
concerns/detectslostconnections.hpp
concerns/hasconnectionresolver.hpp
concerns/logsqueries.hpp
concerns/managestransactions.hpp
connectionresolverinterface.hpp
connectors/connectionfactory.hpp
connectors/connector.hpp
@@ -130,6 +131,7 @@ function(tiny_sources out_headers out_sources)
concerns/detectslostconnections.cpp
concerns/hasconnectionresolver.cpp
concerns/logsqueries.cpp
concerns/managestransactions.cpp
connectors/connectionfactory.cpp
connectors/connector.cpp
connectors/mysqlconnector.cpp

View File

@@ -11,6 +11,7 @@ headersList += \
$$PWD/orm/concerns/detectslostconnections.hpp \
$$PWD/orm/concerns/hasconnectionresolver.hpp \
$$PWD/orm/concerns/logsqueries.hpp \
$$PWD/orm/concerns/managestransactions.hpp \
$$PWD/orm/config.hpp \
$$PWD/orm/connectionresolverinterface.hpp \
$$PWD/orm/connectors/connectionfactory.hpp \

View File

@@ -5,7 +5,9 @@
#include "orm/macros/systemheader.hpp"
TINY_SYSTEM_HEADER
#include <QtGlobal>
#include <QElapsedTimer>
#include <optional>
#include "orm/macros/export.hpp"
#include "orm/types/statementscounter.hpp"
@@ -25,6 +27,9 @@ namespace Concerns
{
Q_DISABLE_COPY(CountsQueries)
// To access hitTransactionalCounters() method
friend class ManagesTransactions;
public:
/*! Default constructor. */
inline CountsQueries() = default;
@@ -73,6 +78,10 @@ namespace Concerns
StatementsCounter m_statementsCounter {};
private:
/*! Count transactional queries execution time and statements counter. */
std::optional<qint64>
hitTransactionalCounters(QElapsedTimer timer, bool countElapsed);
/*! Dynamic cast *this to the DatabaseConnection & derived type. */
DatabaseConnection &databaseConnection();
};

View File

@@ -7,6 +7,9 @@ TINY_SYSTEM_HEADER
#include <QtSql/QSqlQuery>
#include <memory>
#include <optional>
#include "orm/macros/export.hpp"
#include "orm/types/log.hpp"
@@ -72,6 +75,10 @@ namespace Concerns
inline static std::atomic<std::size_t> m_queryLogId = 0;
private:
/*! Convert a named bindings map to the positional bindings vector. */
QVector<QVariant>
convertNamedToPositionalBindings(QVariantMap &&bindings) const;
/*! Dynamic cast *this to the DatabaseConnection & derived type. */
const DatabaseConnection &databaseConnection() const;

View File

@@ -0,0 +1,109 @@
#pragma once
#ifndef ORM_CONCERNS_MANAGESTRANSACTIONS_HPP
#define ORM_CONCERNS_MANAGESTRANSACTIONS_HPP
#include "orm/macros/systemheader.hpp"
TINY_SYSTEM_HEADER
#include <QString>
#include "orm/macros/commonnamespace.hpp"
#include "orm/macros/export.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Orm
{
class DatabaseConnection;
class MySqlConnection;
namespace Concerns
{
class CountsQueries;
// TODO next transaction method with callback silverqx
// TODO rewrite transactions, look at beginTransaction(), commit(), ... whats up, you will see immediately 😎 silverqx
/*! Manages database transactions. */
class SHAREDLIB_EXPORT ManagesTransactions
{
Q_DISABLE_COPY(ManagesTransactions)
// To access resetTransactions() method
friend DatabaseConnection;
// To access resetTransactions() method
friend MySqlConnection;
public:
/*! Default constructor. */
ManagesTransactions();
/*! Virtual destructor, to pass -Weffc++. */
inline virtual ~ManagesTransactions() = default;
/*! Start a new database transaction. */
bool beginTransaction();
/*! Commit the active database transaction. */
bool commit();
/*! Rollback the active database transaction. */
bool rollBack();
/*! Start a new named transaction savepoint. */
bool savepoint(const QString &id);
/*! Start a new named transaction savepoint. */
bool savepoint(std::size_t id);
/*! Rollback to a named transaction savepoint. */
bool rollbackToSavepoint(const QString &id);
/*! Rollback to a named transaction savepoint. */
bool rollbackToSavepoint(std::size_t id);
/*! Get the number of active transactions. */
inline std::size_t transactionLevel() const;
/*! Determine whether the database connection is in the transaction state. */
inline bool inTransaction() const;
/*! Get namespace prefix for MySQL savepoints. */
inline const QString &getSavepointNamespace() const;
/*! Set namespace prefix for MySQL savepoints. */
DatabaseConnection &setSavepointNamespace(const QString &savepointNamespace);
private:
/*! Reset in transaction state and savepoints. */
DatabaseConnection &resetTransactions();
/*! Dynamic cast *this to the DatabaseConnection & derived type. */
DatabaseConnection &databaseConnection();
/*! Dynamic cast *this to the Concerns::CountsQueries & base type. */
Concerns::CountsQueries &countsQueries();
/*! The connection is in the transaction state. */
bool m_inTransaction = false;
/*! Active savepoints counter. */
std::size_t m_savepoints = 0;
/*! Namespace prefix for MySQL savepoints. */
QString m_savepointNamespace;
};
/* public */
std::size_t ManagesTransactions::transactionLevel() const
{
return m_savepoints;
}
bool ManagesTransactions::inTransaction() const
{
return m_inTransaction;
}
const QString &ManagesTransactions::getSavepointNamespace() const
{
return m_savepointNamespace;
}
} // namespace Concerns
} // namespace Orm
TINYORM_END_COMMON_NAMESPACE
#endif // ORM_CONCERNS_MANAGESTRANSACTIONS_HPP

View File

@@ -5,12 +5,12 @@
#include "orm/macros/systemheader.hpp"
TINY_SYSTEM_HEADER
#include <QElapsedTimer>
#include <QtSql/QSqlDatabase>
#include "orm/concerns/countsqueries.hpp"
#include "orm/concerns/detectslostconnections.hpp"
#include "orm/concerns/logsqueries.hpp"
#include "orm/concerns/managestransactions.hpp"
#include "orm/connectors/connectorinterface.hpp"
#include "orm/exceptions/queryerror.hpp"
#include "orm/query/grammars/grammar.hpp"
@@ -52,11 +52,15 @@ namespace Schema
/*! Database connection base class. */
class SHAREDLIB_EXPORT DatabaseConnection :
public Concerns::DetectsLostConnections,
public Concerns::ManagesTransactions,
public Concerns::LogsQueries,
public Concerns::CountsQueries
{
Q_DISABLE_COPY(DatabaseConnection)
// To access shouldCountElapsed() method
friend Concerns::ManagesTransactions;
public:
/*! Constructor. */
explicit DatabaseConnection(
@@ -83,24 +87,6 @@ namespace Schema
/*! Get a new raw query expression. */
inline Query::Expression raw(const QVariant &value) const;
// TODO next transaction method with callback silverqx
/*! Start a new database transaction. */
bool beginTransaction();
/*! Commit the active database transaction. */
bool commit();
/*! Rollback the active database transaction. */
bool rollBack();
/*! Start a new named transaction savepoint. */
bool savepoint(const QString &id);
/*! Start a new named transaction savepoint. */
bool savepoint(std::size_t id);
/*! Rollback to a named transaction savepoint. */
bool rollbackToSavepoint(const QString &id);
/*! Rollback to a named transaction savepoint. */
bool rollbackToSavepoint(std::size_t id);
/*! Get the number of active transactions. */
inline std::size_t transactionLevel() const;
/* Running SQL Queries */
/*! Run a select statement against the database. */
QSqlQuery
@@ -216,12 +202,6 @@ namespace Schema
/*! Reset the record modification state. */
inline void forgetRecordModificationState();
/*! Get namespace prefix for MySQL savepoints. */
inline const QString &getSavepointNamespace() const;
/*! Set namespace prefix for MySQL savepoints. */
inline DatabaseConnection &
setSavepointNamespace(const QString &savepointNamespace);
protected:
/*! Set the query grammar to the default implementation. */
void useDefaultQueryGrammar();
@@ -257,14 +237,12 @@ namespace Schema
/*! Reconnect to the database if a PDO connection is missing. */
void reconnectIfMissingConnection() const;
/*! Reset in transaction state and savepoints. */
DatabaseConnection &resetTransactions();
/*! Log database disconnected, invoked during MySQL ping. */
void logDisconnected();
/*! Log database connected, invoked during MySQL ping. */
void logConnected();
protected:
/*! The active QSqlDatabase connection name. */
std::optional<Connectors::ConnectionName> m_qtConnection = std::nullopt;
/*! The QSqlDatabase connection resolver. */
@@ -288,8 +266,6 @@ namespace Schema
/* Others */
/*! Indicates if the connection is in a "dry run". */
bool m_pretending = false;
/*! Namespace prefix for MySQL savepoints. */
QString m_savepointNamespace;
private:
/*! Prepare an SQL statement and return the query object. */
@@ -308,21 +284,13 @@ namespace Schema
const QString &queryString, const QVector<QVariant> &bindings,
const RunCallback<Return> &callback) const;
/*! Count transactional queries execution time and statements counter. */
std::optional<qint64>
hitTransactionalCounters(QElapsedTimer timer, bool countElapsed);
/*! Convert a named bindings map to the positional bindings vector. */
QVector<QVariant>
convertNamedToPositionalBindings(QVariantMap &&bindings) const;
/*! Determine if the elapsed time for queries should be counted. */
inline bool shouldCountElapsed() const;
/*! The flag for the database was disconnected, used during MySQL ping. */
bool m_disconnectedLogged = false;
/*! The flag for the database was connected, used during MySQL ping. */
bool m_connectedLogged = false;
/*! The connection is in the transaction state. */
bool m_inTransaction = false;
/*! Active savepoints counter. */
std::size_t m_savepoints = 0;
/*! Connection name, obtained from the connection configuration. */
QString m_connectionName;
@@ -357,11 +325,6 @@ namespace Schema
return Query::Expression(value);
}
std::size_t DatabaseConnection::transactionLevel() const
{
return m_savepoints;
}
const std::function<Connectors::ConnectionName()> &
DatabaseConnection::getQtConnectionResolver() const
{
@@ -403,19 +366,6 @@ namespace Schema
m_recordsModified = false;
}
const QString &DatabaseConnection::getSavepointNamespace() const
{
return m_savepointNamespace;
}
DatabaseConnection &
DatabaseConnection::setSavepointNamespace(const QString &savepointNamespace)
{
m_savepointNamespace = savepointNamespace;
return *this;
}
/* protected */
template<typename Return>
@@ -427,7 +377,7 @@ namespace Schema
reconnectIfMissingConnection();
// Elapsed timer needed
const auto countElapsed = !m_pretending && (m_debugSql || m_countingElapsed);
const auto countElapsed = shouldCountElapsed();
QElapsedTimer timer;
if (countElapsed)
@@ -488,11 +438,10 @@ namespace Schema
const RunCallback<Return> &callback) const
{
// FUTURE add info about in transaction into the exception that it was a reason why connection was not reconnected/recovered silverqx
if (m_inTransaction)
if (inTransaction())
std::rethrow_exception(ePtr);
return tryAgainIfCausedByLostConnection(ePtr, e, queryString, bindings,
callback);
return tryAgainIfCausedByLostConnection(ePtr, e, queryString, bindings, callback);
}
template<typename Return>
@@ -511,6 +460,11 @@ namespace Schema
std::rethrow_exception(ePtr);
}
bool DatabaseConnection::shouldCountElapsed() const
{
return !m_pretending && (m_debugSql || m_countingElapsed);
}
} // namespace Orm
TINYORM_END_COMMON_NAMESPACE

View File

@@ -7,6 +7,8 @@ TINYORM_BEGIN_COMMON_NAMESPACE
namespace Orm::Concerns
{
/* public */
bool CountsQueries::countingElapsed() const
{
return m_countingElapsed;
@@ -107,6 +109,29 @@ DatabaseConnection &CountsQueries::resetStatementsCounter()
return databaseConnection();
}
/* private */
std::optional<qint64>
CountsQueries::hitTransactionalCounters(const QElapsedTimer timer,
const bool countElapsed)
{
std::optional<qint64> elapsed;
if (countElapsed) {
// Hit elapsed timer
elapsed = timer.elapsed();
// Queries execution time counter
m_elapsedCounter += *elapsed;
}
// Query statements counter
if (m_countingStatements)
++m_statementsCounter.transactional;
return elapsed;
}
DatabaseConnection &CountsQueries::databaseConnection()
{
return dynamic_cast<DatabaseConnection &>(*this);

View File

@@ -1,5 +1,9 @@
#include "orm/concerns/logsqueries.hpp"
#if defined(TINYORM_DEBUG_SQL)
#include <QDebug>
#endif
#include "orm/databaseconnection.hpp"
#include "orm/macros/likely.hpp"
#ifdef TINYORM_DEBUG_SQL
@@ -167,6 +171,18 @@ LogsQueries::withFreshQueryLog(const std::function<QVector<Log>()> &callback)
/* private */
QVector<QVariant>
LogsQueries::convertNamedToPositionalBindings(QVariantMap &&bindings) const
{
QVector<QVariant> result;
result.reserve(bindings.size());
for (auto &&binding : bindings)
result << std::move(binding);
return result;
}
const DatabaseConnection &LogsQueries::databaseConnection() const
{
return dynamic_cast<const DatabaseConnection &>(*this);

View File

@@ -0,0 +1,248 @@
#include "orm/concerns/managestransactions.hpp"
#include "orm/concerns/countsqueries.hpp"
#include "orm/databaseconnection.hpp"
#include "orm/exceptions/sqltransactionerror.hpp"
#include "orm/support/databaseconfiguration.hpp"
#include "orm/utils/type.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Orm::Concerns
{
/* public */
ManagesTransactions::ManagesTransactions()
: m_savepointNamespace(Support::DatabaseConfiguration::defaultSavepointNamespace)
{}
bool ManagesTransactions::beginTransaction()
{
Q_ASSERT(m_inTransaction == false);
static const auto query = QStringLiteral("START TRANSACTION");
// Elapsed timer needed
const auto countElapsed = databaseConnection().shouldCountElapsed();
QElapsedTimer timer;
if (countElapsed)
timer.start();
if (!databaseConnection().pretending() &&
!databaseConnection().getQtConnection().transaction()
)
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
databaseConnection().getRawQtConnection().lastError());
m_inTransaction = true;
// Queries execution time counter / Query statements counter
auto elapsed = countsQueries().hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (databaseConnection().pretending())
databaseConnection().logTransactionQueryForPretend(query);
else
databaseConnection().logTransactionQuery(query, std::move(elapsed));
return true;
}
bool ManagesTransactions::commit()
{
Q_ASSERT(m_inTransaction);
static const auto query = QStringLiteral("COMMIT");
// Elapsed timer needed
const auto countElapsed = databaseConnection().shouldCountElapsed();
QElapsedTimer timer;
if (countElapsed)
timer.start();
if (!databaseConnection().pretending() &&
!databaseConnection().getQtConnection().commit()
)
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
databaseConnection().getRawQtConnection().lastError());
m_inTransaction = false;
// Queries execution time counter / Query statements counter
auto elapsed = countsQueries().hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (databaseConnection().pretending())
databaseConnection().logTransactionQueryForPretend(query);
else
databaseConnection().logTransactionQuery(query, std::move(elapsed));
return true;
}
bool ManagesTransactions::rollBack()
{
Q_ASSERT(m_inTransaction);
static const auto query = QStringLiteral("ROLLBACK");
// Elapsed timer needed
const auto countElapsed = databaseConnection().shouldCountElapsed();
QElapsedTimer timer;
if (countElapsed)
timer.start();
if (!databaseConnection().pretending() &&
!databaseConnection().getQtConnection().rollback()
)
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
databaseConnection().getRawQtConnection().lastError());
m_inTransaction = false;
// Queries execution time counter / Query statements counter
auto elapsed = countsQueries().hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (databaseConnection().pretending())
databaseConnection().logTransactionQueryForPretend(query);
else
databaseConnection().logTransactionQuery(query, std::move(elapsed));
return true;
}
bool ManagesTransactions::savepoint(const QString &id)
{
// TODO rewrite savepoint() and rollBack() with a new m_connection.statement() API silverqx
Q_ASSERT(m_inTransaction);
auto savePoint = databaseConnection().getQtQuery();
const auto query = QStringLiteral("SAVEPOINT %1_%2").arg(m_savepointNamespace, id);
// Elapsed timer needed
const auto countElapsed = databaseConnection().shouldCountElapsed();
QElapsedTimer timer;
if (countElapsed)
timer.start();
// Execute a savepoint query
if (!databaseConnection().pretending() && !savePoint.exec(query))
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
savePoint.lastError());
++m_savepoints;
// Queries execution time counter / Query statements counter
auto elapsed = countsQueries().hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (databaseConnection().pretending())
databaseConnection().logTransactionQueryForPretend(query);
else
databaseConnection().logTransactionQuery(query, std::move(elapsed));
return true;
}
bool ManagesTransactions::savepoint(const std::size_t id)
{
return savepoint(QString::number(id));
}
bool ManagesTransactions::rollbackToSavepoint(const QString &id)
{
Q_ASSERT(m_inTransaction);
Q_ASSERT(m_savepoints > 0);
auto rollbackToSavepoint = databaseConnection().getQtQuery();
const auto query = QStringLiteral("ROLLBACK TO SAVEPOINT %1_%2")
.arg(m_savepointNamespace, id);
// Elapsed timer needed
const auto countElapsed = databaseConnection().shouldCountElapsed();
QElapsedTimer timer;
if (countElapsed)
timer.start();
// Execute a rollback to savepoint query
if (!databaseConnection().pretending() && !rollbackToSavepoint.exec(query))
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
rollbackToSavepoint.lastError());
m_savepoints = std::max<std::size_t>(0, m_savepoints - 1);
// Queries execution time counter / Query statements counter
auto elapsed = countsQueries().hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (databaseConnection().pretending())
databaseConnection().logTransactionQueryForPretend(query);
else
databaseConnection().logTransactionQuery(query, std::move(elapsed));
return true;
}
bool ManagesTransactions::rollbackToSavepoint(const std::size_t id)
{
return rollbackToSavepoint(QString::number(id));
}
DatabaseConnection &
ManagesTransactions::setSavepointNamespace(const QString &savepointNamespace)
{
m_savepointNamespace = savepointNamespace;
return databaseConnection();
}
/* private */
DatabaseConnection &ManagesTransactions::resetTransactions()
{
m_savepoints = 0;
m_inTransaction = false;
return databaseConnection();
}
DatabaseConnection &ManagesTransactions::databaseConnection()
{
return dynamic_cast<DatabaseConnection &>(*this);
}
CountsQueries &ManagesTransactions::countsQueries()
{
return dynamic_cast<CountsQueries &>(*this);
}
} // namespace Orm::Concerns
TINYORM_END_COMMON_NAMESPACE

View File

@@ -1,13 +1,11 @@
#include "orm/databaseconnection.hpp"
#include <QDateTime>
#if defined(TINYORM_DEBUG_SQL) || defined(TINYORM_MYSQL_PING)
#if defined(TINYORM_MYSQL_PING)
#include <QDebug>
#endif
#include "orm/exceptions/sqltransactionerror.hpp"
#include "orm/query/querybuilder.hpp"
#include "orm/support/databaseconfiguration.hpp"
#include "orm/utils/type.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
@@ -45,7 +43,6 @@ DatabaseConnection::DatabaseConnection(
, m_database(database)
, m_tablePrefix(tablePrefix)
, m_config(config)
, m_savepointNamespace(Support::DatabaseConfiguration::defaultSavepointNamespace)
, m_connectionName(getConfig(NAME).value<QString>())
, m_hostName(getConfig(host_).value<QString>())
{}
@@ -81,199 +78,6 @@ QSharedPointer<QueryBuilder> DatabaseConnection::query()
return QSharedPointer<QueryBuilder>::create(*this, *m_queryGrammar);
}
bool DatabaseConnection::beginTransaction()
{
Q_ASSERT(m_inTransaction == false);
static const auto query = QStringLiteral("START TRANSACTION");
// Elapsed timer needed
const auto countElapsed = !m_pretending && (m_debugSql || m_countingElapsed);
QElapsedTimer timer;
if (countElapsed)
timer.start();
if (!m_pretending && !getQtConnection().transaction())
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
getRawQtConnection().lastError());
m_inTransaction = true;
// Queries execution time counter / Query statements counter
auto elapsed = hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (m_pretending)
logTransactionQueryForPretend(query);
else
logTransactionQuery(query, std::move(elapsed));
return true;
}
bool DatabaseConnection::commit()
{
Q_ASSERT(m_inTransaction);
static const auto query = QStringLiteral("COMMIT");
// Elapsed timer needed
const auto countElapsed = !m_pretending && (m_debugSql || m_countingElapsed);
QElapsedTimer timer;
if (countElapsed)
timer.start();
// TODO rewrite transactions to DatabaseConnection::statement, so I have access to QSqlQuery for logQuery() silverqx
if (!m_pretending && !getQtConnection().commit())
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
getRawQtConnection().lastError());
m_inTransaction = false;
// Queries execution time counter / Query statements counter
auto elapsed = hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (m_pretending)
logTransactionQueryForPretend(query);
else
logTransactionQuery(query, std::move(elapsed));
return true;
}
bool DatabaseConnection::rollBack()
{
Q_ASSERT(m_inTransaction);
static const auto query = QStringLiteral("ROLLBACK");
// Elapsed timer needed
const auto countElapsed = !m_pretending && (m_debugSql || m_countingElapsed);
QElapsedTimer timer;
if (countElapsed)
timer.start();
if (!m_pretending && !getQtConnection().rollback())
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
getRawQtConnection().lastError());
m_inTransaction = false;
// Queries execution time counter / Query statements counter
auto elapsed = hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (m_pretending)
logTransactionQueryForPretend(query);
else
logTransactionQuery(query, std::move(elapsed));
return true;
}
bool DatabaseConnection::savepoint(const QString &id)
{
// TODO rewrite savepoint() and rollBack() with a new m_connection.statement() API silverqx
Q_ASSERT(m_inTransaction);
auto savePoint = getQtQuery();
const auto query = QStringLiteral("SAVEPOINT %1_%2").arg(m_savepointNamespace, id);
// Elapsed timer needed
const auto countElapsed = !m_pretending && (m_debugSql || m_countingElapsed);
QElapsedTimer timer;
if (countElapsed)
timer.start();
// Execute a savepoint query
if (!m_pretending && !savePoint.exec(query))
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
savePoint.lastError());
++m_savepoints;
// Queries execution time counter / Query statements counter
auto elapsed = hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (m_pretending)
logTransactionQueryForPretend(query);
else
logTransactionQuery(query, std::move(elapsed));
return true;
}
bool DatabaseConnection::savepoint(const std::size_t id)
{
return savepoint(QString::number(id));
}
bool DatabaseConnection::rollbackToSavepoint(const QString &id)
{
Q_ASSERT(m_inTransaction);
Q_ASSERT(m_savepoints > 0);
auto rollbackToSavepoint = getQtQuery();
const auto query = QStringLiteral("ROLLBACK TO SAVEPOINT %1_%2")
.arg(m_savepointNamespace, id);
// Elapsed timer needed
const auto countElapsed = !m_pretending && (m_debugSql || m_countingElapsed);
QElapsedTimer timer;
if (countElapsed)
timer.start();
// Execute a rollback to savepoint query
if (!m_pretending && !rollbackToSavepoint.exec(query))
throw Exceptions::SqlTransactionError(
QStringLiteral("Statement in %1() failed : %2")
.arg(__tiny_func__, query),
rollbackToSavepoint.lastError());
m_savepoints = std::max<std::size_t>(0, m_savepoints - 1);
// Queries execution time counter / Query statements counter
auto elapsed = hitTransactionalCounters(timer, countElapsed);
/* Once we have run the transaction query we will calculate the time
that it took to run and then log the query and execution time.
We'll log time in milliseconds. */
if (m_pretending)
logTransactionQueryForPretend(query);
else
logTransactionQuery(query, std::move(elapsed));
return true;
}
bool DatabaseConnection::rollbackToSavepoint(const std::size_t id)
{
return rollbackToSavepoint(QString::number(id));
}
/* Running SQL Queries */
QSqlQuery
@@ -578,27 +382,6 @@ void DatabaseConnection::bindValues(QSqlQuery &query,
}
}
std::optional<qint64>
DatabaseConnection::hitTransactionalCounters(const QElapsedTimer timer,
const bool countElapsed)
{
std::optional<qint64> elapsed;
if (countElapsed) {
// Hit elapsed timer
elapsed = timer.elapsed();
// Queries execution time counter
m_elapsedCounter += *elapsed;
}
// Query statements counter
if (m_countingStatements)
++m_statementsCounter.transactional;
return elapsed;
}
bool DatabaseConnection::pingDatabase()
{
throw Exceptions::RuntimeError(
@@ -771,16 +554,9 @@ void DatabaseConnection::reconnectIfMissingConnection() const
}
}
DatabaseConnection &DatabaseConnection::resetTransactions()
{
m_savepoints = 0;
m_inTransaction = false;
return *this;
}
void DatabaseConnection::logDisconnected()
{
#ifdef TINYORM_MYSQL_PING
if (m_disconnectedLogged)
return;
@@ -794,10 +570,12 @@ void DatabaseConnection::logDisconnected()
m_connectionName.toUtf8().constData(),
m_hostName.toUtf8().constData(),
m_database.toUtf8().constData());
#endif
}
void DatabaseConnection::logConnected()
{
#ifdef TINYORM_MYSQL_PING
if (m_connectedLogged)
return;
@@ -806,11 +584,14 @@ void DatabaseConnection::logConnected()
// Reset disconnected flag
m_disconnectedLogged = false;
/* I still don't know if it's a good idea to log this to the console by default,
it's a very important log message though. */
qInfo("%s database connected (%s, %s@%s)",
driverNamePrintable().toUtf8().constData(),
m_connectionName.toUtf8().constData(),
m_hostName.toUtf8().constData(),
m_database.toUtf8().constData());
#endif
}
/* private */
@@ -828,18 +609,6 @@ QSqlQuery DatabaseConnection::prepareQuery(const QString &queryString)
return query;
}
QVector<QVariant>
DatabaseConnection::convertNamedToPositionalBindings(QVariantMap &&bindings) const
{
QVector<QVariant> result;
result.reserve(bindings.size());
for (auto &&binding : bindings)
result << std::move(binding);
return result;
}
} // namespace Orm
TINYORM_END_COMMON_NAMESPACE

View File

@@ -7,6 +7,7 @@ sourcesList += \
$$PWD/orm/concerns/detectslostconnections.cpp \
$$PWD/orm/concerns/hasconnectionresolver.cpp \
$$PWD/orm/concerns/logsqueries.cpp \
$$PWD/orm/concerns/managestransactions.cpp \
$$PWD/orm/connectors/connectionfactory.cpp \
$$PWD/orm/connectors/connector.cpp \
$$PWD/orm/connectors/mysqlconnector.cpp \