text: #pragma once
  #include <functional>
  #include <memory>
  #include <mutex>
  #include "dmresultset.hpp"
  
  namespace gdp
  {
  namespace db
  {
  
  class DBConnection
  {
  public:
      DBConnection( const DBConnection& ) = delete;
      DBConnection& operator=( const DBConnection& ) = delete;
      DBConnection() {}
  
      ~DBConnection()
      {
          m_connected = false;
          mysql_close( &m_mysql );
          mysql_thread_end();
      }
  
      int init( const std::string& db = "", const std::string& user = "root",
                const std::string& passwd = "",
                const std::string& host = "localhost", int port = 3306,
                unsigned int timeout = 10 )
  
      {
          static std::once_flag flag;
          std::call_once( flag, []()
          {
              mysql_library_init( 0, nullptr, nullptr );
          } );
  
          mysql_init( &m_mysql );
          mysql_thread_init();
  
          //重连
          my_bool reconnect = 1;
          mysql_options( &m_mysql, MYSQL_OPT_RECONNECT, &reconnect );
          //超时
          mysql_options( &m_mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout );
          mysql_options( &m_mysql, MYSQL_OPT_READ_TIMEOUT, &timeout );
          mysql_options( &m_mysql, MYSQL_OPT_WRITE_TIMEOUT, &timeout );
          //编码
          mysql_options( &m_mysql, MYSQL_SET_CHARSET_NAME, "utf8" );
  
          MYSQL* res = mysql_real_connect( &m_mysql, host.c_str(), user.c_str(),
                                           passwd.c_str(), db.c_str(), port, NULL, 0 );
  
          if ( res )
          {
              m_connected = true;
              dlog( "connect to server %s:%s@%s:%d success", user.c_str(),
                    passwd.c_str(), host.c_str(), port );
          }
          else
          {
              elog( "failed to connect to database error: %s\n", mysql_error( &m_mysql ) );
          }
  
          return res != nullptr;
      }
  
      bool use( const std::string& db )
      {
          if ( !this->is_connected() )
          {
              return false;
          }
  
          int ret = mysql_select_db( &m_mysql, db.c_str() );
  
          if ( ret != 0 )
          {
              elog( "execute query  error %s\n", mysql_error( &m_mysql ) );
          }
  
          return ret == 0;
      }
  
      bool is_connected()
      {
          return m_connected;
      }
  
      // execute sql without result
      bool execute( const std::string& sql )
      {
          if ( !this->is_connected() )
          {
              return false;
          }
  
          dlog( "execute query :%s ", sql.c_str() );
          int ret = mysql_real_query( &m_mysql, sql.c_str(), sql.size() );
  
          if ( ret != 0 )
          {
              elog( "execute query error: %s\n", mysql_error( &m_mysql ) );
          }
  
          return ret == 0;
      }
  
      ResultSetPtr query( const std::string& sql )
      {
          if ( !this->is_connected() )
          {
              return nullptr;
          }
  
          int ret = mysql_real_query( &m_mysql, sql.c_str(), sql.size() );
  
          if ( ret != 0 )
          {
              elog( "execute query error: %s\n", mysql_error( &m_mysql ) );
              return nullptr;
          }
  
          MYSQL_RES* res = mysql_store_result( &m_mysql );
          ResultSetPtr rset = std::make_shared<ResultSet>( res );
          return rset;
      }
  
      my_ulonglong get_insert_id()
      {
          if ( !this->is_connected() )
          {
              return my_ulonglong( -1 );
          }
  
          return mysql_insert_id( &m_mysql );
      }
  
  private:
      bool m_connected = false;
      MYSQL m_mysql;
  };
  
  typedef std::shared_ptr<DBConnection> DBConnectionPtr;
  
  }  // namespace db
  }  // namespace gdp
  