mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 08:47:17 +01:00
Switched the SQLite module to use C++ exceptions to fix the Sqrat issues and gain significantly more performance.
Also fixed various other issues in the SQLite module.
This commit is contained in:
parent
8340a5dbc4
commit
331b03028c
@ -363,6 +363,7 @@
|
||||
<Add option="-Wextra" />
|
||||
<Add option="-Wall" />
|
||||
<Add option="-DSQMOD_PLUGIN_API" />
|
||||
<Add option="-DSCRAT_USE_EXCEPTIONS" />
|
||||
<Add directory="../modules/sqlite" />
|
||||
<Add directory="../shared" />
|
||||
<Add directory="../include" />
|
||||
|
@ -19,107 +19,91 @@ SQInteger Column::Typename(HSQUIRRELVM vm)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Column::Validate() const
|
||||
void Column::Validate() const
|
||||
{
|
||||
// Are we pointing to a valid index?
|
||||
if (m_Index < 0)
|
||||
_SqMod->SqThrow("Invalid column index");
|
||||
SqThrowF("Invalid column index");
|
||||
// Do we belong to a valid statement?
|
||||
else if (!m_Stmt)
|
||||
_SqMod->SqThrow("Invalid SQLite statement reference");
|
||||
// Requirements satisfied
|
||||
else
|
||||
return true;
|
||||
// Validation failed
|
||||
return false;
|
||||
SqThrowF("Invalid SQLite statement reference");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Column::RowAvailable() const
|
||||
void Column::ValidateRow() const
|
||||
{
|
||||
// Are we pointing to a valid index?
|
||||
if (m_Index < 0)
|
||||
_SqMod->SqThrow("Invalid column index");
|
||||
SqThrowF("Invalid column index");
|
||||
// Do we belong to a valid statement?
|
||||
else if (!m_Stmt)
|
||||
_SqMod->SqThrow("Invalid SQLite statement reference");
|
||||
SqThrowF("Invalid SQLite statement reference");
|
||||
// Do we have any rows available?
|
||||
else if (!m_Stmt->mGood)
|
||||
_SqMod->SqThrow("No row available");
|
||||
// Requirements satisfied
|
||||
else
|
||||
return true;
|
||||
// Validation failed
|
||||
return false;
|
||||
SqThrowF("No row available");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object Column::GetStatement() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return Object(new Statement(m_Stmt));
|
||||
// Request failed
|
||||
return Object(new Statement());
|
||||
// Validate the column
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Object(new Statement(m_Stmt));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object Column::GetConnection() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return Object(new Connection(m_Stmt->mConn));
|
||||
// Request failed
|
||||
return Object(new Connection());
|
||||
// Validate the column
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Object(new Connection(m_Stmt->mConn));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 Column::GetNumber() const
|
||||
{
|
||||
// Validate the handle and index
|
||||
if (RowAvailable())
|
||||
return sqlite3_column_int(m_Stmt, m_Index);
|
||||
// Request failed
|
||||
return 0;
|
||||
// Validate the column and statement row
|
||||
ValidateRow();
|
||||
// Return the requested information
|
||||
return sqlite3_column_int(m_Stmt, m_Index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Column::GetInteger() const
|
||||
{
|
||||
// Validate the handle and index
|
||||
if (RowAvailable())
|
||||
// Validate the column and statement row
|
||||
ValidateRow();
|
||||
// Return the requested information
|
||||
#ifdef _SQ64
|
||||
return sqlite3_column_int64(m_Stmt, m_Index);
|
||||
return sqlite3_column_int64(m_Stmt, m_Index);
|
||||
#else
|
||||
return sqlite3_column_int(m_Stmt, m_Index);
|
||||
return sqlite3_column_int(m_Stmt, m_Index);
|
||||
#endif
|
||||
// Request failed
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQFloat Column::GetFloat() const
|
||||
{
|
||||
// Validate the handle and index
|
||||
if (RowAvailable())
|
||||
return (SQFloat)sqlite3_column_double(m_Stmt, m_Index);
|
||||
// Request failed
|
||||
return SQFloat(0.0);
|
||||
// Validate the column and statement row
|
||||
ValidateRow();
|
||||
// Return the requested information
|
||||
return (SQFloat)sqlite3_column_double(m_Stmt, m_Index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object Column::GetLong() const
|
||||
{
|
||||
// Validate the handle and index
|
||||
if (!RowAvailable())
|
||||
return Object(); // Request failed
|
||||
// Validate the column and statement row
|
||||
ValidateRow();
|
||||
// Obtain the initial stack size
|
||||
const Int32 top = sq_gettop(_SqVM);
|
||||
// Push a long integer instance with the requested value on the stack
|
||||
_SqMod->PushSLongObject(_SqVM, sqlite3_column_int64(m_Stmt, m_Index));
|
||||
// Obtain the object from the stack
|
||||
Var< Object > inst(_SqVM, -1);
|
||||
// Remove an pushed values (if any) to restore the stack
|
||||
// Remove any pushed values (if any) to restore the stack
|
||||
sq_pop(_SqVM, sq_gettop(_SqVM) - top);
|
||||
// Return the long integer instance
|
||||
return inst.value;
|
||||
@ -128,9 +112,8 @@ Object Column::GetLong() const
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object Column::GetString() const
|
||||
{
|
||||
// Validate the handle and index
|
||||
if (!RowAvailable())
|
||||
return Object(); // Request failed
|
||||
// Validate the column and statement row
|
||||
ValidateRow();
|
||||
// Obtain the initial stack size
|
||||
const Int32 top = sq_gettop(_SqVM);
|
||||
// Push the column text on the stack
|
||||
@ -138,7 +121,7 @@ Object Column::GetString() const
|
||||
sqlite3_column_bytes(m_Stmt, m_Index));
|
||||
// Obtain the object from the stack
|
||||
Var< Object > inst(_SqVM, -1);
|
||||
// Remove an pushed values (if any) to restore the stack
|
||||
// Remove any pushed values (if any) to restore the stack
|
||||
sq_pop(_SqVM, sq_gettop(_SqVM) - top);
|
||||
// Return the long integer instance
|
||||
return inst.value;
|
||||
@ -147,19 +130,17 @@ Object Column::GetString() const
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Column::GetBoolean() const
|
||||
{
|
||||
// Validate the handle and index
|
||||
if (RowAvailable())
|
||||
return sqlite3_column_int(m_Stmt, m_Index) > 0;
|
||||
// Request failed
|
||||
return false;
|
||||
// Validate the column and statement row
|
||||
ValidateRow();
|
||||
// Return the requested information
|
||||
return sqlite3_column_int(m_Stmt, m_Index) > 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object Column::GetBlob() const
|
||||
{
|
||||
// Validate the handle and index
|
||||
if (RowAvailable())
|
||||
return Object(); // Request failed
|
||||
// Validate the column and statement row
|
||||
ValidateRow();
|
||||
// Obtain the initial stack size
|
||||
const Int32 top = sq_gettop(_SqVM);
|
||||
// Obtain the size of the data
|
||||
@ -170,71 +151,63 @@ Object Column::GetBlob() const
|
||||
const void * b = sqlite3_column_blob(m_Stmt, m_Index);
|
||||
// Could the memory blob be allocated?
|
||||
if (!p)
|
||||
{
|
||||
_SqMod->SqThrow("Unable to allocate space for column blob value");
|
||||
// Request failed
|
||||
return Object();
|
||||
}
|
||||
SqThrowF("Unable to allocate space for column blob value");
|
||||
// Is there any data to read?
|
||||
else if (!b)
|
||||
{
|
||||
// Pop the memory blob from the stack
|
||||
sq_pop(_SqVM, sq_gettop(_SqVM) - top);
|
||||
// Now throw the error
|
||||
_SqMod->SqThrow("Unable to read data from column blob value");
|
||||
// Request failed
|
||||
return Object();
|
||||
// Push a null value instead
|
||||
sq_pushnull(_SqVM);
|
||||
}
|
||||
// Copy the data into the memory blob
|
||||
else
|
||||
memcpy(p, b, sz);
|
||||
// Obtain the object from the stack
|
||||
Var< Object > inst(_SqVM, -1);
|
||||
// Remove an pushed values (if any) to restore the stack
|
||||
// Remove any pushed values (if any) to restore the stack
|
||||
sq_pop(_SqVM, sq_gettop(_SqVM) - top);
|
||||
// Return the long integer instance
|
||||
// Return the blob instance
|
||||
return inst.value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQChar Column::GetChar() const
|
||||
{
|
||||
// Validate the handle and index
|
||||
if (RowAvailable())
|
||||
return (SQChar)sqlite3_column_int(m_Stmt, m_Index);
|
||||
// Request failed
|
||||
return 0;
|
||||
// Validate the column and statement row
|
||||
ValidateRow();
|
||||
// Return the requested information
|
||||
return (SQChar)sqlite3_column_int(m_Stmt, m_Index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Column::IsNull() const
|
||||
{
|
||||
// Can we make the request?
|
||||
if (Validate())
|
||||
return (sqlite3_column_type(m_Stmt, m_Index) == SQLITE_NULL);
|
||||
// Request failed
|
||||
return true;
|
||||
// Validate the column
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return (sqlite3_column_type(m_Stmt, m_Index) == SQLITE_NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr Column::GetName() const
|
||||
{
|
||||
// Can we make the request?
|
||||
if (Validate())
|
||||
return sqlite3_column_name(m_Stmt, m_Index);
|
||||
// Request failed
|
||||
return _SC("");
|
||||
// Validate the column
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return sqlite3_column_name(m_Stmt, m_Index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr Column::GetOriginName() const
|
||||
{
|
||||
#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
||||
// Can we make the request?
|
||||
if (Validate())
|
||||
return sqlite3_column_origin_name(m_Stmt, m_Index);
|
||||
// Validate the column
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return sqlite3_column_origin_name(m_Stmt, m_Index);
|
||||
#else
|
||||
_SqMod->SqThrow("The module was compiled without this feature");
|
||||
SqThrowF("The module was compiled without this feature");
|
||||
#endif
|
||||
// Request failed
|
||||
return _SC("");
|
||||
@ -243,22 +216,19 @@ CSStr Column::GetOriginName() const
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 Column::GetType() const
|
||||
{
|
||||
// Can we make the request?
|
||||
if (Validate())
|
||||
return sqlite3_column_type(m_Stmt, m_Index);
|
||||
// Request failed
|
||||
return -1;
|
||||
// Validate the column
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return sqlite3_column_type(m_Stmt, m_Index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 Column::GetBytes() const
|
||||
{
|
||||
// Can we make the request?
|
||||
if (Validate())
|
||||
return sqlite3_column_bytes(m_Stmt, m_Index);
|
||||
// Request failed
|
||||
return -1;
|
||||
// Validate the column
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return sqlite3_column_bytes(m_Stmt, m_Index);
|
||||
}
|
||||
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
@ -27,12 +27,12 @@ private:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the statement reference and index, and throw an error if they're invalid.
|
||||
*/
|
||||
bool Validate() const;
|
||||
void Validate() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the statement reference, index and row, and throw an error if they're invalid.
|
||||
*/
|
||||
bool RowAvailable() const;
|
||||
void ValidateRow() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
|
@ -15,6 +15,27 @@ static SQChar g_Buffer[4096]; // Common buffer to reduce memory allocations.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SStr GetTempBuff()
|
||||
{
|
||||
return g_Buffer;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SqThrowF(CSStr str, ...)
|
||||
{
|
||||
// Initialize the argument list
|
||||
va_list args;
|
||||
va_start (args, str);
|
||||
// Write the requested contents
|
||||
if (snprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0)
|
||||
strcpy(g_Buffer, "Unknown error has occurred");
|
||||
// Release the argument list
|
||||
va_end(args);
|
||||
// Throw the exception with the resulted message
|
||||
throw Sqrat::Exception(g_Buffer);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr FmtStr(CSStr str, ...)
|
||||
{
|
||||
@ -72,7 +93,7 @@ ConnHnd::Handle::~Handle()
|
||||
// Are we dealing with a memory leak? Technically shouldn't reach this situation!
|
||||
else if (mRef != 0)
|
||||
// Should we deal with undefined behavior instead? How bad is one connection left open?
|
||||
_SqMod->LogErr("SQLite connection is still referenced.");
|
||||
_SqMod->LogErr("SQLite connection is still referenced (%s)", mName.c_str());
|
||||
else
|
||||
{
|
||||
// NOTE: Should we call sqlite3_interrupt(...) before closing?
|
||||
@ -91,18 +112,10 @@ void ConnHnd::Handle::Create(CSStr name, Int32 flags, CSStr vfs)
|
||||
{
|
||||
// Make sure a previous connection doesn't exist
|
||||
if (mPtr)
|
||||
{
|
||||
_SqMod->SqThrow("Unable to connect to database. Database already connected");
|
||||
// Unable to proceed
|
||||
return;
|
||||
}
|
||||
SqThrowF("Unable to connect to database. Database already connected");
|
||||
// Make sure the name is valid
|
||||
else if (!name || strlen(name) <= 0)
|
||||
{
|
||||
_SqMod->SqThrow("Unable to connect to database. The name is invalid");
|
||||
// Unable to proceed
|
||||
return;
|
||||
}
|
||||
SqThrowF("Unable to connect to database. The name is invalid");
|
||||
// Attempt to create the database connection
|
||||
else if ((mStatus = sqlite3_open_v2(name, &mPtr, flags, vfs)) != SQLITE_OK)
|
||||
{
|
||||
@ -111,9 +124,7 @@ void ConnHnd::Handle::Create(CSStr name, Int32 flags, CSStr vfs)
|
||||
// Explicitly make sure it's null
|
||||
mPtr = NULL;
|
||||
// Now its safe to throw the error
|
||||
_SqMod->SqThrow("Unable to connect to database [%s]", sqlite3_errstr(mStatus));
|
||||
// Unable to proceed
|
||||
return;
|
||||
SqThrowF("Unable to connect to database [%s]", sqlite3_errstr(mStatus));
|
||||
}
|
||||
// Let's save the specified information
|
||||
mName.assign(name);
|
||||
@ -142,11 +153,7 @@ Int32 ConnHnd::Handle::Flush(Uint32 num, Object & env, Function & func)
|
||||
QueryList::iterator end = mQueue.begin() + num;
|
||||
// Attempt to begin the flush transaction
|
||||
if ((mStatus = sqlite3_exec(mPtr, "BEGIN", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
{
|
||||
_SqMod->SqThrow("Unable to begin transaction [%s]", sqlite3_errmsg(mPtr));
|
||||
// Unable to proceed
|
||||
return -1;
|
||||
}
|
||||
SqThrowF("Unable to begin transaction [%s]", sqlite3_errmsg(mPtr));
|
||||
// Process all queries within range of selection
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
@ -175,10 +182,10 @@ Int32 ConnHnd::Handle::Flush(Uint32 num, Object & env, Function & func)
|
||||
return sqlite3_changes(mPtr);
|
||||
// Attempt to roll back erroneous changes
|
||||
else if ((mStatus = sqlite3_exec(mPtr, "ROLLBACK", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to rollback transaction [%s]", sqlite3_errmsg(mPtr));
|
||||
SqThrowF("Unable to rollback transaction [%s]", sqlite3_errmsg(mPtr));
|
||||
// The transaction failed somehow but we managed to rollback
|
||||
else
|
||||
_SqMod->SqThrow("Unable to commit transaction because [%s]", sqlite3_errmsg(mPtr));
|
||||
SqThrowF("Unable to commit transaction because [%s]", sqlite3_errmsg(mPtr));
|
||||
// Operation failed
|
||||
return -1;
|
||||
}
|
||||
@ -192,7 +199,7 @@ StmtHnd::Handle::~Handle()
|
||||
// Are we dealing with a memory leak? Technically shouldn't reach this situation!
|
||||
else if (mRef != 0)
|
||||
// Should we deal with undefined behavior instead? How bad is one statement left alive?
|
||||
_SqMod->LogErr("SQLite statement is still referenced.");
|
||||
_SqMod->LogErr("SQLite statement is still referenced (%s)", mQuery.c_str());
|
||||
else
|
||||
{
|
||||
// Attempt to finalize the statement
|
||||
@ -206,33 +213,25 @@ void StmtHnd::Handle::Create(CSStr query)
|
||||
{
|
||||
// Make sure a previous statement doesn't exist
|
||||
if (mPtr)
|
||||
{
|
||||
_SqMod->SqThrow("Unable to prepare statement. Statement already prepared");
|
||||
// Unable to proceed
|
||||
return;
|
||||
}
|
||||
SqThrowF("Unable to prepare statement. Statement already prepared");
|
||||
// Is the specified database connection is valid?
|
||||
else if (!mConn)
|
||||
{
|
||||
_SqMod->SqThrow("Unable to prepare statement. Invalid connection handle");
|
||||
// Unable to proceed
|
||||
return;
|
||||
}
|
||||
SqThrowF("Unable to prepare statement. Invalid connection handle");
|
||||
// Save the query string and therefore multiple strlen(...) calls
|
||||
mQuery.assign(query ? query : _SC(""));
|
||||
// Is the specified query string we just saved, valid?
|
||||
if (mQuery.empty())
|
||||
_SqMod->SqThrow("Unable to prepare statement. Invalid query string");
|
||||
SqThrowF("Unable to prepare statement. Invalid query string");
|
||||
// Attempt to prepare a statement with the specified query string
|
||||
else if ((mStatus = sqlite3_prepare_v2(mConn, mQuery.c_str(), (Int32)mQuery.size(),
|
||||
&mPtr, NULL)) != SQLITE_OK)
|
||||
{
|
||||
// Clear the query string since it failed
|
||||
mQuery.clear();
|
||||
// Now it's safe to throw the error
|
||||
_SqMod->SqThrow("Unable to prepare statement [%s]", mConn.ErrMsg());
|
||||
// Explicitly make sure the handle is null
|
||||
mPtr = NULL;
|
||||
// Now it's safe to throw the error
|
||||
SqThrowF("Unable to prepare statement [%s]", mConn.ErrMsg());
|
||||
}
|
||||
else
|
||||
// Obtain the number of available columns
|
||||
@ -244,7 +243,7 @@ Int32 StmtHnd::Handle::GetColumnIndex(CSStr name)
|
||||
{
|
||||
// Validate the handle
|
||||
if (!mPtr)
|
||||
_SqMod->SqThrow("Invalid SQLite statement");
|
||||
SqThrowF("Invalid SQLite statement");
|
||||
// Are the names cached?
|
||||
else if (mIndexes.empty())
|
||||
{
|
||||
@ -254,7 +253,7 @@ Int32 StmtHnd::Handle::GetColumnIndex(CSStr name)
|
||||
CSStr name = (CSStr)sqlite3_column_name(mPtr, i);
|
||||
// Validate the name
|
||||
if (!name)
|
||||
_SqMod->SqThrow("Unable to retrieve column name for index (%d)", i);
|
||||
SqThrowF("Unable to retrieve column name for index (%d)", i);
|
||||
// Save it to guarantee the same lifetime as this instance
|
||||
else
|
||||
mIndexes[name] = i;
|
||||
@ -269,6 +268,12 @@ Int32 StmtHnd::Handle::GetColumnIndex(CSStr name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CSStr GetErrStr(Int32 status)
|
||||
{
|
||||
return sqlite3_errstr(status);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SetSoftHeapLimit(Int32 limit)
|
||||
{
|
||||
@ -290,7 +295,7 @@ Object GetMemoryUsage()
|
||||
_SqMod->PushSLongObject(_SqVM, sqlite3_memory_used());
|
||||
// Obtain the object from the stack
|
||||
Var< Object > inst(_SqVM, -1);
|
||||
// Remove an pushed values (if any) to restore the stack
|
||||
// Remove any pushed values (if any) to restore the stack
|
||||
sq_pop(_SqVM, sq_gettop(_SqVM) - top);
|
||||
// Return the long integer instance
|
||||
return inst.value;
|
||||
@ -305,7 +310,7 @@ Object GetMemoryHighwaterMark(bool reset)
|
||||
_SqMod->PushSLongObject(_SqVM, sqlite3_memory_highwater(reset));
|
||||
// Obtain the object from the stack
|
||||
Var< Object > inst(_SqVM, -1);
|
||||
// Remove an pushed values (if any) to restore the stack
|
||||
// Remove any pushed values (if any) to restore the stack
|
||||
sq_pop(_SqVM, sq_gettop(_SqVM) - top);
|
||||
// Return the long integer instance
|
||||
return inst.value;
|
||||
@ -331,7 +336,7 @@ CCStr EscapeStringEx(SQChar spec, CCStr str)
|
||||
// Validate the specified format specifier
|
||||
if (spec != 'q' && spec != 'Q' && spec != 'w' && spec != 's')
|
||||
{
|
||||
_SqMod->SqThrow("Unknown format specifier: %c", spec);
|
||||
SqThrowF("Unknown format specifier: %c", spec);
|
||||
// Default to empty string
|
||||
return _SC("");
|
||||
}
|
||||
@ -367,11 +372,7 @@ CCStr ArrayToQueryColumns(Array & arr)
|
||||
{
|
||||
// Is the name valid?
|
||||
if (itr->empty())
|
||||
{
|
||||
_SqMod->SqThrow("Invalid column name");
|
||||
// Default to empty string
|
||||
return _SC("");
|
||||
}
|
||||
SqThrowF("Invalid column name");
|
||||
// Attempt to append the column name to the buffer
|
||||
sqlite3_snprintf(sizeof(g_Buffer) - offset, g_Buffer + offset, "[%q], ", itr->c_str());
|
||||
// Add the column name size to the offset
|
||||
@ -403,11 +404,7 @@ CCStr TableToQueryColumns(Table & tbl)
|
||||
name.assign(itr.getName());
|
||||
// Is the name valid?
|
||||
if (name.empty())
|
||||
{
|
||||
_SqMod->SqThrow("Invalid column name");
|
||||
// Default to empty string
|
||||
return _SC("");
|
||||
}
|
||||
SqThrowF("Invalid column name");
|
||||
// Attempt to append the column name to the buffer
|
||||
sqlite3_snprintf(sizeof(g_Buffer) - offset, g_Buffer + offset, "[%q], ", name.c_str());
|
||||
// Add the column name size to the offset
|
||||
|
@ -38,6 +38,16 @@ class Transaction;
|
||||
#define SQSQLITE_VERSION_MINOR 0
|
||||
#define SQSQLITE_VERSION_PATCH 1
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve the temporary buffer.
|
||||
*/
|
||||
SStr GetTempBuff();
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Throw a formatted exception.
|
||||
*/
|
||||
void SqThrowF(CSStr str, ...);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Generate a formatted string.
|
||||
*/
|
||||
@ -726,42 +736,47 @@ public:
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Retrieve the string representation of a certain status code.
|
||||
*/
|
||||
CSStr GetErrStr(Int32 status);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Set a specific heap limit.
|
||||
*/
|
||||
void SetSoftHeapLimit(Int32 limit);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Release the specified amount of memory.
|
||||
*/
|
||||
Int32 ReleaseMemory(Int32 bytes);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Retrieve the current memory usage.
|
||||
*/
|
||||
Object GetMemoryUsage();
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Retrieve the memory high watermark.
|
||||
*/
|
||||
Object GetMemoryHighwaterMark(bool reset);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Retrieve the escaped version of the specified string.
|
||||
*/
|
||||
CSStr EscapeString(CSStr str);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Retrieve the escaped version of the specified string using the supplied format specifier.
|
||||
*/
|
||||
CCStr EscapeStringEx(SQChar spec, CCStr str);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Convert the values from the specified array to a list of column names string.
|
||||
*/
|
||||
CCStr ArrayToQueryColumns(Array & arr);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Convert the keys from the specified array to a list of column names string.
|
||||
*/
|
||||
CCStr TableToQueryColumns(Table & tbl);
|
||||
|
||||
|
@ -18,13 +18,11 @@ SQInteger Connection::Typename(HSQUIRRELVM vm)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Connection::Validate() const
|
||||
void Connection::Validate() const
|
||||
{
|
||||
if (m_Handle)
|
||||
return true;
|
||||
// Invalid connection reference
|
||||
_SqMod->SqThrow("Invalid SQLite connection reference");
|
||||
return false;
|
||||
// Is the handle valid?
|
||||
if (!m_Handle)
|
||||
SqThrowF("Invalid SQLite connection reference");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -40,12 +38,6 @@ Connection::Connection(CSStr name)
|
||||
{
|
||||
if (m_Handle.m_Hnd)
|
||||
m_Handle->Create(name, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
|
||||
// Because Sqrat is majorly stupid and clears the error message
|
||||
// then does an assert on debug builds thinking the type wasn't registered
|
||||
// or throws a generic "unknown error" message on release builds
|
||||
// we have to use this approach
|
||||
if (Sqrat::Error::Occurred(_SqVM))
|
||||
_SqMod->LogErr("%s", Sqrat::Error::Message(_SqVM).c_str());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -54,12 +46,6 @@ Connection::Connection(CSStr name, Int32 flags)
|
||||
{
|
||||
if (m_Handle.m_Hnd)
|
||||
m_Handle->Create(name, flags, NULL);
|
||||
// Because Sqrat is majorly stupid and clears the error message
|
||||
// then does an assert on debug builds thinking the type wasn't registered
|
||||
// or throws a generic "unknown error" message on release builds
|
||||
// we have to use this approach
|
||||
if (Sqrat::Error::Occurred(_SqVM))
|
||||
_SqMod->LogErr("%s", Sqrat::Error::Message(_SqVM).c_str());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -68,75 +54,60 @@ Connection::Connection(CSStr name, Int32 flags, CSStr vfs)
|
||||
{
|
||||
if (m_Handle.m_Hnd)
|
||||
m_Handle->Create(name, flags, vfs);
|
||||
// Because Sqrat is majorly stupid and clears the error message
|
||||
// then does an assert on debug builds thinking the type wasn't registered
|
||||
// or throws a generic "unknown error" message on release builds
|
||||
// we have to use this approach
|
||||
if (Sqrat::Error::Occurred(_SqVM))
|
||||
_SqMod->LogErr("%s", Sqrat::Error::Message(_SqVM).c_str());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 Connection::Exec(CSStr str)
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate() && (m_Handle = sqlite3_exec(m_Handle, str, NULL, NULL, NULL)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to execute query [%s]", m_Handle.ErrMsg());
|
||||
Validate();
|
||||
// Attempt to execute the specified query
|
||||
if ((m_Handle = sqlite3_exec(m_Handle, str, NULL, NULL, NULL)) != SQLITE_OK)
|
||||
SqThrowF("Unable to execute query [%s]", m_Handle.ErrMsg());
|
||||
// Return rows affected by this query
|
||||
else
|
||||
return sqlite3_changes(m_Handle);
|
||||
// Operation failed
|
||||
return -1;
|
||||
return sqlite3_changes(m_Handle);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object Connection::Query(CSStr str) const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return Object(new Statement(m_Handle, str));
|
||||
// Request failed
|
||||
return Object(new Statement());
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Object(new Statement(m_Handle, str));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Connection::Queue(CSStr str)
|
||||
{
|
||||
// Validate the handle
|
||||
if (!Validate())
|
||||
return; // Nothing to commit
|
||||
Validate();
|
||||
// Is there a query to commit?
|
||||
else if (IsQueryEmpty(str))
|
||||
_SqMod->SqThrow("No query to queue");
|
||||
if (IsQueryEmpty(str))
|
||||
SqThrowF("No query string to queue");
|
||||
// Add the specified string to the queue
|
||||
else
|
||||
m_Handle->mQueue.push_back(str);
|
||||
m_Handle->mQueue.push_back(str);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Connection::IsReadOnly() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (!Validate())
|
||||
return false;
|
||||
Validate();
|
||||
// Request the desired information
|
||||
const int result = sqlite3_db_readonly(m_Handle, "main");
|
||||
// Verify the result
|
||||
if (result == -1)
|
||||
_SqMod->SqThrow("'main' is not the name of a database on connection");
|
||||
// Return the result
|
||||
else
|
||||
return (result != 1);
|
||||
// Inexistent is same as read-only
|
||||
return true;
|
||||
SqThrowF("'main' is not the name of a database on connection");
|
||||
// Return the requested information
|
||||
return (result != 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Connection::TableExists(CCStr name) const
|
||||
{
|
||||
// Validate the handle
|
||||
if (!Validate())
|
||||
return false;
|
||||
Validate();
|
||||
// Prepare a statement to inspect the master table
|
||||
Statement stmt(m_Handle, "SELECT count(*) FROM [sqlite_master] WHERE [type]='table' AND [name]=?");
|
||||
// Could the statement be created?
|
||||
@ -156,8 +127,7 @@ bool Connection::TableExists(CCStr name) const
|
||||
Object Connection::GetLastInsertRowID() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (!Validate())
|
||||
return Object();
|
||||
Validate();
|
||||
// Obtain the initial stack size
|
||||
const Int32 top = sq_gettop(_SqVM);
|
||||
// Push a long integer instance with the requested value on the stack
|
||||
@ -173,155 +143,130 @@ Object Connection::GetLastInsertRowID() const
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Connection::SetBusyTimeout(Int32 millis)
|
||||
{
|
||||
// Validate the handle and apply requested timeout
|
||||
if (Validate() && ((m_Handle = sqlite3_busy_timeout(m_Handle, millis)) != SQLITE_OK))
|
||||
_SqMod->SqThrow("Unable to set busy timeout [%s]", m_Handle.ErrMsg());
|
||||
// Validate the handle
|
||||
Validate();
|
||||
// Apply requested timeout
|
||||
if ((m_Handle = sqlite3_busy_timeout(m_Handle, millis)) != SQLITE_OK)
|
||||
SqThrowF("Unable to set busy timeout [%s]", m_Handle.ErrMsg());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 Connection::GetInfo(Int32 operation, bool highwater, bool reset)
|
||||
{
|
||||
// Don't even bother to continue if there's no valid connection handle
|
||||
if (!Validate())
|
||||
return -1;
|
||||
Validate();
|
||||
// Where to retrieve the information
|
||||
Int32 cur_value;
|
||||
Int32 hiwtr_value;
|
||||
// Attempt to retrieve the specified information
|
||||
if((m_Handle = sqlite3_db_status(m_Handle, operation, &cur_value, &hiwtr_value, reset)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to get runtime status information", m_Handle.ErrMsg());
|
||||
// Return what was requested
|
||||
if ((m_Handle = sqlite3_db_status(m_Handle, operation, &cur_value, &hiwtr_value, reset)) != SQLITE_OK)
|
||||
SqThrowF("Unable to get runtime status information", m_Handle.ErrMsg());
|
||||
// Return the high-water value if requested
|
||||
else if (highwater)
|
||||
return hiwtr_value;
|
||||
else
|
||||
return cur_value;
|
||||
// Request failed
|
||||
return -1;
|
||||
// Return the requested information
|
||||
return cur_value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection Connection::CopyToMemory()
|
||||
{
|
||||
// Validate the handle
|
||||
if (!Validate())
|
||||
return Connection();
|
||||
Validate();
|
||||
// Is the database already in memory?
|
||||
else if (m_Handle->mMemory)
|
||||
{
|
||||
_SqMod->SqThrow("The database is already in memory");
|
||||
// No reason to move it again
|
||||
return Connection();
|
||||
}
|
||||
if (m_Handle->mMemory)
|
||||
SqThrowF("The database is already in memory");
|
||||
// Destination database
|
||||
ConnHnd db(_SC(""));
|
||||
// Attempt to open an in-memory database
|
||||
// Attempt to open the in-memory database
|
||||
db->Create(_SC(":memory:"), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
|
||||
// See if the database could be opened
|
||||
if (!db)
|
||||
// The creation process already generated the error
|
||||
return Connection();
|
||||
// Clear any previous error (there shouldn't be any but just in case)
|
||||
Sqrat::Error::Clear(_SqVM);
|
||||
// Clear the temporary buffer
|
||||
GetTempBuff()[0] = 0;
|
||||
// Begin a transaction to replicate the schema of origin database
|
||||
if ((m_Handle = sqlite3_exec(m_Handle, "BEGIN", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to begin schema replication [%s]", m_Handle.ErrMsg());
|
||||
// Attempt to replicate the schema of origin database to the in-memory one
|
||||
SqThrowF("Unable to begin schema replication [%s]", m_Handle.ErrMsg());
|
||||
// Attempt to replicate the schema of origin database to the in-memory one
|
||||
else if ((m_Handle = sqlite3_exec(m_Handle,
|
||||
"SELECT [sql] FROM [sqlite_master] WHERE [sql] NOT NULL AND [tbl_name] != 'sqlite_sequence'",
|
||||
&Connection::ProcessDDLRow, db->mPtr, NULL)) != SQLITE_OK)
|
||||
{
|
||||
// Did the error occurred from the DDL process function?
|
||||
if (Sqrat::Error::Occurred(_SqVM))
|
||||
{
|
||||
// Obtain the occurred message
|
||||
String msg(Sqrat::Error::Message(_SqVM));
|
||||
if (GetTempBuff()[0] != 0)
|
||||
// Throw the resulted message but also include the point where it failed
|
||||
_SqMod->SqThrow("Unable to replicate schema [%s]", msg.c_str());
|
||||
}
|
||||
SqThrowF("Unable to replicate schema [%s]", GetTempBuff());
|
||||
// Obtain the message from the connection handle if possible
|
||||
else
|
||||
_SqMod->SqThrow("Unable to replicate schema [%s]", m_Handle.ErrMsg());
|
||||
SqThrowF("Unable to replicate schema [%s]", m_Handle.ErrMsg());
|
||||
}
|
||||
// Attempt to commit the changes to the database schema replication
|
||||
else if ((m_Handle = sqlite3_exec(m_Handle, "COMMIT", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to commit schema replication [%s]", m_Handle.ErrMsg());
|
||||
SqThrowF("Unable to commit schema replication [%s]", m_Handle.ErrMsg());
|
||||
// Attempt to attach the origin database to the in-memory one
|
||||
else if ((db = sqlite3_exec(db, QFmtStr("ATTACH DATABASE '%q' as origin", m_Handle->mName.c_str()),
|
||||
NULL, NULL, NULL)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to attach origin [%s]", db.ErrMsg());
|
||||
SqThrowF("Unable to attach origin [%s]", db.ErrMsg());
|
||||
// Begin a transaction to replicate the data of origin database
|
||||
else if ((db = sqlite3_exec(db, "BEGIN", NULL, NULL, NULL) != SQLITE_OK))
|
||||
_SqMod->SqThrow("Unable to begin data replication [%s]", db.ErrMsg());
|
||||
SqThrowF("Unable to begin data replication [%s]", db.ErrMsg());
|
||||
// Attempt to replicate the data of origin database to the in-memory one
|
||||
else if ((db = sqlite3_exec(db, "SELECT [name] FROM [origin.sqlite_master] WHERE [type]='table'",
|
||||
&Connection::ProcessDMLRow, db->mPtr, NULL)) != SQLITE_OK)
|
||||
{
|
||||
// Did the error occurred from the DML process function?
|
||||
if (Sqrat::Error::Occurred(_SqVM))
|
||||
if (GetTempBuff()[0] != 0)
|
||||
{
|
||||
// Obtain the occurred message
|
||||
String msg(Sqrat::Error::Message(_SqVM));
|
||||
// Throw the resulted message but also include the point where it failed
|
||||
_SqMod->SqThrow("Unable to replicate data [%s]", msg.c_str());
|
||||
SqThrowF("Unable to replicate data [%s]", GetTempBuff());
|
||||
}
|
||||
// Obtain the message from the connection handle if possible
|
||||
else
|
||||
_SqMod->SqThrow("Unable to replicate data [%s]", db.ErrMsg());
|
||||
SqThrowF("Unable to replicate data [%s]", db.ErrMsg());
|
||||
}
|
||||
// Attempt to commit the changes to the database data replication
|
||||
else if ((db = sqlite3_exec(db, "COMMIT", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
{
|
||||
_SqMod->SqThrow("Unable to commit data replication [%s]", db.ErrMsg());
|
||||
// Attempt to rollback changes from the data copy operation
|
||||
if ((db = sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to rollback data replication [%s]", db.ErrMsg());
|
||||
SqThrowF("Unable to rollback data replication [%s]", db.ErrMsg());
|
||||
// Attempt to detach the disk origin from in-memory database
|
||||
else if ((db = sqlite3_exec(db, "DETACH DATABASE origin", NULL, NULL, NULL)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to detach origin [%s]", db.ErrMsg());
|
||||
SqThrowF("Unable to detach origin [%s]", db.ErrMsg());
|
||||
// Operation failed
|
||||
SqThrowF("Unable to commit data replication [%s]", db.ErrMsg());
|
||||
}
|
||||
// At this point everything went fine and the database instance should be returned
|
||||
else
|
||||
return Connection(db);
|
||||
// Failed to replicate the database
|
||||
return Connection();
|
||||
return Connection(db);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Connection::CopyToDatabase(Connection & db)
|
||||
void Connection::CopyToDatabase(const Connection & db)
|
||||
{
|
||||
// Make sure that we have two valid database handles
|
||||
if (Validate() && db.Validate())
|
||||
_SqMod->SqThrow("Invalid database connections");
|
||||
Validate();
|
||||
db.Validate();
|
||||
// Attempt to take the snapshot and return the result
|
||||
else
|
||||
TakeSnapshot(db.m_Handle);
|
||||
TakeSnapshot(db.m_Handle);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 Connection::Flush(Uint32 num)
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
{
|
||||
// We need to supply a null callback
|
||||
Object env;
|
||||
Function func;
|
||||
// Attempt to flush the requested amount of queries
|
||||
return m_Handle->Flush(num, env, func);
|
||||
}
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// We need to supply a null callback
|
||||
Object env;
|
||||
Function func;
|
||||
// Attempt to flush the requested amount of queries
|
||||
return m_Handle->Flush(num, env, func);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 Connection::Flush(Uint32 num, Object & env, Function & func)
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
// Attempt to flush the requested amount of queries
|
||||
return m_Handle->Flush(num, env, func);
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// Attempt to flush the requested amount of queries
|
||||
return m_Handle->Flush(num, env, func);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -340,10 +285,10 @@ int Connection::ProcessDDLRow(void * db, int columns_count, char ** values, char
|
||||
{
|
||||
// Make sure that exactly one column exists in the result
|
||||
if (columns_count != 1)
|
||||
_SqMod->SqThrow("Error occurred during DDL: columns != 1");
|
||||
FmtStr("Error occurred during DDL: columns != 1");
|
||||
// Execute the sql statement in values[0] in the received database connection
|
||||
else if (sqlite3_exec((sqlite3 *)db, values[0], NULL, NULL, NULL) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Error occurred during DDL execution: %s", sqlite3_errmsg((sqlite3 *)db));
|
||||
FmtStr("Error occurred during DDL execution: %s", sqlite3_errmsg((sqlite3 *)db));
|
||||
else
|
||||
// Continue processing
|
||||
return 0;
|
||||
@ -354,9 +299,9 @@ int Connection::ProcessDDLRow(void * db, int columns_count, char ** values, char
|
||||
int Connection::ProcessDMLRow(void * db, int columns_count, char ** values, char ** /*columns*/)
|
||||
{
|
||||
// Make sure that exactly one column exists in the result
|
||||
if(columns_count != 1)
|
||||
if (columns_count != 1)
|
||||
{
|
||||
_SqMod->SqThrow("Error occurred during DML: columns != 1");
|
||||
FmtStr("Error occurred during DML: columns != 1");
|
||||
// Operation aborted
|
||||
return -1;
|
||||
}
|
||||
@ -364,7 +309,7 @@ int Connection::ProcessDMLRow(void * db, int columns_count, char ** values, char
|
||||
char * sql = sqlite3_mprintf("INSERT INTO main.%q SELECT * FROM origin.%q", values[0], values[0]);
|
||||
// Attempt to execute the generated query string on the received database connection
|
||||
if (sqlite3_exec((sqlite3 *)db, sql, NULL, NULL, NULL) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Error occurred during DML execution: %s", sqlite3_errmsg((sqlite3 *)db));
|
||||
FmtStr("Error occurred during DML execution: %s", sqlite3_errmsg((sqlite3 *)db));
|
||||
else
|
||||
{
|
||||
// Free the generated query string
|
||||
@ -379,19 +324,24 @@ int Connection::ProcessDMLRow(void * db, int columns_count, char ** values, char
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Connection::TakeSnapshot(ConnHnd & destination)
|
||||
void Connection::TakeSnapshot(const ConnHnd & destination)
|
||||
{
|
||||
// Attempt to initialize a backup structure
|
||||
sqlite3_backup * backup = sqlite3_backup_init(destination, "main", m_Handle, "main");
|
||||
// See if the backup structure could be created
|
||||
if (!backup)
|
||||
_SqMod->SqThrow("Unable to initialize the backup structure [%s]", destination.ErrMsg());
|
||||
SqThrowF("Unable to initialize the backup structure [%s]", destination.ErrMsg());
|
||||
// -1 to copy the entire source database to the destination
|
||||
else if ((m_Handle = sqlite3_backup_step(backup, -1)) != SQLITE_DONE)
|
||||
_SqMod->SqThrow("Unable to copy source [%s]", m_Handle.ErrStr());
|
||||
if ((m_Handle = sqlite3_backup_step(backup, -1)) != SQLITE_DONE)
|
||||
{
|
||||
// Finalize the backup structure first
|
||||
sqlite3_backup_finish(backup);
|
||||
// Now it's safe to throw the error
|
||||
SqThrowF("Unable to copy source [%s]", m_Handle.ErrStr());
|
||||
}
|
||||
// Clean up resources allocated by sqlite3_backup_init()
|
||||
if ((m_Handle = sqlite3_backup_finish(backup)) != SQLITE_OK)
|
||||
_SqMod->SqThrow("Unable to finalize backup [%s]", m_Handle.ErrStr());
|
||||
SqThrowF("Unable to finalize backup [%s]", m_Handle.ErrStr());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -421,16 +371,16 @@ SQInteger Connection::ExecF(HSQUIRRELVM vm)
|
||||
// Now we can throw the error message
|
||||
return sq_throwerror(vm, "Unable to retrieve the query");
|
||||
}
|
||||
// Prevent the object from being destroyed once we pop it
|
||||
Var< Object > obj(vm, -1);
|
||||
// If the value was converted to a string then pop the string
|
||||
sq_pop(vm, sq_gettop(vm) - top);
|
||||
// Attempt to execute the specified query
|
||||
if ((inst.value->m_Handle = sqlite3_exec(inst.value->m_Handle, sql, NULL, NULL, NULL)) != SQLITE_OK)
|
||||
{
|
||||
// If the value was converted to a string then pop the string
|
||||
sq_pop(vm, sq_gettop(vm) - top);
|
||||
// Generate the error message and throw the resulted string
|
||||
return sq_throwerror(vm, FmtStr("Unable to execute query [%s]", inst.value->m_Handle.ErrMsg()));
|
||||
}
|
||||
// If the value was converted to a string then pop the string
|
||||
sq_pop(vm, sq_gettop(vm) - top);
|
||||
// Push the result onto the stack
|
||||
sq_pushinteger(vm, sqlite3_changes(inst.value->m_Handle));
|
||||
}
|
||||
@ -492,6 +442,7 @@ SQInteger Connection::QueueF(HSQUIRRELVM vm)
|
||||
{
|
||||
// If the value was converted to a string then pop the string
|
||||
sq_pop(vm, sq_gettop(vm) - top);
|
||||
// Now we can throw the error message
|
||||
return sq_throwerror(vm,"No query to queue");
|
||||
}
|
||||
// Attempt to queue the specified query
|
||||
@ -549,17 +500,18 @@ SQInteger Connection::QueryF(HSQUIRRELVM vm)
|
||||
// Now we can throw the error message
|
||||
return sq_throwerror(vm, "Unable to retrieve the query");
|
||||
}
|
||||
// Attempt to create a statement with the specified query
|
||||
ClassType< Statement >::PushInstance(vm, new Statement(inst.value->m_Handle, sql));
|
||||
// Prevent the object from being destroyed once we pop it
|
||||
Var< Object > obj(vm, -1);
|
||||
// If the value was converted to a string then pop the string
|
||||
sq_pop(vm, sq_gettop(vm) - top);
|
||||
// See if any errors occured
|
||||
if (Sqrat::Error::Occurred(vm))
|
||||
// Attempt to create a statement with the specified query
|
||||
try
|
||||
{
|
||||
// Obtain the error message from sqrat
|
||||
String msg = Sqrat::Error::Message(vm);
|
||||
// Throw the error message further down the line
|
||||
return sq_throwerror(vm, msg.c_str());
|
||||
ClassType< Statement >::PushInstance(vm, new Statement(inst.value->m_Handle, sql));
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.Message().c_str());
|
||||
}
|
||||
}
|
||||
// Do we have enough values to call the format function?
|
||||
@ -573,14 +525,13 @@ SQInteger Connection::QueryF(HSQUIRRELVM vm)
|
||||
if (SQ_FAILED(ret))
|
||||
return ret;
|
||||
// Attempt to create a statement with the specified query
|
||||
ClassType< Statement >::PushInstance(vm, new Statement(inst.value->m_Handle, sql));
|
||||
// See if any errors occured
|
||||
if (Sqrat::Error::Occurred(vm))
|
||||
try
|
||||
{
|
||||
// Obtain the error message from sqrat
|
||||
String msg = Sqrat::Error::Message(vm);
|
||||
// Throw the error message further down the line
|
||||
return sq_throwerror(vm, msg.c_str());
|
||||
ClassType< Statement >::PushInstance(vm, new Statement(inst.value->m_Handle, sql));
|
||||
}
|
||||
catch (const Sqrat::Exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.Message().c_str());
|
||||
}
|
||||
}
|
||||
// All methods of retrieving the message value failed
|
||||
|
@ -23,7 +23,7 @@ protected:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the document reference and throw an error if invalid.
|
||||
*/
|
||||
bool Validate() const;
|
||||
void Validate() const;
|
||||
|
||||
private:
|
||||
|
||||
@ -138,10 +138,9 @@ public:
|
||||
CSStr ToString() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mName.c_str();
|
||||
// Request failed
|
||||
return _SC("");
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mName.c_str();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -187,10 +186,9 @@ public:
|
||||
Int32 GetStatus() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mStatus;
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mStatus;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -199,10 +197,9 @@ public:
|
||||
Int32 GetFlags() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mFlags;
|
||||
// Request failed
|
||||
return 0;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mFlags;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -211,10 +208,9 @@ public:
|
||||
CSStr GetName() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mName.c_str();
|
||||
// Request failed
|
||||
return _SC("");
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mName.c_str();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -223,10 +219,9 @@ public:
|
||||
CSStr GetVFS() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mVFS.c_str();
|
||||
// Request failed
|
||||
return _SC("");
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mVFS.c_str();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -234,9 +229,10 @@ public:
|
||||
*/
|
||||
Int32 GetErrorCode() const
|
||||
{
|
||||
if (Validate())
|
||||
return m_Handle.ErrNo();
|
||||
return -1;
|
||||
// Validate the handle
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle.ErrNo();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -244,9 +240,10 @@ public:
|
||||
*/
|
||||
Int32 GetExtendedErrorCode() const
|
||||
{
|
||||
if (Validate())
|
||||
return m_Handle.ExErrNo();
|
||||
return -1;
|
||||
// Validate the handle
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle.ExErrNo();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -254,9 +251,10 @@ public:
|
||||
*/
|
||||
CSStr GetErrStr() const
|
||||
{
|
||||
if (Validate())
|
||||
return m_Handle.ErrStr();
|
||||
return _SC("");
|
||||
// Validate the handle
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle.ErrStr();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -264,9 +262,10 @@ public:
|
||||
*/
|
||||
CSStr GetErrMsg() const
|
||||
{
|
||||
if (Validate())
|
||||
return m_Handle.ErrMsg();
|
||||
return _SC("");
|
||||
// Validate the handle
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle.ErrMsg();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -326,11 +325,10 @@ public:
|
||||
*/
|
||||
bool GetAutoCommit() const
|
||||
{
|
||||
// Request failed
|
||||
if (Validate())
|
||||
return sqlite3_get_autocommit(m_Handle);
|
||||
// Request failed
|
||||
return false;
|
||||
// Validate the handle
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return sqlite3_get_autocommit(m_Handle);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -345,10 +343,9 @@ public:
|
||||
Int32 GetChanges() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return sqlite3_changes(m_Handle);
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return sqlite3_changes(m_Handle);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -358,10 +355,9 @@ public:
|
||||
Int32 GetTotalChanges() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return sqlite3_total_changes(m_Handle);
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return sqlite3_total_changes(m_Handle);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -370,10 +366,9 @@ public:
|
||||
bool GetTracing() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mTrace;
|
||||
// Request failed
|
||||
return false;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mTrace;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -381,8 +376,10 @@ public:
|
||||
*/
|
||||
void SetTracing(bool toggle)
|
||||
{
|
||||
// Validate the handle and check whether changes are necessary
|
||||
if (!Validate() || m_Handle->mTrace == toggle)
|
||||
// Validate the handle
|
||||
Validate();
|
||||
// Check whether changes are necessary
|
||||
if (m_Handle->mTrace == toggle)
|
||||
return; /* No point in proceeding */
|
||||
// Do we have to disable it?
|
||||
else if (m_Handle->mTrace)
|
||||
@ -398,10 +395,9 @@ public:
|
||||
bool GetProfiling() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mProfile;
|
||||
// Request failed
|
||||
return false;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mProfile;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -409,8 +405,10 @@ public:
|
||||
*/
|
||||
void SetProfiling(bool toggle)
|
||||
{
|
||||
// Validate the handle and check whether changes are necessary
|
||||
if (!Validate() || m_Handle->mProfile == toggle)
|
||||
// Validate the handle
|
||||
Validate();
|
||||
// Check whether changes are necessary
|
||||
if (m_Handle->mProfile == toggle)
|
||||
return; /* No point in proceeding */
|
||||
// Do we have to disable it?
|
||||
else if (m_Handle->mProfile)
|
||||
@ -431,8 +429,9 @@ public:
|
||||
void InterruptOperation() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
sqlite3_interrupt(m_Handle);
|
||||
Validate();
|
||||
// Perform the requested action
|
||||
sqlite3_interrupt(m_Handle);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -441,8 +440,9 @@ public:
|
||||
void ReleaseMemory() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
sqlite3_db_release_memory(m_Handle);
|
||||
Validate();
|
||||
// Perform the requested action
|
||||
sqlite3_db_release_memory(m_Handle);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -453,7 +453,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Takes a snapshot of a database which is located in memory and saves it to a database file.
|
||||
*/
|
||||
void CopyToDatabase(Connection & db);
|
||||
void CopyToDatabase(const Connection & db);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Returns internal runtime status information associated with the current database connection.
|
||||
@ -482,10 +482,9 @@ public:
|
||||
Uint32 QueueSize() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return (Uint32)m_Handle->mQueue.size();
|
||||
// Request failed
|
||||
return 0;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return (Uint32)m_Handle->mQueue.size();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -494,8 +493,9 @@ public:
|
||||
void ClearQueue() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
m_Handle->mQueue.clear();
|
||||
Validate();
|
||||
// Return the requested information
|
||||
m_Handle->mQueue.clear();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -504,7 +504,9 @@ public:
|
||||
void PopQueue() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate() && !m_Handle->mQueue.empty())
|
||||
Validate();
|
||||
// Perform the requested action
|
||||
if (!m_Handle->mQueue.empty())
|
||||
m_Handle->mQueue.pop_back();
|
||||
}
|
||||
|
||||
@ -514,10 +516,9 @@ public:
|
||||
Int32 Flush()
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return Flush(m_Handle->mQueue.size());
|
||||
// Request failed
|
||||
return 0;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Flush(m_Handle->mQueue.size());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -570,7 +571,7 @@ protected:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Takes and saves a snapshot of the memory database in a file.
|
||||
*/
|
||||
void TakeSnapshot(ConnHnd & destination);
|
||||
void TakeSnapshot(const ConnHnd & destination);
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
@ -325,6 +325,7 @@ void RegisterAPI(HSQUIRRELVM vm)
|
||||
.Func(_SC("Release"), &Column::Release)
|
||||
);
|
||||
|
||||
sqlns.Func(_SC("GetErrStr"), &GetErrStr);
|
||||
sqlns.Func(_SC("SetSoftHeapLimit"), &SetSoftHeapLimit);
|
||||
sqlns.Func(_SC("ReleaseMemory"), &ReleaseMemory);
|
||||
sqlns.Func(_SC("MemoryUsage"), &GetMemoryUsage);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -27,17 +27,17 @@ protected:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the statement reference and throw an error if invalid.
|
||||
*/
|
||||
bool Validate() const;
|
||||
void Validate() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the statement reference and index, and throw an error if they're invalid.
|
||||
*/
|
||||
bool ValidateIndex(Int32 idx) const;
|
||||
void ValidateIndex(Int32 idx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the statement reference and row, and throw an error if they're invalid.
|
||||
*/
|
||||
bool RowAvailable() const;
|
||||
void ValidateRow() const;
|
||||
|
||||
public:
|
||||
|
||||
@ -196,10 +196,9 @@ public:
|
||||
Int32 GetStatus() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mStatus;
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mStatus;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -208,10 +207,9 @@ public:
|
||||
Int32 GetErrorCode() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle.ErrNo();
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle.ErrNo();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -220,10 +218,9 @@ public:
|
||||
Int32 GetExtendedErrorCode() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle.ExErrNo();
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle.ExErrNo();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -232,10 +229,9 @@ public:
|
||||
CSStr GetErrStr() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle.ErrStr();
|
||||
// Request failed
|
||||
return _SC("");
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle.ErrStr();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -244,10 +240,9 @@ public:
|
||||
CSStr GetErrMsg() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle.ErrMsg();
|
||||
// Request failed
|
||||
return _SC("");
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle.ErrMsg();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -256,10 +251,9 @@ public:
|
||||
Int32 GetColumns() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mColumns;
|
||||
// Request failed
|
||||
return -1;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mColumns;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -268,10 +262,9 @@ public:
|
||||
CSStr GetQuery() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mQuery.c_str();
|
||||
// Request failed
|
||||
return _SC("");
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mQuery.c_str();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -280,10 +273,9 @@ public:
|
||||
bool GetGood() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mGood;
|
||||
// Request failed
|
||||
return false;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mGood;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -292,10 +284,9 @@ public:
|
||||
bool GetDone() const
|
||||
{
|
||||
// Validate the handle
|
||||
if (Validate())
|
||||
return m_Handle->mDone;
|
||||
// Request failed
|
||||
return false;
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return m_Handle->mDone;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user