Core/Database: Optimised Database::StoreResult by using a map of field names to indices instead of a char pointer array. Issue #559
This commit is contained in:
parent
f66d687bfe
commit
dc552fc9f6
3 changed files with 33 additions and 50 deletions
|
@ -233,7 +233,13 @@ bool DatabaseNew::Select(DatabaseResult *result, const char *query, ...) {
|
|||
res = mysql_store_result(&mysql);
|
||||
|
||||
if (res != NULL)
|
||||
ret = result->StoreResult(res);
|
||||
{
|
||||
// Grab number of rows and number of fields from the query
|
||||
uint8 num_rows = mysql_affected_rows(&mysql);
|
||||
uint8 num_fields = mysql_field_count(&mysql);
|
||||
|
||||
ret = result->StoreResult(res, num_fields, num_rows);
|
||||
}
|
||||
else {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Error storing MySql query result (%d): %s\n%s", mysql_errno(&mysql), mysql_error(&mysql), buf);
|
||||
ret = false;
|
||||
|
|
|
@ -28,11 +28,7 @@
|
|||
//return this instead of NULL for certain functions to prevent crashes from coding errors
|
||||
static const char *empty_str = "";
|
||||
|
||||
DatabaseResult::DatabaseResult() {
|
||||
result = NULL;
|
||||
field_names = NULL;
|
||||
num_fields = 0;
|
||||
row = 0;
|
||||
DatabaseResult::DatabaseResult(): field_map(), result(0), num_fields(0), row(0) {
|
||||
}
|
||||
|
||||
DatabaseResult::~DatabaseResult() {
|
||||
|
@ -41,60 +37,40 @@ DatabaseResult::~DatabaseResult() {
|
|||
if (result != NULL)
|
||||
mysql_free_result(result);
|
||||
|
||||
if (field_names != NULL) {
|
||||
for (i = 0; i < num_fields; i++)
|
||||
free(field_names[i]);
|
||||
free(field_names);
|
||||
if (field_map.size()) {
|
||||
field_map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabaseResult::StoreResult(MYSQL_RES *res) {
|
||||
unsigned int i, j;
|
||||
MYSQL_FIELD *field;
|
||||
bool DatabaseResult::StoreResult(MYSQL_RES* res, uint8 field_count, uint8 row_count) {
|
||||
|
||||
//clear any previously stored result
|
||||
if (result != NULL)
|
||||
mysql_free_result(result);
|
||||
|
||||
//clear any field names from a previous result
|
||||
if (field_names != NULL) {
|
||||
for (i = 0; i < num_fields; i++)
|
||||
free(field_names[i]);
|
||||
free(field_names);
|
||||
if (field_map.size()) {
|
||||
field_map.clear();
|
||||
}
|
||||
|
||||
//store the new result
|
||||
result = res;
|
||||
num_fields = mysql_num_fields(res);
|
||||
|
||||
//allocate enough space for each field's name
|
||||
if ((field_names = (char **)malloc(sizeof(char *) * num_fields)) == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database Result", "Unable to allocate %u bytes when storing database result and fetching field names\nNumber of fields=%u\n", sizeof(char *) * num_fields, num_fields);
|
||||
mysql_free_result(result);
|
||||
num_rows = row_count;
|
||||
num_fields = field_count;
|
||||
|
||||
// No rows or fields then we don't care
|
||||
if (!num_rows || !num_fields) {
|
||||
mysql_free_result(res);
|
||||
result = NULL;
|
||||
num_fields = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
//store each field's name
|
||||
i = 0;
|
||||
while ((field = mysql_fetch_field(result)) != NULL) {
|
||||
if ((field_names[i] = (char *)calloc(field->name_length + 1, sizeof(char))) == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database Result", "Unable to allocate %u bytes when storing databse result and copying field name %s\n", field->name_length + 1, field->name);
|
||||
mysql_free_result(result);
|
||||
result = NULL;
|
||||
for (j = 0; j < i; j++)
|
||||
free(field_names[j]);
|
||||
free(field_names);
|
||||
field_names = NULL;
|
||||
num_fields = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
const MYSQL_FIELD* fields = mysql_fetch_fields(result);
|
||||
|
||||
strncpy(field_names[i], field->name, field->name_length);
|
||||
i++;
|
||||
for (uint8 i = 0; i < num_fields; ++i) {
|
||||
field_map.emplace(std::make_pair(std::string_view(fields[i].name), i));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -108,11 +84,9 @@ const char * DatabaseResult::GetFieldValue(unsigned int index) {
|
|||
}
|
||||
|
||||
const char * DatabaseResult::GetFieldValueStr(const char *field_name) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
if (strncmp(field_name, field_names[i], FIELD_NAME_MAX) == 0)
|
||||
return row[i];
|
||||
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);
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
#include <WinSock2.h> //#include <my_global.h> when we/if we go to winsock2 :/
|
||||
#endif
|
||||
#include <mysql.h>
|
||||
#include <map>
|
||||
|
||||
class DatabaseResult {
|
||||
public:
|
||||
DatabaseResult();
|
||||
virtual ~DatabaseResult();
|
||||
|
||||
bool StoreResult(MYSQL_RES *res);
|
||||
bool StoreResult(MYSQL_RES* result, uint8 field_count, uint8 row_count);
|
||||
bool Next();
|
||||
|
||||
bool IsNull(unsigned int index);
|
||||
|
@ -40,15 +41,17 @@ public:
|
|||
const char * GetString(unsigned int index);
|
||||
const char * GetStringStr(const char *field_name);
|
||||
|
||||
unsigned int GetNumRows() {return result == NULL ? 0 : (unsigned int)mysql_num_rows(result);}
|
||||
const unsigned int GetNumRows() { return num_rows; }
|
||||
|
||||
const char * GetFieldValue(unsigned int index);
|
||||
const char * GetFieldValueStr(const char *field_name);
|
||||
private:
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
char **field_names;
|
||||
unsigned int num_rows;
|
||||
unsigned int num_fields;
|
||||
|
||||
std::map<std::string_view,uint8> field_map;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue