diff --git a/module/Library/MySQL.cpp b/module/Library/MySQL.cpp index 379b8a89..9bf2ab1f 100644 --- a/module/Library/MySQL.cpp +++ b/module/Library/MySQL.cpp @@ -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(val.mLen)) != 0) + if (mysql_real_query(conn->m_Handle->Access(), val.mPtr, static_cast(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(val.mLen)) != 0) + if (mysql_real_query(conn->m_Handle->Access(), val.mPtr, static_cast(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(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"); } diff --git a/module/Library/MySQL.hpp b/module/Library/MySQL.hpp index 8a616d90..2be3c28d 100644 --- a/module/Library/MySQL.hpp +++ b/module/Library/MySQL.hpp @@ -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"); } diff --git a/module/Library/SQLite.cpp b/module/Library/SQLite.cpp index d9f1ddb7..0b5738d1 100644 --- a/module/Library/SQLite.cpp +++ b/module/Library/SQLite.cpp @@ -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(value.mLen), SQLITE_TRANSIENT); + m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, value.mPtr, static_cast(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(length), SQLITE_TRANSIENT); + m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, value, static_cast(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(len), SQLITE_TRANSIENT); + m_Handle->mStatus = sqlite3_bind_blob(m_Handle->Access(), m_Index, ptr, static_cast(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(value.GetTimestamp().GetSecondsI())); + m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, static_cast(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) { diff --git a/module/Library/SQLite.hpp b/module/Library/SQLite.hpp index a5083908..dc0f8130 100644 --- a/module/Library/SQLite.hpp +++ b/module/Library/SQLite.hpp @@ -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); } /* -------------------------------------------------------------------------------------------- diff --git a/module/PocoLib/Data.cpp b/module/PocoLib/Data.cpp index ca5976b7..274c08e4 100644 --- a/module/PocoLib/Data.cpp +++ b/module/PocoLib/Data.cpp @@ -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,202 @@ 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 + { + OutputError("query process begin"); + char * err_msg = nullptr; + // Attempt to execute the specified query + mResult = sqlite3_exec(mConnection, mQueryStr, nullptr, nullptr, &err_msg); + OutputError("query process check"); + // Store changes count + if (mResult == SQLITE_OK) + { + mChanges = sqlite3_changes(mConnection); + } + OutputError("query process remember"); + // Check for error message + if (err_msg != nullptr) + { + mError.assign(err_msg); + sqlite3_free(err_msg); + } + OutputError("query process completed"); + // 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) + { + OutputError("result was 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()) + { + OutputError("result was bad"); + SQLiteConnRef conn_ref{new SQLiteConnHnd(std::move(mSession))}; + OutputError("handle created"); + LightObj connection{SqTypeIdentity< SQLiteConnection >{}, SqVM(), conn_ref}; + OutputError("object is ready"); + mRejected.Execute(connection, mResult, mError, mQueryObj); + OutputError("callback finished"); + } + } + + /* -------------------------------------------------------------------------------------------- + * 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() +{ + 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 +960,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 +989,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) diff --git a/module/PocoLib/Data.hpp b/module/PocoLib/Data.hpp index d6728a29..a2a06105 100644 --- a/module/PocoLib/Data.hpp +++ b/module/PocoLib/Data.hpp @@ -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