Lightweight 0.20260303.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 /// Default constructor.
36 /// Default move constructor.
38 /// Default copy constructor.
40 /// Default move assignment operator.
42 /// Default copy assignment operator.
44
45 virtual ~SqlDataBinderCallback() = default;
46
47 /// Plans a callback to be called after the statement has been executed.
48 ///
49 /// @see SqlDataBinder::PostExecute()
50 virtual void PlanPostExecuteCallback(std::function<void()>&&) = 0;
51
52 /// Plans a callback to be called after a column has been processed.
53 ///
54 /// @see SqlDataBinder::PostProcessOutputColumn()
55 virtual void PlanPostProcessOutputColumn(std::function<void()>&&) = 0;
56
57 /// Provides a pointer to a single indicator for a single input parameter.
58 ///
59 /// @note The caller is responsible for filling the indicator with the length of the data or
60 /// SQL_NULL_DATA.
61 /// @note The indicator must remain valid until the statement is executed.
62 ///
63 /// @return A pointer to the indicator.
64 virtual SQLLEN* ProvideInputIndicator() = 0;
65
66 /// Provides a pointer to a contiguous array of indicators for a batch of input parameters.
67 ///
68 /// @note The caller is responsible for filling the indicators with the lengths of the data or
69 /// SQL_NULL_DATA.
70 /// @note The indicators must remain valid until the statement is executed.
71 ///
72 /// @param rowCount The number of rows in the batch.
73 /// @return A pointer to the first element of the indicator array.
74 virtual SQLLEN* ProvideInputIndicators(size_t rowCount) = 0;
75
76 /// @return The server type of the database.
77 [[nodiscard]] virtual SqlServerType ServerType() const noexcept = 0;
78
79 /// @return The driver name of the database.
80 [[nodiscard]] virtual std::string const& DriverName() const noexcept = 0;
81};
82
83template <typename>
84struct SqlDataBinder;
85
86// Default traits for output string parameters
87// This needs to be implemented for each string type that should be used as output parameter via
88// SqlDataBinder<>. An std::string specialization is provided below. Feel free to add more specializations for
89// other string types, such as CString, etc.
90template <typename>
91struct SqlBasicStringOperations;
92
93// -----------------------------------------------------------------------------------------------
94
95namespace detail
96{
97
98 // clang-format off
99template <typename T>
100concept HasGetStringAndGetLength = requires(T const& t) {
101 { t.GetLength() } -> std::same_as<int>;
102 { t.GetString() } -> std::same_as<char const*>;
103};
104
105template <typename T>
106concept HasGetStringAndLength = requires(T const& t)
107{
108 { t.Length() } -> std::same_as<int>;
109 { t.GetString() } -> std::same_as<char const*>;
110};
111 // clang-format on
112
113 template <typename>
114 struct SqlViewHelper;
115
116 template <typename T>
117 concept HasSqlViewHelper = requires(T const& t) {
118 { SqlViewHelper<T>::View(t) } -> std::convertible_to<std::string_view>;
119 };
120
121 template <typename CharT>
122 struct SqlViewHelper<std::basic_string<CharT>>
123 {
124 static LIGHTWEIGHT_FORCE_INLINE std::basic_string_view<CharT> View(std::basic_string<CharT> const& str) noexcept
125 {
126 return { str.data(), str.size() };
127 }
128 };
129
130 template <detail::HasGetStringAndGetLength CStringLike>
131 struct SqlViewHelper<CStringLike>
132 {
133 static LIGHTWEIGHT_FORCE_INLINE std::string_view View(CStringLike const& str) noexcept
134 {
135 return { str.GetString(), static_cast<size_t>(str.GetLength()) };
136 }
137 };
138
139 template <detail::HasGetStringAndLength StringLike>
140 struct SqlViewHelper<StringLike>
141 {
142 static LIGHTWEIGHT_FORCE_INLINE std::string_view View(StringLike const& str) noexcept
143 {
144 return { str.GetString(), static_cast<size_t>(str.Length()) };
145 }
146 };
147
148} // namespace detail
149
150// -----------------------------------------------------------------------------------------------
151
152template <typename T>
153concept SqlInputParameterBinder = requires(SQLHSTMT hStmt, SQLUSMALLINT column, T const& value, SqlDataBinderCallback& cb) {
154 { SqlDataBinder<T>::InputParameter(hStmt, column, value, cb) } -> std::same_as<SQLRETURN>;
155};
156
157template <typename T>
158concept SqlOutputColumnBinder =
159 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T* result, SQLLEN* indicator, SqlDataBinderCallback& cb) {
160 { SqlDataBinder<T>::OutputColumn(hStmt, column, result, indicator, cb) } -> std::same_as<SQLRETURN>;
161 };
162
163template <typename T>
164concept SqlInputParameterBatchBinder =
165 requires(SQLHSTMT hStmt, SQLUSMALLINT column, std::ranges::range_value_t<T>* result, SqlDataBinderCallback& cb) {
166 {
167 SqlDataBinder<std::ranges::range_value_t<T>>::InputParameter(
168 hStmt, column, std::declval<std::ranges::range_value_t<T>>(), cb)
169 } -> std::same_as<SQLRETURN>;
170 };
171
172template <typename T>
173concept SqlGetColumnNativeType =
174 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T* result, SQLLEN* indicator, SqlDataBinderCallback const& cb) {
175 { SqlDataBinder<T>::GetColumn(hStmt, column, result, indicator, cb) } -> std::same_as<SQLRETURN>;
176 };
177
178template <typename T>
179concept SqlDataBinderSupportsInspect = requires(T const& value) {
180 { SqlDataBinder<std::remove_cvref_t<T>>::Inspect(value) } -> std::convertible_to<std::string>;
181};
182
183// clang-format off
184template <typename StringType, typename CharType>
185concept SqlBasicStringBinderConcept = requires(StringType* str) {
186 { SqlBasicStringOperations<StringType>::Data(str) } -> std::same_as<CharType*>;
187 { SqlBasicStringOperations<StringType>::Size(str) } -> std::same_as<SQLULEN>;
188 { SqlBasicStringOperations<StringType>::Reserve(str, size_t {}) } -> std::same_as<void>;
189 { SqlBasicStringOperations<StringType>::Resize(str, SQLLEN {}) } -> std::same_as<void>;
190 { SqlBasicStringOperations<StringType>::Clear(str) } -> std::same_as<void>;
191};
192// clang-format on
193
194} // namespace Lightweight
virtual void PlanPostExecuteCallback(std::function< void()> &&)=0
virtual SQLLEN * ProvideInputIndicator()=0
SqlDataBinderCallback(SqlDataBinderCallback &&)=default
Default move constructor.
virtual SqlServerType ServerType() const noexcept=0
virtual void PlanPostProcessOutputColumn(std::function< void()> &&)=0
SqlDataBinderCallback & operator=(SqlDataBinderCallback const &)=default
Default copy assignment operator.
SqlDataBinderCallback & operator=(SqlDataBinderCallback &&)=default
Default move assignment operator.
SqlDataBinderCallback()=default
Default constructor.
virtual SQLLEN * ProvideInputIndicators(size_t rowCount)=0
SqlDataBinderCallback(SqlDataBinderCallback const &)=default
Default copy constructor.