Replace Statement::Ptr with std::shared_ptr

This commit is contained in:
Kacperos155 2022-01-25 18:40:23 +01:00
parent edf49ee141
commit 6da299db12
4 changed files with 112 additions and 203 deletions

View File

@ -14,8 +14,11 @@
#include <SQLiteCpp/Exception.h>
#include <string>
#include <memory>
#include <climits> // For INT_MAX
// Forward declarations to avoid inclusion of <sqlite3.h> in a header
struct sqlite3_stmt;
namespace SQLite
{
@ -26,7 +29,6 @@ extern const int TEXT; ///< SQLITE_TEXT
extern const int BLOB; ///< SQLITE_BLOB
extern const int Null; ///< SQLITE_NULL
/**
* @brief Encapsulation of a Column in a row of the result pointed by the prepared Statement.
*
@ -52,7 +54,7 @@ public:
* @param[in] aStmtPtr Shared pointer to the prepared SQLite Statement Object.
* @param[in] aIndex Index of the column in the row of result, starting at 0
*/
Column(Statement::Ptr& aStmtPtr, int aIndex) noexcept;
Column(Statement::TStatementPtr& aStmtPtr, int aIndex) noexcept;
// default destructor: the finalization will be done by the destructor of the last shared pointer
// default copy constructor and assignment operator are perfectly suited :
@ -250,8 +252,8 @@ public:
}
private:
Statement::Ptr mStmtPtr; ///< Shared Pointer to the prepared SQLite Statement Object
int mIndex; ///< Index of the column in the row of result, starting at 0
Statement::TStatementPtr mStmtPtr; ///< Shared Pointer to the prepared SQLite Statement Object
int mIndex; ///< Index of the column in the row of result, starting at 0
};
/**
@ -281,7 +283,7 @@ T Statement::getColumns()
template<typename T, const int... Is>
T Statement::getColumns(const std::integer_sequence<int, Is...>)
{
return T{Column(mStmtPtr, Is)...};
return T{Column(mpPreparedStatement, Is)...};
}
#endif

View File

@ -15,6 +15,7 @@
#include <string>
#include <map>
#include <memory>
// Forward declarations to avoid inclusion of <sqlite3.h> in a header
struct sqlite3;
@ -50,8 +51,6 @@ extern const int OK; ///< SQLITE_OK
*/
class Statement
{
friend class Column; // For access to Statement::Ptr inner class
public:
/**
* @brief Compile and register the SQL query for the provided SQLite Database Connection
@ -645,52 +644,8 @@ public:
/// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
const char* getErrorMsg() const noexcept;
private:
/**
* @brief Shared pointer to the sqlite3_stmt SQLite Statement Object.
*
* Manage the finalization of the sqlite3_stmt with a reference counter.
*
* This is a internal class, not part of the API (hence full documentation is in the cpp).
*/
// TODO Convert this whole custom pointer to a C++11 std::shared_ptr with a custom deleter
class Ptr
{
public:
// Prepare the statement and initialize its reference counter
Ptr(sqlite3* apSQLite, std::string& aQuery);
// Copy constructor increments the ref counter
Ptr(const Ptr& aPtr);
// Move constructor
Ptr(Ptr&& aPtr);
// Decrement the ref counter and finalize the sqlite3_stmt when it reaches 0
~Ptr();
/// Inline cast operator returning the pointer to SQLite Database Connection Handle
operator sqlite3*() const
{
return mpSQLite;
}
/// Inline cast operator returning the pointer to SQLite Statement Object
operator sqlite3_stmt*() const
{
return mpStmt;
}
private:
/// @{ Unused/forbidden copy/assignment operator
Ptr& operator=(const Ptr& aPtr);
/// @}
private:
sqlite3* mpSQLite; //!< Pointer to SQLite Database Connection Handle
sqlite3_stmt* mpStmt; //!< Pointer to SQLite Statement Object
unsigned int* mpRefCount; //!< Pointer to the heap allocated reference counter of the sqlite3_stmt
//!< (to share it with Column objects)
};
/// Shared pointer to SQLite Prepared Statement Object
typedef std::shared_ptr<sqlite3_stmt> TStatementPtr;
private:
/**
@ -702,7 +657,7 @@ private:
{
if (SQLite::OK != aRet)
{
throw SQLite::Exception(mStmtPtr, aRet);
throw SQLite::Exception(mpSQLite, aRet);
}
}
@ -728,17 +683,33 @@ private:
}
}
/**
* @brief Prepare statement object.
*
* @return Shared pointer to prepared statement object
*/
TStatementPtr prepareStatement();
/**
* @brief Return a prepared statement object.
*
* Throw an exception if the statement object was not prepared.
* @return raw pointer to Prepared Statement Object
*/
sqlite3_stmt* getPreparedStatement() const;
private:
/// Map of columns index by name (mutable so getColumnIndex can be const)
typedef std::map<std::string, int> TColumnNames;
private:
std::string mQuery; //!< UTF-8 SQL Query
Ptr mStmtPtr; //!< Shared Pointer to the prepared SQLite Statement Object
int mColumnCount; //!< Number of columns in the result of the prepared statement
mutable TColumnNames mColumnNames; //!< Map of columns index by name (mutable so getColumnIndex can be const)
bool mbHasRow; //!< true when a row has been fetched with executeStep()
bool mbDone; //!< true when the last executeStep() had no more row to fetch
std::string mQuery; //!< UTF-8 SQL Query
sqlite3* mpSQLite; //!< Pointer to SQLite Database Connection Handle
TStatementPtr mpPreparedStatement; //!< Shared Pointer to the prepared SQLite Statement Object
int mColumnCount{0}; //!< Number of columns in the result of the prepared statement
mutable TColumnNames mColumnNames; //!< Map of columns index by name (mutable so getColumnIndex can be const)
bool mbHasRow{false}; //!< true when a row has been fetched with executeStep()
bool mbDone{false}; //!< true when the last executeStep() had no more row to fetch
};

