diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-05-14 16:30:05 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-05-14 16:30:05 +0200 |
commit | eadafb0347d606e5e3e660d21227aa15378bdb21 (patch) | |
tree | 84f89281f37c0b32bb792167f59f1de85720ec56 /src | |
parent | 8d0620eb05e80644219300fecb136beae52bf2e2 (diff) |
Core/DBLayer: Relaxed restrictions on which Field class member function can be used to access column value from "strict match" to "must not truncate"
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Field.cpp | 217 | ||||
-rw-r--r-- | src/server/database/Database/Field.h | 37 | ||||
-rw-r--r-- | src/server/database/Database/FieldValueConverter.cpp | 48 | ||||
-rw-r--r-- | src/server/database/Database/FieldValueConverter.h | 50 | ||||
-rw-r--r-- | src/server/database/Database/FieldValueConverters.h | 112 | ||||
-rw-r--r-- | src/server/database/Database/QueryResult.cpp | 76 |
6 files changed, 321 insertions, 219 deletions
diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp index cdcb32c6508..6957cec00ad 100644 --- a/src/server/database/Database/Field.cpp +++ b/src/server/database/Database/Field.cpp @@ -17,294 +17,153 @@ #include "Field.h" #include "Errors.h" +#include "FieldValueConverter.h" #include "Log.h" -#include "StringConvert.h" #include <cstring> -Field::Field() +Field::Field() : _value(nullptr), _length(0), _meta(nullptr) { - data.value = nullptr; - data.length = 0; - data.raw = false; - meta = nullptr; } Field::~Field() = default; uint8 Field::GetUInt8() const { - if (!data.value) + if (!_value) return 0; -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Int8)) - { - LogWrongType(__FUNCTION__); - return 0; - } -#endif - - if (data.raw) - return *reinterpret_cast<uint8 const*>(data.value); - return Trinity::StringTo<uint8>(data.value, 10).value_or(0); + return _meta->Converter->GetUInt8(_value, _length, _meta); } int8 Field::GetInt8() const { - if (!data.value) + if (!_value) return 0; -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Int8)) - { - LogWrongType(__FUNCTION__); - return 0; - } -#endif - - if (data.raw) - return *reinterpret_cast<int8 const*>(data.value); - return Trinity::StringTo<int8>(data.value, 10).value_or(0); + return _meta->Converter->GetInt8(_value, _length, _meta); } uint16 Field::GetUInt16() const { - if (!data.value) + if (!_value) return 0; -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Int16)) - { - LogWrongType(__FUNCTION__); - return 0; - } -#endif - - if (data.raw) - return *reinterpret_cast<uint16 const*>(data.value); - return Trinity::StringTo<uint16>(data.value, 10).value_or(0); + return _meta->Converter->GetUInt16(_value, _length, _meta); } int16 Field::GetInt16() const { - if (!data.value) - return 0; - -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Int16)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast<int16 const*>(data.value); - return Trinity::StringTo<int16>(data.value, 10).value_or(0); + return _meta->Converter->GetInt16(_value, _length, _meta); } uint32 Field::GetUInt32() const { - if (!data.value) + if (!_value) return 0; -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Int32)) - { - LogWrongType(__FUNCTION__); - return 0; - } -#endif - - if (data.raw) - return *reinterpret_cast<uint32 const*>(data.value); - return Trinity::StringTo<uint32>(data.value, 10).value_or(0); + return _meta->Converter->GetUInt32(_value, _length, _meta); } int32 Field::GetInt32() const { - if (!data.value) - return 0; - -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Int32)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast<int32 const*>(data.value); - return Trinity::StringTo<int32>(data.value, 10).value_or(0); + return _meta->Converter->GetInt32(_value, _length, _meta); } uint64 Field::GetUInt64() const { - if (!data.value) - return 0; - -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Int64)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast<uint64 const*>(data.value); - return Trinity::StringTo<uint64>(data.value, 10).value_or(0); + return _meta->Converter->GetUInt64(_value, _length, _meta); } int64 Field::GetInt64() const { - if (!data.value) - return 0; - -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Int64)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0; - } -#endif - if (data.raw) - return *reinterpret_cast<int64 const*>(data.value); - return Trinity::StringTo<int64>(data.value, 10).value_or(0); + return _meta->Converter->GetInt64(_value, _length, _meta); } float Field::GetFloat() const { - if (!data.value) + if (!_value) return 0.0f; -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Float)) - { - LogWrongType(__FUNCTION__); - return 0.0f; - } -#endif - - if (data.raw) - return *reinterpret_cast<float const*>(data.value); - return Trinity::StringTo<float>(data.value, 10).value_or(0); + return _meta->Converter->GetFloat(_value, _length, _meta); } double Field::GetDouble() const { - if (!data.value) - return 0.0; - -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (!IsType(DatabaseFieldTypes::Double) && !IsType(DatabaseFieldTypes::Decimal)) - { - LogWrongType(__FUNCTION__); + if (!_value) return 0.0; - } -#endif - if (data.raw && !IsType(DatabaseFieldTypes::Decimal)) - return *reinterpret_cast<double const*>(data.value); - return Trinity::StringTo<double>(data.value, 10).value_or(0); + return _meta->Converter->GetDouble(_value, _length, _meta); } char const* Field::GetCString() const { - if (!data.value) + if (!_value) return nullptr; -#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS - if (IsNumeric() && data.raw) - { - LogWrongType(__FUNCTION__); - return nullptr; - } -#endif - return static_cast<char const*>(data.value); + return _meta->Converter->GetCString(_value, _length, _meta); } std::string Field::GetString() const { - if (!data.value) + if (!_value) return ""; char const* string = GetCString(); if (!string) return ""; - return std::string(string, data.length); + return std::string(string, _length); } std::string_view Field::GetStringView() const { - if (!data.value) + if (!_value) return {}; char const* const string = GetCString(); if (!string) return {}; - return { string, data.length }; + return { string, _length }; } std::vector<uint8> Field::GetBinary() const { std::vector<uint8> result; - if (!data.value || !data.length) + if (!_value || !_length) return result; - result.resize(data.length); - memcpy(result.data(), data.value, data.length); + result.resize(_length); + memcpy(result.data(), _value, _length); return result; } void Field::GetBinarySizeChecked(uint8* buf, size_t length) const { - ASSERT(data.value && (data.length == length), "Expected %zu-byte binary blob, got %sdata (%u bytes) instead", length, data.value ? "" : "no ", data.length); - memcpy(buf, data.value, length); + ASSERT(_value && (_length == length), "Expected %zu-byte binary blob, got %sdata (%u bytes) instead", length, _value ? "" : "no ", _length); + memcpy(buf, _value, length); } -void Field::SetByteValue(char const* newValue, uint32 length) +void Field::SetValue(char const* newValue, uint32 length) { // This value stores raw bytes that have to be explicitly cast later - data.value = newValue; - data.length = length; - data.raw = true; -} - -void Field::SetStructuredValue(char const* newValue, uint32 length) -{ - // This value stores somewhat structured data that needs function style casting - data.value = newValue; - data.length = length; - data.raw = false; -} - -bool Field::IsType(DatabaseFieldTypes type) const -{ - return meta->Type == type; -} - -bool Field::IsNumeric() const -{ - 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); -} - -void Field::LogWrongType(char const* getter) const -{ - TC_LOG_WARN("sql.sql", "Warning: {} on {} field {}.{} ({}.{}) at index {}.", - getter, meta->TypeName, meta->TableAlias, meta->Alias, meta->TableName, meta->Name, meta->Index); + _value = newValue; + _length = length; } -void Field::SetMetadata(QueryResultFieldMetadata const* fieldMeta) +void Field::SetMetadata(QueryResultFieldMetadata const* meta) { - meta = fieldMeta; + _meta = meta; } diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h index 0229c852647..d0613a3a94f 100644 --- a/src/server/database/Database/Field.h +++ b/src/server/database/Database/Field.h @@ -15,22 +15,27 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _FIELD_H -#define _FIELD_H +#ifndef TRINITY_DATABASE_FIELD_H +#define TRINITY_DATABASE_FIELD_H #include "Define.h" -#include "DatabaseEnvFwd.h" #include <array> #include <string> #include <string_view> #include <vector> +class BaseDatabaseResultValueConverter; + enum class DatabaseFieldTypes : uint8 { Null, + UInt8, Int8, + UInt16, Int16, + UInt32, Int32, + UInt64, Int64, Float, Double, @@ -48,6 +53,7 @@ struct QueryResultFieldMetadata char const* TypeName = nullptr; uint32 Index = 0; DatabaseFieldTypes Type = DatabaseFieldTypes::Null; + BaseDatabaseResultValueConverter const* Converter = nullptr; }; /** @@ -118,28 +124,17 @@ class TC_DATABASE_API Field bool IsNull() const { - return data.value == nullptr; + return _value == nullptr; } - protected: - struct - { - char const* value; // Actual data in memory - uint32 length; // Length - bool raw; // Raw bytes? (Prepared statement or ad hoc) - } data; - - void SetByteValue(char const* newValue, uint32 length); - void SetStructuredValue(char const* newValue, uint32 length); - - bool IsType(DatabaseFieldTypes type) const; + private: + char const* _value; // Actual data in memory + uint32 _length; // Length - bool IsNumeric() const; + void SetValue(char const* newValue, uint32 length); - private: - QueryResultFieldMetadata const* meta; - void LogWrongType(char const* getter) const; - void SetMetadata(QueryResultFieldMetadata const* fieldMeta); + QueryResultFieldMetadata const* _meta; + void SetMetadata(QueryResultFieldMetadata const* meta); void GetBinarySizeChecked(uint8* buf, size_t size) const; }; diff --git a/src/server/database/Database/FieldValueConverter.cpp b/src/server/database/Database/FieldValueConverter.cpp new file mode 100644 index 00000000000..589d33c8850 --- /dev/null +++ b/src/server/database/Database/FieldValueConverter.cpp @@ -0,0 +1,48 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "FieldValueConverter.h" +#include "Errors.h" +#include "Field.h" + +BaseDatabaseResultValueConverter::BaseDatabaseResultValueConverter() = default; +BaseDatabaseResultValueConverter::~BaseDatabaseResultValueConverter() = default; + +void BaseDatabaseResultValueConverter::LogTruncation(char const* getter, QueryResultFieldMetadata const* meta) +{ + char const* expectedAccessor = ""; + switch (meta->Type) + { + case DatabaseFieldTypes::UInt8: expectedAccessor = "Field::GetUInt8"; break; + case DatabaseFieldTypes::Int8: expectedAccessor = "Field::GetInt8"; break; + case DatabaseFieldTypes::UInt16: expectedAccessor = "Field::GetUInt16"; break; + case DatabaseFieldTypes::Int16: expectedAccessor = "Field::GetInt16"; break; + case DatabaseFieldTypes::UInt32: expectedAccessor = "Field::GetUIn32"; break; + case DatabaseFieldTypes::Int32: expectedAccessor = "Field::GetInt32"; break; + case DatabaseFieldTypes::UInt64: expectedAccessor = "Field::GetUIn64"; break; + case DatabaseFieldTypes::Int64: expectedAccessor = "Field::GetInt64"; break; + case DatabaseFieldTypes::Float: expectedAccessor = "Field::GetFloat"; break; + case DatabaseFieldTypes::Double: expectedAccessor = "Field::GetDouble"; break; + case DatabaseFieldTypes::Decimal: expectedAccessor = "Field::GetDouble or Field::GetString"; break; + case DatabaseFieldTypes::Binary: expectedAccessor = "Field::GetString or Field::GetBinary"; break; + default: + break; + } + + ASSERT(false, "%s on %s field %s.%s (%s.%s) at index %u caused value to be truncated. Use %s instead.", + getter, meta->TypeName, meta->TableAlias, meta->Alias, meta->TableName, meta->Name, meta->Index, expectedAccessor); +} diff --git a/src/server/database/Database/FieldValueConverter.h b/src/server/database/Database/FieldValueConverter.h new file mode 100644 index 00000000000..15e65b0fa33 --- /dev/null +++ b/src/server/database/Database/FieldValueConverter.h @@ -0,0 +1,50 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_FIELD_VALUE_CONVERTER_H +#define TRINITY_FIELD_VALUE_CONVERTER_H + +#include "Define.h" + +struct QueryResultFieldMetadata; + +class BaseDatabaseResultValueConverter +{ +public: + BaseDatabaseResultValueConverter(); + BaseDatabaseResultValueConverter(BaseDatabaseResultValueConverter const&) = delete; + BaseDatabaseResultValueConverter(BaseDatabaseResultValueConverter&&) = delete; + BaseDatabaseResultValueConverter& operator=(BaseDatabaseResultValueConverter const&) = delete; + BaseDatabaseResultValueConverter& operator=(BaseDatabaseResultValueConverter&&) = delete; + virtual ~BaseDatabaseResultValueConverter(); + + virtual uint8 GetUInt8(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual int8 GetInt8(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual uint16 GetUInt16(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual int16 GetInt16(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual uint32 GetUInt32(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual int32 GetInt32(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual uint64 GetUInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual int64 GetInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual float GetFloat(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual double GetDouble(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + virtual char const* GetCString(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const = 0; + + static void LogTruncation(char const* getter, QueryResultFieldMetadata const* meta); +}; + +#endif // TRINITY_FIELD_VALUE_CONVERTER_H diff --git a/src/server/database/Database/FieldValueConverters.h b/src/server/database/Database/FieldValueConverters.h new file mode 100644 index 00000000000..e050d8052ca --- /dev/null +++ b/src/server/database/Database/FieldValueConverters.h @@ -0,0 +1,112 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_FIELD_VALUE_CONVERTERS_H +#define TRINITY_FIELD_VALUE_CONVERTERS_H + +#include "FieldValueConverter.h" +#include "StringConvert.h" + +// converts string value returned from query to type specified in column metadata +template<typename DatabaseType> +class FromStringToDatabaseTypeConverter : public BaseDatabaseResultValueConverter +{ +public: + static DatabaseType GetDatabaseValue(char const* data, uint32 size) + { + return Trinity::StringTo<DatabaseType>({ data, size }).template value_or<DatabaseType>(0); + } + + static char const* GetStringValue(char const* data) + { + return data; + } +}; + +// converts binary value returned from query to type specified in column metadata +template<typename DatabaseType> +class FromBinaryToDatabaseTypeConverter : public BaseDatabaseResultValueConverter +{ +public: + static DatabaseType GetDatabaseValue(char const* data, uint32 /*size*/) + { + return *reinterpret_cast<DatabaseType const*>(data); + } + + static char const* GetStringValue(char const* /*data*/) + { + return nullptr; + } +}; + +// converts column value from type specified in column metadata to type requested by Field::Get* function +template<typename DatabaseType, template<typename...> typename ToDatabaseTypeConverter> +class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter +{ +public: + template<typename T> + static T GetNumericValue(char const* data, uint32 size, QueryResultFieldMetadata const* meta, char const* func) + { + DatabaseType source = ToDatabaseTypeConverter<DatabaseType>::GetDatabaseValue(data, size); + T result = static_cast<T>(source); + if (static_cast<DatabaseType>(result) != source) + { + LogTruncation(func, meta); + return T(); + } + return result; + } + + uint8 GetUInt8(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<uint8>(data, size, meta, "Field::GetUInt8"); } + int8 GetInt8(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<int8>(data, size, meta, "Field::GetInt8"); } + uint16 GetUInt16(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<uint16>(data, size, meta, "Field::GetUInt16"); } + int16 GetInt16(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<int16>(data, size, meta, "Field::GetInt16"); } + uint32 GetUInt32(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<uint32>(data, size, meta, "Field::GetUInt32"); } + int32 GetInt32(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<int32>(data, size, meta, "Field::GetInt32"); } + uint64 GetUInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<uint64>(data, size, meta, "Field::GetUInt64"); } + int64 GetInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<int64>(data, size, meta, "Field::GetInt64"); } + float GetFloat(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<float>(data, size, meta, "Field::GetFloat"); } + double GetDouble(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue<double>(data, size, meta, "Field::GetDouble"); } + char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override + { + char const* result = ToDatabaseTypeConverter<DatabaseType>::GetStringValue(data); + if (data && !result) + LogTruncation("Field::GetCString", meta); + return result; + } +}; + +template<> +class PrimitiveResultValueConverter<char const*, std::void_t> : public BaseDatabaseResultValueConverter +{ +public: + uint8 GetUInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt8", meta); return 0; } + int8 GetInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt8", meta); return 0; } + uint16 GetUInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt16", meta); return 0; } + int16 GetInt16(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt16", meta); return 0; } + uint32 GetUInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt32", meta); return 0; } + int32 GetInt32(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt32", meta); return 0; } + uint64 GetUInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt64", meta); return 0; } + int64 GetInt64(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetInt64", meta); return 0; } + float GetFloat(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetFloat", meta); return 0.0f; } + double GetDouble(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDouble", meta); return 0.0; } + char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* /*meta*/) const override { return data; } +}; + +using StringResultValueConverter = PrimitiveResultValueConverter<char const*, std::void_t>; + +#endif // TRINITY_FIELD_VALUE_CONVERTERS_H diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp index 14994acf6aa..f68fdd643fc 100644 --- a/src/server/database/Database/QueryResult.cpp +++ b/src/server/database/Database/QueryResult.cpp @@ -18,6 +18,7 @@ #include "QueryResult.h" #include "Errors.h" #include "Field.h" +#include "FieldValueConverters.h" #include "Log.h" #include "MySQLHacks.h" #include "MySQLWorkaround.h" @@ -75,23 +76,23 @@ static uint32 SizeForType(MYSQL_FIELD* field) } } -DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type) +DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type, uint32 flags) { switch (type) { case MYSQL_TYPE_NULL: return DatabaseFieldTypes::Null; case MYSQL_TYPE_TINY: - return DatabaseFieldTypes::Int8; + return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt8 : DatabaseFieldTypes::Int8; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: - return DatabaseFieldTypes::Int16; + return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt16 : DatabaseFieldTypes::Int16; case MYSQL_TYPE_INT24: case MYSQL_TYPE_LONG: - return DatabaseFieldTypes::Int32; + return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt32 : DatabaseFieldTypes::Int32; case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_BIT: - return DatabaseFieldTypes::Int64; + return (flags & UNSIGNED_FLAG) ? DatabaseFieldTypes::UInt64 : DatabaseFieldTypes::Int64; case MYSQL_TYPE_FLOAT: return DatabaseFieldTypes::Float; case MYSQL_TYPE_DOUBLE: @@ -119,7 +120,7 @@ DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type) return DatabaseFieldTypes::Null; } -static char const* FieldTypeToString(enum_field_types type) +static char const* FieldTypeToString(enum_field_types type, uint32 flags) { switch (type) { @@ -133,19 +134,19 @@ static char const* FieldTypeToString(enum_field_types type) 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_INT24: return (flags & UNSIGNED_FLAG) ? "UNSIGNED INT24" : "INT24"; + case MYSQL_TYPE_LONG: return (flags & UNSIGNED_FLAG) ? "UNSIGNED LONG" : "LONG"; + case MYSQL_TYPE_LONGLONG: return (flags & UNSIGNED_FLAG) ? "UNSIGNED LONGLONG" : "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_SHORT: return (flags & UNSIGNED_FLAG) ? "UNSIGNED SHORT" : "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: return (flags & UNSIGNED_FLAG) ? "UNSIGNED TINY" : "TINY"; case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB"; case MYSQL_TYPE_VAR_STRING: return "VAR_STRING"; case MYSQL_TYPE_YEAR: return "YEAR"; @@ -153,15 +154,52 @@ static char const* FieldTypeToString(enum_field_types type) } } -void InitializeDatabaseFieldMetadata(QueryResultFieldMetadata* meta, MySQLField const* field, uint32 fieldIndex) +std::unique_ptr<BaseDatabaseResultValueConverter> FromStringValueConverters[14] = +{ + nullptr, + std::make_unique<PrimitiveResultValueConverter<uint8, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<int8, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<uint16, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<int16, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<uint32, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<int32, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<uint64, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<int64, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<float, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<double, FromStringToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<double, FromStringToDatabaseTypeConverter>>(), + nullptr, + std::make_unique<StringResultValueConverter>() +}; + +std::unique_ptr<BaseDatabaseResultValueConverter> BinaryValueConverters[14] = +{ + nullptr, + std::make_unique<PrimitiveResultValueConverter<uint8, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<int8, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<uint16, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<int16, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<uint32, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<int32, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<uint64, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<int64, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<float, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<double, FromBinaryToDatabaseTypeConverter>>(), + std::make_unique<PrimitiveResultValueConverter<double, FromStringToDatabaseTypeConverter>>(), // always sent as string + nullptr, + std::make_unique<StringResultValueConverter>() +}; + +void InitializeDatabaseFieldMetadata(QueryResultFieldMetadata* meta, MySQLField const* field, uint32 fieldIndex, bool binaryProtocol) { meta->TableName = field->org_table; meta->TableAlias = field->table; meta->Name = field->org_name; meta->Alias = field->name; - meta->TypeName = FieldTypeToString(field->type); + meta->TypeName = FieldTypeToString(field->type, field->flags); meta->Index = fieldIndex; - meta->Type = MysqlTypeToFieldType(field->type); + meta->Type = MysqlTypeToFieldType(field->type, field->flags); + meta->Converter = binaryProtocol ? BinaryValueConverters[AsUnderlyingType(meta->Type)].get() : FromStringValueConverters[AsUnderlyingType(meta->Type)].get(); } } @@ -175,7 +213,7 @@ _fields(fields) _currentRow = new Field[_fieldCount]; for (uint32 i = 0; i < _fieldCount; i++) { - InitializeDatabaseFieldMetadata(&_fieldMetadata[i], &_fields[i], i); + InitializeDatabaseFieldMetadata(&_fieldMetadata[i], &_fields[i], i, false); _currentRow[i].SetMetadata(&_fieldMetadata[i]); } } @@ -230,7 +268,7 @@ m_metadataResult(result) uint32 size = SizeForType(&field[i]); rowSize += size; - InitializeDatabaseFieldMetadata(&m_fieldMetadata[i], &field[i], i); + InitializeDatabaseFieldMetadata(&m_fieldMetadata[i], &field[i], i, true); m_rBind[i].buffer_type = field[i].type; m_rBind[i].buffer_length = size; @@ -290,7 +328,7 @@ m_metadataResult(result) break; } - m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue( + m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetValue( (char const*)buffer, fetched_length); @@ -299,7 +337,7 @@ m_metadataResult(result) } else { - m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue( + m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetValue( nullptr, *m_rBind[fIndex].length); } @@ -345,7 +383,7 @@ bool ResultSet::NextRow() } for (uint32 i = 0; i < _fieldCount; i++) - _currentRow[i].SetStructuredValue(row[i], lengths[i]); + _currentRow[i].SetValue(row[i], lengths[i]); return true; } |