summaryrefslogtreecommitdiff
path: root/src/server/database/Database/Field.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/database/Database/Field.cpp')
-rw-r--r--src/server/database/Database/Field.cpp434
1 files changed, 232 insertions, 202 deletions
diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp
index 1de88a6837..35f84c2a0a 100644
--- a/src/server/database/Database/Field.cpp
+++ b/src/server/database/Database/Field.cpp
@@ -19,6 +19,8 @@
#include "Errors.h"
#include "Log.h"
#include "MySQLHacks.h"
+#include "StringConvert.h"
+#include "Types.h"
Field::Field()
{
@@ -28,282 +30,310 @@ Field::Field()
meta = nullptr;
}
-Field::~Field() = default;
-
-uint8 Field::GetUInt8() const
+namespace
{
- if (!data.value)
- return 0;
-
-#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Int8))
+ template<typename T>
+ constexpr T GetDefaultValue()
{
- LogWrongType(__FUNCTION__);
- return 0;
+ if constexpr (std::is_same_v<T, bool>)
+ return false;
+ else if constexpr (std::is_integral_v<T>)
+ return 0;
+ else if constexpr (std::is_floating_point_v<T>)
+ return 1.0f;
+ else if constexpr (std::is_same_v<T, std::vector<uint8>> || std::is_same_v<std::string_view, T>)
+ return {};
+ else
+ return "";
}
-#endif
-
- if (data.raw)
- return *reinterpret_cast<uint8 const*>(data.value);
- return static_cast<uint8>(strtoul(data.value, nullptr, 10));
-}
-
-int8 Field::GetInt8() const
-{
- if (!data.value)
- return 0;
-#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Int8))
+ template<typename T>
+ inline bool IsCorrectFieldType(DatabaseFieldTypes type)
{
- LogWrongType(__FUNCTION__);
- return 0;
+ // Int8
+ if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, int8> || std::is_same_v<T, uint8>)
+ {
+ if (type == DatabaseFieldTypes::Int8)
+ return true;
+ }
+
+ // In16
+ if constexpr (std::is_same_v<T, uint16> || std::is_same_v<T, int16>)
+ {
+ if (type == DatabaseFieldTypes::Int16)
+ return true;
+ }
+
+ // Int32
+ if constexpr (std::is_same_v<T, uint32> || std::is_same_v<T, int32>)
+ {
+ if (type == DatabaseFieldTypes::Int32)
+ return true;
+ }
+
+ // Int64
+ if constexpr (std::is_same_v<T, uint64> || std::is_same_v<T, int64>)
+ {
+ if (type == DatabaseFieldTypes::Int64)
+ return true;
+ }
+
+ // float
+ if constexpr (std::is_same_v<T, float>)
+ {
+ if (type == DatabaseFieldTypes::Float)
+ return true;
+ }
+
+ // dobule
+ if constexpr (std::is_same_v<T, double>)
+ {
+ if (type == DatabaseFieldTypes::Double || type == DatabaseFieldTypes::Decimal)
+ return true;
+ }
+
+ // Binary
+ if constexpr (std::is_same_v<T, Binary>)
+ {
+ if (type == DatabaseFieldTypes::Binary)
+ return true;
+ }
+
+ return false;
}
-#endif
- if (data.raw)
- return *reinterpret_cast<int8 const*>(data.value);
- return static_cast<int8>(strtol(data.value, nullptr, 10));
-}
+ inline Optional<std::string_view> GetCleanAliasName(std::string_view alias)
+ {
+ if (alias.empty())
+ return {};
-uint16 Field::GetUInt16() const
-{
- if (!data.value)
- return 0;
+ auto pos = alias.find_first_of('(');
+ if (pos == std::string_view::npos)
+ return {};
-#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Int16))
- {
- LogWrongType(__FUNCTION__);
- return 0;
+ alias.remove_suffix(alias.length() - pos);
+
+ return { alias };
}
-#endif
- if (data.raw)
- return *reinterpret_cast<uint16 const*>(data.value);
- return static_cast<uint16>(strtoul(data.value, nullptr, 10));
-}
+ template<typename T>
+ inline bool IsCorrectAlias(DatabaseFieldTypes type, std::string_view alias)
+ {
+ if constexpr (std::is_same_v<T, double>)
+ {
+ if ((StringEqualI(alias, "sum") || StringEqualI(alias, "avg")) && type == DatabaseFieldTypes::Decimal)
+ return true;
-int16 Field::GetInt16() const
-{
- if (!data.value)
- return 0;
+ return false;
+ }
-#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Int16))
- {
- LogWrongType(__FUNCTION__);
- return 0;
- }
-#endif
+ if constexpr (std::is_same_v<T, uint64>)
+ {
+ if (StringEqualI(alias, "count") && type == DatabaseFieldTypes::Int64)
+ return true;
- if (data.raw)
- return *reinterpret_cast<int16 const*>(data.value);
- return static_cast<int16>(strtol(data.value, nullptr, 10));
-}
+ return false;
+ }
-uint32 Field::GetUInt32() const
-{
- if (!data.value)
- return 0;
+ if ((StringEqualI(alias, "min") || StringEqualI(alias, "max")) && IsCorrectFieldType<T>(type))
+ {
+ return true;
+ }
-#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Int32))
- {
- LogWrongType(__FUNCTION__);
- return 0;
+ return false;
}
-#endif
+}
- if (data.raw)
- return *reinterpret_cast<uint32 const*>(data.value);
- return static_cast<uint32>(strtoul(data.value, nullptr, 10));
+void Field::GetBinarySizeChecked(uint8* buf, size_t length) const
+{
+ ASSERT(data.value && (data.length == length), "Expected {}-byte binary blob, got {}data ({} bytes) instead", length, data.value ? "" : "no ", data.length);
+ memcpy(buf, data.value, length);
}
-int32 Field::GetInt32() const
+void Field::SetByteValue(char const* newValue, uint32 length)
{
- if (!data.value)
- return 0;
+ // This value stores raw bytes that have to be explicitly cast later
+ data.value = newValue;
+ data.length = length;
+ data.raw = true;
+}
-#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Int32))
- {
- LogWrongType(__FUNCTION__);
- return 0;
- }
-#endif
+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;
+}
- if (data.raw)
- return *reinterpret_cast<int32 const*>(data.value);
- return static_cast<int32>(strtol(data.value, nullptr, 10));
+bool Field::IsType(DatabaseFieldTypes type) const
+{
+ return meta->Type == type;
}
-uint64 Field::GetUInt64() const
+bool Field::IsNumeric() const
{
- if (!data.value)
- return 0;
+ 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 ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Int64))
- {
- LogWrongType(__FUNCTION__);
- return 0;
- }
-#endif
+void Field::LogWrongType(std::string_view getter, std::string_view typeName) const
+{
+ LOG_WARN("sql.sql", "Warning: {}<{}> on {} field {}.{} ({}.{}) at index {}.",
+ getter, typeName, meta->TypeName, meta->TableAlias, meta->Alias, meta->TableName, meta->Name, meta->Index);
+}
- if (data.raw)
- return *reinterpret_cast<uint64 const*>(data.value);
- return static_cast<uint64>(strtoull(data.value, nullptr, 10));
+void Field::SetMetadata(QueryResultFieldMetadata const* fieldMeta)
+{
+ meta = fieldMeta;
}
-int64 Field::GetInt64() const
+template<typename T>
+T Field::GetData() const
{
+ static_assert(std::is_arithmetic_v<T>, "Unsurropt type for Field::GetData()");
+
if (!data.value)
- return 0;
+ return GetDefaultValue<T>();
#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Int64))
+ if (!IsCorrectFieldType<T>(meta->Type))
{
- LogWrongType(__FUNCTION__);
- return 0;
+ LogWrongType(__FUNCTION__, typeid(T).name());
+ //return GetDefaultValue<T>();
}
#endif
- if (data.raw)
- return *reinterpret_cast<int64 const*>(data.value);
- return static_cast<int64>(strtoll(data.value, nullptr, 10));
-}
+ Optional<T> result = {};
-float Field::GetFloat() const
-{
- if (!data.value)
- return 0.0f;
+ if (data.raw)
+ result = *reinterpret_cast<T const*>(data.value);
+ else
+ result = Acore::StringTo<T>(data.value);
-#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Float))
+ // Correct double fields... this undefined behavior :/
+ if constexpr (std::is_same_v<T, double>)
{
- LogWrongType(__FUNCTION__);
- return 0.0f;
+ if (data.raw && !IsType(DatabaseFieldTypes::Decimal))
+ result = *reinterpret_cast<double const*>(data.value);
+ else
+ result = Acore::StringTo<float>(data.value);
}
-#endif
- if (data.raw)
- return *reinterpret_cast<float const*>(data.value);
- return static_cast<float>(atof(data.value));
-}
+ // Check -1 for *_dbc db tables
+ if constexpr (std::is_same_v<T, uint32>)
+ {
+ std::string_view tableName{ meta->TableName };
+
+ if (!tableName.empty() && tableName.size() > 4)
+ {
+ auto signedResult = Acore::StringTo<int32>(data.value);
+
+ if (signedResult && !result && tableName.substr(tableName.length() - 4) == "_dbc")
+ {
+ LOG_DEBUG("sql.sql", "> Found incorrect value '{}' for type '{}' in _dbc table.", data.value, typeid(T).name());
+ LOG_DEBUG("sql.sql", "> Table name '{}'. Field name '{}'. Try return int32 value", meta->TableName, meta->Name);
+ return GetData<int32>();
+ }
+ }
+ }
-double Field::GetDouble() const
-{
- if (!data.value)
- return 0.0f;
+ if (auto alias = GetCleanAliasName(meta->Alias))
+ {
+ if ((StringEqualI(*alias, "min") || StringEqualI(*alias, "max")) && !IsCorrectAlias<T>(meta->Type, *alias))
+ {
+ LogWrongType(__FUNCTION__, typeid(T).name());
+ }
+
+ if ((StringEqualI(*alias, "sum") || StringEqualI(*alias, "avg")) && !IsCorrectAlias<T>(meta->Type, *alias))
+ {
+ LogWrongType(__FUNCTION__, typeid(T).name());
+ LOG_WARN("sql.sql", "> Please use GetData<double>()");
+ return GetData<double>();
+ }
+
+ if (StringEqualI(*alias, "count") && !IsCorrectAlias<T>(meta->Type, *alias))
+ {
+ LogWrongType(__FUNCTION__, typeid(T).name());
+ LOG_WARN("sql.sql", "> Please use GetData<uint64>()");
+ return GetData<uint64>();
+ }
+ }
-#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
- if (!IsType(DatabaseFieldTypes::Double) && !IsType(DatabaseFieldTypes::Decimal))
+ if (!result)
{
- LogWrongType(__FUNCTION__);
- return 0.0f;
+ LOG_FATAL("sql.sql", "> Incorrect value '{}' for type '{}'. Value is raw ? '{}'", data.value, typeid(T).name(), data.raw);
+ LOG_FATAL("sql.sql", "> Table name '{}'. Field name '{}'", meta->TableName, meta->Name);
+ //ABORT();
+ return GetDefaultValue<T>();
}
-#endif
- if (data.raw && !IsType(DatabaseFieldTypes::Decimal))
- return *reinterpret_cast<double const*>(data.value);
- return static_cast<double>(atof(data.value));
+ return *result;
}
-char const* Field::GetCString() const
+template bool Field::GetData() const;
+template uint8 Field::GetData() const;
+template uint16 Field::GetData() const;
+template uint32 Field::GetData() const;
+template uint64 Field::GetData() const;
+template int8 Field::GetData() const;
+template int16 Field::GetData() const;
+template int32 Field::GetData() const;
+template int64 Field::GetData() const;
+template float Field::GetData() const;
+template double Field::GetData() const;
+
+std::string Field::GetDataString() const
{
if (!data.value)
- return nullptr;
+ return "";
#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
if (IsNumeric() && data.raw)
{
- LogWrongType(__FUNCTION__);
- return nullptr;
+ LogWrongType(__FUNCTION__, "std::string");
+ return "";
}
#endif
- return static_cast<char const*>(data.value);
-}
-
-std::string Field::GetString() const
-{
- if (!data.value)
- return "";
- char const* string = GetCString();
- if (!string)
- return "";
-
- return std::string(string, data.length);
+ return { data.value, data.length };
}
-std::string_view Field::GetStringView() const
+std::string_view Field::GetDataStringView() const
{
if (!data.value)
return {};
- char const* const string = GetCString();
- if (!string)
+#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
+ if (IsNumeric() && data.raw)
+ {
+ LogWrongType(__FUNCTION__, "std::string_view");
return {};
+ }
+#endif
- return { string, data.length };
+ return { data.value, data.length };
}
-std::vector<uint8> Field::GetBinary() const
+Binary Field::GetDataBinary() const
{
- std::vector<uint8> result;
+ Binary result = {};
if (!data.value || !data.length)
return result;
+#ifdef ACORE_STRICT_DATABASE_TYPE_CHECKS
+ if (!IsCorrectFieldType<Binary>(meta->Type))
+ {
+ LogWrongType(__FUNCTION__, "Binary");
+ return {};
+ }
+#endif
+
result.resize(data.length);
memcpy(result.data(), data.value, data.length);
return result;
}
-
-void Field::GetBinarySizeChecked(uint8* buf, size_t length) const
-{
- ASSERT(data.value && (data.length == length), "Expected {}-byte binary blob, got {}data ({} bytes) instead", length, data.value ? "" : "no ", data.length);
- memcpy(buf, data.value, 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.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
-{
- LOG_WARN("sql.sql", "Warning: {} on {} field {}.{} ({}.{}) at index {}.",
- getter, meta->TypeName, meta->TableAlias, meta->Alias, meta->TableName, meta->Name, meta->Index);
-}
-
-void Field::SetMetadata(QueryResultFieldMetadata const* fieldMeta)
-{
- meta = fieldMeta;
-}