249 lines
6.1 KiB
C++
249 lines
6.1 KiB
C++
// Copyright (C) 2007 EQ2EMulator Development Team - GPL v3 License
|
|
|
|
#pragma once
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <cstdlib>
|
|
#include <mysql.h>
|
|
|
|
#include "../types.hpp"
|
|
#include "../log.hpp"
|
|
|
|
using namespace std;
|
|
|
|
// Return this instead of NULL for string functions to prevent crashes
|
|
static const char* empty_str = "";
|
|
|
|
// Database result wrapper class for MySQL query results with type-safe accessors
|
|
class DatabaseResult
|
|
{
|
|
public:
|
|
// Constructor - initializes empty result set
|
|
DatabaseResult() : field_map(), result(0), num_fields(0), row(0)
|
|
{
|
|
}
|
|
|
|
// Destructor - frees MySQL result and clears field mappings
|
|
virtual ~DatabaseResult()
|
|
{
|
|
if (result != NULL)
|
|
mysql_free_result(result);
|
|
if (field_map.size()) {
|
|
field_map.clear();
|
|
}
|
|
}
|
|
|
|
// Store MySQL result set and build field name to index mapping
|
|
bool StoreResult(MYSQL_RES* res, uint8 field_count, uint8 row_count)
|
|
{
|
|
if (result != NULL)
|
|
mysql_free_result(result);
|
|
if (field_map.size()) {
|
|
field_map.clear();
|
|
}
|
|
|
|
result = res;
|
|
num_rows = row_count;
|
|
num_fields = field_count;
|
|
|
|
if (!num_rows || !num_fields) {
|
|
mysql_free_result(res);
|
|
result = NULL;
|
|
return false;
|
|
}
|
|
|
|
const MYSQL_FIELD* fields = mysql_fetch_fields(result);
|
|
for (uint8 i = 0; i < num_fields; ++i) {
|
|
field_map.emplace(std::make_pair(std::string_view(fields[i].name), i));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Advance to next row in result set
|
|
bool Next()
|
|
{
|
|
return (result != NULL && (row = mysql_fetch_row(result)) != NULL);
|
|
}
|
|
|
|
// Get total number of rows in result set
|
|
const unsigned int GetNumRows() { return num_rows; }
|
|
|
|
// Check if field value at index is NULL
|
|
bool IsNull(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL;
|
|
}
|
|
|
|
// Check if field value by name is NULL
|
|
bool IsNullStr(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL;
|
|
}
|
|
|
|
// Type-safe getters by index
|
|
int8 GetInt8(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
sint8 GetSInt8(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
int16 GetInt16(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
sint16 GetSInt16(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
int32 GetInt32(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0U : strtoul(value, NULL, 10);
|
|
}
|
|
|
|
sint32 GetSInt32(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
uint64 GetInt64(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0UL : strtoull(value, NULL, 10);
|
|
}
|
|
|
|
sint64 GetSInt64(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0L : strtoll(value, NULL, 10);
|
|
}
|
|
|
|
float GetFloat(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? 0.0F : atof(value);
|
|
}
|
|
|
|
char GetChar(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? '\0' : value[0];
|
|
}
|
|
|
|
const char* GetString(unsigned int index)
|
|
{
|
|
const char* value = GetFieldValue(index);
|
|
return value == NULL ? empty_str : value;
|
|
}
|
|
|
|
// Type-safe getters by field name
|
|
int8 GetInt8Str(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
sint8 GetSInt8Str(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
int16 GetInt16Str(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
sint16 GetSInt16Str(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
int32 GetInt32Str(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0U : strtoul(value, NULL, 10);
|
|
}
|
|
|
|
sint32 GetSInt32Str(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0 : atoi(value);
|
|
}
|
|
|
|
uint64 GetInt64Str(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0UL : strtoull(value, NULL, 10);
|
|
}
|
|
|
|
sint64 GetSInt64Str(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0L : strtoll(value, NULL, 10);
|
|
}
|
|
|
|
float GetFloatStr(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? 0.0F : atof(value);
|
|
}
|
|
|
|
char GetCharStr(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? '\0' : value[0];
|
|
}
|
|
|
|
const char* GetStringStr(const char* field_name)
|
|
{
|
|
const char* value = GetFieldValueStr(field_name);
|
|
return value == NULL ? empty_str : value;
|
|
}
|
|
|
|
// Get raw field value by index with bounds checking
|
|
const char* GetFieldValue(unsigned int index)
|
|
{
|
|
if (index >= num_fields) {
|
|
LogWrite(DATABASE__ERROR, 0, "Database Result", "Attempt to access field at index %u but there %s only %u field%s", index, num_fields == 1 ? "is" : "are", num_fields, num_fields == 1 ? "" : "s");
|
|
return NULL;
|
|
}
|
|
return row[index];
|
|
}
|
|
|
|
// Get raw field value by name with field mapping lookup
|
|
const char* GetFieldValueStr(const char* field_name)
|
|
{
|
|
const auto& map_iterator = field_map.find(std::string_view(field_name));
|
|
if (map_iterator != field_map.end()) {
|
|
return row[map_iterator->second];
|
|
}
|
|
LogWrite(DATABASE__ERROR, 0, "Database Result", "Unknown field name '%s'", field_name);
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
MYSQL_RES* result; // MySQL result set from query
|
|
MYSQL_ROW row; // Current row data
|
|
unsigned int num_rows; // Total number of rows in result
|
|
unsigned int num_fields; // Total number of fields per row
|
|
std::map<std::string_view, uint8> field_map; // Field name to index mapping for fast lookups
|
|
}; |