diff --git a/orm_lib/inc/drogon/orm/DbClient.h b/orm_lib/inc/drogon/orm/DbClient.h index 89b3f12390..ee83718a4f 100644 --- a/orm_lib/inc/drogon/orm/DbClient.h +++ b/orm_lib/inc/drogon/orm/DbClient.h @@ -350,8 +350,10 @@ class DROGON_EXPORT DbClient : public trantor::NonCopyable std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&exceptCallback) = 0; + std::function &&exceptCallback, + bool usePreparedStmt) = 0; protected: ClientType type_; diff --git a/orm_lib/inc/drogon/orm/SqlBinder.h b/orm_lib/inc/drogon/orm/SqlBinder.h index 3335e6ffbd..52d6b7d4d8 100644 --- a/orm_lib/inc/drogon/orm/SqlBinder.h +++ b/orm_lib/inc/drogon/orm/SqlBinder.h @@ -115,6 +115,15 @@ enum class Mode NonBlocking, Blocking }; +enum class ResultFormat +{ + Text = 0, + Binary = 1 +}; +enum class SqlOption +{ + DisablePreparedStmt +}; namespace internal { @@ -323,6 +332,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable parameters_(std::move(that.parameters_)), lengths_(std::move(that.lengths_)), formats_(std::move(that.formats_)), + resultFormat_(that.resultFormat_), objs_(std::move(that.objs_)), mode_(that.mode_), callbackHolder_(std::move(that.callbackHolder_)), @@ -331,6 +341,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable execed_(that.execed_), destructed_(that.destructed_), isExceptionPtr_(that.isExceptionPtr_), + usePreparedStmt_(that.usePreparedStmt_), type_(that.type_) { // set the execed_ to true to avoid the same sql being executed twice. @@ -511,6 +522,50 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable return *this; } + self &operator<<(const ResultFormat &resultFormat) + { + resultFormat_ = resultFormat; + return *this; + } + + self &operator<<(ResultFormat &resultFormat) + { + resultFormat_ = resultFormat; + return *this; + } + + self &operator<<(ResultFormat &&resultFormat) + { + resultFormat_ = resultFormat; + return *this; + } + + self &setSqlOption(SqlOption option) + { + switch (option) + { + case SqlOption::DisablePreparedStmt: + usePreparedStmt_ = false; + break; + } + return *this; + } + + self &operator<<(const SqlOption &option) + { + return setSqlOption(option); + } + + self &operator<<(SqlOption &option) + { + return setSqlOption(option); + } + + self &operator<<(SqlOption &&option) + { + return setSqlOption(option); + } + template self &operator<<(const std::optional ¶meter) { @@ -590,6 +645,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable std::vector parameters_; std::vector lengths_; std::vector formats_; + ResultFormat resultFormat_{ResultFormat::Text}; std::vector> objs_; Mode mode_{Mode::NonBlocking}; std::shared_ptr callbackHolder_; @@ -598,6 +654,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable bool execed_{false}; bool destructed_{false}; bool isExceptionPtr_{false}; + bool usePreparedStmt_{true}; ClientType type_; }; diff --git a/orm_lib/src/DbClientImpl.cc b/orm_lib/src/DbClientImpl.cc index 730c7c75fc..07551d85eb 100644 --- a/orm_lib/src/DbClientImpl.cc +++ b/orm_lib/src/DbClientImpl.cc @@ -123,8 +123,10 @@ void DbClientImpl::execSql( std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&exceptCallback) + std::function &&exceptCallback, + bool usePreparedStmt) { assert(paraNum == parameters.size()); assert(paraNum == length.size()); @@ -138,8 +140,10 @@ void DbClientImpl::execSql( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); return; } DbConnectionPtr conn; @@ -147,7 +151,7 @@ void DbClientImpl::execSql( { std::lock_guard guard(connectionsMutex_); - if (readyConnections_.size() == 0) + if (readyConnections_.empty()) { if (sqlCmdBuffer_.size() > 200000) { @@ -163,8 +167,10 @@ void DbClientImpl::execSql( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); sqlCmdBuffer_.push_back(std::move(cmd)); } } @@ -183,8 +189,10 @@ void DbClientImpl::execSql( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); return; } if (busy) @@ -368,8 +376,10 @@ void DbClientImpl::handleNewTask(const DbConnectionPtr &connPtr) std::move(cmd->parameters_), std::move(cmd->lengths_), std::move(cmd->formats_), + cmd->resultFormat_, std::move(cmd->callback_), - std::move(cmd->exceptionCallback_)); + std::move(cmd->exceptionCallback_), + cmd->usePreparedStmt_); return; } } @@ -487,8 +497,10 @@ void DbClientImpl::execSqlWithTimeout( std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&ecb) + std::function &&ecb, + bool usePreparedStmt) { DbConnectionPtr conn; assert(timeout_ > 0.0); @@ -536,7 +548,7 @@ void DbClientImpl::execSqlWithTimeout( { std::lock_guard guard(connectionsMutex_); - if (readyConnections_.size() == 0) + if (readyConnections_.empty()) { if (sqlCmdBuffer_.size() > 200000) { @@ -552,8 +564,10 @@ void DbClientImpl::execSqlWithTimeout( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(resultCallback), - std::move(exceptionCallback)); + std::move(exceptionCallback), + usePreparedStmt); sqlCmdBuffer_.emplace_back(command); *cmd = command; } @@ -573,8 +587,10 @@ void DbClientImpl::execSqlWithTimeout( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(resultCallback), - std::move(exceptionCallback)); + std::move(exceptionCallback), + usePreparedStmt); timeoutFlagPtr->runTimer(); return; } diff --git a/orm_lib/src/DbClientImpl.h b/orm_lib/src/DbClientImpl.h index 09ad0c994d..9cbf29e1c3 100644 --- a/orm_lib/src/DbClientImpl.h +++ b/orm_lib/src/DbClientImpl.h @@ -41,15 +41,17 @@ class DbClientImpl : public DbClient, ClientType type); #endif ~DbClientImpl() noexcept override; - void execSql(const char *sql, - size_t sqlLength, - size_t paraNum, - std::vector &¶meters, - std::vector &&length, - std::vector &&format, - ResultCallback &&rcb, - std::function - &&exceptCallback) override; + void execSql( + const char *sql, + size_t sqlLength, + size_t paraNum, + std::vector &¶meters, + std::vector &&length, + std::vector &&format, + int resultFormat, + ResultCallback &&rcb, + std::function &&exceptCallback, + bool usePreparedStmt) override; std::shared_ptr newTransaction( const std::function &commitCallback = std::function()) noexcept(false) override; @@ -99,8 +101,10 @@ class DbClientImpl : public DbClient, std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&exceptCallback); + std::function &&exceptCallback, + bool usePreparedStmt); }; } // namespace orm diff --git a/orm_lib/src/DbClientLockFree.cc b/orm_lib/src/DbClientLockFree.cc index de0d248462..626409ce28 100644 --- a/orm_lib/src/DbClientLockFree.cc +++ b/orm_lib/src/DbClientLockFree.cc @@ -93,8 +93,10 @@ void DbClientLockFree::execSql( std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&exceptCallback) + std::function &&exceptCallback, + bool usePreparedStmt) { assert(paraNum == parameters.size()); assert(paraNum == length.size()); @@ -109,8 +111,10 @@ void DbClientLockFree::execSql( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); return; } if (!connections_.empty() && sqlCmdBuffer_.empty() && @@ -128,6 +132,7 @@ void DbClientLockFree::execSql( std::move(parameters), std::move(length), std::move(format), + resultFormat, [rcb = std::move(rcb), this](const Result &r) { if (sqlCmdBuffer_.empty()) { @@ -139,7 +144,8 @@ void DbClientLockFree::execSql( [rcb = std::move(rcb), r]() { rcb(r); }); } }, - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); return; } } @@ -158,6 +164,7 @@ void DbClientLockFree::execSql( std::move(parameters), std::move(length), std::move(format), + resultFormat, [rcb = std::move(rcb), this](const Result &r) { if (sqlCmdBuffer_.empty()) { @@ -169,7 +176,8 @@ void DbClientLockFree::execSql( [rcb = std::move(rcb), r]() { rcb(r); }); } }, - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); return; } } @@ -190,8 +198,10 @@ void DbClientLockFree::execSql( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); return; } } @@ -210,12 +220,13 @@ void DbClientLockFree::execSql( } // LOG_TRACE << "Push query to buffer"; - sqlCmdBuffer_.emplace_back(std::make_shared( + auto cmdPtr = std::make_shared( std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), std::move(format), + resultFormat, [rcb = std::move(rcb), this](const Result &r) { if (sqlCmdBuffer_.empty()) { @@ -226,7 +237,9 @@ void DbClientLockFree::execSql( loop_->queueInLoop([rcb = std::move(rcb), r]() { rcb(r); }); } }, - std::move(exceptCallback))); + std::move(exceptCallback), + usePreparedStmt); + sqlCmdBuffer_.emplace_back(std::move(cmdPtr)); } std::shared_ptr DbClientLockFree::newTransaction( @@ -378,8 +391,10 @@ void DbClientLockFree::handleNewTask(const DbConnectionPtr &conn) std::move(cmd->parameters_), std::move(cmd->lengths_), std::move(cmd->formats_), + cmd->resultFormat_, std::move(cmd->callback_), - std::move(cmd->exceptionCallback_)); + std::move(cmd->exceptionCallback_), + cmd->usePreparedStmt_); } else { @@ -396,8 +411,10 @@ void DbClientLockFree::handleNewTask(const DbConnectionPtr &conn) std::move(cmd->parameters_), std::move(cmd->lengths_), std::move(cmd->formats_), + cmd->resultFormat_, std::move(cmd->callback_), - std::move(cmd->exceptionCallback_)); + std::move(cmd->exceptionCallback_), + cmd->usePreparedStmt_); #endif return; } @@ -501,8 +518,10 @@ void DbClientLockFree::execSqlWithTimeout( std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&ecb) + std::function &&ecb, + bool usePreparedStmt) { auto commandPtr = std::make_shared>(); auto ecpPtr = @@ -557,6 +576,7 @@ void DbClientLockFree::execSqlWithTimeout( std::move(parameters), std::move(length), std::move(format), + resultFormat, [resultCallback = std::move(resultCallback), this](const Result &r) { if (sqlCmdBuffer_.empty()) @@ -570,7 +590,8 @@ void DbClientLockFree::execSqlWithTimeout( r]() { resultCallback(r); }); } }, - std::move(exceptionCallback)); + std::move(exceptionCallback), + usePreparedStmt); timeoutFlagPtr->runTimer(); return; } @@ -590,6 +611,7 @@ void DbClientLockFree::execSqlWithTimeout( std::move(parameters), std::move(length), std::move(format), + resultFormat, [resultCallback = std::move(resultCallback), this](const Result &r) { if (sqlCmdBuffer_.empty()) @@ -603,7 +625,8 @@ void DbClientLockFree::execSqlWithTimeout( r]() { resultCallback(r); }); } }, - std::move(exceptionCallback)); + std::move(exceptionCallback), + usePreparedStmt); timeoutFlagPtr->runTimer(); return; } @@ -625,8 +648,10 @@ void DbClientLockFree::execSqlWithTimeout( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(resultCallback), - std::move(exceptionCallback)); + std::move(exceptionCallback), + usePreparedStmt); timeoutFlagPtr->runTimer(); return; } @@ -651,6 +676,7 @@ void DbClientLockFree::execSqlWithTimeout( std::move(parameters), std::move(length), std::move(format), + resultFormat, [resultCallback = std::move(resultCallback), this](const Result &r) { if (sqlCmdBuffer_.empty()) { @@ -662,7 +688,8 @@ void DbClientLockFree::execSqlWithTimeout( r]() { resultCallback(r); }); } }, - std::move(exceptionCallback)); + std::move(exceptionCallback), + usePreparedStmt); sqlCmdBuffer_.emplace_back(cmdPtr); *commandPtr = cmdPtr; timeoutFlagPtr->runTimer(); diff --git a/orm_lib/src/DbClientLockFree.h b/orm_lib/src/DbClientLockFree.h index 1e2e4d715c..897f6b639d 100644 --- a/orm_lib/src/DbClientLockFree.h +++ b/orm_lib/src/DbClientLockFree.h @@ -44,15 +44,17 @@ class DbClientLockFree : public DbClient, #endif ~DbClientLockFree() noexcept override; - void execSql(const char *sql, - size_t sqlLength, - size_t paraNum, - std::vector &¶meters, - std::vector &&length, - std::vector &&format, - ResultCallback &&rcb, - std::function - &&exceptCallback) override; + void execSql( + const char *sql, + size_t sqlLength, + size_t paraNum, + std::vector &¶meters, + std::vector &&length, + std::vector &&format, + int resultFormat, + ResultCallback &&rcb, + std::function &&exceptCallback, + bool usePreparedStmt) override; std::shared_ptr newTransaction( const std::function &commitCallback = std::function()) noexcept(false) override; @@ -94,8 +96,10 @@ class DbClientLockFree : public DbClient, std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&ecb); + std::function &&ecb, + bool usePreparedStmt); void handleNewTask(const DbConnectionPtr &conn); #if LIBPQ_SUPPORTS_BATCH_MODE size_t connectionPos_{0}; // Used for pg batch mode. diff --git a/orm_lib/src/DbConnection.h b/orm_lib/src/DbConnection.h index c49838a2a0..5f3fcd19dc 100644 --- a/orm_lib/src/DbConnection.h +++ b/orm_lib/src/DbConnection.h @@ -52,8 +52,10 @@ struct SqlCmd std::vector parameters_; std::vector lengths_; std::vector formats_; + int resultFormat_{0}; QueryCallback callback_; ExceptPtrCallback exceptionCallback_; + bool usePreparedStmt_{true}; std::string preparingStatement_; #if LIBPQ_SUPPORTS_BATCH_MODE bool isChanging_{false}; @@ -63,15 +65,19 @@ struct SqlCmd std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, QueryCallback &&cb, - ExceptPtrCallback &&exceptCb) + ExceptPtrCallback &&exceptCb, + bool usePreparedStmt = true) : sql_(std::move(sql)), parametersNumber_(paraNum), parameters_(std::move(parameters)), lengths_(std::move(length)), formats_(std::move(format)), + resultFormat_(resultFormat), callback_(std::move(cb)), - exceptionCallback_(std::move(exceptCb)) + exceptionCallback_(std::move(exceptCb)), + usePreparedStmt_(usePreparedStmt) { } }; @@ -111,8 +117,31 @@ class DbConnection : public trantor::NonCopyable std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&exceptCallback) = 0; + std::function &&exceptCallback, + bool usePreparedStmt) = 0; + + void execSql( + std::string_view &&sql, + size_t paraNum, + std::vector &¶meters, + std::vector &&length, + std::vector &&format, + ResultCallback &&rcb, + std::function &&exceptCallback) + { + execSql(std::move(sql), + paraNum, + std::move(parameters), + std::move(length), + std::move(format), + 0, + std::move(rcb), + std::move(exceptCallback), + true); + } + virtual void batchSql( std::deque> &&sqlCommands) = 0; diff --git a/orm_lib/src/SqlBinder.cc b/orm_lib/src/SqlBinder.cc index b93a2bd716..f629352b87 100644 --- a/orm_lib/src/SqlBinder.cc +++ b/orm_lib/src/SqlBinder.cc @@ -39,6 +39,7 @@ void SqlBinder::exec() std::move(parameters_), std::move(lengths_), std::move(formats_), + (int)resultFormat_, [holder = std::move(callbackHolder_), objs = std::move(objs_), sqlptr = std::move(sqlPtr_)](const Result &r) mutable { @@ -72,7 +73,8 @@ void SqlBinder::exec() if (exceptPtrCb) exceptPtrCb(exception); } - }); + }, + usePreparedStmt_); } else { @@ -87,6 +89,7 @@ void SqlBinder::exec() std::move(parameters_), std::move(lengths_), std::move(formats_), + (int)resultFormat_, [pro](const Result &r) { pro->set_value(r); }, [pro](const std::exception_ptr &exception) { try @@ -97,7 +100,8 @@ void SqlBinder::exec() { assert(0); } - }); + }, + usePreparedStmt_); try { diff --git a/orm_lib/src/TransactionImpl.cc b/orm_lib/src/TransactionImpl.cc index 0f55142400..c98e4c930c 100644 --- a/orm_lib/src/TransactionImpl.cc +++ b/orm_lib/src/TransactionImpl.cc @@ -52,6 +52,7 @@ TransactionImpl::~TransactionImpl() {}, {}, {}, + 0, [commitCb](const Result &) { LOG_TRACE << "Transaction committed!"; if (commitCb) @@ -73,7 +74,8 @@ TransactionImpl::~TransactionImpl() commitCb(false); } } - }); + }, + true); }); } else @@ -91,8 +93,10 @@ void TransactionImpl::execSqlInLoop( std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&exceptCallback) + std::function &&exceptCallback, + bool usePreparedStmt) { loop_->assertInLoopThread(); if (!isCommitedOrRolledback_) @@ -104,8 +108,10 @@ void TransactionImpl::execSqlInLoop( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); return; } auto thisPtr = shared_from_this(); @@ -113,18 +119,20 @@ void TransactionImpl::execSqlInLoop( { isWorking_ = true; thisPtr_ = thisPtr; - connectionPtr_->execSql(std::move(sql), - paraNum, - std::move(parameters), - std::move(length), - std::move(format), - std::move(rcb), - [exceptCallback, - thisPtr](const std::exception_ptr &ePtr) { - thisPtr->rollback(); - if (exceptCallback) - exceptCallback(ePtr); - }); + connectionPtr_->execSql( + std::move(sql), + paraNum, + std::move(parameters), + std::move(length), + std::move(format), + resultFormat, + std::move(rcb), + [exceptCallback, thisPtr](const std::exception_ptr &ePtr) { + thisPtr->rollback(); + if (exceptCallback) + exceptCallback(ePtr); + }, + usePreparedStmt); } else { @@ -135,8 +143,10 @@ void TransactionImpl::execSqlInLoop( cmdPtr->parameters_ = std::move(parameters); cmdPtr->lengths_ = std::move(length); cmdPtr->formats_ = std::move(format); + cmdPtr->resultFormat_ = resultFormat; cmdPtr->callback_ = std::move(rcb); cmdPtr->exceptionCallback_ = std::move(exceptCallback); + cmdPtr->usePreparedStmt_ = usePreparedStmt; cmdPtr->thisPtr_ = thisPtr; thisPtr->sqlCmdBuffer_.push_back(std::move(cmdPtr)); } @@ -186,6 +196,7 @@ void TransactionImpl::rollback() {}, {}, {}, + 0, [thisPtr](const Result &) { LOG_TRACE << "Transaction roll back!"; thisPtr->isCommitedOrRolledback_ = true; @@ -195,7 +206,8 @@ void TransactionImpl::rollback() // clearupCb(); LOG_ERROR << "Transaction roll back error"; thisPtr->isCommitedOrRolledback_ = true; - }); + }, + true); }); } @@ -218,6 +230,7 @@ void TransactionImpl::execNewTask() std::move(cmd->parameters_), std::move(cmd->lengths_), std::move(cmd->formats_), + cmd->resultFormat_, [callback = std::move(cmd->callback_), cmd, thisPtr]( const Result &r) { if (cmd->isRollbackCmd_) @@ -236,7 +249,8 @@ void TransactionImpl::execNewTask() } if (cmd->exceptionCallback_) cmd->exceptionCallback_(ePtr); - }); + }, + cmd->usePreparedStmt_); return; } isWorking_ = false; @@ -285,11 +299,13 @@ void TransactionImpl::doBegin() {}, {}, {}, + 0, [](const Result &) { LOG_TRACE << "Transaction begin!"; }, [thisPtr](const std::exception_ptr &) { LOG_ERROR << "Error occurred in transaction begin"; thisPtr->isCommitedOrRolledback_ = true; - }); + }, + true); }); } @@ -299,8 +315,10 @@ void TransactionImpl::execSqlInLoopWithTimeout( std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&ecb) + std::function &&ecb, + bool usePreparedStmt) { auto thisPtr = shared_from_this(); std::weak_ptr weakPtr = thisPtr; @@ -346,22 +364,24 @@ void TransactionImpl::execSqlInLoopWithTimeout( { isWorking_ = true; thisPtr_ = thisPtr; - connectionPtr_->execSql(std::move(sql), - paraNum, - std::move(parameters), - std::move(length), - std::move(format), - std::move(resultCallback), - [ecpPtr, timeoutFlagPtr, thisPtr]( - const std::exception_ptr &ePtr) { - thisPtr->rollback(); - if (timeoutFlagPtr->done()) - return; - if (*ecpPtr) - { - (*ecpPtr)(ePtr); - } - }); + connectionPtr_->execSql( + std::move(sql), + paraNum, + std::move(parameters), + std::move(length), + std::move(format), + resultFormat, + std::move(resultCallback), + [ecpPtr, timeoutFlagPtr, thisPtr](const std::exception_ptr &ePtr) { + thisPtr->rollback(); + if (timeoutFlagPtr->done()) + return; + if (*ecpPtr) + { + (*ecpPtr)(ePtr); + } + }, + usePreparedStmt); } else { @@ -372,6 +392,7 @@ void TransactionImpl::execSqlInLoopWithTimeout( cmdPtr->parameters_ = std::move(parameters); cmdPtr->lengths_ = std::move(length); cmdPtr->formats_ = std::move(format); + cmdPtr->resultFormat_ = resultFormat; cmdPtr->callback_ = std::move(resultCallback); cmdPtr->exceptionCallback_ = [ecpPtr, timeoutFlagPtr](const std::exception_ptr &ePtr) { @@ -382,7 +403,7 @@ void TransactionImpl::execSqlInLoopWithTimeout( (*ecpPtr)(ePtr); } }; - + cmdPtr->usePreparedStmt_ = usePreparedStmt; cmdPtr->thisPtr_ = thisPtr; thisPtr->sqlCmdBuffer_.push_back(cmdPtr); *commandPtr = cmdPtr; diff --git a/orm_lib/src/TransactionImpl.h b/orm_lib/src/TransactionImpl.h index 0be310f5c0..6bdaefedd3 100644 --- a/orm_lib/src/TransactionImpl.h +++ b/orm_lib/src/TransactionImpl.h @@ -53,15 +53,17 @@ class TransactionImpl : public Transaction, private: DbConnectionPtr connectionPtr_; - void execSql(const char *sql, - size_t sqlLength, - size_t paraNum, - std::vector &¶meters, - std::vector &&length, - std::vector &&format, - ResultCallback &&rcb, - std::function - &&exceptCallback) override + void execSql( + const char *sql, + size_t sqlLength, + size_t paraNum, + std::vector &¶meters, + std::vector &&length, + std::vector &&format, + int resultFormat, + ResultCallback &&rcb, + std::function &&exceptCallback, + bool usePreparedStmt) override { if (loop_->isInLoopThread()) { @@ -70,8 +72,10 @@ class TransactionImpl : public Transaction, std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); } else { @@ -82,6 +86,8 @@ class TransactionImpl : public Transaction, parameters = std::move(parameters), length = std::move(length), format = std::move(format), + resultFormat, + usePreparedStmt, rcb = std::move(rcb), exceptCallback = std::move(exceptCallback)]() mutable { thisPtr->execSqlInLoop(std::move(sql), @@ -89,8 +95,10 @@ class TransactionImpl : public Transaction, std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + usePreparedStmt); }); } } @@ -101,16 +109,20 @@ class TransactionImpl : public Transaction, std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&exceptCallback); + std::function &&exceptCallback, + bool usePreparedStmt); void execSqlInLoopWithTimeout( std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, std::vector &&format, + int resultFormat, ResultCallback &&rcb, - std::function &&exceptCallback); + std::function &&exceptCallback, + bool usePreparedStmt); std::shared_ptr newTransaction( const std::function &) noexcept(false) override @@ -133,13 +145,15 @@ class TransactionImpl : public Transaction, struct SqlCmd { std::string_view sql_; - size_t parametersNumber_; + size_t parametersNumber_{0}; std::vector parameters_; std::vector lengths_; std::vector formats_; + int resultFormat_{0}; QueryCallback callback_; ExceptPtrCallback exceptionCallback_; bool isRollbackCmd_{false}; + bool usePreparedStmt_{true}; std::shared_ptr thisPtr_; }; diff --git a/orm_lib/src/mysql_impl/MysqlConnection.h b/orm_lib/src/mysql_impl/MysqlConnection.h index 4ec0c618a8..51ba5a504f 100644 --- a/orm_lib/src/mysql_impl/MysqlConnection.h +++ b/orm_lib/src/mysql_impl/MysqlConnection.h @@ -44,14 +44,16 @@ class MysqlConnection : public DbConnection, { } - void execSql(std::string_view &&sql, - size_t paraNum, - std::vector &¶meters, - std::vector &&length, - std::vector &&format, - ResultCallback &&rcb, - std::function - &&exceptCallback) override + void execSql( + std::string_view &&sql, + size_t paraNum, + std::vector &¶meters, + std::vector &&length, + std::vector &&format, + int /* resultFormat */, + ResultCallback &&rcb, + std::function &&exceptCallback, + bool /* usePreparedStmt */) override { if (loop_->isInLoopThread()) { diff --git a/orm_lib/src/postgresql_impl/PgBatchConnection.cc b/orm_lib/src/postgresql_impl/PgBatchConnection.cc index 631ef6907c..e200293120 100644 --- a/orm_lib/src/postgresql_impl/PgBatchConnection.cc +++ b/orm_lib/src/postgresql_impl/PgBatchConnection.cc @@ -230,7 +230,9 @@ void PgConnection::execSqlInLoop( std::vector &&length, std::vector &&format, ResultCallback &&rcb, - std::function &&exceptCallback) + std::function &&exceptCallback, + int resultFormat, + bool /* usePreparedStmt not supported in batch mode yet */) { LOG_TRACE << sql; isWorking_ = true; @@ -240,6 +242,7 @@ void PgConnection::execSqlInLoop( std::move(parameters), std::move(length), std::move(format), + resultFormat, std::move(rcb), std::move(exceptCallback))); if (batchSqlCommands_.size() == 1 && !channel_.isWriting()) @@ -349,7 +352,7 @@ void PgConnection::sendBatchedSql() cmd->parameters_.data(), cmd->lengths_.data(), cmd->formats_.data(), - 0) == 0) + cmd->resultFormat_) == 0) { isWorking_ = false; handleFatalError(true); diff --git a/orm_lib/src/postgresql_impl/PgConnection.cc b/orm_lib/src/postgresql_impl/PgConnection.cc index 59d080cc71..305a7413ba 100644 --- a/orm_lib/src/postgresql_impl/PgConnection.cc +++ b/orm_lib/src/postgresql_impl/PgConnection.cc @@ -203,7 +203,9 @@ void PgConnection::execSqlInLoop( std::vector &&length, std::vector &&format, ResultCallback &&rcb, - std::function &&exceptCallback) + std::function &&exceptCallback, + int resultFormat, + bool usePreparedStmt) { LOG_TRACE << sql; loop_->assertInLoopThread(); @@ -220,7 +222,14 @@ void PgConnection::execSqlInLoop( if (paraNum == 0) { isPreparingStatement_ = false; - if (PQsendQuery(connectionPtr_.get(), sql_.data()) == 0) + if (PQsendQueryParams(connectionPtr_.get(), + sql_.data(), + 0, + nullptr, + nullptr, + nullptr, + nullptr, + resultFormat) == 0) { LOG_ERROR << "send query error: " << PQerrorMessage(connectionPtr_.get()); @@ -236,7 +245,7 @@ void PgConnection::execSqlInLoop( } flush(); } - else + else if (usePreparedStmt) { auto iter = preparedStatementsMap_.find(sql_); if (iter != preparedStatementsMap_.end()) @@ -248,7 +257,7 @@ void PgConnection::execSqlInLoop( parameters.data(), length.data(), format.data(), - 0) == 0) + resultFormat) == 0) { LOG_ERROR << "send query error: " << PQerrorMessage(connectionPtr_.get()); @@ -288,6 +297,31 @@ void PgConnection::execSqlInLoop( parameters_ = std::move(parameters); lengths_ = std::move(length); formats_ = std::move(format); + resultFormat_ = resultFormat; + } + flush(); + } + else + { + if (PQsendQueryParams(connectionPtr_.get(), + sql_.data(), + static_cast(paraNum), + nullptr, + parameters.data(), + length.data(), + format.data(), + resultFormat) == 0) + { + LOG_ERROR << "send query error: " + << PQerrorMessage(connectionPtr_.get()); + if (isWorking_) + { + isWorking_ = false; + handleFatalError(); + callback_ = nullptr; + idleCb_(); + } + return; } flush(); } @@ -380,7 +414,7 @@ void PgConnection::doAfterPreparing() parameters_.data(), lengths_.data(), formats_.data(), - 0) == 0) + resultFormat_) == 0) { LOG_ERROR << "send query error: " << PQerrorMessage(connectionPtr_.get()); diff --git a/orm_lib/src/postgresql_impl/PgConnection.h b/orm_lib/src/postgresql_impl/PgConnection.h index b962ec297e..b15960275a 100644 --- a/orm_lib/src/postgresql_impl/PgConnection.h +++ b/orm_lib/src/postgresql_impl/PgConnection.h @@ -47,14 +47,16 @@ class PgConnection : public DbConnection, void init() override; - void execSql(std::string_view &&sql, - size_t paraNum, - std::vector &¶meters, - std::vector &&length, - std::vector &&format, - ResultCallback &&rcb, - std::function - &&exceptCallback) override + void execSql( + std::string_view &&sql, + size_t paraNum, + std::vector &¶meters, + std::vector &&length, + std::vector &&format, + int resultFormat, + ResultCallback &&rcb, + std::function &&exceptCallback, + bool usePreparedStmt) override { if (loop_->isInLoopThread()) { @@ -64,28 +66,33 @@ class PgConnection : public DbConnection, std::move(length), std::move(format), std::move(rcb), - std::move(exceptCallback)); + std::move(exceptCallback), + resultFormat, + usePreparedStmt); } else { auto thisPtr = shared_from_this(); - loop_->queueInLoop( - [thisPtr, - sql = std::move(sql), - paraNum, - parameters = std::move(parameters), - length = std::move(length), - format = std::move(format), - rcb = std::move(rcb), - exceptCallback = std::move(exceptCallback)]() mutable { - thisPtr->execSqlInLoop(std::move(sql), - paraNum, - std::move(parameters), - std::move(length), - std::move(format), - std::move(rcb), - std::move(exceptCallback)); - }); + loop_->queueInLoop([thisPtr, + sql = std::move(sql), + paraNum, + parameters = std::move(parameters), + length = std::move(length), + format = std::move(format), + rcb = std::move(rcb), + exceptCallback = std::move(exceptCallback), + resultFormat, + usePreparedStmt]() mutable { + thisPtr->execSqlInLoop(std::move(sql), + paraNum, + std::move(parameters), + std::move(length), + std::move(format), + std::move(rcb), + std::move(exceptCallback), + resultFormat, + usePreparedStmt); + }); } } @@ -126,13 +133,16 @@ class PgConnection : public DbConnection, std::vector &&length, std::vector &&format, ResultCallback &&rcb, - std::function &&exceptCallback); + std::function &&exceptCallback, + int resultFormat = 0, + bool usePreparedStmt = true); void doAfterPreparing(); std::string statementName_; int parametersNumber_{0}; std::vector parameters_; std::vector lengths_; std::vector formats_; + int resultFormat_{0}; int flush(); void handleFatalError(); std::set preparedStatements_; diff --git a/orm_lib/src/sqlite3_impl/Sqlite3Connection.cc b/orm_lib/src/sqlite3_impl/Sqlite3Connection.cc index 8ad70c7474..1cf410b503 100644 --- a/orm_lib/src/sqlite3_impl/Sqlite3Connection.cc +++ b/orm_lib/src/sqlite3_impl/Sqlite3Connection.cc @@ -96,8 +96,10 @@ void Sqlite3Connection::execSql( std::vector &¶meters, std::vector &&length, std::vector &&format, + int /* resultFormat */, ResultCallback &&rcb, - std::function &&exceptCallback) + std::function &&exceptCallback, + bool /* usePreparedStmt */) { auto thisPtr = shared_from_this(); loopThread_.getLoop()->queueInLoop( diff --git a/orm_lib/src/sqlite3_impl/Sqlite3Connection.h b/orm_lib/src/sqlite3_impl/Sqlite3Connection.h index 8f3ed834af..a6177580d4 100644 --- a/orm_lib/src/sqlite3_impl/Sqlite3Connection.h +++ b/orm_lib/src/sqlite3_impl/Sqlite3Connection.h @@ -46,14 +46,16 @@ class Sqlite3Connection : public DbConnection, void init() override; - void execSql(std::string_view &&sql, - size_t paraNum, - std::vector &¶meters, - std::vector &&length, - std::vector &&format, - ResultCallback &&rcb, - std::function - &&exceptCallback) override; + void execSql( + std::string_view &&sql, + size_t paraNum, + std::vector &¶meters, + std::vector &&length, + std::vector &&format, + int /* resultFormat */, + ResultCallback &&rcb, + std::function &&exceptCallback, + bool /* usePreparedStmt */) override; void batchSql(std::deque> &&) override { diff --git a/orm_lib/tests/db_test.cc b/orm_lib/tests/db_test.cc index 086a8cca25..579c08448f 100644 --- a/orm_lib/tests/db_test.cc +++ b/orm_lib/tests/db_test.cc @@ -379,7 +379,45 @@ DROGON_TEST(PostgreTest) "postgresql1", "pg", "postgresql"); - /// 2.6 clean up + + /// 2.6. Test pg options with plain sql + clientPtr->execSqlAsync( + "select 12345::int", + [TEST_CTX](const Result &r) { + MANDATE(r[0][0].length() == sizeof(int)); + int i = *(int *)r[0][0].c_str(); + MANDATE(ntohl(i) == 12345); + SUCCESS(); + }, + [TEST_CTX](const DrogonDbException &e) { + FAULT( + "postgresql - DbClient pg special options" + "what():" + + std::string(e.base().what())); + }, + ResultFormat::Binary, + SqlOption::DisablePreparedStmt); + + /// 2.7. Test pg options + clientPtr->execSqlAsync( + "select $1::int", + [TEST_CTX](const Result &r) { + MANDATE(r[0][0].length() == sizeof(int)); + int i = *(int *)r[0][0].c_str(); + MANDATE(ntohl(i) == 12345); + SUCCESS(); + }, + [TEST_CTX](const DrogonDbException &e) { + FAULT( + "postgresql - DbClient pg special options" + "what():" + + std::string(e.base().what())); + }, + 12345, + ResultFormat::Binary, + SqlOption::DisablePreparedStmt); + + /// 2.8 clean up clientPtr->execSqlAsync( "truncate table users restart identity", [TEST_CTX](const Result &r) { SUCCESS(); }, @@ -464,7 +502,27 @@ DROGON_TEST(PostgreTest) { SUCCESS(); } - /// 3.6 clean up + + /// 3.6. Test pg options + try + { + auto r = clientPtr->execSqlSync("select $1::int", + 12345, + ResultFormat::Binary, + SqlOption::DisablePreparedStmt); + MANDATE(r[0][0].length() == sizeof(int)); + int i = *(int *)r[0][0].c_str(); + MANDATE(ntohl(i) == 12345); + } + catch (const DrogonDbException &e) + { + FAULT( + "postgresql - DbClient pg special options" + "what():" + + std::string(e.base().what())); + } + + /// 3.7 clean up try { auto r = @@ -557,7 +615,28 @@ DROGON_TEST(PostgreTest) { SUCCESS(); } - /// 4.6 clean up + + /// 4.6. Test pg options + f = clientPtr->execSqlAsyncFuture("select $1::int", + 12345, + ResultFormat::Binary, + SqlOption::DisablePreparedStmt); + try + { + auto r = f.get(); + MANDATE(r[0][0].length() == sizeof(int)); + int i = *(int *)r[0][0].c_str(); + MANDATE(ntohl(i) == 12345); + } + catch (const DrogonDbException &e) + { + FAULT( + "postgresql - DbClient pg special options" + "what():" + + std::string(e.base().what())); + } + + /// 4.7 clean up f = clientPtr->execSqlAsyncFuture("truncate table users restart identity"); try {