Lightweight 0.20250904.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 using native_type = std::chrono::hh_mm_ss<std::chrono::microseconds>;
45
46#if defined(SQL_SS_TIME2)
47 using sql_type = SQL_SS_TIME2_STRUCT;
48#else
49 using sql_type = SQL_TIME_STRUCT;
50#endif
51
52 sql_type sqlValue {};
53
54 constexpr SqlTime() noexcept = default;
55 constexpr SqlTime(SqlTime&&) noexcept = default;
56 constexpr SqlTime& operator=(SqlTime&&) noexcept = default;
57 constexpr SqlTime(SqlTime const&) noexcept = default;
58 constexpr SqlTime& operator=(SqlTime const&) noexcept = default;
59 constexpr ~SqlTime() noexcept = default;
60
61 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr native_type value() const noexcept
62 {
63 return ConvertToNative(sqlValue);
64 }
65
66 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(SqlTime const& other) const noexcept
67 {
68 return value().to_duration().count() == other.value().to_duration().count();
69 }
70
71 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(SqlTime const& other) const noexcept
72 {
73 return !(*this == other);
74 }
75
76 LIGHTWEIGHT_FORCE_INLINE constexpr SqlTime(native_type value) noexcept:
77 sqlValue { SqlTime::ConvertToSqlValue(value) }
78 {
79 }
80
81 LIGHTWEIGHT_FORCE_INLINE constexpr SqlTime(std::chrono::hours hour,
82 std::chrono::minutes minute,
83 std::chrono::seconds second,
84 std::chrono::microseconds micros = {}) noexcept:
85 SqlTime(native_type { hour + minute + second + micros })
86 {
87 }
88
89 static LIGHTWEIGHT_FORCE_INLINE constexpr sql_type ConvertToSqlValue(native_type value) noexcept
90 {
91 return sql_type {
92 .hour = (SQLUSMALLINT) value.hours().count(),
93 .minute = (SQLUSMALLINT) value.minutes().count(),
94 .second = (SQLUSMALLINT) value.seconds().count(),
95#if defined(SQL_SS_TIME2)
96 .fraction = (SQLUINTEGER) value.subseconds().count(),
97#endif
98 };
99 }
100
101 static LIGHTWEIGHT_FORCE_INLINE constexpr native_type ConvertToNative(sql_type const& value) noexcept
102 {
103 // clang-format off
104 return native_type { std::chrono::hours { (int) value.hour }
105 + std::chrono::minutes { (unsigned) value.minute }
106 + std::chrono::seconds { (unsigned) value.second }
107#if defined(SQL_SS_TIME2)
108 + std::chrono::microseconds { value.fraction }
109#endif
110
111 };
112 // clang-format on
113 }
114};
115
116template <>
117struct SqlDataBinder<SqlTime>
118{
119 static constexpr auto ColumnType = SqlColumnTypeDefinitions::Time {};
120
121 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
122 SQLUSMALLINT column,
123 SqlTime const& value,
124 SqlDataBinderCallback& /*cb*/) noexcept
125 {
126 return SQLBindParameter(
127 stmt, column, SQL_PARAM_INPUT, SQL_C_TYPE_TIME, SQL_TYPE_TIME, 0, 0, (SQLPOINTER) &value.sqlValue, 0, nullptr);
128 }
129
130 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN OutputColumn(
131 SQLHSTMT stmt, SQLUSMALLINT column, SqlTime* result, SQLLEN* indicator, SqlDataBinderCallback& /*cb*/) noexcept
132 {
133 return SQLBindCol(stmt, column, SQL_C_TYPE_TIME, &result->sqlValue, sizeof(result->sqlValue), indicator);
134 }
135
136 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(
137 SQLHSTMT stmt, SQLUSMALLINT column, SqlTime* result, SQLLEN* indicator, SqlDataBinderCallback const& /*cb*/) noexcept
138 {
139 return SQLGetData(stmt, column, SQL_C_TYPE_TIME, &result->sqlValue, sizeof(result->sqlValue), indicator);
140 }
141
142 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(SqlTime const& value) noexcept
143 {
144 return std::format("{:02}:{:02}:{:02}.{:06}",
145 value.sqlValue.hour,
146 value.sqlValue.minute,
147 value.sqlValue.second,
148 value.sqlValue.fraction);
149 }
150};
151
152} // namespace Lightweight
153
154template <>
155struct std::formatter<Lightweight::SqlTime>: std::formatter<std::string>
156{
157 auto format(Lightweight::SqlTime const& value, std::format_context& ctx) const -> std::format_context::iterator
158 {
159 return std::formatter<std::string>::format(std::format("{:02}:{:02}:{:02}:{:06}",
160 value.sqlValue.hour,
161 value.sqlValue.minute,
162 value.sqlValue.second,
163 value.sqlValue.fraction),
164 ctx);
165 }
166};