/** * * SqlBinder.cc * An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon * Use of this source code is governed by a MIT license * that can be found in the License file. * * Drogon * */ #include #include #include #include #include #include #if USE_MYSQL #include #endif using namespace drogon::orm; using namespace drogon::orm::internal; void SqlBinder::exec() { execed_ = true; if (mode_ == Mode::NonBlocking) { // nonblocking mode,default mode // Retain shared_ptrs of parameters until we get the result; client_.execSql( sqlViewPtr_, sqlViewLength_, parametersNumber_, std::move(parameters_), std::move(lengths_), std::move(formats_), [holder = std::move(callbackHolder_), objs = std::move(objs_), sqlptr = std::move(sqlPtr_)](const Result &r) mutable { objs.clear(); if (holder) { holder->execCallback(r); } }, [exceptCb = std::move(exceptionCallback_), exceptPtrCb = std::move(exceptionPtrCallback_), isExceptPtr = isExceptionPtr_](const std::exception_ptr &exception) { // LOG_DEBUG<<"exp callback "<> pro(new std::promise); auto f = pro->get_future(); client_.execSql( sqlViewPtr_, sqlViewLength_, parametersNumber_, std::move(parameters_), std::move(lengths_), std::move(formats_), [pro](const Result &r) { pro->set_value(r); }, [pro](const std::exception_ptr &exception) { try { pro->set_exception(exception); } catch (...) { assert(0); } }); try { const Result &v = f.get(); if (callbackHolder_) { callbackHolder_->execCallback(v); } } catch (const DrogonDbException &exception) { if (!destructed_) { // throw exception std::rethrow_exception(std::current_exception()); } else { if (exceptionCallback_) { exceptionCallback_(exception); } } } } } SqlBinder::~SqlBinder() { destructed_ = true; if (!execed_) { exec(); } } SqlBinder &SqlBinder::operator<<(const std::string_view &str) { auto obj = std::make_shared(str.data(), str.length()); parameters_.push_back(obj->data()); lengths_.push_back(static_cast(obj->length())); objs_.push_back(obj); ++parametersNumber_; if (type_ == ClientType::PostgreSQL) { formats_.push_back(0); } else if (type_ == ClientType::Mysql) { formats_.push_back(MySqlString); } else if (type_ == ClientType::Sqlite3) { formats_.push_back(Sqlite3TypeText); } return *this; } SqlBinder &SqlBinder::operator<<(const std::string &str) { auto obj = std::make_shared(str); objs_.push_back(obj); ++parametersNumber_; parameters_.push_back(obj->data()); lengths_.push_back(static_cast(obj->length())); if (type_ == ClientType::PostgreSQL) { formats_.push_back(0); } else if (type_ == ClientType::Mysql) { formats_.push_back(MySqlString); } else if (type_ == ClientType::Sqlite3) { formats_.push_back(Sqlite3TypeText); } return *this; } SqlBinder &SqlBinder::operator<<(std::string &&str) { std::shared_ptr obj = std::make_shared(std::move(str)); objs_.push_back(obj); ++parametersNumber_; parameters_.push_back((char *)obj->c_str()); lengths_.push_back(static_cast(obj->length())); if (type_ == ClientType::PostgreSQL) { formats_.push_back(0); } else if (type_ == ClientType::Mysql) { formats_.push_back(MySqlString); } else if (type_ == ClientType::Sqlite3) { formats_.push_back(Sqlite3TypeText); } return *this; } SqlBinder &SqlBinder::operator<<(const std::vector &v) { std::shared_ptr> obj = std::make_shared>(v); objs_.push_back(obj); ++parametersNumber_; parameters_.push_back((char *)obj->data()); lengths_.push_back(static_cast(obj->size())); if (type_ == ClientType::PostgreSQL) { formats_.push_back(1); } else if (type_ == ClientType::Mysql) { formats_.push_back(MySqlString); } else if (type_ == ClientType::Sqlite3) { formats_.push_back(Sqlite3TypeBlob); } return *this; } SqlBinder &SqlBinder::operator<<(std::vector &&v) { std::shared_ptr> obj = std::make_shared>(std::move(v)); objs_.push_back(obj); ++parametersNumber_; parameters_.push_back((char *)obj->data()); lengths_.push_back(static_cast(obj->size())); if (type_ == ClientType::PostgreSQL) { formats_.push_back(1); } else if (type_ == ClientType::Mysql) { formats_.push_back(MySqlString); } else if (type_ == ClientType::Sqlite3) { formats_.push_back(Sqlite3TypeBlob); } return *this; } SqlBinder &SqlBinder::operator<<(double f) { if (type_ == ClientType::Sqlite3) { ++parametersNumber_; auto obj = std::make_shared(f); objs_.push_back(obj); formats_.push_back(Sqlite3TypeDouble); lengths_.push_back(0); parameters_.push_back((char *)(obj.get())); return *this; } return operator<<(std::to_string(f)); } SqlBinder &SqlBinder::operator<<(std::nullptr_t) { ++parametersNumber_; parameters_.push_back(nullptr); lengths_.push_back(0); if (type_ == ClientType::PostgreSQL) { formats_.push_back(0); } else if (type_ == ClientType::Mysql) { formats_.push_back(MySqlNull); } else if (type_ == ClientType::Sqlite3) { formats_.push_back(Sqlite3TypeNull); } return *this; } SqlBinder &SqlBinder::operator<<(DefaultValue dv) { (void)dv; if (type_ == ClientType::PostgreSQL) { std::regex r("\\$" + std::to_string(parametersNumber_ + 1) + "\\b"); // initialize with empty, as the next line will make a copy anyway if (!sqlPtr_) sqlPtr_ = std::make_shared(); *sqlPtr_ = std::regex_replace(sqlViewPtr_, r, "default"); // decrement all other $n parameters by 1 size_t i = parametersNumber_ + 2; while ((sqlPtr_->find("$" + std::to_string(i))) != std::string::npos) { r = "\\$" + std::to_string(i) + "\\b"; // use sed format to avoid $n regex group substitution, // and use ->data() to compile in C++14 mode *sqlPtr_ = std::regex_replace(sqlPtr_->data(), r, "$" + std::to_string(i - 1), std::regex_constants::format_sed); ++i; } sqlViewPtr_ = sqlPtr_->data(); sqlViewLength_ = sqlPtr_->length(); } else if (type_ == ClientType::Mysql) { ++parametersNumber_; parameters_.push_back(nullptr); lengths_.push_back(0); formats_.push_back(DrogonDefaultValue); } else if (type_ == ClientType::Sqlite3) { LOG_FATAL << "default not supported in sqlite3"; exit(1); } return *this; } int SqlBinder::getMysqlTypeBySize(size_t size) { #if USE_MYSQL switch (size) { case 1: return MySqlTiny; break; case 2: return MySqlShort; break; case 4: return MySqlLong; break; case 8: return MySqlLongLong; break; default: return 0; } #else static_cast(size); LOG_FATAL << "Mysql is not supported!"; exit(1); #endif }