// Include
#include "gamesrv.h"
#include "stdafx.h"

#include "DramaturgyManager.h"
#include "Skillscript.h"
#include "Skill_Common.h"
#include "Player_Common.h"

// Local definitions
#pragma warning( disable: 4127 )

// memory를 안전하게 해제
#define SafeDelete(P) if (P!=NULL) { delete(P); (P)=NULL; }

/* macro for strtok checking */
#define TOKEN_CHECK(token, buffer, seps)					    \
	token = strtok( buffer, seps );								\
	if ( token == NULL ) throw false;

// Global data

// cSQLGame Constructor.
cSQLGame::cSQLGame(void) : mIoContextPool(NULL)
{
}

// ~cSQLGame Destructor.
cSQLGame::~cSQLGame(void)
{
}

// InsertItemDefine Method
bool cSQLGame::InsertItemDefine(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Define.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			throw false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			throw false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			throw false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			throw false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			throw false;

		if ( sqlStatement->TruncateItemDefine( ) != SQL_SUCCESS )
			throw false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char           buffer[4096];
		int            bufferLen = sizeof(buffer)/sizeof(char);

		char           seps[] = "\t";           // 파싱구문 Parsing.
		char*          token;                   // 파싱토근 Parsing Token.

		TB_ITEM_DEFINE tbItemDefine;
		SQLRETURN      sqlReturn;
		long           retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemDefine, 0, sizeof(TB_ITEM_DEFINE) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// 인덱스(INDEX)
			TOKEN_CHECK( token, buffer, seps );
			tbItemDefine.index = atoi( token );

			// 이름(NAME)
			TOKEN_CHECK( token, NULL, seps );
			MultiByteToWideChar( CP_ACP, 0, token, (int)strlen(token)+1, tbItemDefine.name, (int)(sizeof(tbItemDefine.name)/sizeof(wchar_t)) );

			// 이름 인덱스(NAME INDEX)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// 툴팁 인덱스(TOOL TIP INDEX)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// 종류(TYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.type = (BYTE)atoi( token );

			// 세부종류(SUBTYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.subType = (BYTE)atoi( token );

			// 무게(WEIGHT)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.weight = (short)atoi( token );

			// 겹침개수(CAPACITY)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.capacity = (short)atoi( token );

			// 판매방법(SELL TYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.sellType = atoi( token );

			// 판매가(SELL PRICE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.sellPrice = atoi( token );

			// 구입방법(BUY TYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.buyType = atoi( token );

			// 구입가(BUY PRICE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.buyPrice = atoi( token );

			// 최대 출현갯수(MAX PRESENT)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.maxPresent = atoi( token );

			// 보유가능개수(MAX INVENTORY)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.maxInventory = atoi( token );

			// 사용자거래여부(EXCHANGE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.exchange = (BYTE)atoi( token );

			// 속성 인덱스(ABILITY INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.abilityIndex = atoi( token );

			// 제한 인덱스(LIMIT INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.limitIndex = atoi( token );

			// 카드 인덱스(CARD INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.cardIndex = atoi( token );

			// 타로 인덱스(TAROT INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.tarotIndex = atoi( token );

			// 스프레드 인덱스(SPREAD INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.spreadIndex = atoi( token );

			// 분해 인덱스(DISJOINT INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.disjointIndex = atoi( token );

			// 카드슬롯 인덱스(CARD SLOT INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.cardSlotIndex = atoi( token );

			// 강화확률 인덱스(ENHANCED RATE INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.enhancedRateIndex = atoi( token );

			// 강화 인덱스(ENHANCED INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.enhancedIndex = atoi( token );

			// 교환 인덱스(CHANGE INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.changeIndex = atoi( token );

			// 호칭 인덱스(CHANGE INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemDefine.titleIndex = atoi( token );

			// 아이콘 인덱스(ICON INDEX)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// 모델 인덱스0-오른손(MODEL INDEX)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// 모델 인덱스0-왼  손(MODEL INDEX)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// 투구 여부 ON(1)/OFF(0)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// 툴팁 생상(TOOL TIP COLOR)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			sqlReturn = sqlStatement->InsertItemDefine( &tbItemDefine, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemDefine, 0, sizeof(TB_ITEM_DEFINE) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemAbility Method
bool cSQLGame::InsertItemAbility(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Ability.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			throw false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			throw false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			throw false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			throw false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			throw false;

		if ( sqlStatement->TruncateItemAbility( ) != SQL_SUCCESS )
			throw false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_ABILITY tbItemAbility;
		SQLRETURN       sqlReturn;
		long            retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemAbility, 0, sizeof(TB_ITEM_ABILITY) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// 이름(NAME)
			// TOKEN_CHECK( token, buffer, seps );
			// Skip

			// 인덱스(INDEX)
			TOKEN_CHECK( token, buffer, seps );
			tbItemAbility.index = atoi( token );

			// 사용효과설명 인덱스(DESCRIPTION INDEX)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// 방어구재질(DEFENSE TYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.def_class = (short)atoi( token );

			// 범위방식(RANGE_TYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.range_type = (BYTE)atoi( token );

			// 효과적용타겟(TARGET_TYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.target_type = (BYTE)atoi( token );

			// 사용거리(USE_RANGE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.use_range = (short)atoi( token );

			// 물리방어력(DEFENSE P)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.p_def = (short)atoi( token );

			// 마법방어력(DEFENSE M)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.m_def = (short)atoi( token );

			// 사거리(ATTACK RANGE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.atk_range = (short)atoi( token );

			// 공격애니속도(ATTACK SPEED)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.atk_spd = (short)atoi( token );

			// 재사용시간(COOL TIME1)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.cool_time1 = atoi( token );

			// 그룹쿨타임(COOL TIME2)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.cool_time2 = atoi( token );

			// 물리공격력-소(ATTACK P MIN)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.min_p_atk = (short)atoi( token );

			// 물리공격력-대(ATTACK P MAX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.max_p_atk = (short)atoi( token );

			// 마법공격력-소(ATTACK M MIN)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.min_m_atk = (short)atoi( token );

			// 마법공격력-대(ATTACK_M_MAX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.max_m_atk = (short)atoi( token );

			// 옵션01인덱스(OPT01_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt01_index = (short)atoi( token );
			// 옵션01효과값(OPT01_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt01_value = (short)atoi( token );

			// 옵션02인덱스(OPT02_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt02_index = (short)atoi( token );
			// 옵션02효과값(OPT02_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt02_value = (short)atoi( token );

			// 옵션03인덱스(OPT03_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt03_index = (short)atoi( token );
			// 옵션03효과값(OPT03_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt03_value = (short)atoi( token );

			// 옵션04인덱스(OPT04_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt04_index = (short)atoi( token );
			// 옵션04효과값(OPT04_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt04_value = (short)atoi( token );

			// 옵션05인덱스(OPT05_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt05_index = (short)atoi( token );
			// 옵션05효과값(OPT05_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt05_value = (short)atoi( token );

			// 옵션06인덱스(OPT06_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt06_index = (short)atoi( token );
			// 옵션06효과값(OPT06_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt06_value = (short)atoi( token );

			// 옵션07인덱스(OPT07_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt07_index = (short)atoi( token );
			// 옵션07효과값(OPT07_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt07_value = (short)atoi( token );

			// 옵션08인덱스(OPT08_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt08_index = (short)atoi( token );
			// 옵션08효과값(OPT08_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt08_value = (short)atoi( token );

			// 옵션09인덱스(OPT09_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt09_index = (short)atoi( token );
			// 옵션09효과값(OPT09_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt09_value = (short)atoi( token );

			// 옵션10인덱스(OPT10_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt10_index = (short)atoi( token );
			// 옵션10효과값(OPT10_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.opt10_value = (short)atoi( token );

			// 소모효과(INFLUENCE_IDX)
			TOKEN_CHECK( token, NULL, seps );
			tbItemAbility.influence_idx = atoi( token );

			sqlReturn = sqlStatement->InsertItemAbility( &tbItemAbility, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemAbility, 0, sizeof(TB_ITEM_ABILITY) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemLimit Method
bool cSQLGame::InsertItemLimit(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Limit.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemLimit( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_LIMIT   tbItemLimit;
		SQLRETURN       sqlReturn;
		long            retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemLimit, 0, sizeof(TB_ITEM_LIMIT) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// INDEX
			TOKEN_CHECK( token, buffer, seps );
			tbItemLimit.index = atoi( token );
			// CHAR_RACE
			TOKEN_CHECK( token, NULL, seps );
			tbItemLimit.charRace = (BYTE)atoi( token );
			// CHAR_GENDER
			TOKEN_CHECK( token, NULL, seps );
			tbItemLimit.charGender = (BYTE)atoi( token );
			// CHAR_JOB
			TOKEN_CHECK( token, NULL, seps );
			tbItemLimit.charJob = atoi( token );
			// CHAR_LEVEL
			TOKEN_CHECK( token, NULL, seps );
			tbItemLimit.charLevel = (BYTE)atoi( token );
			// PVP_ONLY
			TOKEN_CHECK( token, NULL, seps );
			tbItemLimit.pvpOnly = (BYTE)atoi( token );

			sqlReturn = sqlStatement->InsertItemLimit( &tbItemLimit, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemLimit, 0, sizeof(TB_ITEM_LIMIT) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemCard Method
bool cSQLGame::InsertItemCard(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Card.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemCard( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_CARD    tbItemCard;
		SQLRETURN       sqlReturn;
		long            retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemCard, 0, sizeof(TB_ITEM_CARD) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// 카드명(NAME)
			// TOKEN_CHECK( token, buffer, seps );
			// Skip

			// 인덱스(INDEX)
			TOKEN_CHECK( token, buffer, seps );
			tbItemCard.index = (long)atoi( token );

			// 판(EPISODE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemCard.episode = (long)atoi( token );

			// 카드넘버(NUMBER)
			TOKEN_CHECK( token, NULL, seps );
			tbItemCard.number = (long)atoi( token );

			// 희귀도(LEVEL)
			TOKEN_CHECK( token, NULL, seps );
			tbItemCard.level = (BYTE)atoi( token );

			// 카드분류(TYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemCard.type = (BYTE)atoi( token );

			// 장착위치(SUBTYPE)
			TOKEN_CHECK( token, NULL, seps );
			tbItemCard.subType = (BYTE)atoi( token );

			// 이미지인덱스(IMAGE_INDEX)
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			sqlReturn = sqlStatement->InsertItemCard( &tbItemCard, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemCard, 0, sizeof(TB_ITEM_CARD) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemCardSlot Method
bool cSQLGame::InsertItemCardSlot(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Card_Slot.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemCardSlot( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char              buffer[4096];
		int               bufferLen = sizeof(buffer)/sizeof(char);

		char              seps[] = "\t";           // 파싱구문 Parsing.
		char*             token;                   // 파싱토근 Parsing Token.

		TB_ITEM_CARD_SLOT itemCardSlot;
		SQLRETURN         sqlReturn;
		long              retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &itemCardSlot, 0, sizeof(itemCardSlot) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// 인덱스(INDEX)
			TOKEN_CHECK( token, buffer, seps );
			itemCardSlot.index = atoi( token );

			// 카드슬롯1(0없음/1A형/2B형/3AB형/4O형)
			TOKEN_CHECK( token, NULL, seps );
			itemCardSlot.slot1 = (BYTE)atoi( token );

			// 카드슬롯2(0없음/1A형/2B형/3AB형/4O형)
			TOKEN_CHECK( token, NULL, seps );
			itemCardSlot.slot2 = (BYTE)atoi( token );

			// 카드슬롯3(0없음/1A형/2B형/3AB형/4O형)
			TOKEN_CHECK( token, NULL, seps );
			itemCardSlot.slot3 = (BYTE)atoi( token );

			// 카드슬롯4(0없음/1A형/2B형/3AB형/4O형)
			TOKEN_CHECK( token, NULL, seps );
			itemCardSlot.slot4 = (BYTE)atoi( token );

			// 카드슬롯5(0없음/1A형/2B형/3AB형/4O형)
			TOKEN_CHECK( token, NULL, seps );
			itemCardSlot.slot5 = (BYTE)atoi( token );

			sqlReturn = sqlStatement->InsertItemCardSlot( &itemCardSlot, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &itemCardSlot, 0, sizeof(itemCardSlot) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemTarot Method
bool cSQLGame::InsertItemTarot(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Tarot.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemTarot( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_TAROT   tbItemTarot;
		SQLRETURN       sqlReturn;
		long            retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemTarot, 0, sizeof(TB_ITEM_TAROT) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// INDEX
			TOKEN_CHECK( token, buffer, seps );
			tbItemTarot.index = atoi( token );

			// IMG_INDEX
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// NUMBER
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarot.number = atoi( token );

			// LEVEL
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarot.level = (BYTE)atoi( token );

			// STR_VALUE
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarot.strValue = atoi( token );

			// INV_VALUE
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarot.invValue = atoi( token );

			// PROP
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarot.prop = atoi( token );

			// EPISODE
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarot.episode = atoi( token );

			// STR_DESCRIPTION
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// INV_DESCRIPTION
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			sqlReturn = sqlStatement->InsertItemTarot( &tbItemTarot, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemTarot, 0, sizeof(TB_ITEM_TAROT) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemTarotResult Method
bool cSQLGame::InsertItemTarotResult(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Tarot_Result.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemTarotResult( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char                 buffer[4096];
		int                  bufferLen = sizeof(buffer)/sizeof(char);

		char                 seps[] = "\t";           // 파싱구문 Parsing.
		char*                token;                   // 파싱토근 Parsing Token.

		TB_ITEM_TAROT_RESULT tbItemTarotResult;
		SQLRETURN            sqlReturn;
		long                 retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemTarotResult, 0, sizeof(TB_ITEM_TAROT_RESULT) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// INDEX
			TOKEN_CHECK( token, buffer, seps );
			tbItemTarotResult.index = (long)atoi( token );

			// MIN
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarotResult.min_value = (long)atoi( token );

			// MAX
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarotResult.max_value = (long)atoi( token );

			// INFLUENCE_IDX1
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarotResult.influence_idx1 = (long)atoi( token );

			// INFLUENCE_IDX2
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarotResult.influence_idx2 = (long)atoi( token );

			// INFLUENCE_IDX3
			TOKEN_CHECK( token, NULL, seps );
			tbItemTarotResult.influence_idx3 = (long)atoi( token );

			sqlReturn = sqlStatement->InsertItemTarotResult( &tbItemTarotResult, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemTarotResult, 0, sizeof(TB_ITEM_TAROT_RESULT) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemSpread Method
bool cSQLGame::InsertItemSpread(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Spread.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemSpread( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_SPREAD   tbItemSpread;
		SQLRETURN        sqlReturn;
		long             retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemSpread, 0, sizeof(TB_ITEM_SPREAD) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// INDEX
			TOKEN_CHECK( token, buffer, seps );
			tbItemSpread.index = atoi( token );

			// IMG_INDEX
			TOKEN_CHECK( token, NULL, seps );
			// Skip

			// AXIS_ARRAY
			TOKEN_CHECK( token, NULL, seps );
			tbItemSpread.axisArray = (BYTE)atoi( token );

			// XPOS
			TOKEN_CHECK( token, NULL, seps );
			tbItemSpread.xPos = (short)atoi( token );

			// YPOS
			TOKEN_CHECK( token, NULL, seps );
			tbItemSpread.yPos = (short)atoi( token );

			// DIR
			TOKEN_CHECK( token, NULL, seps );
			tbItemSpread.dir = (BYTE)atoi( token );

			// CALC
			TOKEN_CHECK( token, NULL, seps );
			strncpy( tbItemSpread.calc, token, 1 );

			// VALUE
			TOKEN_CHECK( token, NULL, seps );
			tbItemSpread.value = (short)atoi( token );

			sqlReturn = sqlStatement->InsertItemSpread( &tbItemSpread, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemSpread, 0, sizeof(TB_ITEM_SPREAD) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemDisjoint Method
bool cSQLGame::InsertItemDisjoint(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Disjoint.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemDisjoint( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_DISJOINT itemDisjoint;
		SQLRETURN        sqlReturn;
		long             retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &itemDisjoint, 0, sizeof(itemDisjoint) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// INDEX
			TOKEN_CHECK( token, buffer, seps );
			itemDisjoint.index = atoi( token );

			// PRICE
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.price = atoi( token );

			// ITEM_DEFINE_INDEX1
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.itemDefineIndex1 = atoi( token );

			// INVENTORY_COUNT1
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.inventoryCount1 = (short)atoi( token );

			// ITEM_DEFINE_INDEX2
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.itemDefineIndex2 = atoi( token );

			// INVENTORY_COUNT2
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.inventoryCount2 = (short)atoi( token );

			// ITEM_DEFINE_INDEX3
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.itemDefineIndex3 = atoi( token );

			// INVENTORY_COUNT3
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.inventoryCount3 = (short)atoi( token );

			// ITEM_DEFINE_INDEX4
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.itemDefineIndex4 = atoi( token );

			// INVENTORY_COUNT4
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.inventoryCount4 = (short)atoi( token );

			// ITEM_DEFINE_INDEX5
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.itemDefineIndex5 = atoi( token );

			// INVENTORY_COUNT5
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.inventoryCount5 = (short)atoi( token );

			// ITEM_DEFINE_INDEX6
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.itemDefineIndex6 = atoi( token );

			// INVENTORY_COUNT6
			TOKEN_CHECK( token, NULL, seps );
			itemDisjoint.inventoryCount6 = (short)atoi( token );

			sqlReturn = sqlStatement->InsertItemDisjoint( &itemDisjoint, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &itemDisjoint, 0, sizeof(itemDisjoint) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemEnhanced Method
bool cSQLGame::InsertItemEnhanced(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Enhanced.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemEnhanced( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_ENHANCED tbItemEnhanced;
		SQLRETURN        sqlReturn;
		long             retvalue;
		char             format[260];

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemEnhanced, 0, sizeof(TB_ITEM_ENHANCED) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// INDEX
			TOKEN_CHECK( token, buffer, seps );
			tbItemEnhanced.index = atoi( token );

			// ENHANCED1
			TOKEN_CHECK( token, NULL, seps );
			tbItemEnhanced.enhanced1 = (BYTE)atoi( token );

			// ENHANCED2
			TOKEN_CHECK( token, NULL, seps );
			tbItemEnhanced.enhanced2 = (BYTE)atoi( token );

			TOKEN_CHECK( token, NULL, seps );
			sprintf( format, "%d", atoi( token ) );
			strcpy( tbItemEnhanced.strPlus, format );
			for ( int i = 1; i < MAX_ITEM_ENHANCED; i++ )
			{
				TOKEN_CHECK( token, NULL, seps );
				sprintf( format, ",%d", atoi( token ) );
				strcat( tbItemEnhanced.strPlus, format );
			}

			sqlReturn = sqlStatement->InsertItemEnhanced( &tbItemEnhanced, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemEnhanced, 0, sizeof(TB_ITEM_ENHANCED) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemEnhancedRate Method
bool cSQLGame::InsertItemEnhancedRate(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_EnhancedRate.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemEnhancedRate( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_ENHANCED_RATE tbItemEnhancedRate;
		SQLRETURN             sqlReturn;
		long                  retvalue;
		char                  format[260];

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbItemEnhancedRate, 0, sizeof(TB_ITEM_ENHANCED_RATE) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// INDEX - 구문 문자열
			TOKEN_CHECK( token, buffer, seps );
			if ( stricmp( token, "index" ) )
				throw false;

			// INDEX - 값
			TOKEN_CHECK( token, NULL, seps );
			tbItemEnhancedRate.index = atoi( token );

			// Success - MAX_ITEM_ENHANCED 단계.
			if ( fgets( buffer, bufferLen, stream ) == NULL )
				throw false;

			TOKEN_CHECK( token, buffer, seps );
			sprintf( format, "%s", token );
			strcpy( tbItemEnhancedRate.str.success, format );

			for ( int i = 1; i < MAX_ITEM_ENHANCED; i++ )
			{
				TOKEN_CHECK( token, NULL, seps );
				sprintf( format, ",%s", token );
				strcat( tbItemEnhancedRate.str.success, format );
			}

			// Down - MAX_ITEM_ENHANCED 단계.
			if ( fgets( buffer, bufferLen, stream ) == NULL )
				throw false;

			TOKEN_CHECK( token, buffer, seps );
			sprintf( format, "%s", token );
			strcpy( tbItemEnhancedRate.str.down, format );

			for ( int i = 1; i < MAX_ITEM_ENHANCED; i++ )
			{
				TOKEN_CHECK( token, NULL, seps );
				sprintf( format, ",%s", token );
				strcat( tbItemEnhancedRate.str.down, format );
			}

			// Destruct - MAX_ITEM_ENHANCED 단계.
			if ( fgets( buffer, bufferLen, stream ) == NULL )
				throw false;

			TOKEN_CHECK( token, buffer, seps );
			sprintf( format, "%s", token );
			strcpy( tbItemEnhancedRate.str.destruct, format );

			for ( int i = 1; i < MAX_ITEM_ENHANCED; i++ )
			{
				TOKEN_CHECK( token, NULL, seps );
				sprintf( format, ",%s", token );
				strcat( tbItemEnhancedRate.str.destruct, format );
			}

			sqlReturn = sqlStatement->InsertItemEnhancedRate( &tbItemEnhancedRate, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbItemEnhancedRate, 0, sizeof(TB_ITEM_ENHANCED_RATE) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertItemChange Method
bool cSQLGame::InsertItemChange(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Item_Change.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateItemChange( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t\n";         // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_ITEM_CHANGE  itemChange;
		SQLRETURN       sqlReturn;
		long            retvalue;
		char            format[260];

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &itemChange, 0, sizeof(TB_ITEM_CHANGE) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// INDEX - 구문 문자열
			TOKEN_CHECK( token, buffer, seps );
			if ( stricmp( token, "index" ) )
				throw false;

			// INDEX - 값
			TOKEN_CHECK( token, NULL, seps );
			itemChange.index = atoi( token );

			if ( fgets( buffer, bufferLen, stream ) == NULL )
				throw false;

			// MONEY - 구문 문자열
			TOKEN_CHECK( token, buffer, seps );
			if ( stricmp( token, "money" ) )
				throw false;

			// Min Money
			TOKEN_CHECK( token, NULL, seps );
			itemChange.minMoney = atoi( token );

			// Max Money
			TOKEN_CHECK( token, NULL, seps );
			itemChange.maxMoney = atoi( token );

			if ( fgets( buffer, bufferLen, stream ) == NULL )
				throw false;

			// RATE - 구문 문자열
			TOKEN_CHECK( token, buffer, seps );
			if ( stricmp( token, "rate" ) )
				throw false;

			TOKEN_CHECK( token, NULL, seps );
			sprintf( format, "%s", token );
			strcpy( itemChange.str.rate, format );

			token = strtok( NULL, seps );
			if ( token != NULL )
			{
				int i = 0;
				do {
					sprintf( format, ",%s", token );
					strcat( itemChange.str.rate, format );
					token = strtok( NULL, seps );
				} while ( ++i < MAX_ITEM_CHANGE_RATE && token != NULL );
			}

			// TB_ITEM_DEFINE::INDEX.
			if ( fgets( buffer, bufferLen, stream ) == NULL )
				throw false;
			TOKEN_CHECK( token, buffer, seps );
			if ( stricmp( token, "item" ) )
				throw false;

			TOKEN_CHECK( token, NULL, seps );
			sprintf( format, "%s", token );
			strcpy( itemChange.str.index, format );

			token = strtok( NULL, seps );
			if ( token != NULL )
			{
				int i = 0;
				do {
					sprintf( format, ",%s", token );
					strcat( itemChange.str.index, format );
					token = strtok( NULL, seps );
				} while ( ++i < MAX_ITEM_CHANGE_DATA && token != NULL );
			}

			// TB_INVENTORY::COUNT.
			if ( fgets( buffer, bufferLen, stream ) == NULL )
				throw false;
			TOKEN_CHECK( token, buffer, seps );
			if ( stricmp( token, "count" ) )
				throw false;

			TOKEN_CHECK( token, NULL, seps );
			sprintf( format, "%s", token );
			strcpy( itemChange.str.count, format );

			token = strtok( NULL, seps );
			if ( token != NULL )
			{
				int i = 0;
				do {
					sprintf( format, ",%s", token );
					strcat( itemChange.str.count, format );
					token = strtok( NULL, seps );
				} while ( ++i < MAX_ITEM_CHANGE_DATA && token != NULL );
			}

			sqlReturn = sqlStatement->InsertItemChange( &itemChange, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &itemChange, 0, sizeof(TB_ITEM_CHANGE) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

// InsertDefaultItems Method
bool cSQLGame::InsertDefaultItems(char* dsn, char* uid, char* pwd)
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );
	FILE*            stream        = fopen( "Script\\Resource\\Default_Items.txt", "rt" );

	try
	{
		//ODBC, SQL 사용을 초기화.
		if ( sqlEnv->AllocEnv( ) == false )
			return false;

		//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
		if ( sqlEnv->SetEnvAttr( ) == false )
			return false;

		if ( sqlConnection->AllocDbc( sqlEnv ) == false )
			return false;

		if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
			return false;

		if ( sqlStatement->AllocStmt( sqlConnection ) == false )
			return false;

		if ( sqlStatement->TruncateDefaultItems( ) != SQL_SUCCESS )
			return false;

		if ( stream == NULL )
			throw false;

		// Parsing.
		char            buffer[4096];
		int             bufferLen = sizeof(buffer)/sizeof(char);

		char            seps[] = "\t";           // 파싱구문 Parsing.
		char*           token;                   // 파싱토근 Parsing Token.

		TB_DEFAULT_ITEMS tbDefaultItems;
		SQLRETURN        sqlReturn;
		long             retvalue;

		fseek( stream, 0, SEEK_END );
		fseek( stream, 0, SEEK_SET );

		memset( buffer, 0, bufferLen );
		memset( &tbDefaultItems, 0, sizeof(TB_DEFAULT_ITEMS) );

		// fgets 에서 문자열로 읽어 올 경우, 0x0A(\r,CR) 값은 생략된다.
		while ( fgets( buffer, bufferLen, stream ) != NULL )
		{
			if ( !strnicmp( buffer, "//", 2 ) || !strnicmp( buffer, "\r\n", 2 ) || (*buffer) == 0x0A )
			{
				memset( buffer, 0, bufferLen );
				continue;
			}

			// CHARACTER_JOB
			TOKEN_CHECK( token, buffer, seps );
			tbDefaultItems.characterJob = (long)atoi( token );

			// ITEM_DEFINE_INDEX
			TOKEN_CHECK( token, NULL, seps );
			tbDefaultItems.itemDefineIndex = (long)atoi( token );

			// INVENTORY_NUMBER
			TOKEN_CHECK( token, NULL, seps );
			tbDefaultItems.inventoryNumber = (short)atoi( token );

			// INVENTORY_COUNT
			TOKEN_CHECK( token, NULL, seps );
			tbDefaultItems.inventoryCount = (short)atoi( token );

			sqlReturn = sqlStatement->InsertDefaultItems( &tbDefaultItems, retvalue );
			if ( sqlReturn != SQL_SUCCESS || retvalue != 0 )
				throw false;

			memset( buffer, 0, bufferLen );
			memset( &tbDefaultItems, 0, sizeof(TB_DEFAULT_ITEMS) );
		}
		throw true;
	}
	catch ( bool retcode )
	{
		if ( stream != NULL )
		{
			fclose( stream );
			stream = NULL;
		}

		SafeDelete( sqlStatement );
		SafeDelete( sqlConnection );
		SafeDelete( sqlEnv );

		return retcode;
	}
}

bool cSQLGame::InsertSkillPC( char* dsn, char* uid, char* pwd )
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );

	//ODBC, SQL 사용을 초기화.
	if ( sqlEnv->AllocEnv( ) == false )
		return false;

	//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
	if ( sqlEnv->SetEnvAttr( ) == false )
		return false;

	if ( sqlConnection->AllocDbc( sqlEnv ) == false )
		return false;

	if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
		return false;

	if ( sqlStatement->AllocStmt( sqlConnection ) == false )
		return false;

	if ( sqlStatement->TruncateSkillListPc( ) != SQL_SUCCESS )
		return false;

	typedef tPointerHashMap<unsigned long, void*> cSkillHashMap;

	cSkillHashMap::cIterator start = mpSkillScript->GetPlayerSkillInfoMap()->Begin();
	cSkillHashMap::cIterator end = mpSkillScript->GetPlayerSkillInfoMap()->End();

	for( ; start != end ; ++start )
	{
		if ( sqlStatement->SkillListPcInsert( (*start).mSecond ) != SQL_SUCCESS )
			return false;
	}
	return true;
}

bool cSQLGame::InsertDefaultSkill( char* dsn, char* uid, char* pwd )
{
	cSQLEnvironment* sqlEnv        = new cSQLEnvironment( );
	cSQLConnection*  sqlConnection = new cSQLConnection( );
	cSQLGameStmt*    sqlStatement  = new cSQLGameStmt( );

	//ODBC, SQL 사용을 초기화.
	if ( sqlEnv->AllocEnv( ) == false )
		return false;

	//SQL_ATTR_ODBC_VERSION 를 SQL_OV_ODBC3 로 설정.
	if ( sqlEnv->SetEnvAttr( ) == false )
		return false;

	if ( sqlConnection->AllocDbc( sqlEnv ) == false )
		return false;

	if ( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
		return false;

	if ( sqlStatement->AllocStmt( sqlConnection ) == false )
		return false;

	if ( sqlStatement->TruncateDefalultSkill( ) != SQL_SUCCESS )
		return false;

	typedef tArray<unsigned long> cSkillAry;

	for( int i=0; i<10; i++ )
	{
		cSkillAry* pSkillAry = SKILLSCRIPT->GetFreeSkill( i );
		if( pSkillAry )
		{
			cSkillAry::cIterator begin = pSkillAry->Begin();
			cSkillAry::cIterator end = pSkillAry->End();
			unsigned char skillRace;

			for( ; begin != end; ++begin )
			{
				skillRace = mpSkillScript->GetPlayerSkillInfo( *begin )->mRace;

				for( char playerRace = eRACE_HUMAN ; playerRace < eRACE_MAX ; ++playerRace )
				{
					if( skillRace == eSKILLRACE_ALL )
					{
						if ( sqlStatement->DefalultSkillInsert( i, *begin, playerRace ) != SQL_SUCCESS )
							return false;

						continue;
					}

					switch( playerRace )
					{
					case eRACE_HUMAN:
						{
							if( skillRace == eSKILLRACE_HUMAN ||
								skillRace == eSKILLRACE_HUMAN_BEAST || skillRace == eSKILLRACE_HUMAN_ELF )
							{
								if ( sqlStatement->DefalultSkillInsert( i, *begin, eRACE_HUMAN ) != SQL_SUCCESS )
									return false;
							}						
						}break;
					case eRACE_BEAST:
						{
							if( skillRace == eSKILLRACE_BEAST ||
								skillRace == eSKILLRACE_HUMAN_BEAST || skillRace == eSKILLRACE_BEAST_ELF )
							{
								if ( sqlStatement->DefalultSkillInsert( i, *begin, eRACE_BEAST ) != SQL_SUCCESS )
									return false;
							}
						}break;
					case eRACE_ELF:
						{
							if( skillRace == eSKILLRACE_ELF ||
								skillRace == eSKILLRACE_HUMAN_ELF || skillRace == eSKILLRACE_BEAST_ELF )
							{
								if ( sqlStatement->DefalultSkillInsert( i, *begin, eRACE_ELF ) != SQL_SUCCESS )
									return false;
							}
						}break;
					}
				}
			}

		}
	}

	return true;
}

bool cSQLGame::InsertQuestData( char* dsn, char* uid, char* pwd )
{
	cSQLEnvironment* sqlEnv = new cSQLEnvironment();
	cSQLConnection* sqlConnection = new cSQLConnection();
	cSQLGameStmt* sqlGameStmt = new cSQLGameStmt();

	if( sqlEnv->AllocEnv() == false )
		return false;

	if( sqlEnv->SetEnvAttr() == false )
		return false;

	if( sqlConnection->AllocDbc( sqlEnv ) == false )
		return false;

	if( sqlConnection->Connect( (SQLCHAR*)dsn, (SQLCHAR*)uid, (SQLCHAR*)pwd ) == false )
		return false;

	if( sqlGameStmt->AllocStmt( sqlConnection ) == false )
		return false;

	/// 각 퀘스트 테이블 초기화 
	if( sqlGameStmt->TruncateQuestDefine() != SQL_SUCCESS )
		return false;

	/// 로딩한 데이터를 DB 에 넣기.
	typedef tPointerHashMap<unsigned long, void*> cQuestDefineMap;
	cQuestDefineMap::cIterator i = mpQuestManager->GetQuestDefineMap()->Begin();
	cQuestDefineMap::cIterator end = mpQuestManager->GetQuestDefineMap()->End();

	for( ; i != end; ++i )
	{
		cQuestDefine* define = (cQuestDefine*)(*i).mSecond;
		if( !define )
			return false;
		
		/// 각 테이블간 연결 인덱스 정의
		if( sqlGameStmt->InsertQuestDefine( define ) != SQL_SUCCESS )
			return false;
	}
	return true;
}

// Initialize Method
bool cSQLGame::Initialize(char* dsn, char* uid, char* pwd, unsigned int numWorkerThreads, unsigned int bufferLength)
{
	mIoContextPool = new cIoContextPool( bufferLength );
	return cSQLPool::Initialize( dsn, uid, pwd, numWorkerThreads );
}

// Shutdown Method
void cSQLGame::Shutdown(void)
{
	cSQLPool::Shutdown( );
	if ( mIoContextPool != NULL )
	{
		delete mIoContextPool;
		mIoContextPool = NULL;
	}
}

// AllocSQLConnection Method
PerSQLConnection* cSQLGame::AllocSQLConnection(void)
{
	PerSQLConnection* perSQLConnection = (PerSQLConnection*)GlobalAlloc( GPTR, sizeof(PerSQLConnection) );

	if ( perSQLConnection != NULL )
	{
		// PerSQLConnection - 초기화
		perSQLConnection->sqlConnection = new cSQLConnection( );  // 1. SQLConnection 생성.
		perSQLConnection->sqlStatement  = new cSQLGameStmt( );    // 2. cSQLGameStmt   생성.
		perSQLConnection->prev          = NULL;                   // 선형리스트의 포인터 - 이전.
		perSQLConnection->next          = NULL;                   // 선형리스트의 포인터 - 다음.

		// 클래스 생성 확인.
		if ( perSQLConnection->sqlConnection != NULL && perSQLConnection->sqlStatement != NULL )
		{
			// SQLEnvironment 클래스를 참조하여 핸들 생성.
			if ( perSQLConnection->sqlConnection->AllocDbc( mSqlEnv ) == true )
			{
				// DBC 연결.
				if ( perSQLConnection->sqlConnection->Connect( (SQLCHAR*)mDsn, (SQLCHAR*)mUid, (SQLCHAR*)mPwd ) == true )
				{
					// SQLConnection클래스를 참조하여 핸들 생성.
					if ( perSQLConnection->sqlStatement->AllocStmt( perSQLConnection->sqlConnection ) == true )
					{
						// mWorkingSetSize를 증가.
						mWorkingSetSize++;
						return perSQLConnection;
					}
				}
			}
		}
	}

	FreeSQLConnection( &perSQLConnection );
	return perSQLConnection;
}

// PostServerEvent Method
bool cSQLGame::PostServerEvent(LPCTSTR format, ...)
{
	bool retvalue = false;
	if ( g_gameSrv != NULL )
	{
		LPVOID  msgBuf = NULL;
		DWORD   bufferLength;

		va_list args;

		va_start( args, format );

		bufferLength = _vscprintf( format, args ) + 1;
		msgBuf       = malloc( bufferLength );

		vsprintf( (char*)msgBuf, format, args );

		va_end( args );

		if ( msgBuf != NULL )
		{
			retvalue = g_gameSrv->PostServerEvent( (char*)msgBuf );
			free( msgBuf );
		}
	}
	return retvalue;
}

// GetIoContextPool Method
void cSQLGame::GetIoContextPool(SIZE_T& quotaPagedPoolUsage, SIZE_T& quotaNonPagedPoolUsage, SIZE_T& workingSetSize)
{
	mIoContextPool->GetProcessMemoryInfo( quotaPagedPoolUsage, quotaNonPagedPoolUsage, workingSetSize );
}

// Get Method
PerIoContext* cSQLGame::Get( )
{
	return mIoContextPool->GetIoContext( NULL, IOCP_REQUEST_CALLBACK );
}

// Release Method
void cSQLGame::Release(PerIoContext* perIoContext)
{
	DWORD error = 0;
	mIoContextPool->ReleaseIoContext( perIoContext /*false, &error*/ );
	if ( error != 0 )
		PostServerEvent( "WARNING - cSQLGame::Release:Error(=0x%08xh)", error );
}

// WorkerThread Method
DWORD cSQLGame::WorkerThread(void)
{
	PerSQLConnection* perSQLConnection = NULL;
	cSQLGameStmt*     sqlGameStmt      = NULL;
	SQLRETURN         sqlReturn        = 0;

	PerIoContext*     perIoContext     = NULL;
	BOOL              retValue;

	DWORD             bytesTransfered;
	ULONG_PTR         completionKey;
	OVERLAPPED*       overlapped;

	while ( true )
	{
		// 대기중 I/O 가져오기.
		retValue = GetQueuedCompletionStatus( mRequestQueue, &bytesTransfered, &completionKey, &overlapped, INFINITE );

		// Shutdown.
		if ( overlapped == POOL_SHUTDOWN )
			break;

		// Error - 오류.
		if ( retValue == FALSE || bytesTransfered == 0 ) 
			continue;

		// SQLConnection - 가져오기.
		perSQLConnection = GetPool( );

		// SQLConnection - 연결확인.
		if ( perSQLConnection == NULL )
		{
			// 1(순서에 주위), 지연시간 10/1000(s) - CPU 과부화 방지에 사용.
			Sleep( 10 );

			// 2(순서에 주위), 연결이 안 되었을 경우, 다시 시도.
			QueueRequest( completionKey, overlapped, bytesTransfered );
			continue;
		}

		// SQLStatement를 cSQLGameStmt로 캐스팅.
		sqlGameStmt = (cSQLGameStmt*)perSQLConnection->sqlStatement;

		// OVERLAPPED를 PerIoContext로 케스팅.
		perIoContext = (PerIoContext*)overlapped;

		// 1. SQL를 실행
		switch ( perIoContext->iParam )
		{
		/*-- Remove Cooltime
		*/
		case SQL_REQUEST_GAME_INIT:
			sqlReturn = sqlGameStmt->Init( (INIT_GAME*)perIoContext->buffer );
			break;

		/*-- Shutdown - Game Database
		*/
		case SQL_REQUEST_GAME_SHUTDOWN:
			sqlReturn = sqlGameStmt->Shutdown( (SHUTDOWN_GAME*)perIoContext->buffer );
			break;

		/*-- TB_ITEM_DEFINE / TB_ITEM_ABILITY / TB_LIMIT / TB_CARD Table
		*/
		case SQL_GAME_PROCESS_VERIFY_ITEM_DEFINE:
			sqlReturn = sqlGameStmt->VerifyItemDefine( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_ABILITY:
			sqlReturn = sqlGameStmt->VerifyItemAbility( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_COOLTIME2:
			sqlReturn = sqlGameStmt->VerifyItemCooltime2( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_LIMIT:
			sqlReturn = sqlGameStmt->VerifyItemLimit( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_CARD:
			sqlReturn = sqlGameStmt->VerifyItemCard( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_CARD_SLOT:
			sqlReturn = sqlGameStmt->VerifyItemCardSlot( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_TAROT:
			sqlReturn = sqlGameStmt->VerifyItemTarot( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_ENHANCED:
			sqlReturn = sqlGameStmt->VerifyItemEnhanced( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_ENHANCEDRATE:
			sqlReturn = sqlGameStmt->VerifyItemEnhancedRate( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_DISJOINT:
			sqlReturn = sqlGameStmt->VerifyItemDisjoint( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_VERIFY_ITEM_CHANGE:
			sqlReturn = sqlGameStmt->VerifyItemChange( (VERIFY_ITEM_TABLE*)perIoContext->buffer );
			break;

		case SQL_GAME_PROCESS_ITEM_DEFINE:
			sqlReturn = sqlGameStmt->ItemDefine( (ITEM_DEFINE_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_ABILITY:
			sqlReturn = sqlGameStmt->ItemAbility( (ITEM_ABILITY_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_COOLTIME2:
			sqlReturn = sqlGameStmt->ItemCooltime2( (ITEM_COOLTIME2_TABLE*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_ITEM_LIMIT:
			sqlReturn = sqlGameStmt->ItemLimit( (ITEM_LIMIT_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_CARD:
			sqlReturn = sqlGameStmt->ItemCard( (ITEM_CARD_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_CARD_SLOT:
			sqlReturn = sqlGameStmt->ItemCardSlot( (ITEM_CARD_SLOT_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_TAROT:
			sqlReturn = sqlGameStmt->ItemTarot( (ITEM_TAROT_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_ENHANCED:
			sqlReturn = sqlGameStmt->ItemEnhanced( (ITEM_ENHANCED_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_ENHANCEDRATE:
			sqlReturn = sqlGameStmt->ItemEnhancedRate( (ITEM_ENHANCED_RATE_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_DISJOINT:
			sqlReturn = sqlGameStmt->ItemDisjoint( (ITEM_DISJOINT_TABLE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_CHANGE:
			sqlReturn = sqlGameStmt->ItemChange( (ITEM_CHANGE_TABLE*)perIoContext->buffer );
			break;

		case SQL_GAME_PROCESS_VERIFY_DEFAULT_ITEMS:
			sqlReturn = sqlGameStmt->VerifyDefaultItems( (VERIFY_DEFAULT_ITEMS*)perIoContext->buffer );
			break;

		case SQL_GAME_PROCESS_VERIFY_GUILD:
			sqlReturn = sqlGameStmt->VerifyGuild( (VERIFY_GUILD*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILD_SELECT:
			sqlReturn = sqlGameStmt->GuildSelect( (GUILD_SELECT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILDUSER_SELECT:
			sqlReturn = sqlGameStmt->GuildUserSelect( (GUILDUSER_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;

		/*-- TB_CHARACTER Table
		*/
		case SQL_GAME_PROCESS_CHARACTER_LIST:
			sqlReturn = sqlGameStmt->CharacterList( (CHARACTER_LIST*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_CHARACTER_NAME:
			sqlReturn = sqlGameStmt->CharacterName( (CHARACTER_NAME*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_INSERT:
			sqlReturn = sqlGameStmt->CharacterInsert( (CHARACTER_INSERT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_CHARACTER_DELETE:
			sqlReturn = sqlGameStmt->CharacterDelete( (CHARACTER_DELETE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_UPDATE:
			sqlReturn = sqlGameStmt->CharacterUpdate( (CHARACTER_UPDATE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_SELECT:
			sqlReturn = sqlGameStmt->CharacterSelect( (CHARACTER_SELECT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_EQUIP:
			sqlReturn = sqlGameStmt->CharacterEquip( (CHARACTER_EQUIP*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_MONEY:
			sqlReturn = sqlGameStmt->CharacterMoney( (CHARACTER_MONEY*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_DEPOSIT:
			sqlReturn = sqlGameStmt->CharacterDeposit( (CHARACTER_DEPOSIT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_TAROT_POINT:
			sqlReturn = sqlGameStmt->CharacterTarotPoint( (CHARACTER_TAROT_POINT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_PVP_POINT:
			sqlReturn = sqlGameStmt->CharacterPvpPoint( (CHARACTER_PVP_POINT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_LEVEL:
			sqlReturn = sqlGameStmt->CharacterLevel( (CHARACTER_LEVEL*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_SKILLLEVEL:
			sqlReturn = sqlGameStmt->CharacterSkillLevel( (CHARACTER_SKILLLEVEL*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_ACTIVE_WEPON:
			sqlReturn = sqlGameStmt->CharacterActiveWeapon( (CHARACTER_ACTIVE_WEAPON*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_OPTION:
			sqlReturn = sqlGameStmt->CharacterOption( (CHARACTER_OPTION*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_FORCETYPE:
			sqlReturn = sqlGameStmt->CharacterForce( (CHARACTER_FORCE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_SKILLRESET:
			sqlReturn = sqlGameStmt->CharacterSkillReset( (CHARACTER_SKILL_RESET*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_CHARACTER_BLOCK_SELECT:
			sqlReturn = sqlGameStmt->CharacterBlockSelect( (CHARACTER_BLOCK_SELECT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_CHARACTER_BLOCK_INSERT:
			sqlReturn = sqlGameStmt->CharacterBlockInsert( (CHARACTER_BLOCK_INSERT*)perIoContext->buffer );
			break;

		/*-- TB_INVENTORY Table
		*/
		case SQL_GAME_PROCESS_INVENTORY_INSERT:
			sqlReturn = sqlGameStmt->InventoryInsert( (INVENTORY_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_SELECT:
			sqlReturn = sqlGameStmt->InventorySelect( (INVENTORY_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_INVENTORY_DELETE:
			sqlReturn = sqlGameStmt->InventoryDelete( (INVENTORY_DELETE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_COOLTIME_SELECT:
			sqlReturn = sqlGameStmt->InventoryCooltimeSelect( (INVENTORY_COOLTIME_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_INVENTORY_COOLTIME_INSERT:
			sqlReturn = sqlGameStmt->InventoryCooltimeInsert( (INVENTORY_COOLTIME_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_REMOVE:
			sqlReturn = sqlGameStmt->InventoryRemove( (INVENTORY_REMOVE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_USE:
			sqlReturn = sqlGameStmt->InventoryUse( (INVENTORY_USE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_SWAP:
			sqlReturn = sqlGameStmt->InventorySwap( (INVENTORY_SWAP*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_MOVE:
			sqlReturn = sqlGameStmt->InventoryMove( (INVENTORY_MOVE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_EXCEPT:
			sqlReturn = sqlGameStmt->InventoryExcept( (INVENTORY_EXCEPT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_MERGE:
			sqlReturn = sqlGameStmt->InventoryMerge( (INVENTORY_MERGE*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_INVENTORY_DIVIDE:
			sqlReturn = sqlGameStmt->InventoryDivide( (INVENTORY_DIVIDE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_MOVE2:
			sqlReturn = sqlGameStmt->InventoryMove2( (INVENTORY_MOVE2*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_ENHANCED:
			sqlReturn = sqlGameStmt->InventoryEnhanced( (INVENTORY_ENHANCED*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_DISJOINT:
			sqlReturn = sqlGameStmt->InventoryDisjoint( (INVENTORY_DISJOINT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_PUT_CARD:
			sqlReturn = sqlGameStmt->InventoryPutCard( (INVENTORY_PUT_CARD*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INVENTORY_CHANGE:
			sqlReturn = sqlGameStmt->InventoryChange( (INVENTORY_CHANGE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_SELL:
			sqlReturn = sqlGameStmt->ItemSell( (ITEM_SELL*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_BUY:
			sqlReturn = sqlGameStmt->ItemBuy( (ITEM_BUY*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_COLLECT:
			sqlReturn = sqlGameStmt->ItemCollect( (ITEM_COLLECT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_GET:
			sqlReturn = sqlGameStmt->ItemGet( (ITEM_GET*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_GET_QUEST:
			sqlReturn = sqlGameStmt->ItemGetQuest( (ITEM_GET_QUEST*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_USE:
			sqlReturn = sqlGameStmt->ItemUse( (ITEM_USE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_EXCHANGE:
			sqlReturn = sqlGameStmt->ItemExchange( (ITEM_EXCHANGE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_ITEM_MIX:
			sqlReturn = sqlGameStmt->ItemMix( (ITEM_MIX*)perIoContext->buffer );
			break;

		/*-- TB_NOTE Table
		*/
		case SQL_GAME_PROCESS_NOTE_SELECT:
			sqlReturn = sqlGameStmt->NoteSelect( (NOTE_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_NOTE_INSERT:
			sqlReturn = sqlGameStmt->NoteInsert( (NOTE_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_NOTE_DELETE:
			sqlReturn = sqlGameStmt->NoteDelete( (NOTE_DELETE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILDNOTE_INSERT:
			sqlReturn = sqlGameStmt->GuildNoteInsert( (GUILDNOTE_INSERT*)perIoContext->buffer );
			break;

		/*-- TB_FRIEND Table
		*/
		case SQL_GAME_PROCESS_FRIEND_SELECT:
			sqlReturn = sqlGameStmt->FriendSelect( (FRIEND_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_FRIEND_INSERT:
			sqlReturn = sqlGameStmt->FriendInsert( (FRIEND_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_FRIEND_UPDATE:
			sqlReturn = sqlGameStmt->FriendUpdate( (FRIEND_UPDATE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_FRIEND_DELETE:
			sqlReturn = sqlGameStmt->FriendDelete( (FRIEND_DELETE*)perIoContext->buffer );
			break;

		/*-- TB_ITEM_SPREAD Table
		*/
		case SQL_GAME_PROCESS_ITEM_SPREAD_VALUE:
			sqlReturn = sqlGameStmt->ItemSpreadValue( (ITEM_SPREAD_VALUE*)perIoContext->buffer );
			break;
		/*-- TB_ITEM_TAROT_RESULT Table
		*/
		case SQL_GAME_PROCESS_ITEM_TAROT_RESULT:
			sqlReturn = sqlGameStmt->ItemTarotResult( (ITEM_TAROT_RESULT*)perIoContext->buffer );
			break;

		/*-- TB_CHARACTER_SKILL Table
		*/
		case SQL_GAME_PROCESS_SKILL_SELECT:
			sqlReturn = sqlGameStmt->SkillSelect( (SKILL_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_SKILL_INSERT:
			sqlReturn = sqlGameStmt->SkillInsert( (SKILL_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_SKILL_UPDATE:
			sqlReturn = sqlGameStmt->SkillUpdate( (SKILL_UPDATE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_SKILL_COOLTIME:
			sqlReturn = sqlGameStmt->SkillCoolTime( (SKILL_COOLTIME*)perIoContext->buffer );
			break;

		case SQL_GAME_PROCESS_INFLUENCE_SELECT:
			sqlReturn = sqlGameStmt->SkillInfluenceSelect( (SKILL_INFLUENCE_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_INFLUENCE_DELETE:
			sqlReturn = sqlGameStmt->SkillInfluenceDelete( (SKILL_INFLUENCE_DELETE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_INFLUENCE_INSERT:
			sqlReturn = sqlGameStmt->SkillInfluenceInsert( (SKILL_INFLUENCE_INSERT*)perIoContext->buffer );
			break;

		/*-- TB_STALL_SELL Table
		*/
		case SQL_GAME_PROCESS_STALL_SELL_SEARCH:
			sqlReturn = sqlGameStmt->StallSellSearch( (STALL_SELL_SEARCH*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_STALL_SELL_INSERT:
			sqlReturn = sqlGameStmt->StallSellInsert( (STALL_SELL_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_STALL_SELL_REMOVE:
			sqlReturn = sqlGameStmt->StallSellRemove( (STALL_SELL_REMOVE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_STALL_SELL_CLEAR:
			sqlReturn = sqlGameStmt->StallSellClear( (STALL_SELL_CLEAR*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_STALL_SELL_GET:
			sqlReturn = sqlGameStmt->StallSellGet( (STALL_SELL_GET*)perIoContext->buffer );
			break;

		/*-- TB_SHORTCUT Table
		*/
		case SQL_GAME_PROCESS_SHORTCUT_SELECT:
			sqlReturn = sqlGameStmt->ShortcutSelect( (SHORTCUT_SELECT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_SHORTCUT_UPDATE:
			sqlReturn = sqlGameStmt->ShortcutUpdate( (SHORTCUT_UPDATE*)perIoContext->buffer );
			break;

		/*-- TB_QUEST_PROGRESS Table
		*/
		case SQL_GAME_PROCESS_QUEST_INSERT:
			sqlReturn = sqlGameStmt->QuestInsert( (QUEST_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_QUEST_INSERTBYITEM:
			sqlReturn = sqlGameStmt->QuestInsertByItem( (QUEST_INSERTBYITEM*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_QUEST_SELECT:
			sqlReturn = sqlGameStmt->QuestSelect( (QUEST_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_QUEST_UPDATE:
			sqlReturn = sqlGameStmt->QuestUpdate( (QUEST_UPDATE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_QUEST_DELETE:
		case SQL_GAME_PROCESS_QUEST_DELETEAUTO:
			sqlReturn = sqlGameStmt->QuestDelete( (QUEST_DELETE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_QUEST_COMPLETE:
			sqlReturn = sqlGameStmt->QuestComplete( (QUEST_COMPLETE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_QUEST_REWARD:
			sqlReturn = sqlGameStmt->QuestReward( (QUEST_REWARD*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_QUEST_ENDLISTSELECT:
			sqlReturn = sqlGameStmt->QuestEndListSelect( (QUEST_ENDLIST*)perIoContext->buffer, perIoContext->offset );
			break;		
		case SQL_GAME_PROCESS_QUEST_REMOVE:
			sqlReturn = sqlGameStmt->QuestRemove( (QUEST_REMOVE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_TITLE_INSERT:
			sqlReturn = sqlGameStmt->TitleInsert( (TITLE_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_TITLE_SELECT:
			sqlReturn = sqlGameStmt->TitleSelect( (TITLE_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_GUILD_CREATE:
			sqlReturn = sqlGameStmt->GuildCreate( (GUILD_CREATE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILDUSER_ADD:
			sqlReturn = sqlGameStmt->GuildUserAdd( (GUILDUSER_ADD*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILDUSER_OUT:
			sqlReturn = sqlGameStmt->GuildUserOut( (GUILDUSER_OUT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILDUSER_CUT:
			sqlReturn = sqlGameStmt->GuildUserOut( (GUILDUSER_OUT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILD_DELETE:
			sqlReturn = sqlGameStmt->GuildDelete( (GUILD_DELETE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILD_UPDATE:
			sqlReturn = sqlGameStmt->GuildUpdate( (GUILD_UPDATE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILDUSER_GIVEPOSITION:
			sqlReturn = sqlGameStmt->GuildUserGivePosition( (GUILDUSER_GIVEPOSITION*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_GUILDMARK_UPDATE:
			sqlReturn = sqlGameStmt->GuildMarkUpdate( (GUILDMARK_UPDATE*)perIoContext->buffer );
			break;

			/*-- TB_CHARACTER_MAKESKILL Table
			*/
		case SQL_GAME_PROCESS_MAKESKILL_INSERT:
			sqlReturn = sqlGameStmt->MakeSkillInsert( (MAKESKILL_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_MAKESKILL_SELECT:
			sqlReturn = sqlGameStmt->MakeSkillSelect( (MAKESKILL_SELECT*)perIoContext->buffer, perIoContext->offset );
			break;
		case SQL_GAME_PROCESS_MAKESKILL_DELETE:
			sqlReturn = sqlGameStmt->MakeSkillDelete( (MAKESKILL_DELETE*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_RECIPE_INSERT:
			sqlReturn = sqlGameStmt->RecipeInsert( (RECIPE_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_RECIPE_GROUP_INSERT:
			sqlReturn = sqlGameStmt->RecipeGroupInsert( (RECIPE_GROUP_INSERT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_RECIPE_COOLTIME:
			sqlReturn = sqlGameStmt->RecipeCoolTime( (RECIPE_COOLTIME*)perIoContext->buffer );
			break;

		case SQL_GAME_PROCESS_FORTUNE_SELECT:
			sqlReturn = sqlGameStmt->FortuneSelect( (FORTUNE_SELECT*)perIoContext->buffer );
			break;
		case SQL_GAME_PROCESS_FORTUNE_UPDATE:
			sqlReturn = sqlGameStmt->FortuneUpdate( (FORTUNE_UPDATE*)perIoContext->buffer );
			break;

		/*-- Error
		*/
		default:
			sqlReturn = SQL_ERROR;
			break;
		}

		// 2. 이벤트 - 오류만 기록.
		if ( !SQL_SUCCEEDED( sqlReturn ) )
		{
			// 오류확인.
			SQLHSTMT    hstmt = sqlGameStmt->GetSqlStmt( );
			SQLCHAR     sqlstate[ SQL_SQLSTATE_SIZE + 1 ]     = "\0";
			SQLINTEGER  nativeErrorPtr                        = 0;
			SQLCHAR     messageText[ SQL_MAX_MESSAGE_LENGTH ] = "\0";
			SQLSMALLINT bufferLength                          = SQL_MAX_MESSAGE_LENGTH;
			SQLSMALLINT textLength                            = 0;
			SQLRETURN   result;

			result = SQLGetDiagRec( SQL_HANDLE_STMT, hstmt, 1, sqlstate, &nativeErrorPtr, messageText, bufferLength, &textLength );

			// 저장프로시저 쿼리 마무리.
			while ( SQLMoreResults( hstmt ) == SQL_SUCCESS );
			// 열려있는 결과 닫기. (Close the open result set.)
			SQLCloseCursor( hstmt );

			// 로그전송.
			PostServerEvent( "cSQLGame::IParam[%d]:Returns[%d] - SQL Error State string[%s] Native Error code[%d] SQL Error Text string[%s]",
							 perIoContext->iParam,
							 sqlReturn,
							 sqlstate,
							 nativeErrorPtr,
							 messageText );
		}

		// 3. PerIoContext 사용완료 - 결과는 콜백으로 되돌려준다.
		// perIoContext->requestType   = IOCP_REQUEST_CALLBACK;
		// perIoContext->requestResult = IOCP_REQUEST_SUCCESS;
		cGameProcess* gameProcess = g_gameSrv->GetGameProcess( );
		if ( gameProcess != NULL )
		{
			perIoContext->requestResult = (sqlReturn == SQL_SUCCESS || sqlReturn == SQL_SUCCESS_WITH_INFO) ? IOCP_REQUEST_SUCCESS : IOCP_REQUEST_ERROR;
			gameProcess->QueueRequest( completionKey, (OVERLAPPED*)perIoContext, perIoContext->offset );
		}

		// SQLConnection - 내보내기.
//		ReleasePool( perSQLConnection, true );
		ReleasePool( perSQLConnection, !(sqlReturn == SQL_SUCCESS || sqlReturn == SQL_SUCCESS_WITH_INFO) );
	}
	return 0L;
}

bool cSQLGame::ConsoleInsertInit()
{
	mpSkillScript = new cSkillScript;
	if ( !mpSkillScript->Init( ) )
		return false;

	mpTriggerManager = new cTriggerManager;
	if ( !mpTriggerManager->Init( ) )
		return false;

	mpQuestManager = new cQuestManager;
	if ( !mpQuestManager->Init( ) )
		return false;

	mpTitleManager = new cTitleManager;
	if( !mpTitleManager->Init() )
		return false;
	return true;
}

void cSQLGame::ConsoleInsertRelease()
{
	mpSkillScript->Release();
	delete mpSkillScript;
}
