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