github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/3rd_party/fflib/include/ff/sql/mysql.hpp (about) 1 /*********************************************** 2 The MIT License (MIT) 3 4 Copyright (c) 2012 Athrun Arthur <athrunarthur@gmail.com> 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 *************************************************/ 24 #pragma once 25 26 #include "ff/sql/engine.h" 27 #include "ff/sql/rows.h" 28 #include "ff/sql/table.h" 29 #include <cppconn/driver.h> 30 #include <cppconn/exception.h> 31 #include <cppconn/prepared_statement.h> 32 #include <cppconn/resultset.h> 33 #include <cppconn/statement.h> 34 #include <sstream> 35 #include <thread> 36 37 namespace ff { 38 namespace sql { 39 40 41 template<class STMT, class T> struct mysql_bind_setter{ 42 static void bind(STMT , int , const T& ){ 43 throw std::runtime_error("No support yet"); 44 } 45 }; 46 #define impl_mysql_bind_setter(type, method) \ 47 template<class STMT> \ 48 struct mysql_bind_setter<STMT, type>{ \ 49 static void bind(STMT stmt, int index, const type & value){ \ 50 stmt->method(index, value); \ 51 } \ 52 }; 53 impl_mysql_bind_setter(std::string, setString); 54 impl_mysql_bind_setter(int8_t, setInt); 55 impl_mysql_bind_setter(uint8_t, setUInt); 56 impl_mysql_bind_setter(int16_t, setInt); 57 impl_mysql_bind_setter(uint16_t, setUInt); 58 impl_mysql_bind_setter(int32_t, setInt); 59 impl_mysql_bind_setter(uint32_t, setUInt); 60 impl_mysql_bind_setter(int64_t, setInt64); 61 impl_mysql_bind_setter(uint64_t, setUInt64); 62 impl_mysql_bind_setter(double, setDouble); 63 impl_mysql_bind_setter(float, setDouble); 64 #undef impl_mysql_bind_setter 65 66 template<class T> 67 struct mysql_rs_getter{}; 68 #define impl_mysql_rs_getter(type, method) \ 69 template<> \ 70 struct mysql_rs_getter<type>{ \ 71 template <typename RST> \ 72 static type get(RST r, const std::string & name){ \ 73 return r->method(name); \ 74 } \ 75 }; \ 76 77 impl_mysql_rs_getter(std::string, getString); 78 impl_mysql_rs_getter(double, getDouble); 79 impl_mysql_rs_getter(float, getDouble); 80 impl_mysql_rs_getter(int64_t, getInt64); 81 impl_mysql_rs_getter(uint64_t, getUInt64); 82 impl_mysql_rs_getter(int32_t, getInt); 83 impl_mysql_rs_getter(uint32_t, getUInt); 84 impl_mysql_rs_getter(int16_t, getInt); 85 impl_mysql_rs_getter(uint16_t, getUInt); 86 impl_mysql_rs_getter(int8_t, getInt); 87 impl_mysql_rs_getter(uint8_t, getUInt); 88 #undef impl_mysql_rs_getter 89 90 template<typename... ARGS> 91 struct mysql_record_setter{}; 92 93 template<> 94 struct mysql_record_setter<>{ 95 template<typename RT, typename RST> 96 static void set(RT & , RST ){ 97 } 98 }; 99 template<typename T, typename... ARGS> 100 struct mysql_record_setter<T, ARGS...>{ 101 template<typename RT, typename RST> 102 static void set(RT & row, RST r){ 103 row.template set<T>(mysql_rs_getter<typename T::type>::get(r, T::name)); 104 mysql_record_setter<ARGS...>::set(row, r); 105 } 106 }; 107 108 template<typename... ARGS> class lazy_eval_string_impl{ 109 public: 110 void to_string(std::stringstream & )const { 111 } 112 }; 113 114 template<typename T, typename... ARGS> 115 class lazy_eval_string_impl<T, ARGS...>{ 116 public: 117 lazy_eval_string_impl(const T & t, const ARGS& ...args): m_t(t), m_params(args...){} 118 void to_string(std::stringstream & ss) const{ 119 ss<<m_t; 120 m_params.to_string(ss); 121 } 122 protected: 123 const T & m_t; 124 lazy_eval_string_impl<ARGS...> m_params; 125 }; 126 template<typename... ARGS> 127 lazy_eval_string_impl<ARGS...> lazy_eval_string(const ARGS& ...args){ 128 return lazy_eval_string_impl<ARGS...>(args...); 129 } 130 template <> class mysql<cppconn> { 131 public: 132 typedef std::shared_ptr<::sql::PreparedStatement > native_statement_type; 133 typedef std::shared_ptr<::sql::ResultSet> query_result_type; 134 135 mysql(const std::string & url, const std::string & usrname, const std::string & passwd, const std::string &dbname) 136 : m_url(url), m_usrname(usrname), m_passwd(passwd), m_dbname(dbname), m_is_worker_thread(false){ 137 138 m_sql_driver = get_driver_instance(); 139 m_sql_conn.reset(m_sql_driver->connect(m_url, m_usrname, m_passwd)); 140 m_sql_conn->setSchema(m_dbname); 141 m_local_thread_id = std::this_thread::get_id(); 142 } 143 144 virtual ~mysql(){ 145 if(m_is_worker_thread){ 146 m_sql_driver->threadEnd(); 147 } 148 } 149 150 protected: 151 mysql(mysql<cppconn> * engine) 152 : m_sql_driver(engine->m_sql_driver) 153 , m_url(engine->m_url) 154 , m_usrname(engine->m_usrname) 155 , m_passwd(engine->m_passwd) 156 , m_dbname(engine->m_dbname) 157 , m_is_worker_thread(true){ 158 m_sql_driver->threadInit(); 159 m_sql_conn.reset(m_sql_driver->connect(m_url, m_usrname, m_passwd)); 160 m_sql_conn->setSchema(m_dbname); 161 m_local_thread_id = std::this_thread::get_id(); 162 } 163 public: 164 165 std::shared_ptr<mysql<cppconn> > thread_copy(){ 166 std::shared_ptr<mysql<cppconn> > ret; 167 ret.reset(new mysql<cppconn>(this)); 168 return ret; 169 } 170 171 void eval_sql_string(const std::string &sql) { 172 if(sql.empty()) return ; 173 check_local_thread(lazy_eval_string("can't call ", sql, " in another thread. Please check thread_copy().")); 174 std::shared_ptr<::sql::Statement> stmt(m_sql_conn->createStatement()); 175 stmt->execute(sql); 176 } 177 178 query_result_type eval_sql_query_string(const std::string &sql) { 179 check_local_thread(lazy_eval_string("can't call ", sql, " in another thread. Please check thread_copy().")); 180 std::shared_ptr<::sql::Statement> stmt(m_sql_conn->createStatement()); 181 query_result_type ret; 182 ret.reset(stmt->executeQuery(sql)); 183 return ret; 184 } 185 186 template<typename... ARGS> 187 row_collection<ARGS...> parse_records(query_result_type query_result){ 188 row_collection<ARGS...> rows; 189 190 while(query_result->next()){ 191 typename row_collection<ARGS...>::row_type r; 192 mysql_record_setter<ARGS...>::set(r, query_result); 193 rows.push_back(std::move(r)); 194 } 195 return rows; 196 } 197 198 native_statement_type prepare_sql_with_string(const std::string &sql) { 199 check_local_thread(lazy_eval_string("can't call ", sql, " in another thread. Please check thread_copy().")); 200 native_statement_type stmt; 201 stmt.reset(m_sql_conn->prepareStatement(sql.c_str())); 202 return stmt; 203 } 204 205 query_result_type eval_native_sql_stmt(native_statement_type stmt) { 206 check_local_thread(lazy_eval_string("can't call ", "executeQuery", " in another thread. Please check thread_copy().")); 207 query_result_type ret; 208 ret.reset(stmt->executeQuery()); 209 return ret; 210 } 211 template <typename T> 212 void bind_to_native_statement(native_statement_type stmt, int index, 213 const T &value) { 214 mysql_bind_setter<native_statement_type, T>::bind(stmt, index, value); 215 } 216 217 void begin_transaction() { 218 eval_sql_string("START TRANSACTION"); 219 } 220 void end_transaction() { 221 eval_sql_string("COMMIT"); 222 } 223 224 protected: 225 template<typename T> 226 void check_local_thread(const T & msg){ 227 std::thread::id local_id = std::this_thread::get_id(); 228 if(local_id != m_local_thread_id){ 229 std::stringstream ss; 230 msg.to_string(ss); 231 throw std::runtime_error(ss.str()); 232 } 233 } 234 235 protected: 236 ::sql::Driver *m_sql_driver; 237 std::shared_ptr<::sql::Connection> m_sql_conn; 238 239 const std::string m_url; 240 const std::string m_usrname; 241 const std::string m_passwd; 242 const std::string m_dbname; 243 bool m_is_worker_thread; 244 std::thread::id m_local_thread_id; 245 }; 246 247 using default_engine = mysql<cppconn>; 248 249 template <typename TM, typename... ARGS> 250 using default_table = table<default_engine, TM, ARGS...>; 251 } // namespace sql 252 } // namespace ff 253