Lightweight 0.20251202.0
Loading...
Searching...
No Matches
Core.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#if defined(_WIN32) || defined(_WIN64)
6 #include <Windows.h>
7#endif
8
9#include "../Api.hpp"
10#include "../SqlServerType.hpp"
11
12#include <concepts>
13#include <functional>
14
15#include <sql.h>
16#include <sqlext.h>
17#include <sqltypes.h>
18
19namespace Lightweight
20{
21
22/// @defgroup DataTypes Data Types
23///
24/// @brief Special purpose data types for SQL data binding.
25
26/// Callback interface for SqlDataBinder to allow post-processing of output columns.
27///
28/// This is needed because the SQLBindCol() function does not allow to specify a callback function to be called
29/// after the data has been fetched from the database. This is needed to trim strings to the correct size, for
30/// example.
31class LIGHTWEIGHT_API SqlDataBinderCallback
32{
33 public:
34 SqlDataBinderCallback() = default;
37 SqlDataBinderCallback& operator=(SqlDataBinderCallback&&) = default;
38 SqlDataBinderCallback& operator=(SqlDataBinderCallback const&) = default;
39
40 virtual ~SqlDataBinderCallback() = default;
41
42 /// Plans a callback to be called after the statement has been executed.
43 ///
44 /// @see SqlDataBinder::PostExecute()
45 virtual void PlanPostExecuteCallback(std::function<void()>&&) = 0;
46
47 /// Plans a callback to be called after a column has been processed.
48 ///
49 /// @see SqlDataBinder::PostProcessOutputColumn()
50 virtual void PlanPostProcessOutputColumn(std::function<void()>&&) = 0;
51
52 /// Provides a pointer to a single indicator for a single input parameter.
53 ///
54 /// @note The caller is responsible for filling the indicator with the length of the data or
55 /// SQL_NULL_DATA.
56 /// @note The indicator must remain valid until the statement is executed.
57 ///
58 /// @return A pointer to the indicator.
59 virtual SQLLEN* ProvideInputIndicator() = 0;
60
61 /// Provides a pointer to a contiguous array of indicators for a batch of input parameters.
62 ///
63 /// @note The caller is responsible for filling the indicators with the lengths of the data or
64 /// SQL_NULL_DATA.
65 /// @note The indicators must remain valid until the statement is executed.
66 ///
67 /// @param rowCount The number of rows in the batch.
68 /// @return A pointer to the first element of the indicator array.
69 virtual SQLLEN* ProvideInputIndicators(size_t rowCount) = 0;
70
71 /// @return The server type of the database.
72 [[nodiscard]] virtual SqlServerType ServerType() const noexcept = 0;
73
74 /// @return The driver name of the database.
75 [[nodiscard]] virtual std::string const& DriverName() const noexcept = 0;
76};
77
78template <typename>
79struct SqlDataBinder;
80
81// Default traits for output string parameters
82// This needs to be implemented for each string type that should be used as output parameter via
83// SqlDataBinder<>. An std::string specialization is provided below. Feel free to add more specializations for
84// other string types, such as CString, etc.
85template <typename>
86struct SqlBasicStringOperations;
87
88// -----------------------------------------------------------------------------------------------
89
90namespace detail
91{
92
93 // clang-format off
94template <typename T>
95concept HasGetStringAndGetLength = requires(T const& t) {
96 { t.GetLength() } -> std::same_as<int>;
97 { t.GetString() } -> std::same_as<char const*>;
98};
99
100template <typename T>
101concept HasGetStringAndLength = requires(T const& t)
102{
103 { t.Length() } -> std::same_as<int>;
104 { t.GetString() } -> std::same_as<char const*>;
105};
106 // clang-format on
107
108 template <typename>
109 struct SqlViewHelper;
110
111 template <typename T>
112 concept HasSqlViewHelper = requires(T const& t) {
113 { SqlViewHelper<T>::View(t) } -> std::convertible_to<std::string_view>;
114 };
115
116 template <typename CharT>
117 struct SqlViewHelper<std::basic_string<CharT>>
118 {
119 static LIGHTWEIGHT_FORCE_INLINE std::basic_string_view<CharT> View(std::basic_string<CharT> const& str) noexcept
120 {
121 return { str.data(), str.size() };
122 }
123 };
124
125 template <detail::HasGetStringAndGetLength CStringLike>
126 struct SqlViewHelper<CStringLike>
127 {
128 static LIGHTWEIGHT_FORCE_INLINE std::string_view View(CStringLike const& str) noexcept
129 {
130 return { str.GetString(), static_cast<size_t>(str.GetLength()) };
131 }
132 };
133
134 template <detail::HasGetStringAndLength StringLike>
135 struct SqlViewHelper<StringLike>
136 {
137 static LIGHTWEIGHT_FORCE_INLINE std::string_view View(StringLike const& str) noexcept
138 {
139 return { str.GetString(), static_cast<size_t>(str.Length()) };
140 }
141 };
142
143} // namespace detail
144
145// -----------------------------------------------------------------------------------------------
146
147template <typename T>
148concept SqlInputParameterBinder = requires(SQLHSTMT hStmt, SQLUSMALLINT column, T const& value, SqlDataBinderCallback& cb) {
149 { SqlDataBinder<T>::InputParameter(hStmt, column, value, cb) } -> std::same_as<SQLRETURN>;
150};
151
152template <typename T>
153concept SqlOutputColumnBinder =
154 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T* result, SQLLEN* indicator, SqlDataBinderCallback& cb) {
155 { SqlDataBinder<T>::OutputColumn(hStmt, column, result, indicator, cb) } -> std::same_as<SQLRETURN>;
156 };
157
158template <typename T>
159concept SqlInputParameterBatchBinder =
160 requires(SQLHSTMT hStmt, SQLUSMALLINT column, std::ranges::range_value_t<T>* result, SqlDataBinderCallback& cb) {
161 {
162 SqlDataBinder<std::ranges::range_value_t<T>>::InputParameter(
163 hStmt, column, std::declval<std::ranges::range_value_t<T>>(), cb)
164 } -> std::same_as<SQLRETURN>;
165 };
166
167template <typename T>
168concept SqlGetColumnNativeType =
169 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T* result, SQLLEN* indicator, SqlDataBinderCallback const& cb) {
170 { SqlDataBinder<T>::GetColumn(hStmt, column, result, indicator, cb) } -> std::same_as<SQLRETURN>;
171 };
172
173template <typename T>
174concept SqlDataBinderSupportsInspect = requires(T const& value) {
175 { SqlDataBinder<std::remove_cvref_t<T>>::Inspect(value) } -> std::convertible_to<std::string>;
176};
177
178// clang-format off
179template <typename StringType, typename CharType>
180concept SqlBasicStringBinderConcept = requires(StringType* str) {
181 { SqlBasicStringOperations<StringType>::Data(str) } -> std::same_as<CharType*>;
182 { SqlBasicStringOperations<StringType>::Size(str) } -> std::same_as<SQLULEN>;
183 { SqlBasicStringOperations<StringType>::Reserve(str, size_t {}) } -> std::same_as<void>;
184 { SqlBasicStringOperations<StringType>::Resize(str, SQLLEN {}) } -> std::same_as<void>;
185 { SqlBasicStringOperations<StringType>::Clear(str) } -> std::same_as<void>;
186};
187// clang-format on
188
189} // namespace Lightweight
virtual void PlanPostExecuteCallback(std::function< void()> &&)=0
virtual SQLLEN * ProvideInputIndicator()=0
virtual SqlServerType ServerType() const noexcept=0
virtual void PlanPostProcessOutputColumn(std::function< void()> &&)=0
virtual SQLLEN * ProvideInputIndicators(size_t rowCount)=0