Explorar el Código

Turned SqlStmt into a C++ class (#8857)

Made handling easier (especially allocation and freeing) and more error prone

Thanks to @vstumpf
Lemongrass3110 hace 5 meses
padre
commit
70232309fb

+ 2 - 2
src/char/CMakeLists.txt

@@ -14,8 +14,8 @@ file(GLOB CHAR_SOURCES_CXX ${CHAR_SOURCE_DIR}/*.cpp)
 set(CHAR_SOURCES ${CHAR_SOURCES_C} ${CHAR_SOURCES_CXX})
 #message( STATUS "CHAR_SOURCES="${CHAR_SOURCES})
 set( DEPENDENCIES common )
-set( LIBRARIES ${GLOBAL_LIBRARIES} )
-set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ${RA_INCLUDE_DIRS} )
+set( LIBRARIES ${GLOBAL_LIBRARIES} ${MYSQL_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ${RA_INCLUDE_DIRS} ${MYSQL_INCLUDE_DIRS} )
 set( DEFINITIONS "${GLOBAL_DEFINITIONS} ${COMMON_BASE_DEFINITIONS}" )
 set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${COMMON_HEADERS} ${CHAR_HEADERS} ${CHAR_SOURCES} )
 source_group( common FILES ${COMMON_BASE_HEADERS} ${COMMON_HEADERS} )

+ 4 - 4
src/char/char-server.vcxproj

@@ -109,7 +109,7 @@
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>$(DefineConstants);WIN32;FD_SETSIZE=4096;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS;LIBCONFIG_STATIC;YY_USE_CONST;_DEBUG;_CONSOLE;_LIB;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -130,7 +130,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -151,7 +151,7 @@
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -174,7 +174,7 @@
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>

+ 215 - 244
src/char/char.cpp

@@ -531,7 +531,7 @@ int32 char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 /// Saves an array of 'item' entries into the specified table.
 int32 char_memitemdata_to_sql(const struct item items[], int32 max, int32 id, enum storage_type tableswitch, uint8 stor_id) {
 	StringBuf buf;
-	SqlStmt* stmt;
+	SqlStmt stmt{ *sql_handle };
 	int32 i, j, offset = 0, errors = 0;
 	const char *tablename, *selectoption, *printname;
 	struct item item; // temp storage variable
@@ -585,42 +585,40 @@ int32 char_memitemdata_to_sql(const struct item items[], int32 max, int32 id, en
 	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id);
 
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||  SQL_ERROR == SqlStmt_Execute(stmt) )
+	if( SQL_ERROR == stmt.PrepareStr( StringBuf_Value(&buf))
+	||  SQL_ERROR == stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 		return 1;
 	}
 
-	SqlStmt_BindColumn(stmt, 0, SQLDT_INT,       &item.id,          0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 1, SQLDT_UINT,      &item.nameid,      0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,     &item.amount,      0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 3, SQLDT_UINT,      &item.equip,       0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR,      &item.identify,    0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,      &item.refine,      0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &item.attribute,   0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &item.expire_time, 0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 8, SQLDT_UINT,      &item.bound,       0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 9, SQLDT_UINT64,    &item.unique_id,   0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt,10, SQLDT_INT8,      &item.enchantgrade,0, nullptr, nullptr);
+	stmt.BindColumn( 0, SQLDT_INT,       &item.id,          0, nullptr, nullptr);
+	stmt.BindColumn( 1, SQLDT_UINT,      &item.nameid,      0, nullptr, nullptr);
+	stmt.BindColumn( 2, SQLDT_SHORT,     &item.amount,      0, nullptr, nullptr);
+	stmt.BindColumn( 3, SQLDT_UINT,      &item.equip,       0, nullptr, nullptr);
+	stmt.BindColumn( 4, SQLDT_CHAR,      &item.identify,    0, nullptr, nullptr);
+	stmt.BindColumn( 5, SQLDT_CHAR,      &item.refine,      0, nullptr, nullptr);
+	stmt.BindColumn( 6, SQLDT_CHAR,      &item.attribute,   0, nullptr, nullptr);
+	stmt.BindColumn( 7, SQLDT_UINT,      &item.expire_time, 0, nullptr, nullptr);
+	stmt.BindColumn( 8, SQLDT_UINT,      &item.bound,       0, nullptr, nullptr);
+	stmt.BindColumn( 9, SQLDT_UINT64,    &item.unique_id,   0, nullptr, nullptr);
+	stmt.BindColumn(10, SQLDT_INT8,      &item.enchantgrade,0, nullptr, nullptr);
 	if (tableswitch == TABLE_INVENTORY){
-		SqlStmt_BindColumn(stmt, 11, SQLDT_CHAR, &item.favorite,    0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 12, SQLDT_UINT, &item.equipSwitch, 0, nullptr, nullptr);
+		stmt.BindColumn(11, SQLDT_CHAR, &item.favorite,    0, nullptr, nullptr);
+		stmt.BindColumn(12, SQLDT_UINT, &item.equipSwitch, 0, nullptr, nullptr);
 	}
 	for( i = 0; i < MAX_SLOTS; ++i )
-		SqlStmt_BindColumn(stmt, 11+offset+i, SQLDT_UINT, &item.card[i], 0, nullptr, nullptr);
+		stmt.BindColumn(11+offset+i, SQLDT_UINT, &item.card[i], 0, nullptr, nullptr);
 	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		SqlStmt_BindColumn(stmt, 11+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 12+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 13+offset+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, nullptr, nullptr);
+		stmt.BindColumn(11+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, nullptr, nullptr);
+		stmt.BindColumn(12+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, nullptr, nullptr);
+		stmt.BindColumn(13+offset+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, nullptr, nullptr);
 	}
 	// bit array indicating which inventory items have already been matched
 	flag = (bool*) aCalloc(max, sizeof(bool));
 
-	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
+	while( SQL_SUCCESS == stmt.NextRow() )
 	{
 		found = false;
 		// search for the presence of the item in the char's inventory
@@ -690,7 +688,6 @@ int32 char_memitemdata_to_sql(const struct item items[], int32 max, int32 id, en
 			}
 		}
 	}
-	SqlStmt_Free(stmt);
 
 	StringBuf_Clear(&buf);
 	StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`, `enchantgrade`", tablename, selectoption);
@@ -747,7 +744,7 @@ int32 char_memitemdata_to_sql(const struct item items[], int32 max, int32 id, en
 
 bool char_memitemdata_from_sql(struct s_storage* p, int32 max, int32 id, enum storage_type tableswitch, uint8 stor_id) {
 	StringBuf buf;
-	SqlStmt* stmt;
+	SqlStmt stmt{ *sql_handle };
 	int32 i,j, offset = 0, max2;
 	struct item item, *storage;
 	const char *tablename, *selectoption, *printname;
@@ -792,11 +789,6 @@ bool char_memitemdata_from_sql(struct s_storage* p, int32 max, int32 id, enum st
 	p->stor_id = stor_id;
 	p->max_amount = max2;
 
-	stmt = SqlStmt_Malloc(sql_handle);
-	if (stmt == nullptr) {
-		SqlStmt_ShowDebug(stmt);
-		return false;
-	}
 
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`,`enchantgrade`");
@@ -813,47 +805,44 @@ bool char_memitemdata_from_sql(struct s_storage* p, int32 max, int32 id, enum st
 	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`=? ORDER BY `nameid`", tablename, selectoption );
 
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-		||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &id, 0)
-		||	SQL_ERROR == SqlStmt_Execute(stmt) )
+	if( SQL_ERROR == stmt.PrepareStr(StringBuf_Value(&buf))
+		||	SQL_ERROR == stmt.BindParam(0, SQLDT_INT, &id, 0)
+		||	SQL_ERROR == stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 		return false;
 	}
 
-	SqlStmt_BindColumn(stmt, 0, SQLDT_INT,          &item.id,        0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 1, SQLDT_UINT,         &item.nameid,    0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,        &item.amount,    0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 3, SQLDT_UINT,         &item.equip,     0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR,         &item.identify,  0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,         &item.refine,    0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,         &item.attribute, 0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,         &item.expire_time, 0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,         &item.bound,     0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 9, SQLDT_ULONGLONG,    &item.unique_id, 0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt,10, SQLDT_INT8,         &item.enchantgrade, 0, nullptr, nullptr);
+	stmt.BindColumn( 0, SQLDT_INT,          &item.id,        0, nullptr, nullptr);
+	stmt.BindColumn( 1, SQLDT_UINT,         &item.nameid,    0, nullptr, nullptr);
+	stmt.BindColumn( 2, SQLDT_SHORT,        &item.amount,    0, nullptr, nullptr);
+	stmt.BindColumn( 3, SQLDT_UINT,         &item.equip,     0, nullptr, nullptr);
+	stmt.BindColumn( 4, SQLDT_CHAR,         &item.identify,  0, nullptr, nullptr);
+	stmt.BindColumn( 5, SQLDT_CHAR,         &item.refine,    0, nullptr, nullptr);
+	stmt.BindColumn( 6, SQLDT_CHAR,         &item.attribute, 0, nullptr, nullptr);
+	stmt.BindColumn( 7, SQLDT_UINT,         &item.expire_time, 0, nullptr, nullptr);
+	stmt.BindColumn( 8, SQLDT_CHAR,         &item.bound,     0, nullptr, nullptr);
+	stmt.BindColumn( 9, SQLDT_ULONGLONG,    &item.unique_id, 0, nullptr, nullptr);
+	stmt.BindColumn(10, SQLDT_INT8,         &item.enchantgrade, 0, nullptr, nullptr);
 	if (tableswitch == TABLE_INVENTORY){
-		SqlStmt_BindColumn(stmt, 11, SQLDT_CHAR, &item.favorite,    0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 12, SQLDT_UINT, &item.equipSwitch, 0, nullptr, nullptr);
+		stmt.BindColumn(11, SQLDT_CHAR, &item.favorite,    0, nullptr, nullptr);
+		stmt.BindColumn(12, SQLDT_UINT, &item.equipSwitch, 0, nullptr, nullptr);
 	}
 	for( i = 0; i < MAX_SLOTS; ++i )
-		SqlStmt_BindColumn(stmt, 11+offset+i, SQLDT_UINT, &item.card[i],   0, nullptr, nullptr);
+		stmt.BindColumn(11+offset+i, SQLDT_UINT, &item.card[i],   0, nullptr, nullptr);
  	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		SqlStmt_BindColumn(stmt, 11+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 12+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 13+offset+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, nullptr, nullptr);
+		stmt.BindColumn(11+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, nullptr, nullptr);
+		stmt.BindColumn(12+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, nullptr, nullptr);
+		stmt.BindColumn(13+offset+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, nullptr, nullptr);
  	}
 
-	for( i = 0; i < max && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
+	for( i = 0; i < max && SQL_SUCCESS == stmt.NextRow(); ++i )
 		memcpy(&storage[i], &item, sizeof(item));
 
 	p->amount = i;
 	ShowInfo("Loaded %s data from table %s for %s: %d (total: %d)\n", printname, tablename, selectoption, id, p->amount);
 
-	SqlStmt_FreeResult(stmt);
-	SqlStmt_Free(stmt);
 	StringBuf_Destroy(&buf);
 
 	return true;
@@ -911,16 +900,11 @@ int32 char_mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p);
 //=====================================================================================================
 // Loads the basic character rooster for the given account. Returns total buffer used.
 int32 char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf, uint8* count ) {
-	SqlStmt* stmt;
+	SqlStmt stmt{ *sql_handle };
 	struct mmo_charstatus p;
 	int32 j = 0, i;
 	char sex[2];
 
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( stmt == nullptr ) {
-		SqlStmt_ShowDebug(stmt);
-		return 0;
-	}
 	memset(&p, 0, sizeof(p));
 
 	for( i = 0; i < MAX_CHARS; i++ ) {
@@ -929,7 +913,7 @@ int32 char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf, uint8* co
 	}
 
 	// read char data
-	if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT "
+	if( SQL_ERROR == stmt.Prepare( "SELECT "
 		"`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`,"
 		"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`,"
 		"`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`,"
@@ -939,73 +923,72 @@ int32 char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf, uint8* co
 		"`max_ap`,`ap`,`trait_point`,`pow`,`sta`,`wis`,`spl`,`con`,`crt`,"
 		"`inventory_slots`,`body_direction`,`disable_call`"
 		" FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", schema_config.char_db, sd->account_id, MAX_CHARS)
-	||	SQL_ERROR == SqlStmt_Execute(stmt)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0,  SQLDT_INT,    &p.char_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1,  SQLDT_UCHAR,  &p.slot, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2,  SQLDT_STRING, &p.name, sizeof(p.name), nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 3,  SQLDT_SHORT,  &p.class_, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 4,  SQLDT_UINT,   &p.base_level, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 5,  SQLDT_UINT,   &p.job_level, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 6,  SQLDT_UINT64, &p.base_exp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 7,  SQLDT_UINT64, &p.job_exp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 8,  SQLDT_INT,    &p.zeny, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 9,  SQLDT_SHORT,  &p.str, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT,  &p.agi, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT,  &p.vit, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT,  &p.int_, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT,  &p.dex, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT,  &p.luk, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_UINT,   &p.max_hp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_UINT,   &p.hp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_UINT,   &p.max_sp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_UINT,   &p.sp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT,   &p.status_point, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT,   &p.skill_point, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT,   &p.option, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR,  &p.karma, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT,  &p.manner, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT,  &p.hair, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT,  &p.hair_color, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT,  &p.clothes_color, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT,  &p.body, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT,  &p.weapon, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT,  &p.shield, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT,  &p.head_top, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT,  &p.head_mid, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT,  &p.head_bottom, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_STRING, &p.last_point.map, sizeof(p.last_point.map), nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT,	&p.rename, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_UINT32, &p.delete_date, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT,  &p.robe, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_UINT,   &p.character_moves, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_LONG,   &p.unban_time, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_UCHAR,  &p.font, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_UINT,   &p.uniqueitem_counter, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_ENUM,   &sex, sizeof(sex), nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_UCHAR,  &p.hotkey_rowshift, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_ULONG,  &p.title_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_UINT16, &p.show_equip, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_UCHAR,  &p.hotkey_rowshift2, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_UINT,   &p.max_ap, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_UINT,   &p.ap, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_UINT,   &p.trait_point, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT,  &p.pow, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_SHORT,  &p.sta, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT,  &p.wis, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 52, SQLDT_SHORT,  &p.spl, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 53, SQLDT_SHORT,  &p.con, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 54, SQLDT_SHORT,  &p.crt, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 55, SQLDT_UINT16, &p.inventory_slots, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 56, SQLDT_UINT8,  &p.body_direction, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 57, SQLDT_UINT16, &p.disable_call, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.Execute()
+	||	SQL_ERROR == stmt.BindColumn( 0,  SQLDT_INT,    &p.char_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 1,  SQLDT_UCHAR,  &p.slot, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 2,  SQLDT_STRING, &p.name, sizeof(p.name), nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 3,  SQLDT_SHORT,  &p.class_, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 4,  SQLDT_UINT,   &p.base_level, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 5,  SQLDT_UINT,   &p.job_level, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 6,  SQLDT_UINT64, &p.base_exp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 7,  SQLDT_UINT64, &p.job_exp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 8,  SQLDT_INT,    &p.zeny, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 9,  SQLDT_SHORT,  &p.str, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 10, SQLDT_SHORT,  &p.agi, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 11, SQLDT_SHORT,  &p.vit, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 12, SQLDT_SHORT,  &p.int_, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 13, SQLDT_SHORT,  &p.dex, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 14, SQLDT_SHORT,  &p.luk, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 15, SQLDT_UINT,   &p.max_hp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 16, SQLDT_UINT,   &p.hp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 17, SQLDT_UINT,   &p.max_sp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 18, SQLDT_UINT,   &p.sp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 19, SQLDT_UINT,   &p.status_point, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 20, SQLDT_UINT,   &p.skill_point, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 21, SQLDT_UINT,   &p.option, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 22, SQLDT_UCHAR,  &p.karma, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 23, SQLDT_SHORT,  &p.manner, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 24, SQLDT_SHORT,  &p.hair, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 25, SQLDT_SHORT,  &p.hair_color, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 26, SQLDT_SHORT,  &p.clothes_color, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 27, SQLDT_SHORT,  &p.body, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 28, SQLDT_SHORT,  &p.weapon, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 29, SQLDT_SHORT,  &p.shield, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 30, SQLDT_SHORT,  &p.head_top, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 31, SQLDT_SHORT,  &p.head_mid, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 32, SQLDT_SHORT,  &p.head_bottom, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 33, SQLDT_STRING, &p.last_point.map, sizeof(p.last_point.map), nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 34, SQLDT_SHORT,	&p.rename, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 35, SQLDT_UINT32, &p.delete_date, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 36, SQLDT_SHORT,  &p.robe, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 37, SQLDT_UINT,   &p.character_moves, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 38, SQLDT_LONG,   &p.unban_time, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 39, SQLDT_UCHAR,  &p.font, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 40, SQLDT_UINT,   &p.uniqueitem_counter, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 41, SQLDT_ENUM,   &sex, sizeof(sex), nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 42, SQLDT_UCHAR,  &p.hotkey_rowshift, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 43, SQLDT_ULONG,  &p.title_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 44, SQLDT_UINT16, &p.show_equip, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 45, SQLDT_UCHAR,  &p.hotkey_rowshift2, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 46, SQLDT_UINT,   &p.max_ap, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 47, SQLDT_UINT,   &p.ap, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 48, SQLDT_UINT,   &p.trait_point, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 49, SQLDT_SHORT,  &p.pow, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 50, SQLDT_SHORT,  &p.sta, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 51, SQLDT_SHORT,  &p.wis, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 52, SQLDT_SHORT,  &p.spl, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 53, SQLDT_SHORT,  &p.con, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 54, SQLDT_SHORT,  &p.crt, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 55, SQLDT_UINT16, &p.inventory_slots, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 56, SQLDT_UINT8,  &p.body_direction, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn( 57, SQLDT_UINT16, &p.disable_call, 0, nullptr, nullptr)
 	)
 	{
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		return 0;
 	}
 
-	for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ )
+	for( i = 0; i < MAX_CHARS && SQL_SUCCESS == stmt.NextRow(); i++ )
 	{
 		sd->found_char[p.slot] = p.char_id;
 		sd->unban_time[p.slot] = p.unban_time;
@@ -1023,14 +1006,13 @@ int32 char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf, uint8* co
 
 	memset(sd->new_name,0,sizeof(sd->new_name));
 
-	SqlStmt_Free(stmt);
 	return j;
 }
 
 //=====================================================================================================
 int32 char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_everything) {
 	int32 i;
-	SqlStmt* stmt;
+	SqlStmt stmt{ *sql_handle };
 	struct s_point_str tmp_point;
 	struct s_skill tmp_skill;
 	uint16 skill_count = 0;
@@ -1046,15 +1028,8 @@ int32 char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_
 
 	if (charserv_config.save_log) ShowInfo("Char load request (%d)\n", char_id);
 
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( stmt == nullptr )
-	{
-		SqlStmt_ShowDebug(stmt);
-		return 0;
-	}
-
 	// read char data
-	if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT "
+	if( SQL_ERROR == stmt.Prepare( "SELECT "
 		"`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`,"
 		"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`,"
 		"`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,"
@@ -1064,94 +1039,92 @@ int32 char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_
 		"`max_ap`,`ap`,`trait_point`,`pow`,`sta`,`wis`,`spl`,`con`,`crt`,"
 		"`inventory_slots`,`body_direction`,`disable_call`,`last_instanceid`"
 		" FROM `%s` WHERE `char_id`=? LIMIT 1", schema_config.char_db)
-	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
-	||	SQL_ERROR == SqlStmt_Execute(stmt)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0,  SQLDT_INT,    &p->char_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1,  SQLDT_INT,    &p->account_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2,  SQLDT_UCHAR,  &p->slot, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 3,  SQLDT_STRING, &p->name, sizeof(p->name), nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 4,  SQLDT_SHORT,  &p->class_, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 5,  SQLDT_UINT,   &p->base_level, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 6,  SQLDT_UINT,   &p->job_level, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 7,  SQLDT_UINT64, &p->base_exp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 8,  SQLDT_UINT64, &p->job_exp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 9,  SQLDT_INT,    &p->zeny, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT,  &p->str, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT,  &p->agi, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT,  &p->vit, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT,  &p->int_, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT,  &p->dex, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT,  &p->luk, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_UINT,   &p->max_hp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_UINT,   &p->hp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_UINT,   &p->max_sp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT,   &p->sp, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT,   &p->status_point, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT,   &p->skill_point, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT,   &p->option, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR,  &p->karma, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT,  &p->manner, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT,    &p->party_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT,    &p->guild_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT,    &p->pet_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT,    &p->hom_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT,    &p->ele_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT,  &p->hair, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT,  &p->hair_color, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT,  &p->clothes_color, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT,  &p->body, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT,  &p->weapon, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT,  &p->shield, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT,  &p->head_top, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_SHORT,  &p->head_mid, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_SHORT,  &p->head_bottom, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_STRING, &p->last_point.map, sizeof(p->last_point.map), nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_SHORT,  &p->last_point.x, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_SHORT,  &p->last_point.y, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_STRING, &p->save_point.map, sizeof(p->save_point.map), nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_SHORT,  &p->save_point.x, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_SHORT,  &p->save_point.y, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_UINT32,    &p->partner_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_UINT32,    &p->father, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_UINT32,    &p->mother, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_UINT32,    &p->child, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_INT,    &p->fame, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_SHORT,  &p->rename, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_UINT32, &p->delete_date, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 52, SQLDT_SHORT,  &p->robe, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 53, SQLDT_UINT32, &p->character_moves, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 54, SQLDT_LONG,   &p->unban_time, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 55, SQLDT_UCHAR,  &p->font, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 56, SQLDT_UINT,   &p->uniqueitem_counter, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 57, SQLDT_ENUM,   &sex, sizeof(sex), nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 58, SQLDT_UCHAR,  &p->hotkey_rowshift, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 59, SQLDT_INT,    &p->clan_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 60, SQLDT_ULONG,  &p->title_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 61, SQLDT_UINT16, &p->show_equip, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 62, SQLDT_UCHAR,  &p->hotkey_rowshift2, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 63, SQLDT_UINT,   &p->max_ap, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 64, SQLDT_UINT,   &p->ap, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 65, SQLDT_UINT,   &p->trait_point, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 66, SQLDT_SHORT,  &p->pow, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 67, SQLDT_SHORT,  &p->sta, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 68, SQLDT_SHORT,  &p->wis, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 69, SQLDT_SHORT,  &p->spl, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 70, SQLDT_SHORT,  &p->con, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 71, SQLDT_SHORT,  &p->crt, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 72, SQLDT_UINT16, &p->inventory_slots, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 73, SQLDT_UINT8,  &p->body_direction, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 74, SQLDT_UINT8,	&p->disable_call, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 75, SQLDT_INT,    &p->last_point_instanceid, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindParam(0, SQLDT_INT, &char_id, 0)
+	||	SQL_ERROR == stmt.Execute()
+	||	SQL_ERROR == stmt.BindColumn(0,  SQLDT_INT,    &p->char_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(1,  SQLDT_INT,    &p->account_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(2,  SQLDT_UCHAR,  &p->slot, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(3,  SQLDT_STRING, &p->name, sizeof(p->name), nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(4,  SQLDT_SHORT,  &p->class_, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(5,  SQLDT_UINT,   &p->base_level, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(6,  SQLDT_UINT,   &p->job_level, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(7,  SQLDT_UINT64, &p->base_exp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(8,  SQLDT_UINT64, &p->job_exp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(9,  SQLDT_INT,    &p->zeny, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(10, SQLDT_SHORT,  &p->str, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(11, SQLDT_SHORT,  &p->agi, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(12, SQLDT_SHORT,  &p->vit, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(13, SQLDT_SHORT,  &p->int_, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(14, SQLDT_SHORT,  &p->dex, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(15, SQLDT_SHORT,  &p->luk, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(16, SQLDT_UINT,   &p->max_hp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(17, SQLDT_UINT,   &p->hp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(18, SQLDT_UINT,   &p->max_sp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(19, SQLDT_UINT,   &p->sp, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(20, SQLDT_UINT,   &p->status_point, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(21, SQLDT_UINT,   &p->skill_point, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(22, SQLDT_UINT,   &p->option, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(23, SQLDT_UCHAR,  &p->karma, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(24, SQLDT_SHORT,  &p->manner, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(25, SQLDT_INT,    &p->party_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(26, SQLDT_INT,    &p->guild_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(27, SQLDT_INT,    &p->pet_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(28, SQLDT_INT,    &p->hom_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(29, SQLDT_INT,    &p->ele_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(30, SQLDT_SHORT,  &p->hair, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(31, SQLDT_SHORT,  &p->hair_color, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(32, SQLDT_SHORT,  &p->clothes_color, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(33, SQLDT_SHORT,  &p->body, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(34, SQLDT_SHORT,  &p->weapon, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(35, SQLDT_SHORT,  &p->shield, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(36, SQLDT_SHORT,  &p->head_top, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(37, SQLDT_SHORT,  &p->head_mid, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(38, SQLDT_SHORT,  &p->head_bottom, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(39, SQLDT_STRING, &p->last_point.map, sizeof(p->last_point.map), nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(40, SQLDT_SHORT,  &p->last_point.x, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(41, SQLDT_SHORT,  &p->last_point.y, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(42, SQLDT_STRING, &p->save_point.map, sizeof(p->save_point.map), nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(43, SQLDT_SHORT,  &p->save_point.x, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(44, SQLDT_SHORT,  &p->save_point.y, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(45, SQLDT_UINT32,    &p->partner_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(46, SQLDT_UINT32,    &p->father, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(47, SQLDT_UINT32,    &p->mother, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(48, SQLDT_UINT32,    &p->child, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(49, SQLDT_INT,    &p->fame, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(50, SQLDT_SHORT,  &p->rename, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(51, SQLDT_UINT32, &p->delete_date, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(52, SQLDT_SHORT,  &p->robe, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(53, SQLDT_UINT32, &p->character_moves, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(54, SQLDT_LONG,   &p->unban_time, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(55, SQLDT_UCHAR,  &p->font, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(56, SQLDT_UINT,   &p->uniqueitem_counter, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(57, SQLDT_ENUM,   &sex, sizeof(sex), nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(58, SQLDT_UCHAR,  &p->hotkey_rowshift, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(59, SQLDT_INT,    &p->clan_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(60, SQLDT_ULONG,  &p->title_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(61, SQLDT_UINT16, &p->show_equip, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(62, SQLDT_UCHAR,  &p->hotkey_rowshift2, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(63, SQLDT_UINT,   &p->max_ap, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(64, SQLDT_UINT,   &p->ap, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(65, SQLDT_UINT,   &p->trait_point, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(66, SQLDT_SHORT,  &p->pow, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(67, SQLDT_SHORT,  &p->sta, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(68, SQLDT_SHORT,  &p->wis, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(69, SQLDT_SHORT,  &p->spl, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(70, SQLDT_SHORT,  &p->con, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(71, SQLDT_SHORT,  &p->crt, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(72, SQLDT_UINT16, &p->inventory_slots, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(73, SQLDT_UINT8,  &p->body_direction, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(74, SQLDT_UINT8,	&p->disable_call, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(75, SQLDT_INT,    &p->last_point_instanceid, 0, nullptr, nullptr)
 	)
 	{
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		return 0;
 	}
-	if( SQL_ERROR == SqlStmt_NextRow(stmt) )
+	if( SQL_ERROR == stmt.NextRow() )
 	{
 		ShowError("Requested non-existant character id: %d!\n", char_id);
-		SqlStmt_Free(stmt);
 		return 0;
 	}
 	p->sex = char_mmo_gender(nullptr, p, sex[0]);
@@ -1161,22 +1134,21 @@ int32 char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_
 
 	if (!load_everything) // For quick selection of data when displaying the char menu
 	{
-		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&msg_buf);
 		return 1;
 	}
 
 	//read memo data
 	//`memo` (`memo_id`,`char_id`,`map`,`x`,`y`)
-	if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", schema_config.memo_db, MAX_MEMOPOINTS)
-	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
-	||	SQL_ERROR == SqlStmt_Execute(stmt)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &tmp_point.map, sizeof(tmp_point.map), nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT,  &tmp_point.x, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,  &tmp_point.y, 0, nullptr, nullptr) )
+	if( SQL_ERROR == stmt.Prepare("SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", schema_config.memo_db, MAX_MEMOPOINTS)
+	||	SQL_ERROR == stmt.BindParam(0, SQLDT_INT, &char_id, 0)
+	||	SQL_ERROR == stmt.Execute()
+	||	SQL_ERROR == stmt.BindColumn(0, SQLDT_STRING, &tmp_point.map, sizeof(tmp_point.map), nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(1, SQLDT_SHORT,  &tmp_point.x, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(2, SQLDT_SHORT,  &tmp_point.y, 0, nullptr, nullptr) )
 		SqlStmt_ShowDebug(stmt);
 
-	for( i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
+	for( i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == stmt.NextRow(); ++i )
 	{
 		memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point));
 	}
@@ -1184,18 +1156,18 @@ int32 char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_
 
 	//read skill
 	//`skill` (`char_id`, `id`, `lv`)
-	if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv`,`flag` FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.skill_db, MAX_SKILL)
-		||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
-		||	SQL_ERROR == SqlStmt_Execute(stmt)
-		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_UINT16, &tmp_skill.id  , 0, nullptr, nullptr)
-		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UINT8 , &tmp_skill.lv  , 0, nullptr, nullptr)
-		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT8 , &tmp_skill.flag, 0, nullptr, nullptr) )
+	if( SQL_ERROR == stmt.Prepare("SELECT `id`, `lv`,`flag` FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.skill_db, MAX_SKILL)
+		||	SQL_ERROR == stmt.BindParam(0, SQLDT_INT, &char_id, 0)
+		||	SQL_ERROR == stmt.Execute()
+		||	SQL_ERROR == stmt.BindColumn(0, SQLDT_UINT16, &tmp_skill.id  , 0, nullptr, nullptr)
+		||	SQL_ERROR == stmt.BindColumn(1, SQLDT_UINT8 , &tmp_skill.lv  , 0, nullptr, nullptr)
+		||	SQL_ERROR == stmt.BindColumn(2, SQLDT_UINT8 , &tmp_skill.flag, 0, nullptr, nullptr) )
 		SqlStmt_ShowDebug(stmt);
 
 	if( tmp_skill.flag != SKILL_FLAG_PERM_GRANTED )
 		tmp_skill.flag = SKILL_FLAG_PERMANENT;
 
-	for( i = 0; skill_count < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ ) {
+	for( i = 0; skill_count < MAX_SKILL && SQL_SUCCESS == stmt.NextRow(); i++ ) {
 		if( tmp_skill.id > 0 && tmp_skill.id < MAX_SKILL_ID ) {
 			memcpy(&p->skill[i], &tmp_skill, sizeof(tmp_skill));
 			skill_count++;
@@ -1207,31 +1179,31 @@ int32 char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_
 
 	//read friends
 	//`friends` (`char_id`, `friend_id`)
-	if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", schema_config.char_db, schema_config.friend_db, MAX_FRIENDS)
-	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
-	||	SQL_ERROR == SqlStmt_Execute(stmt)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT,    &tmp_friend.account_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT,    &tmp_friend.char_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), nullptr, nullptr) )
+	if( SQL_ERROR == stmt.Prepare("SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", schema_config.char_db, schema_config.friend_db, MAX_FRIENDS)
+	||	SQL_ERROR == stmt.BindParam(0, SQLDT_INT, &char_id, 0)
+	||	SQL_ERROR == stmt.Execute()
+	||	SQL_ERROR == stmt.BindColumn(0, SQLDT_INT,    &tmp_friend.account_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(1, SQLDT_INT,    &tmp_friend.char_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), nullptr, nullptr) )
 		SqlStmt_ShowDebug(stmt);
 
-	for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
+	for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == stmt.NextRow(); ++i )
 		memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend));
 	StringBuf_AppendStr(&msg_buf, " friends");
 
 #ifdef HOTKEY_SAVING
 	//read hotkeys
 	//`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`
-	if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", schema_config.hotkey_db)
-	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
-	||	SQL_ERROR == SqlStmt_Execute(stmt)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT,    &hotkey_num, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR,  &tmp_hotkey.type, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT,   &tmp_hotkey.id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, nullptr, nullptr) )
+	if( SQL_ERROR == stmt.Prepare("SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", schema_config.hotkey_db)
+	||	SQL_ERROR == stmt.BindParam(0, SQLDT_INT, &char_id, 0)
+	||	SQL_ERROR == stmt.Execute()
+	||	SQL_ERROR == stmt.BindColumn(0, SQLDT_INT,    &hotkey_num, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(1, SQLDT_UCHAR,  &tmp_hotkey.type, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(2, SQLDT_UINT,   &tmp_hotkey.id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(3, SQLDT_USHORT, &tmp_hotkey.lv, 0, nullptr, nullptr) )
 		SqlStmt_ShowDebug(stmt);
 
-	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
+	while( SQL_SUCCESS == stmt.NextRow() )
 	{
 		if( hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS_DB )
 			memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey));
@@ -1248,7 +1220,6 @@ int32 char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_
 
 	if (charserv_config.save_log)
 		ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, StringBuf_Value(&msg_buf)); //ok. all data load successfully!
-	SqlStmt_Free(stmt);
 
 	std::shared_ptr<struct mmo_charstatus> cp = util::umap_find( char_get_chardb(), char_id );
 

+ 6 - 9
src/char/char_logif.cpp

@@ -479,26 +479,23 @@ int32 chlogif_parse_ackchangesex(int32 fd)
 			unsigned char i;
 			int32 char_id = 0, class_ = 0, guild_id = 0;
 			std::shared_ptr<struct auth_node> node = util::umap_find( char_get_authdb(), acc );
-			SqlStmt *stmt;
+			SqlStmt stmt{ *sql_handle };
 
 			if (node != nullptr)
 				node->sex = sex;
 
 			// get characters
-			stmt = SqlStmt_Malloc(sql_handle);
-			if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `char_id`, `class`, `guild_id` FROM `%s` WHERE `account_id` = '%d'", schema_config.char_db, acc) || SqlStmt_Execute(stmt)) {
+			if (SQL_ERROR == stmt.Prepare( "SELECT `char_id`, `class`, `guild_id` FROM `%s` WHERE `account_id` = '%d'", schema_config.char_db, acc) || stmt.Execute()) {
 				SqlStmt_ShowDebug(stmt);
-				SqlStmt_Free(stmt);
 			}
 
-			SqlStmt_BindColumn(stmt, 0, SQLDT_INT,   &char_id,  0, nullptr, nullptr);
-			SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &class_,   0, nullptr, nullptr);
-			SqlStmt_BindColumn(stmt, 2, SQLDT_INT,   &guild_id, 0, nullptr, nullptr);
+			stmt.BindColumn(0, SQLDT_INT,   &char_id,  0, nullptr, nullptr);
+			stmt.BindColumn(1, SQLDT_SHORT, &class_,   0, nullptr, nullptr);
+			stmt.BindColumn(2, SQLDT_INT,   &guild_id, 0, nullptr, nullptr);
 
-			for (i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) {
+			for (i = 0; i < MAX_CHARS && SQL_SUCCESS == stmt.NextRow(); ++i) {
 				chlogif_parse_change_sex_sub(sex, acc, char_id, class_, guild_id);
 			}
-			SqlStmt_Free(stmt);
 		}
 
 		// notify all mapservers about this change

+ 17 - 21
src/char/char_mapif.cpp

@@ -1207,7 +1207,7 @@ int32 chmapif_parse_reqcharban(int32 fd){
 			char* data;
 			time_t unban_time;
 			time_t now = time(nullptr);
-			SqlStmt* stmt = SqlStmt_Malloc(sql_handle);
+			SqlStmt stmt{ *sql_handle };
 
 			Sql_GetData(sql_handle, 0, &data, nullptr); t_aid = atoi(data);
 			Sql_GetData(sql_handle, 1, &data, nullptr); t_cid = atoi(data);
@@ -1220,20 +1220,18 @@ int32 chmapif_parse_reqcharban(int32 fd){
 			unban_time += timediff; //alterate the time
 			if( unban_time < now ) unban_time=0; //we have totally reduce the time
 
-			if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
+			if( SQL_SUCCESS != stmt.Prepare(
 					  "UPDATE `%s` SET `unban_time` = ? WHERE `char_id` = ? LIMIT 1",
 					  schema_config.char_db)
-				|| SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_LONG,   (void*)&unban_time,   sizeof(unban_time))
-				|| SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_INT,    (void*)&t_cid,     sizeof(t_cid))
-				|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+				|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_LONG,   (void*)&unban_time,   sizeof(unban_time))
+				|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_INT,    (void*)&t_cid,     sizeof(t_cid))
+				|| SQL_SUCCESS != stmt.Execute()
 
 				)
 			{
 				SqlStmt_ShowDebug(stmt);
-				SqlStmt_Free(stmt);
 				return 1;
 			}
-			SqlStmt_Free(stmt);
 
 			// condition applies; send to all map-servers to disconnect the player
 			if( unban_time > now ) {
@@ -1284,27 +1282,26 @@ int32 chmapif_bonus_script_get(int32 fd) {
 		uint8 num_rows = 0;
 		uint32 cid = RFIFOL(fd,2);
 		struct bonus_script_data tmp_bsdata;
-		SqlStmt* stmt = SqlStmt_Malloc(sql_handle);
+		SqlStmt stmt{ *sql_handle };
 
 		RFIFOSKIP(fd,6);
 
-		if (SQL_ERROR == SqlStmt_Prepare(stmt,
+		if (SQL_ERROR == stmt.Prepare(
 			"SELECT `script`, `tick`, `flag`, `type`, `icon` FROM `%s` WHERE `char_id` = '%d' LIMIT %d",
 			schema_config.bonus_script_db, cid, MAX_PC_BONUS_SCRIPT) ||
-			SQL_ERROR == SqlStmt_Execute(stmt) ||
-			SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &tmp_bsdata.script_str, sizeof(tmp_bsdata.script_str), nullptr, nullptr) ||
-			SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT64, &tmp_bsdata.tick, 0, nullptr, nullptr) ||
-			SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT16, &tmp_bsdata.flag, 0, nullptr, nullptr) ||
-			SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_UINT8,  &tmp_bsdata.type, 0, nullptr, nullptr) ||
-			SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT16,  &tmp_bsdata.icon, 0, nullptr, nullptr)
+			SQL_ERROR == stmt.Execute() ||
+			SQL_ERROR == stmt.BindColumn(0, SQLDT_STRING, &tmp_bsdata.script_str, sizeof(tmp_bsdata.script_str), nullptr, nullptr) ||
+			SQL_ERROR == stmt.BindColumn(1, SQLDT_INT64, &tmp_bsdata.tick, 0, nullptr, nullptr) ||
+			SQL_ERROR == stmt.BindColumn(2, SQLDT_UINT16, &tmp_bsdata.flag, 0, nullptr, nullptr) ||
+			SQL_ERROR == stmt.BindColumn(3, SQLDT_UINT8,  &tmp_bsdata.type, 0, nullptr, nullptr) ||
+			SQL_ERROR == stmt.BindColumn(4, SQLDT_INT16,  &tmp_bsdata.icon, 0, nullptr, nullptr)
 			)
 		{
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			return 1;
 		}
 
-		if ((num_rows = (uint8)SqlStmt_NumRows(stmt)) > 0) {
+		if ((num_rows = (uint8)stmt.NumRows()) > 0) {
 			uint8 i;
 			uint32 size = 9 + num_rows * sizeof(struct bonus_script_data);
 
@@ -1314,7 +1311,7 @@ int32 chmapif_bonus_script_get(int32 fd) {
 			WFIFOL(fd, 4) = cid;
 			WFIFOB(fd, 8) = num_rows;
 
-			for (i = 0; i < num_rows && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++) {
+			for (i = 0; i < num_rows && SQL_SUCCESS == stmt.NextRow(); i++) {
 				struct bonus_script_data bsdata;
 				memset(&bsdata, 0, sizeof(bsdata));
 				memset(bsdata.script_str, '\0', sizeof(bsdata.script_str));
@@ -1331,11 +1328,10 @@ int32 chmapif_bonus_script_get(int32 fd) {
 
 			ShowInfo("Bonus Script loaded for CID=%d. Total: %d.\n", cid, i);
 
-			if (SQL_ERROR == SqlStmt_Prepare(stmt,"DELETE FROM `%s` WHERE `char_id`='%d'",schema_config.bonus_script_db,cid) ||
-				SQL_ERROR == SqlStmt_Execute(stmt))
+			if (SQL_ERROR == stmt.Prepare("DELETE FROM `%s` WHERE `char_id`='%d'",schema_config.bonus_script_db,cid) ||
+				SQL_ERROR == stmt.Execute())
 				SqlStmt_ShowDebug(stmt);
 		}
-		SqlStmt_Free(stmt);
 	}
 	return 1;
 }

+ 9 - 12
src/char/int_achievement.cpp

@@ -29,7 +29,7 @@ struct achievement *mapif_achievements_fromsql(uint32 char_id, int32 *count)
 {
 	struct achievement *achievelog = nullptr;
 	struct achievement tmp_achieve;
-	SqlStmt *stmt;
+	SqlStmt stmt{ *sql_handle };
 	StringBuf buf;
 	int32 i;
 
@@ -44,29 +44,27 @@ struct achievement *mapif_achievements_fromsql(uint32 char_id, int32 *count)
 		StringBuf_Printf(&buf, ", `count%d`", i + 1);
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id` = '%u'", schema_config.achievement_table, char_id);
 
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||  SQL_ERROR == SqlStmt_Execute(stmt) )
+	if( SQL_ERROR == stmt.PrepareStr(StringBuf_Value(&buf))
+	||  SQL_ERROR == stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 		*count = 0;
 		return nullptr;
 	}
 
-	SqlStmt_BindColumn(stmt, 0, SQLDT_INT,  &tmp_achieve.achievement_id, 0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 1, SQLDT_INT,  &tmp_achieve.completed, 0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 2, SQLDT_INT,  &tmp_achieve.rewarded, 0, nullptr, nullptr);
+	stmt.BindColumn(0, SQLDT_INT,  &tmp_achieve.achievement_id, 0, nullptr, nullptr);
+	stmt.BindColumn(1, SQLDT_INT,  &tmp_achieve.completed, 0, nullptr, nullptr);
+	stmt.BindColumn(2, SQLDT_INT,  &tmp_achieve.rewarded, 0, nullptr, nullptr);
 	for (i = 0; i < MAX_ACHIEVEMENT_OBJECTIVES; ++i)
-		SqlStmt_BindColumn(stmt, 3 + i, SQLDT_INT, &tmp_achieve.count[i], 0, nullptr, nullptr);
+		stmt.BindColumn(3 + i, SQLDT_INT, &tmp_achieve.count[i], 0, nullptr, nullptr);
 
-	*count = (int)SqlStmt_NumRows(stmt);
+	*count = (int)stmt.NumRows();
 	if (*count > 0) {
 		i = 0;
 
 		achievelog = (struct achievement *)aCalloc(*count, sizeof(struct achievement));
-		while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) {
+		while (SQL_SUCCESS == stmt.NextRow()) {
 			if (i >= *count) // Sanity check, should never happen
 				break;
 			memcpy(&achievelog[i++], &tmp_achieve, sizeof(tmp_achieve));
@@ -78,7 +76,6 @@ struct achievement *mapif_achievements_fromsql(uint32 char_id, int32 *count)
 		}
 	}
 
-	SqlStmt_Free(stmt);
 	StringBuf_Destroy(&buf);
 
 	ShowInfo("achievement load complete from DB - id: %d (total: %d)\n", char_id, *count);

+ 13 - 17
src/char/int_auction.cpp

@@ -49,7 +49,7 @@ int32 auction_count(uint32 char_id, bool buy)
 void auction_save( std::shared_ptr<struct auction_data> auction ){
 	int32 j;
 	StringBuf buf;
-	SqlStmt* stmt;
+	SqlStmt stmt{ *sql_handle };
 
 	if( !auction )
 		return;
@@ -66,24 +66,22 @@ void auction_save( std::shared_ptr<struct auction_data> auction ){
 	}
 	StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id);
 
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
+	if( SQL_SUCCESS != stmt.PrepareStr(StringBuf_Value(&buf))
+	||  SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))
+	||  SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH))
+	||  SQL_SUCCESS != stmt.BindParam(2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH))
+	||  SQL_SUCCESS != stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
 	}
 
-	SqlStmt_Free(stmt);
 	StringBuf_Destroy(&buf);
 }
 
 uint32 auction_create( std::shared_ptr<struct auction_data> auction ){
 	int32 j;
 	StringBuf buf;
-	SqlStmt* stmt;
+	SqlStmt stmt{ *sql_handle };
 
 	if( !auction )
 		return false;
@@ -110,12 +108,11 @@ uint32 auction_create( std::shared_ptr<struct auction_data> auction ){
 	}
 	StringBuf_AppendStr(&buf, ")");
 
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
+	if( SQL_SUCCESS != stmt.PrepareStr(StringBuf_Value(&buf))
+	||  SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))
+	||  SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH))
+	||  SQL_SUCCESS != stmt.BindParam(2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH))
+	||  SQL_SUCCESS != stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
 		auction->auction_id = 0;
@@ -128,14 +125,13 @@ uint32 auction_create( std::shared_ptr<struct auction_data> auction ){
 		auction->item.identify = 1;
 		auction->item.expire_time = 0;
 
-		auction->auction_id = (uint32)SqlStmt_LastInsertId(stmt);
+		auction->auction_id = (uint32)stmt.LastInsertId();
 		auction->auction_end_timer = add_timer( gettick() + tick , auction_end_timer, auction->auction_id, 0);
 		ShowInfo("New Auction %u | time left %" PRtf " ms | By %s.\n", auction->auction_id, tick, auction->seller_name);
 
 		auction_db[auction->auction_id] = auction;
 	}
 
-	SqlStmt_Free(stmt);
 	StringBuf_Destroy(&buf);
 
 	return auction->auction_id;

+ 5 - 9
src/char/int_homun.cpp

@@ -117,28 +117,24 @@ bool mapif_homunculus_save(struct s_homunculus* hd)
 		}
 		else
 		{
-			SqlStmt* stmt;
+			SqlStmt stmt{ *sql_handle };
 			int32 i;
 
-			stmt = SqlStmt_Malloc(sql_handle);
-			if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", schema_config.skill_homunculus_db, hd->hom_id) )
+			if( SQL_ERROR == stmt.Prepare("REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", schema_config.skill_homunculus_db, hd->hom_id) )
 				SqlStmt_ShowDebug(stmt);
 			for( i = 0; i < MAX_HOMUNSKILL; ++i )
 			{
 				if( hd->hskill[i].id > 0 && hd->hskill[i].lv != 0 )
 				{
-					SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0);
-					SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0);
-					if( SQL_ERROR == SqlStmt_Execute(stmt) )
-					{
+					stmt.BindParam(0, SQLDT_USHORT, &hd->hskill[i].id, 0);
+					stmt.BindParam(1, SQLDT_USHORT, &hd->hskill[i].lv, 0);
+					if( SQL_ERROR == stmt.Execute() ){
 						SqlStmt_ShowDebug(stmt);
-						SqlStmt_Free(stmt);
 						flag = false;
 						break;
 					}
 				}
 			}
-			SqlStmt_Free(stmt);
 		}
 	}
 

+ 8 - 11
src/char/int_mail.cpp

@@ -82,7 +82,7 @@ int32 mail_fromsql(uint32 char_id, struct mail_data* md)
 int32 mail_savemessage(struct mail_message* msg)
 {
 	StringBuf buf;
-	SqlStmt* stmt;
+	SqlStmt stmt{ *sql_handle };
 	int32 i, j;
 	bool found = false;
 
@@ -98,22 +98,19 @@ int32 mail_savemessage(struct mail_message* msg)
 	StringBuf_AppendStr(&buf, ")");
 
 	// prepare and execute query
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH))
-	||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
+	if( SQL_SUCCESS != stmt.PrepareStr(StringBuf_Value(&buf))
+	||  SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH))
+	||  SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH))
+	||  SQL_SUCCESS != stmt.BindParam(2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH))
+	||  SQL_SUCCESS != stmt.BindParam(3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH))
+	||  SQL_SUCCESS != stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
 		StringBuf_Destroy(&buf);
 		Sql_QueryStr( sql_handle, "ROLLBACK" );
 		return msg->id = 0;
 	} else
-		msg->id = (int)SqlStmt_LastInsertId(stmt);
-
-	SqlStmt_Free(stmt);
+		msg->id = (int)stmt.LastInsertId();
 	
 	StringBuf_Clear(&buf);
 	StringBuf_Printf(&buf,"INSERT INTO `%s` (`id`, `index`, `amount`, `nameid`, `refine`, `attribute`, `identify`, `unique_id`, `bound`, `enchantgrade`", schema_config.mail_attachment_db);

+ 12 - 21
src/char/int_quest.cpp

@@ -26,39 +26,31 @@
 struct quest *mapif_quests_fromsql( uint32 char_id, size_t& count ){
 	struct quest *questlog = nullptr;
 	struct quest tmp_quest;
-	SqlStmt *stmt;
-
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( stmt == nullptr ) {
-		SqlStmt_ShowDebug(stmt);
-		count = 0;
-		return nullptr;
-	}
+	SqlStmt stmt{ *sql_handle };
 
 	memset(&tmp_quest, 0, sizeof(struct quest));
 
-	if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? ", schema_config.quest_db)
-	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
-	||	SQL_ERROR == SqlStmt_Execute(stmt)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT,  &tmp_quest.quest_id, 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT,  &tmp_quest.state,    0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time,     0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT,  &tmp_quest.count[0], 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT,  &tmp_quest.count[1], 0, nullptr, nullptr)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT,  &tmp_quest.count[2], 0, nullptr, nullptr)
+	if( SQL_ERROR == stmt.Prepare("SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? ", schema_config.quest_db)
+	||	SQL_ERROR == stmt.BindParam(0, SQLDT_INT, &char_id, 0)
+	||	SQL_ERROR == stmt.Execute()
+	||	SQL_ERROR == stmt.BindColumn(0, SQLDT_INT,  &tmp_quest.quest_id, 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(1, SQLDT_INT,  &tmp_quest.state,    0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(2, SQLDT_UINT, &tmp_quest.time,     0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(3, SQLDT_INT,  &tmp_quest.count[0], 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(4, SQLDT_INT,  &tmp_quest.count[1], 0, nullptr, nullptr)
+	||	SQL_ERROR == stmt.BindColumn(5, SQLDT_INT,  &tmp_quest.count[2], 0, nullptr, nullptr)
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		count = 0;
 		return nullptr;
 	}
 
-	count = static_cast<std::remove_reference<decltype(count)>::type>( SqlStmt_NumRows( stmt ) );
+	count = static_cast<std::remove_reference<decltype(count)>::type>( stmt.NumRows() );
 	if( count > 0 ) {
 		size_t i = 0;
 
 		questlog = (struct quest *)aCalloc( count, sizeof( struct quest ) );
-		while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) {
+		while( SQL_SUCCESS == stmt.NextRow() ) {
 			// Sanity check, should never happen
 			if( i >= count ){
 				break;
@@ -74,7 +66,6 @@ struct quest *mapif_quests_fromsql( uint32 char_id, size_t& count ){
 		}
 	}
 
-	SqlStmt_Free(stmt);
 	return questlog;
 }
 

+ 23 - 29
src/char/int_storage.cpp

@@ -323,7 +323,7 @@ void mapif_itembound_store2gstorage(int32 fd, int32 guild_id, struct item items[
 bool mapif_parse_itembound_retrieve(int32 fd)
 {
 	StringBuf buf;
-	SqlStmt* stmt;
+	SqlStmt stmt{ *sql_handle };
 	unsigned short i = 0, count = 0;
 	struct item item, items[MAX_INVENTORY];
 	int32 j, guild_id = RFIFOW(fd,10);
@@ -342,44 +342,41 @@ bool mapif_parse_itembound_retrieve(int32 fd)
 	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = %d", schema_config.inventory_db,char_id, BOUND_GUILD);
 
-	stmt = SqlStmt_Malloc(sql_handle);
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
-		SQL_ERROR == SqlStmt_Execute(stmt) )
+	if( SQL_ERROR == stmt.PrepareStr(StringBuf_Value(&buf)) ||
+		SQL_ERROR == stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 		mapif_itembound_ack(fd,account_id,guild_id);
 		return true;
 	}
 
-	SqlStmt_BindColumn(stmt, 0, SQLDT_INT,       &item.id,           0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 1, SQLDT_UINT,      &item.nameid,       0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,     &item.amount,       0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 3, SQLDT_UINT,      &item.equip,        0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR,      &item.identify,     0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,      &item.refine,       0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &item.attribute,    0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &item.expire_time,  0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,      &item.bound,        0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 9, SQLDT_ULONGLONG, &item.unique_id,    0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 10, SQLDT_INT8,     &item.enchantgrade, 0, nullptr, nullptr);
+	stmt.BindColumn(0, SQLDT_INT,       &item.id,           0, nullptr, nullptr);
+	stmt.BindColumn(1, SQLDT_UINT,      &item.nameid,       0, nullptr, nullptr);
+	stmt.BindColumn(2, SQLDT_SHORT,     &item.amount,       0, nullptr, nullptr);
+	stmt.BindColumn(3, SQLDT_UINT,      &item.equip,        0, nullptr, nullptr);
+	stmt.BindColumn(4, SQLDT_CHAR,      &item.identify,     0, nullptr, nullptr);
+	stmt.BindColumn(5, SQLDT_CHAR,      &item.refine,       0, nullptr, nullptr);
+	stmt.BindColumn(6, SQLDT_CHAR,      &item.attribute,    0, nullptr, nullptr);
+	stmt.BindColumn(7, SQLDT_UINT,      &item.expire_time,  0, nullptr, nullptr);
+	stmt.BindColumn(8, SQLDT_CHAR,      &item.bound,        0, nullptr, nullptr);
+	stmt.BindColumn(9, SQLDT_ULONGLONG, &item.unique_id,    0, nullptr, nullptr);
+	stmt.BindColumn(10, SQLDT_INT8,     &item.enchantgrade, 0, nullptr, nullptr);
 	for( j = 0; j < MAX_SLOTS; ++j )
-		SqlStmt_BindColumn(stmt,11+j, SQLDT_UINT, &item.card[j], 0, nullptr, nullptr);
+		stmt.BindColumn(11+j, SQLDT_UINT, &item.card[j], 0, nullptr, nullptr);
 	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
-		SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+j*3, SQLDT_SHORT, &item.option[j].id, 0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+j*3, SQLDT_SHORT, &item.option[j].value, 0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 13+MAX_SLOTS+j*3, SQLDT_CHAR, &item.option[j].param, 0, nullptr, nullptr);
+		stmt.BindColumn(11+MAX_SLOTS+j*3, SQLDT_SHORT, &item.option[j].id, 0, nullptr, nullptr);
+		stmt.BindColumn(12+MAX_SLOTS+j*3, SQLDT_SHORT, &item.option[j].value, 0, nullptr, nullptr);
+		stmt.BindColumn(13+MAX_SLOTS+j*3, SQLDT_CHAR, &item.option[j].param, 0, nullptr, nullptr);
 	}
 	memset(&items, 0, sizeof(items));
-	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
+	while( SQL_SUCCESS == stmt.NextRow() )
 		memcpy(&items[count++], &item, sizeof(struct item));
 	Sql_FreeResult(sql_handle);
 
 	ShowInfo("Found '" CL_WHITE "%d" CL_RESET "' guild bound item(s) from CID = " CL_WHITE "%d" CL_RESET ", AID = %d, Guild ID = " CL_WHITE "%d" CL_RESET ".\n", count, char_id, account_id, guild_id);
 	if (!count) { //No items found - No need to continue
 		StringBuf_Destroy(&buf);
-		SqlStmt_Free(stmt);
 		mapif_itembound_ack(fd,account_id,guild_id);
 		return true;
 	}
@@ -389,11 +386,10 @@ bool mapif_parse_itembound_retrieve(int32 fd)
 	// Delete bound items from player's inventory
 	StringBuf_Clear(&buf);
 	StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE `char_id` = %d AND `bound` = %d",schema_config.inventory_db, char_id, BOUND_GUILD);
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
-		SQL_ERROR == SqlStmt_Execute(stmt) )
+	if( SQL_ERROR == stmt.PrepareStr(StringBuf_Value(&buf)) ||
+		SQL_ERROR == stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 		mapif_itembound_ack(fd,account_id,guild_id);
 		return true;
@@ -434,11 +430,10 @@ bool mapif_parse_itembound_retrieve(int32 fd)
 		StringBuf_Init(&buf2);
 		StringBuf_Printf(&buf2, "UPDATE `%s` SET %s WHERE `char_id`='%d'", schema_config.char_db, StringBuf_Value(&buf), char_id);
 
-		if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf2)) ||
-			SQL_ERROR == SqlStmt_Execute(stmt) )
+		if( SQL_ERROR == stmt.PrepareStr(StringBuf_Value(&buf2)) ||
+			SQL_ERROR == stmt.Execute() )
 		{
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			StringBuf_Destroy(&buf);
 			StringBuf_Destroy(&buf2);
 			mapif_itembound_ack(fd,account_id,guild_id);
@@ -448,7 +443,6 @@ bool mapif_parse_itembound_retrieve(int32 fd)
 	}
 
 	StringBuf_Destroy(&buf);
-	SqlStmt_Free(stmt);
 
 	char_unset_session_flag(account_id, 1);
 	return false;

+ 162 - 234
src/common/sql.cpp

@@ -3,19 +3,12 @@
 
 #include "sql.hpp"
 
-#ifdef WIN32
-#include "winapi.hpp"
-#endif
-
 #include <cstdlib>// strtoul
 
-#include <mysql.h>
-
 #include "cbasetypes.hpp"
 #include "cli.hpp"
 #include "malloc.hpp"
 #include "showmsg.hpp"
-#include "strlib.hpp"
 #include "timer.hpp"
 
 // MySQL 8.0 or later removed my_bool typedef.
@@ -41,35 +34,6 @@ struct Sql
 	int32 keepalive;
 };
 
-
-
-// Column length receiver.
-// Takes care of the possible size missmatch between uint32 and unsigned long.
-struct s_column_length
-{
-	uint32* out_length;
-	unsigned long length;
-};
-typedef struct s_column_length s_column_length;
-
-
-
-/// Sql statement
-struct SqlStmt
-{
-	StringBuf buf;
-	MYSQL_STMT* stmt;
-	MYSQL_BIND* params;
-	MYSQL_BIND* columns;
-	s_column_length* column_lengths;
-	size_t max_params;
-	size_t max_columns;
-	bool bind_params;
-	bool bind_columns;
-};
-
-
-
 ///////////////////////////////////////////////////////////////////////////////
 // Sql Handle
 ///////////////////////////////////////////////////////////////////////////////
@@ -652,18 +616,17 @@ static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_ty
 /// Reports debug information about a truncated column.
 ///
 /// @private
-static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i)
-{
+void SqlStmt::ShowDebugTruncatedColumn( size_t i ){
 	MYSQL_RES* meta;
 	MYSQL_FIELD* field;
 	MYSQL_BIND* column;
 
-	meta = mysql_stmt_result_metadata(self->stmt);
+	meta = mysql_stmt_result_metadata(this->stmt);
 	field = mysql_fetch_field_direct(meta, (uint32)i);
 	ShowSQL("DB error - data of field '%s' was truncated.\n", field->name);
 	ShowDebug("column - %lu\n", (unsigned long)i);
-	Sql_P_ShowDebugMysqlFieldInfo("data   - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, "");
-	column = &self->columns[i];
+	Sql_P_ShowDebugMysqlFieldInfo("data   - ", field->type, field->flags&UNSIGNED_FLAG, this->column_lengths[i].length, "");
+	column = &this->columns[i];
 	if( column->buffer_type == MYSQL_TYPE_STRING )
 		Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)");
 	else
@@ -674,44 +637,33 @@ static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i)
 
 
 /// Allocates and initializes a new SqlStmt handle.
-SqlStmt* SqlStmt_Malloc(Sql* sql)
-{
-	SqlStmt* self;
-	MYSQL_STMT* stmt;
+SqlStmt::SqlStmt( Sql& sql ){
+	this->stmt = mysql_stmt_init( &sql.handle );
 
-	if( sql == nullptr )
-		return nullptr;
-
-	stmt = mysql_stmt_init(&sql->handle);
-	if( stmt == nullptr )
-	{
-		ShowSQL("DB error - %s\n", mysql_error(&sql->handle));
-		return nullptr;
+	if( this->stmt == nullptr ){
+		ShowSQL( "DB error - %s\n", mysql_error( &sql.handle ) );
+		throw std::runtime_error( "Out of memory" );
 	}
-	CREATE(self, SqlStmt, 1);
-	StringBuf_Init(&self->buf);
-	self->stmt = stmt;
-	self->params = nullptr;
-	self->columns = nullptr;
-	self->column_lengths = nullptr;
-	self->max_params = 0;
-	self->max_columns = 0;
-	self->bind_params = false;
-	self->bind_columns = false;
 
-	return self;
+	StringBuf_Init( &this->buf );
+	this->params = nullptr;
+	this->columns = nullptr;
+	this->column_lengths = nullptr;
+	this->max_params = 0;
+	this->max_columns = 0;
+	this->bind_params = false;
+	this->bind_columns = false;
 }
 
 
 
 /// Prepares the statement.
-int32 SqlStmt_Prepare(SqlStmt* self, const char* query, ...)
-{
+int32 SqlStmt::Prepare(const char* query, ...){
 	int32 res;
 	va_list args;
 
 	va_start(args, query);
-	res = SqlStmt_PrepareV(self, query, args);
+	res = this->PrepareV(query, args);
 	va_end(args);
 
 	return res;
@@ -720,21 +672,18 @@ int32 SqlStmt_Prepare(SqlStmt* self, const char* query, ...)
 
 
 /// Prepares the statement.
-int32 SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args)
-{
-	if( self == nullptr )
-		return SQL_ERROR;
-
-	SqlStmt_FreeResult(self);
-	StringBuf_Clear(&self->buf);
-	StringBuf_Vprintf(&self->buf, query, args);
-	if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
-	{
-		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
-		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
+int32 SqlStmt::PrepareV(const char* query, va_list args){
+	this->FreeResult();
+	StringBuf_Clear( &this->buf );
+	StringBuf_Vprintf( &this->buf, query, args );
+
+	if( mysql_stmt_prepare( this->stmt, StringBuf_Value( &this->buf ), (unsigned long)StringBuf_Length( &this->buf ) ) ){
+		ShowSQL( "DB error - %s\n", mysql_stmt_error( this->stmt ) );
+		ra_mysql_error_handler( mysql_stmt_errno( this->stmt ) );
 		return SQL_ERROR;
 	}
-	self->bind_params = false;
+
+	this->bind_params = false;
 
 	return SQL_SUCCESS;
 }
@@ -742,21 +691,18 @@ int32 SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args)
 
 
 /// Prepares the statement.
-int32 SqlStmt_PrepareStr(SqlStmt* self, const char* query)
-{
-	if( self == nullptr )
-		return SQL_ERROR;
-
-	SqlStmt_FreeResult(self);
-	StringBuf_Clear(&self->buf);
-	StringBuf_AppendStr(&self->buf, query);
-	if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
-	{
-		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
-		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
+int32 SqlStmt::PrepareStr(const char* query){
+	this->FreeResult();
+	StringBuf_Clear( &this->buf );
+	StringBuf_AppendStr( &this->buf, query );
+
+	if( mysql_stmt_prepare( this->stmt, StringBuf_Value( &this->buf ), (unsigned long)StringBuf_Length( &this->buf ) ) ){
+		ShowSQL( "DB error - %s\n", mysql_stmt_error( this->stmt ) );
+		ra_mysql_error_handler( mysql_stmt_errno( this->stmt ) );
 		return SQL_ERROR;
 	}
-	self->bind_params = false;
+
+	this->bind_params = false;
 
 	return SQL_SUCCESS;
 }
@@ -764,65 +710,60 @@ int32 SqlStmt_PrepareStr(SqlStmt* self, const char* query)
 
 
 /// Returns the number of parameters in the prepared statement.
-size_t SqlStmt_NumParams(SqlStmt* self)
-{
-	if( self )
-		return (size_t)mysql_stmt_param_count(self->stmt);
-	else
-		return 0;
+size_t SqlStmt::NumParams(){
+	return (size_t)mysql_stmt_param_count( this->stmt );
 }
 
 
 
 /// Binds a parameter to a buffer.
-int32 SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len)
-{
-	if( self == nullptr )
-		return SQL_ERROR;
+int32 SqlStmt::BindParam(size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len){
+	if( !this->bind_params ){
+		// initialize the bindings
+		size_t count = this->NumParams();
+
+		if( this->max_params < count ){
+			this->max_params = count;
+			RECREATE( this->params, MYSQL_BIND, count );
+		}
 
-	if( !self->bind_params )
-	{// initialize the bindings
-		size_t i;
-		size_t count;
+		memset( this->params, 0, count * sizeof( MYSQL_BIND ) );
 
-		count = SqlStmt_NumParams(self);
-		if( self->max_params < count )
-		{
-			self->max_params = count;
-			RECREATE(self->params, MYSQL_BIND, count);
+		for( size_t i = 0; i < count; ++i ){
+			this->params[i].buffer_type = MYSQL_TYPE_NULL;
 		}
-		memset(self->params, 0, count*sizeof(MYSQL_BIND));
-		for( i = 0; i < count; ++i )
-			self->params[i].buffer_type = MYSQL_TYPE_NULL;
-		self->bind_params = true;
+
+		this->bind_params = true;
 	}
-	if( idx < self->max_params )
-		return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, nullptr, nullptr);
-	else
+
+	if( idx < this->max_params ){
+		return Sql_P_BindSqlDataType( this->params + idx, buffer_type, buffer, buffer_len, nullptr, nullptr );
+	}else{
+		// TODO: for real...? Check this! [Lemongrass]
 		return SQL_SUCCESS;// out of range - ignore
+	}
 }
 
 
 
 /// Executes the prepared statement.
-int32 SqlStmt_Execute(SqlStmt* self)
-{
-	if( self == nullptr )
-		return SQL_ERROR;
+int32 SqlStmt::Execute(){
+	this->FreeResult();
 
-	SqlStmt_FreeResult(self);
-	if( (self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) ||
-		mysql_stmt_execute(self->stmt) )
+	if( ( this->bind_params && mysql_stmt_bind_param( this->stmt, this->params ) ) ||
+		mysql_stmt_execute( this->stmt ) )
 	{
-		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
-		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
+		ShowSQL("DB error - %s\n", mysql_stmt_error(this->stmt));
+		ra_mysql_error_handler(mysql_stmt_errno(this->stmt));
 		return SQL_ERROR;
 	}
-	self->bind_columns = false;
-	if( mysql_stmt_store_result(self->stmt) )// store all the data
-	{
-		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
-		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
+
+	this->bind_columns = false;
+
+	// store all the data
+	if( mysql_stmt_store_result( this->stmt ) ){
+		ShowSQL( "DB error - %s\n", mysql_stmt_error( this->stmt ) );
+		ra_mysql_error_handler( mysql_stmt_errno( this->stmt ) );
 		return SQL_ERROR;
 	}
 
@@ -832,67 +773,55 @@ int32 SqlStmt_Execute(SqlStmt* self)
 
 
 /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement.
-uint64 SqlStmt_LastInsertId(SqlStmt* self)
-{
-	if( self )
-		return (uint64)mysql_stmt_insert_id(self->stmt);
-	else
-		return 0;
+uint64 SqlStmt::LastInsertId(){
+	return (uint64)mysql_stmt_insert_id( this->stmt );
 }
 
 
 
 /// Returns the number of columns in each row of the result.
-size_t SqlStmt_NumColumns(SqlStmt* self)
-{
-	if( self )
-		return (size_t)mysql_stmt_field_count(self->stmt);
-	else
-		return 0;
+size_t SqlStmt::NumColumns(){
+	return (size_t)mysql_stmt_field_count( this->stmt );
 }
 
 
 
 /// Binds the result of a column to a buffer.
-int32 SqlStmt_BindColumn(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null)
-{
-	if( self == nullptr )
-		return SQL_ERROR;
-
+int32 SqlStmt::BindColumn(size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null){
 	if( buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM )
 	{
 		if( buffer_len < 1 )
 		{
-			ShowDebug("SqlStmt_BindColumn: buffer_len(%" PRIuPTR ") is too small, no room for the nul-terminator\n", buffer_len);
+			ShowDebug("SqlStmt::BindColumn: buffer_len(%" PRIuPTR ") is too small, no room for the nul-terminator\n", buffer_len);
 			return SQL_ERROR;
 		}
 		--buffer_len;// nul-terminator
 	}
-	if( !self->bind_columns )
-	{// initialize the bindings
-		size_t i;
-		size_t cols;
 
-		cols = SqlStmt_NumColumns(self);
-		if( self->max_columns < cols )
-		{
-			self->max_columns = cols;
-			RECREATE(self->columns, MYSQL_BIND, cols);
-			RECREATE(self->column_lengths, s_column_length, cols);
+	if( !this->bind_columns ){
+		// initialize the bindings
+		size_t cols = this->NumColumns();
+
+		if( this->max_columns < cols ){
+			this->max_columns = cols;
+			RECREATE( this->columns, MYSQL_BIND, cols );
+			RECREATE( this->column_lengths, s_column_length, cols );
 		}
-		memset(self->columns, 0, cols*sizeof(MYSQL_BIND));
-		memset(self->column_lengths, 0, cols*sizeof(s_column_length));
-		for( i = 0; i < cols; ++i )
-			self->columns[i].buffer_type = MYSQL_TYPE_NULL;
-		self->bind_columns = true;
-	}
-	if( idx < self->max_columns )
-	{
-		self->column_lengths[idx].out_length = out_length;
-		return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null);
+		memset( this->columns, 0, cols * sizeof( MYSQL_BIND ) );
+		memset( this->column_lengths, 0, cols * sizeof( s_column_length ) );
+
+		for( size_t i = 0; i < cols; ++i ){
+			this->columns[i].buffer_type = MYSQL_TYPE_NULL;
+		}
+
+		this->bind_columns = true;
 	}
-	else
-	{
+
+	if( idx < this->max_columns ){
+		this->column_lengths[idx].out_length = out_length;
+		return Sql_P_BindSqlDataType( this->columns + idx, buffer_type, buffer, buffer_len, &this->column_lengths[idx].length, out_is_null );
+	}else{
+		// TODO: for real...? Check this! [Lemongrass]
 		return SQL_SUCCESS;// out of range - ignore
 	}
 }
@@ -900,31 +829,23 @@ int32 SqlStmt_BindColumn(SqlStmt* self, size_t idx, enum SqlDataType buffer_type
 
 
 /// Returns the number of rows in the result.
-uint64 SqlStmt_NumRows(SqlStmt* self)
-{
-	if( self )
-		return (uint64)mysql_stmt_num_rows(self->stmt);
-	else
-		return 0;
+uint64 SqlStmt::NumRows(){
+	return (uint64)mysql_stmt_num_rows( this->stmt );
 }
 
 
 
 /// Fetches the next row.
-int32 SqlStmt_NextRow(SqlStmt* self)
-{
+int32 SqlStmt::NextRow(){
 	int32 err;
-	size_t i;
-	size_t cols;
-
-	if( self == nullptr )
-		return SQL_ERROR;
 
 	// bind columns
-	if( self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns) )
+	if( this->bind_columns && mysql_stmt_bind_result(this->stmt, this->columns) ){
 		err = 1;// error binding columns
-	else
-		err = mysql_stmt_fetch(self->stmt);// fetch row
+	}else{
+		// fetch row
+		err = mysql_stmt_fetch( this->stmt );
+	}
 
 	// check for errors
 	if( err == MYSQL_NO_DATA )
@@ -935,23 +856,22 @@ int32 SqlStmt_NextRow(SqlStmt* self)
 	{
 		my_bool truncated;
 
-		if( !self->bind_columns )
-		{
+		if( !this->bind_columns ){
 			ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n");
 			return SQL_ERROR;
 		}
 
 		// find truncated column
-		cols = SqlStmt_NumColumns(self);
-		for( i = 0; i < cols; ++i )
-		{
-			MYSQL_BIND* column = &self->columns[i];
+		size_t cols = this->NumColumns();
+
+		for( size_t i = 0; i < cols; ++i ){
+			MYSQL_BIND* column = &this->columns[i];
 			column->error = &truncated;
-			mysql_stmt_fetch_column(self->stmt, column, (uint32)i, 0);
+			mysql_stmt_fetch_column( this->stmt, column, (uint32)i, 0 );
 			column->error = nullptr;
 			if( truncated )
 			{// report truncated column
-				SqlStmt_P_ShowDebugTruncatedColumn(self, i);
+				this->ShowDebugTruncatedColumn( i );
 				return SQL_ERROR;
 			}
 		}
@@ -961,31 +881,35 @@ int32 SqlStmt_NextRow(SqlStmt* self)
 #endif
 	if( err )
 	{
-		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
-		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
+		ShowSQL("DB error - %s\n", mysql_stmt_error(this->stmt));
+		ra_mysql_error_handler(mysql_stmt_errno(this->stmt));
 		return SQL_ERROR;
 	}
 
 	// propagate column lengths and clear unused parts of string/enum/blob buffers
-	cols = SqlStmt_NumColumns(self);
-	for( i = 0; i < cols; ++i )
-	{
-		unsigned long length = self->column_lengths[i].length;
-		MYSQL_BIND* column = &self->columns[i];
+	size_t cols = this->NumColumns();
+
+	for( size_t i = 0; i < cols; ++i ){
+		unsigned long length = this->column_lengths[i].length;
+		MYSQL_BIND* column = &this->columns[i];
+
 #if !defined(MYSQL_DATA_TRUNCATED)
 		// MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS]
 		if( column->buffer_length < length )
 		{// report truncated column
 			if( column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB )
 			{// string/enum/blob column
-				SqlStmt_P_ShowDebugTruncatedColumn(self, i);
+				this->ShowDebugTruncatedColumn( i );
 				return SQL_ERROR;
 			}
 			// FIXME numeric types and null [FlavioJS]
 		}
 #endif
-		if( self->column_lengths[i].out_length )
-			*self->column_lengths[i].out_length = (uint32)length;
+
+		if( this->column_lengths[i].out_length ){
+			*this->column_lengths[i].out_length = (uint32)length;
+		}
+
 		if( column->buffer_type == MYSQL_TYPE_STRING )
 		{// clear unused part of the string/enum buffer (and nul-terminate)
 			memset((char*)column->buffer + length, 0, column->buffer_length - length + 1);
@@ -1002,43 +926,47 @@ int32 SqlStmt_NextRow(SqlStmt* self)
 
 
 /// Frees the result of the statement execution.
-void SqlStmt_FreeResult(SqlStmt* self)
-{
-	if( self )
-		mysql_stmt_free_result(self->stmt);
+void SqlStmt::FreeResult(){
+	mysql_stmt_free_result( this->stmt );
 }
 
 
 
 /// Shows debug information (with statement).
-void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line)
-{
-	if( self == nullptr )
-		ShowDebug("at %s:%lu -  self is nullptr\n", debug_file, debug_line);
-	else if( StringBuf_Length(&self->buf) > 0 )
-		ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf));
-	else
+void SqlStmt::ShowDebug_(const char* debug_file, const unsigned long debug_line){
+#if !defined(SQL_REMOVE_SHOWDEBUG)
+	if( StringBuf_Length( &this->buf ) > 0 ){
+		ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&this->buf));
+	}else{
 		ShowDebug("at %s:%lu\n", debug_file, debug_line);
+	}
+#endif
 }
 
 
 
-/// Frees a SqlStmt returned by SqlStmt_Malloc.
-void SqlStmt_Free(SqlStmt* self)
-{
-	if( self )
-	{
-		SqlStmt_FreeResult(self);
-		StringBuf_Destroy(&self->buf);
-		mysql_stmt_close(self->stmt);
-		if( self->params )
-			aFree(self->params);
-		if( self->columns )
-		{
-			aFree(self->columns);
-			aFree(self->column_lengths);
-		}
-		aFree(self);
+/// Frees a SqlStmt.
+SqlStmt::~SqlStmt(){
+	this->FreeResult();
+	StringBuf_Destroy( &this->buf );
+	if( this->stmt != nullptr ){
+		mysql_stmt_close( this->stmt );
+		this->stmt = nullptr;
+	}
+
+	if( this->params != nullptr ){
+		aFree( this->params );
+		this->params = nullptr;
+	}
+
+	if( this->columns != nullptr ){
+		aFree( this->columns );
+		this->columns = nullptr;
+	}
+
+	if( this->column_lengths != nullptr ){
+		aFree( this->column_lengths );
+		this->column_lengths = nullptr;
 	}
 }
 

+ 109 - 116
src/common/sql.hpp

@@ -5,8 +5,16 @@
 #define SQL_HPP
 
 #include <cstdarg>// va_list
+#include <stdexcept>
+
+#ifdef WIN32
+#include "winapi.hpp"
+#endif
+
+#include <mysql.h>
 
 #include "cbasetypes.hpp"
+#include "strlib.hpp"
 
 // Return codes
 #define SQL_ERROR -1
@@ -56,11 +64,9 @@ enum SqlDataType
 };
 
 struct Sql;// Sql handle (private access)
-struct SqlStmt;// Sql statement (private access)
 
 typedef enum SqlDataType SqlDataType;
 typedef struct Sql Sql;
-typedef struct SqlStmt SqlStmt;
 
 
 /// Allocates and initializes a new Sql handle.
@@ -216,6 +222,14 @@ void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug
 /// Frees a Sql handle returned by Sql_Malloc.
 void Sql_Free(Sql* self);
 
+// Column length receiver.
+// Takes care of the possible size missmatch between uint32 and unsigned long.
+struct s_column_length
+{
+	uint32* out_length;
+	unsigned long length;
+};
+typedef struct s_column_length s_column_length;
 
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -230,125 +244,104 @@ void Sql_Free(Sql* self);
 // example queries with parameters:
 // 1) SELECT col FROM table WHERE id=?
 // 2) INSERT INTO table(col1,col2) VALUES(?,?)
-
-
-
-/// Allocates and initializes a new SqlStmt handle.
-/// It uses the connection of the parent Sql handle.
-/// Queries in Sql and SqlStmt are independent and don't affect each other.
-///
-/// @return SqlStmt handle or nullptr if an error occured
-struct SqlStmt* SqlStmt_Malloc(Sql* sql);
-
-
-
-/// Prepares the statement.
-/// Any previous result is freed and all parameter bindings are removed.
-/// The query is constructed as if it was sprintf.
-///
-/// @return SQL_SUCCESS or SQL_ERROR
-int32 SqlStmt_Prepare(SqlStmt* self, const char* query, ...);
-
-
-
-/// Prepares the statement.
-/// Any previous result is freed and all parameter bindings are removed.
-/// The query is constructed as if it was svprintf.
-///
-/// @return SQL_SUCCESS or SQL_ERROR
-int32 SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args);
-
-
-
-/// Prepares the statement.
-/// Any previous result is freed and all parameter bindings are removed.
-/// The query is used directly.
-///
-/// @return SQL_SUCCESS or SQL_ERROR
-int32 SqlStmt_PrepareStr(SqlStmt* self, const char* query);
-
-
-
-/// Returns the number of parameters in the prepared statement.
-///
-/// @return Number or paramenters
-size_t SqlStmt_NumParams(SqlStmt* self);
-
-
-
-/// Binds a parameter to a buffer.
-/// The buffer data will be used when the statement is executed.
-/// All parameters should have bindings.
-///
-/// @return SQL_SUCCESS or SQL_ERROR
-int32 SqlStmt_BindParam(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len);
-
-
-
-/// Executes the prepared statement.
-/// Any previous result is freed and all column bindings are removed.
-///
-/// @return SQL_SUCCESS or SQL_ERROR
-int32 SqlStmt_Execute(SqlStmt* self);
-
-
-
-/// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement.
-///
-/// @return Value of the auto-increment column
-uint64 SqlStmt_LastInsertId(SqlStmt* self);
-
-
-
-/// Returns the number of columns in each row of the result.
-///
-/// @return Number of columns
-size_t SqlStmt_NumColumns(SqlStmt* self);
-
-
-
-/// Binds the result of a column to a buffer.
-/// The buffer will be filled with data when the next row is fetched.
-/// For string/enum buffer types there has to be enough space for the data 
-/// and the nul-terminator (an extra byte).
-///
-/// @return SQL_SUCCESS or SQL_ERROR
-int32 SqlStmt_BindColumn(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null);
-
-
-
-/// Returns the number of rows in the result.
-///
-/// @return Number of rows
-uint64 SqlStmt_NumRows(SqlStmt* self);
-
-
-
-/// Fetches the next row.
-/// All column bindings will be filled with data.
-///
-/// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA
-int32 SqlStmt_NextRow(SqlStmt* self);
-
-
-
-/// Frees the result of the statement execution.
-void SqlStmt_FreeResult(SqlStmt* self);
-
-
+class SqlStmt{
+private:
+	StringBuf buf;
+	MYSQL_STMT* stmt;
+	MYSQL_BIND* params;
+	MYSQL_BIND* columns;
+	s_column_length* column_lengths;
+	size_t max_params;
+	size_t max_columns;
+	bool bind_params;
+	bool bind_columns;
+
+	void ShowDebugTruncatedColumn( size_t i );
+
+public:
+	explicit SqlStmt( Sql& sql ) noexcept(false);
+	~SqlStmt();
+
+	/// Prepares the statement.
+	/// Any previous result is freed and all parameter bindings are removed.
+	/// The query is constructed as if it was sprintf.
+	///
+	/// @return SQL_SUCCESS or SQL_ERROR
+	int32 Prepare( const char* query, ... );
+
+	/// Prepares the statement.
+	/// Any previous result is freed and all parameter bindings are removed.
+	/// The query is constructed as if it was svprintf.
+	///
+	/// @return SQL_SUCCESS or SQL_ERROR
+	int32 PrepareV( const char* query, va_list args );
+
+	/// Prepares the statement.
+	/// Any previous result is freed and all parameter bindings are removed.
+	/// The query is used directly.
+	///
+	/// @return SQL_SUCCESS or SQL_ERROR
+	int32 PrepareStr( const char* query );
+
+	/// Returns the number of parameters in the prepared statement.
+	///
+	/// @return Number or paramenters
+	size_t NumParams();
+
+	/// Binds a parameter to a buffer.
+	/// The buffer data will be used when the statement is executed.
+	/// All parameters should have bindings.
+	///
+	/// @return SQL_SUCCESS or SQL_ERROR
+	int32 BindParam( size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len );
+
+	/// Executes the prepared statement.
+	/// Any previous result is freed and all column bindings are removed.
+	///
+	/// @return SQL_SUCCESS or SQL_ERROR
+	int32 Execute();
+
+	/// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement.
+	///
+	/// @return Value of the auto-increment column
+	uint64 LastInsertId();
+
+	/// Returns the number of columns in each row of the result.
+	///
+	/// @return Number of columns
+	size_t NumColumns();
+
+	/// Binds the result of a column to a buffer.
+	/// The buffer will be filled with data when the next row is fetched.
+	/// For string/enum buffer types there has to be enough space for the data 
+	/// and the nul-terminator (an extra byte).
+	///
+	/// @return SQL_SUCCESS or SQL_ERROR
+	int32 BindColumn( size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null );
+
+	/// Returns the number of rows in the result.
+	///
+	/// @return Number of rows
+	uint64 NumRows();
+
+	/// Fetches the next row.
+	/// All column bindings will be filled with data.
+	///
+	/// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA
+	int32 NextRow();
+
+	/// Frees the result of the statement execution.
+	void FreeResult();
+
+	void ShowDebug_( const char* file, const unsigned long line );
+};
 
 #if defined(SQL_REMOVE_SHOWDEBUG)
 #define SqlStmt_ShowDebug(self) (void)0
 #else
-#define SqlStmt_ShowDebug(self) SqlStmt_ShowDebug_(self, __FILE__, __LINE__)
+// TODO: we have to keep this until C++20 and std::source_location is available [Lemongrass]
+#define SqlStmt_ShowDebug(self) (self).ShowDebug_( __FILE__, __LINE__ )
 #endif
-/// Shows debug information (with statement).
-void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line);
-
-
-
-/// Frees a SqlStmt returned by SqlStmt_Malloc.
-void SqlStmt_Free(SqlStmt* self);
 
 void Sql_Init(void);
 

+ 2 - 2
src/login/CMakeLists.txt

@@ -12,8 +12,8 @@ file(GLOB LOGIN_SOURCES_CXX ${LOGIN_SOURCE_DIR}/*.cpp)
 set(LOGIN_SOURCES ${LOGIN_SOURCES_C} ${LOGIN_SOURCES_CXX})
 #message( STATUS "LOGIN_SOURCES="${LOGIN_SOURCES})
 set( DEPENDENCIES common )
-set( LIBRARIES ${GLOBAL_LIBRARIES} )
-set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ${RA_INCLUDE_DIRS} )
+set( LIBRARIES ${GLOBAL_LIBRARIES} ${MYSQL_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ${RA_INCLUDE_DIRS} ${MYSQL_INCLUDE_DIRS} )
 set( DEFINITIONS "${GLOBAL_DEFINITIONS} ${COMMON_BASE_DEFINITIONS} -DWITH_SQL" )
 set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${COMMON_HEADERS} ${LOGIN_HEADERS} ${LOGIN_SOURCES} )
 source_group( common FILES ${COMMON_BASE_HEADERS} ${COMMON_HEADERS} )

+ 40 - 41
src/login/account.cpp

@@ -549,7 +549,7 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, uint32
  */
 static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new, bool refresh_token) {
 	Sql* sql_handle = db->accounts;
-	SqlStmt* stmt = SqlStmt_Malloc(sql_handle);
+	SqlStmt stmt{ *sql_handle };
 	bool result = false;
 
 	// try
@@ -564,34 +564,34 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 
 	if( is_new )
 	{// insert into account table
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
+		if( SQL_SUCCESS != stmt.Prepare(
 #ifdef VIP_ENABLE
 			"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`, `vip_time`, `old_group` ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 #else
 			"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 #endif
 			db->account_db)
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_INT,       (void*)&acc->account_id,      sizeof(acc->account_id))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING,    (void*)acc->userid,           strlen(acc->userid))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  2, SQLDT_STRING,    (void*)acc->pass,             strlen(acc->pass))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  3, SQLDT_ENUM,      (void*)&acc->sex,             sizeof(acc->sex))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  4, SQLDT_STRING,    (void*)&acc->email,           strlen(acc->email))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  5, SQLDT_INT,       (void*)&acc->group_id,        sizeof(acc->group_id))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  6, SQLDT_UINT,      (void*)&acc->state,           sizeof(acc->state))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  7, SQLDT_LONG,      (void*)&acc->unban_time,      sizeof(acc->unban_time))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  8, SQLDT_INT,       (void*)&acc->expiration_time, sizeof(acc->expiration_time))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  9, SQLDT_UINT,      (void*)&acc->logincount,      sizeof(acc->logincount))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, acc->lastlogin[0]?SQLDT_STRING:SQLDT_NULL,    (void*)&acc->lastlogin,       strlen(acc->lastlogin))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING,    (void*)&acc->last_ip,         strlen(acc->last_ip))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, acc->birthdate[0]?SQLDT_STRING:SQLDT_NULL,    (void*)&acc->birthdate,       strlen(acc->birthdate))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_UCHAR,     (void*)&acc->char_slots,      sizeof(acc->char_slots))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING,    (void*)&acc->pincode,         strlen(acc->pincode))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG,      (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
+		||  SQL_SUCCESS != stmt.BindParam( 0, SQLDT_INT,       (void*)&acc->account_id,      sizeof(acc->account_id))
+		||  SQL_SUCCESS != stmt.BindParam( 1, SQLDT_STRING,    (void*)acc->userid,           strlen(acc->userid))
+		||  SQL_SUCCESS != stmt.BindParam( 2, SQLDT_STRING,    (void*)acc->pass,             strlen(acc->pass))
+		||  SQL_SUCCESS != stmt.BindParam( 3, SQLDT_ENUM,      (void*)&acc->sex,             sizeof(acc->sex))
+		||  SQL_SUCCESS != stmt.BindParam( 4, SQLDT_STRING,    (void*)&acc->email,           strlen(acc->email))
+		||  SQL_SUCCESS != stmt.BindParam( 5, SQLDT_INT,       (void*)&acc->group_id,        sizeof(acc->group_id))
+		||  SQL_SUCCESS != stmt.BindParam( 6, SQLDT_UINT,      (void*)&acc->state,           sizeof(acc->state))
+		||  SQL_SUCCESS != stmt.BindParam( 7, SQLDT_LONG,      (void*)&acc->unban_time,      sizeof(acc->unban_time))
+		||  SQL_SUCCESS != stmt.BindParam( 8, SQLDT_INT,       (void*)&acc->expiration_time, sizeof(acc->expiration_time))
+		||  SQL_SUCCESS != stmt.BindParam( 9, SQLDT_UINT,      (void*)&acc->logincount,      sizeof(acc->logincount))
+		||  SQL_SUCCESS != stmt.BindParam(10, acc->lastlogin[0]?SQLDT_STRING:SQLDT_NULL,    (void*)&acc->lastlogin,       strlen(acc->lastlogin))
+		||  SQL_SUCCESS != stmt.BindParam(11, SQLDT_STRING,    (void*)&acc->last_ip,         strlen(acc->last_ip))
+		||  SQL_SUCCESS != stmt.BindParam(12, acc->birthdate[0]?SQLDT_STRING:SQLDT_NULL,    (void*)&acc->birthdate,       strlen(acc->birthdate))
+		||  SQL_SUCCESS != stmt.BindParam(13, SQLDT_UCHAR,     (void*)&acc->char_slots,      sizeof(acc->char_slots))
+		||  SQL_SUCCESS != stmt.BindParam(14, SQLDT_STRING,    (void*)&acc->pincode,         strlen(acc->pincode))
+		||  SQL_SUCCESS != stmt.BindParam(15, SQLDT_LONG,      (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
 #ifdef VIP_ENABLE
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_LONG,       (void*)&acc->vip_time,         sizeof(acc->vip_time))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 17, SQLDT_INT,        (void*)&acc->old_group,        sizeof(acc->old_group))
+		||  SQL_SUCCESS != stmt.BindParam(16, SQLDT_LONG,       (void*)&acc->vip_time,         sizeof(acc->vip_time))
+		||  SQL_SUCCESS != stmt.BindParam(17, SQLDT_INT,        (void*)&acc->old_group,        sizeof(acc->old_group))
 #endif
-		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
+		||  SQL_SUCCESS != stmt.Execute()
 		) {
 			SqlStmt_ShowDebug(stmt);
 			break;
@@ -599,33 +599,33 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 	}
 	else
 	{// update account table
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, 
+		if( SQL_SUCCESS != stmt.Prepare( 
 #ifdef VIP_ENABLE
 			"UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=?, `vip_time`=?, `old_group`=? WHERE `account_id` = '%d'",
 #else
 			"UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=? WHERE `account_id` = '%d'",
 #endif
 			db->account_db, acc->account_id)
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_STRING,    (void*)acc->userid,           strlen(acc->userid))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING,    (void*)acc->pass,             strlen(acc->pass))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  2, SQLDT_ENUM,      (void*)&acc->sex,             sizeof(acc->sex))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  3, SQLDT_STRING,    (void*)acc->email,            strlen(acc->email))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  4, SQLDT_INT,       (void*)&acc->group_id,        sizeof(acc->group_id))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  5, SQLDT_UINT,      (void*)&acc->state,           sizeof(acc->state))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  6, SQLDT_LONG,      (void*)&acc->unban_time,      sizeof(acc->unban_time))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  7, SQLDT_LONG,      (void*)&acc->expiration_time, sizeof(acc->expiration_time))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  8, SQLDT_UINT,      (void*)&acc->logincount,      sizeof(acc->logincount))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  9, acc->lastlogin[0]?SQLDT_STRING:SQLDT_NULL,    (void*)&acc->lastlogin,       strlen(acc->lastlogin))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING,    (void*)&acc->last_ip,         strlen(acc->last_ip))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, acc->birthdate[0]?SQLDT_STRING:SQLDT_NULL,    (void*)&acc->birthdate,       strlen(acc->birthdate))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_UCHAR,     (void*)&acc->char_slots,      sizeof(acc->char_slots))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING,    (void*)&acc->pincode,         strlen(acc->pincode))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG,      (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
+		||  SQL_SUCCESS != stmt.BindParam( 0, SQLDT_STRING,    (void*)acc->userid,           strlen(acc->userid))
+		||  SQL_SUCCESS != stmt.BindParam( 1, SQLDT_STRING,    (void*)acc->pass,             strlen(acc->pass))
+		||  SQL_SUCCESS != stmt.BindParam( 2, SQLDT_ENUM,      (void*)&acc->sex,             sizeof(acc->sex))
+		||  SQL_SUCCESS != stmt.BindParam( 3, SQLDT_STRING,    (void*)acc->email,            strlen(acc->email))
+		||  SQL_SUCCESS != stmt.BindParam( 4, SQLDT_INT,       (void*)&acc->group_id,        sizeof(acc->group_id))
+		||  SQL_SUCCESS != stmt.BindParam( 5, SQLDT_UINT,      (void*)&acc->state,           sizeof(acc->state))
+		||  SQL_SUCCESS != stmt.BindParam( 6, SQLDT_LONG,      (void*)&acc->unban_time,      sizeof(acc->unban_time))
+		||  SQL_SUCCESS != stmt.BindParam( 7, SQLDT_LONG,      (void*)&acc->expiration_time, sizeof(acc->expiration_time))
+		||  SQL_SUCCESS != stmt.BindParam( 8, SQLDT_UINT,      (void*)&acc->logincount,      sizeof(acc->logincount))
+		||  SQL_SUCCESS != stmt.BindParam( 9, acc->lastlogin[0]?SQLDT_STRING:SQLDT_NULL,    (void*)&acc->lastlogin,       strlen(acc->lastlogin))
+		||  SQL_SUCCESS != stmt.BindParam(10, SQLDT_STRING,    (void*)&acc->last_ip,         strlen(acc->last_ip))
+		||  SQL_SUCCESS != stmt.BindParam(11, acc->birthdate[0]?SQLDT_STRING:SQLDT_NULL,    (void*)&acc->birthdate,       strlen(acc->birthdate))
+		||  SQL_SUCCESS != stmt.BindParam(12, SQLDT_UCHAR,     (void*)&acc->char_slots,      sizeof(acc->char_slots))
+		||  SQL_SUCCESS != stmt.BindParam(13, SQLDT_STRING,    (void*)&acc->pincode,         strlen(acc->pincode))
+		||  SQL_SUCCESS != stmt.BindParam(14, SQLDT_LONG,      (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
 #ifdef VIP_ENABLE
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG,      (void*)&acc->vip_time,        sizeof(acc->vip_time))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_INT,       (void*)&acc->old_group,       sizeof(acc->old_group))
+		||  SQL_SUCCESS != stmt.BindParam(15, SQLDT_LONG,      (void*)&acc->vip_time,        sizeof(acc->vip_time))
+		||  SQL_SUCCESS != stmt.BindParam(16, SQLDT_INT,       (void*)&acc->old_group,       sizeof(acc->old_group))
 #endif
-		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
+		||  SQL_SUCCESS != stmt.Execute()
 		) {
 			SqlStmt_ShowDebug(stmt);
 			break;
@@ -702,7 +702,6 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 	// finally
 
 	result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") );
-	SqlStmt_Free(stmt);
 
 	return result;
 }

