5#include "../SqlColumnTypeDefinitions.hpp"
6#include "../SqlError.hpp"
7#include "Primitives.hpp"
14#include <source_location>
22#if defined(__SIZEOF_INT128__) && !defined(_MSC_VER)
23 #define LIGHTWEIGHT_INT128_T __int128_t
24 static_assert(
sizeof(__int128_t) ==
sizeof(SQL_NUMERIC_STRUCT::val));
36template <std::
size_t ThePrecision, std::
size_t TheScale>
39 static constexpr auto ColumnType = SqlColumnTypeDefinitions::Decimal { .precision = ThePrecision, .scale = TheScale };
45 static constexpr auto Scale = TheScale;
47 static_assert(TheScale < SQL_MAX_NUMERIC_LEN);
61 constexpr
SqlNumeric(std::floating_point auto value) noexcept
67 constexpr explicit SqlNumeric(SQL_NUMERIC_STRUCT
const& value)
noexcept:
73 static_assert(std::endian::native == std::endian::little);
76 LIGHTWEIGHT_FORCE_INLINE
constexpr void assign(std::floating_point
auto value)
noexcept
78#if defined(LIGHTWEIGHT_INT128_T)
79 auto const num =
static_cast<LIGHTWEIGHT_INT128_T
>(value * std::pow(10,
Scale));
80 *((LIGHTWEIGHT_INT128_T*)
sqlValue.val) = num;
82 auto const num =
static_cast<int64_t
>(value * std::pow(10,
Scale));
100 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
auto ToUnscaledValue() const noexcept
102 auto const sign =
sqlValue.sign ? 1 : -1;
103#if defined(LIGHTWEIGHT_INT128_T)
104 return sign * *
reinterpret_cast<LIGHTWEIGHT_INT128_T const*
>(
sqlValue.val);
106 return sign * *
reinterpret_cast<int64_t const*
>(
sqlValue.val);
111 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
float ToFloat() const noexcept
117 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
double ToDouble() const noexcept
123 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
long double ToLongDouble() const noexcept
129 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
explicit operator float() const noexcept
135 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
explicit operator double() const noexcept
141 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
explicit operator long double() const noexcept
147 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE std::string
ToString()
const
152 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE std::weak_ordering operator<=>(
SqlNumeric const& other)
const noexcept
154 return ToDouble() <=> other.ToDouble();
157 template <std::
size_t OtherPrecision, std::
size_t OtherScale>
158 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
bool operator==(
159 SqlNumeric<OtherPrecision, OtherScale>
const& other)
const noexcept
161 return ToFloat() == other.ToFloat();
166concept SqlNumericType =
requires(T t) {
167 { T::Precision } -> std::convertible_to<std::size_t>;
168 { T::Scale } -> std::convertible_to<std::size_t>;
169} && std::same_as<T, SqlNumeric<T::Precision, T::Scale>>;
172template <std::
size_t Precision, std::
size_t Scale>
173struct SqlDataBinder<SqlNumeric<Precision, Scale>>
175 using ValueType = SqlNumeric<Precision, Scale>;
177 static constexpr auto ColumnType = SqlColumnTypeDefinitions::Decimal { .precision = Precision, .scale = Scale };
179 static void RequireSuccess(SQLHSTMT stmt, SQLRETURN error, std::source_location sourceLocation = std::source_location::current())
181 if (SQL_SUCCEEDED(error))
187 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt, SQLUSMALLINT column, ValueType
const& value, SqlDataBinderCallback& )
noexcept
189 auto* mut =
const_cast<ValueType*
>(&value);
190 mut->sqlValue.precision = Precision;
191 mut->sqlValue.scale = Scale;
192 RequireSuccess(stmt, SQLBindParameter(stmt, column, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, Precision, Scale, (SQLPOINTER) &value.sqlValue, 0,
nullptr));
196 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN OutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback& )
noexcept
199 RequireSuccess(stmt, SQLGetStmtAttr(stmt, SQL_ATTR_APP_ROW_DESC, (SQLPOINTER) &hDesc, 0,
nullptr));
200 RequireSuccess(stmt, SQLSetDescField(hDesc, (SQLSMALLINT) column, SQL_DESC_PRECISION, (SQLPOINTER) Precision, 0));
201 RequireSuccess(stmt, SQLSetDescField(hDesc, (SQLSMALLINT) column, SQL_DESC_SCALE, (SQLPOINTER) Scale, 0));
203 return SQLBindCol(stmt, column, SQL_C_NUMERIC, &result->sqlValue,
sizeof(ValueType), indicator);
206 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback
const& )
noexcept
209 RequireSuccess(stmt, SQLGetStmtAttr(stmt, SQL_ATTR_APP_ROW_DESC, (SQLPOINTER) &hDesc, 0,
nullptr));
210 RequireSuccess(stmt, SQLSetDescField(hDesc, (SQLSMALLINT) column, SQL_DESC_PRECISION, (SQLPOINTER) Precision, 0));
211 RequireSuccess(stmt, SQLSetDescField(hDesc, (SQLSMALLINT) column, SQL_DESC_SCALE, (SQLPOINTER) Scale, 0));
213 return SQLGetData(stmt, column, SQL_C_NUMERIC, &result->sqlValue,
sizeof(ValueType), indicator);
216 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(ValueType
const& value)
noexcept
218 return value.ToString();
225template <Lightweight::SqlNumericType Type>
226struct std::formatter<Type>: std::formatter<std::string>
228 template <
typename FormatContext>
229 auto format(Type
const& value, FormatContext& ctx)
231 return formatter<std::string>::format(value.ToString(), ctx);
static SqlErrorInfo FromStatementHandle(SQLHSTMT hStmt)
Constructs an ODBC error info object from the given ODBC statement handle.
constexpr LIGHTWEIGHT_FORCE_INLINE float ToFloat() const noexcept
Converts the numeric to a floating point value.
constexpr LIGHTWEIGHT_FORCE_INLINE double ToDouble() const noexcept
Converts the numeric to a double precision floating point value.
constexpr SqlNumeric(SQL_NUMERIC_STRUCT const &value) noexcept
Constructs a numeric from a SQL_NUMERIC_STRUCT.
LIGHTWEIGHT_FORCE_INLINE std::string ToString() const
Converts the numeric to a string.
static constexpr auto Precision
Number of total digits.
LIGHTWEIGHT_FORCE_INLINE constexpr void assign(std::floating_point auto value) noexcept
Assigns a value to the numeric.
SQL_NUMERIC_STRUCT sqlValue
The value is stored as a string to avoid floating point precision issues.
constexpr LIGHTWEIGHT_FORCE_INLINE auto ToUnscaledValue() const noexcept
Converts the numeric to an unscaled integer value.
static constexpr auto Scale
Number of digits after the decimal point.
constexpr LIGHTWEIGHT_FORCE_INLINE long double ToLongDouble() const noexcept
Converts the numeric to a long double precision floating point value.
LIGHTWEIGHT_FORCE_INLINE constexpr SqlNumeric & operator=(std::floating_point auto value) noexcept
Assigns a floating point value to the numeric.