Lightweight 0.20250904.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 virtual void PlanPostExecuteCallback(std::function<void()>&&) = 0;
43 virtual void PlanPostProcessOutputColumn(std::function<void()>&&) = 0;
44
45 [[nodiscard]] virtual SqlServerType ServerType() const noexcept = 0;
46 [[nodiscard]] virtual std::string const& DriverName() const noexcept = 0;
47};
48
49template <typename>
50struct SqlDataBinder;
51
52// Default traits for output string parameters
53// This needs to be implemented for each string type that should be used as output parameter via
54// SqlDataBinder<>. An std::string specialization is provided below. Feel free to add more specializations for
55// other string types, such as CString, etc.
56template <typename>
57struct SqlBasicStringOperations;
58
59// -----------------------------------------------------------------------------------------------
60
61namespace detail
62{
63
64 // clang-format off
65template <typename T>
66concept HasGetStringAndGetLength = requires(T const& t) {
67 { t.GetLength() } -> std::same_as<int>;
68 { t.GetString() } -> std::same_as<char const*>;
69};
70
71template <typename T>
72concept HasGetStringAndLength = requires(T const& t)
73{
74 { t.Length() } -> std::same_as<int>;
75 { t.GetString() } -> std::same_as<char const*>;
76};
77 // clang-format on
78
79 template <typename>
80 struct SqlViewHelper;
81
82 template <typename T>
83 concept HasSqlViewHelper = requires(T const& t) {
84 { SqlViewHelper<T>::View(t) } -> std::convertible_to<std::string_view>;
85 };
86
87 template <typename CharT>
88 struct SqlViewHelper<std::basic_string<CharT>>
89 {
90 static LIGHTWEIGHT_FORCE_INLINE std::basic_string_view<CharT> View(std::basic_string<CharT> const& str) noexcept
91 {
92 return { str.data(), str.size() };
93 }
94 };
95
96 template <detail::HasGetStringAndGetLength CStringLike>
97 struct SqlViewHelper<CStringLike>
98 {
99 static LIGHTWEIGHT_FORCE_INLINE std::string_view View(CStringLike const& str) noexcept
100 {
101 return { str.GetString(), static_cast<size_t>(str.GetLength()) };
102 }
103 };
104
105 template <detail::HasGetStringAndLength StringLike>
106 struct SqlViewHelper<StringLike>
107 {
108 static LIGHTWEIGHT_FORCE_INLINE std::string_view View(StringLike const& str) noexcept
109 {
110 return { str.GetString(), static_cast<size_t>(str.Length()) };
111 }
112 };
113
114} // namespace detail
115
116// -----------------------------------------------------------------------------------------------
117
118template <typename T>
119concept SqlInputParameterBinder = requires(SQLHSTMT hStmt, SQLUSMALLINT column, T const& value, SqlDataBinderCallback& cb) {
120 { SqlDataBinder<T>::InputParameter(hStmt, column, value, cb) } -> std::same_as<SQLRETURN>;
121};
122
123template <typename T>
124concept SqlOutputColumnBinder =
125 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T* result, SQLLEN* indicator, SqlDataBinderCallback& cb) {
126 { SqlDataBinder<T>::OutputColumn(hStmt, column, result, indicator, cb) } -> std::same_as<SQLRETURN>;
127 };
128
129template <typename T>
130concept SqlInputParameterBatchBinder =
131 requires(SQLHSTMT hStmt, SQLUSMALLINT column, std::ranges::range_value_t<T>* result, SqlDataBinderCallback& cb) {
132 {
133 SqlDataBinder<std::ranges::range_value_t<T>>::InputParameter(
134 hStmt, column, std::declval<std::ranges::range_value_t<T>>(), cb)
135 } -> std::same_as<SQLRETURN>;
136 };
137
138template <typename T>
139concept SqlGetColumnNativeType =
140 requires(SQLHSTMT hStmt, SQLUSMALLINT column, T* result, SQLLEN* indicator, SqlDataBinderCallback const& cb) {
141 { SqlDataBinder<T>::GetColumn(hStmt, column, result, indicator, cb) } -> std::same_as<SQLRETURN>;
142 };
143
144template <typename T>
145concept SqlDataBinderSupportsInspect = requires(T const& value) {
146 { SqlDataBinder<std::remove_cvref_t<T>>::Inspect(value) } -> std::convertible_to<std::string>;
147};
148
149// clang-format off
150template <typename StringType, typename CharType>
151concept SqlBasicStringBinderConcept = requires(StringType* str) {
152 { SqlBasicStringOperations<StringType>::Data(str) } -> std::same_as<CharType*>;
153 { SqlBasicStringOperations<StringType>::Size(str) } -> std::same_as<SQLULEN>;
154 { SqlBasicStringOperations<StringType>::Reserve(str, size_t {}) } -> std::same_as<void>;
155 { SqlBasicStringOperations<StringType>::Resize(str, SQLLEN {}) } -> std::same_as<void>;
156 { SqlBasicStringOperations<StringType>::Clear(str) } -> std::same_as<void>;
157};
158// clang-format on
159
160} // namespace Lightweight