Lightweight 0.20260625.0
Loading...
Searching...
No Matches
SqlOdbcWide.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5// <sql.h> below needs the Windows prelude established first — see the note in Utils.hpp.
6#if defined(_WIN32) || defined(_WIN64)
7 #include <Windows.h>
8#endif
9
10#include "DataBinder/UnicodeConverter.hpp"
11
12#include <string>
13#include <string_view>
14#include <utility>
15
16#include <sql.h>
17
18namespace Lightweight::detail
19{
20
21// ODBC W variants assume `SQLWCHAR` is layout-compatible with `char16_t` (true on
22// Windows where it's `wchar_t`, and on Linux unixODBC where it's `unsigned short` —
23// both 16-bit). Anything else and the reinterpret_casts below would silently corrupt.
24static_assert(sizeof(SQLWCHAR) == sizeof(char16_t), "ODBC W variants require a 16-bit code unit; SQLWCHAR shape mismatch");
25
26/// @brief Converts a UTF-8 string view into a `std::u16string` for ODBC W variants.
27/// Use this rather than `ToUtf16(std::string const&)` from `UnicodeConverter.hpp`:
28/// that overload treats its input as the platform narrow encoding (CP_ACP on
29/// Windows), which silently corrupts UTF-8 bytes >= 0x80.
30inline std::u16string OdbcUtf8ToUtf16(std::string_view utf8)
31{
32 return ToUtf16(std::u8string_view { reinterpret_cast<char8_t const*>(utf8.data()), utf8.size() });
33}
34
35/// @brief Reinterprets a `char16_t*` buffer as the `SQLWCHAR*` ODBC W variants want.
36/// Note: ODBC W input-string parameters are non-const (a legacy API quirk; the
37/// driver does not mutate them), so callers must hold their `std::u16string` non-const.
38inline SQLWCHAR* AsSqlWChar(char16_t* p) noexcept
39{
40 return reinterpret_cast<SQLWCHAR*>(p);
41}
42
43/// @brief Holds a UTF-16 buffer mapped from a UTF-8 input plus the (pointer, length)
44/// pair the ODBC W introspection / connect / prepare calls expect. Empty input
45/// produces a null pointer / zero length, mirroring the ODBC idiom of "pass nullptr
46/// when the caller does not want to filter on this field". The buffer's lifetime
47/// equals the `OdbcWideArg`'s, satisfying SQL_NTS for the duration of one call.
48struct OdbcWideArg
49{
50 std::u16string buffer;
51
52 explicit OdbcWideArg(std::string_view utf8):
53 buffer(utf8.empty() ? std::u16string {} : OdbcUtf8ToUtf16(utf8))
54 {
55 }
56
57 explicit OdbcWideArg(std::u16string utf16) noexcept:
58 buffer(std::move(utf16))
59 {
60 }
61
62 [[nodiscard]] SQLWCHAR* data() noexcept
63 {
64 return buffer.empty() ? nullptr : AsSqlWChar(buffer.data());
65 }
66
67 [[nodiscard]] SQLSMALLINT length() const noexcept
68 {
69 return static_cast<SQLSMALLINT>(buffer.size());
70 }
71};
72
73} // namespace Lightweight::detail
std::u16string ToUtf16(std::basic_string_view< T > const u32InputString)