├── xorm ├── xorm.hpp ├── dbconfig.hpp ├── db_utils.hpp ├── simple_pool.hpp ├── meta_utility.hpp ├── data_type.hpp ├── dao.hpp ├── mysqlc++14.hpp ├── sqlite3.hpp ├── reflect │ └── reflector.hpp └── mysql.hpp ├── .gitignore ├── CMakeLists.txt ├── README.md └── main.cpp /xorm/xorm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dao.hpp" 3 | #ifdef _ENABLE_XORM_ 4 | #ifdef XORM_ENABLE_MYSQL 5 | #include "mysql.hpp" 6 | #endif // ENABLE_MYSQL 7 | #ifdef XORM_ENABLE_SQLITE 8 | #include "sqlite3.hpp" 9 | #endif // ENABLE_MYSQL 10 | #endif // _ENABLE_XORM_ 11 | -------------------------------------------------------------------------------- /xorm/dbconfig.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | struct dataBaseConfig { 4 | std::string index_key; 5 | std::string host; 6 | std::string user; 7 | std::string password; 8 | std::string dbname; 9 | std::string character_encoding; 10 | unsigned int port = 3306; 11 | std::size_t reconnect_number = 1; 12 | int timeout = -1; 13 | std::size_t conn_number; 14 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | build 11 | lbuild 12 | # Precompiled Headers 13 | *.gch 14 | *.pch 15 | 16 | # Compiled Dynamic libraries 17 | *.so 18 | *.dylib 19 | *.dll 20 | 21 | # Fortran module files 22 | *.mod 23 | *.smod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app -------------------------------------------------------------------------------- /xorm/db_utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | namespace xorm { 5 | class db_error final { 6 | friend class mysql; 7 | friend class sqlite; 8 | public: 9 | db_error() = default; 10 | public: 11 | operator bool() { 12 | return is_error_; 13 | } 14 | std::string message() { 15 | return message_; 16 | } 17 | private: 18 | bool is_error_ = false; 19 | std::string message_; 20 | }; 21 | 22 | template 23 | struct db_result { //for query 24 | db_error error{}; 25 | bool success = false; 26 | std::vector results; 27 | }; 28 | 29 | template<> 30 | struct db_result { //for insert, del, update, execute 31 | db_error error{}; 32 | bool success = false; 33 | std::uint64_t affect_rows = 0; 34 | std::uint64_t unique_id = 0; 35 | }; 36 | } -------------------------------------------------------------------------------- /xorm/simple_pool.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | template 7 | class simple_pool 8 | { 9 | using element_type = std::shared_ptr; 10 | public: 11 | simple_pool() = default; 12 | simple_pool(std::size_t size):pool_(size){ 13 | pool_.reserve(size); 14 | } 15 | public: 16 | void expand(std::size_t size) { 17 | pool_.resize(size); 18 | } 19 | public: 20 | template 21 | void init_pool(Function&& function) { 22 | for (auto& iter : pool_) { 23 | function(iter); 24 | } 25 | } 26 | public: 27 | element_type takeout() { 28 | std::unique_lock lock(mutex_); 29 | cdvar_.wait(lock, [this]() { 30 | return !pool_.empty(); 31 | }); 32 | auto data = pool_.back(); 33 | pool_.pop_back(); 34 | return data; 35 | } 36 | void revert(std::weak_ptr eleref) { 37 | std::unique_lock lock(mutex_); 38 | pool_.push_back(eleref.lock()); 39 | cdvar_.notify_all(); 40 | } 41 | private: 42 | std::vector pool_; 43 | std::mutex mutex_; 44 | std::condition_variable cdvar_; 45 | }; -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | set(project_name xorm) 3 | project(${project_name}) 4 | SET(ENABLE_XORM ON) 5 | SET(ENABLE_MYSQL ON) 6 | SET(ENABLE_SQLITE OFF) 7 | SET(ENABLE_SQLITE_CODEC OFF) 8 | if (MSVC) 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest") 10 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 11 | else () 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++11") 13 | endif () 14 | 15 | set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) 16 | set(CMAKE_INSTALL_RPATH "/usr/local/lib:") 17 | if(ENABLE_XORM) 18 | add_definitions(-D_ENABLE_XORM_) 19 | if(ENABLE_MYSQL) 20 | add_definitions(-DXORM_ENABLE_MYSQL) 21 | endif() 22 | if(ENABLE_SQLITE) 23 | add_definitions(-DXORM_ENABLE_SQLITE) 24 | if(ENABLE_SQLITE_CODEC) 25 | add_definitions(-DSQLITE_HAS_CODEC) 26 | endif() 27 | endif() 28 | endif() 29 | 30 | 31 | set(SOURCE_FILES main.cpp) 32 | include_directories(${CMAKE_SOURCE_DIR}/xorm) 33 | 34 | add_executable(${project_name} ${SOURCE_FILES}) 35 | 36 | if(ENABLE_XORM) 37 | if(ENABLE_MYSQL) 38 | if(MSVC) 39 | target_link_libraries(${project_name} libmysql) 40 | else() 41 | target_link_libraries(${project_name} mysqlclient) 42 | endif() 43 | endif() 44 | if(ENABLE_SQLITE) 45 | target_link_libraries(${project_name} sqlite3) 46 | endif() 47 | endif() 48 | 49 | install(TARGETS ${project_name} DESTINATION include) 50 | -------------------------------------------------------------------------------- /xorm/meta_utility.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | namespace xorm { 4 | template 5 | struct is_tuple_type:std::false_type { 6 | 7 | }; 8 | template 9 | struct is_tuple_type> :std::true_type { 10 | 11 | }; 12 | //template 13 | //constexpr bool is_tuple_type_v = is_tuple_type::value; 14 | 15 | template 16 | struct each_tuple { 17 | template 18 | static void each(Tuple&& tp, CallBack&& callback) { 19 | callback(std::get(tp)); 20 | each_tuple::template each(std::forward(tp), std::forward(callback)); 21 | } 22 | 23 | template 24 | static void each2(Tuple&& tp, Tuple2&& copytp, CallBack&& callback) { 25 | callback(std::get(tp),std::get(copytp)); 26 | each_tuple::template each2(std::forward(tp), std::forward(copytp),std::forward(callback)); 27 | } 28 | }; 29 | 30 | template 31 | struct each_tuple { 32 | template 33 | static void each(Tuple&& tp, CallBack&& callback) { 34 | 35 | } 36 | 37 | template 38 | static void each2(Tuple&& tp, Tuple2&& copytp, CallBack&& callback) { 39 | 40 | } 41 | }; 42 | 43 | namespace xorm_utils { 44 | 45 | template 46 | struct index_package { 47 | 48 | }; 49 | 50 | template 51 | struct index_package { 52 | using type = typename index_package::type; 53 | }; 54 | 55 | template 56 | struct index_package<0, Index...> { 57 | using type = index_package; 58 | }; 59 | 60 | template 61 | using make_index_package = typename index_package::type; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /xorm/data_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #ifdef _WIN32 4 | #include 5 | #else 6 | #include 7 | #endif // __LINUX__ 8 | #include 9 | #include 10 | #include 11 | namespace xorm { 12 | template 13 | class FundamentionType final { 14 | friend std::ostream& operator <<(std::ostream& out, FundamentionType const& v) { 15 | if (v.is_null()) { 16 | out << "NULL"; 17 | } 18 | else { 19 | out << v.value(); 20 | } 21 | return out; 22 | } 23 | public: 24 | using value_type = Type; 25 | public: 26 | FundamentionType() :data_(0), is_null_(true) { 27 | 28 | } 29 | FundamentionType(Type v) :data_(v), is_null_(false) { 30 | 31 | } 32 | FundamentionType& operator=(Type v) { 33 | data_ = v; 34 | is_null_ = false; 35 | return *this; 36 | } 37 | bool is_null() const { 38 | return is_null_; 39 | } 40 | char* null_buffer() { 41 | return &is_null_; 42 | } 43 | char* buffer() { 44 | return (char*)(&data_); 45 | } 46 | void clear() { 47 | data_ = 0; 48 | is_null_ = true; 49 | } 50 | Type value() const { 51 | return data_; 52 | } 53 | public: 54 | static const enum_field_types field_type = FieldType; 55 | private: 56 | Type data_; 57 | char is_null_; 58 | }; 59 | 60 | template 61 | struct is_fundamention_type :std::false_type { 62 | 63 | }; 64 | 65 | template 66 | struct is_fundamention_type> :std::true_type { 67 | 68 | }; 69 | 70 | template 71 | class TimeDate { 72 | friend std::ostream& operator <<(std::ostream& out, TimeDate const& v) { 73 | if (v.is_null()) { 74 | out << "NULL"; 75 | } 76 | else { 77 | out << v.value(); 78 | } 79 | return out; 80 | } 81 | public: 82 | using value_type = MYSQL_TIME; 83 | public: 84 | static const enum_field_types field_type = FieldType; 85 | public: 86 | TimeDate() :is_null_(true) { 87 | 88 | } 89 | TimeDate(std::string const& date) :is_null_(false) { 90 | decode_time(date); 91 | } 92 | TimeDate& operator=(std::string const& date) { 93 | decode_time(date); 94 | return *this; 95 | } 96 | void clear() { 97 | data_.day = 0; 98 | data_.hour = 0; 99 | data_.minute = 0; 100 | data_.month = 0; 101 | data_.second = 0; 102 | data_.second_part = 0; 103 | data_.year = 0; 104 | data_.neg = 0; 105 | is_null_ = true; 106 | } 107 | bool is_null() const { 108 | return is_null_; 109 | } 110 | char* null_buffer() { 111 | return &is_null_; 112 | } 113 | char* buffer() { 114 | return (char*)(&data_); 115 | } 116 | std::string value() const { 117 | return encode_time(); 118 | } 119 | void format_timestamp(std::time_t timestamp) { 120 | struct tm* ttime = localtime(×tamp); 121 | auto year = ttime->tm_year + 1900; 122 | auto month = ttime->tm_mon + 1; 123 | auto day = ttime->tm_mday; 124 | auto hour = ttime->tm_hour; 125 | auto minute = ttime->tm_min; 126 | auto second = ttime->tm_sec; 127 | if (FieldType == MYSQL_TYPE_DATETIME) { 128 | data_.year = year; 129 | data_.month = month; 130 | data_.day = day; 131 | data_.hour = hour; 132 | data_.minute = minute; 133 | data_.second = second; 134 | data_.second_part = 0; 135 | } 136 | else if (FieldType == MYSQL_TYPE_DATE) { 137 | data_.year = year; 138 | data_.month = month; 139 | data_.day = day; 140 | data_.hour = 0; 141 | data_.minute = 0; 142 | data_.second = 0; 143 | data_.second_part = 0; 144 | } 145 | else if (FieldType == MYSQL_TYPE_TIME) { 146 | data_.year = 0; 147 | data_.month = 0; 148 | data_.day = 0; 149 | data_.hour = hour; 150 | data_.minute = minute; 151 | data_.second = second; 152 | data_.second_part = 0; 153 | data_.neg = 0; 154 | } 155 | is_null_ = false; 156 | } 157 | private: 158 | void decode_time(std::string const& date) { 159 | char const* cptr = date.data(); 160 | if (FieldType == MYSQL_TYPE_DATETIME) { 161 | data_.year = atoi(cptr); 162 | data_.month = atoi(cptr + 5); 163 | data_.day = atoi(cptr + 8); 164 | data_.hour = atoi(cptr + 11); 165 | data_.minute = atoi(cptr + 14); 166 | data_.second = atoi(cptr + 17); 167 | data_.second_part = 0; 168 | } 169 | else if (FieldType == MYSQL_TYPE_DATE) { 170 | data_.year = atoi(cptr); 171 | data_.month = atoi(cptr + 5); 172 | data_.day = atoi(cptr + 8); 173 | data_.hour = 0; 174 | data_.minute = 0; 175 | data_.second = 0; 176 | data_.second_part = 0; 177 | } 178 | else if (FieldType == MYSQL_TYPE_TIME) { 179 | data_.year = 0; 180 | data_.month = 0; 181 | data_.day = 0; 182 | data_.hour = atoi(cptr); 183 | data_.minute = atoi(cptr + 3); 184 | data_.second = atoi(cptr + 6); 185 | data_.second_part = 0; 186 | data_.neg = 0; 187 | } 188 | is_null_ = false; 189 | } 190 | std::string encode_time() const { 191 | std::stringstream ss; 192 | if (FieldType == MYSQL_TYPE_DATETIME) { 193 | ss << data_.year << "-" << fix_number(data_.month) << "-" << fix_number(data_.day) << " " << fix_number(data_.hour) << ":" << fix_number(data_.minute) << ":" << fix_number(data_.second); //<< "." << data_.second_part 194 | } 195 | else if (FieldType == MYSQL_TYPE_DATE) { 196 | ss << data_.year << "-" << fix_number(data_.month) << "-" << fix_number(data_.day); 197 | } 198 | else if (FieldType == MYSQL_TYPE_TIME) { 199 | ss << fix_number(data_.hour) << ":" << fix_number(data_.minute) << ":" << fix_number(data_.second); //<< "." << data_.second_part 200 | } 201 | return ss.str(); 202 | } 203 | std::string fix_number(int v) const { 204 | std::stringstream ss; 205 | if (v < 10) { 206 | ss << "0" << v; 207 | } 208 | else { 209 | ss << v; 210 | } 211 | return ss.str(); 212 | } 213 | private: 214 | char is_null_; 215 | MYSQL_TIME data_; 216 | }; 217 | 218 | template 219 | struct is_date_type :std::false_type { 220 | 221 | }; 222 | 223 | template 224 | struct is_date_type> :std::true_type { 225 | 226 | }; 227 | } 228 | -------------------------------------------------------------------------------- /xorm/dao.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "simple_pool.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "reflect/reflector.hpp" 10 | #include "db_utils.hpp" 11 | #include "dbconfig.hpp" 12 | namespace xorm { 13 | 14 | class dao_message { 15 | public: 16 | static dao_message& get() { 17 | static dao_message instance; 18 | return instance; 19 | } 20 | private: 21 | dao_message() { 22 | error_callback_ = [](std::string const& message) { 23 | std::cout << message << std::endl; 24 | }; 25 | } 26 | public: 27 | void set_error_callback(std::function const& callback) { 28 | if (callback != nullptr) { 29 | error_callback_ = callback; 30 | } 31 | } 32 | void trigger_error(std::string const& message) { 33 | if (error_callback_ != nullptr) { 34 | error_callback_(message); 35 | } 36 | } 37 | private: 38 | std::function error_callback_; 39 | }; 40 | 41 | struct pool_impl { 42 | pool_impl() = default; 43 | virtual ~pool_impl(){} 44 | }; 45 | 46 | template 47 | struct Pool:pool_impl { 48 | Pool(std::size_t size, dataBaseConfig const& config):pool_(size){ 49 | pool_.init_pool([&config](std::shared_ptr& iter) { 50 | iter = std::make_shared(config, [](std::string const& message) { 51 | dao_message::get().trigger_error(message); 52 | }); 53 | }); 54 | } 55 | simple_pool pool_; 56 | }; 57 | 58 | 59 | struct data_base { 60 | std::shared_ptr config_ = nullptr; 61 | std::shared_ptr pool_ = nullptr; 62 | }; 63 | 64 | inline std::unordered_map>& get_database_configs() { 65 | static std::unordered_map> instance_; 66 | return instance_; 67 | } 68 | 69 | template 70 | class dao_t final{ 71 | public: 72 | static void init_conn_pool(dataBaseConfig const& config) { 73 | auto data_base_ptr = std::shared_ptr(new data_base{}); 74 | data_base_ptr->config_ = std::make_shared(config); 75 | auto pool = std::shared_ptr>{ new Pool{data_base_ptr->config_->conn_number,*(data_base_ptr->config_)} }; 76 | data_base_ptr->pool_ = pool; 77 | auto&& configs_map = get_database_configs(); 78 | configs_map.insert(std::make_pair(config.index_key, data_base_ptr)); 79 | } 80 | 81 | static std::shared_ptr get_data_base(std::string const& indexKey) { 82 | auto&& configs_map = get_database_configs(); 83 | auto iter = configs_map.find(indexKey); 84 | if (iter != configs_map.end()) { 85 | return iter->second; 86 | } 87 | return nullptr; 88 | } 89 | 90 | public: 91 | dao_t(std::string const& indexKey){ 92 | std::shared_ptr data_base_ptr = get_data_base(indexKey); 93 | if (data_base_ptr != nullptr) { 94 | data_base_ = data_base_ptr; 95 | auto current_pool = std::dynamic_pointer_cast>(data_base_ptr->pool_); 96 | if (current_pool != nullptr) { 97 | conn_ = current_pool->pool_.takeout(); 98 | if (!conn_->ping()) { 99 | conn_->reconnect(*(data_base_ptr->config_)); 100 | } 101 | } 102 | else { 103 | conn_ = nullptr; 104 | } 105 | } 106 | else { 107 | conn_ = nullptr; 108 | } 109 | 110 | } 111 | dao_t(dao_t const&) = delete; 112 | dao_t& operator=(dao_t const&) = delete; 113 | public: 114 | /*return type 115 | first:effective row number 116 | second: insert data's id(key) 117 | */ 118 | template 119 | db_result insert(T&& t) { 120 | if (conn_ ==nullptr || !conn_->is_connect()) { 121 | return {}; 122 | } 123 | return conn_->insert(std::forward(t)); 124 | } 125 | template 126 | db_result del(std::string const& condition,U&&...args) { 127 | if (conn_ == nullptr || !conn_->is_connect()) { 128 | return {}; 129 | } 130 | return conn_->template del(condition,std::forward(args)...); 131 | } 132 | 133 | template::type>::value>::type> 134 | db_result update(T&& v) { 135 | if (conn_ == nullptr || !conn_->is_connect()) { 136 | return {}; 137 | } 138 | return conn_->update(std::forward(v)); 139 | } 140 | 141 | template 142 | db_result update(std::string const& condition,T&&...args) { 143 | if (conn_ == nullptr || !conn_->is_connect()) { 144 | return {}; 145 | } 146 | return conn_->update(condition,std::forward(args)...); 147 | } 148 | 149 | //template 150 | //std::pair> query(std::string const& condition = "") { 151 | // if (!conn_->is_connect()) { 152 | // return { false,{} }; 153 | // } 154 | // return conn_->template query(condition); 155 | //} 156 | 157 | template 158 | db_result query(std::string const& condition, Params&&...params) { 159 | if (conn_ == nullptr || !conn_->is_connect()) { 160 | return {}; 161 | } 162 | return conn_->template query(condition,std::forward(params)...); 163 | } 164 | 165 | db_result begin() { 166 | if (conn_ == nullptr) { 167 | return {}; 168 | } 169 | return conn_->begin(); 170 | } 171 | 172 | db_result commit() { 173 | if (conn_ == nullptr) { 174 | start_transaction_ = false; 175 | return {}; 176 | } 177 | auto r = conn_->commit(); 178 | start_transaction_ = !r.success; 179 | return r; 180 | } 181 | 182 | db_result rollback() { 183 | start_transaction_ = false; 184 | if (conn_ == nullptr) { 185 | return {}; 186 | } 187 | return conn_->rollback(); 188 | } 189 | 190 | db_result execute(std::string const& sql) { 191 | if (conn_ == nullptr) { 192 | return {}; 193 | } 194 | return conn_->execute(sql); 195 | } 196 | 197 | template 198 | db_result execute(std::string const& sql,std::function const& callback) { 199 | if (conn_ == nullptr) { 200 | return {}; 201 | } 202 | return conn_->execute(sql, callback); 203 | } 204 | 205 | std::uint64_t get_affected_rows() { 206 | if (conn_ == nullptr) { 207 | return 0; 208 | } 209 | return conn_->get_affected_rows(); 210 | } 211 | 212 | void start_transaction() { 213 | begin(); 214 | start_transaction_ = true; 215 | } 216 | 217 | bool is_open() { 218 | if (conn_ == nullptr) { 219 | return false; 220 | } 221 | return conn_->is_connect(); 222 | } 223 | std::shared_ptr const& get_connection() { 224 | return conn_; 225 | } 226 | public: 227 | ~dao_t() { 228 | if (start_transaction_) { 229 | commit(); 230 | } 231 | auto data_base_ptr = data_base_.lock(); 232 | if (data_base_ptr != nullptr) { 233 | auto current_pool = std::dynamic_pointer_cast>(data_base_ptr->pool_); 234 | if (current_pool != nullptr) { 235 | current_pool->pool_.revert(conn_); 236 | } 237 | } 238 | } 239 | private: 240 | std::weak_ptr data_base_; 241 | std::shared_ptr conn_ = nullptr; 242 | bool start_transaction_ = false; 243 | }; 244 | } 245 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xorm 2 | 基于c++11 标准的orm 3 | 4 | ## 特性 5 | 1. 使用简单 6 | 2. stmt全面支持,防止注入 7 | 3. head only,方便用于其他项目 8 | 4. 支持mysql,sqlite3 9 | 10 | ## RoadMap 11 | 1. 增加postgre等数据库支持 12 | 13 | # 目录 14 | * [xorm配置](#初始化配置) 15 | * [新增](#新增数据) 16 | * [删除](#删除数据) 17 | * [修改](#修改) 18 | * [查询](#查询) 19 | * [原生执行](#execute方法) 20 | * [开启事务](#开启事务) 21 | * [日志监听](#日志监听) 22 | 23 | # 初始化配置 24 | >在使用之前需要进行数据库配置,通过init_database_config方法注册配置,配置参数如下: 25 | * host 用来指定连接的地址 26 | * user 数据库用户名 27 | * password 数据库密码 28 | * dbname 数据库名 29 | * conn_number 连接池数量 30 | ##### 非必填参数 31 | * character_encoding 数据库编码方式 32 | * port 数据库端口号 33 | * reconnect_number 尝试重连次数 34 | * timeout 超时时间 35 | ```` 36 | #include 37 | #include "mysql.hpp" 38 | #include "dao.hpp" 39 | using namespace xorm; 40 | 41 | int main(){ 42 | dataBaseConfig config; 43 | config.character_encoding = "utf8"; 44 | config.conn_number = 2; 45 | config.dbname = "xorm"; 46 | config.host = "127.0.0.1"; 47 | config.password = "root"; 48 | config.user = "root"; 49 | init_database_config(config); //全局初始化配置 50 | } 51 | ```` 52 | # 新增数据 53 | >通过dao_t::insert 进行数据的添加 54 | ##### db_result insert(T&& t) 55 | * 参数: 通过REFLECTION注册过的表结构对象 56 | * 返回数据: success: SQL语句无错误返回true , affect_rows: 影响行数, unique_id: 唯一ID, error: 是否有错误(error.message取出错误详情) 57 | 58 | ```` 59 | #include 60 | #include "mysql.hpp" 61 | #include "dao.hpp" 62 | using namespace xorm; 63 | struct test { 64 | mysql::Integer id; 65 | mysql::Integer a; 66 | std::string b; 67 | mysql::MysqlDateTime time; 68 | mysql::MysqlDate date; 69 | mysql::MysqlTime tm; 70 | mysql::Double money; 71 | }; 72 | REFLECTION(test, id, a, b, time, date, tm, money) 73 | int main(){ 74 | dao_t dao; 75 | test data; 76 | data.id = 0; 77 | data.a = i; 78 | data.b = "t0 你好" + std::to_string(i); 79 | data.time.format_timestamp(std::time(nullptr)); 80 | data.date = "2019-10-09"; 81 | data.tm.format_timestamp(std::time(nullptr)); 82 | data.money = 12.03; 83 | auto pr = dao.insert(data); 84 | if (pr.success == true && pr.affect_rows > 0) 85 | { 86 | std::cout << "insert row " << pr.affect_rows << " insert id " << pr.unique_id << std::endl; 87 | } 88 | else { 89 | std::cout << "error " << pr.error << " message " << pr.error.message() << std::endl; 90 | } 91 | } 92 | ```` 93 | 94 | # 删除数据 95 | >通过dao_t::del 进行数据的删减 96 | ##### db_result del(std::string const& condition,...) 97 | * 参数1: 删除条件,可以为空字符串 98 | > "where id=?" 99 | * 后续参数: 条件中的值 100 | > mysql::Integer{10} 101 | * 返回数据: success: SQL语句无错误返回true , affect_rows: 影响行数, unique_id: 唯一ID, error: 是否有错误(error.message取出错误详情) 102 | 103 | ```` 104 | #include 105 | #include "mysql.hpp" 106 | #include "dao.hpp" 107 | using namespace xorm; 108 | struct test { 109 | mysql::Integer id; 110 | mysql::Integer a; 111 | std::string b; 112 | mysql::MysqlDateTime time; 113 | mysql::MysqlDate date; 114 | mysql::MysqlTime tm; 115 | mysql::Double money; 116 | }; 117 | REFLECTION(test, id, a, b, time, date, tm, money) 118 | int main(){ 119 | dao_t dao; 120 | bool r = dao.del("where id = ?",mysql::Integer{10}); 121 | } 122 | ```` 123 | 124 | # 修改数据 125 | >支持两种方式 126 | ###### db_result update(T&& v) 127 | * 参数: 数据表结构对象 128 | * 返回数据: success: SQL语句无错误返回true , affect_rows: 影响行数, unique_id: 唯一ID, error: 是否有错误(error.message取出错误详情) 129 | 130 | 131 | ###### db_result update(std::string const& condition,...) 132 | * 参数: update语句 133 | >"update test set a=? where id=?" 134 | * 后续参数: 条件中的值 135 | >如 mysql::Integer{10} 136 | * 返回数据: success: SQL语句无错误返回true , affect_rows: 影响行数, unique_id: 唯一ID, error: 是否有错误(error.message取出错误详情) 137 | 138 | ```` 139 | #include 140 | #include "mysql.hpp" 141 | #include "dao.hpp" 142 | using namespace xorm; 143 | struct test { 144 | mysql::Integer id; 145 | mysql::Integer a; 146 | std::string b; 147 | mysql::MysqlDateTime time; 148 | mysql::MysqlDate date; 149 | mysql::MysqlTime tm; 150 | mysql::Double money; 151 | }; 152 | REFLECTION(test, id, a, b, time, date, tm, money) 153 | int main(){ 154 | test data; 155 | data.id = 1; 156 | data.a = 1024; 157 | dao_t dao; 158 | bool r = t.update(data); 159 | bool r1 = t.update("update test set a=? where id=?",mysql::Integer{10},mysql::Integer{1}); 160 | } 161 | ```` 162 | 163 | # 查询数据 164 | ###### db_result query(std::string const& condition, ...) 165 | * 模板参数: 数据表结构类型 166 | * 参数: 查询条件 (可以为空字符串) 167 | >"where id=?" 168 | * 后续参数: 条件中的值 169 | >如 mysql::Integer{1} 170 | * 返回数据: success: SQL语句无错误返回true , results: 返回数据结果vector , error: 是否有错误(error.message取出错误详情) 171 | 172 | ###### 使用方式二 173 | * 模板参数: 自定义std::tuple\ 如 std::tuple\ 代表查询的数据集的field类型 174 | * 参数: 完整的查询语句 175 | >"where id=?" 176 | * 后续参数: 条件中的值 177 | >如 mysql::Integer{1} 178 | * 返回数据: success: SQL语句无错误返回true , results: 返回数据结果vector , error: 是否有错误(error.message取出错误详情) 179 | 180 | ```` 181 | #include 182 | #include "mysql.hpp" 183 | #include "dao.hpp" 184 | using namespace xorm; 185 | struct test { 186 | mysql::Integer id; 187 | mysql::Integer a; 188 | std::string b; 189 | mysql::MysqlDateTime time; 190 | mysql::MysqlDate date; 191 | mysql::MysqlTime tm; 192 | mysql::Double money; 193 | }; 194 | REFLECTION(test, id, a, b, time, date, tm, money) 195 | int main(){ 196 | dao_t dao; 197 | auto r = dao.query("where id=?",mysql::Integer{1}); 198 | auto r0 = dao.query>("select a,b from test where id=?",mysql::Integer{1}); 199 | } 200 | ```` 201 | # execute方法 202 | >支持原生数据库的命令执行 203 | ##### db_result execute(std::string const& sql) 204 | * 参数: 完整的sql语句 205 | * 返回数据: success: SQL语句无错误返回true , affect_rows: 影响行数, unique_id: 唯一ID, error: 是否有错误(error.message取出错误详情) 206 | 207 | ##### db_result execute(std::string const& sql,...) 208 | * 参数: 完整的sql语句 209 | >如果执行的sql语句可以返回结果集合 210 | * 参数2: 执行结果集的回调方法,回调参数为数据结果集的指针(可能是nullptr) 211 | * 返回数据: success: SQL语句无错误返回true , affect_rows: 影响行数, unique_id: 唯一ID, error: 是否有错误(error.message取出错误详情) 212 | 213 | ````cpp 214 | #include 215 | #include "mysql.hpp" 216 | #include "dao.hpp" 217 | using namespace xorm; 218 | int main(){ 219 | dao_t dao; 220 | auto r = dao.execute("commit"); 221 | std::function get_reuslt = [](MYSQL_RES*){} 222 | auto r1 = dao.execute("select * from test",get_reuslt); 223 | } 224 | ```` 225 | # 开启事务 226 | >提供了两种开启事务的方式 227 | * 自动事务开启 228 | ###### start_transaction() 229 | >在声明的dao_t对象声明周期结束后会自动提交当前事务 230 | * 手动事务开启 231 | ###### begin() 232 | ###### rollback() 233 | ###### commit() 234 | ````cpp 235 | #include 236 | #include "mysql.hpp" 237 | #include "dao.hpp" 238 | using namespace xorm; 239 | int main(){ 240 | { 241 | dao_t dao; 242 | dao.start_transaction(); 243 | ////// 244 | } 245 | dao_t dao; 246 | dao.begin(); 247 | ///balabala 248 | if(///balabala){ 249 | dao.rollback(); 250 | } 251 | dao.commit(); 252 | } 253 | ```` 254 | # 日志监听 255 | #### 可以通过设置回调方法获取数据库操作日志 256 | >如语句执行错误等 257 | ````cpp 258 | #include 259 | #include "mysql.hpp" 260 | #include "dao.hpp" 261 | using namespace xorm; 262 | int main(){ 263 | dao_message::get().set_error_callback([](std::string const& msg) { 264 | std::cout << msg << "\n"; 265 | }); 266 | } 267 | ```` 268 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace xorm; 4 | #include 5 | #include 6 | #ifdef XORM_ENABLE_MYSQL 7 | struct test { 8 | mysql::Integer id; 9 | mysql::Integer a; 10 | std::string b; 11 | mysql::MysqlDateTime time; 12 | mysql::MysqlDate date; 13 | mysql::MysqlTime tm; 14 | mysql::Double money; 15 | std::string d; 16 | mysql::Blob binary1; 17 | mysql::Blob binary2; 18 | }; 19 | REFLECTION(test, id, a, b, time, date, tm, money, d, binary1, binary2) 20 | 21 | struct default_tb { 22 | mysql::Integer id; 23 | std::string text; 24 | }; 25 | REFLECTION(default_tb,id,text) 26 | #endif 27 | 28 | 29 | #ifdef XORM_ENABLE_SQLITE 30 | struct test1 { 31 | sqlite::Integer a; 32 | sqlite::Double b; 33 | sqlite::Integer id; 34 | std::string text; 35 | sqlite::Blob binary; 36 | }; 37 | REFLECTION(test1,a,b,id, text, binary) 38 | #endif 39 | 40 | int main() { 41 | #ifdef XORM_ENABLE_MYSQL 42 | dataBaseConfig config; 43 | config.index_key = "xorm"; 44 | config.character_encoding = "utf8"; 45 | config.conn_number = 2; 46 | config.dbname = "xorm"; 47 | config.host = "127.0.0.1"; 48 | config.password = "root"; 49 | config.user = "root"; 50 | dao_t::init_conn_pool(config); 51 | 52 | 53 | 54 | dataBaseConfig config2; 55 | config2.index_key = "xorm2"; 56 | config2.character_encoding = "utf8"; 57 | config2.conn_number = 4; 58 | config2.dbname = "xorm2"; 59 | config2.host = "127.0.0.1"; 60 | config2.password = "root"; 61 | config2.user = "root"; 62 | dao_t::init_conn_pool(config2); 63 | 64 | dao_message::get().set_error_callback([](std::string const& msg) { 65 | std::cout << msg << "\n"; 66 | }); 67 | 68 | //auto t0 = std::thread([]() { 69 | // for (auto i = 0; i < 5; i++) { 70 | // dao_t dao{"xorm"}; 71 | // dao.start_transaction(); 72 | // test data; 73 | // data.id = 0; 74 | // data.a = i; 75 | // data.b = "t0 中国好" + std::to_string(i); 76 | // data.time.format_timestamp(std::time(nullptr)); 77 | // data.date = "2019-10-09"; 78 | // data.tm.format_timestamp(std::time(nullptr)); 79 | // data.money = 12.03; 80 | // dao.insert(data); 81 | // std::this_thread::sleep_for(std::chrono::milliseconds(800)); 82 | // } 83 | // }); 84 | //auto t1 = std::thread([]() { 85 | // dao_t t{ "xorm" }; 86 | // t.start_transaction(); 87 | // for (auto i = 0; i < 5; i++) { 88 | // test data; 89 | // data.id = 0; 90 | // data.a = i; 91 | // data.b = "t1 中国好" + std::to_string(i); 92 | // data.time.format_timestamp(std::time(nullptr)); 93 | // data.date = "2019-10-09"; 94 | // data.tm.format_timestamp(std::time(nullptr)); 95 | // t.insert(data); 96 | // std::this_thread::sleep_for(std::chrono::milliseconds(802)); 97 | // } 98 | // }); 99 | //auto t2 = std::thread([]() { 100 | // dao_t t{ "xorm" }; 101 | // t.start_transaction(); 102 | // for (auto i = 0; i < 5; i++) { 103 | // test data; 104 | // data.id = 0; 105 | // data.a = i; 106 | // data.b = "t2 中国好" + std::to_string(i); 107 | // data.time.format_timestamp(std::time(nullptr)); 108 | // data.date = "2019-10-09"; 109 | // data.tm.format_timestamp(std::time(nullptr)); 110 | // t.insert(data); 111 | // std::this_thread::sleep_for(std::chrono::milliseconds(803)); 112 | // } 113 | // }); 114 | //auto t3 = std::thread([]() { 115 | // dao_t t{ "xorm" }; 116 | // t.start_transaction(); 117 | // for (auto i = 0; i < 5; i++) { 118 | // test data; 119 | // data.id = 0; 120 | // data.a = i; 121 | // data.b = "t3 中国好" + std::to_string(i); 122 | // data.time.format_timestamp(std::time(nullptr)); 123 | // data.date = "2019-10-09"; 124 | // data.tm.format_timestamp(std::time(nullptr)); 125 | // t.insert(data); 126 | // std::this_thread::sleep_for(std::chrono::milliseconds(804)); 127 | // } 128 | // }); 129 | //{ 130 | // dao_t dao_query{ "xorm" }; 131 | // dao_query.start_transaction(); 132 | // auto r = dao_query.query(" for update"); 133 | // std::cout << r.success << " " << r.results.size() << std::endl; 134 | // if (!r.results.empty()) { 135 | // auto& info = r.results[0]; 136 | // auto rr = dao_query.update(info); 137 | // std::cout << rr.affect_rows << std::endl; 138 | // } 139 | //} 140 | //t0.join(); 141 | //t1.join(); 142 | //t2.join(); 143 | //t3.join(); 144 | 145 | //dao_t dao_query{ "xorm" }; 146 | //auto r0 = dao_query.update("update test set a=? where a=?", mysql::Integer{ 2048 }, mysql::Integer{ 0 }); 147 | //auto r1 = dao_query.del("where id=?", mysql::Integer{1}); 148 | //auto r2 = dao_query.query(" where id=?", mysql::Integer{ 2 }); 149 | //if (!r2.results.empty()) { 150 | // auto& info = r2.results[0]; 151 | // info.a = 6666; 152 | // auto r5 = dao_query.update(info); 153 | //} 154 | //auto r3 = dao_query.query(""); 155 | //auto r4 = dao_query.query>("select a from test where id=?", mysql::Integer{ 2 }); 156 | //auto rrr = dao_query.del(""); 157 | 158 | //dao_t dao_query; 159 | //auto r = dao_query.query>("select id, b,d from test"); 160 | //int c = 0; 161 | 162 | //auto r0 = dao_query.query(""); 163 | //int d = 0; 164 | 165 | //dao_t dao_query2{ "xorm2" }; 166 | //auto xorm2r = dao_query2.query(" where id=?", mysql::Integer{ 1 }); 167 | //dao_query2.get_connection()->get_raw_connetion(); 168 | 169 | dao_t dao{ "xorm" }; 170 | test tb_info; 171 | tb_info.id = 0; 172 | tb_info.a = 0; 173 | //tb_info.b = "hello"; 174 | tb_info.time.format_timestamp( std::time(nullptr)); 175 | tb_info.date.format_timestamp(std::time(nullptr)); 176 | tb_info.tm.format_timestamp(std::time(nullptr)); 177 | tb_info.money = 100.05; 178 | tb_info.d = "world"; 179 | std::ifstream file1("./time.jpg", std::ios::binary); 180 | std::stringstream ss1; 181 | ss1 << file1.rdbuf(); 182 | auto content0 = ss1.str(); 183 | 184 | std::ifstream file2("./time2.jpg", std::ios::binary); 185 | std::stringstream ss2; 186 | ss2 << file2.rdbuf(); 187 | auto content2 = ss2.str(); 188 | 189 | tb_info.binary1 = mysql::Blob(content0.begin(), content0.end()); 190 | //tb_info.binary2 = mysql::Blob(content2.begin(), content2.end()); 191 | 192 | auto r10 = dao.insert(tb_info); 193 | tb_info.id = r10.unique_id; 194 | auto r11 = dao.query(""); 195 | 196 | //if (!r11.results.empty()) { 197 | // auto&& data = r11.results[0]; 198 | // std::ofstream out0("./record0.jpg",std::ios::binary); 199 | // out0.write(data.binary1.data(), data.binary1.size()); 200 | 201 | // std::ofstream out1("./record1.jpg", std::ios::binary); 202 | // out1.write(data.binary2.data(), data.binary2.size()); 203 | //} 204 | 205 | //auto r12 = dao.query>("select binary1 from test"); 206 | //tb_info.binary2 = tb_info.binary1; 207 | //auto r13 = dao.update(tb_info); 208 | auto r14 = dao.del(""); 209 | 210 | #endif 211 | 212 | #ifdef XORM_ENABLE_SQLITE 213 | dataBaseConfig config; 214 | config.index_key = "xorm"; 215 | config.character_encoding = "utf8"; 216 | config.host = "./test1.db"; 217 | config.conn_number = 5; 218 | dao_message::get().set_error_callback([](std::string const& msg) { 219 | std::cout << msg << "\n"; 220 | }); 221 | dao_t::init_conn_pool(config); 222 | dao_t dao{ "xorm" }; 223 | auto rs0 = dao.query(""); 224 | auto r = dao.query(""); 225 | test1 tt; 226 | tt.a = 56; 227 | tt.b = 10.4; 228 | tt.id = 1; 229 | tt.text = "abccdd"; 230 | std::ifstream file("./time.jpg", std::ios::binary); 231 | std::stringstream ss; 232 | ss << file.rdbuf(); 233 | auto content = ss.str(); 234 | auto data_begin = content.data(); 235 | tt.binary = sqlite::Blob(data_begin, data_begin + content.size()); 236 | auto r0 = dao.insert(tt); 237 | auto r1 = dao.query>("select a from test1 where id=?", sqlite::Integer{ 1 }); 238 | auto r11 = dao.query(""); 239 | if (!r11.results.empty()) { 240 | auto&& first = r11.results[0]; 241 | std::ofstream output("./readout.jpg", std::ios::binary); 242 | output.write((char const*)first.binary.data(), first.binary.size()); 243 | } 244 | auto r12 = dao.query("where id=?", sqlite::Integer{ 1 }); 245 | tt.b = 1024.1024; 246 | auto r2 = dao.update(tt); 247 | auto r90 = dao.update("update test1 set a=? where id=?", sqlite::Integer{ 100 }, sqlite::Integer{ 1 }); 248 | auto rs = dao.query>("select id from test1 where text=?", std::string("abccdd")); 249 | auto r3 = dao.del(""); 250 | #endif // XORM_ENABLE_SQLITE 251 | std::getchar(); 252 | } -------------------------------------------------------------------------------- /xorm/mysqlc++14.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef _WIN32 3 | #include 4 | #else 5 | #include 6 | #endif // __LINUX__ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "reflect/reflector.hpp" 15 | #include "data_type.hpp" 16 | #include "meta_utility.hpp" 17 | #include "dbconfig.hpp" 18 | namespace xorm { 19 | class mysql final { 20 | public: 21 | using Integer = FundamentionType; 22 | using Float = FundamentionType; 23 | using Double = FundamentionType; 24 | using BigInt = FundamentionType; 25 | using SmallInt = FundamentionType; 26 | using TinyInt = FundamentionType; 27 | using MysqlDate = TimeDate; 28 | using MysqlDateTime = TimeDate; 29 | using MysqlTime = TimeDate; 30 | private: 31 | template 32 | typename std::enable_if::type>::value || is_date_type::type>::value>::type bind_value(T& t, MYSQL_BIND& bind, bool get = false) { 33 | using type = typename std::remove_reference::type; 34 | bind.buffer_type = type::field_type; 35 | bind.buffer = t.buffer(); 36 | bind.is_null = t.null_buffer(); 37 | bind.length = 0; 38 | //bind.buffer_length = 0; 39 | } 40 | template 41 | typename std::enable_if::type, std::string>::value>::type bind_value(T& t, MYSQL_BIND& bind, bool get = false) { 42 | if (get) { 43 | t.resize(string_max_size_); 44 | } 45 | bind.buffer_type = MYSQL_TYPE_STRING; 46 | bind.buffer = &(t[0]); 47 | bind.is_null = 0; 48 | bind.length = 0; 49 | bind.buffer_length = (unsigned long)t.size(); 50 | } 51 | 52 | template 53 | typename std::enable_if::type, std::string>::value>::type clear_field(T& t,U& v) { 54 | v = std::string(&v[0], strlen(v.data())); 55 | memset(&t[0], 0, t.size()); 56 | } 57 | 58 | template 59 | typename std::enable_if::type, std::string>::value>::type clear_field(T& t,U& v) { 60 | t.clear(); 61 | } 62 | public: 63 | mysql() = default; 64 | mysql(dataBaseConfig const& config) { 65 | connect(config); 66 | } 67 | public: 68 | void connect(dataBaseConfig const& config) { 69 | bool is_success = false; 70 | if (0 == mysql_server_init(0, nullptr, nullptr)) { 71 | is_success = true; 72 | } 73 | conn_ = mysql_init(nullptr); 74 | if (nullptr != conn_) { 75 | is_success = true; 76 | mysql_options(conn_, MYSQL_OPT_RECONNECT, &config.reconnect_number); 77 | mysql_options(conn_, MYSQL_SET_CHARSET_NAME, config.character_encoding.data()); 78 | } 79 | 80 | if (config.timeout > 0) { 81 | if (mysql_options(conn_, MYSQL_OPT_CONNECT_TIMEOUT, &config.timeout) != 0) { 82 | is_success = false; 83 | } 84 | else { 85 | is_success = true; 86 | } 87 | } 88 | 89 | if (is_success && nullptr != mysql_real_connect(conn_, config.host.c_str(), config.user.c_str(), config.password.c_str(), config.dbname.c_str(), config.port, nullptr, 0)) { 90 | is_connect_ = true; 91 | } 92 | } 93 | void reconnect(dataBaseConfig const& config) { 94 | disconnect(); 95 | connect(config); 96 | } 97 | 98 | void disconnect() { 99 | if (conn_ != nullptr) { 100 | mysql_close(conn_); 101 | conn_ = nullptr; 102 | is_connect_ = false; 103 | } 104 | } 105 | bool is_connect() { 106 | return conn_!=nullptr && is_connect_; 107 | } 108 | 109 | bool ping() { 110 | if (conn_ == nullptr) { 111 | is_connect_ = false; 112 | return false; 113 | } 114 | bool r = mysql_ping(conn_) == 0; 115 | if (!r) { 116 | is_connect_ = false; 117 | } 118 | return r; 119 | } 120 | public: 121 | template 122 | typename std::enable_if::type>::value, std::pair>::type insert(T&& t) { 123 | auto meta = meta_info_reflect(t); 124 | std::string tablename = meta.get_class_name(); 125 | std::stringstream ss; 126 | ss << "INSERT INTO " << tablename << " ("; 127 | auto size = meta.element_size(); 128 | int index = 0; 129 | std::string value_place = ""; 130 | MYSQL_BIND bind[meta.element_size()]; 131 | memset(bind, 0, sizeof(bind)); 132 | reflector::each_object(std::forward(t), [&ss, &index, size, &value_place, &bind, this](auto&& obj, auto name, auto field) { 133 | this->bind_value((obj.*field), bind[index]); 134 | if (index < (size - 1)) { 135 | ss << name << ","; 136 | value_place.append("?,"); 137 | } 138 | else if (index == (size - 1)) { 139 | ss << name; 140 | value_place.append("?"); 141 | } 142 | ++index; 143 | }); 144 | ss << ")" << " VALUES(" << value_place << ")"; 145 | return stmt_execute(ss.str(), bind); 146 | } 147 | 148 | template 149 | typename std::enable_if::type>::value, bool>::type del(std::string const& condition) { 150 | auto meta = meta_info_reflect(T{}); 151 | std::string sql = "DELETE FROM " + meta.get_class_name() + " " + condition; 152 | return execute(sql); 153 | } 154 | 155 | template 156 | typename std::enable_if::type>::value, bool>::type update(T&& v, std::string const& condition = "") { 157 | auto meta = meta_info_reflect(v); 158 | std::string tablename = meta.get_class_name(); 159 | std::stringstream ss; 160 | MYSQL_BIND bind[meta.element_size()]; 161 | memset(bind, 0, sizeof(bind)); 162 | if (condition.empty()) { 163 | ss << "replace into " << tablename << " ("; 164 | auto size = meta.element_size(); 165 | int index = 0; 166 | std::string value_place = ""; 167 | reflector::each_object(std::forward(v), [&ss, &index, size, &value_place, &bind, this](auto&& obj, auto name, auto field) { 168 | this->bind_value((obj.*field), bind[index]); 169 | if (index < (size - 1)) { 170 | ss << name << ","; 171 | value_place.append("?,"); 172 | } 173 | else if (index == (size - 1)) { 174 | ss << name; 175 | value_place.append("?"); 176 | } 177 | ++index; 178 | }); 179 | ss << ")" << " VALUES(" << value_place << ")"; 180 | } 181 | else { 182 | ss << "UPDATE " << tablename << " SET "; 183 | auto size = meta.element_size(); 184 | int index = 0; 185 | reflector::each_object(std::forward(v), [&ss, &index, size, &bind, this](auto&& obj, auto name, auto field) { 186 | this->bind_value((obj.*field), bind[index]); 187 | if (index < (size - 1)) { 188 | ss << name << "=?" << ","; 189 | } 190 | else if (index == (size - 1)) { 191 | ss << name << "=?"; 192 | } 193 | ++index; 194 | }); 195 | ss << " " << condition; 196 | } 197 | auto rpr = stmt_execute(ss.str(), bind); 198 | if (condition.empty()) { 199 | return rpr.first == 2 ? true : false; 200 | } 201 | else { 202 | return rpr.first != 0 ? true : false; 203 | } 204 | } 205 | 206 | template 207 | typename std::enable_if::type>::value, std::pair>>::type query(std::string const& condition="" ) { 208 | auto meta = meta_info_reflect(T{}); 209 | std::string tablename = meta.get_class_name(); 210 | std::stringstream ss; 211 | MYSQL_BIND bind[meta.element_size()]; 212 | memset(bind, 0, sizeof(bind)); 213 | auto name_arr = meta.get_element_names(); 214 | ss << "SELECT "; 215 | auto size = name_arr.size(); 216 | for (auto index = 0; index < size; index++) { 217 | ss << name_arr[index]; 218 | if (index < (size - 1)) { 219 | ss << ","; 220 | } 221 | } 222 | ss << " FROM " << tablename<<" "<< condition; 223 | MYSQL_STMT* pStmt = nullptr; 224 | pStmt = mysql_stmt_init(conn_); 225 | std::vector result; 226 | if (pStmt != nullptr) { 227 | auto sqlStr = ss.str(); 228 | int iRet = mysql_stmt_prepare(pStmt, sqlStr.c_str(), (unsigned long)sqlStr.size()); 229 | if (iRet == 0) { 230 | T tmp{}; 231 | int index = 0; 232 | reflector::each_object(tmp, [&index, &bind, this](auto&& obj, auto name, auto field) { 233 | this->bind_value((obj.*field), bind[index], true); 234 | ++index; 235 | }); 236 | bool r = mysql_stmt_bind_result(pStmt, bind); 237 | if (!r) { 238 | r = mysql_stmt_execute(pStmt); 239 | if (!r) { 240 | while (mysql_stmt_fetch(pStmt) == 0) { 241 | T copy_v = tmp; 242 | reflector::each_object(tmp, [this,©_v](auto&& obj, auto name, auto field) { 243 | this->clear_field((obj.*field),(copy_v.*field)); 244 | }); 245 | result.push_back(std::move(copy_v)); 246 | } 247 | return { true,result }; 248 | } 249 | } 250 | } 251 | else { 252 | std::cout << mysql_error(conn_) << std::endl; 253 | } 254 | } 255 | return { false,result }; 256 | } 257 | 258 | template 259 | typename std::enable_if, std::pair>>::type query(std::string const& sqlStr) { 260 | constexpr std::size_t tuple_size = std::tuple_size::value; 261 | MYSQL_BIND bind[tuple_size]; 262 | memset(bind, 0, sizeof(bind)); 263 | MYSQL_STMT* pStmt = nullptr; 264 | pStmt = mysql_stmt_init(conn_); 265 | std::vector result; 266 | if (pStmt != nullptr) { 267 | int iRet = mysql_stmt_prepare(pStmt, sqlStr.c_str(), (unsigned long)sqlStr.size()); 268 | if (iRet == 0) { 269 | T tmp{}; 270 | int index = 0; 271 | each_tuple<0, tuple_size>::each(tmp, [&bind,this,&index](auto& v) { 272 | this->bind_value(v, bind[index], true); 273 | ++index; 274 | }); 275 | bool r = mysql_stmt_bind_result(pStmt, bind); 276 | if (!r) { 277 | r = mysql_stmt_execute(pStmt); 278 | if (!r) { 279 | while (mysql_stmt_fetch(pStmt) == 0) { 280 | T copy_v = tmp; 281 | each_tuple<0, tuple_size>::each2(tmp, copy_v,[&bind,this](auto& v,auto& u) { 282 | this->clear_field(v,u); 283 | }); 284 | result.push_back(copy_v); 285 | } 286 | return { true,result }; 287 | } 288 | } 289 | } 290 | else { 291 | std::cout << mysql_error(conn_) << std::endl; 292 | } 293 | } 294 | return { false,result }; 295 | } 296 | 297 | bool execute(std::string const& sql) { 298 | auto iRet = mysql_query(conn_, sql.c_str()); 299 | bool r = iRet != 0 ? false : true; 300 | if (r) { 301 | auto pRes = mysql_use_result(conn_); 302 | mysql_free_result(pRes); 303 | } 304 | else { 305 | std::cout << mysql_error(conn_) << std::endl; 306 | } 307 | return r; 308 | } 309 | bool begin() { 310 | return execute("BEGIN"); 311 | } 312 | bool commit() { 313 | return execute("COMMIT"); 314 | } 315 | bool rollback() { 316 | return execute("ROLLBACK"); 317 | } 318 | void set_max_string_size(std::size_t size) { 319 | string_max_size_ = size; 320 | } 321 | std::size_t get_max_string_size() { 322 | return string_max_size_; 323 | } 324 | private: 325 | std::pair stmt_execute(std::string const& sqlStr, MYSQL_BIND* bind) { 326 | MYSQL_STMT* pStmt = nullptr; 327 | pStmt = mysql_stmt_init(conn_); 328 | if (pStmt != nullptr) { 329 | begin(); 330 | int iRet = mysql_stmt_prepare(pStmt, sqlStr.data(), (unsigned long)sqlStr.size()); 331 | if (iRet == 0) { 332 | iRet = mysql_stmt_bind_param(pStmt, bind); 333 | if (iRet == 0) { 334 | iRet = mysql_stmt_execute(pStmt); 335 | if (iRet == 0) { 336 | auto rows = mysql_stmt_affected_rows(pStmt); 337 | if (rows != 0) { 338 | bool cr = commit(); 339 | auto pr = query>("SELECT LAST_INSERT_ID();"); 340 | if (cr && pr.first) { 341 | auto& id_arr = pr.second; 342 | if (!id_arr.empty()) { 343 | auto id = std::get<0>((id_arr[0])); 344 | return { rows ,id.value() }; 345 | } 346 | } 347 | return { rows,0 }; 348 | } 349 | } 350 | } 351 | } 352 | rollback(); 353 | } 354 | return { 0 ,0}; 355 | } 356 | private: 357 | MYSQL* conn_; 358 | bool is_connect_ = false; 359 | std::size_t string_max_size_ = 1024 * 1024; 360 | }; 361 | } -------------------------------------------------------------------------------- /xorm/sqlite3.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef XORM_ENABLE_SQLITE 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "reflect/reflector.hpp" 13 | #include "dbconfig.hpp" 14 | #include "meta_utility.hpp" 15 | #include "db_utils.hpp" 16 | namespace xorm { 17 | 18 | template 19 | class SqliteFundamentionType final { 20 | friend std::ostream& operator <<(std::ostream& out, SqliteFundamentionType const& v) { 21 | out << v.value(); 22 | return out; 23 | } 24 | public: 25 | using value_type = Type; 26 | public: 27 | SqliteFundamentionType() :data_(0), is_null_(true) { 28 | 29 | } 30 | SqliteFundamentionType(Type v) :data_(v), is_null_(false) { 31 | 32 | } 33 | SqliteFundamentionType& operator=(Type v) { 34 | data_ = v; 35 | is_null_ = false; 36 | return *this; 37 | } 38 | 39 | bool is_null() const { 40 | return is_null_; 41 | } 42 | 43 | void clear() { 44 | data_ = 0; 45 | is_null_ = true; 46 | } 47 | Type value() const { 48 | return data_; 49 | } 50 | private: 51 | Type data_; 52 | bool is_null_; 53 | }; 54 | template 55 | struct is_sqlitefundametion_type { 56 | constexpr static bool value = false; 57 | }; 58 | 59 | template 60 | struct is_sqlitefundametion_type> { 61 | constexpr static bool value = true; 62 | }; 63 | 64 | //template 65 | //typename std::enable_if::type>::value, bool>::type is_null_value_for_field(T&& t) { 66 | // return t.is_null(); 67 | //} 68 | 69 | //template 70 | //typename std::enable_if::type>::value, bool>::type is_null_value_for_field(T&& t) { 71 | // return t.empty(); 72 | //} 73 | 74 | class sqlite final { 75 | public: 76 | using Integer = SqliteFundamentionType; 77 | using Double = SqliteFundamentionType; 78 | using Int64 = SqliteFundamentionType; 79 | using Blob = std::vector; 80 | struct SQLITE_RES { 81 | int argu1; 82 | char** argu2; 83 | char** argu3; 84 | }; 85 | protected: 86 | template 87 | class stmt_guard { 88 | public: 89 | template 90 | stmt_guard(U&& resource) :resource_(std::forward(resource)) { 91 | 92 | } 93 | public: 94 | ~stmt_guard() { 95 | if (resource_ != nullptr) { 96 | sqlite3_finalize(resource_); 97 | } 98 | } 99 | private: 100 | T* resource_ = nullptr; 101 | }; 102 | 103 | template 104 | struct auto_params_lambda0 { 105 | auto_params_lambda0(std::stringstream& ss_, int& index_, std::size_t size_, std::string& value_place_, T0* that) :ss(ss_), index(index_), size(size_), value_place(value_place_),this_(that) { 106 | 107 | } 108 | template 109 | void operator()(T&& obj, U&& name, Y&& field) { 110 | 111 | if (index < (size - 1)) { 112 | ss << "'" << name << "' " << ","; 113 | value_place.append("?,"); 114 | } 115 | else if (index == (size - 1)) { 116 | ss << "'" << name << "' "; 117 | value_place.append("?"); 118 | } 119 | ++index; 120 | } 121 | std::stringstream& ss; 122 | int& index; 123 | std::size_t size; 124 | std::string& value_place; 125 | T0* this_; 126 | }; 127 | 128 | template 129 | struct auto_params_lambda1 { 130 | auto_params_lambda1(std::stringstream& ss_, int& index_, std::size_t size_, T0* that) :ss(ss_), index(index_), size(size_), this_(that) { 131 | 132 | } 133 | template 134 | void operator()(T&& obj, U&& name, Y&& field) { 135 | 136 | if (index < (size - 1)) { 137 | ss << "`" << name << "` " << ","; 138 | } 139 | else if (index == (size - 1)) { 140 | ss << "`" << name << "` "; 141 | } 142 | ++index; 143 | } 144 | std::stringstream& ss; 145 | int& index; 146 | std::size_t size; 147 | T0* this_; 148 | }; 149 | private: 150 | template 151 | typename std::enable_if::type>::value && std::is_same::type::value_type,int>::value,int>::type bind_value(sqlite3_stmt* stmt,T&& v,std::size_t index,bool get = false) { 152 | if (get) { 153 | v = sqlite3_column_int(stmt, (int)index); 154 | return 0; 155 | } 156 | if (v.is_null()) { 157 | return sqlite3_bind_null(stmt, (int)index); 158 | } 159 | return sqlite3_bind_int(stmt, (int)index, v.value()); 160 | } 161 | 162 | template 163 | typename std::enable_if::type>::value&& std::is_same::type::value_type, double>::value, int>::type bind_value(sqlite3_stmt* stmt, T&& v, std::size_t index, bool get = false) { 164 | if (get) { 165 | v = sqlite3_column_double(stmt, (int)index); 166 | return 0; 167 | } 168 | if (v.is_null()) { 169 | return sqlite3_bind_null(stmt, (int)index); 170 | } 171 | return sqlite3_bind_double(stmt, (int)index, v.value()); 172 | } 173 | 174 | template 175 | typename std::enable_if::type>::value&& std::is_same::type::value_type, sqlite3_int64>::value, int>::type bind_value(sqlite3_stmt* stmt, T&& v, std::size_t index, bool get = false) { 176 | if (get) { 177 | v = sqlite3_column_int64(stmt, (int)index); 178 | return 0; 179 | } 180 | if (v.is_null()) { 181 | return sqlite3_bind_null(stmt, (int)index); 182 | } 183 | return sqlite3_bind_int64(stmt, (int)index, v.value()); 184 | } 185 | 186 | template 187 | typename std::enable_if::type>::value&& std::is_same::type, std::string>::value, int>::type bind_value(sqlite3_stmt* stmt, T&& v, std::size_t index, bool get = false) { 188 | if (get) { 189 | auto size = (std::size_t)sqlite3_column_bytes(stmt, (int)index); 190 | v = std::string((char*)sqlite3_column_text(stmt, (int)index), size); 191 | return 0; 192 | } 193 | return sqlite3_bind_text(stmt, (int)index, v.data(),(int)v.size(),nullptr); 194 | } 195 | 196 | template 197 | typename std::enable_if::type>::value&& std::is_same::type, Blob>::value, int>::type bind_value(sqlite3_stmt* stmt, T&& v, std::size_t index, bool get = false) { 198 | if (get) { 199 | auto size = (std::size_t)sqlite3_column_bytes(stmt, (int)index); 200 | auto start = (char*)sqlite3_column_blob(stmt, (int)index); 201 | v = Blob(start, start + size); 202 | return 0; 203 | } 204 | return sqlite3_bind_blob(stmt, (int)index, v.data(), (int)v.size(), nullptr); 205 | } 206 | 207 | template 208 | int void_parameter_content(T...args) { 209 | auto range = sizeof...(T); 210 | int arr[sizeof...(T)+1] = { args... }; 211 | int r = SQLITE_OK; 212 | for (auto i = 0; i < range; i++) { 213 | r = r | arr[i]; 214 | } 215 | return r; 216 | } 217 | 218 | template 219 | int bind_params_with_obj(sqlite3_stmt* stmt,T&& obj, Tuple&& tup, xorm_utils::index_package) { 220 | return void_parameter_content(bind_value(stmt, (obj.*(std::get(tup))), Indexs+1)...); 221 | } 222 | 223 | template 224 | int bind_params_without_obj(sqlite3_stmt* stmt,Tuple&& tup, xorm_utils::index_package) { 225 | return void_parameter_content(bind_value(stmt, std::get(tup), Indexs + 1)...); 226 | } 227 | 228 | template 229 | int get_row_data_for_tuple(sqlite3_stmt* stmt, Tuple&& tup, xorm_utils::index_package, bool get = false) { 230 | return void_parameter_content(bind_value(stmt, std::get(tup), Indexs, get)...); 231 | } 232 | 233 | template 234 | int get_row_data_for_obj(sqlite3_stmt* stmt,T&& obj,Tuple&& tup, xorm_utils::index_package) { 235 | return void_parameter_content(bind_value(stmt, (obj.*(std::get(tup))), Indexs,true)...); 236 | } 237 | private: 238 | void trigger_error(std::string const& msg) { 239 | if (error_callback_ != nullptr) { 240 | error_callback_("db_index: " + db_index_key_ + " , error: " + msg); 241 | } 242 | } 243 | void set_error_callback(std::function const& callback) { 244 | if (callback != nullptr) { 245 | error_callback_ = callback; 246 | } 247 | } 248 | void init_error_default_callback() { 249 | error_callback_ = [](std::string const& message) { 250 | std::cout << message << "\n"; 251 | }; 252 | } 253 | public: 254 | sqlite() { 255 | init_error_default_callback(); 256 | } 257 | sqlite(dataBaseConfig const& config, std::function const& error_callback = nullptr) { 258 | if (error_callback == nullptr) { 259 | init_error_default_callback(); 260 | } 261 | else { 262 | error_callback_ = error_callback; 263 | } 264 | connect(config); 265 | } 266 | ~sqlite() { 267 | disconnect(); 268 | } 269 | bool connect(dataBaseConfig const& config) { 270 | db_index_key_ = config.index_key; 271 | auto r = sqlite3_open(config.host.c_str(), &sqlite_handler_); 272 | if (r == SQLITE_OK) { //表示连接成功 273 | #ifdef SQLITE_HAS_CODEC 274 | if (!config.password.empty()) { 275 | sqlite3_key(sqlite_handler_, config.password.c_str(), (int)config.password.size()); 276 | } 277 | #endif 278 | is_connect_ = true; 279 | return true; 280 | } 281 | return false; 282 | } 283 | void reconnect(dataBaseConfig const& config) { 284 | disconnect(); 285 | connect(config); 286 | } 287 | void disconnect() { 288 | if (sqlite_handler_ != nullptr) { 289 | sqlite3_close(sqlite_handler_); 290 | sqlite_handler_ = nullptr; 291 | is_connect_ = false; 292 | } 293 | } 294 | bool ping() { 295 | return is_connect_; 296 | } 297 | bool is_connect() { 298 | return sqlite_handler_ != nullptr && is_connect_; 299 | } 300 | public: 301 | template::type>::value>> 302 | db_result insert(T&& obj) { 303 | auto meta = meta_info_reflect(obj); 304 | std::string tablename = meta.get_class_name(); 305 | std::stringstream ss; 306 | ss << "INSERT INTO '" << tablename << "' ("; 307 | auto size = meta.element_size(); 308 | int index = 0; 309 | std::string value_place = ""; 310 | sqlite3_stmt* stmt = nullptr; 311 | auto_params_lambda0 lambda{ ss ,index ,size ,value_place ,this }; 312 | reflector::each_object(std::forward(obj), lambda); 313 | ss << ")" << " VALUES(" << value_place << ")"; 314 | auto sqlStr = ss.str(); 315 | return stmt_execute_with_obj(sqlStr, std::forward(obj), meta.get_element_meta_protype()); 316 | } 317 | template::type>::value>,typename...Params> 318 | db_result del(std::string const& condition, Params&&...params) { 319 | auto meta = meta_info_reflect(T{}); 320 | std::stringstream ss; 321 | ss << "DELETE FROM '" << meta.get_class_name() << "' "<< condition; 322 | return stmt_execute(ss.str(), std::forward(params)...); 323 | } 324 | 325 | template::type>::value>> 326 | db_result update(T&& obj) { 327 | auto meta = meta_info_reflect(obj); 328 | std::stringstream ss; 329 | ss << "replace into '" << meta.get_class_name() << "' ("; 330 | int index = 0; 331 | auto size = meta.element_size(); 332 | std::string value_place = ""; 333 | auto_params_lambda0 lambda{ ss ,index ,size ,value_place ,this }; 334 | reflector::each_object(std::forward(obj), lambda); 335 | ss << ")" << " VALUES(" << value_place << ")"; 336 | auto sqlStr = ss.str(); 337 | return stmt_execute_with_obj(sqlStr, std::forward(obj), meta.get_element_meta_protype()); 338 | } 339 | 340 | template 341 | db_result update(std::string const& sqlStr ,Params&& ...params) { 342 | return stmt_execute(sqlStr, std::forward(params)...); 343 | } 344 | 345 | template 346 | typename std::enable_if ::value, db_result>::type query(std::string const& condition, Params&& ...params) { 347 | auto meta = meta_info_reflect(T{}); 348 | std::stringstream ss; 349 | ss << "SELECT "; 350 | int index = 0; 351 | auto size = meta.element_size(); 352 | auto_params_lambda1 lambda{ ss,index ,size ,this }; 353 | reflector::each_object(T{}, lambda); 354 | ss << " FROM '" << meta.get_class_name() << "' "<< condition; 355 | return get_obj_stmt_execute(ss.str(), std::forward(params)...); 356 | } 357 | 358 | template 359 | typename std::enable_if<(!reflector::is_reflect_class::value && is_tuple_type::value), db_result >::type query(std::string const& sqlStr, Params&& ...params) { 360 | return get_tuple_stmt_execute(sqlStr, std::forward(params)...); 361 | } 362 | 363 | db_result execute(const std::string& sql) { 364 | db_result dbresult; 365 | if (sqlite3_exec(sqlite_handler_, sql.data(), nullptr, nullptr, nullptr) != SQLITE_OK) { 366 | std::string message = sqlite3_errmsg(sqlite_handler_); 367 | trigger_error(message); 368 | dbresult.success = false; 369 | dbresult.error.is_error_ = true; 370 | dbresult.error.message_ = message; 371 | return dbresult; 372 | } 373 | dbresult.success = true; 374 | return dbresult; 375 | } 376 | db_result execute(std::string const& sql, std::function const& data_callback) { 377 | db_result dbresult; 378 | auto callback = [](void* a0, int a1, char** a2, char** a3)->int { 379 | SQLITE_RES r{ a1,a2,a3 }; 380 | auto fun = static_cast*>(a0); 381 | (*fun)(&r); 382 | return 0; 383 | }; 384 | if (sqlite3_exec(sqlite_handler_, sql.data(), callback, const_cast*>(&data_callback), nullptr) != SQLITE_OK) { 385 | std::string message = sqlite3_errmsg(sqlite_handler_); 386 | trigger_error(message); 387 | dbresult.success = false; 388 | dbresult.error.is_error_ = true; 389 | dbresult.error.message_ = message; 390 | return dbresult; 391 | } 392 | dbresult.success = true; 393 | return dbresult; 394 | } 395 | db_result begin() { 396 | return execute("BEGIN"); 397 | } 398 | db_result commit() { 399 | return execute("COMMIT"); 400 | } 401 | db_result rollback() { 402 | return execute("ROLLBACK"); 403 | } 404 | std::uint64_t get_affected_rows() { 405 | return sqlite3_changes(sqlite_handler_); 406 | } 407 | private: 408 | template 409 | db_result stmt_execute(std::string const& sqlStr, Params&& ...params) { 410 | sqlite3_stmt* stmt = nullptr; 411 | auto r = sqlite3_prepare_v2(sqlite_handler_, sqlStr.c_str(), (int)sqlStr.size(), &stmt, nullptr); 412 | stmt_guard guard{ stmt }; 413 | db_result dbresult; 414 | if (r == SQLITE_OK) { 415 | auto params_tuple = std::make_tuple(params...); 416 | auto result = bind_params_without_obj(stmt, params_tuple, xorm_utils::make_index_package{}); 417 | if (result == SQLITE_OK) { 418 | result = sqlite3_step(stmt); 419 | if (result == SQLITE_DONE) { 420 | auto effect_rows = get_affected_rows(); 421 | dbresult.affect_rows = effect_rows; 422 | dbresult.success = true; 423 | dbresult.unique_id = sqlite3_last_insert_rowid(sqlite_handler_); 424 | return dbresult; 425 | } 426 | } 427 | } 428 | std::string error_message = sqlite3_errmsg(sqlite_handler_); 429 | trigger_error(error_message); 430 | dbresult.success = false; 431 | dbresult.error.is_error_ = true; 432 | dbresult.error.message_ = error_message; 433 | return dbresult; 434 | } 435 | 436 | template::type>::value>,typename Tuple> 437 | db_result stmt_execute_with_obj(std::string const& sqlStr, T&& obj, Tuple&& tup) { 438 | sqlite3_stmt* stmt = nullptr; 439 | auto r = sqlite3_prepare_v2(sqlite_handler_, sqlStr.c_str(), (int)sqlStr.size(), &stmt, nullptr); 440 | stmt_guard guard{ stmt }; 441 | db_result dbresult; 442 | if (r == SQLITE_OK) { 443 | auto result = bind_params_with_obj(stmt,std::forward(obj), std::forward(tup), xorm_utils::make_index_package::type>::value>{}); 444 | if (result == SQLITE_OK) { 445 | result = sqlite3_step(stmt); 446 | if (result == SQLITE_DONE) { 447 | dbresult.affect_rows = get_affected_rows(); 448 | dbresult.success = true; 449 | dbresult.unique_id = sqlite3_last_insert_rowid(sqlite_handler_); 450 | return dbresult; 451 | } 452 | } 453 | } 454 | std::string error_message = sqlite3_errmsg(sqlite_handler_); 455 | trigger_error(error_message); 456 | dbresult.success = false; 457 | dbresult.error.is_error_ = true; 458 | dbresult.error.message_ = error_message; 459 | return dbresult; 460 | } 461 | 462 | private: 463 | template 464 | db_result get_obj_stmt_execute(std::string const& sqlStr, Params&& ...params) { 465 | sqlite3_stmt* stmt = nullptr; 466 | auto r = sqlite3_prepare_v2(sqlite_handler_, sqlStr.c_str(), -1, &stmt, nullptr); 467 | stmt_guard guard{ stmt }; 468 | db_result dbresult; 469 | if (r == SQLITE_OK) { 470 | auto params_tuple = std::make_tuple(params...); 471 | auto result = bind_params_without_obj(stmt, params_tuple, xorm_utils::make_index_package{}); 472 | if (result == SQLITE_OK) { 473 | while (sqlite3_step(stmt)== SQLITE_ROW) { 474 | T tmp{}; 475 | auto meta = meta_info_reflect(tmp); 476 | get_row_data_for_obj(stmt, tmp, meta.get_element_meta_protype(), xorm_utils::make_index_package{}); 477 | dbresult.results.emplace_back(tmp); 478 | } 479 | dbresult.success = true; 480 | return dbresult; 481 | } 482 | else { 483 | std::string error_message = sqlite3_errmsg(sqlite_handler_); 484 | trigger_error(error_message); 485 | dbresult.success = false; 486 | dbresult.error.is_error_ = true; 487 | dbresult.error.message_ = error_message; 488 | return dbresult; 489 | } 490 | } 491 | else { 492 | std::string error_message = sqlite3_errmsg(sqlite_handler_); 493 | trigger_error(error_message); 494 | dbresult.success = false; 495 | dbresult.error.is_error_ = true; 496 | dbresult.error.message_ = error_message; 497 | return dbresult; 498 | } 499 | return dbresult; 500 | } 501 | 502 | template 503 | db_result get_tuple_stmt_execute(std::string const& sqlStr, Params&& ...params) { 504 | sqlite3_stmt* stmt = nullptr; 505 | auto r = sqlite3_prepare_v2(sqlite_handler_, sqlStr.c_str(), -1, &stmt, nullptr); 506 | stmt_guard guard{ stmt }; 507 | db_result dbresult; 508 | if (r == SQLITE_OK) { 509 | auto params_tuple = std::make_tuple(params...); 510 | auto result = bind_params_without_obj(stmt, params_tuple, xorm_utils::make_index_package{}); 511 | if (result == SQLITE_OK) { 512 | while (sqlite3_step(stmt) == SQLITE_ROW) { 513 | T tmp{}; 514 | get_row_data_for_tuple(stmt, tmp, xorm_utils::make_index_package::value>{},true); 515 | dbresult.results.emplace_back(tmp); 516 | } 517 | dbresult.success = true; 518 | return dbresult; 519 | } 520 | else { 521 | std::string error_message = sqlite3_errmsg(sqlite_handler_); 522 | trigger_error(error_message); 523 | dbresult.success = false; 524 | dbresult.error.is_error_ = true; 525 | dbresult.error.message_ = error_message; 526 | return dbresult; 527 | } 528 | } 529 | else { 530 | std::string error_message = sqlite3_errmsg(sqlite_handler_); 531 | trigger_error(error_message); 532 | dbresult.success = false; 533 | dbresult.error.is_error_ = true; 534 | dbresult.error.message_ = error_message; 535 | return dbresult; 536 | } 537 | return dbresult; 538 | } 539 | public: 540 | sqlite3* get_raw_connetion() { 541 | return is_connect_ == true ? sqlite_handler_ : nullptr; 542 | } 543 | private: 544 | bool is_connect_ = false; 545 | sqlite3* sqlite_handler_ = nullptr; 546 | std::function error_callback_; 547 | std::string db_index_key_; 548 | }; 549 | } 550 | #endif // ENABLE_SQLITE -------------------------------------------------------------------------------- /xorm/reflect/reflector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | namespace reflector 6 | { 7 | #define place_holder 120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 8 | #define expand_marco(...) __VA_ARGS__ 9 | #define concat_a_b_(a,b) a##b 10 | #define concat_a_b(a,b) concat_a_b_(a,b) 11 | 12 | #ifdef _MSC_VER 13 | 14 | #define inner_var(...) unused,__VA_ARGS__ 15 | #define get_count_(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100,_101,_102,_103,_104,_105,_106,_107,_108,_109,_110,_111,_112,_113,_114,_115,_116,_117,_118,_119,_120,count,...) count 16 | #define get_count_help(...) expand_marco(get_count_(__VA_ARGS__)) 17 | #define get_count(...) get_count_help(inner_var(__VA_ARGS__),place_holder) 18 | 19 | #else // _NOT_MSC_VER 20 | #define get_count_(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100,_101,_102,_103,_104,_105,_106,_107,_108,_109,_110,_111,_112,_113,_114,_115,_116,_117,_118,_119,_120,count,...) count 21 | #define get_count_help(...) get_count_(__VA_ARGS__) 22 | #define get_count(...) get_count_help(0,## __VA_ARGS__,place_holder) 23 | #endif 24 | 25 | #define For_1(method,ClassName,element,...) method(ClassName,element) 26 | #define For_2(method,ClassName,element,...) method(ClassName,element),expand_marco(For_1(method,ClassName,__VA_ARGS__)) 27 | #define For_3(method,ClassName,element,...) method(ClassName,element),expand_marco(For_2(method,ClassName,__VA_ARGS__)) 28 | #define For_4(method,ClassName,element,...) method(ClassName,element),expand_marco(For_3(method,ClassName,__VA_ARGS__)) 29 | #define For_5(method,ClassName,element,...) method(ClassName,element),expand_marco(For_4(method,ClassName,__VA_ARGS__)) 30 | #define For_6(method,ClassName,element,...) method(ClassName,element),expand_marco(For_5(method,ClassName,__VA_ARGS__)) 31 | #define For_7(method,ClassName,element,...) method(ClassName,element),expand_marco(For_6(method,ClassName,__VA_ARGS__)) 32 | #define For_8(method,ClassName,element,...) method(ClassName,element),expand_marco(For_7(method,ClassName,__VA_ARGS__)) 33 | #define For_9(method,ClassName,element,...) method(ClassName,element),expand_marco(For_8(method,ClassName,__VA_ARGS__)) 34 | #define For_10(method,ClassName,element,...) method(ClassName,element),expand_marco(For_9(method,ClassName,__VA_ARGS__)) 35 | #define For_11(method,ClassName,element,...) method(ClassName,element),expand_marco(For_10(method,ClassName,__VA_ARGS__)) 36 | #define For_12(method,ClassName,element,...) method(ClassName,element),expand_marco(For_11(method,ClassName,__VA_ARGS__)) 37 | #define For_13(method,ClassName,element,...) method(ClassName,element),expand_marco(For_12(method,ClassName,__VA_ARGS__)) 38 | #define For_14(method,ClassName,element,...) method(ClassName,element),expand_marco(For_13(method,ClassName,__VA_ARGS__)) 39 | #define For_15(method,ClassName,element,...) method(ClassName,element),expand_marco(For_14(method,ClassName,__VA_ARGS__)) 40 | #define For_16(method,ClassName,element,...) method(ClassName,element),expand_marco(For_15(method,ClassName,__VA_ARGS__)) 41 | #define For_17(method,ClassName,element,...) method(ClassName,element),expand_marco(For_16(method,ClassName,__VA_ARGS__)) 42 | #define For_18(method,ClassName,element,...) method(ClassName,element),expand_marco(For_17(method,ClassName,__VA_ARGS__)) 43 | #define For_19(method,ClassName,element,...) method(ClassName,element),expand_marco(For_18(method,ClassName,__VA_ARGS__)) 44 | #define For_20(method,ClassName,element,...) method(ClassName,element),expand_marco(For_19(method,ClassName,__VA_ARGS__)) 45 | #define For_21(method,ClassName,element,...) method(ClassName,element),expand_marco(For_20(method,ClassName,__VA_ARGS__)) 46 | #define For_22(method,ClassName,element,...) method(ClassName,element),expand_marco(For_21(method,ClassName,__VA_ARGS__)) 47 | #define For_23(method,ClassName,element,...) method(ClassName,element),expand_marco(For_22(method,ClassName,__VA_ARGS__)) 48 | #define For_24(method,ClassName,element,...) method(ClassName,element),expand_marco(For_23(method,ClassName,__VA_ARGS__)) 49 | #define For_25(method,ClassName,element,...) method(ClassName,element),expand_marco(For_24(method,ClassName,__VA_ARGS__)) 50 | #define For_26(method,ClassName,element,...) method(ClassName,element),expand_marco(For_25(method,ClassName,__VA_ARGS__)) 51 | #define For_27(method,ClassName,element,...) method(ClassName,element),expand_marco(For_26(method,ClassName,__VA_ARGS__)) 52 | #define For_28(method,ClassName,element,...) method(ClassName,element),expand_marco(For_27(method,ClassName,__VA_ARGS__)) 53 | #define For_29(method,ClassName,element,...) method(ClassName,element),expand_marco(For_28(method,ClassName,__VA_ARGS__)) 54 | #define For_30(method,ClassName,element,...) method(ClassName,element),expand_marco(For_29(method,ClassName,__VA_ARGS__)) 55 | #define For_31(method,ClassName,element,...) method(ClassName,element),expand_marco(For_30(method,ClassName,__VA_ARGS__)) 56 | #define For_32(method,ClassName,element,...) method(ClassName,element),expand_marco(For_31(method,ClassName,__VA_ARGS__)) 57 | #define For_33(method,ClassName,element,...) method(ClassName,element),expand_marco(For_32(method,ClassName,__VA_ARGS__)) 58 | #define For_34(method,ClassName,element,...) method(ClassName,element),expand_marco(For_33(method,ClassName,__VA_ARGS__)) 59 | #define For_35(method,ClassName,element,...) method(ClassName,element),expand_marco(For_34(method,ClassName,__VA_ARGS__)) 60 | #define For_36(method,ClassName,element,...) method(ClassName,element),expand_marco(For_35(method,ClassName,__VA_ARGS__)) 61 | #define For_37(method,ClassName,element,...) method(ClassName,element),expand_marco(For_36(method,ClassName,__VA_ARGS__)) 62 | #define For_38(method,ClassName,element,...) method(ClassName,element),expand_marco(For_37(method,ClassName,__VA_ARGS__)) 63 | #define For_39(method,ClassName,element,...) method(ClassName,element),expand_marco(For_38(method,ClassName,__VA_ARGS__)) 64 | #define For_40(method,ClassName,element,...) method(ClassName,element),expand_marco(For_39(method,ClassName,__VA_ARGS__)) 65 | #define For_41(method,ClassName,element,...) method(ClassName,element),expand_marco(For_40(method,ClassName,__VA_ARGS__)) 66 | #define For_42(method,ClassName,element,...) method(ClassName,element),expand_marco(For_41(method,ClassName,__VA_ARGS__)) 67 | #define For_43(method,ClassName,element,...) method(ClassName,element),expand_marco(For_42(method,ClassName,__VA_ARGS__)) 68 | #define For_44(method,ClassName,element,...) method(ClassName,element),expand_marco(For_43(method,ClassName,__VA_ARGS__)) 69 | #define For_45(method,ClassName,element,...) method(ClassName,element),expand_marco(For_44(method,ClassName,__VA_ARGS__)) 70 | #define For_46(method,ClassName,element,...) method(ClassName,element),expand_marco(For_45(method,ClassName,__VA_ARGS__)) 71 | #define For_47(method,ClassName,element,...) method(ClassName,element),expand_marco(For_46(method,ClassName,__VA_ARGS__)) 72 | #define For_48(method,ClassName,element,...) method(ClassName,element),expand_marco(For_47(method,ClassName,__VA_ARGS__)) 73 | #define For_49(method,ClassName,element,...) method(ClassName,element),expand_marco(For_48(method,ClassName,__VA_ARGS__)) 74 | #define For_50(method,ClassName,element,...) method(ClassName,element),expand_marco(For_49(method,ClassName,__VA_ARGS__)) 75 | #define For_51(method,ClassName,element,...) method(ClassName,element),expand_marco(For_50(method,ClassName,__VA_ARGS__)) 76 | #define For_52(method,ClassName,element,...) method(ClassName,element),expand_marco(For_51(method,ClassName,__VA_ARGS__)) 77 | #define For_53(method,ClassName,element,...) method(ClassName,element),expand_marco(For_52(method,ClassName,__VA_ARGS__)) 78 | #define For_54(method,ClassName,element,...) method(ClassName,element),expand_marco(For_53(method,ClassName,__VA_ARGS__)) 79 | #define For_55(method,ClassName,element,...) method(ClassName,element),expand_marco(For_54(method,ClassName,__VA_ARGS__)) 80 | #define For_56(method,ClassName,element,...) method(ClassName,element),expand_marco(For_55(method,ClassName,__VA_ARGS__)) 81 | #define For_57(method,ClassName,element,...) method(ClassName,element),expand_marco(For_56(method,ClassName,__VA_ARGS__)) 82 | #define For_58(method,ClassName,element,...) method(ClassName,element),expand_marco(For_57(method,ClassName,__VA_ARGS__)) 83 | #define For_59(method,ClassName,element,...) method(ClassName,element),expand_marco(For_58(method,ClassName,__VA_ARGS__)) 84 | #define For_60(method,ClassName,element,...) method(ClassName,element),expand_marco(For_59(method,ClassName,__VA_ARGS__)) 85 | #define For_61(method,ClassName,element,...) method(ClassName,element),expand_marco(For_60(method,ClassName,__VA_ARGS__)) 86 | #define For_62(method,ClassName,element,...) method(ClassName,element),expand_marco(For_61(method,ClassName,__VA_ARGS__)) 87 | #define For_63(method,ClassName,element,...) method(ClassName,element),expand_marco(For_62(method,ClassName,__VA_ARGS__)) 88 | #define For_64(method,ClassName,element,...) method(ClassName,element),expand_marco(For_63(method,ClassName,__VA_ARGS__)) 89 | #define For_65(method,ClassName,element,...) method(ClassName,element),expand_marco(For_64(method,ClassName,__VA_ARGS__)) 90 | #define For_66(method,ClassName,element,...) method(ClassName,element),expand_marco(For_65(method,ClassName,__VA_ARGS__)) 91 | #define For_67(method,ClassName,element,...) method(ClassName,element),expand_marco(For_66(method,ClassName,__VA_ARGS__)) 92 | #define For_68(method,ClassName,element,...) method(ClassName,element),expand_marco(For_67(method,ClassName,__VA_ARGS__)) 93 | #define For_69(method,ClassName,element,...) method(ClassName,element),expand_marco(For_68(method,ClassName,__VA_ARGS__)) 94 | #define For_70(method,ClassName,element,...) method(ClassName,element),expand_marco(For_69(method,ClassName,__VA_ARGS__)) 95 | #define For_71(method,ClassName,element,...) method(ClassName,element),expand_marco(For_70(method,ClassName,__VA_ARGS__)) 96 | #define For_72(method,ClassName,element,...) method(ClassName,element),expand_marco(For_71(method,ClassName,__VA_ARGS__)) 97 | #define For_73(method,ClassName,element,...) method(ClassName,element),expand_marco(For_72(method,ClassName,__VA_ARGS__)) 98 | #define For_74(method,ClassName,element,...) method(ClassName,element),expand_marco(For_73(method,ClassName,__VA_ARGS__)) 99 | #define For_75(method,ClassName,element,...) method(ClassName,element),expand_marco(For_74(method,ClassName,__VA_ARGS__)) 100 | #define For_76(method,ClassName,element,...) method(ClassName,element),expand_marco(For_75(method,ClassName,__VA_ARGS__)) 101 | #define For_77(method,ClassName,element,...) method(ClassName,element),expand_marco(For_76(method,ClassName,__VA_ARGS__)) 102 | #define For_78(method,ClassName,element,...) method(ClassName,element),expand_marco(For_77(method,ClassName,__VA_ARGS__)) 103 | #define For_79(method,ClassName,element,...) method(ClassName,element),expand_marco(For_78(method,ClassName,__VA_ARGS__)) 104 | #define For_80(method,ClassName,element,...) method(ClassName,element),expand_marco(For_79(method,ClassName,__VA_ARGS__)) 105 | #define For_81(method,ClassName,element,...) method(ClassName,element),expand_marco(For_80(method,ClassName,__VA_ARGS__)) 106 | #define For_82(method,ClassName,element,...) method(ClassName,element),expand_marco(For_81(method,ClassName,__VA_ARGS__)) 107 | #define For_83(method,ClassName,element,...) method(ClassName,element),expand_marco(For_82(method,ClassName,__VA_ARGS__)) 108 | #define For_84(method,ClassName,element,...) method(ClassName,element),expand_marco(For_83(method,ClassName,__VA_ARGS__)) 109 | #define For_85(method,ClassName,element,...) method(ClassName,element),expand_marco(For_84(method,ClassName,__VA_ARGS__)) 110 | #define For_86(method,ClassName,element,...) method(ClassName,element),expand_marco(For_85(method,ClassName,__VA_ARGS__)) 111 | #define For_87(method,ClassName,element,...) method(ClassName,element),expand_marco(For_86(method,ClassName,__VA_ARGS__)) 112 | #define For_88(method,ClassName,element,...) method(ClassName,element),expand_marco(For_87(method,ClassName,__VA_ARGS__)) 113 | #define For_89(method,ClassName,element,...) method(ClassName,element),expand_marco(For_88(method,ClassName,__VA_ARGS__)) 114 | #define For_90(method,ClassName,element,...) method(ClassName,element),expand_marco(For_89(method,ClassName,__VA_ARGS__)) 115 | #define For_91(method,ClassName,element,...) method(ClassName,element),expand_marco(For_90(method,ClassName,__VA_ARGS__)) 116 | #define For_92(method,ClassName,element,...) method(ClassName,element),expand_marco(For_91(method,ClassName,__VA_ARGS__)) 117 | #define For_93(method,ClassName,element,...) method(ClassName,element),expand_marco(For_92(method,ClassName,__VA_ARGS__)) 118 | #define For_94(method,ClassName,element,...) method(ClassName,element),expand_marco(For_93(method,ClassName,__VA_ARGS__)) 119 | #define For_95(method,ClassName,element,...) method(ClassName,element),expand_marco(For_94(method,ClassName,__VA_ARGS__)) 120 | #define For_96(method,ClassName,element,...) method(ClassName,element),expand_marco(For_95(method,ClassName,__VA_ARGS__)) 121 | #define For_97(method,ClassName,element,...) method(ClassName,element),expand_marco(For_96(method,ClassName,__VA_ARGS__)) 122 | #define For_98(method,ClassName,element,...) method(ClassName,element),expand_marco(For_97(method,ClassName,__VA_ARGS__)) 123 | #define For_99(method,ClassName,element,...) method(ClassName,element),expand_marco(For_98(method,ClassName,__VA_ARGS__)) 124 | #define For_100(method,ClassName,element,...) method(ClassName,element),expand_marco(For_99(method,ClassName,__VA_ARGS__)) 125 | #define For_101(method,ClassName,element,...) method(ClassName,element),expand_marco(For_100(method,ClassName,__VA_ARGS__)) 126 | #define For_102(method,ClassName,element,...) method(ClassName,element),expand_marco(For_101(method,ClassName,__VA_ARGS__)) 127 | #define For_103(method,ClassName,element,...) method(ClassName,element),expand_marco(For_102(method,ClassName,__VA_ARGS__)) 128 | #define For_104(method,ClassName,element,...) method(ClassName,element),expand_marco(For_103(method,ClassName,__VA_ARGS__)) 129 | #define For_105(method,ClassName,element,...) method(ClassName,element),expand_marco(For_104(method,ClassName,__VA_ARGS__)) 130 | #define For_106(method,ClassName,element,...) method(ClassName,element),expand_marco(For_105(method,ClassName,__VA_ARGS__)) 131 | #define For_107(method,ClassName,element,...) method(ClassName,element),expand_marco(For_106(method,ClassName,__VA_ARGS__)) 132 | #define For_108(method,ClassName,element,...) method(ClassName,element),expand_marco(For_107(method,ClassName,__VA_ARGS__)) 133 | #define For_109(method,ClassName,element,...) method(ClassName,element),expand_marco(For_108(method,ClassName,__VA_ARGS__)) 134 | #define For_110(method,ClassName,element,...) method(ClassName,element),expand_marco(For_109(method,ClassName,__VA_ARGS__)) 135 | #define For_111(method,ClassName,element,...) method(ClassName,element),expand_marco(For_110(method,ClassName,__VA_ARGS__)) 136 | #define For_112(method,ClassName,element,...) method(ClassName,element),expand_marco(For_111(method,ClassName,__VA_ARGS__)) 137 | #define For_113(method,ClassName,element,...) method(ClassName,element),expand_marco(For_112(method,ClassName,__VA_ARGS__)) 138 | #define For_114(method,ClassName,element,...) method(ClassName,element),expand_marco(For_113(method,ClassName,__VA_ARGS__)) 139 | #define For_115(method,ClassName,element,...) method(ClassName,element),expand_marco(For_114(method,ClassName,__VA_ARGS__)) 140 | #define For_116(method,ClassName,element,...) method(ClassName,element),expand_marco(For_115(method,ClassName,__VA_ARGS__)) 141 | #define For_117(method,ClassName,element,...) method(ClassName,element),expand_marco(For_116(method,ClassName,__VA_ARGS__)) 142 | #define For_118(method,ClassName,element,...) method(ClassName,element),expand_marco(For_117(method,ClassName,__VA_ARGS__)) 143 | #define For_119(method,ClassName,element,...) method(ClassName,element),expand_marco(For_118(method,ClassName,__VA_ARGS__)) 144 | #define For_120(method,ClassName,element,...) method(ClassName,element),expand_marco(For_119(method,ClassName,__VA_ARGS__)) 145 | #define For_121(method,ClassName,element,...) method(ClassName,element),expand_marco(For_120(method,ClassName,__VA_ARGS__)) 146 | #define For_122(method,ClassName,element,...) method(ClassName,element),expand_marco(For_121(method,ClassName,__VA_ARGS__)) 147 | #define For_123(method,ClassName,element,...) method(ClassName,element),expand_marco(For_122(method,ClassName,__VA_ARGS__)) 148 | #define For_124(method,ClassName,element,...) method(ClassName,element),expand_marco(For_123(method,ClassName,__VA_ARGS__)) 149 | #define For_125(method,ClassName,element,...) method(ClassName,element),expand_marco(For_124(method,ClassName,__VA_ARGS__)) 150 | 151 | #define address_macro(Class,Element) &Class::Element 152 | #define element_name_macro(Class,Element) #Element 153 | 154 | #define GENERATOR_META(N,ClassName,...) \ 155 | static std::array ClassName##_element_name_arr = { expand_marco(concat_a_b(For_,N)(element_name_macro,ClassName,__VA_ARGS__)) }; \ 156 | struct ClassName##_meta_info \ 157 | { \ 158 | auto get_element_names()-> std::array \ 159 | { \ 160 | return ClassName##_element_name_arr; \ 161 | } \ 162 | auto get_element_meta_protype()->decltype(std::make_tuple(expand_marco(concat_a_b(For_,N)(address_macro,ClassName,__VA_ARGS__)))) \ 163 | { \ 164 | return std::make_tuple(expand_marco(concat_a_b(For_,N)(address_macro,ClassName,__VA_ARGS__))); \ 165 | } \ 166 | std::string get_class_name() \ 167 | { \ 168 | return #ClassName ; \ 169 | } \ 170 | constexpr std::size_t element_size() { return N; } \ 171 | }; \ 172 | static auto meta_info_reflect(ClassName const& t)->ClassName##_meta_info \ 173 | { \ 174 | return ClassName##_meta_info{}; \ 175 | } 176 | #define REFLECTION(ClassName,...) GENERATOR_META(get_count(__VA_ARGS__),ClassName,__VA_ARGS__) 177 | 178 | template 179 | using void_t = void; 180 | 181 | template 182 | struct is_reflect_class :std::false_type 183 | { 184 | 185 | }; 186 | 187 | template 188 | struct is_reflect_class()))>> :std::true_type 189 | { 190 | 191 | }; 192 | 193 | template 194 | struct each_ 195 | { 196 | template 197 | static void each(name_tuple&& tuple0, protype_tuple&& tuple1, T&& t, Function&& callback) 198 | { 199 | callback(std::forward(t), std::get(tuple0), std::get(tuple1)); 200 | each_::template each(std::forward(tuple0), std::forward(tuple1), std::forward(t), std::forward(callback)); 201 | } 202 | }; 203 | 204 | template 205 | struct each_ 206 | { 207 | template 208 | static void each(name_tuple&& tuple0, protype_tuple&& tuple1, T&& t, Function&& callback) 209 | { 210 | 211 | } 212 | }; 213 | 214 | template 215 | struct each_1 216 | { 217 | template 218 | static void each(name_tuple&& tuple0, protype_tuple&& tuple1, std::string const& name, T&& t, Function&& callback) 219 | { 220 | if (name == std::get(tuple0)) { 221 | callback(std::forward(t), std::get(tuple0), std::get(tuple1)); 222 | } 223 | each_1::template each(std::forward(tuple0), std::forward(tuple1), name, std::forward(t), std::forward(callback)); 224 | } 225 | }; 226 | 227 | template 228 | struct each_1 229 | { 230 | template 231 | static void each(name_tuple&& tuple0, protype_tuple&& tuple1, std::string const& name, T&& t, Function&& callback) 232 | { 233 | 234 | } 235 | }; 236 | 237 | template 238 | typename std::enable_if::type>::value>::type each_object(T&& t, Function&& callback) 239 | { 240 | using class_type = typename std::remove_reference::type; 241 | using meta_info_type = decltype(meta_info_reflect(std::declval())); 242 | auto meta = meta_info_type{}; 243 | each_<0, meta.element_size()>::template each(meta.get_element_names(), meta.get_element_meta_protype(), std::forward(t), std::forward(callback)); 244 | } 245 | 246 | template 247 | typename std::enable_if::type>::value>::type find_protype(std::string const& name, T&& t, Function&& callback) 248 | { 249 | using class_type = typename std::remove_reference::type; 250 | using meta_info_type = decltype(meta_info_reflect(std::declval())); 251 | auto meta = meta_info_type{}; 252 | each_1<0, meta.element_size()>::template each(meta.get_element_names(), meta.get_element_meta_protype(), name, std::forward(t), std::forward(callback)); 253 | } 254 | 255 | } -------------------------------------------------------------------------------- /xorm/mysql.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef XORM_ENABLE_MYSQL 3 | #ifdef _WIN32 4 | #include 5 | #else 6 | #include 7 | #endif // __LINUX__ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "reflect/reflector.hpp" 17 | #include "data_type.hpp" 18 | #include "meta_utility.hpp" 19 | #include "dbconfig.hpp" 20 | #include "db_utils.hpp" 21 | namespace xorm { 22 | 23 | template 24 | struct auto_params_lambda0 { 25 | auto_params_lambda0(std::stringstream& ss_, int& index_, std::size_t size_, std::string& value_place_, MYSQL_BIND* bind_, T0* that) :ss(ss_), index(index_), size(size_), value_place(value_place_), bind(bind_), this_(that) { 26 | 27 | } 28 | template 29 | void operator()(T&& obj, U&& name, Y&& field) { 30 | this_->bind_value((obj.*field), bind[index]); 31 | if (index < (size - 1)) { 32 | ss << "`" << name << "` " << ","; 33 | value_place.append("?,"); 34 | } 35 | else if (index == (size - 1)) { 36 | ss << "`" << name << "` "; 37 | value_place.append("?"); 38 | } 39 | ++index; 40 | } 41 | std::stringstream& ss; 42 | int& index; 43 | std::size_t size; 44 | std::string& value_place; 45 | MYSQL_BIND* bind; 46 | T0* this_; 47 | }; 48 | 49 | template 50 | struct auto_params_lambda1 { 51 | auto_params_lambda1(std::stringstream& ss_, int& index_, std::size_t size_, MYSQL_BIND* bind_, T0* that) :ss(ss_), index(index_), size(size_), bind(bind_), this_(that) { 52 | 53 | } 54 | template 55 | void operator()(T&& obj, U&& name, Y&& field) { 56 | this_->bind_value((obj.*field), bind[index]); 57 | if (index < (size - 1)) { 58 | ss << "`" << name << "`" << "=?" << ","; 59 | } 60 | else if (index == (size - 1)) { 61 | ss << "`" << name << "`" << "=?"; 62 | } 63 | ++index; 64 | } 65 | std::stringstream& ss; 66 | int& index; 67 | std::size_t size; 68 | MYSQL_BIND* bind; 69 | T0* this_; 70 | }; 71 | template 72 | struct auto_params_lambda2 { 73 | auto_params_lambda2(int& index_, MYSQL_BIND* bind_, T0* that) :index(index_), bind(bind_), this_(that) { 74 | 75 | } 76 | template 77 | void operator()(T&& obj, U&& name, Y&& field) { 78 | this_->bind_value((obj.*field), bind[index], true); 79 | ++index; 80 | } 81 | int& index; 82 | MYSQL_BIND* bind; 83 | T0* this_; 84 | }; 85 | template 86 | struct auto_params_lambda3 { 87 | auto_params_lambda3(T0* that, Object& copy_v_) : this_(that), copy_v(copy_v_) { 88 | 89 | } 90 | template 91 | void operator()(T&& obj, U&& name, Y&& field) { 92 | this_->clear_field((obj.*field), (copy_v.*field), index_, index_blob_); 93 | } 94 | T0* this_; 95 | Object& copy_v; 96 | std::size_t index_ = 0; 97 | std::size_t index_blob_ = 0; 98 | }; 99 | template 100 | struct auto_params_lambda4 { 101 | auto_params_lambda4(int& index_, MYSQL_BIND* bind_, T0* that) :index(index_), bind(bind_), this_(that) { 102 | 103 | } 104 | template 105 | void operator()(T& v) { 106 | this_->bind_value(v, bind[index], true); 107 | ++index; 108 | } 109 | int& index; 110 | MYSQL_BIND* bind; 111 | T0* this_; 112 | }; 113 | template 114 | struct auto_params_lambda5 { 115 | auto_params_lambda5(MYSQL_BIND* bind_, T0* that) : bind(bind_), this_(that) { 116 | 117 | } 118 | template 119 | void operator()(T& v, U& u) { 120 | this_->clear_field(v, u, index_, index_blob_); 121 | } 122 | MYSQL_BIND* bind; 123 | T0* this_; 124 | std::size_t index_ = 0; 125 | std::size_t index_blob_ = 0; 126 | }; 127 | template 128 | class stmt_guard { 129 | public: 130 | template 131 | stmt_guard(U&& resource) :resource_(std::forward(resource)) { 132 | 133 | } 134 | public: 135 | ~stmt_guard() { 136 | if (resource_ != nullptr) { 137 | mysql_stmt_close(resource_); 138 | } 139 | } 140 | private: 141 | T* resource_ = nullptr; 142 | }; 143 | class string_size_vec_clear { 144 | public: 145 | string_size_vec_clear(std::vector& vec):vec_(vec){ 146 | vec_.clear(); 147 | } 148 | ~string_size_vec_clear() { 149 | vec_.clear(); 150 | } 151 | private: 152 | std::vector& vec_; 153 | }; 154 | class mysql final { 155 | template 156 | friend struct auto_params_lambda0; 157 | template 158 | friend struct auto_params_lambda1; 159 | template 160 | friend struct auto_params_lambda2; 161 | template 162 | friend struct auto_params_lambda3; 163 | template 164 | friend struct auto_params_lambda4; 165 | template 166 | friend struct auto_params_lambda5; 167 | public: 168 | using Integer = FundamentionType; 169 | using Float = FundamentionType; 170 | using Double = FundamentionType; 171 | using BigInt = FundamentionType; 172 | using SmallInt = FundamentionType; 173 | using TinyInt = FundamentionType; 174 | using MysqlDate = TimeDate; 175 | using MysqlDateTime = TimeDate; 176 | using MysqlTime = TimeDate; 177 | using Blob = std::vector; 178 | private: 179 | template 180 | typename std::enable_if::type>::value || is_date_type::type>::value, bool>::type bind_value(T & t, MYSQL_BIND & bind, bool get = false) { 181 | using type = typename std::remove_reference::type; 182 | bind.buffer_type = type::field_type; 183 | bind.buffer = t.buffer(); 184 | bind.is_null = t.null_buffer(); 185 | bind.length = 0; 186 | //bind.buffer_length = 0; 187 | return true; 188 | } 189 | template 190 | typename std::enable_if::type, std::string>::value,bool>::type bind_value(T& t, MYSQL_BIND& bind, bool get = false) { 191 | if (get) { 192 | record_string_size_.push_back(0); 193 | auto& data = record_string_size_.back(); 194 | bind.length = &data; 195 | t.resize(string_max_size_); 196 | } 197 | else { 198 | bind.length = nullptr; 199 | } 200 | bind.buffer_type = MYSQL_TYPE_STRING; 201 | bind.buffer = &(t[0]); 202 | bind.is_null = 0; 203 | bind.buffer_length = (unsigned long)t.size(); 204 | return true; 205 | } 206 | 207 | template //blob 208 | typename std::enable_if::type, Blob>::value, bool>::type bind_value(T& t, MYSQL_BIND& bind, bool get = false) { 209 | if (get) { 210 | record_blob_size_.push_back(0); 211 | auto& data = record_blob_size_.back(); 212 | bind.length = &data; 213 | t.resize(blob_max_size_); 214 | } 215 | else { 216 | bind.length = nullptr; 217 | } 218 | bind.buffer_type = MYSQL_TYPE_LONG_BLOB; 219 | bind.buffer = t.empty()? nullptr:&(t[0]); 220 | bind.is_null = 0; 221 | bind.buffer_length = (unsigned long)t.size(); 222 | return true; 223 | } 224 | 225 | template 226 | typename std::enable_if::type, std::string>::value>::type clear_field(T& t, U& v,std::size_t& index, std::size_t& index_blob) { 227 | auto& size = record_string_size_[index]; 228 | index++; 229 | if (size != 0) { 230 | v = std::string(&t[0], size); 231 | } 232 | else { 233 | v = std::string(); 234 | } 235 | size = 0; 236 | //memset(&t[0], 0, t.size()); no use, optimized by record_string_size_ 237 | } 238 | 239 | template //blob 240 | typename std::enable_if::type, Blob>::value>::type clear_field(T& t, U& v, std::size_t& index, std::size_t& index_blob) { 241 | auto& size = record_blob_size_[index_blob]; 242 | index_blob++; 243 | if (size != 0) { 244 | auto begin = &t[0]; 245 | v = Blob(begin, begin + size); 246 | } 247 | else { 248 | v = Blob(); 249 | } 250 | size = 0; 251 | //memset(&t[0], 0, t.size()); no use, optimized by record_string_size_ 252 | } 253 | 254 | template 255 | typename std::enable_if::type, std::string>::value && !std::is_same::type, Blob>::value>::type clear_field(T& t, U& v, std::size_t& index, std::size_t& index_blob) { 256 | v = t; 257 | t.clear(); 258 | } 259 | public: 260 | mysql() { 261 | init_error_default_callback(); 262 | } 263 | mysql(dataBaseConfig const& config, std::function const& error_callback = nullptr) { 264 | if (error_callback == nullptr) { 265 | init_error_default_callback(); 266 | } 267 | else { 268 | error_callback_ = error_callback; 269 | } 270 | connect(config); 271 | } 272 | ~mysql() { 273 | disconnect(); 274 | } 275 | private: 276 | void init_error_default_callback() { 277 | error_callback_ = [](std::string const& message) { 278 | std::cout << message << "\n"; 279 | }; 280 | } 281 | public: 282 | void connect(dataBaseConfig const& config) { 283 | db_index_key_ = config.index_key; 284 | bool is_success = false; 285 | if (0 == mysql_server_init(0, nullptr, nullptr)) { 286 | is_success = true; 287 | } 288 | conn_ = mysql_init(nullptr); 289 | if (nullptr != conn_) { 290 | is_success = true; 291 | mysql_options(conn_, MYSQL_OPT_RECONNECT, &config.reconnect_number); 292 | mysql_options(conn_, MYSQL_SET_CHARSET_NAME, config.character_encoding.data()); 293 | } 294 | 295 | if (config.timeout > 0) { 296 | if (mysql_options(conn_, MYSQL_OPT_CONNECT_TIMEOUT, &config.timeout) != 0) { 297 | is_success = false; 298 | } 299 | else { 300 | is_success = true; 301 | } 302 | } 303 | 304 | if (is_success && nullptr != mysql_real_connect(conn_, config.host.c_str(), config.user.c_str(), config.password.c_str(), config.dbname.c_str(), config.port, nullptr, 0)) { 305 | is_connect_ = true; 306 | } 307 | else { 308 | trigger_error(mysql_error(conn_)); 309 | } 310 | } 311 | void reconnect(dataBaseConfig const& config) { 312 | disconnect(); 313 | connect(config); 314 | } 315 | 316 | void disconnect() { 317 | if (conn_ != nullptr) { 318 | mysql_close(conn_); 319 | conn_ = nullptr; 320 | is_connect_ = false; 321 | } 322 | } 323 | bool is_connect() { 324 | return conn_ != nullptr && is_connect_; 325 | } 326 | 327 | bool ping() { 328 | if (conn_ == nullptr) { 329 | is_connect_ = false; 330 | return false; 331 | } 332 | bool r = mysql_ping(conn_) == 0; 333 | if (!r) { 334 | is_connect_ = false; 335 | } 336 | return r; 337 | } 338 | public: 339 | template 340 | typename std::enable_if::type>::value, db_result>::type insert(T&& t) { 341 | auto meta = meta_info_reflect(t); 342 | std::string tablename = meta.get_class_name(); 343 | std::stringstream ss; 344 | ss << "INSERT INTO `" << tablename << "` ("; 345 | auto size = meta.element_size(); 346 | int index = 0; 347 | std::string value_place = ""; 348 | MYSQL_BIND bind[meta.element_size()]; 349 | memset(bind, 0, sizeof(bind)); 350 | auto_params_lambda0 lambda{ ss ,index ,size ,value_place ,bind,this }; 351 | reflector::each_object(std::forward(t), lambda); 352 | ss << ")" << " VALUES(" << value_place << ")"; 353 | return stmt_execute(ss.str(), bind); 354 | } 355 | 356 | template 357 | typename std::enable_if::type>::value, db_result>::type del(std::string const& condition,U&&...args) { 358 | //static_assert((sizeof...(args)) != 0, "require at least one argument!!!"); 359 | auto meta = meta_info_reflect(T{}); 360 | MYSQL_BIND bind[sizeof...(args)+1]; //0 argument will be ill-formed 361 | std::string sql = "DELETE FROM `" + meta.get_class_name() + "` " + condition; 362 | auto tp = std::make_tuple(std::forward(args)...); 363 | expand_bind_value(bind, tp, xorm_utils::make_index_package{}); 364 | return stmt_execute(sql, bind); 365 | } 366 | 367 | template 368 | typename std::enable_if::type>::value, db_result>::type update(T&& v) { 369 | auto meta = meta_info_reflect(v); 370 | std::string tablename = meta.get_class_name(); 371 | std::stringstream ss; 372 | MYSQL_BIND bind[meta.element_size()]; 373 | memset(bind, 0, sizeof(bind)); 374 | ss << "replace into `" << tablename << "` ("; 375 | auto size = meta.element_size(); 376 | int index = 0; 377 | std::string value_place = ""; 378 | auto_params_lambda0 lambda{ ss ,index ,size ,value_place ,bind,this }; 379 | reflector::each_object(std::forward(v), lambda); 380 | ss << ")" << " VALUES(" << value_place << ")"; 381 | return stmt_execute(ss.str(), bind); 382 | } 383 | 384 | void void_parameter_content(...) { 385 | 386 | } 387 | 388 | template 389 | void expand_bind_value(Bind&& bind,std::tuple& tp, xorm_utils::index_package) { 390 | void_parameter_content(bind_value(std::get(tp), bind[Indexs])...); 391 | } 392 | 393 | template 394 | void expand_bind_value(Bind&& bind, std::tuple<>& tp, xorm_utils::index_package) { 395 | 396 | } 397 | 398 | template 399 | db_result update(std::string const& sql,T&&...args) { 400 | //static_assert((sizeof...(args)) != 0, "require at least one argument!!!"); 401 | MYSQL_BIND bind[sizeof...(args)+1]; //0 argument will be ill-formed 402 | auto tp = std::make_tuple(std::forward(args)...); 403 | expand_bind_value(bind, tp, xorm_utils::make_index_package{}); 404 | return stmt_execute(sql, bind); 405 | } 406 | 407 | //template 408 | //typename std::enable_if::type>::value, std::pair>::type update(T&& v, std::string const& condition) { 409 | // auto meta = meta_info_reflect(v); 410 | // std::string tablename = meta.get_class_name(); 411 | // std::stringstream ss; 412 | // MYSQL_BIND bind[meta.element_size()]; 413 | // memset(bind, 0, sizeof(bind)); 414 | // ss << "UPDATE `" << tablename << "` SET "; 415 | // auto size = meta.element_size(); 416 | // int index = 0; 417 | // auto_params_lambda1 lambda1{ ss ,index ,size ,bind ,this }; 418 | // reflector::each_object(std::forward(v), lambda1); 419 | // ss << " " << condition; 420 | // auto r = stmt_execute(ss.str(), bind); 421 | // return { r.first != 0,r.first }; 422 | //} 423 | 424 | template 425 | typename std::enable_if::type>::value, db_result>::type query(std::string const& condition , Params&&...params) { 426 | auto meta = meta_info_reflect(T{}); 427 | std::string tablename = meta.get_class_name(); 428 | std::stringstream ss; 429 | MYSQL_BIND bind[meta.element_size()]; 430 | MYSQL_BIND bind_params[sizeof...(params) + 1]; //0 will ill-formed 431 | auto tp = std::make_tuple(std::forward(params)...); 432 | expand_bind_value(bind_params, tp, xorm_utils::make_index_package{}); 433 | memset(bind, 0, sizeof(bind)); 434 | auto name_arr = meta.get_element_names(); 435 | ss << "SELECT "; 436 | auto size = name_arr.size(); 437 | for (std::size_t index = 0; index < size; index++) { 438 | ss << "`" << name_arr[index] << "` "; 439 | if (index < (size - 1)) { 440 | ss << ","; 441 | } 442 | } 443 | ss << " FROM `" << tablename << "` " << condition; 444 | MYSQL_STMT* pStmt = mysql_stmt_init(conn_); 445 | stmt_guard guard(pStmt); 446 | string_size_vec_clear string_guard{ record_string_size_ }; 447 | string_size_vec_clear blob_guard{ record_blob_size_ }; 448 | record_string_size_.reserve(meta.element_size()*2); 449 | record_blob_size_.reserve(meta.element_size() * 2); 450 | db_result dbresult; 451 | if (pStmt != nullptr) { 452 | auto sqlStr = ss.str(); 453 | int iRet = mysql_stmt_prepare(pStmt, sqlStr.c_str(), (unsigned long)sqlStr.size()); 454 | if (iRet == 0) { 455 | iRet = mysql_stmt_bind_param(pStmt, bind_params); 456 | if (iRet != 0) { 457 | std::string error_message = mysql_error(conn_); 458 | trigger_error(error_message); 459 | dbresult.success = false; 460 | dbresult.error.is_error_ = true; 461 | dbresult.error.message_ = error_message; 462 | return dbresult; 463 | } 464 | T tmp{}; 465 | int index = 0; 466 | auto_params_lambda2 lambda{ index ,bind ,this }; 467 | reflector::each_object(tmp, lambda); 468 | bool r = mysql_stmt_bind_result(pStmt, bind); 469 | if (!r) { 470 | r = mysql_stmt_execute(pStmt); 471 | r |= mysql_stmt_store_result(pStmt) != 0; 472 | if (!r) { 473 | while (mysql_stmt_fetch(pStmt) == 0) { 474 | T copy_v{}; 475 | auto_params_lambda3 lambda3{ this,copy_v }; 476 | reflector::each_object(tmp, lambda3); 477 | dbresult.results.emplace_back(std::move(copy_v)); 478 | } 479 | dbresult.success = true; 480 | return dbresult; 481 | } 482 | else { 483 | std::string error_message = mysql_error(conn_); 484 | trigger_error(error_message); 485 | dbresult.success = false; 486 | dbresult.error.is_error_ = true; 487 | dbresult.error.message_ = error_message; 488 | return dbresult; 489 | } 490 | } 491 | else { 492 | std::string error_message = mysql_error(conn_); 493 | trigger_error(error_message); 494 | dbresult.success = false; 495 | dbresult.error.is_error_ = true; 496 | dbresult.error.message_ = error_message; 497 | return dbresult; 498 | } 499 | } 500 | else { 501 | std::string error_message = mysql_error(conn_); 502 | trigger_error(error_message); 503 | dbresult.success = false; 504 | dbresult.error.is_error_ = true; 505 | dbresult.error.message_ = error_message; 506 | return dbresult; 507 | } 508 | } 509 | dbresult.success = false; 510 | return dbresult; 511 | } 512 | 513 | template 514 | typename std::enable_if::value, db_result>::type query(std::string const& sqlStr ,Params&& ...params) { 515 | constexpr std::size_t tuple_size = std::tuple_size::value; 516 | MYSQL_BIND bind[tuple_size]; 517 | MYSQL_BIND bind_params[sizeof...(params) + 1]; //0 will ill-formed 518 | auto tp = std::make_tuple(std::forward(params)...); 519 | expand_bind_value(bind_params, tp, xorm_utils::make_index_package{}); 520 | memset(bind, 0, sizeof(bind)); 521 | MYSQL_STMT* pStmt = mysql_stmt_init(conn_); 522 | stmt_guard guard(pStmt); 523 | string_size_vec_clear string_guard{ record_string_size_ }; 524 | string_size_vec_clear blob_guard{ record_blob_size_ }; 525 | record_string_size_.reserve(tuple_size*2); 526 | record_blob_size_.reserve(tuple_size*2); 527 | db_result dbresult; 528 | if (pStmt != nullptr) { 529 | int iRet = mysql_stmt_prepare(pStmt, sqlStr.c_str(), (unsigned long)sqlStr.size()); 530 | if (iRet == 0) { 531 | iRet = mysql_stmt_bind_param(pStmt, bind_params); 532 | if (iRet != 0) { 533 | std::string error_message = mysql_error(conn_); 534 | trigger_error(error_message); 535 | dbresult.success = false; 536 | dbresult.error.is_error_ = true; 537 | dbresult.error.message_ = error_message; 538 | return dbresult; 539 | } 540 | T tmp{}; 541 | int index = 0; 542 | auto_params_lambda4 lambda4{ index ,bind,this }; 543 | each_tuple<0, tuple_size>::each(tmp, lambda4); 544 | bool r = mysql_stmt_bind_result(pStmt, bind); 545 | if (!r) { 546 | r = mysql_stmt_execute(pStmt); 547 | r |= mysql_stmt_store_result(pStmt) != 0; 548 | if (!r) { 549 | while (mysql_stmt_fetch(pStmt) == 0) { 550 | T copy_v{}; 551 | auto_params_lambda5 lambda5{ bind ,this }; 552 | each_tuple<0, tuple_size>::each2(tmp, copy_v, lambda5); 553 | dbresult.results.emplace_back(std::move(copy_v)); 554 | } 555 | dbresult.success = true; 556 | return dbresult; 557 | } 558 | else { 559 | std::string error_message = mysql_error(conn_); 560 | trigger_error(error_message); 561 | dbresult.success = false; 562 | dbresult.error.is_error_ = true; 563 | dbresult.error.message_ = error_message; 564 | return dbresult; 565 | } 566 | } 567 | else { 568 | std::string error_message = mysql_error(conn_); 569 | trigger_error(error_message); 570 | dbresult.success = false; 571 | dbresult.error.is_error_ = true; 572 | dbresult.error.message_ = error_message; 573 | return dbresult; 574 | } 575 | } 576 | else { 577 | std::string error_message = mysql_error(conn_); 578 | trigger_error(error_message); 579 | dbresult.success = false; 580 | dbresult.error.is_error_ = true; 581 | dbresult.error.message_ = error_message; 582 | return dbresult; 583 | } 584 | } 585 | dbresult.success = false; 586 | return dbresult; 587 | } 588 | 589 | db_result execute(std::string const& sql) { 590 | db_result dbresult; 591 | auto iRet = mysql_query(conn_, sql.c_str()); 592 | bool r = iRet != 0 ? false : true; 593 | if (r) { 594 | dbresult.success = true; 595 | auto pRes = mysql_use_result(conn_); 596 | mysql_free_result(pRes); 597 | } 598 | else { 599 | std::string message = mysql_error(conn_); 600 | trigger_error(message); 601 | dbresult.success = false; 602 | dbresult.error.is_error_ = true; 603 | dbresult.error.message_ = message; 604 | } 605 | return dbresult; 606 | } 607 | 608 | db_result execute(std::string const& sql, std::function const& data_callback) { 609 | auto iRet = mysql_query(conn_, sql.c_str()); 610 | db_result dbresult; 611 | bool r = iRet != 0 ? false : true; 612 | if (r) { 613 | dbresult.success = true; 614 | auto pRes = mysql_store_result(conn_); 615 | data_callback(pRes); 616 | mysql_free_result(pRes); 617 | } 618 | else { 619 | std::string message = mysql_error(conn_); 620 | trigger_error(message); 621 | data_callback(nullptr); 622 | dbresult.success = false; 623 | dbresult.error.is_error_ = true; 624 | dbresult.error.message_ = message; 625 | } 626 | return dbresult; 627 | } 628 | 629 | std::uint64_t get_affected_rows() { 630 | return mysql_affected_rows(conn_); 631 | } 632 | 633 | db_result begin() { 634 | return execute("BEGIN"); 635 | } 636 | db_result commit() { 637 | return execute("COMMIT"); 638 | } 639 | db_result rollback() { 640 | return execute("ROLLBACK"); 641 | } 642 | void set_max_string_size(std::size_t size) { 643 | string_max_size_ = size; 644 | } 645 | std::size_t get_max_string_size() { 646 | return string_max_size_; 647 | } 648 | void set_max_blob_size(std::size_t size) { 649 | blob_max_size_ = size; 650 | } 651 | std::size_t get_max_blob_size() { 652 | return blob_max_size_; 653 | } 654 | private: 655 | db_result stmt_execute(std::string const& sqlStr, MYSQL_BIND* bind) { 656 | MYSQL_STMT* pStmt = mysql_stmt_init(conn_); 657 | stmt_guard guard(pStmt); 658 | db_result result; 659 | if (pStmt != nullptr) { 660 | //begin(); 661 | int iRet = mysql_stmt_prepare(pStmt, sqlStr.data(), (unsigned long)sqlStr.size()); 662 | if (iRet == 0) { 663 | iRet = mysql_stmt_bind_param(pStmt, bind); 664 | if (iRet == 0) { 665 | iRet = mysql_stmt_execute(pStmt); 666 | if (iRet == 0) { 667 | auto rows = mysql_stmt_affected_rows(pStmt); 668 | //bool cr = commit(); 669 | auto key_id = mysql_insert_id(conn_); 670 | result.success = true; 671 | result.affect_rows = rows; 672 | result.unique_id = key_id; 673 | return result; 674 | } 675 | else { 676 | std::string error_message = mysql_error(conn_); 677 | trigger_error(error_message); 678 | result.affect_rows = 0; 679 | result.success = false; 680 | result.unique_id = 0; 681 | result.error.is_error_ = true; 682 | result.error.message_ = error_message; 683 | return result; 684 | } 685 | } 686 | else { 687 | std::string error_message = mysql_error(conn_); 688 | trigger_error(error_message); 689 | result.affect_rows = 0; 690 | result.success = false; 691 | result.unique_id = 0; 692 | result.error.is_error_ = true; 693 | result.error.message_ = error_message; 694 | return result; 695 | } 696 | } 697 | else { 698 | std::string error_message = mysql_error(conn_); 699 | trigger_error(error_message); 700 | result.affect_rows = 0; 701 | result.success = false; 702 | result.unique_id = 0; 703 | result.error.is_error_ = true; 704 | result.error.message_ = error_message; 705 | return result; 706 | } 707 | //rollback(); 708 | } 709 | return result; 710 | } 711 | public: 712 | void set_error_callback(std::function const& callback) { 713 | if (callback != nullptr) { 714 | error_callback_ = callback; 715 | } 716 | } 717 | void trigger_error(std::string const& message) { 718 | if (error_callback_ != nullptr) { 719 | error_callback_("db_index: "+ db_index_key_+ " , error: "+ message); 720 | } 721 | } 722 | MYSQL* get_raw_connetion() { 723 | return is_connect_ == true ? conn_ : nullptr; 724 | } 725 | private: 726 | MYSQL* conn_ = nullptr; 727 | bool is_connect_ = false; 728 | std::size_t string_max_size_ = 1024 * 1024; 729 | std::size_t blob_max_size_ = 3* 1024 * 1024; 730 | std::function error_callback_; 731 | std::vector record_string_size_; 732 | std::vector record_blob_size_; 733 | std::string db_index_key_; 734 | }; 735 | } 736 | #endif // ENABLE_MYSQL --------------------------------------------------------------------------------