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