From e14fe608355f78ef87597f5225a510a22a1b44c5 Mon Sep 17 00:00:00 2001 From: Lukas Zanner Date: Fri, 22 Mar 2024 10:06:22 +0100 Subject: [PATCH] Allow retrieval of movable types from row --- include/soci/row.h | 6 ++-- include/soci/type-holder.h | 74 +++++++++++++++++++++++++++++++++++++- src/core/row.cpp | 3 +- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/include/soci/row.h b/include/soci/row.h index 8aaeb4a71..07f7c3432 100644 --- a/include/soci/row.h +++ b/include/soci/row.h @@ -78,7 +78,8 @@ class SOCI_DECL row typedef typename type_conversion::base_type base_type; static_assert(details::can_use_from_base>(), "Can't use row::get() with this type (not convertible/copy-assignable from base_type) - did you mean to use move_as?"); - base_type const& baseVal = holders_.at(pos)->get(); + base_type const& baseVal = + holders_.at(pos)->get(details::value_cast_tag{}); T ret; type_conversion::from_base(baseVal, *indicators_.at(pos), ret); @@ -91,7 +92,8 @@ class SOCI_DECL row typedef typename type_conversion::base_type base_type; static_assert(details::can_use_move_from_base(), "row::move_as() can only be called with types that can be instantiated from a base type rvalue reference"); - base_type & baseVal = holders_.at(pos)->get(); + base_type & baseVal = + holders_.at(pos)->get(details::value_reference_tag{}); T ret; type_conversion::move_from_base(baseVal, *indicators_.at(pos), ret); diff --git a/include/soci/type-holder.h b/include/soci/type-holder.h index 121e11227..73badaa14 100644 --- a/include/soci/type-holder.h +++ b/include/soci/type-holder.h @@ -8,6 +8,7 @@ #ifndef SOCI_TYPE_HOLDER_H_INCLUDED #define SOCI_TYPE_HOLDER_H_INCLUDED +#include "soci/blob.h" #include "soci/error.h" #include "soci/soci-backend.h" #include "soci/soci-types.h" @@ -50,6 +51,26 @@ T* checked_ptr_cast(U* ptr) return static_cast(ptr); } +template +struct soci_return_same +{ + static inline T& value(U&) + { + throw std::bad_cast(); + } +}; + +template +struct soci_return_same< + T, U, + typename std::enable_if::value>::type> +{ + static inline T& value(U& val) + { + return val; + } +}; + // Type safe conversion that throws if the types are mismatched template struct soci_cast @@ -120,6 +141,7 @@ union type_holder uint64_t* u64; double* d; std::tm* t; + blob* b; }; template @@ -223,6 +245,15 @@ struct type_holder_trait static const db_type type = db_date; }; +template <> +struct type_holder_trait +{ + static const db_type type = db_blob; +}; + +struct value_cast_tag{}; +struct value_reference_tag{}; + // Class for storing type data instances in a container of holder objects class holder { @@ -268,6 +299,8 @@ class holder delete val_.t; break; case db_blob: + delete val_.b; + break; case db_xml: case db_string: delete val_.s; @@ -282,7 +315,7 @@ class holder #pragma warning(disable:4702) #endif template - T get() + T get(value_cast_tag) { switch (dt_) { @@ -307,6 +340,8 @@ class holder case db_date: return soci_cast::cast(*val_.t); case db_blob: + // blob is not copyable + break; case db_xml: case db_string: return soci_cast::cast(*val_.s); @@ -314,6 +349,41 @@ class holder throw std::bad_cast(); } + + template + T& get(value_reference_tag) + { + switch (dt_) + { + case db_int8: + return soci_return_same::value(*val_.i8); + case db_int16: + return soci_return_same::value(*val_.i16); + case db_int32: + return soci_return_same::value(*val_.i32); + case db_int64: + return soci_return_same::value(*val_.i64); + case db_uint8: + return soci_return_same::value(*val_.u8); + case db_uint16: + return soci_return_same::value(*val_.u16); + case db_uint32: + return soci_return_same::value(*val_.u32); + case db_uint64: + return soci_return_same::value(*val_.u64); + case db_double: + return soci_return_same::value(*val_.d); + case db_date: + return soci_return_same::value(*val_.t); + case db_blob: + return soci_return_same::value(*val_.b); + case db_xml: + case db_string: + return soci_return_same::value(*val_.s); + } + + throw std::bad_cast(); + } #ifdef _MSC_VER #pragma warning(pop) #endif @@ -354,6 +424,8 @@ class holder val_.t = static_cast(val); return; case db_blob: + val_.b = static_cast(val); + return; case db_xml: case db_string: val_.s = static_cast(val); diff --git a/src/core/row.cpp b/src/core/row.cpp index da145deb7..af4bdc745 100644 --- a/src/core/row.cpp +++ b/src/core/row.cpp @@ -7,6 +7,7 @@ #define SOCI_SOURCE #include "soci/row.h" +#include "soci/type-holder.h" #include #include @@ -114,7 +115,7 @@ template <> blob row::move_as(std::size_t pos) const { typedef typename type_conversion::base_type base_type; - base_type & baseVal = holders_.at(pos)->get(); + base_type & baseVal = holders_.at(pos)->get(value_reference_tag{}); blob ret; type_conversion::move_from_base(baseVal, *indicators_.at(pos), ret);