From 404bb5b3c21b445ae21fbbfcfd7f51d255e07c39 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 10 Apr 2024 13:59:19 +0200 Subject: Core/DBLayer: Support retrieving DATE/DATETIME/TIMESTAMP column values directly without casting in sql --- src/server/database/Database/Field.cpp | 9 +- src/server/database/Database/Field.h | 3 + .../database/Database/FieldValueConverter.cpp | 2 + src/server/database/Database/FieldValueConverter.h | 2 + .../database/Database/FieldValueConverters.h | 29 ++- .../database/Database/MySQLPreparedStatement.cpp | 28 +++ .../database/Database/MySQLPreparedStatement.h | 2 + src/server/database/Database/PreparedStatement.cpp | 42 +++-- src/server/database/Database/PreparedStatement.h | 34 ++-- src/server/database/Database/QueryResult.cpp | 200 ++++++++++++++++++++- 10 files changed, 310 insertions(+), 41 deletions(-) diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp index 6957cec00ad..664090839c0 100644 --- a/src/server/database/Database/Field.cpp +++ b/src/server/database/Database/Field.cpp @@ -18,7 +18,6 @@ #include "Field.h" #include "Errors.h" #include "FieldValueConverter.h" -#include "Log.h" #include Field::Field() : _value(nullptr), _length(0), _meta(nullptr) @@ -107,6 +106,14 @@ double Field::GetDouble() const return _meta->Converter->GetDouble(_value, _length, _meta); } +SystemTimePoint Field::GetDate() const +{ + if (!_value) + return SystemTimePoint::min(); + + return _meta->Converter->GetDate(_value, _length, _meta); +} + char const* Field::GetCString() const { if (!_value) diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h index d0613a3a94f..1d28d8cf713 100644 --- a/src/server/database/Database/Field.h +++ b/src/server/database/Database/Field.h @@ -19,6 +19,7 @@ #define TRINITY_DATABASE_FIELD_H #include "Define.h" +#include "Duration.h" #include #include #include @@ -41,6 +42,7 @@ enum class DatabaseFieldTypes : uint8 Double, Decimal, Date, + Time, Binary }; @@ -110,6 +112,7 @@ class TC_DATABASE_API Field int64 GetInt64() const; float GetFloat() const; double GetDouble() const; + SystemTimePoint GetDate() const; char const* GetCString() const; std::string GetString() const; std::string_view GetStringView() const; diff --git a/src/server/database/Database/FieldValueConverter.cpp b/src/server/database/Database/FieldValueConverter.cpp index 589d33c8850..6e36c1c8703 100644 --- a/src/server/database/Database/FieldValueConverter.cpp +++ b/src/server/database/Database/FieldValueConverter.cpp @@ -38,6 +38,8 @@ void BaseDatabaseResultValueConverter::LogTruncation(char const* getter, QueryRe 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::Date: expectedAccessor = "Field::GetDate"; break; + case DatabaseFieldTypes::Time: expectedAccessor = "Field::GetTime"; break; case DatabaseFieldTypes::Binary: expectedAccessor = "Field::GetString or Field::GetBinary"; break; default: break; diff --git a/src/server/database/Database/FieldValueConverter.h b/src/server/database/Database/FieldValueConverter.h index 15e65b0fa33..8023ff48e2b 100644 --- a/src/server/database/Database/FieldValueConverter.h +++ b/src/server/database/Database/FieldValueConverter.h @@ -19,6 +19,7 @@ #define TRINITY_FIELD_VALUE_CONVERTER_H #include "Define.h" +#include "Duration.h" struct QueryResultFieldMetadata; @@ -42,6 +43,7 @@ public: 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 SystemTimePoint GetDate(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); diff --git a/src/server/database/Database/FieldValueConverters.h b/src/server/database/Database/FieldValueConverters.h index e050d8052ca..fc6dec8682d 100644 --- a/src/server/database/Database/FieldValueConverters.h +++ b/src/server/database/Database/FieldValueConverters.h @@ -23,7 +23,7 @@ // converts string value returned from query to type specified in column metadata template -class FromStringToDatabaseTypeConverter : public BaseDatabaseResultValueConverter +class FromStringToDatabaseTypeConverter { public: static DatabaseType GetDatabaseValue(char const* data, uint32 size) @@ -39,7 +39,7 @@ public: // converts binary value returned from query to type specified in column metadata template -class FromBinaryToDatabaseTypeConverter : public BaseDatabaseResultValueConverter +class FromBinaryToDatabaseTypeConverter { public: static DatabaseType GetDatabaseValue(char const* data, uint32 /*size*/) @@ -54,7 +54,7 @@ public: }; // converts column value from type specified in column metadata to type requested by Field::Get* function -template typename ToDatabaseTypeConverter> +template typename ToDatabaseTypeConverter> class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter { public: @@ -81,6 +81,7 @@ public: int64 GetInt64(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetInt64"); } float GetFloat(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetFloat"); } double GetDouble(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override { return GetNumericValue(data, size, meta, "Field::GetDouble"); } + SystemTimePoint GetDate(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDate", meta); return SystemTimePoint::min(); } char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { char const* result = ToDatabaseTypeConverter::GetStringValue(data); @@ -91,7 +92,7 @@ public: }; template<> -class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter +class PrimitiveResultValueConverter : public BaseDatabaseResultValueConverter { public: uint8 GetUInt8(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetUInt8", meta); return 0; } @@ -104,9 +105,27 @@ public: 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; } + SystemTimePoint GetDate(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDate", meta); return SystemTimePoint::min(); } char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* /*meta*/) const override { return data; } }; -using StringResultValueConverter = PrimitiveResultValueConverter; +using StringResultValueConverter = PrimitiveResultValueConverter; + +class NotImplementedResultValueConverter : 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; } + SystemTimePoint GetDate(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetDate", meta); return SystemTimePoint::min(); } + char const* GetCString(char const* /*data*/, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override { LogTruncation("Field::GetCString", meta); return nullptr; } +}; #endif // TRINITY_FIELD_VALUE_CONVERTERS_H diff --git a/src/server/database/Database/MySQLPreparedStatement.cpp b/src/server/database/Database/MySQLPreparedStatement.cpp index dc25264e85c..0fc4de403f8 100644 --- a/src/server/database/Database/MySQLPreparedStatement.cpp +++ b/src/server/database/Database/MySQLPreparedStatement.cpp @@ -20,6 +20,7 @@ #include "Log.h" #include "MySQLHacks.h" #include "PreparedStatement.h" +#include #include template @@ -145,6 +146,33 @@ void MySQLPreparedStatement::SetParameter(uint8 index, T value) memcpy(param->buffer, &value, len); } +void MySQLPreparedStatement::SetParameter(uint8 index, SystemTimePoint value) +{ + AssertValidIndex(index); + m_paramsSet[index] = true; + MYSQL_BIND* param = &m_bind[index]; + uint32 len = sizeof(MYSQL_TIME); + param->buffer_type = MYSQL_TYPE_DATETIME; + delete[] static_cast(param->buffer); + param->buffer = new char[len]; + param->buffer_length = len; + param->is_null_value = 0; + delete param->length; + param->length = new unsigned long(len); + + std::chrono::year_month_day ymd(time_point_cast(value)); + std::chrono::hh_mm_ss hms(duration_cast(value - std::chrono::sys_days(ymd))); + + MYSQL_TIME* time = reinterpret_cast(static_cast(param->buffer)); + time->year = static_cast(ymd.year()); + time->month = static_cast(ymd.month()); + time->day = static_cast(ymd.day()); + time->hour = hms.hours().count(); + time->minute = hms.minutes().count(); + time->second = hms.seconds().count(); + time->second_part = hms.subseconds().count(); +} + void MySQLPreparedStatement::SetParameter(uint8 index, std::string const& value) { AssertValidIndex(index); diff --git a/src/server/database/Database/MySQLPreparedStatement.h b/src/server/database/Database/MySQLPreparedStatement.h index d348130097f..e30152f7f04 100644 --- a/src/server/database/Database/MySQLPreparedStatement.h +++ b/src/server/database/Database/MySQLPreparedStatement.h @@ -20,6 +20,7 @@ #include "DatabaseEnvFwd.h" #include "Define.h" +#include "Duration.h" #include #include @@ -47,6 +48,7 @@ class TC_DATABASE_API MySQLPreparedStatement void SetParameter(uint8 index, bool value); template void SetParameter(uint8 index, T value); + void SetParameter(uint8 index, SystemTimePoint value); void SetParameter(uint8 index, std::string const& value); void SetParameter(uint8 index, std::vector const& value); diff --git a/src/server/database/Database/PreparedStatement.cpp b/src/server/database/Database/PreparedStatement.cpp index fe20f1c0a7e..684d3ee4eb6 100644 --- a/src/server/database/Database/PreparedStatement.cpp +++ b/src/server/database/Database/PreparedStatement.cpp @@ -20,6 +20,7 @@ #include "MySQLConnection.h" #include "QueryResult.h" #include "StringFormat.h" +#include PreparedStatementBase::PreparedStatementBase(uint32 index, uint8 capacity) : m_index(index), statement_data(capacity) { } @@ -27,91 +28,97 @@ PreparedStatementBase::PreparedStatementBase(uint32 index, uint8 capacity) : PreparedStatementBase::~PreparedStatementBase() { } //- Bind to buffer -void PreparedStatementBase::setBool(const uint8 index, const bool value) +void PreparedStatementBase::setBool(uint8 index, bool value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setUInt8(const uint8 index, const uint8 value) +void PreparedStatementBase::setUInt8(uint8 index, uint8 value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setUInt16(const uint8 index, const uint16 value) +void PreparedStatementBase::setUInt16(uint8 index, uint16 value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setUInt32(const uint8 index, const uint32 value) +void PreparedStatementBase::setUInt32(uint8 index, uint32 value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setUInt64(const uint8 index, const uint64 value) +void PreparedStatementBase::setUInt64(uint8 index, uint64 value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setInt8(const uint8 index, const int8 value) +void PreparedStatementBase::setInt8(uint8 index, int8 value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setInt16(const uint8 index, const int16 value) +void PreparedStatementBase::setInt16(uint8 index, int16 value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setInt32(const uint8 index, const int32 value) +void PreparedStatementBase::setInt32(uint8 index, int32 value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setInt64(const uint8 index, const int64 value) +void PreparedStatementBase::setInt64(uint8 index, int64 value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setFloat(const uint8 index, const float value) +void PreparedStatementBase::setFloat(uint8 index, float value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setDouble(const uint8 index, const double value) +void PreparedStatementBase::setDouble(uint8 index, double value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setString(const uint8 index, const std::string& value) +void PreparedStatementBase::setDate(uint8 index, SystemTimePoint value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setStringView(const uint8 index, const std::string_view value) +void PreparedStatementBase::setString(uint8 index, std::string const& value) +{ + ASSERT(index < statement_data.size()); + statement_data[index].data = value; +} + +void PreparedStatementBase::setStringView(uint8 index, std::string_view value) { ASSERT(index < statement_data.size()); statement_data[index].data.emplace(value); } -void PreparedStatementBase::setBinary(const uint8 index, const std::vector& value) +void PreparedStatementBase::setBinary(uint8 index, std::vector const& value) { ASSERT(index < statement_data.size()); statement_data[index].data = value; } -void PreparedStatementBase::setNull(const uint8 index) +void PreparedStatementBase::setNull(uint8 index) { ASSERT(index < statement_data.size()); statement_data[index].data = nullptr; @@ -176,6 +183,11 @@ std::string PreparedStatementData::ToString(std::vector const& /*value*/) return "BINARY"; } +std::string PreparedStatementData::ToString(SystemTimePoint value) +{ + return Trinity::StringFormat("{:%F %T}", value); +} + std::string PreparedStatementData::ToString(std::nullptr_t) { return "NULL"; diff --git a/src/server/database/Database/PreparedStatement.h b/src/server/database/Database/PreparedStatement.h index 9fde41e6f2a..88151ef193b 100644 --- a/src/server/database/Database/PreparedStatement.h +++ b/src/server/database/Database/PreparedStatement.h @@ -20,6 +20,7 @@ #include "DatabaseEnvFwd.h" #include "Define.h" +#include "Duration.h" #include #include #include @@ -43,6 +44,7 @@ struct PreparedStatementData double, std::string, std::vector, + SystemTimePoint, std::nullptr_t > data; @@ -54,6 +56,7 @@ struct PreparedStatementData static std::string ToString(int8 value); static std::string ToString(std::string const& value); static std::string ToString(std::vector const& value); + static std::string ToString(SystemTimePoint value); static std::string ToString(std::nullptr_t); }; @@ -66,21 +69,22 @@ class TC_DATABASE_API PreparedStatementBase explicit PreparedStatementBase(uint32 index, uint8 capacity); virtual ~PreparedStatementBase(); - void setNull(const uint8 index); - void setBool(const uint8 index, const bool value); - void setUInt8(const uint8 index, const uint8 value); - void setUInt16(const uint8 index, const uint16 value); - void setUInt32(const uint8 index, const uint32 value); - void setUInt64(const uint8 index, const uint64 value); - void setInt8(const uint8 index, const int8 value); - void setInt16(const uint8 index, const int16 value); - void setInt32(const uint8 index, const int32 value); - void setInt64(const uint8 index, const int64 value); - void setFloat(const uint8 index, const float value); - void setDouble(const uint8 index, const double value); - void setString(const uint8 index, const std::string& value); - void setStringView(const uint8 index, const std::string_view value); - void setBinary(const uint8 index, const std::vector& value); + void setNull(uint8 index); + void setBool(uint8 index, bool value); + void setUInt8(uint8 index, uint8 value); + void setUInt16(uint8 index, uint16 value); + void setUInt32(uint8 index, uint32 value); + void setUInt64(uint8 index, uint64 value); + void setInt8(uint8 index, int8 value); + void setInt16(uint8 index, int16 value); + void setInt32(uint8 index, int32 value); + void setInt64(uint8 index, int64 value); + void setFloat(uint8 index, float value); + void setDouble(uint8 index, double value); + void setDate(uint8 index, SystemTimePoint value); + void setString(uint8 index, std::string const& value); + void setStringView(uint8 index, std::string_view value); + void setBinary(uint8 index, std::vector const& value); template void setBinary(const uint8 index, std::array const& value) { diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp index f68fdd643fc..48a8e5ac608 100644 --- a/src/server/database/Database/QueryResult.cpp +++ b/src/server/database/Database/QueryResult.cpp @@ -22,6 +22,7 @@ #include "Log.h" #include "MySQLHacks.h" #include "MySQLWorkaround.h" +#include #include namespace @@ -102,9 +103,10 @@ DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type, uint32 flags) return DatabaseFieldTypes::Decimal; case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATETIME: return DatabaseFieldTypes::Date; + case MYSQL_TYPE_TIME: + return DatabaseFieldTypes::Time; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: @@ -154,7 +156,193 @@ static char const* FieldTypeToString(enum_field_types type, uint32 flags) } } -std::unique_ptr FromStringValueConverters[14] = +template +class FromStringToMYSQL_TIME +{ +public: + static MYSQL_TIME GetDatabaseValue(char const* data, uint32 size) + { + MYSQL_TIME result = {}; + if (!data || !size) + { + result.time_type = MYSQL_TIMESTAMP_NONE; + return result; + } + + std::string_view in(data, size); + + size_t firstSeparatorIndex = in.find_first_of(":-"); + if (firstSeparatorIndex == std::string_view::npos) + { + result.time_type = MYSQL_TIMESTAMP_NONE; + return result; + } + + char firstSeparator = in[firstSeparatorIndex]; + + auto parseNextComponent = [&](uint32& value, char requiredSeparator = '\0') -> bool + { + std::from_chars_result parseResult = std::from_chars(in.data(), in.data() + in.size(), value); + if (parseResult.ec != std::errc()) + return false; + + in.remove_prefix(parseResult.ptr - in.data()); + if (requiredSeparator) + { + if (in.empty() || in[0] != requiredSeparator) + return false; + + in.remove_prefix(1); + } + + return true; + }; + + uint32 yearOrHours = 0; + uint32 monthOrMinutes = 0; + uint32 dayOrSeconds = 0; + if (!parseNextComponent(yearOrHours, firstSeparator) + || !parseNextComponent(monthOrMinutes, firstSeparator) + || !parseNextComponent(dayOrSeconds)) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + if (firstSeparator == ':') + { + if (!in.empty()) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + // time + result.hour = yearOrHours; + result.minute = monthOrMinutes; + result.second = dayOrSeconds; + result.time_type = MYSQL_TIMESTAMP_TIME; + } + else + { + if (in.empty()) + { + // date + result.year = yearOrHours; + result.month = monthOrMinutes; + result.day = dayOrSeconds; + result.time_type = MYSQL_TIMESTAMP_DATE; + return result; + } + + // date+time + if (in[0] != ' ') + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + in.remove_prefix(1); + + uint32 hours = 0; + uint32 minutes = 0; + uint32 seconds = 0; + if (!parseNextComponent(hours, ':') + || !parseNextComponent(minutes, ':') + || !parseNextComponent(seconds)) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + uint32 microseconds = 0; + if (!in.empty()) + { + if (in[0] != '.') + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + in.remove_prefix(1); + if (!parseNextComponent(microseconds)) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + + if (!in.empty()) + { + result.time_type = MYSQL_TIMESTAMP_ERROR; + return result; + } + } + + result.year = yearOrHours; + result.month = monthOrMinutes; + result.day = dayOrSeconds; + result.hour = hours; + result.minute = minutes; + result.second = seconds; + result.second_part = microseconds; + result.time_type = MYSQL_TIMESTAMP_DATETIME; + } + + return result; + } + + static char const* GetStringValue(char const* data) + { + return data; + } +}; + +template typename ToDatabaseTypeConverter> +class DateResultValueConverter : public BaseDatabaseResultValueConverter +{ + 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; } + + SystemTimePoint GetDate(char const* data, uint32 size, QueryResultFieldMetadata const* meta) const override + { + using namespace std::chrono; + MYSQL_TIME source = ToDatabaseTypeConverter::GetDatabaseValue(data, size); + switch (source.time_type) + { + case MYSQL_TIMESTAMP_DATE: + return sys_days(year(source.year) / month(source.month) / day(source.day)); + case MYSQL_TIMESTAMP_DATETIME: + return sys_days(year(source.year) / month(source.month) / day(source.day)) + + hours(source.hour) + + minutes(source.minute) + + seconds(source.second) + + microseconds(source.second_part); + default: + break; + } + + LogTruncation("Field::GetDate", meta); + return SystemTimePoint(); + } + + char const* GetCString(char const* data, uint32 /*size*/, QueryResultFieldMetadata const* meta) const override + { + char const* result = ToDatabaseTypeConverter::GetStringValue(data); + if (data && !result) + LogTruncation("Field::GetCString", meta); + return result; + } +}; + +std::unique_ptr const FromStringValueConverters[15] = { nullptr, std::make_unique>(), @@ -168,11 +356,12 @@ std::unique_ptr FromStringValueConverters[14] std::make_unique>(), std::make_unique>(), std::make_unique>(), - nullptr, + std::make_unique>(), + std::make_unique(), // DatabaseFieldTypes::Time std::make_unique() }; -std::unique_ptr BinaryValueConverters[14] = +std::unique_ptr const BinaryValueConverters[15] = { nullptr, std::make_unique>(), @@ -186,7 +375,8 @@ std::unique_ptr BinaryValueConverters[14] = std::make_unique>(), std::make_unique>(), std::make_unique>(), // always sent as string - nullptr, + std::make_unique>(), + std::make_unique(), // DatabaseFieldTypes::Time std::make_unique() }; -- cgit v1.2.3