l2-unlegits/libl2c_utils/l2c_db.cpp
2012-02-01 05:25:08 +00:00

567 lines
14 KiB
C++

#include "pch.h"
#include "l2c_utils.h"
#include "l2c_db.h"
MysqlQuery::MysqlQuery()
{
q = NULL;
result = NULL;
num_rows = num_fields = 0;
strcpy( NULL_RET, "NULL" );
}
MysqlQuery::MysqlQuery( const wchar_t *_Format, ... )
{
q = NULL;
result = NULL;
num_rows = num_fields = 0;
strcpy( NULL_RET, "NULL" );
if( _Format )
{
va_list arglist;
va_start( arglist, _Format );
int n = _vscwprintf( _Format, arglist );
if( n >= 1 )
{
q = (wchar_t *)malloc( 2*n + 16 );
if( q )
{
va_start( arglist, _Format );
vswprintf( q, n+2, _Format, arglist );
}
}
}
}
MysqlQuery::~MysqlQuery()
{
clear();
}
void MysqlQuery::clear()
{
if( q ) free( q );
q = NULL;
if( result ) mysql_free_result( result );
result = NULL;
num_rows = num_fields = 0;
row = NULL;
}
int MysqlQuery::getNumRows() const
{
return num_rows;
}
int MysqlQuery::getNumFields() const
{
return num_fields;
}
void MysqlQuery::create( const wchar_t *_Format, ... )
{
clear();
va_list _ArgList;
va_start( _ArgList, _Format );
int l = _vscwprintf( _Format, _ArgList ); // number of chars will be printed
if( l <= 1 ) return;
q = (wchar_t *)malloc( l*2 + 2 ); // number of bytes needed
if( !q ) return;
va_start( _ArgList, _Format );
vswprintf( q, l+1, _Format, _ArgList );
}
bool MysqlQuery::getNextRow()
{
if( !result ) return false;
row = mysql_fetch_row( result );
if( row ) return true;
return false;
}
char *MysqlQuery::getFieldStr( int idx )
{
if( !row || !result ) return NULL_RET;
char *ret = NULL;
if( idx>=0 && idx<=(num_fields-1) ) ret = row[idx];
if( !ret ) return NULL_RET; // row[idx] can still be NULL if MySQL table specs ALLOW NULL
return ret;
}
char *MysqlQuery::getFieldStr( const wchar_t *field_name )
{
if( !field_name ) return NULL_RET;
size_t flen = wcslen( field_name );
char *aname = (char *)malloc( flen+1 );
if( !aname ) return NULL_RET;
l2c_unicode_to_ansi( field_name, aname, flen );
char *ret = getFieldStr( aname );
free( aname );
aname = NULL;
return ret;
}
char *MysqlQuery::getFieldStr( const char *field_name )
{
if( !field_name ) return NULL_RET;
if( !result || !row ) return NULL_RET;
if( num_fields < 1 ) return NULL_RET;
MYSQL_FIELD *fields = mysql_fetch_fields( result );
if( !fields ) return NULL_RET;
int i;
int idx = -1;
for( i=0; i<num_fields; i++ )
{
if( _stricmp( fields[i].name, field_name ) == 0 )
{
idx = i;
break;
}
}
if( idx == -1 ) return NULL_RET;
if( row[idx] == NULL ) return NULL_RET; // row[idx] can still be NULL if MySQL table specs ALLOW NULL
return row[idx];
}
int MysqlQuery::getFieldInt( int idx )
{
int i = 0;
char *sret = getFieldStr( idx );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%d", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldInt(): cannot convert [%s] to int", sret );
return i;
}
unsigned int MysqlQuery::getFieldUInt( int idx )
{
unsigned int i = 0;
char *sret = getFieldStr( idx );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%u", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldUInt(): cannot convert [%s] to unsigned int", sret );
return i;
}
long long int MysqlQuery::getFieldInt64( int idx )
{
long long int i = 0;
char *sret = getFieldStr( idx );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%I64d", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldInt64(): cannot convert [%s] to int64", sret );
return true;
}
unsigned long long int MysqlQuery::getFieldUInt64( int idx )
{
unsigned long long int i = 0;
char *sret = getFieldStr( idx );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%I64u", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldUInt64(): cannot convert [%s] to unsigned int64", sret );
return i;
}
double MysqlQuery::getFieldDouble( int idx )
{
double i = 0.0;
char *sret = getFieldStr( idx );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%lf", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldDouble(): cannot convert [%s] to double", sret );
return i;
}
bool MysqlQuery::getFieldBool( int idx )
{
bool i = false;
char *sret = getFieldStr( idx );
if( sret == NULL_RET ) return false;
if( _stricmp( sret, "true" ) == 0 ) { i = true; return true; }
if( _stricmp( sret, "false" ) == 0 ) { i = false; return true; }
int ii = 0;
int r = sscanf( sret, "%d", &ii );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldBool(): cannot convert [%s] to bool", sret );
i = (ii != 0);
return i;
}
int MysqlQuery::getFieldInt( const char *field_name )
{
int i = 0;
char *sret = getFieldStr( field_name );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%d", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldInt(): cannot convert [%s] to int", sret );
return i;
}
unsigned int MysqlQuery::getFieldUInt( const char *field_name )
{
unsigned int i = 0;
char *sret = getFieldStr( field_name );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%u", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldUInt(): cannot convert [%s] to unsigned int", sret );
return i;
}
long long int MysqlQuery::getFieldInt64( const char *field_name )
{
long long int i = 0;
char *sret = getFieldStr( field_name );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%I64d", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldInt64(): cannot convert [%s] to int64", sret );
return i;
}
unsigned long long int MysqlQuery::getFieldUInt64( const char *field_name )
{
unsigned long long int i = 0;
char *sret = getFieldStr( field_name );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%I64u", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldUInt64(): cannot convert [%s] to unsigned int64", sret );
return i;
}
double MysqlQuery::getFieldDouble( const char *field_name )
{
double i = 0.0;
char *sret = getFieldStr( field_name );
//if( sret == NULL_RET ) return false;
int r = sscanf( sret, "%lf", &i );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldDouble(): cannot convert [%s] to double", sret );
return i;
}
bool MysqlQuery::getFieldBool( const char *field_name )
{
bool i = false;
char *sret = getFieldStr( field_name );
if( sret == NULL_RET ) return false;
if( _stricmp( sret, "true" ) == 0 ) { i = true; return true; }
if( _stricmp( sret, "false" ) == 0 ) { i = false; return true; }
int ii = 0;
int r = sscanf( sret, "%d", &ii );
if( r != 1 ) throw L2C_Exception( "MysqlQuery::getFieldBool(): cannot convert [%s] to bool", sret );
i = (ii != 0);
return i;
}
// get field content as unicode strings
void MysqlQuery::getFieldStrW( int idx, wchar_t *out, size_t maxCount )
{
char *ret = getFieldStr( idx );
l2c_ansi_to_unicode( ret, out, maxCount );
}
void MysqlQuery::getFieldStrW( const char *field_name, wchar_t *out, size_t maxCount )
{
char *ret = getFieldStr( field_name );
l2c_ansi_to_unicode( ret, out, maxCount );
}
void MysqlQuery::getFieldStrW( const wchar_t *field_name, wchar_t *out, size_t maxCount )
{
char *ret = getFieldStr( field_name );
l2c_ansi_to_unicode( ret, out, maxCount );
}
MysqlConnection::MysqlConnection()
{
mysql_init( &m_mysql );
m_connected = false;
m_errstr[0] = 0;
return;
}
MysqlConnection::~MysqlConnection()
{
close();
}
char *MysqlConnection::escapeStringMalloc( const char *in )
{
if( !in ) return NULL;
size_t ll = strlen( in );
char *out = (char *)malloc( ll*2 + 2 );
if( !out ) return NULL;
if( m_connected )
mysql_real_escape_string( &m_mysql, out, in, ll );
else
mysql_escape_string( out, in, ll );
return out;
}
bool MysqlConnection::connect( const wchar_t *server, const wchar_t *user, const wchar_t *pass, const wchar_t *db )
{
if( m_connected ) return false;
// set option
my_bool bVal = 1;
int oret = mysql_options( &m_mysql, MYSQL_OPT_RECONNECT, (const char *)&bVal );
if( oret != 0 ) return false;
// convert strings
char aserver[256] = {0};
char auser[256] = {0};
char apass[256] = {0};
char adb[256] = {0};
l2c_unicode_to_ansi( server, aserver, 255 );
l2c_unicode_to_ansi( user, auser, 255 );
l2c_unicode_to_ansi( pass, apass, 255 );
l2c_unicode_to_ansi( db, adb, 255 );
// attempt connect
MYSQL *ret = mysql_real_connect( &m_mysql, aserver, auser, apass, adb, 3306, NULL,
/*CLIENT_FOUND_ROWS |*/ CLIENT_INTERACTIVE | CLIENT_MULTI_STATEMENTS );
if( ret == NULL || ret != &m_mysql ) return false;
m_connected = true;
return true;
}
bool MysqlConnection::close()
{
if( !m_connected ) return false;
mysql_close( &m_mysql );
m_connected = false;
return true;
}
const wchar_t *MysqlConnection::getErrorStr()
{
char *aerr = _strdup( mysql_error( &m_mysql ) );
wcscpy( m_errstr, L"<none>" );
if( aerr ) l2c_ansi_to_unicode( aerr, m_errstr, 255 );
return (const wchar_t *)m_errstr;
}
bool MysqlConnection::isConnected()
{
if( m_connected )
{
int ret = mysql_ping( &m_mysql );
if( ret != 0 )
{
close();
return false;
}
return true;
}
return false;
}
bool MysqlConnection::executeQuery( MysqlQuery& q )
{
if( !m_connected ) return false;
if( !q.q ) return false;
size_t qlen = wcslen( q.q );
char *a_query = (char *)malloc( qlen + 1 );
if( !a_query ) return false;
l2c_unicode_to_ansi( q.q, a_query, qlen+1 );
int q_res = mysql_query( &m_mysql, a_query );
free( a_query );
a_query = NULL;
if( q_res == 0 )
{
// no error
q.result = mysql_store_result( &m_mysql );
if( q.result )
{
q.num_fields = (int)mysql_num_fields( q.result );
q.num_rows = (int)mysql_num_rows( q.result );
}
else
{
q.num_fields = mysql_field_count( &m_mysql );
// query was not a SELECT
if( q.num_fields == 0 )
q.num_rows = (int)mysql_affected_rows( &m_mysql );
}
// no error
return true;
}
// error
return false;
}
// memory for static variable
bool MysqlConnectionManager::m_wasLibraryInit = false;
MysqlConnectionManager::MysqlConnectionManager()
{
m_initialized = false;
m_server[0] = m_user[0] = m_pass[0] = m_db[0] = 0;
m_maxConnections = m_numActiveConnections = 0;
m_connections = NULL;
}
MysqlConnectionManager::~MysqlConnectionManager()
{
closeAllConnections();
}
bool MysqlConnectionManager::initialize( int maxConnections, const wchar_t *server, const wchar_t *user,
const wchar_t *pass, const wchar_t *db )
{
if( m_initialized ) return true;
// init lock
InitializeCriticalSectionAndSpinCount( &m_lock, 10 );
Lock();
// init mysql library?
if( !MysqlConnectionManager::m_wasLibraryInit )
{
mysql_server_init( 0, NULL, NULL );
MysqlConnectionManager::m_wasLibraryInit = true;
}
// try allocate
m_connections = (MysqlConnection **)malloc( maxConnections * sizeof(MysqlConnection *) );
if( !m_connections )
{
Unlock();
return false;
}
m_connbusy = (bool *)malloc( maxConnections * sizeof(bool) );
if( !m_connbusy )
{
free( m_connections );
m_connections = NULL;
Unlock();
return false;
}
// init nulls
int i;
for( i=0; i<maxConnections; i++ )
{
m_connections[i] = NULL;
m_connbusy[i] = false;
}
// copy data
wcscpy( m_server, server );
wcscpy( m_user, user );
m_pass[0] = 0;
if( pass ) wcscpy( m_pass, pass );
wcscpy( m_db, db );
m_maxConnections = maxConnections;
//
m_initialized = true;
Unlock();
return true;
}
void MysqlConnectionManager::closeAllConnections()
{
if( !m_initialized ) return;
Lock();
int i;
for( i=0; i<m_maxConnections; i++ )
{
if( m_connections[i] )
{
m_numActiveConnections--;
m_connections[i]->close();
delete m_connections[i];
m_connections[i] = NULL;
m_connbusy[i] = false;
}
}
free( m_connections );
m_connections = NULL;
free( m_connbusy );
m_connbusy = NULL;
m_initialized = false;
Unlock();
DeleteCriticalSection( &m_lock );
}
MysqlConnection *MysqlConnectionManager::getConnection()
{
MysqlConnection *ret = NULL;
int i = 0;
Lock();
for( i=0; i<m_maxConnections; i++ )
{
if( !m_connections[i] )
{
m_connections[i] = new MysqlConnection();
m_connections[i]->connect( m_server, m_user, m_pass, m_db );
m_connbusy[i] = true;
ret = m_connections[i];
m_numActiveConnections++;
break;
}
if( m_connections[i] && !m_connbusy[i] )
{
if( !m_connections[i]->isConnected() )
m_connections[i]->connect( m_server, m_user, m_pass, m_db );
m_connbusy[i] = true;
ret = m_connections[i];
m_numActiveConnections++;
break;
}
}
Unlock();
return ret;
}
bool MysqlConnectionManager::releaseConnection( MysqlConnection *con )
{
if( !con ) return false;
int i = 0;
bool ret = false;
Lock();
for( i=0; i<m_maxConnections; i++ )
{
if( m_connections[i] == con )
{
m_connbusy[i] = false;
// close connections with index > 0
if( i > 0 ) m_connections[i]->close();
// at least 1 conn with idx 0 will be active all the time
m_numActiveConnections--;
ret = true;
break;
}
}
Unlock();
return ret;
}
int MysqlConnectionManager::getCountActiveConnections() const
{
return m_numActiveConnections;
}
int MysqlConnectionManager::getCountMaxConnections() const
{
return m_maxConnections;
}
void MysqlConnectionManager::Lock()
{
EnterCriticalSection( &m_lock );
}
void MysqlConnectionManager::Unlock()
{
LeaveCriticalSection( &m_lock );
}