mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Implemented the SQLite transaction class using the RAII pattern.
Fixed an issue that generated bad messages for errors that occurred in the formatted query execution method. Minor adjustments throughout the code structure.
This commit is contained in:
parent
133bedce50
commit
1a312f7e7f
@ -1,6 +1,7 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Common.hpp"
|
||||
#include "Module.hpp"
|
||||
#include "Connection.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <ctype.h>
|
||||
@ -322,6 +323,70 @@ Int32 StmtHnd::Handle::GetColumnIndex(CSStr name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Transaction::Transaction(const Connection & db)
|
||||
: Transaction(db.GetHandle())
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Transaction::Transaction(const ConnHnd & db)
|
||||
: m_Connection(db), m_Committed(false)
|
||||
{
|
||||
// Was the specified database connection valid?
|
||||
if (!m_Connection)
|
||||
{
|
||||
STHROWF("Invalid connection handle");
|
||||
}
|
||||
// Attempt to begin transaction
|
||||
else if ((m_Connection = sqlite3_exec(m_Connection, "BEGIN", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
{
|
||||
STHROWF("Unable to begin transaction [%s]", m_Connection.ErrMsg());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Transaction::~Transaction()
|
||||
{
|
||||
// Was this transaction successfully committed?
|
||||
if (m_Committed)
|
||||
{
|
||||
return; // We're done here!
|
||||
}
|
||||
// Attempt to roll back changes because this failed to commit
|
||||
if ((m_Connection = sqlite3_exec(m_Connection, "ROLLBACK", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
{
|
||||
STHROWF("Unable to rollback transaction [%s]", m_Connection.ErrMsg());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Transaction::Commit()
|
||||
{
|
||||
// We shouldn't even be here if there wasn't a valid connection but let's be sure
|
||||
if (!m_Connection)
|
||||
{
|
||||
STHROWF("Invalid database connection");
|
||||
}
|
||||
// Was this transaction already committed?
|
||||
else if (m_Committed)
|
||||
{
|
||||
STHROWF("Transaction was already committed");
|
||||
}
|
||||
// Attempt to commit the change during this transaction
|
||||
else if ((m_Connection = sqlite3_exec(m_Connection, "COMMIT", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
{
|
||||
STHROWF("Unable to commit transaction [%s]", m_Connection.ErrMsg());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Committed = true; // Everything was committed successfully
|
||||
}
|
||||
// Return the result
|
||||
return m_Committed;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr GetErrStr(Int32 status)
|
||||
{
|
||||
|
@ -212,7 +212,9 @@ private:
|
||||
void Grab()
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
++(m_Hnd->mRef);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -221,7 +223,9 @@ private:
|
||||
void Drop()
|
||||
{
|
||||
if (m_Hnd && --(m_Hnd->mRef) == 0)
|
||||
{
|
||||
delete m_Hnd; // Let the destructor take care of cleaning up (if necessary)
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -304,7 +308,9 @@ public:
|
||||
ConnHnd & operator = (Int32 status)
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
m_Hnd->mStatus = status;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -330,7 +336,9 @@ public:
|
||||
bool operator == (Int32 status) const
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
return (m_Hnd->mStatus == status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -340,7 +348,9 @@ public:
|
||||
bool operator != (Int32 status) const
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
return (m_Hnd->mStatus != status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -428,6 +438,14 @@ public:
|
||||
return m_Hnd ? m_Hnd->mRef : 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the last known status code.
|
||||
*/
|
||||
Int32 Status() const
|
||||
{
|
||||
return m_Hnd ? m_Hnd->mStatus : SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the message of the last received error code.
|
||||
*/
|
||||
@ -435,7 +453,9 @@ public:
|
||||
{
|
||||
// SQLite does it's null pointer validations internally
|
||||
if (m_Hnd)
|
||||
{
|
||||
return sqlite3_errstr(sqlite3_errcode(m_Hnd->mPtr));
|
||||
}
|
||||
return _SC("");
|
||||
}
|
||||
|
||||
@ -446,7 +466,9 @@ public:
|
||||
{
|
||||
// SQLite does it's null pointer validations internally
|
||||
if (m_Hnd)
|
||||
{
|
||||
return sqlite3_errmsg(m_Hnd->mPtr);
|
||||
}
|
||||
return _SC("");
|
||||
}
|
||||
|
||||
@ -457,7 +479,9 @@ public:
|
||||
{
|
||||
// SQLite does it's null pointer validations internally
|
||||
if (m_Hnd)
|
||||
{
|
||||
return sqlite3_errcode(m_Hnd->mPtr);
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
@ -468,7 +492,9 @@ public:
|
||||
{
|
||||
// SQLite does it's null pointer validations internally
|
||||
if (m_Hnd)
|
||||
{
|
||||
return sqlite3_extended_errcode(m_Hnd->mPtr);
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
};
|
||||
@ -581,7 +607,9 @@ private:
|
||||
void Grab()
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
++(m_Hnd->mRef);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -590,7 +618,9 @@ private:
|
||||
void Drop()
|
||||
{
|
||||
if (m_Hnd && --(m_Hnd->mRef) == 0)
|
||||
{
|
||||
delete m_Hnd; // Let the destructor take care of cleaning up (if necessary)
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -674,7 +704,9 @@ public:
|
||||
StmtHnd & operator = (Int32 status)
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
m_Hnd->mStatus = status;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -700,7 +732,9 @@ public:
|
||||
bool operator == (Int32 status) const
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
return (m_Hnd->mStatus == status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -710,7 +744,9 @@ public:
|
||||
bool operator != (Int32 status) const
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
return (m_Hnd->mStatus != status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -798,13 +834,23 @@ public:
|
||||
return m_Hnd ? m_Hnd->mRef : 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the last known status code.
|
||||
*/
|
||||
Int32 Status() const
|
||||
{
|
||||
return m_Hnd ? m_Hnd->mStatus : SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the message of the last received error code.
|
||||
*/
|
||||
CCStr ErrStr() const
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
return m_Hnd->mConn.ErrStr();
|
||||
}
|
||||
return _SC("");
|
||||
}
|
||||
|
||||
@ -814,7 +860,9 @@ public:
|
||||
CCStr ErrMsg() const
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
return m_Hnd->mConn.ErrMsg();
|
||||
}
|
||||
return _SC("");
|
||||
}
|
||||
|
||||
@ -824,7 +872,9 @@ public:
|
||||
Int32 ErrNo() const
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
return m_Hnd->mConn.ErrNo();
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
@ -834,11 +884,75 @@ public:
|
||||
Int32 ExErrNo() const
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
return m_Hnd->mConn.ExErrNo();
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Implements the RAII pattern for database transactions.
|
||||
*/
|
||||
class Transaction
|
||||
{
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct by taking the handle from a connection.
|
||||
*/
|
||||
Transaction(const Connection & db);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct using the direct connection handle.
|
||||
*/
|
||||
Transaction(const ConnHnd & db);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
Transaction(const Transaction & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
Transaction(Transaction && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Transaction();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
Transaction & operator = (const Transaction & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
Transaction & operator = (Transaction && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to commit changes to the database.
|
||||
*/
|
||||
bool Commit();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the change during this transaction were successfully committed.
|
||||
*/
|
||||
bool Commited() const
|
||||
{
|
||||
return m_Committed;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ConnHnd m_Connection; // The database connection handle where the transaction began.
|
||||
bool m_Committed; // Whether changes were successfully committed to the database.
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve the string representation of a certain status code.
|
||||
*/
|
||||
|
@ -386,7 +386,14 @@ SQInteger Connection::ExecF(HSQUIRRELVM vm)
|
||||
// Attempt to execute the specified query
|
||||
else if ((conn->m_Handle = sqlite3_exec(conn->m_Handle, sql, NULL, NULL, NULL)) != SQLITE_OK)
|
||||
{
|
||||
return sq_throwerror(vm, FmtStr("Unable to execute query [%s]", conn->m_Handle.ErrMsg()));
|
||||
// Generate the query message first
|
||||
String msg("Unable to execute query ");
|
||||
// (we can't use FmtStr here because Squirrel doesn't make a copy of the message)
|
||||
msg.push_back('[');
|
||||
msg.append(conn->m_Handle.ErrMsg());
|
||||
msg.push_back(']');
|
||||
// Now throw the message
|
||||
return sq_throwerror(vm, msg.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -401,7 +408,14 @@ SQInteger Connection::ExecF(HSQUIRRELVM vm)
|
||||
// Attempt to execute the specified query
|
||||
else if ((conn->m_Handle = sqlite3_exec(conn->m_Handle, sql.value, NULL, NULL, NULL)) != SQLITE_OK)
|
||||
{
|
||||
return sq_throwerror(vm, FmtStr("Unable to execute query [%s]", conn->m_Handle.ErrMsg()));
|
||||
// Generate the query message first
|
||||
String msg("Unable to execute query ");
|
||||
// (we can't use FmtStr here because Squirrel doesn't make a copy of the message)
|
||||
msg.push_back('[');
|
||||
msg.append(conn->m_Handle.ErrMsg());
|
||||
msg.push_back(']');
|
||||
// Now throw the message
|
||||
return sq_throwerror(vm, msg.c_str());
|
||||
}
|
||||
}
|
||||
// Push the number of changes onto the stack
|
||||
|
@ -170,16 +170,16 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
Table sqlns(vm);
|
||||
|
||||
sqlns.Bind(_SC("Connection"), Class< Connection >(vm, _SC("SqSQLiteConnection"))
|
||||
/* Constructors */
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< CCStr >()
|
||||
.Ctor< CCStr, Int32 >()
|
||||
.Ctor< CCStr, Int32, CCStr >()
|
||||
/* Metamethods */
|
||||
// Metamethods
|
||||
.Func(_SC("_cmp"), &Connection::Cmp)
|
||||
.SquirrelFunc(_SC("_typename"), &Connection::Typename)
|
||||
.Func(_SC("_tostring"), &Connection::ToString)
|
||||
/* Properties */
|
||||
// Properties
|
||||
.Prop(_SC("Valid"), &Connection::IsValid)
|
||||
.Prop(_SC("Refs"), &Connection::GetRefCount)
|
||||
.Prop(_SC("Connected"), &Connection::IsValid)
|
||||
@ -201,7 +201,7 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
.Prop(_SC("Profile"), &Connection::GetProfiling, &Connection::SetProfiling)
|
||||
.Prop(_SC("BusyTimeout"), (Int32 (Connection::*)(void) const)(NULL), &Connection::SetBusyTimeout)
|
||||
.Prop(_SC("QueueSize"), &Connection::QueueSize)
|
||||
/* Functions */
|
||||
// Member Methods
|
||||
.Func(_SC("Release"), &Connection::Release)
|
||||
.Overload< void (Connection::*)(CSStr) >(_SC("Open"), &Connection::Open)
|
||||
.Overload< void (Connection::*)(CSStr, Int32) >(_SC("Open"), &Connection::Open)
|
||||
@ -229,15 +229,15 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
);
|
||||
|
||||
sqlns.Bind(_SC("Statement"), Class< Statement >(vm, _SC("SqSQLiteStatement"))
|
||||
/* Constructors */
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< const Connection &, CCStr >()
|
||||
.Ctor< const Statement & >()
|
||||
/* Metamethods */
|
||||
// Metamethods
|
||||
.Func(_SC("_cmp"), &Statement::Cmp)
|
||||
.SquirrelFunc(_SC("_typename"), &Statement::Typename)
|
||||
.Func(_SC("_tostring"), &Statement::ToString)
|
||||
/* Properties */
|
||||
// Properties
|
||||
.Prop(_SC("Valid"), &Statement::IsValid)
|
||||
.Prop(_SC("Refs"), &Statement::GetRefCount)
|
||||
.Prop(_SC("Conn"), &Statement::GetConnection)
|
||||
@ -252,7 +252,7 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
.Prop(_SC("Query"), &Statement::GetQuery)
|
||||
.Prop(_SC("Good"), &Statement::GetGood)
|
||||
.Prop(_SC("Done"), &Statement::GetDone)
|
||||
/* Functions */
|
||||
// Member Methods
|
||||
.Func(_SC("Release"), &Statement::Release)
|
||||
.Func(_SC("Reset"), &Statement::Reset)
|
||||
.Func(_SC("Clear"), &Statement::Clear)
|
||||
@ -299,14 +299,14 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
);
|
||||
|
||||
sqlns.Bind(_SC("Column"), Class< Column >(vm, _SC("SqSQLiteColumn"))
|
||||
/* Constructors */
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< const Column & >()
|
||||
/* Metamethods */
|
||||
// Metamethods
|
||||
.Func(_SC("_cmp"), &Column::Cmp)
|
||||
.SquirrelFunc(_SC("_typename"), &Column::Typename)
|
||||
.Func(_SC("_tostring"), &Column::ToString)
|
||||
/* Properties */
|
||||
// Properties
|
||||
.Prop(_SC("Valid"), &Column::IsValid)
|
||||
.Prop(_SC("Refs"), &Column::GetRefCount)
|
||||
.Prop(_SC("Index"), &Column::GetIndex)
|
||||
@ -325,10 +325,19 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
.Prop(_SC("OriginName"), &Column::GetOriginName)
|
||||
.Prop(_SC("Type"), &Column::GetType)
|
||||
.Prop(_SC("Bytes"), &Column::GetBytes)
|
||||
/* Functions */
|
||||
// Member Methods
|
||||
.Func(_SC("Release"), &Column::Release)
|
||||
);
|
||||
|
||||
sqlns.Bind(_SC("Transaction"), Class< Transaction, NoCopy< Transaction > >(vm, _SC("SqSQLiteTransaction"))
|
||||
// Constructors
|
||||
.Ctor< const Connection & >()
|
||||
// Properties
|
||||
.Prop(_SC("Committed"), &Transaction::Commited)
|
||||
// Member Methods
|
||||
.Func(_SC("Commit"), &Transaction::Commit)
|
||||
);
|
||||
|
||||
sqlns.Func(_SC("IsQueryEmpty"), &IsQueryEmpty);
|
||||
sqlns.Func(_SC("GetErrStr"), &GetErrStr);
|
||||
sqlns.Func(_SC("SetSoftHeapLimit"), &SetSoftHeapLimit);
|
||||
@ -343,7 +352,7 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
|
||||
RootTable(vm).Bind(_SC("SQLite"), sqlns);
|
||||
|
||||
/*
|
||||
|
||||
ConstTable(vm).Enum(_SC("ESQLite"), Enumeration(vm)
|
||||
.Const(_SC("ABORT"), SQLITE_ABORT)
|
||||
.Const(_SC("ABORT_ROLLBACK"), SQLITE_ABORT_ROLLBACK)
|
||||
@ -682,7 +691,6 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
.Const(_SC("WARNING"), SQLITE_WARNING)
|
||||
.Const(_SC("WARNING_AUTOINDEX"), SQLITE_WARNING_AUTOINDEX)
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user