+ 4 - 4
src/login/login-server.vcxproj

@@ -111,7 +111,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -130,7 +130,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -151,7 +151,7 @@
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -174,7 +174,7 @@
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>

+ 2 - 2
src/map/CMakeLists.txt

@@ -12,8 +12,8 @@ message( STATUS "Creating target map-server" )
 file(GLOB MAP_HEADERS ${MAP_SOURCE_DIR}/*.hpp)
 file(GLOB MAP_SOURCES ${MAP_SOURCE_DIR}/*.cpp)
 set( DEPENDENCIES common ryml)
-set( LIBRARIES ${GLOBAL_LIBRARIES})
-set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ${RA_INCLUDE_DIRS} )
+set( LIBRARIES ${GLOBAL_LIBRARIES} ${MYSQL_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ${RA_INCLUDE_DIRS} ${MYSQL_INCLUDE_DIRS} )
 set( DEFINITIONS "${GLOBAL_DEFINITIONS} ${COMMON_BASE_DEFINITIONS}" )
 if( WITH_PCRE )
 	message( STATUS "Enabled PCRE code" )

+ 29 - 42
src/map/log.cpp

@@ -178,17 +178,15 @@ void log_branch(map_session_data* sd)
 		return;
 
 	if( log_config.sql_logs ) {
-		SqlStmt* stmt;
-		stmt = SqlStmt_Malloc(logmysql_handle);
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`branch_date`, `account_id`, `char_id`, `char_name`, `map`) VALUES (NOW(), '%d', '%d', ?, '%s')", log_config.log_branch, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
-		||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
+		SqlStmt stmt{ *logmysql_handle };
+
+		if( SQL_SUCCESS != stmt.Prepare(LOG_QUERY " INTO `%s` (`branch_date`, `account_id`, `char_id`, `char_name`, `map`) VALUES (NOW(), '%d', '%d', ?, '%s')", log_config.log_branch, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
+		||  SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
+		||  SQL_SUCCESS != stmt.Execute() )
 		{
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			return;
 		}
-		SqlStmt_Free(stmt);
 	}
 	else
 	{
@@ -220,7 +218,7 @@ void log_pick(int32 id, int16 m, e_log_pick_type type, int32 amount, struct item
 	if( log_config.sql_logs )
 	{
 		int32 i;
-		SqlStmt* stmt = SqlStmt_Malloc(logmysql_handle);
+		SqlStmt stmt{ *logmysql_handle };
 		StringBuf buf;
 		StringBuf_Init(&buf);
 
@@ -241,10 +239,9 @@ void log_pick(int32 id, int16 m, e_log_pick_type type, int32 amount, struct item
 			StringBuf_Printf(&buf, ",'%d','%d','%d'", itm->option[i].id, itm->option[i].value, itm->option[i].param);
 		StringBuf_Printf(&buf, ")");
 
-		if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) || SQL_SUCCESS != SqlStmt_Execute(stmt))
+		if (SQL_SUCCESS != stmt.PrepareStr(StringBuf_Value(&buf)) || SQL_SUCCESS != stmt.Execute())
 			SqlStmt_ShowDebug(stmt);
 
-		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 	}
 	else
@@ -353,19 +350,16 @@ void log_atcommand(map_session_data* sd, const char* message)
 
 	if( log_config.sql_logs )
 	{
-		SqlStmt* stmt;
+		SqlStmt stmt{ *logmysql_handle };
 
-		stmt = SqlStmt_Malloc(logmysql_handle);
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_gm, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255))
-		||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
+		if( SQL_SUCCESS != stmt.Prepare(LOG_QUERY " INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_gm, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
+		||  SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
+		||  SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (char*)message, safestrnlen(message, 255))
+		||  SQL_SUCCESS != stmt.Execute() )
 		{
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			return;
 		}
-		SqlStmt_Free(stmt);
 	}
 	else
 	{
@@ -391,18 +385,16 @@ void log_npc( struct npc_data* nd, const char* message ){
 
 	if( log_config.sql_logs )
 	{
-		SqlStmt* stmt;
-		stmt = SqlStmt_Malloc(logmysql_handle);
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`npc_date`, `char_name`, `map`, `mes`) VALUES (NOW(), ?, '%s', ?)", log_config.log_npc, map_mapid2mapname(nd->bl.m) )
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, nd->name, strnlen(nd->name, NAME_LENGTH))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255))
-		||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
+		SqlStmt stmt{ *logmysql_handle };
+
+		if( SQL_SUCCESS != stmt.Prepare(LOG_QUERY " INTO `%s` (`npc_date`, `char_name`, `map`, `mes`) VALUES (NOW(), ?, '%s', ?)", log_config.log_npc, map_mapid2mapname(nd->bl.m) )
+		||  SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, nd->name, strnlen(nd->name, NAME_LENGTH))
+		||  SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (char*)message, safestrnlen(message, 255))
+		||  SQL_SUCCESS != stmt.Execute() )
 		{
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			return;
 		}
-		SqlStmt_Free(stmt);
 	}
 	else
 	{
@@ -429,18 +421,16 @@ void log_npc(map_session_data* sd, const char* message)
 
 	if( log_config.sql_logs )
 	{
-		SqlStmt* stmt;
-		stmt = SqlStmt_Malloc(logmysql_handle);
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_npc, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255))
-		||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
+		SqlStmt stmt{ *logmysql_handle };
+
+		if( SQL_SUCCESS != stmt.Prepare(LOG_QUERY " INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_npc, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
+		||  SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
+		||  SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (char*)message, safestrnlen(message, 255))
+		||  SQL_SUCCESS != stmt.Execute() )
 		{
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			return;
 		}
-		SqlStmt_Free(stmt);
 	}
 	else
 	{
@@ -476,19 +466,16 @@ void log_chat(e_log_chat_type type, int32 type_id, int32 src_charid, int32 src_a
 	}
 
 	if( log_config.sql_logs ) {
-		SqlStmt* stmt;
+		SqlStmt stmt{ *logmysql_handle };
 
-		stmt = SqlStmt_Malloc(logmysql_handle);
-		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%c', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", log_config.log_chat, log_chattype2char(type), type_id, src_charid, src_accid, mapname, x, y)
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (char*)dst_charname, safestrnlen(dst_charname, NAME_LENGTH))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE_MAX))
-		||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
+		if( SQL_SUCCESS != stmt.Prepare(LOG_QUERY " INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%c', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", log_config.log_chat, log_chattype2char(type), type_id, src_charid, src_accid, mapname, x, y)
+		||  SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, (char*)dst_charname, safestrnlen(dst_charname, NAME_LENGTH))
+		||  SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE_MAX))
+		||  SQL_SUCCESS != stmt.Execute() )
 		{
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			return;
 		}
-		SqlStmt_Free(stmt);
 	}
 	else
 	{

+ 4 - 4
src/map/map-server-generator.vcxproj

@@ -111,7 +111,7 @@
       <DisableSpecificWarnings>4018;4200</DisableSpecificWarnings>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
     </ClCompile>
@@ -132,7 +132,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -154,7 +154,7 @@
       <DisableSpecificWarnings>4018</DisableSpecificWarnings>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -179,7 +179,7 @@
       <DisableSpecificWarnings>4018</DisableSpecificWarnings>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>

+ 4 - 4
src/map/map-server.vcxproj

@@ -111,7 +111,7 @@
       <DisableSpecificWarnings>4018;4200</DisableSpecificWarnings>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
     </ClCompile>
@@ -132,7 +132,7 @@
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -154,7 +154,7 @@
       <DisableSpecificWarnings>4018</DisableSpecificWarnings>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -179,7 +179,7 @@
       <DisableSpecificWarnings>4018</DisableSpecificWarnings>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\pcre\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>

+ 4 - 2
src/map/map.hpp

@@ -1275,13 +1275,15 @@ typedef struct s_elemental_data	TBL_ELEM;
 #define BL_CAST(type_, bl) \
 	( ((bl) == (struct block_list*)nullptr || (bl)->type != (type_)) ? (T ## type_ *)nullptr : (T ## type_ *)(bl) )
 
-#include <common/sql.hpp>
-
 extern int32 db_use_sqldbs;
 
+#ifndef ONLY_CONSTANTS
+#include <common/sql.hpp>
+
 extern Sql* mmysql_handle;
 extern Sql* qsmysql_handle;
 extern Sql* logmysql_handle;
+#endif
 
 extern char barter_table[32];
 extern char buyingstores_table[32];

+ 7 - 10
src/map/mapreg.cpp

@@ -186,27 +186,26 @@ static void script_load_mapreg(void)
 	   | varname | index | value |
 	   +-------------------------+
 	                                */
-	SqlStmt* stmt = SqlStmt_Malloc(mmysql_handle);
+	SqlStmt stmt{ *mmysql_handle };
 	char varname[32+1];
 	uint32 index;
 	char value[255+1];
 	uint32 length;
 
-	if ( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `varname`, `index`, `value` FROM `%s`", mapreg_table)
-	  || SQL_ERROR == SqlStmt_Execute(stmt)
+	if ( SQL_ERROR == stmt.Prepare("SELECT `varname`, `index`, `value` FROM `%s`", mapreg_table)
+	  || SQL_ERROR == stmt.Execute()
 	  ) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		return;
 	}
 
 	skip_insert = true;
 
-	SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &varname[0], sizeof(varname), &length, nullptr);
-	SqlStmt_BindColumn(stmt, 1, SQLDT_UINT32, &index, 0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &value[0], sizeof(value), nullptr, nullptr);
+	stmt.BindColumn(0, SQLDT_STRING, &varname[0], sizeof(varname), &length, nullptr);
+	stmt.BindColumn(1, SQLDT_UINT32, &index, 0, nullptr, nullptr);
+	stmt.BindColumn(2, SQLDT_STRING, &value[0], sizeof(value), nullptr, nullptr);
 
