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