View File

@ -26,7 +26,7 @@ const int Null = SQLITE_NULL;
// Encapsulation of a Column in a row of the result pointed by the prepared Statement.
Column::Column(Statement::Ptr& aStmtPtr, int aIndex) noexcept :
Column::Column(Statement::TStatementPtr& aStmtPtr, int aIndex) noexcept :
mStmtPtr(aStmtPtr),
mIndex(aIndex)
{
@ -35,21 +35,21 @@ Column::Column(Statement::Ptr& aStmtPtr, int aIndex) noexcept :
// Return the named assigned to this result column (potentially aliased)
const char* Column::getName() const noexcept
{
return sqlite3_column_name(mStmtPtr, mIndex);
return sqlite3_column_name(mStmtPtr.get(), mIndex);
}
#ifdef SQLITE_ENABLE_COLUMN_METADATA
// Return the name of the table column that is the origin of this result column
const char* Column::getOriginName() const noexcept
{
return sqlite3_column_origin_name(mStmtPtr, mIndex);
return sqlite3_column_origin_name(mStmtPtr.get(), mIndex);
}
#endif
// Return the integer value of the column specified by its index starting at 0
int Column::getInt() const noexcept
{
return sqlite3_column_int(mStmtPtr, mIndex);
return sqlite3_column_int(mStmtPtr.get(), mIndex);
}
// Return the unsigned integer value of the column specified by its index starting at 0
@ -61,26 +61,26 @@ unsigned Column::getUInt() const noexcept
// Return the 64bits integer value of the column specified by its index starting at 0
long long Column::getInt64() const noexcept
{
return sqlite3_column_int64(mStmtPtr, mIndex);
return sqlite3_column_int64(mStmtPtr.get(), mIndex);
}
// Return the double value of the column specified by its index starting at 0
double Column::getDouble() const noexcept
{
return sqlite3_column_double(mStmtPtr, mIndex);
return sqlite3_column_double(mStmtPtr.get(), mIndex);
}
// Return a pointer to the text value (NULL terminated string) of the column specified by its index starting at 0
const char* Column::getText(const char* apDefaultValue /* = "" */) const noexcept
{
const char* pText = reinterpret_cast<const char*>(sqlite3_column_text(mStmtPtr, mIndex));
const char* pText = reinterpret_cast<const char*>(sqlite3_column_text(mStmtPtr.get(), mIndex));
return (pText?pText:apDefaultValue);
}
// Return a pointer to the blob value (*not* NULL terminated) of the column specified by its index starting at 0
const void* Column::getBlob() const noexcept
{
return sqlite3_column_blob(mStmtPtr, mIndex);
return sqlite3_column_blob(mStmtPtr.get(), mIndex);
}
// Return a std::string to a TEXT or BLOB column
@ -88,23 +88,23 @@ std::string Column::getString() const
{
// Note: using sqlite3_column_blob and not sqlite3_column_text
// - no need for sqlite3_column_text to add a \0 on the end, as we're getting the bytes length directly
const char *data = static_cast<const char *>(sqlite3_column_blob(mStmtPtr, mIndex));
const char *data = static_cast<const char *>(sqlite3_column_blob(mStmtPtr.get(), mIndex));
// SQLite docs: "The safest policy is to invoke… sqlite3_column_blob() followed by sqlite3_column_bytes()"
// Note: std::string is ok to pass nullptr as first arg, if length is 0
return std::string(data, sqlite3_column_bytes(mStmtPtr, mIndex));
return std::string(data, sqlite3_column_bytes(mStmtPtr.get(), mIndex));
}
// Return the type of the value of the column
int Column::getType() const noexcept
{
return sqlite3_column_type(mStmtPtr, mIndex);
return sqlite3_column_type(mStmtPtr.get(), mIndex);
}
// Return the number of bytes used by the text value of the column
int Column::getBytes() const noexcept
{
return sqlite3_column_bytes(mStmtPtr, mIndex);
return sqlite3_column_bytes(mStmtPtr.get(), mIndex);
}
// Standard std::ostream inserter

View File

@ -22,21 +22,21 @@ namespace SQLite
Statement::Statement(Database &aDatabase, const char* apQuery) :
mQuery(apQuery),
mStmtPtr(aDatabase.getHandle(), mQuery), // prepare the SQL query, and ref count (needs Database friendship)
mColumnCount(0),
mbHasRow(false),
mbDone(false)
mpSQLite(aDatabase.getHandle()),
mpPreparedStatement(prepareStatement()) // prepare the SQL query (needs Database friendship)
{
mColumnCount = sqlite3_column_count(mStmtPtr);
mColumnCount = sqlite3_column_count(mpPreparedStatement.get());
}
Statement::Statement(Statement&& aStatement) noexcept :
mQuery(std::move(aStatement.mQuery)),
mStmtPtr(std::move(aStatement.mStmtPtr)),
mpSQLite(aStatement.mpSQLite),
mpPreparedStatement(std::move(aStatement.mpPreparedStatement)),
mColumnCount(aStatement.mColumnCount),
mbHasRow(aStatement.mbHasRow),
mbDone(aStatement.mbDone)
{
aStatement.mpSQLite = nullptr;
aStatement.mColumnCount = 0;
aStatement.mbHasRow = false;
aStatement.mbDone = false;
@ -53,53 +53,53 @@ int Statement::tryReset() noexcept
{
mbHasRow = false;
mbDone = false;
return sqlite3_reset(mStmtPtr);
return sqlite3_reset(mpPreparedStatement.get());
}
// Clears away all the bindings of a prepared statement (can be associated with #reset() above).
void Statement::clearBindings()
{
const int ret = sqlite3_clear_bindings(mStmtPtr);
const int ret = sqlite3_clear_bindings(getPreparedStatement());
check(ret);
}
int Statement::getIndex(const char * const apName)
{
return sqlite3_bind_parameter_index(mStmtPtr, apName);
return sqlite3_bind_parameter_index(getPreparedStatement(), apName);
}
// Bind an 32bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const int32_t aValue)
{
const int ret = sqlite3_bind_int(mStmtPtr, aIndex, aValue);
const int ret = sqlite3_bind_int(getPreparedStatement(), aIndex, aValue);
check(ret);
}
// Bind a 32bits unsigned int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const uint32_t aValue)
{
const int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue);
const int ret = sqlite3_bind_int64(getPreparedStatement(), aIndex, aValue);
check(ret);
}
// Bind a 64bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const int64_t aValue)
{
const int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue);
const int ret = sqlite3_bind_int64(getPreparedStatement(), aIndex, aValue);
check(ret);
}
// Bind a double (64bits float) value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const double aValue)
{
const int ret = sqlite3_bind_double(mStmtPtr, aIndex, aValue);
const int ret = sqlite3_bind_double(getPreparedStatement(), aIndex, aValue);
check(ret);
}
// Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const std::string& aValue)
{
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(),
const int ret = sqlite3_bind_text(getPreparedStatement(), aIndex, aValue.c_str(),
static_cast<int>(aValue.size()), SQLITE_TRANSIENT);
check(ret);
}
@ -107,21 +107,21 @@ void Statement::bind(const int aIndex, const std::string& aValue)
// Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const char* apValue)
{
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_TRANSIENT);
const int ret = sqlite3_bind_text(getPreparedStatement(), aIndex, apValue, -1, SQLITE_TRANSIENT);
check(ret);
}
// Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex, const void* apValue, const int aSize)
{
const int ret = sqlite3_bind_blob(mStmtPtr, aIndex, apValue, aSize, SQLITE_TRANSIENT);
const int ret = sqlite3_bind_blob(getPreparedStatement(), aIndex, apValue, aSize, SQLITE_TRANSIENT);
check(ret);
}
// Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const int aIndex, const std::string& aValue)
{
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(),
const int ret = sqlite3_bind_text(getPreparedStatement(), aIndex, aValue.c_str(),
static_cast<int>(aValue.size()), SQLITE_STATIC);
check(ret);
}
@ -129,21 +129,21 @@ void Statement::bindNoCopy(const int aIndex, const std::string& aValue)
// Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const int aIndex, const char* apValue)
{
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_STATIC);
const int ret = sqlite3_bind_text(getPreparedStatement(), aIndex, apValue, -1, SQLITE_STATIC);
check(ret);
}
// Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bindNoCopy(const int aIndex, const void* apValue, const int aSize)
{
const int ret = sqlite3_bind_blob(mStmtPtr, aIndex, apValue, aSize, SQLITE_STATIC);
const int ret = sqlite3_bind_blob(getPreparedStatement(), aIndex, apValue, aSize, SQLITE_STATIC);
check(ret);
}
// Bind a NULL value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
void Statement::bind(const int aIndex)
{
const int ret = sqlite3_bind_null(mStmtPtr, aIndex);
const int ret = sqlite3_bind_null(getPreparedStatement(), aIndex);
check(ret);
}
@ -154,9 +154,9 @@ bool Statement::executeStep()
const int ret = tryExecuteStep();
if ((SQLITE_ROW != ret) && (SQLITE_DONE != ret)) // on row or no (more) row ready, else it's a problem
{
if (ret == sqlite3_errcode(mStmtPtr))
if (ret == sqlite3_errcode(mpSQLite))
{
throw SQLite::Exception(mStmtPtr, ret);
throw SQLite::Exception(mpSQLite, ret);
}
else
{
@ -177,9 +177,9 @@ int Statement::exec()
{
throw SQLite::Exception("exec() does not expect results. Use executeStep.");
}
else if (ret == sqlite3_errcode(mStmtPtr))
else if (ret == sqlite3_errcode(mpSQLite))
{
throw SQLite::Exception(mStmtPtr, ret);
throw SQLite::Exception(mpSQLite, ret);
}
else
{
@ -188,36 +188,27 @@ int Statement::exec()
}
// Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE)
return sqlite3_changes(mStmtPtr);
return sqlite3_changes(mpSQLite);
}
int Statement::tryExecuteStep() noexcept
{
if (false == mbDone)
if (mbDone)
{
const int ret = sqlite3_step(mStmtPtr);
if (SQLITE_ROW == ret) // one row is ready : call getColumn(N) to access it
{
mbHasRow = true;
}
else if (SQLITE_DONE == ret) // no (more) row ready : the query has finished executing
{
mbHasRow = false;
mbDone = true;
}
else
{
mbHasRow = false;
mbDone = false;
}
return SQLITE_MISUSE; // Statement needs to be reseted !
}
return ret;
const int ret = sqlite3_step(mpPreparedStatement.get());
if (SQLITE_ROW == ret) // one row is ready : call getColumn(N) to access it
{
mbHasRow = true;
}
else
{
// Statement needs to be reseted !
return SQLITE_MISUSE;
mbHasRow = false;
mbDone = SQLITE_DONE == ret; // check if the query has finished executing
}
return ret;
}
@ -229,7 +220,7 @@ Column Statement::getColumn(const int aIndex)
checkIndex(aIndex);
// Share the Statement Object handle with the new Column created
return Column(mStmtPtr, aIndex);
return Column(mpPreparedStatement, aIndex);
}
// Return a copy of the column data specified by its column name starting at 0
@ -240,7 +231,7 @@ Column Statement::getColumn(const char* apName)
const int index = getColumnIndex(apName);
// Share the Statement Object handle with the new Column created
return Column(mStmtPtr, index);
return Column(mpPreparedStatement, index);
}
// Test if the column is NULL
@ -248,21 +239,21 @@ bool Statement::isColumnNull(const int aIndex) const
{
checkRow();
checkIndex(aIndex);
return (SQLITE_NULL == sqlite3_column_type(mStmtPtr, aIndex));
return (SQLITE_NULL == sqlite3_column_type(getPreparedStatement(), aIndex));
}
bool Statement::isColumnNull(const char* apName) const
{
checkRow();
const int index = getColumnIndex(apName);
return (SQLITE_NULL == sqlite3_column_type(mStmtPtr, index));
return (SQLITE_NULL == sqlite3_column_type(getPreparedStatement(), index));
}
// Return the named assigned to the specified result column (potentially aliased)
const char* Statement::getColumnName(const int aIndex) const
{
checkIndex(aIndex);
return sqlite3_column_name(mStmtPtr, aIndex);
return sqlite3_column_name(getPreparedStatement(), aIndex);
}
#ifdef SQLITE_ENABLE_COLUMN_METADATA
@ -270,7 +261,7 @@ const char* Statement::getColumnName(const int aIndex) const
const char* Statement::getColumnOriginName(const int aIndex) const
{
checkIndex(aIndex);
return sqlite3_column_origin_name(mStmtPtr, aIndex);
return sqlite3_column_origin_name(getPreparedStatement(), aIndex);
}
#endif
@ -282,7 +273,7 @@ int Statement::getColumnIndex(const char* apName) const
{
for (int i = 0; i < mColumnCount; ++i)
{
const char* pName = sqlite3_column_name(mStmtPtr, i);
const char* pName = sqlite3_column_name(getPreparedStatement(), i);
mColumnNames[pName] = i;
}
}
@ -299,7 +290,7 @@ int Statement::getColumnIndex(const char* apName) const
const char * Statement::getColumnDeclaredType(const int aIndex) const
{
checkIndex(aIndex);
const char * result = sqlite3_column_decltype(mStmtPtr, aIndex);
const char * result = sqlite3_column_decltype(getPreparedStatement(), aIndex);
if (!result)
{
throw SQLite::Exception("Could not determine declared column type.");
@ -313,119 +304,64 @@ const char * Statement::getColumnDeclaredType(const int aIndex) const
// Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
int Statement::getChanges() const noexcept
{
return sqlite3_changes(mStmtPtr);
return sqlite3_changes(mpSQLite);
}
int Statement::getBindParameterCount() const noexcept
{
return sqlite3_bind_parameter_count(mStmtPtr);
return sqlite3_bind_parameter_count(mpPreparedStatement.get());
}
// Return the numeric result code for the most recent failed API call (if any).
int Statement::getErrorCode() const noexcept
{
return sqlite3_errcode(mStmtPtr);
return sqlite3_errcode(mpSQLite);
}
// Return the extended numeric result code for the most recent failed API call (if any).
int Statement::getExtendedErrorCode() const noexcept
{
return sqlite3_extended_errcode(mStmtPtr);
return sqlite3_extended_errcode(mpSQLite);
}
// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
const char* Statement::getErrorMsg() const noexcept
{
return sqlite3_errmsg(mStmtPtr);
return sqlite3_errmsg(mpSQLite);
}
// Return a UTF-8 string containing the SQL text of prepared statement with bound parameters expanded.
std::string Statement::getExpandedSQL() {
char* expanded = sqlite3_expanded_sql(mStmtPtr);
char* expanded = sqlite3_expanded_sql(getPreparedStatement());
std::string expandedString(expanded);
sqlite3_free(expanded);
return expandedString;
}
////////////////////////////////////////////////////////////////////////////////
// Internal class : shared pointer to the sqlite3_stmt SQLite Statement Object
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Prepare the statement and initialize its reference counter
*
* @param[in] apSQLite The sqlite3 database connexion
* @param[in] aQuery The SQL query string to prepare
*/
Statement::Ptr::Ptr(sqlite3* apSQLite, std::string& aQuery) :
mpSQLite(apSQLite),
mpStmt(NULL),
mpRefCount(NULL)
// Prepare SQLite statement object and return shared pointer to this object
Statement::TStatementPtr Statement::prepareStatement()
{
const int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), static_cast<int>(aQuery.size()), &mpStmt, NULL);
sqlite3_stmt* statement;
const int ret = sqlite3_prepare_v2(mpSQLite, mQuery.c_str(), static_cast<int>(mQuery.size()), &statement, NULL);
if (SQLITE_OK != ret)
{
throw SQLite::Exception(apSQLite, ret);
throw SQLite::Exception(mpSQLite, ret);
}
// Initialize the reference counter of the sqlite3_stmt :
// used to share the mStmtPtr between Statement and Column objects;
// This is needed to enable Column objects to live longer than the Statement objet it refers to.
mpRefCount = new unsigned int(1); // NOLINT(readability/casting)
}
/**
* @brief Copy constructor increments the ref counter
*
* @param[in] aPtr Pointer to copy
*/
Statement::Ptr::Ptr(const Statement::Ptr& aPtr) :
mpSQLite(aPtr.mpSQLite),
mpStmt(aPtr.mpStmt),
mpRefCount(aPtr.mpRefCount)
{
assert(mpRefCount);
assert(0 != *mpRefCount);
// Increment the reference counter of the sqlite3_stmt,
// asking not to finalize the sqlite3_stmt during the lifetime of the new objet
++(*mpRefCount);
}
Statement::Ptr::Ptr(Ptr&& aPtr) :
mpSQLite(aPtr.mpSQLite),
mpStmt(aPtr.mpStmt),
mpRefCount(aPtr.mpRefCount)
{
aPtr.mpSQLite = nullptr;
aPtr.mpStmt = nullptr;
aPtr.mpRefCount = nullptr;
}
/**
* @brief Decrement the ref counter and finalize the sqlite3_stmt when it reaches 0
*/
Statement::Ptr::~Ptr()
{
if (mpRefCount)
{
assert(0 != *mpRefCount);
// Decrement and check the reference counter of the sqlite3_stmt
--(*mpRefCount);
if (0 == *mpRefCount)
return Statement::TStatementPtr(statement, [](sqlite3_stmt* stmt)
{
// If count reaches zero, finalize the sqlite3_stmt, as no Statement nor Column objet use it anymore.
// No need to check the return code, as it is the same as the last statement evaluation.
sqlite3_finalize(mpStmt);
// and delete the reference counter
delete mpRefCount;
mpRefCount = nullptr;
mpStmt = nullptr;
}
// else, the finalization will be done later, by the last object
}
sqlite3_finalize(stmt);
});
}
// Return prepered statement object or throw
sqlite3_stmt* Statement::getPreparedStatement() const
{
sqlite3_stmt* ret = mpPreparedStatement.get();
if (ret)
{
return ret;
}
throw SQLite::Exception("Statement was not prepared.");
}
} // namespace SQLite