-	while ( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) {
+	while ( SQL_SUCCESS == stmt.NextRow() ) {
 		int32 s = add_str(varname);
 		int64 uid = reference_uid(s, index);
 
@@ -221,8 +220,6 @@ static void script_load_mapreg(void)
 		}
 	}
 
-	SqlStmt_Free(stmt);
-
 	skip_insert = false;
 	mapreg_dirty = false;
 }

+ 8 - 10
src/map/npc.cpp

@@ -4764,12 +4764,11 @@ int32 npc_instancedestroy(struct npc_data* nd)
  * @param qty Stock
  **/
 void npc_market_tosql(const char *exname, struct npc_item_list *list) {
-	SqlStmt* stmt = SqlStmt_Malloc(mmysql_handle);
-	if (SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`name`,`nameid`,`price`,`amount`,`flag`) VALUES ('%s','%u','%d','%d','%" PRIu8 "')",
+	SqlStmt stmt{ *mmysql_handle };
+	if (SQL_ERROR == stmt.Prepare("REPLACE INTO `%s` (`name`,`nameid`,`price`,`amount`,`flag`) VALUES ('%s','%u','%d','%d','%" PRIu8 "')",
 		market_table, exname, list->nameid, list->value, list->qty, list->flag) ||
-		SQL_ERROR == SqlStmt_Execute(stmt))
+		SQL_ERROR == stmt.Execute())
 		SqlStmt_ShowDebug(stmt);
