Lightweight 0.20260625.0
Loading...
Searching...
No Matches
SqlTime.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../SqlColumnTypeDefinitions.hpp"
6#include "Core.hpp"
7
8#include <chrono>
9#include <format>
10
11// clang-format off
12#if !defined(SQL_SS_TIME2)
13// This is a Microsoft-specific extension to ODBC.
14// It is supported by at lesat the following drivers:
15// - SQL Server 2008 and later
16// - MariaDB and MySQL ODBC drivers
17
18#define SQL_SS_TIME2 (-154)
19
20struct SQL_SS_TIME2_STRUCT
21{
22 SQLUSMALLINT hour;
23 SQLUSMALLINT minute;
24 SQLUSMALLINT second;
25 SQLUINTEGER fraction;
26};
27
28static_assert(
29 sizeof(SQL_SS_TIME2_STRUCT) == 12,
30 "SQL_SS_TIME2_STRUCT size must be padded 12 bytes, as per ODBC extension spec."
31);
32
33#endif
34// clang-format on
35
36namespace Lightweight
37{
38
39/// Stores the time (of the day) to efficiently write to or read from a database.
40///
41/// @ingroup DataTypes
42struct SqlTime
43{
44 /// The native C++ type for time representation.
45 using native_type = std::chrono::hh_mm_ss<std::chrono::microseconds>;
46
47#if defined(SQL_SS_TIME2)
48 /// The SQL type used for ODBC binding.
49 using sql_type = SQL_SS_TIME2_STRUCT;
50#else
51 /// The SQL type used for ODBC binding.
52 using sql_type = SQL_TIME_STRUCT;
53#endif
54
55 /// The underlying SQL value for ODBC binding.
57
58 /// Default constructor.
59 constexpr SqlTime() noexcept = default;
60 /// Move constructor.
61 constexpr SqlTime(SqlTime&&) noexcept = default;
62 /// Move assignment operator.
63 constexpr SqlTime& operator=(SqlTime&&) noexcept = default;
64 /// Copy constructor.
65 constexpr SqlTime(SqlTime const&) noexcept = default;
66 /// Copy assignment operator.
67 constexpr SqlTime& operator=(SqlTime const&) noexcept = default;
68 constexpr ~SqlTime() noexcept = default;
69
70 /// Returns the native time value.
71 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr native_type value() const noexcept
72 {
74 }
75
76 /// Equality comparison operator.
77 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(SqlTime const& other) const noexcept
78 {
79 return value().to_duration().count() == other.value().to_duration().count();
80 }
81
82 /// Inequality comparison operator.
83 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(SqlTime const& other) const noexcept
84 {
85 return !(*this == other);
86 }
87
88 /// Constructs a SqlTime from a native time value.
89 LIGHTWEIGHT_FORCE_INLINE constexpr SqlTime(native_type value) noexcept:
91 {
92 }
93
94 /// Constructs a SqlTime from hours, minutes, seconds, and optional microseconds.
95 LIGHTWEIGHT_FORCE_INLINE constexpr SqlTime(std::chrono::hours hour,
96 std::chrono::minutes minute,
97 std::chrono::seconds second,
98 std::chrono::microseconds micros = {}) noexcept:
99 SqlTime(native_type { hour + minute + second + micros })
100 {
101 }
102
103 /// Converts a native time value to the SQL representation.
104 static LIGHTWEIGHT_FORCE_INLINE constexpr sql_type ConvertToSqlValue(native_type value) noexcept
105 {
106 return sql_type {
107 .hour = (SQLUSMALLINT) value.hours().count(),
108 .minute = (SQLUSMALLINT) value.minutes().count(),
109 .second = (SQLUSMALLINT) value.seconds().count(),
110#if defined(SQL_SS_TIME2)
111 .fraction = (SQLUINTEGER) value.subseconds().count(),
112#endif
113 };
114 }
115
116 /// Converts a SQL time value to the native representation.
117 static LIGHTWEIGHT_FORCE_INLINE constexpr native_type ConvertToNative(sql_type const& value) noexcept
118 {
119 // clang-format off
120 return native_type { std::chrono::hours { (int) value.hour }
121 + std::chrono::minutes { (unsigned) value.minute }
122 + std::chrono::seconds { (unsigned) value.second }
123#if defined(SQL_SS_TIME2)
124 + std::chrono::microseconds { value.fraction }
125#endif
126
127 };
128 // clang-format on
129 }
130};
131
132template <>
133struct SqlDataBinder<SqlTime>
134{
135 static constexpr auto ColumnType = SqlColumnTypeDefinitions::Time {};
136
137 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
138 SQLUSMALLINT column,
139 SqlTime const& value,
140 SqlDataBinderCallback& /*cb*/) noexcept
141 {
142 return SQLBindParameter(
143 stmt, column, SQL_PARAM_INPUT, SQL_C_TYPE_TIME, SQL_TYPE_TIME, 0, 0, (SQLPOINTER) &value.sqlValue, 0, nullptr);
144 }
145
146 /// Binds an array of times as an input parameter for native (row-wise or column-wise) batch
147 /// execution. @p values points at the first element; the driver strides by the statement's
148 /// SQL_ATTR_PARAM_BIND_TYPE. @p indicators optionally supplies per-row NULL flags.
149 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN BatchInputParameter(SQLHSTMT stmt,
150 SQLUSMALLINT column,
151 SqlTime const* values,
152 size_t /*rowCount*/,
153 SqlDataBinderCallback& /*cb*/,
154 SQLLEN* indicators = nullptr) noexcept
155 {
156 return SQLBindParameter(stmt,
157 column,
158 SQL_PARAM_INPUT,
159 SQL_C_TYPE_TIME,
160 SQL_TYPE_TIME,
161 0,
162 0,
163 (SQLPOINTER) &values->sqlValue,
164 sizeof(values->sqlValue),
165 indicators);
166 }
167
168 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN OutputColumn(
169 SQLHSTMT stmt, SQLUSMALLINT column, SqlTime* result, SQLLEN* indicator, SqlDataBinderCallback& /*cb*/) noexcept
170 {
171 return SQLBindCol(stmt, column, SQL_C_TYPE_TIME, &result->sqlValue, sizeof(result->sqlValue), indicator);
172 }
173
174 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(
175 SQLHSTMT stmt, SQLUSMALLINT column, SqlTime* result, SQLLEN* indicator, SqlDataBinderCallback const& /*cb*/) noexcept
176 {
177 return SQLGetData(stmt, column, SQL_C_TYPE_TIME, &result->sqlValue, sizeof(result->sqlValue), indicator);
178 }
179
180 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(SqlTime const& value) noexcept
181 {
182 return std::format("{:02}:{:02}:{:02}.{:06}",
183 value.sqlValue.hour,
184 value.sqlValue.minute,
185 value.sqlValue.second,
186 value.sqlValue.fraction);
187 }
188};
189
190template <>
191inline constexpr bool SqlIsNativeRowBindableValue<SqlTime> = true;
192
193} // namespace Lightweight
194
195template <>
196struct std::formatter<Lightweight::SqlTime>: std::formatter<std::string>
197{
198 auto format(Lightweight::SqlTime const& value, std::format_context& ctx) const -> std::format_context::iterator
199 {
200 return std::formatter<std::string>::format(std::format("{:02}:{:02}:{:02}.{:06}",
201 value.sqlValue.hour,
202 value.sqlValue.minute,
203 value.sqlValue.second,
204 value.sqlValue.fraction),
205 ctx);
206 }
207};
static LIGHTWEIGHT_FORCE_INLINE constexpr sql_type ConvertToSqlValue(native_type value) noexcept
Converts a native time value to the SQL representation.
Definition SqlTime.hpp:104
constexpr SqlTime() noexcept=default
Default constructor.
std::chrono::hh_mm_ss< std::chrono::microseconds > native_type
The native C++ type for time representation.
Definition SqlTime.hpp:45
SQL_SS_TIME2_STRUCT sql_type
The SQL type used for ODBC binding.
Definition SqlTime.hpp:49
LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(SqlTime const &other) const noexcept
Inequality comparison operator.
Definition SqlTime.hpp:83
LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(SqlTime const &other) const noexcept
Equality comparison operator.
Definition SqlTime.hpp:77
sql_type sqlValue
The underlying SQL value for ODBC binding.
Definition SqlTime.hpp:56
LIGHTWEIGHT_FORCE_INLINE constexpr SqlTime(native_type value) noexcept
Constructs a SqlTime from a native time value.
Definition SqlTime.hpp:89
LIGHTWEIGHT_FORCE_INLINE constexpr native_type value() const noexcept
Returns the native time value.
Definition SqlTime.hpp:71
static LIGHTWEIGHT_FORCE_INLINE constexpr native_type ConvertToNative(sql_type const &value) noexcept
Converts a SQL time value to the native representation.
Definition SqlTime.hpp:117
LIGHTWEIGHT_FORCE_INLINE constexpr SqlTime(std::chrono::hours hour, std::chrono::minutes minute, std::chrono::seconds second, std::chrono::microseconds micros={}) noexcept
Constructs a SqlTime from hours, minutes, seconds, and optional microseconds.
Definition SqlTime.hpp:95