aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/DatabaseEnvFwd.h1
-rw-r--r--src/server/database/Database/Field.cpp129
-rw-r--r--src/server/database/Database/Field.h49
-rw-r--r--src/server/database/Database/QueryResult.cpp73
-rw-r--r--src/server/database/Database/QueryResult.h2
5 files changed, 122 insertions, 132 deletions
diff --git a/src/server/database/Database/DatabaseEnvFwd.h b/src/server/database/Database/DatabaseEnvFwd.h
index 930957fb898..8d09e502f72 100644
--- a/src/server/database/Database/DatabaseEnvFwd.h
+++ b/src/server/database/Database/DatabaseEnvFwd.h
@@ -21,6 +21,7 @@
#include <future>
#include <memory>
+struct QueryResultFieldMetadata;
class Field;
class ResultSet;
diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp
index ef257792eff..c0a4d329cd4 100644
--- a/src/server/database/Database/Field.cpp
+++ b/src/server/database/Database/Field.cpp
@@ -17,19 +17,17 @@
#include "Field.h"
#include "Log.h"
+#include "MySQLHacks.h"
Field::Field()
{
data.value = nullptr;
- data.type = DatabaseFieldTypes::Null;
data.length = 0;
data.raw = false;
+ meta = nullptr;
}
-Field::~Field()
-{
- CleanUp();
-}
+Field::~Field() = default;
uint8 Field::GetUInt8() const
{
@@ -46,8 +44,8 @@ uint8 Field::GetUInt8() const
#endif
if (data.raw)
- return *reinterpret_cast<uint8*>(data.value);
- return static_cast<uint8>(strtoul((char*)data.value, nullptr, 10));
+ return *reinterpret_cast<uint8 const*>(data.value);
+ return static_cast<uint8>(strtoul(data.value, nullptr, 10));
}
int8 Field::GetInt8() const
@@ -65,8 +63,8 @@ int8 Field::GetInt8() const
#endif
if (data.raw)
- return *reinterpret_cast<int8*>(data.value);
- return static_cast<int8>(strtol((char*)data.value, nullptr, 10));
+ return *reinterpret_cast<int8 const*>(data.value);
+ return static_cast<int8>(strtol(data.value, nullptr, 10));
}
uint16 Field::GetUInt16() const
@@ -84,8 +82,8 @@ uint16 Field::GetUInt16() const
#endif
if (data.raw)
- return *reinterpret_cast<uint16*>(data.value);
- return static_cast<uint16>(strtoul((char*)data.value, nullptr, 10));
+ return *reinterpret_cast<uint16 const*>(data.value);
+ return static_cast<uint16>(strtoul(data.value, nullptr, 10));
}
int16 Field::GetInt16() const
@@ -103,8 +101,8 @@ int16 Field::GetInt16() const
#endif
if (data.raw)
- return *reinterpret_cast<int16*>(data.value);
- return static_cast<int16>(strtol((char*)data.value, nullptr, 10));
+ return *reinterpret_cast<int16 const*>(data.value);
+ return static_cast<int16>(strtol(data.value, nullptr, 10));
}
uint32 Field::GetUInt32() const
@@ -122,8 +120,8 @@ uint32 Field::GetUInt32() const
#endif
if (data.raw)
- return *reinterpret_cast<uint32*>(data.value);
- return static_cast<uint32>(strtoul((char*)data.value, nullptr, 10));
+ return *reinterpret_cast<uint32 const*>(data.value);
+ return static_cast<uint32>(strtoul(data.value, nullptr, 10));
}
int32 Field::GetInt32() const
@@ -141,8 +139,8 @@ int32 Field::GetInt32() const
#endif
if (data.raw)
- return *reinterpret_cast<int32*>(data.value);
- return static_cast<int32>(strtol((char*)data.value, nullptr, 10));
+ return *reinterpret_cast<int32 const*>(data.value);
+ return static_cast<int32>(strtol(data.value, nullptr, 10));
}
uint64 Field::GetUInt64() const
@@ -160,8 +158,8 @@ uint64 Field::GetUInt64() const
#endif
if (data.raw)
- return *reinterpret_cast<uint64*>(data.value);
- return static_cast<uint64>(strtoull((char*)data.value, nullptr, 10));
+ return *reinterpret_cast<uint64 const*>(data.value);
+ return static_cast<uint64>(strtoull(data.value, nullptr, 10));
}
int64 Field::GetInt64() const
@@ -179,8 +177,8 @@ int64 Field::GetInt64() const
#endif
if (data.raw)
- return *reinterpret_cast<int64*>(data.value);
- return static_cast<int64>(strtoll((char*)data.value, nullptr, 10));
+ return *reinterpret_cast<int64 const*>(data.value);
+ return static_cast<int64>(strtoll(data.value, nullptr, 10));
}
float Field::GetFloat() const
@@ -198,8 +196,8 @@ float Field::GetFloat() const
#endif
if (data.raw)
- return *reinterpret_cast<float*>(data.value);
- return static_cast<float>(atof((char*)data.value));
+ return *reinterpret_cast<float const*>(data.value);
+ return static_cast<float>(atof(data.value));
}
double Field::GetDouble() const
@@ -217,8 +215,8 @@ double Field::GetDouble() const
#endif
if (data.raw && !IsType(DatabaseFieldTypes::Decimal))
- return *reinterpret_cast<double*>(data.value);
- return static_cast<double>(atof((char*)data.value));
+ return *reinterpret_cast<double const*>(data.value);
+ return static_cast<double>(atof(data.value));
}
char const* Field::GetCString() const
@@ -260,93 +258,44 @@ std::vector<uint8> Field::GetBinary() const
return result;
}
-void Field::SetByteValue(void* newValue, DatabaseFieldTypes newType, uint32 length)
+void Field::SetByteValue(char const* newValue, uint32 length)
{
// This value stores raw bytes that have to be explicitly cast later
data.value = newValue;
data.length = length;
- data.type = newType;
data.raw = true;
}
-void Field::SetStructuredValue(char* newValue, DatabaseFieldTypes newType, uint32 length)
+void Field::SetStructuredValue(char const* newValue, uint32 length)
{
- if (data.value)
- CleanUp();
-
// This value stores somewhat structured data that needs function style casting
- if (newValue)
- {
- data.value = new char[length + 1];
- memcpy(data.value, newValue, length);
- *(reinterpret_cast<char*>(data.value) + length) = '\0';
- data.length = length;
- }
-
- data.type = newType;
+ data.value = newValue;
+ data.length = length;
data.raw = false;
}
bool Field::IsType(DatabaseFieldTypes type) const
{
- return data.type == type;
+ return meta->Type == type;
}
bool Field::IsNumeric() const
{
- return (data.type == DatabaseFieldTypes::Int8 ||
- data.type == DatabaseFieldTypes::Int16 ||
- data.type == DatabaseFieldTypes::Int32 ||
- data.type == DatabaseFieldTypes::Int64 ||
- data.type == DatabaseFieldTypes::Float ||
- data.type == DatabaseFieldTypes::Double);
+ return (meta->Type == DatabaseFieldTypes::Int8 ||
+ meta->Type == DatabaseFieldTypes::Int16 ||
+ meta->Type == DatabaseFieldTypes::Int32 ||
+ meta->Type == DatabaseFieldTypes::Int64 ||
+ meta->Type == DatabaseFieldTypes::Float ||
+ meta->Type == DatabaseFieldTypes::Double);
}
-#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS
-
-#include "MySQLHacks.h"
-
-static char const* FieldTypeToString(enum_field_types type)
+void Field::LogWrongType(char const* getter) const
{
- switch (type)
- {
- case MYSQL_TYPE_BIT: return "BIT";
- case MYSQL_TYPE_BLOB: return "BLOB";
- case MYSQL_TYPE_DATE: return "DATE";
- case MYSQL_TYPE_DATETIME: return "DATETIME";
- case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL";
- case MYSQL_TYPE_DECIMAL: return "DECIMAL";
- case MYSQL_TYPE_DOUBLE: return "DOUBLE";
- case MYSQL_TYPE_ENUM: return "ENUM";
- case MYSQL_TYPE_FLOAT: return "FLOAT";
- case MYSQL_TYPE_GEOMETRY: return "GEOMETRY";
- case MYSQL_TYPE_INT24: return "INT24";
- case MYSQL_TYPE_LONG: return "LONG";
- case MYSQL_TYPE_LONGLONG: return "LONGLONG";
- case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB";
- case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB";
- case MYSQL_TYPE_NEWDATE: return "NEWDATE";
- case MYSQL_TYPE_NULL: return "NULL";
- case MYSQL_TYPE_SET: return "SET";
- case MYSQL_TYPE_SHORT: return "SHORT";
- case MYSQL_TYPE_STRING: return "STRING";
- case MYSQL_TYPE_TIME: return "TIME";
- case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP";
- case MYSQL_TYPE_TINY: return "TINY";
- case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB";
- case MYSQL_TYPE_VAR_STRING: return "VAR_STRING";
- case MYSQL_TYPE_YEAR: return "YEAR";
- default: return "-Unknown-";
- }
+ TC_LOG_WARN("sql.sql", "Warning: %s on %s field %s.%s (%s.%s) at index %u.",
+ getter, meta->TypeName, meta->TableAlias, meta->Alias, meta->TableName, meta->Name, meta->Index);
}
-void Field::SetMetadata(MySQLField* field, uint32 fieldIndex)
+void Field::SetMetadata(QueryResultFieldMetadata const* fieldMeta)
{
- meta.TableName = field->org_table;
- meta.TableAlias = field->table;
- meta.Name = field->org_name;
- meta.Alias = field->name;
- meta.Type = FieldTypeToString(field->type);
- meta.Index = fieldIndex;
+ meta = fieldMeta;
}
-#endif
diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h
index 45db25c4ecd..ea7c82d1876 100644
--- a/src/server/database/Database/Field.h
+++ b/src/server/database/Database/Field.h
@@ -36,6 +36,17 @@ enum class DatabaseFieldTypes : uint8
Binary
};
+struct QueryResultFieldMetadata
+{
+ char const* TableName = nullptr;
+ char const* TableAlias = nullptr;
+ char const* Name = nullptr;
+ char const* Alias = nullptr;
+ char const* TypeName = nullptr;
+ uint32 Index = 0;
+ DatabaseFieldTypes Type = DatabaseFieldTypes::Null;
+};
+
/**
@class Field
@@ -99,47 +110,25 @@ class TC_DATABASE_API Field
return data.value == nullptr;
}
- struct Metadata
- {
- char const* TableName;
- char const* TableAlias;
- char const* Name;
- char const* Alias;
- char const* Type;
- uint32 Index;
- };
-
protected:
- #pragma pack(push, 1)
struct
{
- uint32 length; // Length (prepared strings only)
- void* value; // Actual data in memory
- DatabaseFieldTypes type; // Field type
- bool raw; // Raw bytes? (Prepared statement or ad hoc)
+ char const* value; // Actual data in memory
+ uint32 length; // Length
+ bool raw; // Raw bytes? (Prepared statement or ad hoc)
} data;
- #pragma pack(pop)
-
- void SetByteValue(void* newValue, DatabaseFieldTypes newType, uint32 length);
- void SetStructuredValue(char* newValue, DatabaseFieldTypes newType, uint32 length);
- void CleanUp()
- {
- // Field does not own the data if fetched with prepared statement
- if (!data.raw)
- delete[] ((char*)data.value);
- data.value = nullptr;
- }
+ void SetByteValue(char const* newValue, uint32 length);
+ void SetStructuredValue(char const* newValue, uint32 length);
bool IsType(DatabaseFieldTypes type) const;
bool IsNumeric() const;
private:
- #ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS
- void SetMetadata(MySQLField* field, uint32 fieldIndex);
- Metadata meta;
- #endif
+ QueryResultFieldMetadata const* meta;
+ void LogWrongType(char const* getter) const;
+ void SetMetadata(QueryResultFieldMetadata const* fieldMeta);
};
#endif
diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp
index 7d592b2af88..df07c773313 100644
--- a/src/server/database/Database/QueryResult.cpp
+++ b/src/server/database/Database/QueryResult.cpp
@@ -22,6 +22,8 @@
#include "MySQLHacks.h"
#include "MySQLWorkaround.h"
+namespace
+{
static uint32 SizeForType(MYSQL_FIELD* field)
{
switch (field->type)
@@ -116,17 +118,65 @@ DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type)
return DatabaseFieldTypes::Null;
}
+static char const* FieldTypeToString(enum_field_types type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_BIT: return "BIT";
+ case MYSQL_TYPE_BLOB: return "BLOB";
+ case MYSQL_TYPE_DATE: return "DATE";
+ case MYSQL_TYPE_DATETIME: return "DATETIME";
+ case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL";
+ case MYSQL_TYPE_DECIMAL: return "DECIMAL";
+ case MYSQL_TYPE_DOUBLE: return "DOUBLE";
+ case MYSQL_TYPE_ENUM: return "ENUM";
+ case MYSQL_TYPE_FLOAT: return "FLOAT";
+ case MYSQL_TYPE_GEOMETRY: return "GEOMETRY";
+ case MYSQL_TYPE_INT24: return "INT24";
+ case MYSQL_TYPE_LONG: return "LONG";
+ case MYSQL_TYPE_LONGLONG: return "LONGLONG";
+ case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB";
+ case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB";
+ case MYSQL_TYPE_NEWDATE: return "NEWDATE";
+ case MYSQL_TYPE_NULL: return "NULL";
+ case MYSQL_TYPE_SET: return "SET";
+ case MYSQL_TYPE_SHORT: return "SHORT";
+ case MYSQL_TYPE_STRING: return "STRING";
+ case MYSQL_TYPE_TIME: return "TIME";
+ case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP";
+ case MYSQL_TYPE_TINY: return "TINY";
+ case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB";
+ case MYSQL_TYPE_VAR_STRING: return "VAR_STRING";
+ case MYSQL_TYPE_YEAR: return "YEAR";
+ default: return "-Unknown-";
+ }
+}
+
+void InitializeDatabaseFieldMetadata(QueryResultFieldMetadata* meta, MySQLField const* field, uint32 fieldIndex)
+{
+ meta->TableName = field->org_table;
+ meta->TableAlias = field->table;
+ meta->Name = field->org_name;
+ meta->Alias = field->name;
+ meta->TypeName = FieldTypeToString(field->type);
+ meta->Index = fieldIndex;
+ meta->Type = MysqlTypeToFieldType(field->type);
+}
+}
+
ResultSet::ResultSet(MySQLResult* result, MySQLField* fields, uint64 rowCount, uint32 fieldCount) :
_rowCount(rowCount),
_fieldCount(fieldCount),
_result(result),
_fields(fields)
{
+ _fieldMetadata.resize(_fieldCount);
_currentRow = new Field[_fieldCount];
-#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS
for (uint32 i = 0; i < _fieldCount; i++)
- _currentRow[i].SetMetadata(&_fields[i], i);
-#endif
+ {
+ InitializeDatabaseFieldMetadata(&_fieldMetadata[i], &_fields[i], i);
+ _currentRow[i].SetMetadata(&_fieldMetadata[i]);
+ }
}
PreparedResultSet::PreparedResultSet(MySQLStmt* stmt, MySQLResult* result, uint64 rowCount, uint32 fieldCount) :
@@ -172,12 +222,15 @@ m_metadataResult(result)
//- This is where we prepare the buffer based on metadata
MySQLField* field = reinterpret_cast<MySQLField*>(mysql_fetch_fields(m_metadataResult));
+ m_fieldMetadata.resize(m_fieldCount);
std::size_t rowSize = 0;
for (uint32 i = 0; i < m_fieldCount; ++i)
{
uint32 size = SizeForType(&field[i]);
rowSize += size;
+ InitializeDatabaseFieldMetadata(&m_fieldMetadata[i], &field[i], i);
+
m_rBind[i].buffer_type = field[i].type;
m_rBind[i].buffer_length = size;
m_rBind[i].length = &m_length[i];
@@ -209,6 +262,8 @@ m_metadataResult(result)
{
for (uint32 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
{
+ m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&m_fieldMetadata[fIndex]);
+
unsigned long buffer_length = m_rBind[fIndex].buffer_length;
unsigned long fetched_length = *m_rBind[fIndex].length;
if (!*m_rBind[fIndex].is_null)
@@ -226,7 +281,7 @@ m_metadataResult(result)
// when mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED
// we cannot blindly null-terminate the data either as it may be retrieved as binary blob and not specifically a string
// in this case using Field::GetCString will result in garbage
- // TODO: remove Field::GetCString and use boost::string_ref (currently proposed for TS as string_view, maybe in C++17)
+ // TODO: remove Field::GetCString and use std::string_view in C++17
if (fetched_length < buffer_length)
*((char*)buffer + fetched_length) = '\0';
break;
@@ -235,8 +290,7 @@ m_metadataResult(result)
}
m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
- buffer,
- MysqlTypeToFieldType(m_rBind[fIndex].buffer_type),
+ (char const*)buffer,
fetched_length);
// move buffer pointer to next part
@@ -246,13 +300,8 @@ m_metadataResult(result)
{
m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
nullptr,
- MysqlTypeToFieldType(m_rBind[fIndex].buffer_type),
*m_rBind[fIndex].length);
}
-
-#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS
- m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&field[fIndex], fIndex);
-#endif
}
m_rowPosition++;
}
@@ -295,7 +344,7 @@ bool ResultSet::NextRow()
}
for (uint32 i = 0; i < _fieldCount; i++)
- _currentRow[i].SetStructuredValue(row[i], MysqlTypeToFieldType(_fields[i].type), lengths[i]);
+ _currentRow[i].SetStructuredValue(row[i], lengths[i]);
return true;
}
diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h
index cb2780e84e4..18561de8e20 100644
--- a/src/server/database/Database/QueryResult.h
+++ b/src/server/database/Database/QueryResult.h
@@ -36,6 +36,7 @@ class TC_DATABASE_API ResultSet
Field const& operator[](std::size_t index) const;
protected:
+ std::vector<QueryResultFieldMetadata> _fieldMetadata;
uint64 _rowCount;
Field* _currentRow;
uint32 _fieldCount;
@@ -63,6 +64,7 @@ class TC_DATABASE_API PreparedResultSet
Field const& operator[](std::size_t index) const;
protected:
+ std::vector<QueryResultFieldMetadata> m_fieldMetadata;
std::vector<Field> m_rows;
uint64 m_rowCount;
uint64 m_rowPosition;