mirror of
https://github.com/cuberite/SQLiteCpp.git
synced 2025-08-04 17:56:13 -04:00
Added a reference counter to the SQLite Statement Object handle
- manages its lifespan (tracks ownerchip) across the copy to a Column object
This commit is contained in:
parent
17124b3025
commit
9c2544ef16
@ -18,26 +18,33 @@ namespace SQLite
|
|||||||
// Compile and register the SQL query for the provided SQLite Database Connection
|
// Compile and register the SQL query for the provided SQLite Database Connection
|
||||||
Statement::Statement(Database &aDatabase, const char* apQuery) : // throw(SQLite::Exception)
|
Statement::Statement(Database &aDatabase, const char* apQuery) : // throw(SQLite::Exception)
|
||||||
mpStmt(NULL),
|
mpStmt(NULL),
|
||||||
mDatabase(aDatabase),
|
mpStmtRefCount(NULL),
|
||||||
|
mpSQLite(aDatabase.mpSQLite),
|
||||||
mQuery(apQuery),
|
mQuery(apQuery),
|
||||||
mbOk(false),
|
mbOk(false),
|
||||||
mbDone(false)
|
mbDone(false)
|
||||||
{
|
{
|
||||||
int ret = sqlite3_prepare_v2(mDatabase.mpSQLite, mQuery.c_str(), mQuery.size(), &mpStmt, NULL);
|
int ret = sqlite3_prepare_v2(mpSQLite, mQuery.c_str(), mQuery.size(), &mpStmt, NULL);
|
||||||
check(ret);
|
check(ret);
|
||||||
mColumnCount = sqlite3_column_count(mpStmt);
|
mColumnCount = sqlite3_column_count(mpStmt);
|
||||||
|
mpStmtRefCount = new unsigned int;
|
||||||
|
*mpStmtRefCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize and unregister the SQL query from the SQLite Database Connection.
|
// Finalize and unregister the SQL query from the SQLite Database Connection.
|
||||||
Statement::~Statement(void) throw() // nothrow
|
Statement::~Statement(void) throw() // nothrow
|
||||||
{
|
{
|
||||||
int ret = sqlite3_finalize(mpStmt);
|
(*mpStmtRefCount)--;
|
||||||
if (SQLITE_OK != ret)
|
if (0 == *mpStmtRefCount)
|
||||||
{
|
{
|
||||||
// Never throw an exception in a destructor
|
int ret = sqlite3_finalize(mpStmt);
|
||||||
//std::cout << sqlite3_errmsg(mDatabase.mpSQLite);
|
if (SQLITE_OK != ret)
|
||||||
|
{
|
||||||
|
// Never throw an exception in a destructor
|
||||||
|
//std::cout << sqlite3_errmsg(mpSQLite);
|
||||||
|
}
|
||||||
|
mpStmt = NULL;
|
||||||
}
|
}
|
||||||
mpStmt = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the statement to make it ready for a new execution
|
// Reset the statement to make it ready for a new execution
|
||||||
@ -158,9 +165,13 @@ bool Statement::executeStep(void) // throw(SQLite::Exception)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw SQLite::Exception(sqlite3_errmsg(mDatabase.mpSQLite));
|
throw SQLite::Exception(sqlite3_errmsg(mpSQLite));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw SQLite::Exception("Statement need to be reseted");
|
||||||
|
}
|
||||||
|
|
||||||
return mbOk;
|
return mbOk;
|
||||||
}
|
}
|
||||||
@ -177,7 +188,7 @@ Statement::Column Statement::getColumn(const int aIndex) const // throw(SQLite::
|
|||||||
throw SQLite::Exception("Column index out of range");
|
throw SQLite::Exception("Column index out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(mDatabase.mpSQLite, mpStmt, aIndex);
|
return Column(mpSQLite, mpStmt, mpStmtRefCount, aIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if the column is NULL
|
// Test if the column is NULL
|
||||||
@ -195,12 +206,13 @@ bool Statement::isColumnNull(const int aIndex) const // throw(SQLite::Exception)
|
|||||||
return (SQLITE_NULL == sqlite3_column_type(mpStmt, aIndex));
|
return (SQLITE_NULL == sqlite3_column_type(mpStmt, aIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check if aRet equal SQLITE_OK, else throw a SQLite::Exception with the SQLite error message
|
// Check if aRet equal SQLITE_OK, else throw a SQLite::Exception with the SQLite error message
|
||||||
void Statement::check(const int aRet) const // throw(SQLite::Exception)
|
void Statement::check(const int aRet) const // throw(SQLite::Exception)
|
||||||
{
|
{
|
||||||
if (SQLITE_OK != aRet)
|
if (SQLITE_OK != aRet)
|
||||||
{
|
{
|
||||||
throw SQLite::Exception(sqlite3_errmsg(mDatabase.mpSQLite));
|
throw SQLite::Exception(sqlite3_errmsg(mpSQLite));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,21 +220,29 @@ void Statement::check(const int aRet) const // throw(SQLite::Exception)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Implementation of the inner class Statement::Column
|
// Implementation of the inner class Statement::Column
|
||||||
//
|
//
|
||||||
// Warning : you should never try to use directly a Column object, nor copying it;
|
|
||||||
// is is only an Adapter class designed to convert the result value
|
|
||||||
// of Statement::getColumn() to the data type you want
|
|
||||||
//
|
|
||||||
|
|
||||||
// Encapsulation of a Column in a Row of the result.
|
// Encapsulation of a Column in a Row of the result.
|
||||||
Statement::Column::Column(sqlite3* apSQLite, sqlite3_stmt* apStmt, int aIndex) throw() : // nothrow
|
Statement::Column::Column(sqlite3* apSQLite, sqlite3_stmt* apStmt, unsigned int* apStmtRefCount, int aIndex) throw() : // nothrow
|
||||||
mpSQLite(apSQLite),
|
mpSQLite(apSQLite),
|
||||||
mpStmt(apStmt),
|
mpStmt(apStmt),
|
||||||
|
mpStmtRefCount(apStmtRefCount),
|
||||||
mIndex(aIndex)
|
mIndex(aIndex)
|
||||||
{
|
{
|
||||||
|
(*mpStmtRefCount)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::Column::~Column(void) throw() // nothrow
|
Statement::Column::~Column(void) throw() // nothrow
|
||||||
{
|
{
|
||||||
|
(*mpStmtRefCount)--;
|
||||||
|
if (0 == *mpStmtRefCount)
|
||||||
|
{
|
||||||
|
int ret = sqlite3_finalize(mpStmt);
|
||||||
|
if (SQLITE_OK != ret)
|
||||||
|
{
|
||||||
|
throw SQLite::Exception(sqlite3_errmsg(mpSQLite));
|
||||||
|
}
|
||||||
|
mpStmt = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the integer value of the column specified by its index starting at 0
|
// Return the integer value of the column specified by its index starting at 0
|
||||||
@ -243,8 +263,8 @@ double Statement::Column::getDouble(void) const throw() // nothrow
|
|||||||
return sqlite3_column_double(mpStmt, mIndex);
|
return sqlite3_column_double(mpStmt, mIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the text value (NULL terminated string) of the column specified by its index starting at 0
|
// Return a pointer to the text value (NULL terminated string) of the column specified by its index starting at 0
|
||||||
const char * Statement::Column::getText(void) const throw() // nothrow
|
const char* Statement::Column::getText(void) const throw() // nothrow
|
||||||
{
|
{
|
||||||
return (const char*)sqlite3_column_text(mpStmt, mIndex);
|
return (const char*)sqlite3_column_text(mpStmt, mIndex);
|
||||||
}
|
}
|
||||||
|
@ -125,12 +125,12 @@ public:
|
|||||||
* @warning The resulting Column object must not be copied or memorized as it is only valid for a short time,
|
* @warning The resulting Column object must not be copied or memorized as it is only valid for a short time,
|
||||||
* only while the row from the Statement remains valid, that is only until next executeStep
|
* only while the row from the Statement remains valid, that is only until next executeStep
|
||||||
*/
|
*/
|
||||||
Column getColumn (const int aIndex) const; // throw(SQLite::Exception);
|
Column getColumn(const int aIndex) const; // throw(SQLite::Exception);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Test if the column is NULL
|
* @brief Test if the column is NULL
|
||||||
*/
|
*/
|
||||||
bool isColumnNull (const int aIndex) const; // throw(SQLite::Exception);
|
bool isColumnNull(const int aIndex) const; // throw(SQLite::Exception);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -177,24 +177,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
class Column
|
class Column
|
||||||
{
|
{
|
||||||
/// Standard std::ostream inserter
|
|
||||||
friend std::ostream& operator<<(std::ostream &stream, const Column& column);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Compile and register the SQL query for the provided SQLite Database Connection
|
* @brief Compile and register the SQL query for the provided SQLite Database Connection
|
||||||
*/
|
*/
|
||||||
explicit Column(sqlite3* apSQLite, sqlite3_stmt* apStmt, int aIndex) throw(); // nothrow
|
explicit Column(sqlite3* apSQLite, sqlite3_stmt* apStmt, unsigned int* apStmtRefCount, int aIndex) throw(); // nothrow
|
||||||
/// Basic destructor
|
/// Basic destructor
|
||||||
virtual ~Column(void) throw(); // nothrow
|
virtual ~Column(void) throw(); // nothrow
|
||||||
|
|
||||||
/// Return the integer value of the column.
|
/// Return the integer value of the column.
|
||||||
int getInt (void) const throw();
|
int getInt (void) const throw();
|
||||||
// Return the 64bits integer value of the column.
|
/// Return the 64bits integer value of the column.
|
||||||
sqlite3_int64 getInt64 (void) const throw();
|
sqlite3_int64 getInt64 (void) const throw();
|
||||||
// Return the double (64bits float) value of the column.
|
/// Return the double (64bits float) value of the column.
|
||||||
double getDouble(void) const throw();
|
double getDouble(void) const throw();
|
||||||
// Return the text value (NULL terminated string) of the column.
|
/// Return a pointer to the text value (NULL terminated string) of the column.
|
||||||
|
/// Warning, the value pointed at is only valid while the statement is valid (ie. not finalized),
|
||||||
|
/// thus you must copy it before using it beyond its scope (to a std::string for instance).
|
||||||
const char* getText (void) const throw();
|
const char* getText (void) const throw();
|
||||||
|
|
||||||
/// Inline cast operator to int
|
/// Inline cast operator to int
|
||||||
@ -229,9 +228,10 @@ public:
|
|||||||
Column& operator=(const Column&);
|
Column& operator=(const Column&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sqlite3* mpSQLite; //!< Pointer to SQLite Database Connection Handle
|
sqlite3* mpSQLite; //!< Pointer to SQLite Database Connection Handle
|
||||||
sqlite3_stmt* mpStmt; //!< Pointer to SQLite Statement Object
|
sqlite3_stmt* mpStmt; //!< Pointer to SQLite Statement Object
|
||||||
int mIndex; //!< Index of the column in the row of result
|
unsigned int* mpStmtRefCount; //!< Pointer to the reference counter of the (shared) Statement Object
|
||||||
|
int mIndex; //!< Index of the column in the row of result
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -247,7 +247,8 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
sqlite3_stmt* mpStmt; //!< Pointer to SQLite Statement Object
|
sqlite3_stmt* mpStmt; //!< Pointer to SQLite Statement Object
|
||||||
Database& mDatabase; //!< Reference to the SQLite Database Connection
|
unsigned int* mpStmtRefCount; //!< Pointer to the reference counter of the (shared) Statement Object
|
||||||
|
sqlite3* mpSQLite; //!< Pointer to SQLite Database Connection Handle
|
||||||
std::string mQuery; //!< UTF-8 SQL Query
|
std::string mQuery; //!< UTF-8 SQL Query
|
||||||
int mColumnCount; //!< Number of column in the result of the prepared statement
|
int mColumnCount; //!< Number of column in the result of the prepared statement
|
||||||
bool mbOk; //!< True when a row has been fetched with executeStep()
|
bool mbOk; //!< True when a row has been fetched with executeStep()
|
||||||
@ -255,4 +256,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Standard std::ostream inserter
|
||||||
|
std::ostream& operator<<(std::ostream &stream, const Statement::Column& column);
|
||||||
|
|
||||||
|
|
||||||
}; // namespace SQLite
|
}; // namespace SQLite
|
||||||
|
Loading…
x
Reference in New Issue
Block a user