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