1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +01:00

Compare commits

...

4 Commits

Author SHA1 Message Date
Sandu Liviu Catalin
ebe60ebf4b Update Data.cpp
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-07-19 20:03:00 +03:00
Sandu Liviu Catalin
fa9c3a5821 Check for a valid session pointer. 2022-07-19 19:43:30 +03:00
Sandu Liviu Catalin
f238588abe More work on async sql.
Current implementation only provides execution for sqlite queries in worker threads. Statements and MySQL is on the TODO list.
2022-07-19 19:29:32 +03:00
Sandu Liviu Catalin
39524098f1 Extend worker pool.
Task exceptions are caught and they can provide custom information to identify the task that failed.
Take ownership of the task instance sooner.
2022-07-19 19:28:13 +03:00
8 changed files with 593 additions and 167 deletions

View File

@ -125,7 +125,11 @@ void ThreadPool::Process()
// Is the item valid?
if (item)
{
item->OnCompleted(); // Allow the item to finish itself
try {
item->OnCompleted(); // Allow the item to finish itself
} catch (const std::exception & e) {
LogErr("Exception occured in %s completion stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
}
}
}
}
@ -149,7 +153,11 @@ void ThreadPool::WorkerProc()
// Is there an item that requested to try again?
if (item)
{
item->OnAborted(true); // NOLINT(bugprone-use-after-move) There's an `if` condition above idiot!
try {
item->OnAborted(true); // NOLINT(bugprone-use-after-move) There's an `if` condition above idiot!
} catch (const std::exception & e) {
LogErr("Exception occured in %s cancelation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
}
}
// Exit the loop
break;
@ -175,15 +183,30 @@ void ThreadPool::WorkerProc()
// Is there an item to be processed?
if (item)
{
item->OnAborted(false); // It should mark itself as aborted somehow!
try {
item->OnAborted(false); // It should mark itself as aborted somehow!
} catch (const std::exception & e) {
LogErr("Exception occured in %s forced cancelation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
}
}
// Exit the loop
break;
}
bool r;
// Attempt preparation
try {
r = item->OnPrepare();
} catch (const std::exception & e) {
LogErr("Exception occured in %s preparation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
}
// Perform the task
if (item->OnPrepare())
if (r)
{
retry = item->OnProcess();
try {
retry = item->OnProcess();
} catch (const std::exception & e) {
LogErr("Exception occured in %s processing stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
}
}
// The task was performed
if (!retry)

View File

@ -55,6 +55,16 @@ struct ThreadPoolItem
*/
ThreadPoolItem & operator = (ThreadPoolItem && o) = delete;
/* --------------------------------------------------------------------------------------------
* Provide a name to what type of task this is. Mainly for debugging purposes.
*/
SQMOD_NODISCARD virtual const char * TypeName() noexcept { return "worker item"; }
/* --------------------------------------------------------------------------------------------
* Provide unique information that may help identify the task. Mainly for debugging purposes.
*/
SQMOD_NODISCARD virtual const char * IdentifiableInfo() noexcept { return ""; }
/* --------------------------------------------------------------------------------------------
* Invoked in worker thread by the thread pool after obtaining the task from the queue.
* Must return true to indicate that the task can be performed. False indicates failure.
@ -174,6 +184,14 @@ public:
* Queue an item to be processed. Will take ownership of the given pointer!
*/
void Enqueue(ThreadPoolItem * item)
{
Enqueue(Item{item});
}
/* --------------------------------------------------------------------------------------------
* Queue an item to be processed. Will take ownership of the given pointer!
*/
void Enqueue(Item && item)
{
// Only queue valid items
if (!item || !m_Running) return;
@ -183,7 +201,7 @@ public:
// Acquire a lock on the mutex
std::unique_lock< std::mutex > lock(m_Mutex);
// Push the item in the queue
m_Queue.push(Item(item));
m_Queue.push(std::forward< Item >(item));
// Release the mutex before notifying
lock.unlock();
// Notify one thread that there's work
@ -191,18 +209,32 @@ public:
}
else
{
// Take ownership
Item i{item};
bool r;
// Attempt preparation
try {
r = item->OnPrepare();
} catch (const std::exception & e) {
LogErr("Exception occured in %s preparation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
}
// Perform the task in-place
if (i->OnPrepare())
if (r)
{
if (i->OnProcess())
try {
r = item->OnProcess();
} catch (const std::exception & e) {
LogErr("Exception occured in %s processing stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
}
if (r)
{
i->OnAborted(true); // Not accepted in single thread
try {
item->OnAborted(true); // Not accepted in single thread
} catch (const std::exception & e) {
LogErr("Exception occured in %s cancelation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
}
}
}
// Task is completed in processing stage
m_Finished.enqueue(std::move(i));
m_Finished.enqueue(std::forward< Item >(item));
}
}
@ -213,7 +245,6 @@ public:
{
return m_Threads.size();
}
};
} // Namespace:: SqMod

View File

@ -18,7 +18,7 @@
namespace SqMod {
// ------------------------------------------------------------------------------------------------
LightObj GteMySQLFromSession(Poco::Data::SessionImpl * session)
LightObj GetMySQLFromSession(Poco::Data::SessionImpl * session)
{
// Create a reference counted connection handle instance
MySQLConnRef ref(new MySQLConnHnd(session));
@ -551,7 +551,7 @@ char DbConvTo< char >::From(const SQChar * value, unsigned long length, enum_fie
// ------------------------------------------------------------------------------------------------
void MySQLConnHnd::GrabCurrent()
{
mErrNo = mysql_errno(mPtr);
mErrNo = mysql_errno(Access());
mErrStr.assign(mysql_error(mPtr));
}
@ -601,7 +601,7 @@ MySQLConnHnd::MySQLConnHnd()
MySQLConnHnd::MySQLConnHnd(Poco::Data::SessionImpl * session)
: MySQLConnHnd()
{
mSession.assign(session);
mSession.assign(session, true);
// Retrieve the internal handle property
mPtr = Poco::AnyCast< MYSQL * >(session->getProperty("handle"));
}
@ -712,7 +712,7 @@ void MySQLConnHnd::Disconnect()
uint64_t MySQLConnHnd::Execute(const SQChar * query, unsigned long size)
{
// Make sure that we are connected
if (!mPtr)
if (!Access())
{
STHROWF("Invalid MySQL connection");
}
@ -863,7 +863,7 @@ void MySQLStmtBind::SetInput(enum_field_types type, BindType * bind, const char
// ------------------------------------------------------------------------------------------------
void MySQLStmtHnd::GrabCurrent()
{
mErrNo = mysql_stmt_errno(mPtr);
mErrNo = mysql_stmt_errno(Access());
mErrStr.assign(mysql_stmt_error(mPtr));
}
@ -889,7 +889,7 @@ void MySQLStmtHnd::ThrowCurrent(const char * act)
void MySQLStmtHnd::ValidateParam(uint32_t idx, const char * file, int32_t line) const
{
// Is the handle valid?
if (mPtr == nullptr)
if (Access() == nullptr)
{
STHROWF("Invalid MySQL statement reference =>[{}:{}]", file, line);
}
@ -902,7 +902,7 @@ void MySQLStmtHnd::ValidateParam(uint32_t idx, const char * file, int32_t line)
void MySQLStmtHnd::ValidateParam(uint32_t idx) const
{
// Is the handle valid?
if (mPtr == nullptr)
if (Access() == nullptr)
{
STHROWF("Invalid MySQL statement reference");
}
@ -951,7 +951,7 @@ MySQLStmtHnd::~MySQLStmtHnd()
void MySQLStmtHnd::Create(const MySQLConnRef & conn, const SQChar * query)
{
// Is this statement already created?
if (mPtr != nullptr)
if (Access() != nullptr)
{
STHROWF("MySQL statement was already created");
}
@ -1185,7 +1185,7 @@ void MySQLResHnd::ThrowCurrent(const char * act) const
void MySQLResHnd::ValidateField(uint32_t idx, const char * file, int32_t line) const
{
// Is the handle valid?
if (mPtr == nullptr)
if (Access() == nullptr)
{
STHROWF("Invalid MySQL result-set =>[{}:{}]", file, line);
}
@ -1198,7 +1198,7 @@ void MySQLResHnd::ValidateField(uint32_t idx, const char * file, int32_t line) c
void MySQLResHnd::ValidateField(uint32_t idx) const
{
// Is the handle valid?
if (mPtr == nullptr)
if (Access() == nullptr)
{
STHROWF("Invalid MySQL result-set");
}
@ -1213,7 +1213,7 @@ void MySQLResHnd::ValidateField(uint32_t idx) const
uint32_t MySQLResHnd::GetFieldIndex(const SQChar * name)
{
// Validate the handle
if (!mPtr)
if (!Access())
{
STHROWF("Invalid MySQL result-set");
}
@ -1232,7 +1232,7 @@ uint32_t MySQLResHnd::GetFieldIndex(const SQChar * name)
void MySQLResHnd::Create(const MySQLConnRef & conn)
{
// Is this result-set already created?
if (mPtr != nullptr)
if (Access() != nullptr)
{
STHROWF("MySQL result-set was already created");
}
@ -1279,7 +1279,7 @@ void MySQLResHnd::Create(const MySQLConnRef & conn)
void MySQLResHnd::Create(const MySQLStmtRef & stmt)
{
// Is this result-set already created?
if (mPtr != nullptr)
if (Access() != nullptr)
{
STHROWF("MySQL result-set was already created");
}
@ -1369,7 +1369,7 @@ void MySQLResHnd::Create(const MySQLStmtRef & stmt)
uint64_t MySQLResHnd::RowIndex() const
{
// Is this result-set even valid?
if (!mPtr)
if (!Access())
{
STHROWF("Invalid MySQL result-set");
}
@ -1386,7 +1386,7 @@ uint64_t MySQLResHnd::RowIndex() const
uint64_t MySQLResHnd::RowCount() const
{
// Is this result-set even valid?
if (!mPtr)
if (!Access())
{
STHROWF("Invalid MySQL result-set");
}
@ -1403,7 +1403,7 @@ uint64_t MySQLResHnd::RowCount() const
bool MySQLResHnd::Next()
{
// Is this result-set even valid?
if (!mPtr)
if (!Access())
{
STHROWF("Invalid MySQL result-set");
}
@ -1425,7 +1425,7 @@ bool MySQLResHnd::Next()
bool MySQLResHnd::SetRowIndex(uint64_t index)
{
// Is this result-set even valid?
if (!mPtr)
if (!Access())
{
STHROWF("Invalid MySQL result-set");
}
@ -1671,7 +1671,7 @@ void MySQLConnection::ValidateCreated(const char * file, int32_t line) const
{
SqThrowF(SQMOD_RTFMT("Invalid MySQL connection reference =>[{}:{}]"), file, line);
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(SQMOD_RTFMT("Invalid MySQL connection =>[{}:{}]"), file, line);
}
@ -1683,7 +1683,7 @@ void MySQLConnection::ValidateCreated() const
{
SqThrowF(fmt::runtime("Invalid MySQL connection reference"));
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(fmt::runtime("Invalid MySQL connection"));
}
@ -1734,7 +1734,7 @@ SQInteger MySQLConnection::Insert(const SQChar * query)
SQMOD_THROW_CURRENT(*m_Handle, "Unable to execute MySQL query");
}
// Return the identifier of the inserted row
return static_cast< SQInteger >(mysql_insert_id(m_Handle->mPtr));
return static_cast< SQInteger >(mysql_insert_id(m_Handle->Access()));
}
// ------------------------------------------------------------------------------------------------
@ -1872,12 +1872,12 @@ SQInteger MySQLConnection::InsertF(HSQUIRRELVM vm)
// Attempt to execute the specified query
try
{
if (mysql_real_query(conn->m_Handle->mPtr, val.mPtr, static_cast<unsigned long>(val.mLen)) != 0)
if (mysql_real_query(conn->m_Handle->Access(), val.mPtr, static_cast<unsigned long>(val.mLen)) != 0)
{
SQMOD_THROW_CURRENT(*(conn->m_Handle), "Unable to execute MySQL query");
}
// Return the identifier of the inserted row
sq_pushinteger(vm, static_cast< SQInteger >(mysql_insert_id(conn->m_Handle->mPtr)));
sq_pushinteger(vm, static_cast< SQInteger >(mysql_insert_id(conn->m_Handle->Access())));
}
catch (const std::exception & e)
{
@ -1939,7 +1939,7 @@ SQInteger MySQLConnection::QueryF(HSQUIRRELVM vm)
// Attempt to execute the specified query
try
{
if (mysql_real_query(conn->m_Handle->mPtr, val.mPtr, static_cast<unsigned long>(val.mLen)) != 0)
if (mysql_real_query(conn->m_Handle->Access(), val.mPtr, static_cast<unsigned long>(val.mLen)) != 0)
{
SQMOD_THROW_CURRENT(*(conn->m_Handle), "Unable to execute MySQL query");
}
@ -1966,7 +1966,7 @@ LightObj MySQLConnection::EscapeString(StackStrF & str)
// Allocate a buffer for the given string
std::vector< SQChar > buffer(static_cast< size_t >(str.mLen * 2 + 1));
// Attempt to escape the specified string
const unsigned long len = mysql_real_escape_string(m_Handle->mPtr, buffer.data(), str.mPtr,
const unsigned long len = mysql_real_escape_string(m_Handle->Access(), buffer.data(), str.mPtr,
static_cast<unsigned long>(str.mLen));
// Return the resulted string
return LightObj(buffer.data(), static_cast< SQInteger >(len), str.mVM);
@ -2515,7 +2515,7 @@ void MySQLResultSet::ValidateCreated(const char * file, int32_t line) const
{
SqThrowF(SQMOD_RTFMT("Invalid MySQL result-set reference =>[{}:{}]"), file, line);
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(SQMOD_RTFMT("Invalid MySQL result-set =>[{}:{}]"), file, line);
}
@ -2528,7 +2528,7 @@ void MySQLResultSet::ValidateCreated() const
{
SqThrowF(fmt::runtime("Invalid MySQL result-set reference"));
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(fmt::runtime("Invalid MySQL result-set"));
}
@ -2795,7 +2795,7 @@ void MySQLStatement::ValidateCreated(const char * file, int32_t line) const
{
SqThrowF(SQMOD_RTFMT("Invalid MySQL statement reference =>[{}:{}]"), file, line);
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(SQMOD_RTFMT("Invalid MySQL statement =>[{}:{}]"), file, line);
}
@ -2807,7 +2807,7 @@ void MySQLStatement::ValidateCreated() const
{
SqThrowF(fmt::runtime("Invalid MySQL statement reference"));
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(fmt::runtime("Invalid MySQL statement"));
}
@ -2882,46 +2882,46 @@ void MySQLStatement::SetConnection(const MySQLConnection & conn)
int32_t MySQLStatement::Execute()
{
// Attempt to bind the parameters
if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds))
if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->Access(), m_Handle->mMyBinds))
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters");
}
// Attempt to execute the statement
else if (mysql_stmt_execute(m_Handle->mPtr))
else if (mysql_stmt_execute(m_Handle->Access()))
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement");
}
// Return the number of rows affected by this query
return static_cast< int32_t >(mysql_stmt_affected_rows(m_Handle->mPtr));
return static_cast< int32_t >(mysql_stmt_affected_rows(m_Handle->Access()));
}
// ------------------------------------------------------------------------------------------------
uint32_t MySQLStatement::Insert()
{
// Attempt to bind the parameters
if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds))
if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->Access(), m_Handle->mMyBinds))
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters");
}
// Attempt to execute the statement
else if (mysql_stmt_execute(m_Handle->mPtr))
else if (mysql_stmt_execute(m_Handle->Access()))
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement");
}
// Return the identifier of the inserted row
return static_cast< uint32_t >(mysql_stmt_insert_id(m_Handle->mPtr));
return static_cast< uint32_t >(mysql_stmt_insert_id(m_Handle->Access()));
}
// ------------------------------------------------------------------------------------------------
MySQLResultSet MySQLStatement::Query()
{
// Attempt to bind the parameters
if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds))
if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->Access(), m_Handle->mMyBinds))
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters");
}
// Attempt to execute the statement
else if (mysql_stmt_execute(m_Handle->mPtr))
else if (mysql_stmt_execute(m_Handle->Access()))
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement");
}

View File

@ -301,6 +301,20 @@ public:
* Execute a query on the server.
*/
uint64_t Execute(const SQChar * query, unsigned long size = 0UL);
/* --------------------------------------------------------------------------------------------
* Access the connection pointer.
*/
SQMOD_NODISCARD Pointer Access() const
{
if (!mSession.isNull()) {
// Only reason this is necessary is to dirty the connection handle access time-stamp
// So it won't be closed/collected when it comes from a connection/session-pool
[[maybe_unused]] auto _ = mSession->isConnected();
}
// We yield access to the pointer anyway
return mPtr;
}
};
/* ------------------------------------------------------------------------------------------------
@ -436,11 +450,11 @@ public:
// --------------------------------------------------------------------------------------------
unsigned long mParams; // Number of parameters in the statement.
MySQLStmtBind * mBinds; // List of parameter binds.
MySQLStmtBind * mBinds; // List of parameter binds.
BindType * mMyBinds; // List of parameter binds.
// --------------------------------------------------------------------------------------------
MySQLConnRef mConnection; // Reference to the associated connection.
MySQLConnRef mConnection; // Reference to the associated connection.
String mQuery; // The query string.
/* --------------------------------------------------------------------------------------------
@ -488,6 +502,20 @@ public:
* Create the actual statement.
*/
void Create(const MySQLConnRef & conn, const SQChar * query);
/* --------------------------------------------------------------------------------------------
* Access the statement pointer.
*/
SQMOD_NODISCARD Pointer Access() const
{
if (bool(mConnection) && !(mConnection->mSession.isNull())) {
// Only reason this is necessary is to dirty the connection handle access time-stamp
// So it won't be closed/collected when it comes from a connection/session-pool
[[maybe_unused]] auto _ = mConnection->mSession->isConnected();
}
// We yield access to the pointer anyway
return mPtr;
}
};
/* ------------------------------------------------------------------------------------------------
@ -631,13 +659,13 @@ public:
uint32_t mFieldCount; // Number of fields in the result-set.
unsigned long * mLengths; // Data length when the result-set came from a connection.
FieldType * mFields; // Fields in the results set.
MySQLResBind * mBinds; // Bind wrappers.
MySQLResBind * mBinds; // Bind wrappers.
BindType * mMyBinds; // Bind points.
RowType mRow; // Row data.
// --------------------------------------------------------------------------------------------
MySQLConnRef mConnection; // Associated connection.
MySQLStmtRef mStatement; // Associated statement.
MySQLConnRef mConnection; // Associated connection.
MySQLStmtRef mStatement; // Associated statement.
IndexMap mIndexes; // MySQLField names and their associated index.
public:
@ -718,6 +746,19 @@ public:
*/
bool SetRowIndex(uint64_t index);
/* --------------------------------------------------------------------------------------------
* Access the resource pointer.
*/
SQMOD_NODISCARD Pointer Access() const
{
if (bool(mConnection) && !(mConnection->mSession.isNull())) {
// Only reason this is necessary is to dirty the connection handle access time-stamp
// So it won't be closed/collected when it comes from a connection/session-pool
[[maybe_unused]] auto _ = mConnection->mSession->isConnected();
}
// We yield access to the pointer anyway
return mPtr;
}
};
/* ------------------------------------------------------------------------------------------------
@ -1239,7 +1280,7 @@ public:
*/
SQMOD_NODISCARD const SQChar * ToString() const
{
return m_Handle ? mysql_get_host_info(m_Handle->mPtr) : _SC("");
return m_Handle ? mysql_get_host_info(m_Handle->Access()) : _SC("");
}
/* --------------------------------------------------------------------------------------------
@ -1268,7 +1309,7 @@ public:
*/
SQMOD_NODISCARD bool IsConnected() const
{
return m_Handle && (m_Handle->mPtr != nullptr);
return m_Handle && (m_Handle->Access() != nullptr);
}
/* --------------------------------------------------------------------------------------------
@ -1468,7 +1509,7 @@ public:
{
// Attempt to toggle auto-commit if necessary
if (SQMOD_GET_CREATED(*this)->mAutoCommit != toggle &&
mysql_autocommit(m_Handle->mPtr, static_cast< MySQLStmtBind::BoolType >(toggle)) != 0)
mysql_autocommit(m_Handle->Access(), static_cast< MySQLStmtBind::BoolType >(toggle)) != 0)
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot toggle auto-commit");
}

View File

@ -363,7 +363,7 @@ static const EnumElement g_MainEnum[] = {
};
// ------------------------------------------------------------------------------------------------
LightObj GteSQLiteFromSession(Poco::Data::SessionImpl * session)
LightObj GetSQLiteFromSession(Poco::Data::SessionImpl * session)
{
// Create a reference counted connection handle instance
SQLiteConnRef ref(new SQLiteConnHnd(session));
@ -623,7 +623,16 @@ SQLiteConnHnd::SQLiteConnHnd()
SQLiteConnHnd::SQLiteConnHnd(Poco::Data::SessionImpl * session)
: SQLiteConnHnd()
{
mSession.assign(session);
mSession.assign(session, true);
// Retrieve the internal handle property
mPtr = Poco::AnyCast< sqlite3 * >(session->getProperty("handle"));
}
// ------------------------------------------------------------------------------------------------
SQLiteConnHnd::SQLiteConnHnd(Poco::AutoPtr< Poco::Data::SessionImpl > && session)
: SQLiteConnHnd()
{
mSession == std::forward< Poco::AutoPtr< Poco::Data::SessionImpl > >(session);
// Retrieve the internal handle property
mPtr = Poco::AnyCast< sqlite3 * >(session->getProperty("handle"));
}
@ -656,7 +665,7 @@ SQLiteConnHnd::~SQLiteConnHnd()
void SQLiteConnHnd::Create(const SQChar * name, int32_t flags, const SQChar * vfs)
{
// Make sure a previous connection doesn't exist
if (mPtr)
if (Access())
{
STHROWF("Unable to connect to database. Database already connected");
}
@ -689,7 +698,7 @@ void SQLiteConnHnd::Create(const SQChar * name, int32_t flags, const SQChar * vf
int32_t SQLiteConnHnd::Flush(uint32_t num, Object & env, Function & func)
{
// Do we even have a valid connection?
if (!mPtr)
if (!Access())
{
return -1; // No connection!
}
@ -780,7 +789,7 @@ int32_t SQLiteConnHnd::Flush(uint32_t num, Object & env, Function & func)
SQLiteStmtHnd::SQLiteStmtHnd(SQLiteConnRef conn)
: mPtr(nullptr)
, mStatus(SQLITE_OK)
, mConn(std::move(conn))
, mConnection(std::move(conn))
, mQuery()
, mColumns(0)
, mParameters(0)
@ -800,7 +809,7 @@ SQLiteStmtHnd::~SQLiteStmtHnd()
// Attempt to finalize the statement
if ((sqlite3_finalize(mPtr)) != SQLITE_OK)
{
LogErr("Unable to finalize SQLite statement [%s]", mConn->ErrMsg());
LogErr("Unable to finalize SQLite statement [%s]", mConnection->ErrMsg());
}
}
}
@ -809,12 +818,12 @@ SQLiteStmtHnd::~SQLiteStmtHnd()
void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
{
// Make sure a previous statement doesn't exist
if (mPtr)
if (Access())
{
STHROWF("Unable to prepare statement. Statement already prepared");
}
// Is the specified database connection is valid?
else if (!mConn)
else if (!mConnection)
{
STHROWF("Unable to prepare statement. Invalid connection handle");
}
@ -826,7 +835,7 @@ void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
// Save the query string
mQuery.assign(query, static_cast< size_t >(length));
// Attempt to prepare a statement with the specified query string
if ((mStatus = sqlite3_prepare_v2(mConn->mPtr, mQuery.c_str(), ConvTo< int32_t >::From(mQuery.size()),
if ((mStatus = sqlite3_prepare_v2(mConnection->mPtr, mQuery.c_str(), ConvTo< int32_t >::From(mQuery.size()),
&mPtr, nullptr)) != SQLITE_OK)
{
// Clear the query string since it failed
@ -834,7 +843,7 @@ void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
// Explicitly make sure the handle is null
mPtr = nullptr;
// Now it's safe to throw the error
STHROWF("Unable to prepare statement [{}]", mConn->ErrMsg());
STHROWF("Unable to prepare statement [{}]", mConnection->ErrMsg());
}
else
{
@ -849,7 +858,7 @@ void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
int32_t SQLiteStmtHnd::GetColumnIndex(const SQChar * name, SQInteger length)
{
// Validate the handle
if (!mPtr)
if (!Access())
{
STHROWF("Invalid SQLite statement");
}
@ -887,25 +896,25 @@ int32_t SQLiteStmtHnd::GetColumnIndex(const SQChar * name, SQInteger length)
// ------------------------------------------------------------------------------------------------
const char * SQLiteStmtHnd::ErrStr() const
{
return mConn ? sqlite3_errstr(sqlite3_errcode(mConn->mPtr)) : _SC("");
return mConnection ? sqlite3_errstr(sqlite3_errcode(mConnection->Access())) : _SC("");
}
// ------------------------------------------------------------------------------------------------
const char * SQLiteStmtHnd::ErrMsg() const
{
return mConn ? sqlite3_errmsg(mConn->mPtr) : _SC("");
return mConnection ? sqlite3_errmsg(mConnection->Access()) : _SC("");
}
// ------------------------------------------------------------------------------------------------
int32_t SQLiteStmtHnd::ErrNo() const
{
return mConn ? sqlite3_errcode(mConn->mPtr) : SQLITE_NOMEM;
return mConnection ? sqlite3_errcode(mConnection->Access()) : SQLITE_NOMEM;
}
// ------------------------------------------------------------------------------------------------
int32_t SQLiteStmtHnd::ExErrNo() const
{
return mConn ? sqlite3_extended_errcode(mConn->mPtr) : SQLITE_NOMEM;
return mConnection ? sqlite3_extended_errcode(mConnection->Access()) : SQLITE_NOMEM;
}
// ------------------------------------------------------------------------------------------------
@ -947,7 +956,7 @@ void SQLiteConnection::ValidateCreated(const char * file, int32_t line) const
{
SqThrowF(SQMOD_RTFMT("Invalid SQLite connection reference =>[{}:{}]"), file, line);
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(SQMOD_RTFMT("Invalid SQLite connection =>[{}:{}]"), file, line);
}
@ -959,7 +968,7 @@ void SQLiteConnection::ValidateCreated() const
{
SqThrowF(fmt::runtime("Invalid SQLite connection reference"));
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(fmt::runtime("Invalid SQLite connection"));
}
@ -1055,14 +1064,14 @@ int32_t SQLiteConnection::Exec(StackStrF & str)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to execute the specified query
m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, str.mPtr, nullptr, nullptr, nullptr);
m_Handle->mStatus = sqlite3_exec(m_Handle->Access(), str.mPtr, nullptr, nullptr, nullptr);
// Validate the execution result
if (m_Handle->mStatus != SQLITE_OK)
{
STHROWF("Unable to execute query [{}]", m_Handle->ErrMsg());
}
// Return rows affected by this query
return sqlite3_changes(m_Handle->mPtr);
return sqlite3_changes(m_Handle->Access());
}
// ------------------------------------------------------------------------------------------------
@ -1135,12 +1144,12 @@ void SQLiteConnection::SetTracing(bool SQ_UNUSED_ARG(toggle)) // NOLINT(readabil
// Do we have to disable it?
else if (m_Handle->mTrace)
{
sqlite3_trace(m_Handle->mPtr, nullptr, nullptr);
sqlite3_trace(m_Handle->Access(), nullptr, nullptr);
}
// Go ahead and enable tracing
else
{
sqlite3_trace(m_Handle->mPtr, &SQLiteConnection::TraceOutput, nullptr);
sqlite3_trace(m_Handle->Access(), &SQLiteConnection::TraceOutput, nullptr);
}
#endif
}
@ -1159,12 +1168,12 @@ void SQLiteConnection::SetProfiling(bool SQ_UNUSED_ARG(toggle)) // NOLINT(readab
// Do we have to disable it?
else if (m_Handle->mProfile)
{
sqlite3_profile(m_Handle->mPtr, nullptr, nullptr);
sqlite3_profile(m_Handle->Access(), nullptr, nullptr);
}
// Go ahead and enable profiling
else
{
sqlite3_profile(m_Handle->mPtr, &SQLiteConnection::ProfileOutput, nullptr);
sqlite3_profile(m_Handle->Access(), &SQLiteConnection::ProfileOutput, nullptr);
}
#endif
}
@ -1174,7 +1183,7 @@ void SQLiteConnection::SetBusyTimeout(int32_t millis)
{
SQMOD_VALIDATE_CREATED(*this);
// Apply the requested timeout
if ((m_Handle->mStatus = sqlite3_busy_timeout(m_Handle->mPtr, millis)) != SQLITE_OK)
if ((m_Handle->mStatus = sqlite3_busy_timeout(m_Handle->Access(), millis)) != SQLITE_OK)
{
STHROWF("Unable to set busy timeout [{}]", m_Handle->ErrMsg());
}
@ -1295,7 +1304,7 @@ void SQLiteParameter::ValidateCreated(const char * file, int32_t line) const
{
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
}
@ -1312,7 +1321,7 @@ void SQLiteParameter::ValidateCreated() const
{
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(fmt::runtime("Invalid SQLite statement"));
}
@ -1403,7 +1412,7 @@ void SQLiteParameter::SetIndex(const Object & param)
STHROWF("Cannot use an empty parameter name");
}
// Attempt to find a parameter with the specified name
idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->mPtr, val.mPtr);
idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->Access(), val.mPtr);
} break;
// Is this an integer value? (or at least can be easily converted to one)
case OT_INTEGER:
@ -1435,7 +1444,7 @@ void SQLiteParameter::SetIndex(const Object & param)
// Attempt to find a parameter with the specified name
else
{
idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->mPtr, val.mPtr);
idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->Access(), val.mPtr);
}
} break;
// We don't recognize this kind of value!
@ -1458,7 +1467,7 @@ Object SQLiteParameter::GetStatement() const
// ------------------------------------------------------------------------------------------------
Object SQLiteParameter::GetConnection() const
{
return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn);
return GetConnectionObj(SQMOD_GET_VALID(*this)->mConnection);
}
// ------------------------------------------------------------------------------------------------
@ -1503,7 +1512,7 @@ void SQLiteParameter::SetBool(bool value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, value);
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, value);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1516,7 +1525,7 @@ void SQLiteParameter::SetChar(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< SQChar >::From(value));
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< SQChar >::From(value));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1529,7 +1538,7 @@ void SQLiteParameter::SetInteger(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_integer(m_Handle->mPtr, m_Index, value);
m_Handle->mStatus = sqlite3_bind_integer(m_Handle->Access(), m_Index, value);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1542,7 +1551,7 @@ void SQLiteParameter::SetInt8(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int8_t >::From(value));
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< int8_t >::From(value));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1555,7 +1564,7 @@ void SQLiteParameter::SetUint8(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< uint8_t >::From(value));
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< uint8_t >::From(value));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1568,7 +1577,7 @@ void SQLiteParameter::SetInt16(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int16_t >::From(value));
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< int16_t >::From(value));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1581,7 +1590,7 @@ void SQLiteParameter::SetUint16(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< uint16_t >::From(value));
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< uint16_t >::From(value));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1594,7 +1603,7 @@ void SQLiteParameter::SetInt32(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int32_t >::From(value));
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< int32_t >::From(value));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1607,7 +1616,7 @@ void SQLiteParameter::SetUint32(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, static_cast< int32_t >(ConvTo< uint32_t >::From(value)));
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, static_cast< int32_t >(ConvTo< uint32_t >::From(value)));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1620,7 +1629,7 @@ void SQLiteParameter::SetInt64(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value);
m_Handle->mStatus = sqlite3_bind_int64(m_Handle->Access(), m_Index, value);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1633,7 +1642,7 @@ void SQLiteParameter::SetUint64(SQInteger value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value);
m_Handle->mStatus = sqlite3_bind_int64(m_Handle->Access(), m_Index, value);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1646,7 +1655,7 @@ void SQLiteParameter::SetFloat(SQFloat value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, value);
m_Handle->mStatus = sqlite3_bind_double(m_Handle->Access(), m_Index, value);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1659,7 +1668,7 @@ void SQLiteParameter::SetFloat32(SQFloat value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, ConvTo< float >::From(value));
m_Handle->mStatus = sqlite3_bind_double(m_Handle->Access(), m_Index, ConvTo< float >::From(value));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1672,7 +1681,7 @@ void SQLiteParameter::SetFloat64(SQFloat value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, value);
m_Handle->mStatus = sqlite3_bind_double(m_Handle->Access(), m_Index, value);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1685,7 +1694,7 @@ void SQLiteParameter::SetString(StackStrF & value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, value.mPtr, static_cast<int>(value.mLen), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, value.mPtr, static_cast<int>(value.mLen), SQLITE_TRANSIENT);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1698,7 +1707,7 @@ void SQLiteParameter::SetStringRaw(const SQChar * value, SQInteger length)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, value, static_cast<int>(length), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, value, static_cast<int>(length), SQLITE_TRANSIENT);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1711,7 +1720,7 @@ void SQLiteParameter::SetZeroBlob(SQInteger size)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_zeroblob(m_Handle->mPtr, m_Index, ConvTo< int32_t >::From(size));
m_Handle->mStatus = sqlite3_bind_zeroblob(m_Handle->Access(), m_Index, ConvTo< int32_t >::From(size));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1743,7 +1752,7 @@ void SQLiteParameter::SetBlob(const Object & value)
len = sqstd_getblobsize(vm, -1);
}
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, ptr, static_cast<int>(len), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->Access(), m_Index, ptr, static_cast<int>(len), SQLITE_TRANSIENT);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1757,9 +1766,9 @@ void SQLiteParameter::SetData(const SqBuffer & value)
Buffer & buff = *value.GetRef();
// Attempt to bind the specified value
#ifdef _SQ64
m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->mPtr, m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->Access(), m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
#else
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->Access(), m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
#endif
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
@ -1788,9 +1797,9 @@ void SQLiteParameter::SetDataEx(const SqBuffer & value, SQInteger offset, SQInte
}
// Attempt to bind the specified value
#ifdef _SQ64
m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->mPtr, m_Index, (buff.Data() + offset), static_cast< sqlite3_uint64 >(offset + length), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->Access(), m_Index, (buff.Data() + offset), static_cast< sqlite3_uint64 >(offset + length), SQLITE_TRANSIENT);
#else
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, (buff.Data() + offset), static_cast< int >(offset + length), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->Access(), m_Index, (buff.Data() + offset), static_cast< int >(offset + length), SQLITE_TRANSIENT);
#endif
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
@ -1806,7 +1815,7 @@ void SQLiteParameter::SetDate(const Date & value)
// Attempt to generate the specified date string
auto str = fmt::format("{} 00:00:00", value.ToString());
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1829,7 +1838,7 @@ void SQLiteParameter::SetDateEx(SQInteger year, SQInteger month, SQInteger day)
// Attempt to generate the specified date string
auto str = fmt::format("{}-{}-{} 00:00:00", y, m, d);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1842,7 +1851,7 @@ void SQLiteParameter::SetTime(const Time & value)
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, static_cast<int>(value.GetTimestamp().GetSecondsI()));
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, static_cast<int>(value.GetTimestamp().GetSecondsI()));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1874,7 +1883,7 @@ void SQLiteParameter::SetTimeEx(SQInteger hour, SQInteger minute, SQInteger seco
STHROWF("Second value is out of range: {} >= 60", s);
}
// Calculate the number of seconds in the specified time and bind the resulted value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, (h * (60 * 60)) + (m * 60) + s);
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, (h * (60 * 60)) + (m * 60) + s);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1922,7 +1931,7 @@ void SQLiteParameter::SetDatetimeEx(SQInteger year, SQInteger month, SQInteger d
// Attempt to generate the specified date string
auto str = fmt::format(_SC("{:04}-{:02}-{:02} {:02}:{:02}:{:02}"), y, mo, d, h, mi, s);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -1935,7 +1944,7 @@ void SQLiteParameter::SetNow()
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index,
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index,
static_cast< int32_t >(std::time(nullptr)));
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
@ -1949,7 +1958,7 @@ void SQLiteParameter::SetNull()
{
SQMOD_VALIDATE_CREATED(*this);
// Attempt to bind the specified value
m_Handle->mStatus = sqlite3_bind_null(m_Handle->mPtr, m_Index);
m_Handle->mStatus = sqlite3_bind_null(m_Handle->Access(), m_Index);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -2001,7 +2010,7 @@ void SQLiteColumn::ValidateCreated(const char * file, int32_t line) const
{
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
}
@ -2018,7 +2027,7 @@ void SQLiteColumn::ValidateCreated() const
{
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(fmt::runtime("Invalid SQLite statement"));
}
@ -2187,7 +2196,7 @@ Object SQLiteColumn::GetStatement() const
// ------------------------------------------------------------------------------------------------
Object SQLiteColumn::GetConnection() const
{
return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn);
return GetConnectionObj(SQMOD_GET_VALID(*this)->mConnection);
}
// ------------------------------------------------------------------------------------------------
@ -2233,7 +2242,7 @@ Object SQLiteColumn::GetValue() const
// Obtain the initial stack size
const StackGuard sg;
// Identify which type of value must be pushed on the stack
switch (sqlite3_column_type(m_Handle->mPtr, m_Index))
switch (sqlite3_column_type(m_Handle->Access(), m_Index))
{
// Is this a null value?
case SQLITE_NULL:
@ -2243,28 +2252,28 @@ Object SQLiteColumn::GetValue() const
// Is this an integer?
case SQLITE_INTEGER:
{
sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->mPtr, m_Index));
sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->Access(), m_Index));
} break;
// Is this a floating point?
case SQLITE_FLOAT:
{
sq_pushfloat(SqVM(),
ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index)));
ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->Access(), m_Index)));
} break;
// Is this a string?
case SQLITE_TEXT:
{
sq_pushstring(SqVM(),
reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index)),
sqlite3_column_bytes(m_Handle->mPtr, m_Index));
reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->Access(), m_Index)),
sqlite3_column_bytes(m_Handle->Access(), m_Index));
} break;
// Is this raw data?
case SQLITE_BLOB:
{
// Retrieve the size of the blob that must be allocated
const int32_t size = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
const int32_t size = sqlite3_column_bytes(m_Handle->Access(), m_Index);
// Retrieve the the actual blob data that must be returned
auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->mPtr, m_Index));
auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->Access(), m_Index));
// Attempt to create a buffer with the blob data on the stack
Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
} break;
@ -2282,7 +2291,7 @@ Object SQLiteColumn::GetNumber() const
// Obtain the initial stack size
const StackGuard sg;
// Identify which type of value must be pushed on the stack
switch (sqlite3_column_type(m_Handle->mPtr, m_Index))
switch (sqlite3_column_type(m_Handle->Access(), m_Index))
{
// Is this a null value?
case SQLITE_NULL:
@ -2292,18 +2301,18 @@ Object SQLiteColumn::GetNumber() const
// Is this an integer?
case SQLITE_INTEGER:
{
sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->mPtr, m_Index));
sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->Access(), m_Index));
} break;
// Is this a floating point?
case SQLITE_FLOAT:
{
sq_pushfloat(SqVM(),
ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index)));
ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->Access(), m_Index)));
} break;
// Is this a string?
case SQLITE_TEXT:
{
auto str = reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index));
auto str = reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->Access(), m_Index));
// Is there even a string to parse?
if (!str || *str == '\0')
{
@ -2334,7 +2343,7 @@ SQInteger SQLiteColumn::GetInteger() const
{
SQMOD_VALIDATE_ROW(*this);
// Return the requested information
return sqlite3_column_integer(m_Handle->mPtr, m_Index);
return sqlite3_column_integer(m_Handle->Access(), m_Index);
}
// ------------------------------------------------------------------------------------------------
@ -2342,7 +2351,7 @@ SQFloat SQLiteColumn::GetFloat() const
{
SQMOD_VALIDATE_ROW(*this);
// Return the requested information
return ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index));
return ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->Access(), m_Index));
}
// ------------------------------------------------------------------------------------------------
@ -2350,7 +2359,7 @@ SQInteger SQLiteColumn::GetLong() const
{
SQMOD_VALIDATE_ROW(*this);
// Return the requested information
return sqlite3_column_int64(m_Handle->mPtr, m_Index);
return sqlite3_column_int64(m_Handle->Access(), m_Index);
}
// ------------------------------------------------------------------------------------------------
@ -2360,8 +2369,8 @@ Object SQLiteColumn::GetString() const
// Obtain the initial stack size
const StackGuard sg;
// Push the column text on the stack
sq_pushstring(SqVM(), reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index)),
sqlite3_column_bytes(m_Handle->mPtr, m_Index));
sq_pushstring(SqVM(), reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->Access(), m_Index)),
sqlite3_column_bytes(m_Handle->Access(), m_Index));
// Get the object from the stack and return it
return Var< Object >(SqVM(), -1).value;
}
@ -2371,7 +2380,7 @@ bool SQLiteColumn::GetBoolean() const
{
SQMOD_VALIDATE_ROW(*this);
// Return the requested information
return sqlite3_column_int(m_Handle->mPtr, m_Index) > 0;
return sqlite3_column_int(m_Handle->Access(), m_Index) > 0;
}
// ------------------------------------------------------------------------------------------------
@ -2379,7 +2388,7 @@ SQChar SQLiteColumn::GetChar() const
{
SQMOD_VALIDATE_ROW(*this);
// Return the requested information
return (SQChar)sqlite3_column_int(m_Handle->mPtr, m_Index);
return (SQChar)sqlite3_column_int(m_Handle->Access(), m_Index);
}
// ------------------------------------------------------------------------------------------------
@ -2389,9 +2398,9 @@ Object SQLiteColumn::GetBuffer() const
// Remember the current stack size
const StackGuard sg;
// Retrieve the size of the blob that must be allocated
const int32_t size = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
const int32_t size = sqlite3_column_bytes(m_Handle->Access(), m_Index);
// Retrieve the the actual blob data that must be returned
auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->mPtr, m_Index));
auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->Access(), m_Index));
// Attempt to create a buffer with the blob data on the stack
Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
// Get the object from the stack and return it
@ -2405,11 +2414,11 @@ Object SQLiteColumn::GetBlob() const
// Obtain the initial stack size
const StackGuard sg;
// Obtain the size of the data
const int32_t sz = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
const int32_t sz = sqlite3_column_bytes(m_Handle->Access(), m_Index);
// Allocate a blob of the same size
SQUserPointer p = sqstd_createblob(SqVM(), sz);
// Obtain a pointer to the data
const void * b = sqlite3_column_blob(m_Handle->mPtr, m_Index);
const void * b = sqlite3_column_blob(m_Handle->Access(), m_Index);
// Could the memory blob be allocated?
if (!p)
{
@ -2459,7 +2468,7 @@ void SQLiteStatement::ValidateCreated(const char * file, int32_t line) const
{
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
}
@ -2471,7 +2480,7 @@ void SQLiteStatement::ValidateCreated() const
{
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
}
else if (m_Handle->mPtr == nullptr)
else if (m_Handle->Access() == nullptr)
{
SqThrowF(fmt::runtime("Invalid SQLite statement"));
}
@ -2587,7 +2596,7 @@ SQLiteStatement::SQLiteStatement(const SQLiteConnection & connection, StackStrF
// ------------------------------------------------------------------------------------------------
Object SQLiteStatement::GetConnection() const
{
return Object(new SQLiteConnection(SQMOD_GET_VALID(*this)->mConn));
return Object(new SQLiteConnection(SQMOD_GET_VALID(*this)->mConnection));
}
// ------------------------------------------------------------------------------------------------
@ -2598,7 +2607,7 @@ SQLiteStatement & SQLiteStatement::Reset()
m_Handle->mGood = false;
m_Handle->mDone = false;
// Attempt to reset the statement to it's initial state
m_Handle->mStatus = sqlite3_reset(m_Handle->mPtr);
m_Handle->mStatus = sqlite3_reset(m_Handle->Access());
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -2616,7 +2625,7 @@ SQLiteStatement & SQLiteStatement::Clear()
m_Handle->mGood = false;
m_Handle->mDone = false;
// Attempt to clear the statement
m_Handle->mStatus = sqlite3_clear_bindings(m_Handle->mPtr);
m_Handle->mStatus = sqlite3_clear_bindings(m_Handle->Access());
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -2636,7 +2645,7 @@ int32_t SQLiteStatement::Exec()
STHROWF("Executed without resetting first");
}
// Attempt to step the statement
m_Handle->mStatus = sqlite3_step(m_Handle->mPtr);
m_Handle->mStatus = sqlite3_step(m_Handle->Access());
// Have we finished stepping?
if (m_Handle->mStatus == SQLITE_DONE)
{
@ -2644,7 +2653,7 @@ int32_t SQLiteStatement::Exec()
m_Handle->mGood = false;
m_Handle->mDone = true;
// Return the changes made by this statement
return sqlite3_changes(m_Handle->mConn->mPtr);
return sqlite3_changes(m_Handle->mConnection->mPtr);
}
// Specify that we don't have any row and we haven't finished stepping
m_Handle->mGood = false;
@ -2677,7 +2686,7 @@ bool SQLiteStatement::Step()
STHROWF("Stepped without resetting first");
}
// Attempt to step the statement
m_Handle->mStatus = sqlite3_step(m_Handle->mPtr);
m_Handle->mStatus = sqlite3_step(m_Handle->Access());
// Do we have a row available?
if (m_Handle->mStatus == SQLITE_ROW)
{
@ -2827,7 +2836,7 @@ Table SQLiteStatement::GetTable(int32_t min, int32_t max) const
while (min <= max)
{
// Attempt to obtain the column name
const SQChar * name = sqlite3_column_name(m_Handle->mPtr, min);
const SQChar * name = sqlite3_column_name(m_Handle->Access(), min);
// Validate the obtained name
if (!name)
{
@ -2859,7 +2868,7 @@ SQLiteTransaction::SQLiteTransaction(SQLiteConnRef db)
STHROWF("Invalid connection handle");
}
// Attempt to begin transaction
m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "BEGIN", nullptr, nullptr, nullptr);
m_Handle->mStatus = sqlite3_exec(m_Handle->Access(), "BEGIN", nullptr, nullptr, nullptr);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -2876,7 +2885,7 @@ SQLiteTransaction::~SQLiteTransaction()
return; // We're done here!
}
// Attempt to roll back changes because this failed to commit
m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "ROLLBACK", nullptr, nullptr, nullptr);
m_Handle->mStatus = sqlite3_exec(m_Handle->Access(), "ROLLBACK", nullptr, nullptr, nullptr);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{
@ -2899,7 +2908,7 @@ bool SQLiteTransaction::Commit()
STHROWF("Transaction was already committed");
}
// Attempt to commit the change during this transaction
m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "COMMIT", nullptr, nullptr, nullptr);
m_Handle->mStatus = sqlite3_exec(m_Handle->Access(), "COMMIT", nullptr, nullptr, nullptr);
// Validate the result
if (m_Handle->mStatus != SQLITE_OK)
{

View File

@ -2,6 +2,7 @@
// ------------------------------------------------------------------------------------------------
#include "Core/Utility.hpp"
#include "Core/ThreadPool.hpp"
// ------------------------------------------------------------------------------------------------
#include "Library/IO/Buffer.hpp"
@ -200,6 +201,11 @@ public:
*/
explicit SQLiteConnHnd(Poco::Data::SessionImpl * session);
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit SQLiteConnHnd(Poco::AutoPtr< Poco::Data::SessionImpl > && session);
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
@ -266,6 +272,20 @@ public:
{
return sqlite3_extended_errcode(mPtr);
}
/* --------------------------------------------------------------------------------------------
* Access the connection pointer.
*/
SQMOD_NODISCARD Pointer Access() const
{
if (!mSession.isNull()) {
// Only reason this is necessary is to dirty the connection handle access time-stamp
// So it won't be closed/collected when it comes from a connection/session-pool
[[maybe_unused]] auto _ = mSession->isConnected();
}
// We yield access to the pointer anyway
return mPtr;
}
};
/* ------------------------------------------------------------------------------------------------
@ -298,7 +318,7 @@ public:
int32_t mStatus; // The last status code of this connection handle.
// --------------------------------------------------------------------------------------------
SQLiteConnRef mConn; // The handle to the associated database connection.
SQLiteConnRef mConnection; // The handle to the associated database connection.
// --------------------------------------------------------------------------------------------
String mQuery; // The query string used to create this statement.
@ -387,6 +407,20 @@ public:
* Return the extended numeric result code for the most recent failed API call (if any).
*/
SQMOD_NODISCARD int32_t ExErrNo() const;
/* --------------------------------------------------------------------------------------------
* Access the statement pointer.
*/
SQMOD_NODISCARD Pointer Access() const
{
if (bool(mConnection) && !(mConnection->mSession.isNull())) {
// Only reason this is necessary is to dirty the connection handle access time-stamp
// So it won't be closed/collected when it comes from a connection/session-pool
[[maybe_unused]] auto _ = mConnection->mSession->isConnected();
}
// We yield access to the pointer anyway
return mPtr;
}
};
/* ------------------------------------------------------------------------------------------------
@ -538,7 +572,7 @@ public:
*/
operator sqlite3 * () //NOLINT (intentionally implicit)
{
return m_Handle ? m_Handle->mPtr : nullptr;
return m_Handle ? m_Handle->Access() : nullptr;
}
/* --------------------------------------------------------------------------------------------
@ -546,7 +580,7 @@ public:
*/
operator sqlite3 * () const //NOLINT (intentionally implicit)
{
return m_Handle ? m_Handle->mPtr : nullptr;
return m_Handle ? m_Handle->Access() : nullptr;
}
/* --------------------------------------------------------------------------------------------
@ -578,7 +612,7 @@ public:
*/
SQMOD_NODISCARD bool IsConnected() const
{
return m_Handle && (m_Handle->mPtr != nullptr);
return m_Handle && (m_Handle->Access() != nullptr);
}
/* --------------------------------------------------------------------------------------------
@ -691,6 +725,16 @@ public:
*/
Object Query(StackStrF & str) const;
/* --------------------------------------------------------------------------------------------
* Attempt to execute the specified query asynchronously.
*/
LightObj AsyncExec(StackStrF & str);
/* --------------------------------------------------------------------------------------------
* Attempt to create a statement from the specified query asynchronously.
*/
LightObj AsyncQuery(StackStrF & str) const;
/* --------------------------------------------------------------------------------------------
* See if the database connection was opened in read-only mode.
*/
@ -869,8 +913,8 @@ class SQLiteParameter
private:
// --------------------------------------------------------------------------------------------
int32_t m_Index{0}; // The index of the managed parameter.
SQLiteStmtRef m_Handle{}; // Reference to the managed statement.
int32_t m_Index{0}; // The index of the managed parameter.
SQLiteStmtRef m_Handle{}; // Reference to the managed statement.
protected:
@ -1045,7 +1089,7 @@ public:
// Can we attempt to return the parameter name?
if (m_Handle && m_Index)
{
const SQChar * val = sqlite3_bind_parameter_name(m_Handle->mPtr, m_Index);
const SQChar * val = sqlite3_bind_parameter_name(m_Handle->Access(), m_Index);
// Return the value if valid
return val ? val : String{};
}
@ -1448,7 +1492,7 @@ public:
// Can we attempt to return the parameter name?
if (m_Handle && m_Index)
{
const SQChar * val = sqlite3_column_name(m_Handle->mPtr, m_Index);
const SQChar * val = sqlite3_column_name(m_Handle->Access(), m_Index);
// Return the value if valid
return val ? val : String{};
}
@ -1727,7 +1771,7 @@ public:
*/
operator sqlite3_stmt * () // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
{
return m_Handle ? m_Handle->mPtr : nullptr;
return m_Handle ? m_Handle->Access() : nullptr;
}
/* --------------------------------------------------------------------------------------------
@ -1735,7 +1779,7 @@ public:
*/
operator sqlite3_stmt * () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
{
return m_Handle ? m_Handle->mPtr : nullptr;
return m_Handle ? m_Handle->Access() : nullptr;
}
/* --------------------------------------------------------------------------------------------
@ -1767,7 +1811,7 @@ public:
*/
SQMOD_NODISCARD bool IsPrepared() const
{
return m_Handle && (m_Handle->mPtr != nullptr);
return m_Handle && (m_Handle->Access() != nullptr);
}
/* --------------------------------------------------------------------------------------------

View File

@ -1,5 +1,8 @@
// ------------------------------------------------------------------------------------------------
#include "PocoLib/Data.hpp"
#include "Core/ThreadPool.hpp"
#include "Library/SQLite.hpp"
#include "Library/MySQL.hpp"
#include "Poco/Data/SessionImpl.h"
// ------------------------------------------------------------------------------------------------
@ -34,6 +37,7 @@ SQMOD_DECL_TYPENAME(SqPcDataStatement, _SC("SqDataStatement"))
SQMOD_DECL_TYPENAME(SqPcDataRecordSet, _SC("SqDataRecordSet"))
SQMOD_DECL_TYPENAME(SqPcDataTransaction, _SC("SqDataTransaction"))
SQMOD_DECL_TYPENAME(SqPcDataSessionPool, _SC("SqDataSessionPool"))
SQMOD_DECL_TYPENAME(SqPcSqDataAsyncBuilder, _SC("SqSqDataAsyncBuilder"))
SQMOD_DECL_TYPENAME(SqPcDataStatementResult, _SC("SqDataStatementResult"))
// ------------------------------------------------------------------------------------------------
@ -472,8 +476,8 @@ SqDataStatement & SqDataStatement::Into_(LightObj & obj, LightObj & def)
}
// ------------------------------------------------------------------------------------------------
extern LightObj GteSQLiteFromSession(Poco::Data::SessionImpl * session);
extern LightObj GteMySQLFromSession(Poco::Data::SessionImpl * session);
extern LightObj GetSQLiteFromSession(Poco::Data::SessionImpl * session);
extern LightObj GetMySQLFromSession(Poco::Data::SessionImpl * session);
// ------------------------------------------------------------------------------------------------
LightObj SqDataSessionPool::GetSq()
@ -484,17 +488,198 @@ LightObj SqDataSessionPool::GetSq()
// Is this a SQLite session?
if (connector == "sqlite")
{
return GteSQLiteFromSession(session_impl);
return GetSQLiteFromSession(session_impl);
}
// Is this a MySQL session?
else if (connector == "mysql")
{
return GteMySQLFromSession(session_impl);
return GetMySQLFromSession(session_impl);
}
STHROWF("Unknown connector type {}", connector);
SQ_UNREACHABLE
}
// ------------------------------------------------------------------------------------------------
LightObj SqDataSessionPool::AsyncExec(StackStrF & sql)
{
return LightObj{SqTypeIdentity< SqDataAsyncBuilder >{}, SqVM(), get().impl(), sql, false};
}
// ------------------------------------------------------------------------------------------------
LightObj SqDataSessionPool::AsyncQuery(StackStrF & sql)
{
return LightObj{SqTypeIdentity< SqDataAsyncBuilder >{}, SqVM(), get().impl(), sql, true};
}
/* ------------------------------------------------------------------------------------------------
* Common session action implementation.
*/
struct SQLiteAsyncExec : public ThreadPoolItem
{
using SessionRef = Poco::AutoPtr< Poco::Data::SessionImpl >;
// --------------------------------------------------------------------------------------------
SessionRef mSession{}; // The connection that will be used by this task.
sqlite3 * mConnection{nullptr}; // Raw connection handle.
// --------------------------------------------------------------------------------------------
Function mResolved{}; // Callback to invoke when the task was completed.
Function mRejected{}; // Callback to invoke when the task was aborted.
// --------------------------------------------------------------------------------------------
int32_t mResult{SQLITE_OK}; // Execution result code.
int32_t mChanges{0}; // Rows affected by this query.
// --------------------------------------------------------------------------------------------
const SQChar * mQueryStr{nullptr}; // The query string that will be executed.
LightObj mQueryObj{}; // Strong reference to the query string object.
// --------------------------------------------------------------------------------------------
String mError{}; // Error message, if any.
/* --------------------------------------------------------------------------------------------
* Base constructor. Members are supposed to be validated and filled by the builder/proxy.
*/
SQLiteAsyncExec() = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~SQLiteAsyncExec() override = default;
/* --------------------------------------------------------------------------------------------
* Provide a name to what type of task this is. Mainly for debugging purposes.
*/
SQMOD_NODISCARD const char * TypeName() noexcept override { return "sqlite async execute"; }
/* --------------------------------------------------------------------------------------------
* Provide unique information that may help identify the task. Mainly for debugging purposes.
*/
SQMOD_NODISCARD const char * IdentifiableInfo() noexcept override { return mQueryStr; }
/* --------------------------------------------------------------------------------------------
* Invoked in worker thread by the thread pool after obtaining the task from the queue.
* Must return true to indicate that the task can be performed. False indicates failure.
*/
SQMOD_NODISCARD bool OnPrepare() override
{
// Coincidentally, this also dirties the handle time-stamp so it doesn't get collected
return mSession->isConnected();
}
/* --------------------------------------------------------------------------------------------
* Called in worker by the thread pool to performed by the associated tasks.
* Will be called continuously while the returned value is true. While false means it finished.
*/
SQMOD_NODISCARD bool OnProcess() override
{
char * err_msg = nullptr;
// Attempt to execute the specified query
mResult = sqlite3_exec(mConnection, mQueryStr, nullptr, nullptr, &err_msg);
// Store changes count
if (mResult == SQLITE_OK)
{
mChanges = sqlite3_changes(mConnection);
}
// Check for error message
if (err_msg != nullptr)
{
mError.assign(err_msg);
sqlite3_free(err_msg);
}
// Don't retry
return false;
};
/* --------------------------------------------------------------------------------------------
* Invoked in main thread by the thread pool after the task was completed.
*/
void OnCompleted() override
{
if (mResult == SQLITE_OK)
{
if (!mResolved.IsNull())
{
SQLiteConnRef conn_ref{new SQLiteConnHnd(std::move(mSession))};
LightObj connection{SqTypeIdentity< SQLiteConnection >{}, SqVM(), conn_ref};
mResolved.Execute(connection, mChanges, mQueryObj);
}
}
else if (!mRejected.IsNull())
{
SQLiteConnRef conn_ref{new SQLiteConnHnd(std::move(mSession))};
LightObj connection{SqTypeIdentity< SQLiteConnection >{}, SqVM(), conn_ref};
mRejected.Execute(connection, mResult, mError, mQueryObj);
}
}
/* --------------------------------------------------------------------------------------------
* Called in worker by the thread pool to let the task know that it will be aborted.
* Most likely due to a shutdown of the thread pool.
*/
void OnAborted(bool SQ_UNUSED_ARG(retry)) override
{
// We don't really have to do anything for now
}
};
// ------------------------------------------------------------------------------------------------
SqDataAsyncBuilder::SqDataAsyncBuilder(Poco::Data::SessionImpl * session, StackStrF & sql, bool stmt) noexcept
: mSession(session, true)
, mResolved(), mRejected()
, mQueryStr(sql.mPtr), mQueryObj(sql.mObj)
, mStmt(stmt)
{
}
// ------------------------------------------------------------------------------------------------
void SqDataAsyncBuilder::Submit()
{
if (mSession.isNull())
{
STHROWF("Asynchronous query builder instance is invalid.");
}
auto & connector = mSession->connectorName();
// Is this a SQLite session?
if (connector == "sqlite")
{
// Retrieve the internal handle property
auto * connection = Poco::AnyCast< sqlite3 * >(mSession->getProperty("handle"));
// Is this a statement?
if (mStmt)
{
//...
}
else
{
auto * item = new SQLiteAsyncExec();
// Take ownership before any exception can be thrown
std::unique_ptr< ThreadPoolItem > task{static_cast< ThreadPoolItem * >(item)};
// Populate task information
item->mConnection = connection;
item->mResolved = std::move(mResolved);
item->mRejected = std::move(mRejected);
item->mQueryStr = mQueryStr;
item->mQueryObj = std::move(mQueryObj);
item->mSession = std::move(mSession);
// Submit the task
ThreadPool::Get().Enqueue(std::move(task));
}
}
// Is this a MySQL session?
else if (connector == "mysql")
{
if (mStmt)
{
//...
}
else
{
//...
}
}
else
{
STHROWF("Unknown connector type {}", connector);
}
}
// ------------------------------------------------------------------------------------------------
LightObj SqDataSessionPool::GetProperty(StackStrF & name)
{
@ -771,6 +956,16 @@ void Register_POCO_Data(HSQUIRRELVM vm, Table &)
.Overload(_SC("Value"), &SqDataRecordSet::GetValueOr)
);
// --------------------------------------------------------------------------------------------
ns.Bind(_SC("AsyncBuilder"),
Class< SqDataAsyncBuilder, NoConstructor< SqDataAsyncBuilder > >(vm, SqPcSqDataAsyncBuilder::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqPcSqDataAsyncBuilder::Fn)
// Member Methods
.Func(_SC("Submit"), &SqDataAsyncBuilder::Submit)
.CbFunc(_SC("Resolved"), &SqDataAsyncBuilder::OnResolved)
.CbFunc(_SC("Rejected"), &SqDataAsyncBuilder::OnRejected)
);
// --------------------------------------------------------------------------------------------
ns.Bind(_SC("SessionPool"),
Class< SqDataSessionPool, NoCopy< SqDataSessionPool > >(vm, SqPcDataSessionPool::Str)
// Constructors
@ -790,6 +985,8 @@ void Register_POCO_Data(HSQUIRRELVM vm, Table &)
// Member Methods
.Func(_SC("Get"), &SqDataSessionPool::Get)
.Func(_SC("GetSq"), &SqDataSessionPool::GetSq)
.Func(_SC("AsyncExec"), &SqDataSessionPool::AsyncExec)
.Func(_SC("AsyncQuery"), &SqDataSessionPool::AsyncQuery)
.FmtFunc(_SC("GetWithProperty"), &SqDataSessionPool::GetWithProperty)
.FmtFunc(_SC("GetWithFeature"), &SqDataSessionPool::GetWithFeature)
.FmtFunc(_SC("SetFeature"), &SqDataSessionPool::SetFeature)

View File

@ -1771,6 +1771,16 @@ struct SqDataSessionPool : public SessionPool
*/
LightObj GetSq();
/* --------------------------------------------------------------------------------------------
* Create an asynchronus query execution builder.
*/
LightObj AsyncExec(StackStrF & sql);
/* --------------------------------------------------------------------------------------------
* Create an asynchronus query execution builder.
*/
LightObj AsyncQuery(StackStrF & sql);
/* --------------------------------------------------------------------------------------------
* Retrieve a Session with requested property set.
*/
@ -2075,4 +2085,75 @@ struct SqDataTransaction : public Transaction
}
};
/* ------------------------------------------------------------------------------------------------
* Common session action implementation.
*/
struct SqDataAsyncBuilder
{
using SessionRef = Poco::AutoPtr< Poco::Data::SessionImpl >;
// --------------------------------------------------------------------------------------------
SessionRef mSession{}; // The connection that will be used by the task.
// --------------------------------------------------------------------------------------------
Function mResolved{}; // Callback to invoke when the task was completed.
Function mRejected{}; // Callback to invoke when the task was aborted.
// --------------------------------------------------------------------------------------------
const SQChar * mQueryStr{nullptr}; // The query string that will be executed.
LightObj mQueryObj{}; // Strong reference to the query string object.
// --------------------------------------------------------------------------------------------
bool mStmt{false}; // Whether this is a query statement or a simple query execution.
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
SqDataAsyncBuilder(Poco::Data::SessionImpl * session, StackStrF & sql, bool stmt) noexcept;
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
SqDataAsyncBuilder(const SqDataAsyncBuilder & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
SqDataAsyncBuilder(SqDataAsyncBuilder && o) = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~SqDataAsyncBuilder() = default;
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
SqDataAsyncBuilder & operator = (const SqDataAsyncBuilder & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
SqDataAsyncBuilder & operator = (SqDataAsyncBuilder && o) = default;
/* --------------------------------------------------------------------------------------------
* Create the task with the suplied information and submit it to the worker pool.
*/
void Submit();
/* --------------------------------------------------------------------------------------------
* Set the callback to be executed if the query was resolved.
*/
SqDataAsyncBuilder & OnResolved(Function & cb)
{
mResolved = std::move(cb);
return *this; // Allow chaining
}
/* --------------------------------------------------------------------------------------------
* Set the callback to be executed if the query was rejected/failed.
*/
SqDataAsyncBuilder & OnRejected(Function & cb)
{
mRejected = std::move(cb);
return *this; // Allow chaining
}
};
} // Namespace:: SqMod