#include "CDBConnect.h"
#include <string.h>

namespace YADB
{
	CDBConnect::CDBConnect( bool IsTemp )
	{
		__pConn  = 0;
		__IsTemp = IsTemp;
		__pstmt  = 0;
	}


	CDBConnect::~CDBConnect()
	{
		Close();
	}

	bool CDBConnect::Connect( const _DB_CONN_SETTING_ & DBSetting, std::string & Error )
	{
		//创建
		__pConn = mysql_init( NULL );

		//超时设置
		if ( mysql_options( __pConn, MYSQL_OPT_CONNECT_TIMEOUT, &(DBSetting.TimeOut) ) != 0 )
		{
			Error = "Failed to call mysql_options,";
			Error += " LastError=";
			Error += GetLastError();
			return false;
		}

		//设置字符集
		if ( mysql_set_character_set( __pConn, DBSetting.CharSet.c_str() ) != 0 )
		{
			Error = "Failed to call mysql_set_character_set,";
			Error += " LastError=";
			Error += GetLastError();
			return false;
		}

		//连接数据库
		if ( !mysql_real_connect( __pConn, DBSetting.Host.c_str(), DBSetting.User.c_str(), DBSetting.PWD.c_str(), DBSetting.DBName.c_str(), DBSetting.Port, NULL, 0 ) )
		{
			Error = "Failed to connect database,";
			Error += " LastError=";
			Error += GetLastError();
			return false;
		}
		mysql_query(__pConn, "set names utf8");
		//依靠 mysql_ping 无法做到重连
		char value = 1;
		mysql_options(__pConn, MYSQL_OPT_RECONNECT, &value);

		return true;
	}

	void CDBConnect::Close()
	{
		stmtClose();

		if ( __pConn )
		{
			mysql_close( __pConn );
			__pConn = 0;
		}
	}

	int CDBConnect::ConnctionTest( std::string& Error )
	{
		int nRet = -1;

		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			nRet = DB_ERR_NOT_CONNECT_DB;
		}
		else
		{
			nRet = mysql_ping( __pConn );
			if ( nRet != 0 )
			{
				Error = "Failed to mysql_ping,";
				Error += " LastError=";
				Error += GetLastError();
			}			
		}

		return nRet;
	}

	int CDBConnect::AutoCommit( bool Mode, std::string& Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return DB_ERR_NOT_CONNECT_DB;
		}

		return mysql_autocommit( __pConn, Mode );
	}

	int CDBConnect::Commit( std::string& Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return DB_ERR_NOT_CONNECT_DB;
		}

		return mysql_commit( __pConn );
	}

	int CDBConnect::RollBack( std::string& Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return DB_ERR_NOT_CONNECT_DB;
		}

		return mysql_rollback( __pConn );
	}

	CDBResultSet * CDBConnect::ExecuteQuery( const char * szSql, std::string & Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return 0;
		}

		if ( mysql_query( __pConn, szSql ) )
		{
			Error = "Failed to execute SQL!";
			Error += " LastError=";
			Error += GetLastError();
			return 0;
		}

		if ( !__RessultSet.Bind( mysql_store_result( __pConn ), Error ) )
		{
			return 0;
		}

		return &__RessultSet;
	}

	MYSQL_RES* CDBConnect::Query( const char *szSql, std::string& Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return 0;
		}

		if ( mysql_query( __pConn, szSql ) )
		{
			Error = "Failed to execute SQL!";
			Error += " LastError=";
			Error += GetLastError();
			return 0;
		}

		return mysql_store_result( __pConn );
	}

	my_ulonglong CDBConnect::ExecuteSql( const char * szSql, std::string& Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return DB_ERR_NOT_CONNECT_DB;
		}

		if ( mysql_query( __pConn, szSql ) )
		{
			Error = "Failed to execute SQL!";
			Error += " LastError=";
			Error += GetLastError();
			return DB_ERR_EXCUTE_QUERY;
		}

		return mysql_affected_rows( __pConn );
	}

	my_ulonglong CDBConnect::ExecuteRealSql( const char * szSql, std::string & Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return DB_ERR_NOT_CONNECT_DB;
		}

		unsigned long uSqlLen = strlen( szSql );
		if ( mysql_real_query( __pConn, szSql, uSqlLen ) )
		{
			Error = "Failed to execute SQL,";
			Error += " LastError=";
			Error += GetLastError();
			return DB_ERR_EXCUTE_QUERY;
		}

		return mysql_affected_rows( __pConn );
	}

	const char * CDBConnect::GetLastError()
	{
		if ( 0 == __pConn )
		{
			return "";
		}

		return mysql_error( __pConn );
	}

	my_ulonglong CDBConnect::GetLastInsertID( std::string& Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return DB_ERR_NOT_CONNECT_DB;
		}

		return mysql_insert_id( __pConn  );
	}

	bool CDBConnect::IsTemp()
	{
		return __IsTemp;
	}

	bool CDBConnect::Preparestmt( const char *szSql, std::string & Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return DB_ERR_NOT_CONNECT_DB;
		}

		stmtClose();

		__pstmt = mysql_stmt_init( __pConn );

		if ( mysql_stmt_prepare( __pstmt, szSql, strlen( szSql ) ) != 0 )
		{
			Error = "Error, failed to mysql_stmt_prepare!";
			Error += " LastError=";
			Error += GetLastError();
			return false;
		}

		return true;
	}

	bool CDBConnect::stmtExcute( MYSQL_BIND *stBinds, uint64_t * piId, std::string & Error )
	{
		if ( __pstmt == NULL )
		{
			Error = "Bind error, not called Preparestmt function!";
			return false;
		}

		if ( mysql_stmt_bind_param( __pstmt, stBinds ) != 0 )
		{
			Error = "mysql_stmt_bind_param error,";
			Error += mysql_stmt_error( __pstmt );
			return false;
		}

		if ( mysql_stmt_execute( __pstmt ) != 0 )
		{
			Error = "mysql_stmt_execute error,";
			Error += mysql_stmt_error( __pstmt );
			return false;
		}

		if ( piId )
		{
			*piId = mysql_stmt_insert_id( __pstmt );
		}

		return true;
	}

	void CDBConnect::stmtClose()
	{
		if ( __pstmt )
		{
			mysql_stmt_close( __pstmt );
			__pstmt = 0;
		}
	}

	my_ulonglong CDBConnect::ExecuteSqlID( const char * szSql, std::string & Error )
	{
		if ( 0 == __pConn )
		{
			Error = "Error,not connected to database!";
			return DB_ERR_NOT_CONNECT_DB;
		}

		if ( mysql_real_query( __pConn, szSql, strlen( szSql ) ) )
		{
			Error = "Failed to execute SQL!";
			Error += " LastError=";
			Error += GetLastError();
			return DB_ERR_EXCUTE_QUERY;
		}

		return mysql_insert_id( __pConn );
	}
}