diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/DatabaseEnvFwd.h | 1 | ||||
-rw-r--r-- | src/server/database/Database/Field.cpp | 129 | ||||
-rw-r--r-- | src/server/database/Database/Field.h | 49 | ||||
-rw-r--r-- | src/server/database/Database/QueryResult.cpp | 73 | ||||
-rw-r--r-- | src/server/database/Database/QueryResult.h | 2 |
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; |