-	SqlStmt_Free(stmt);
 }
 
 /**
@@ -4779,17 +4778,16 @@ void npc_market_tosql(const char *exname, struct npc_item_list *list) {
  * @param clear True: will removes all records related with the NPC
  **/
 void npc_market_delfromsql_(const char *exname, t_itemid nameid, bool clear) {
-	SqlStmt* stmt = SqlStmt_Malloc(mmysql_handle);
+	SqlStmt stmt{ *mmysql_handle };
 	if (clear) {
-		if( SQL_ERROR == SqlStmt_Prepare(stmt, "DELETE FROM `%s` WHERE `name`='%s'", market_table, exname) ||
-			SQL_ERROR == SqlStmt_Execute(stmt))
+		if( SQL_ERROR == stmt.Prepare("DELETE FROM `%s` WHERE `name`='%s'", market_table, exname) ||
+			SQL_ERROR == stmt.Execute())
 			SqlStmt_ShowDebug(stmt);
 	} else {
-		if (SQL_ERROR == SqlStmt_Prepare(stmt, "DELETE FROM `%s` WHERE `name`='%s' AND `nameid`='%u' LIMIT 1", market_table, exname, nameid) ||
-			SQL_ERROR == SqlStmt_Execute(stmt))
+		if (SQL_ERROR == stmt.Prepare("DELETE FROM `%s` WHERE `name`='%s' AND `nameid`='%u' LIMIT 1", market_table, exname, nameid) ||
+			SQL_ERROR == stmt.Execute())
 			SqlStmt_ShowDebug(stmt);
 	}
-	SqlStmt_Free(stmt);
 }
 
 /**

+ 22 - 25
src/map/storage.cpp

@@ -610,7 +610,7 @@ char storage_guild_storageopen(map_session_data* sd)
 
 void storage_guild_log( map_session_data* sd, struct item* item, int16 amount ){
 	int32 i;
-	SqlStmt* stmt = SqlStmt_Malloc(mmysql_handle);
+	SqlStmt stmt{ *mmysql_handle };
 	StringBuf buf;
 	StringBuf_Init(&buf);
 
@@ -631,10 +631,9 @@ void storage_guild_log( map_session_data* sd, struct item* item, int16 amount ){
 		StringBuf_Printf(&buf, ",'%d','%d','%d'", item->option[i].id, item->option[i].value, item->option[i].param);
 	StringBuf_Printf(&buf, ")");
 
-	if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) || SQL_SUCCESS != SqlStmt_Execute(stmt))
+	if (SQL_SUCCESS != stmt.PrepareStr(StringBuf_Value(&buf)) || SQL_SUCCESS != stmt.Execute())
 		SqlStmt_ShowDebug(stmt);
 
-	SqlStmt_Free(stmt);
 	StringBuf_Destroy(&buf);
 }
 
@@ -656,12 +655,11 @@ enum e_guild_storage_log storage_guild_log_read_sub( map_session_data* sd, std::
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%u'", guild_storage_log_table, sd->status.guild_id );
 	StringBuf_Printf(&buf, " ORDER BY `time` DESC LIMIT %u", max);
 
-	SqlStmt* stmt = SqlStmt_Malloc(mmysql_handle);
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
-		SQL_ERROR == SqlStmt_Execute(stmt) )
+	SqlStmt stmt{ *mmysql_handle };
+	if( SQL_ERROR == stmt.PrepareStr(StringBuf_Value(&buf)) ||
+		SQL_ERROR == stmt.Execute() )
 	{
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 
 		return GUILDSTORAGE_LOG_FAILED;
@@ -670,37 +668,36 @@ enum e_guild_storage_log storage_guild_log_read_sub( map_session_data* sd, std::
 	struct guild_log_entry entry;
 
 	// General data
-	SqlStmt_BindColumn(stmt, 0, SQLDT_UINT,      &entry.id,               0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 1, SQLDT_STRING,    &entry.time, sizeof(entry.time), nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 2, SQLDT_STRING,    &entry.name, sizeof(entry.name), nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT,     &entry.amount,           0, nullptr, nullptr);
+	stmt.BindColumn(0, SQLDT_UINT,      &entry.id,               0, nullptr, nullptr);
+	stmt.BindColumn(1, SQLDT_STRING,    &entry.time, sizeof(entry.time), nullptr, nullptr);
+	stmt.BindColumn(2, SQLDT_STRING,    &entry.name, sizeof(entry.name), nullptr, nullptr);
+	stmt.BindColumn(3, SQLDT_SHORT,     &entry.amount,           0, nullptr, nullptr);
 
 	// Item data
-	SqlStmt_BindColumn(stmt, 4, SQLDT_UINT,      &entry.item.nameid,      0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,      &entry.item.identify,    0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &entry.item.refine,      0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 7, SQLDT_CHAR,      &entry.item.attribute,   0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 8, SQLDT_UINT,      &entry.item.expire_time, 0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 9, SQLDT_UINT,      &entry.item.bound,       0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 10, SQLDT_UINT64,   &entry.item.unique_id,   0, nullptr, nullptr);
-	SqlStmt_BindColumn(stmt, 11, SQLDT_INT8,     &entry.item.enchantgrade,0, nullptr, nullptr);
+	stmt.BindColumn(4, SQLDT_UINT,      &entry.item.nameid,      0, nullptr, nullptr);
+	stmt.BindColumn(5, SQLDT_CHAR,      &entry.item.identify,    0, nullptr, nullptr);
+	stmt.BindColumn(6, SQLDT_CHAR,      &entry.item.refine,      0, nullptr, nullptr);
+	stmt.BindColumn(7, SQLDT_CHAR,      &entry.item.attribute,   0, nullptr, nullptr);
+	stmt.BindColumn(8, SQLDT_UINT,      &entry.item.expire_time, 0, nullptr, nullptr);
+	stmt.BindColumn(9, SQLDT_UINT,      &entry.item.bound,       0, nullptr, nullptr);
+	stmt.BindColumn(10, SQLDT_UINT64,   &entry.item.unique_id,   0, nullptr, nullptr);
+	stmt.BindColumn(11, SQLDT_INT8,     &entry.item.enchantgrade,0, nullptr, nullptr);
 	for( j = 0; j < MAX_SLOTS; ++j )
-		SqlStmt_BindColumn(stmt, 12+j, SQLDT_UINT, &entry.item.card[j], 0, nullptr, nullptr);
+		stmt.BindColumn(12+j, SQLDT_UINT, &entry.item.card[j], 0, nullptr, nullptr);
 	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
-		SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+j*3, SQLDT_SHORT, &entry.item.option[j].id, 0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+j*3+1, SQLDT_SHORT, &entry.item.option[j].value, 0, nullptr, nullptr);
-		SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+j*3+2, SQLDT_CHAR, &entry.item.option[j].param, 0, nullptr, nullptr);
+		stmt.BindColumn(12+MAX_SLOTS+j*3, SQLDT_SHORT, &entry.item.option[j].id, 0, nullptr, nullptr);
+		stmt.BindColumn(12+MAX_SLOTS+j*3+1, SQLDT_SHORT, &entry.item.option[j].value, 0, nullptr, nullptr);
+		stmt.BindColumn(12+MAX_SLOTS+j*3+2, SQLDT_CHAR, &entry.item.option[j].param, 0, nullptr, nullptr);
 	}
 
 	log.reserve(max);
 
-	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ){
+	while( SQL_SUCCESS == stmt.NextRow() ){
 		log.push_back( entry );
 	}
 
 	Sql_FreeResult(mmysql_handle);
 	StringBuf_Destroy(&buf);
-	SqlStmt_Free(stmt);
 
 	if( log.empty() ){
 		return GUILDSTORAGE_LOG_EMPTY;

+ 2 - 2
src/web/CMakeLists.txt

@@ -16,8 +16,8 @@ message( STATUS "Creating target web-server" )
 file(GLOB WEB_HEADERS ${WEB_SOURCE_DIR}/*.hpp)
 file(GLOB WEB_SOURCES ${WEB_SOURCE_DIR}/*.cpp)
 set( DEPENDENCIES common yaml-cpp httplib)
-set( LIBRARIES ${GLOBAL_LIBRARIES})
-set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ${HTTPLIB_INCLUDE_DIRS} ${JSON_INCLUDE_DIRS} ${RA_INCLUDE_DIRS} )
+set( LIBRARIES ${GLOBAL_LIBRARIES} ${MYSQL_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ${HTTPLIB_INCLUDE_DIRS} ${JSON_INCLUDE_DIRS} ${RA_INCLUDE_DIRS} ${MYSQL_INCLUDE_DIRS} )
 set( DEFINITIONS "${GLOBAL_DEFINITIONS} ${COMMON_BASE_DEFINITIONS}" )
 set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${COMMON_HEADERS} ${WEB_HEADERS} ${WEB_SOURCES} )
 source_group( common FILES ${COMMON_BASE_HEADERS} ${COMMON_HEADERS} )

+ 13 - 19
src/web/auth.cpp

@@ -30,29 +30,26 @@ bool isAuthorized(const Request &request, bool checkGuildLeader) {
 
 	auto handle = loginlock.getHandle();
 
-	SqlStmt * stmt = SqlStmt_Malloc(handle);
+	SqlStmt stmt{ *handle };
 
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `account_id` FROM `%s` WHERE (`account_id` = ? AND `web_auth_token` = ? AND `web_auth_token_enabled` = '1')",
 			login_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)token, strlen(token))
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (void *)token, strlen(token))
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		loginlock.unlock();
 		return false;
 	}
 
-	if (SqlStmt_NumRows(stmt) <= 0) {
+	if (stmt.NumRows() <= 0) {
 		ShowWarning("Request with AID %d and token %s unverified\n", account_id, token);
-		SqlStmt_Free(stmt);
 		loginlock.unlock();
 		return false;
 	}
 
-	SqlStmt_Free(stmt);
 	loginlock.unlock();
 	if (!checkGuildLeader) {
 		// we're done, auth ok
@@ -64,28 +61,25 @@ bool isAuthorized(const Request &request, bool checkGuildLeader) {
 	SQLLock charlock(CHAR_SQL_LOCK);
 	charlock.lock();
 	handle = charlock.getHandle();
-	stmt = SqlStmt_Malloc(handle);
+	SqlStmt stmt2{ *handle };
 
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	if (SQL_SUCCESS != stmt2.Prepare(
 		"SELECT `account_id` FROM `%s` LEFT JOIN `%s` using (`char_id`) WHERE (`%s`.`account_id` = ? AND `%s`.`guild_id` = ?) LIMIT 1",
 		guild_db_table, char_db_table, char_db_table, guild_db_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, &guild_id, sizeof(guild_id))
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt2.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt2.BindParam(1, SQLDT_INT, &guild_id, sizeof(guild_id))
+		|| SQL_SUCCESS != stmt2.Execute()
 	) {
-		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
+		SqlStmt_ShowDebug(stmt2);
 		charlock.unlock();
 		return false;
 	}
 
-	if (SqlStmt_NumRows(stmt) <= 0) {
+	if (stmt2.NumRows() <= 0) {
 		ShowDebug("Request with AID %d GDID %d and token %s unverified\n", account_id, guild_id, token);
-		SqlStmt_Free(stmt);
 		charlock.unlock();
 		return false;
 	}
-	SqlStmt_Free(stmt);
 	charlock.unlock();
 	return true;
 }

+ 30 - 39
src/web/charconfig_controller.cpp

@@ -34,30 +34,28 @@ HANDLER_FUNC(charconfig_save) {
 	SQLLock sl(WEB_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt * stmt = SqlStmt_Malloc(handle);
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	SqlStmt stmt{ *handle };
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `data` FROM `%s` WHERE (`account_id` = ? AND `char_id` = ? AND `world_name` = ?) LIMIT 1",
 			char_configs_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, &char_id, sizeof(char_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)world_name.c_str(), world_name.length())
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam( 0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam( 1, SQLDT_INT, &char_id, sizeof(char_id))
+		|| SQL_SUCCESS != stmt.BindParam( 2, SQLDT_STRING, (void *)world_name.c_str(), world_name.length())
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	if (SqlStmt_NumRows(stmt) > 0) {
+	if (stmt.NumRows() > 0) {
 		char databuf[SQL_BUFFER_SIZE];
-		if (SQL_SUCCESS != SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
-			|| SQL_SUCCESS != SqlStmt_NextRow(stmt)
+		if (SQL_SUCCESS != stmt.BindColumn( 0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
+			|| SQL_SUCCESS != stmt.NextRow()
 		) {
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			sl.unlock();
 			res.status = HTTP_BAD_REQUEST;
 			res.set_content("Error", "text/plain");
@@ -71,24 +69,22 @@ HANDLER_FUNC(charconfig_save) {
 
 	auto data_str = data.dump();
 
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	if (SQL_SUCCESS != stmt.Prepare(
 			"REPLACE INTO `%s` (`account_id`, `char_id`, `world_name`, `data`) VALUES (?, ?, ?, ?)",
 			char_configs_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, &char_id, sizeof(char_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)world_name.c_str(), world_name.length())
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void *)data_str.c_str(), data_str.length())
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam( 0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam( 1, SQLDT_INT, &char_id, sizeof(char_id))
+		|| SQL_SUCCESS != stmt.BindParam( 2, SQLDT_STRING, (void *)world_name.c_str(), world_name.length())
+		|| SQL_SUCCESS != stmt.BindParam( 3, SQLDT_STRING, (void *)data_str.c_str(), data_str.length())
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	SqlStmt_Free(stmt);
 	sl.unlock();
 	res.set_content(data_str, "application/json");
 }
@@ -115,41 +111,38 @@ HANDLER_FUNC(charconfig_load) {
 	SQLLock sl(WEB_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt * stmt = SqlStmt_Malloc(handle);
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	SqlStmt stmt{ *handle };
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `data` FROM `%s` WHERE (`account_id` = ? AND `char_id` = ? AND `world_name` = ?) LIMIT 1",
 			char_configs_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, &char_id, sizeof(char_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)world_name, strlen(world_name))
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_INT, &char_id, sizeof(char_id))
+		|| SQL_SUCCESS != stmt.BindParam(2, SQLDT_STRING, (void *)world_name, strlen(world_name))
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	if (SqlStmt_NumRows(stmt) <= 0) {
+	if (stmt.NumRows() <= 0) {
 		std::string data = "{\"Type\": 1}";
 
-		if( SQL_SUCCESS != SqlStmt_Prepare( stmt, "INSERT INTO `%s` (`account_id`, `char_id`, `world_name`, `data`) VALUES (?, ?, ?, ?)", char_configs_table ) ||
-			SQL_SUCCESS != SqlStmt_BindParam( stmt, 0, SQLDT_INT, &account_id, sizeof( account_id ) ) ||
-			SQL_SUCCESS != SqlStmt_BindParam( stmt, 1, SQLDT_INT, &char_id, sizeof( char_id ) ) ||
-			SQL_SUCCESS != SqlStmt_BindParam( stmt, 2, SQLDT_STRING, (void*)world_name, strlen( world_name ) ) ||
-			SQL_SUCCESS != SqlStmt_BindParam( stmt, 3, SQLDT_STRING, (void*)data.c_str(), strlen( data.c_str() ) ) ||
-			SQL_SUCCESS != SqlStmt_Execute( stmt ) ){
+		if( SQL_SUCCESS != stmt.Prepare( "INSERT INTO `%s` (`account_id`, `char_id`, `world_name`, `data`) VALUES (?, ?, ?, ?)", char_configs_table ) ||
+			SQL_SUCCESS != stmt.BindParam( 0, SQLDT_INT, &account_id, sizeof( account_id ) ) ||
+			SQL_SUCCESS != stmt.BindParam( 1, SQLDT_INT, &char_id, sizeof( char_id ) ) ||
+			SQL_SUCCESS != stmt.BindParam( 2, SQLDT_STRING, (void*)world_name, strlen( world_name ) ) ||
+			SQL_SUCCESS != stmt.BindParam( 3, SQLDT_STRING, (void*)data.c_str(), strlen( data.c_str() ) ) ||
+			SQL_SUCCESS != stmt.Execute() ){
 			SqlStmt_ShowDebug( stmt );
-			SqlStmt_Free( stmt );
 			sl.unlock();
 			res.status = HTTP_BAD_REQUEST;
 			res.set_content( "Error", "text/plain" );
 			return;
 		}
 
-		SqlStmt_Free( stmt );
 		sl.unlock();
 		res.set_content( data, "application/json" );
 		return;
@@ -157,18 +150,16 @@ HANDLER_FUNC(charconfig_load) {
 
 	char databuf[SQL_BUFFER_SIZE];
 
-	if (SQL_SUCCESS != SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
-		|| SQL_SUCCESS != SqlStmt_NextRow(stmt)
+	if (SQL_SUCCESS != stmt.BindColumn(0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
+		|| SQL_SUCCESS != stmt.NextRow()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	SqlStmt_Free(stmt);
 	sl.unlock();
 
 	databuf[sizeof(databuf) - 1] = 0;

+ 25 - 33
src/web/emblem_controller.cpp

@@ -48,16 +48,15 @@ HANDLER_FUNC(emblem_download) {
 	SQLLock sl(WEB_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt * stmt = SqlStmt_Malloc(handle);
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	SqlStmt stmt{ *handle };
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `version`, `file_type`, `file_data` FROM `%s` WHERE (`guild_id` = ? AND `world_name` = ?)",
 			guild_emblems_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &guild_id, sizeof(guild_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)world_name, strlen(world_name))
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam( 0, SQLDT_INT, &guild_id, sizeof(guild_id))
+		|| SQL_SUCCESS != stmt.BindParam( 1, SQLDT_STRING, (void *)world_name, strlen(world_name))
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
@@ -69,8 +68,7 @@ HANDLER_FUNC(emblem_download) {
 	char blob[MAX_EMBLEM_SIZE]; // yikes
 	uint32 emblem_size;
 
-	if (SqlStmt_NumRows(stmt) <= 0) {
-		SqlStmt_Free(stmt);
+	if (stmt.NumRows() <= 0) {
 		ShowError("[GuildID: %d / World: \"%s\"] Not found in table\n", guild_id, world_name);
 		sl.unlock();
 		res.status = HTTP_NOT_FOUND;
@@ -79,20 +77,18 @@ HANDLER_FUNC(emblem_download) {
 	}
 
 
-	if (SQL_SUCCESS != SqlStmt_BindColumn(stmt, 0, SQLDT_UINT32, &version, sizeof(version), nullptr, nullptr)
-		|| SQL_SUCCESS != SqlStmt_BindColumn(stmt, 1, SQLDT_STRING, &filetype, sizeof(filetype), nullptr, nullptr)
-		|| SQL_SUCCESS != SqlStmt_BindColumn(stmt, 2, SQLDT_BLOB, &blob, MAX_EMBLEM_SIZE, &emblem_size, nullptr)
-		|| SQL_SUCCESS != SqlStmt_NextRow(stmt)
+	if (SQL_SUCCESS != stmt.BindColumn( 0, SQLDT_UINT32, &version, sizeof(version), nullptr, nullptr)
+		|| SQL_SUCCESS != stmt.BindColumn( 1, SQLDT_STRING, &filetype, sizeof(filetype), nullptr, nullptr)
+		|| SQL_SUCCESS != stmt.BindColumn( 2, SQLDT_BLOB, &blob, MAX_EMBLEM_SIZE, &emblem_size, nullptr)
+		|| SQL_SUCCESS != stmt.NextRow()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	SqlStmt_Free(stmt);
 	sl.unlock();
 
 	if (emblem_size > MAX_EMBLEM_SIZE) {
@@ -227,16 +223,15 @@ HANDLER_FUNC(emblem_upload) {
 	SQLLock sl(WEB_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt * stmt = SqlStmt_Malloc(handle);
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	SqlStmt stmt{ *handle };
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `version` FROM `%s` WHERE (`guild_id` = ? AND `world_name` = ?)",
 			guild_emblems_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &guild_id, sizeof(guild_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)world_name, strlen(world_name))
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &guild_id, sizeof(guild_id))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (void *)world_name, strlen(world_name))
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
@@ -245,12 +240,11 @@ HANDLER_FUNC(emblem_upload) {
 
 	uint32 version = START_VERSION;
 
-	if (SqlStmt_NumRows(stmt) > 0) {
-		if (SQL_SUCCESS != SqlStmt_BindColumn(stmt, 0, SQLDT_UINT32, &version, sizeof(version), nullptr, nullptr)
-			|| SQL_SUCCESS != SqlStmt_NextRow(stmt)
+	if (stmt.NumRows() > 0) {
+		if (SQL_SUCCESS != stmt.BindColumn(0, SQLDT_UINT32, &version, sizeof(version), nullptr, nullptr)
+			|| SQL_SUCCESS != stmt.NextRow()
 		) {
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			sl.unlock();
 			res.status = HTTP_BAD_REQUEST;
 			res.set_content("Error", "text/plain");
@@ -260,25 +254,23 @@ HANDLER_FUNC(emblem_upload) {
 	}
 
 	// insert new
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	if (SQL_SUCCESS != stmt.Prepare(
 		"REPLACE INTO `%s` (`version`, `file_type`, `guild_id`, `world_name`, `file_data`) VALUES (?, ?, ?, ?, ?)",
 		guild_emblems_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_UINT32, &version, sizeof(version))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)imgtype, strlen(imgtype))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_INT, &guild_id, sizeof(guild_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void *)world_name, strlen(world_name))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_BLOB, (void *)img.c_str(), length)
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_UINT32, &version, sizeof(version))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (void *)imgtype, strlen(imgtype))
+		|| SQL_SUCCESS != stmt.BindParam(2, SQLDT_INT, &guild_id, sizeof(guild_id))
+		|| SQL_SUCCESS != stmt.BindParam(3, SQLDT_STRING, (void *)world_name, strlen(world_name))
+		|| SQL_SUCCESS != stmt.BindParam(4, SQLDT_BLOB, (void *)img.c_str(), length)
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	SqlStmt_Free(stmt);
 	sl.unlock();
 
 	std::ostringstream stream;

+ 32 - 40
src/web/merchantstore_controller.cpp

@@ -36,37 +36,35 @@ HANDLER_FUNC(merchantstore_save) {
 	SQLLock sl(WEB_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt* stmt = SqlStmt_Malloc(handle);
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	SqlStmt stmt{ *handle };
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `account_id` FROM `%s` WHERE (`account_id` = ? AND `char_id` = ? AND `world_name` = ? AND `store_type` = ?) LIMIT 1",
 			merchant_configs_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, &char_id, sizeof(char_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)world_name, strlen(world_name))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_INT, &store_type, sizeof(store_type))
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_INT, &char_id, sizeof(char_id))
+		|| SQL_SUCCESS != stmt.BindParam(2, SQLDT_STRING, (void *)world_name, strlen(world_name))
+		|| SQL_SUCCESS != stmt.BindParam(3, SQLDT_INT, &store_type, sizeof(store_type))
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	if (SqlStmt_NumRows(stmt) <= 0) {
-		if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	if (stmt.NumRows() <= 0) {
+		if (SQL_SUCCESS != stmt.Prepare(
 				"INSERT INTO `%s` (`account_id`, `char_id`, `world_name`, `store_type`, `data`) VALUES (?, ?, ?, ?, ?)",
 				merchant_configs_table)
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, &char_id, sizeof(char_id))
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)world_name, strlen(world_name))
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_INT, &store_type, sizeof(store_type))
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void *)data.c_str(), strlen(data.c_str()))
-			|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+			|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+			|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_INT, &char_id, sizeof(char_id))
+			|| SQL_SUCCESS != stmt.BindParam(2, SQLDT_STRING, (void *)world_name, strlen(world_name))
+			|| SQL_SUCCESS != stmt.BindParam(3, SQLDT_INT, &store_type, sizeof(store_type))
+			|| SQL_SUCCESS != stmt.BindParam(4, SQLDT_STRING, (void *)data.c_str(), strlen(data.c_str()))
+			|| SQL_SUCCESS != stmt.Execute()
 		) {
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			sl.unlock();
 			res.status = HTTP_BAD_REQUEST;
 			res.set_content("Error", "text/plain");
@@ -74,18 +72,17 @@ HANDLER_FUNC(merchantstore_save) {
 		}
 	}
 	else {
-		if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+		if (SQL_SUCCESS != stmt.Prepare(
 				"UPDATE `%s` SET `data` = ? WHERE (`account_id` = ? AND `char_id` = ? AND `world_name` = ? AND `store_type` = ?)",
 				merchant_configs_table)
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void *)data.c_str(), strlen(data.c_str()))
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, &account_id, sizeof(account_id))
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_INT, &char_id, sizeof(char_id))
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void *)world_name, strlen(world_name))
-			|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, &store_type, sizeof(store_type))
-			|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+			|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_STRING, (void *)data.c_str(), strlen(data.c_str()))
+			|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_INT, &account_id, sizeof(account_id))
+			|| SQL_SUCCESS != stmt.BindParam(2, SQLDT_INT, &char_id, sizeof(char_id))
+			|| SQL_SUCCESS != stmt.BindParam(3, SQLDT_STRING, (void *)world_name, strlen(world_name))
+			|| SQL_SUCCESS != stmt.BindParam(4, SQLDT_INT, &store_type, sizeof(store_type))
+			|| SQL_SUCCESS != stmt.Execute()
 		) {
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			sl.unlock();
 			res.status = HTTP_BAD_REQUEST;
 			res.set_content("Error", "text/plain");
@@ -93,7 +90,6 @@ HANDLER_FUNC(merchantstore_save) {
 		}
 	}
 
-	SqlStmt_Free(stmt);
 	sl.unlock();
 	res.set_content(data, "application/json");
 }
@@ -121,26 +117,24 @@ HANDLER_FUNC(merchantstore_load) {
 	SQLLock sl(WEB_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt* stmt = SqlStmt_Malloc(handle);
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	SqlStmt stmt{ *handle };
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `data` FROM `%s` WHERE (`account_id` = ? AND `char_id` = ? AND `world_name` = ? AND `store_type` = ?) LIMIT 1",
 			merchant_configs_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_INT, &char_id, sizeof(char_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)world_name, strlen(world_name))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_INT, &store_type, sizeof(store_type))
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_INT, &char_id, sizeof(char_id))
+		|| SQL_SUCCESS != stmt.BindParam(2, SQLDT_STRING, (void *)world_name, strlen(world_name))
+		|| SQL_SUCCESS != stmt.BindParam(3, SQLDT_INT, &store_type, sizeof(store_type))
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	if (SqlStmt_NumRows(stmt) <= 0) {
-		SqlStmt_Free(stmt);
+	if (stmt.NumRows() <= 0) {
 		ShowDebug("[AccountID: %d, World: \"%s\"] Not found in table, sending new info.\n", account_id, world_name);
 		sl.unlock();
 		res.set_content("{\"Type\": 1}", "application/json");
@@ -149,18 +143,16 @@ HANDLER_FUNC(merchantstore_load) {
 
 	char databuf[SQL_BUFFER_SIZE] = { 0 };
 
-	if (SQL_SUCCESS != SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
-		|| SQL_SUCCESS != SqlStmt_NextRow(stmt)
+	if (SQL_SUCCESS != stmt.BindColumn(0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
+		|| SQL_SUCCESS != stmt.NextRow()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	SqlStmt_Free(stmt);
 	sl.unlock();
 
 	databuf[sizeof(databuf) - 1] = 0;

+ 22 - 27
src/web/partybooking_controller.cpp

@@ -66,7 +66,7 @@ bool party_booking_read( std::string& world_name, std::vector<s_party_booking_en
 	SQLLock sl(MAP_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt* stmt = SqlStmt_Malloc( handle );
+	SqlStmt stmt{ *handle };
 	s_party_booking_entry entry;
 	char world_name_escaped[WORLD_NAME_LENGTH * 2 + 1];
 	char char_name[NAME_LENGTH ];
@@ -76,35 +76,33 @@ bool party_booking_read( std::string& world_name, std::vector<s_party_booking_en
 
 	std::string query = "SELECT `account_id`, `char_id`, `char_name`, `purpose`, `assist`, `damagedealer`, `healer`, `tanker`, `minimum_level`, `maximum_level`, `comment` FROM `" + std::string( partybookings_table ) + "` WHERE `world_name` = ? AND " + condition + order;
 
-	if( SQL_SUCCESS != SqlStmt_Prepare( stmt, query.c_str() )
-		|| SQL_SUCCESS != SqlStmt_BindParam( stmt, 0, SQLDT_STRING, (void*)world_name_escaped, strlen( world_name_escaped ) )
-		|| SQL_SUCCESS != SqlStmt_Execute( stmt )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 0, SQLDT_UINT32, &entry.account_id, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 1, SQLDT_UINT32, &entry.char_id, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 2, SQLDT_STRING, (void*)char_name, sizeof( char_name ), nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 3, SQLDT_UINT16, &entry.purpose, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 4, SQLDT_UINT8, &entry.assist, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 5, SQLDT_UINT8, &entry.damagedealer, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 6, SQLDT_UINT8, &entry.healer, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 7, SQLDT_UINT8, &entry.tanker, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 8, SQLDT_UINT16, &entry.minimum_level, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 9, SQLDT_UINT16, &entry.maximum_level, 0, nullptr, nullptr )
-		|| SQL_SUCCESS != SqlStmt_BindColumn( stmt, 10, SQLDT_STRING, (void*)comment, sizeof( comment ), nullptr, nullptr )
+	if( SQL_SUCCESS != stmt.Prepare( query.c_str() )
+		|| SQL_SUCCESS != stmt.BindParam( 0, SQLDT_STRING, (void*)world_name_escaped, strlen( world_name_escaped ) )
+		|| SQL_SUCCESS != stmt.Execute()
+		|| SQL_SUCCESS != stmt.BindColumn( 0, SQLDT_UINT32, &entry.account_id, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 1, SQLDT_UINT32, &entry.char_id, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 2, SQLDT_STRING, (void*)char_name, sizeof( char_name ), nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 3, SQLDT_UINT16, &entry.purpose, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 4, SQLDT_UINT8, &entry.assist, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 5, SQLDT_UINT8, &entry.damagedealer, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 6, SQLDT_UINT8, &entry.healer, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 7, SQLDT_UINT8, &entry.tanker, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 8, SQLDT_UINT16, &entry.minimum_level, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 9, SQLDT_UINT16, &entry.maximum_level, 0, nullptr, nullptr )
+		|| SQL_SUCCESS != stmt.BindColumn( 10, SQLDT_STRING, (void*)comment, sizeof( comment ), nullptr, nullptr )
 	){
 		SqlStmt_ShowDebug( stmt );
-		SqlStmt_Free( stmt );
 		sl.unlock();
 		return false;
 	}
 
-	while( SQL_SUCCESS == SqlStmt_NextRow( stmt ) ){
+	while( SQL_SUCCESS == stmt.NextRow() ){
 		entry.char_name = char_name;
 		entry.comment = comment;
 
 		output.push_back( entry );
 	}
 
-	SqlStmt_Free( stmt );
 	sl.unlock();
 
 	return true;
@@ -123,30 +121,27 @@ HANDLER_FUNC(partybooking_add){
 	SQLLock csl( CHAR_SQL_LOCK );
 	csl.lock();
 	auto chandle = csl.getHandle();
-	SqlStmt* stmt = SqlStmt_Malloc( chandle );
-	if( SQL_SUCCESS != SqlStmt_Prepare( stmt, "SELECT 1 FROM `%s` WHERE `leader_id` = ? AND `leader_char` = ?", party_table, aid, cid )
-		|| SQL_SUCCESS != SqlStmt_BindParam( stmt, 0, SQLDT_UINT32, &aid, sizeof( aid ) )
-		|| SQL_SUCCESS != SqlStmt_BindParam( stmt, 1, SQLDT_UINT32, &cid, sizeof( cid ) )
-		|| SQL_SUCCESS != SqlStmt_Execute( stmt )
+	SqlStmt stmt{ *chandle };
+	if( SQL_SUCCESS != stmt.Prepare( "SELECT 1 FROM `%s` WHERE `leader_id` = ? AND `leader_char` = ?", party_table, aid, cid )
+		|| SQL_SUCCESS != stmt.BindParam( 0, SQLDT_UINT32, &aid, sizeof( aid ) )
+		|| SQL_SUCCESS != stmt.BindParam( 1, SQLDT_UINT32, &cid, sizeof( cid ) )
+		|| SQL_SUCCESS != stmt.Execute()
 	){
 		SqlStmt_ShowDebug( stmt );
-		SqlStmt_Free( stmt );
 		csl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content( "Error", "text/plain" );
 		return;
 	}
 
-	if( SqlStmt_NumRows( stmt ) <= 0 ){
+	if( stmt.NumRows() <= 0 ){
 		// No party or not party leader
-		SqlStmt_Free( stmt );
 		csl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content( "Error", "text/plain" );
 		return;
 	}
 
-	SqlStmt_Free( stmt );
 	csl.unlock();
 
 	auto world_name = req.get_file_value( "WorldName" ).content;

+ 28 - 36
src/web/userconfig_controller.cpp

@@ -33,29 +33,27 @@ HANDLER_FUNC(userconfig_save) {
 	SQLLock sl(WEB_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt * stmt = SqlStmt_Malloc(handle);
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	SqlStmt stmt{ *handle };
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `data` FROM `%s` WHERE (`account_id` = ? AND `world_name` = ?) LIMIT 1",
 			user_configs_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)world_name.c_str(), world_name.length())
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (void *)world_name.c_str(), world_name.length())
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	if (SqlStmt_NumRows(stmt) > 0) {
+	if (stmt.NumRows() > 0) {
 		char databuf[SQL_BUFFER_SIZE];
-		if (SQL_SUCCESS != SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
-			|| SQL_SUCCESS != SqlStmt_NextRow(stmt)
+		if (SQL_SUCCESS != stmt.BindColumn(0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
+			|| SQL_SUCCESS != stmt.NextRow()
 		) {
 			SqlStmt_ShowDebug(stmt);
-			SqlStmt_Free(stmt);
 			sl.unlock();
 			res.status = HTTP_BAD_REQUEST;
 			res.set_content("Error", "text/plain");
@@ -70,23 +68,21 @@ HANDLER_FUNC(userconfig_save) {
 
 	auto data_str = data.dump();
 
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	if (SQL_SUCCESS != stmt.Prepare(
 			"REPLACE INTO `%s` (`account_id`, `world_name`, `data`) VALUES (?, ?, ?)",
 			user_configs_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)world_name.c_str(), world_name.length())
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)data_str.c_str(), data_str.length())
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (void *)world_name.c_str(), world_name.length())
+		|| SQL_SUCCESS != stmt.BindParam(2, SQLDT_STRING, (void *)data_str.c_str(), data_str.length())
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	SqlStmt_Free(stmt);
 	sl.unlock();
 	res.set_content(data_str, "application/json");
 }
@@ -112,39 +108,36 @@ HANDLER_FUNC(userconfig_load) {
 	SQLLock sl(WEB_SQL_LOCK);
 	sl.lock();
 	auto handle = sl.getHandle();
-	SqlStmt * stmt = SqlStmt_Malloc(handle);
-	if (SQL_SUCCESS != SqlStmt_Prepare(stmt,
+	SqlStmt stmt{ *handle };
+	if (SQL_SUCCESS != stmt.Prepare(
 			"SELECT `data` FROM `%s` WHERE (`account_id` = ? AND `world_name` = ?) LIMIT 1",
 			user_configs_table)
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, &account_id, sizeof(account_id))
-		|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)world_name, strlen(world_name))
-		|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+		|| SQL_SUCCESS != stmt.BindParam(0, SQLDT_INT, &account_id, sizeof(account_id))
+		|| SQL_SUCCESS != stmt.BindParam(1, SQLDT_STRING, (void *)world_name, strlen(world_name))
+		|| SQL_SUCCESS != stmt.Execute()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	if (SqlStmt_NumRows(stmt) <= 0) {
+	if (stmt.NumRows() <= 0) {
 		std::string data = "{\"Type\": 1}";
 
-		if( SQL_SUCCESS != SqlStmt_Prepare( stmt, "INSERT INTO `%s` (`account_id`, `world_name`, `data`) VALUES (?, ?, ?)", user_configs_table ) ||
-			SQL_SUCCESS != SqlStmt_BindParam( stmt, 0, SQLDT_INT, &account_id, sizeof( account_id ) ) ||
-			SQL_SUCCESS != SqlStmt_BindParam( stmt, 1, SQLDT_STRING, (void *)world_name, strlen( world_name ) ) ||
-			SQL_SUCCESS != SqlStmt_BindParam( stmt, 2, SQLDT_STRING, (void *)data.c_str(), strlen( data.c_str() ) ) ||
-			SQL_SUCCESS != SqlStmt_Execute( stmt ) ){
+		if( SQL_SUCCESS != stmt.Prepare( "INSERT INTO `%s` (`account_id`, `world_name`, `data`) VALUES (?, ?, ?)", user_configs_table ) ||
+			SQL_SUCCESS != stmt.BindParam( 0, SQLDT_INT, &account_id, sizeof( account_id ) ) ||
+			SQL_SUCCESS != stmt.BindParam( 1, SQLDT_STRING, (void *)world_name, strlen( world_name ) ) ||
+			SQL_SUCCESS != stmt.BindParam( 2, SQLDT_STRING, (void *)data.c_str(), strlen( data.c_str() ) ) ||
+			SQL_SUCCESS != stmt.Execute() ){
 			SqlStmt_ShowDebug( stmt );
-			SqlStmt_Free( stmt );
 			sl.unlock();
 			res.status = HTTP_BAD_REQUEST;
 			res.set_content( "Error", "text/plain" );
 			return;
 		}
 
-		SqlStmt_Free( stmt );
 		sl.unlock();
 		res.set_content( data, "application/json" );
 		return;
@@ -152,21 +145,20 @@ HANDLER_FUNC(userconfig_load) {
 
 	char databuf[SQL_BUFFER_SIZE];
 
-	if (SQL_SUCCESS != SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
-		|| SQL_SUCCESS != SqlStmt_NextRow(stmt)
+	if (SQL_SUCCESS != stmt.BindColumn(0, SQLDT_STRING, &databuf, sizeof(databuf), nullptr, nullptr)
+		|| SQL_SUCCESS != stmt.NextRow()
 	) {
 		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
 		sl.unlock();
 		res.status = HTTP_BAD_REQUEST;
 		res.set_content("Error", "text/plain");
 		return;
 	}
 
-	SqlStmt_Free(stmt);
 	sl.unlock();
 
 	databuf[sizeof(databuf) - 1] = 0;
 	auto response = nlohmann::json::parse(databuf);
 	response["Type"] = 1;
-	res.set_content(response.dump(), "application/json");}
+	res.set_content(response.dump(), "application/json");
+}

+ 4 - 4
src/web/web-server.vcxproj

@@ -94,7 +94,7 @@
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>$(DefineConstants);WIN32;FD_SETSIZE=4096;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS;LIBCONFIG_STATIC;YY_USE_CONST;_DEBUG;_CONSOLE;_LIB;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\httplib\;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\httplib\;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <DisableSpecificWarnings>4018;4200</DisableSpecificWarnings>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <ConformanceMode>true</ConformanceMode>
@@ -114,7 +114,7 @@
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>$(DefineConstants);WIN32;FD_SETSIZE=4096;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS;LIBCONFIG_STATIC;YY_USE_CONST;_DEBUG;_CONSOLE;_LIB;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\httplib\;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\httplib\;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <DisableSpecificWarnings>4018</DisableSpecificWarnings>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
@@ -136,7 +136,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>$(DefineConstants);WIN32;FD_SETSIZE=4096;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS;LIBCONFIG_STATIC;YY_USE_CONST;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\httplib\;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\httplib\;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <DisableSpecificWarnings>4018</DisableSpecificWarnings>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
@@ -160,7 +160,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>$(DefineConstants);WIN32;FD_SETSIZE=4096;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS;LIBCONFIG_STATIC;YY_USE_CONST;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\httplib\;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)3rdparty\libconfig\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)src;$(SolutionDir)3rdparty\httplib\;$(SolutionDir)\3rdparty\rapidyaml\src;$(SolutionDir)\3rdparty\rapidyaml\ext\c4core\src;$(SolutionDir)\3rdparty\json\include;$(SolutionDir)3rdparty\libconfig\;$(SolutionDir)3rdparty\mysql\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <DisableSpecificWarnings>4018</DisableSpecificWarnings>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>