6#include "UnicodeConverter.hpp"
23constexpr inline std::size_t SqlOptimalMaxColumnSize = 4000;
35 template <auto CType,
typename ArrayType>
36 requires requires(ArrayType& arr) {
37 { arr.data() } -> std::convertible_to<typename ArrayType::value_type*>;
38 { arr.size() } -> std::convertible_to<std::size_t>;
39 { arr.resize(std::declval<std::size_t>()) };
41 SQLRETURN GetRawColumnArrayData(SQLHSTMT stmt, SQLUSMALLINT column, ArrayType* result, SQLLEN* indicator)
noexcept
43 using CharType = ArrayType::value_type;
48 constexpr size_t TrailingNulTerminators = CType == SQL_C_BINARY ? 0 : 1;
54 auto sqlResult = SQLGetData(stmt,
57 static_cast<SQLPOINTER
>(result->data()),
58 static_cast<SQLLEN
>(result->size() *
sizeof(CharType)),
61 if (sqlResult == SQL_SUCCESS || sqlResult == SQL_NO_DATA)
64 if (*indicator == SQL_NULL_DATA)
67 result->resize(
static_cast<size_t>(*indicator) /
sizeof(CharType));
71 if (sqlResult == SQL_SUCCESS_WITH_INFO && *indicator != SQL_NO_TOTAL
72 && (
static_cast<size_t>(*indicator) /
sizeof(CharType)) + TrailingNulTerminators > result->size())
78 auto const totalCharCount =
static_cast<size_t>(*indicator) /
sizeof(CharType);
79 auto const charsWritten = result->size() - TrailingNulTerminators;
80 result->resize(totalCharCount + TrailingNulTerminators);
81 auto* bufferCont = result->data() + charsWritten;
82 auto const bufferCharsAvailable = (totalCharCount + TrailingNulTerminators) - charsWritten;
83 sqlResult = SQLGetData(
84 stmt, column, CType, bufferCont,
static_cast<SQLLEN
>(bufferCharsAvailable *
sizeof(CharType)), indicator);
85 if (SQL_SUCCEEDED(sqlResult))
86 result->resize(charsWritten + (
static_cast<size_t>(*indicator) /
sizeof(CharType)));
90 size_t writeIndex = 0;
91 while (sqlResult == SQL_SUCCESS_WITH_INFO && *indicator == SQL_NO_TOTAL)
94 writeIndex += result->size() - TrailingNulTerminators;
95 result->resize(result->size() * 2);
96 auto*
const bufferStart = result->data() + writeIndex;
97 size_t const bufferCharsAvailable = result->size() - writeIndex;
98 sqlResult = SQLGetData(
99 stmt, column, CType, bufferStart,
static_cast<SQLLEN
>(bufferCharsAvailable *
sizeof(CharType)), indicator);
103 if (writeIndex > 0 && SQL_SUCCEEDED(sqlResult) && *indicator != SQL_NULL_DATA && *indicator != SQL_NO_TOTAL)
104 result->resize(writeIndex + (
static_cast<size_t>(*indicator) /
sizeof(CharType)));
108 template <
typename Utf16StringType>
109 SQLRETURN GetColumnUtf16(SQLHSTMT stmt,
111 Utf16StringType* result,
113 SqlDataBinderCallback
const& )
noexcept
115 if constexpr (
requires { Utf16StringType::Capacity; })
116 result->resize(Utf16StringType::Capacity);
117 else if (result->size() == 0)
120 return GetRawColumnArrayData<SQL_C_WCHAR>(stmt, column, result, indicator);
123 template <
typename StringType>
124 SQLRETURN BindOutputColumnNonUtf16Unicode(
125 SQLHSTMT stmt, SQLUSMALLINT column, StringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
127 using CharType = StringType::value_type;
129 auto u16String = std::make_shared<std::u16string>();
130 if (!result->empty())
131 u16String->resize(result->size());
133 u16String->resize(255);
135 cb.PlanPostProcessOutputColumn([stmt, column, result, indicator, u16String = u16String]() {
136 if (*indicator == SQL_NULL_DATA)
138 else if (*indicator == SQL_NO_TOTAL)
140 else if (std::cmp_less_equal(*indicator, u16String->size() *
sizeof(
char16_t)))
141 u16String->resize(
static_cast<size_t>(*indicator) /
sizeof(
char16_t));
144 auto const totalCharsRequired =
static_cast<size_t>(*indicator) /
sizeof(char16_t);
145 *indicator +=
sizeof(char16_t);
146 u16String->resize(totalCharsRequired);
147 auto const sqlResult = SQLGetData(stmt, column, SQL_C_WCHAR, u16String->data(), *indicator, indicator);
149 assert(SQL_SUCCEEDED(sqlResult));
150 assert(std::cmp_equal(*indicator, totalCharsRequired *
sizeof(
char16_t)));
153 if constexpr (
sizeof(
typename StringType::value_type) == 1)
154 *result =
ToUtf8(*u16String);
155 else if constexpr (
sizeof(
typename StringType::value_type) == 4)
158 auto const u32String =
ToUtf32(*u16String);
159 *result = StringType {
160 (CharType
const*) u32String.data(),
161 (CharType
const*) u32String.data() + u32String.size(),
171 using StringTraits = SqlBasicStringOperations<StringType>;
172 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
174 if (*indicator != SQL_NULL_DATA && *indicator != SQL_NO_TOTAL)
176 auto const syntheticIndicator =
static_cast<SQLLEN
>(StringTraits::Size(result) *
sizeof(CharType));
177 StringTraits::PostProcessOutputColumn(result, syntheticIndicator);
182 return SQLBindCol(stmt,
185 static_cast<SQLPOINTER
>(u16String->data()),
186 static_cast<SQLLEN
>(u16String->size() *
sizeof(
char16_t)),
193template <
typename AnsiStringType>
194 requires SqlBasicStringBinderConcept<AnsiStringType, char>
195struct SqlDataBinder<AnsiStringType>
197 using ValueType = AnsiStringType;
198 using CharType = char;
199 using StringTraits = SqlBasicStringOperations<AnsiStringType>;
201 static constexpr auto ColumnType = StringTraits::ColumnType;
203 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
205 AnsiStringType
const& value,
206 SqlDataBinderCallback& cb)
noexcept
217 if (cb.ServerType() == SqlServerType::POSTGRESQL)
219 auto u16String = std::make_shared<std::u16string>(
ToUtf16(std::u8string_view {
220 reinterpret_cast<char8_t const*
>(StringTraits::Data(&value)), StringTraits::Size(&value) }));
221 cb.PlanPostExecuteCallback([u16String = u16String]() {});
222 auto const charCount = u16String->size();
223 auto const byteCount = charCount *
sizeof(char16_t);
225 static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_WLONGVARCHAR : SQL_WVARCHAR);
227 SQLLEN* indicator = cb.ProvideInputIndicator();
228 *indicator =
static_cast<SQLLEN
>(byteCount);
230 return SQLBindParameter(stmt,
237 (SQLPOINTER) u16String->data(),
238 static_cast<SQLLEN
>(byteCount),
242 auto const charCount = StringTraits::Size(&value);
243 auto const sqlType =
static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_LONGVARCHAR : SQL_VARCHAR);
245 SQLLEN* indicator = cb.ProvideInputIndicator();
246 *indicator =
static_cast<SQLLEN
>(charCount);
248 return SQLBindParameter(stmt,
255 (SQLPOINTER) StringTraits::Data(&value),
260 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN BatchInputParameter(SQLHSTMT stmt,
262 AnsiStringType
const* values,
264 SqlDataBinderCallback& cb)
noexcept
267 SQLLEN* indicators = cb.ProvideInputIndicators(rowCount);
268 for (
size_t i = 0; i < rowCount; ++i)
270 auto const len = StringTraits::Size(&values[i]);
271 indicators[i] =
static_cast<SQLLEN
>(len);
276 auto const sqlType =
static_cast<SQLSMALLINT
>(maxLen > SqlOptimalMaxColumnSize ? SQL_LONGVARCHAR : SQL_VARCHAR);
278 return SQLBindParameter(stmt,
286 sizeof(AnsiStringType),
303 static SQLRETURN BatchRowWiseInputParameter(SQLHSTMT stmt,
305 AnsiStringType
const* elem0,
306 std::size_t rowStride,
307 std::size_t rowCount,
308 SqlDataBinderCallback& cb)
noexcept
309 requires requires { AnsiStringType::Capacity; }
311 auto const* sourceBytes =
reinterpret_cast<std::byte const*
>(elem0);
312 auto*
const indicatorBytes = cb.ProvideBatchStagingBuffer(((rowCount - 1) * rowStride) +
sizeof(SQLLEN));
313 for (
auto const i: std::views::iota(std::size_t { 0 }, rowCount))
315 auto const& str = *
reinterpret_cast<AnsiStringType const*
>(sourceBytes + (i * rowStride));
316 *
reinterpret_cast<SQLLEN*
>(indicatorBytes + (i * rowStride)) =
static_cast<SQLLEN
>(StringTraits::Size(&str));
319 return BatchRowWiseBindInline(stmt, column, elem0,
reinterpret_cast<SQLLEN*
>(indicatorBytes));
329 static SQLRETURN BatchRowWiseBindInline(SQLHSTMT stmt,
331 AnsiStringType
const* elem0,
332 SQLLEN* indicators)
noexcept
333 requires requires { AnsiStringType::Capacity; }
335 return SQLBindParameter(stmt,
340 AnsiStringType::Capacity,
342 (SQLPOINTER) StringTraits::Data(elem0),
343 static_cast<SQLLEN
>(AnsiStringType::Capacity) + 1,
360 static SQLRETURN BatchRowWiseInputParameterOptional(SQLHSTMT stmt,
362 std::optional<AnsiStringType>
const* elem0,
363 std::size_t rowStride,
364 std::size_t rowCount,
365 SqlDataBinderCallback& cb)
noexcept
366 requires requires { AnsiStringType::Capacity; }
368 using OptionalType = std::optional<AnsiStringType>;
371 auto const valueOffset = detail::OptionalValueOffset<AnsiStringType>();
373 auto const* sourceBytes =
reinterpret_cast<std::byte const*
>(elem0);
374 auto*
const indicatorBytes = cb.ProvideBatchStagingBuffer(((rowCount - 1) * rowStride) +
sizeof(SQLLEN));
375 for (
auto const i: std::views::iota(std::size_t { 0 }, rowCount))
377 auto const& optional = *
reinterpret_cast<OptionalType const*
>(sourceBytes + (i * rowStride));
378 *
reinterpret_cast<SQLLEN*
>(indicatorBytes + (i * rowStride)) =
379 optional.has_value() ?
static_cast<SQLLEN
>(StringTraits::Size(std::addressof(*optional)))
380 : SQLLEN { SQL_NULL_DATA };
384 auto const* containedRow0 =
reinterpret_cast<AnsiStringType const*
>(sourceBytes + valueOffset);
385 return BatchRowWiseBindInline(stmt, column, containedRow0,
reinterpret_cast<SQLLEN*
>(indicatorBytes));
388 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN OutputColumn(
389 SQLHSTMT stmt, SQLUSMALLINT column, AnsiStringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
397 if (cb.ServerType() == SqlServerType::POSTGRESQL)
399 auto u16String = std::make_shared<std::u16string>();
400 u16String->resize(StringTraits::Size(result) != 0 ? StringTraits::Size(result) : 255);
402 cb.PlanPostProcessOutputColumn([stmt, column, result, indicator, u16String]() {
403 if (*indicator == SQL_NULL_DATA)
405 else if (*indicator == SQL_NO_TOTAL)
407 else if (std::cmp_less_equal(*indicator, u16String->size() *
sizeof(
char16_t)))
408 u16String->resize(
static_cast<size_t>(*indicator) /
sizeof(
char16_t));
412 auto const totalChars =
static_cast<size_t>(*indicator) /
sizeof(char16_t);
413 u16String->resize(totalChars + 1);
414 auto const rv = SQLGetData(stmt,
418 static_cast<SQLLEN
>((totalChars + 1) *
sizeof(
char16_t)),
421 assert(SQL_SUCCEEDED(rv));
422 u16String->resize(totalChars);
425 auto const u8String =
ToUtf8(*u16String);
428 StringTraits::Resize(result,
static_cast<SQLLEN
>(u8String.size()));
429 std::memcpy(StringTraits::Data(result), u8String.data(), StringTraits::Size(result));
431 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
432 if (*indicator != SQL_NULL_DATA && *indicator != SQL_NO_TOTAL)
434 auto const syntheticIndicator =
static_cast<SQLLEN
>(StringTraits::Size(result));
435 StringTraits::PostProcessOutputColumn(result, syntheticIndicator);
439 return SQLBindCol(stmt,
442 static_cast<SQLPOINTER
>(u16String->data()),
443 static_cast<SQLLEN
>(u16String->size() *
sizeof(
char16_t)),
447 if constexpr (
requires { AnsiStringType::Capacity; })
448 StringTraits::Resize(result, AnsiStringType::Capacity);
449 else if (StringTraits::Size(result) == 0)
450 StringTraits::Resize(result, 255);
452 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
453 cb.PlanPostProcessOutputColumn(
454 [indicator, result]() { StringTraits::PostProcessOutputColumn(result, *indicator); });
456 cb.PlanPostProcessOutputColumn(
457 [stmt, column, indicator, result]() { PostProcessOutputColumn(stmt, column, result, indicator); });
463 SQLLEN
const bufferLength = [&]() -> SQLLEN {
464 if constexpr (
requires { AnsiStringType::Capacity; })
465 return static_cast<SQLLEN
>(AnsiStringType::Capacity) + 1;
467 return static_cast<SQLLEN
>(StringTraits::Size(result));
470 return SQLBindCol(stmt, column, SQL_C_CHAR, (SQLPOINTER) StringTraits::Data(result), bufferLength, indicator);
473 static void PostProcessOutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, AnsiStringType* result, SQLLEN* indicator)
477 if (*indicator == SQL_NO_TOTAL)
480 StringTraits::Resize(result,
static_cast<SQLLEN
>(StringTraits::Size(result)) - 1);
482 else if (*indicator == SQL_NULL_DATA)
485 StringTraits::Resize(result, 0);
487 else if (*indicator <=
static_cast<SQLLEN
>(StringTraits::Size(result)))
489 StringTraits::Resize(result, *indicator);
496 auto const totalCharsRequired = *indicator;
497 StringTraits::Resize(result, totalCharsRequired + 1);
498 auto const sqlResult =
499 SQLGetData(stmt, column, SQL_C_CHAR, StringTraits::Data(result), totalCharsRequired + 1, indicator);
501 assert(SQL_SUCCEEDED(sqlResult));
502 assert(*indicator == totalCharsRequired);
503 StringTraits::Resize(result, totalCharsRequired);
508 static SQLRETURN GetColumn(SQLHSTMT stmt,
510 AnsiStringType* result,
512 SqlDataBinderCallback
const& cb)
noexcept
517 if (cb.ServerType() == SqlServerType::POSTGRESQL)
519 auto u16String = std::u16string {};
520 auto const sqlResult = detail::GetColumnUtf16(stmt, column, &u16String, indicator, cb);
521 if (!SQL_SUCCEEDED(sqlResult))
524 auto const u8String =
ToUtf8(u16String);
527 StringTraits::Resize(result,
static_cast<SQLLEN
>(u8String.size()));
528 std::memcpy(StringTraits::Data(result), u8String.data(), StringTraits::Size(result));
532 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
533 if (*indicator != SQL_NULL_DATA && *indicator != SQL_NO_TOTAL)
534 StringTraits::PostProcessOutputColumn(result,
static_cast<SQLLEN
>(StringTraits::Size(result)));
538 if constexpr (
requires { AnsiStringType::Capacity; })
540 StringTraits::Resize(result, AnsiStringType::Capacity);
544 SQLGetData(stmt, column, SQL_C_CHAR, StringTraits::Data(result), AnsiStringType::Capacity + 1, indicator);
545 if (rv == SQL_SUCCESS || rv == SQL_NO_DATA)
547 if (*indicator == SQL_NULL_DATA)
548 StringTraits::Resize(result, 0);
549 else if (*indicator != SQL_NO_TOTAL)
550 StringTraits::Resize(
551 result,
static_cast<SQLLEN
>((std::min) (AnsiStringType::Capacity,
static_cast<size_t>(*indicator))));
553 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
554 StringTraits::PostProcessOutputColumn(result, *indicator);
559 StringTraits::Reserve(result, 15);
560 size_t writeIndex = 0;
564 auto*
const bufferStart = StringTraits::Data(result) + writeIndex;
565 size_t const bufferSize = StringTraits::Size(result) - writeIndex;
567 SQLGetData(stmt, column, SQL_C_CHAR, bufferStart,
static_cast<SQLLEN
>(bufferSize), indicator);
573 if (*indicator != SQL_NULL_DATA)
575 StringTraits::Resize(result,
static_cast<SQLLEN
>(writeIndex) + *indicator);
576 *indicator =
static_cast<SQLLEN
>(StringTraits::Size(result));
579 case SQL_SUCCESS_WITH_INFO: {
581 if (*indicator == SQL_NO_TOTAL)
584 writeIndex += bufferSize - 1;
585 StringTraits::Resize(result,
static_cast<SQLLEN
>((2 * writeIndex) + 1));
587 else if (std::cmp_greater_equal(*indicator, bufferSize))
590 writeIndex += bufferSize - 1;
591 StringTraits::Resize(result,
static_cast<SQLLEN
>(writeIndex) + *indicator);
596 StringTraits::Resize(result,
static_cast<SQLLEN
>(writeIndex) + *indicator - 1);
602 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
603 StringTraits::PostProcessOutputColumn(result, *indicator);
610 static LIGHTWEIGHT_FORCE_INLINE std::string_view Inspect(AnsiStringType
const& value)
noexcept
612 return { StringTraits::Data(&value), StringTraits::Size(&value) };
617template <
typename Utf16StringType>
618 requires(SqlBasicStringBinderConcept<Utf16StringType, char16_t>
619 || (SqlBasicStringBinderConcept<Utf16StringType, unsigned short>)
620 || (SqlBasicStringBinderConcept<Utf16StringType, wchar_t> &&
sizeof(
wchar_t) == 2))
621struct SqlDataBinder<Utf16StringType>
623 using ValueType = Utf16StringType;
624 using CharType = std::remove_cvref_t<decltype(std::declval<Utf16StringType>()[0])>;
625 using StringTraits = SqlBasicStringOperations<Utf16StringType>;
627 static constexpr auto ColumnType = StringTraits::ColumnType;
629 static constexpr auto CType = SQL_C_WCHAR;
631 static SQLRETURN InputParameter(SQLHSTMT stmt,
633 Utf16StringType
const& value,
634 SqlDataBinderCallback& cb)
noexcept
639 using CharType = StringTraits::CharType;
640 auto const* data = StringTraits::Data(&value);
641 auto const sizeInBytes = StringTraits::Size(&value) *
sizeof(CharType);
642 auto const charCount = StringTraits::Size(&value);
643 auto const sqlType =
static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_WLONGVARCHAR : SQL_WVARCHAR);
645 SQLLEN* indicator = cb.ProvideInputIndicator();
646 *indicator =
static_cast<SQLLEN
>(sizeInBytes);
648 return SQLBindParameter(stmt,
656 static_cast<SQLLEN
>(sizeInBytes),
660 static SQLRETURN OutputColumn(
661 SQLHSTMT stmt, SQLUSMALLINT column, Utf16StringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
663 if constexpr (
requires { Utf16StringType::Capacity; })
664 StringTraits::Resize(result, Utf16StringType::Capacity);
665 else if (StringTraits::Size(result) == 0)
666 StringTraits::Resize(result, 255);
668 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
670 cb.PlanPostProcessOutputColumn(
671 [indicator, result]() { StringTraits::PostProcessOutputColumn(result, *indicator); });
675 cb.PlanPostProcessOutputColumn([stmt, column, indicator, result]() {
678 if (*indicator == SQL_NULL_DATA)
679 StringTraits::Resize(result, 0);
680 else if (*indicator == SQL_NO_TOTAL)
682 else if (*indicator <=
static_cast<SQLLEN
>(result->size() *
sizeof(
char16_t)))
683 result->resize(
static_cast<size_t>(*indicator) /
sizeof(
char16_t));
686 auto const totalCharsRequired =
static_cast<size_t>(*indicator) /
sizeof(char16_t);
687 *indicator +=
sizeof(char16_t);
688 result->resize(totalCharsRequired);
689 auto const sqlResult = SQLGetData(stmt, column, SQL_C_WCHAR, result->data(), *indicator, indicator);
691 assert(SQL_SUCCEEDED(sqlResult));
692 assert(std::cmp_equal(*indicator, totalCharsRequired *
sizeof(
char16_t)));
696 return SQLBindCol(stmt,
699 (SQLPOINTER) StringTraits::Data(result),
700 (SQLLEN) ((StringTraits::Size(result) + 1) *
sizeof(CharType)),
704 static SQLRETURN GetColumn(SQLHSTMT stmt,
706 Utf16StringType* result,
708 SqlDataBinderCallback
const& cb)
noexcept
710 return detail::GetColumnUtf16(stmt, column, result, indicator, cb);
713 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(Utf16StringType
const& value)
noexcept
715 auto u8String =
ToUtf8(detail::SqlViewHelper<Utf16StringType>::View(value));
716 return std::string(
reinterpret_cast<char const*
>(u8String.data()), u8String.size());
721template <
typename Utf32StringType>
722 requires(SqlBasicStringBinderConcept<Utf32StringType, char32_t>
723 || (SqlBasicStringBinderConcept<Utf32StringType, uint32_t>)
724 || (SqlBasicStringBinderConcept<Utf32StringType, wchar_t> &&
sizeof(
wchar_t) == 4))
725struct SqlDataBinder<Utf32StringType>
727 using ValueType = Utf32StringType;
728 using CharType = Utf32StringType::value_type;
729 using StringTraits = SqlBasicStringOperations<Utf32StringType>;
731 static constexpr auto ColumnType = StringTraits::ColumnType;
733 static SQLRETURN InputParameter(SQLHSTMT stmt,
735 Utf32StringType
const& value,
736 SqlDataBinderCallback& cb)
noexcept
740 auto u16String = std::make_shared<std::u16string>(
ToUtf16(detail::SqlViewHelper<Utf32StringType>::View(value)));
741 cb.PlanPostExecuteCallback([u16String = u16String]() {});
742 auto const* data = u16String->data();
743 auto const charCount = u16String->size();
744 auto const sizeInBytes = u16String->size() *
sizeof(char16_t);
745 auto const CType = SQLSMALLINT { SQL_C_WCHAR };
746 auto const sqlType =
static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_WLONGVARCHAR : SQL_WVARCHAR);
748 SQLLEN* indicator = cb.ProvideInputIndicator();
749 *indicator =
static_cast<SQLLEN
>(sizeInBytes);
751 return SQLBindParameter(stmt,
759 static_cast<SQLLEN
>(sizeInBytes),
763 static SQLRETURN OutputColumn(
764 SQLHSTMT stmt, SQLUSMALLINT column, Utf32StringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
766 return detail::BindOutputColumnNonUtf16Unicode<Utf32StringType>(stmt, column, result, indicator, cb);
769 static SQLRETURN GetColumn(SQLHSTMT stmt,
771 Utf32StringType* result,
773 SqlDataBinderCallback
const& cb)
noexcept
775 auto u16String = std::u16string {};
776 auto const sqlResult = detail::GetColumnUtf16(stmt, column, &u16String, indicator, cb);
777 if (!SQL_SUCCEEDED(sqlResult))
780 auto const u32String =
ToUtf32(u16String);
781 StringTraits::Resize(result,
static_cast<SQLLEN
>(u32String.size()));
782 std::copy_n((CharType
const*) u32String.data(), u32String.size(), StringTraits::Data(result));
787 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(Utf32StringType
const& value)
noexcept
789 auto u8String =
ToUtf8(detail::SqlViewHelper<Utf32StringType>::View(value));
790 return std::string(
reinterpret_cast<char const*
>(u8String.data()), u8String.size());
795template <
typename Utf8StringType>
796 requires SqlBasicStringBinderConcept<Utf8StringType, char8_t>
797struct SqlDataBinder<Utf8StringType>
799 using ValueType = Utf8StringType;
800 using CharType = char8_t;
801 using StringTraits = SqlBasicStringOperations<Utf8StringType>;
803 static constexpr auto ColumnType = StringTraits::ColumnType;
805 static SQLRETURN InputParameter(SQLHSTMT stmt,
807 Utf8StringType
const& value,
808 SqlDataBinderCallback& cb)
noexcept
812 auto u16String = std::make_shared<std::u16string>(
ToUtf16(detail::SqlViewHelper<Utf8StringType>::View(value)));
813 cb.PlanPostExecuteCallback([u16String = u16String]() {});
815 auto const CType = SQL_C_WCHAR;
816 auto const charCount = u16String->size();
817 auto const byteCount = u16String->size() *
sizeof(char16_t);
818 auto const sqlType =
static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_WLONGVARCHAR : SQL_WVARCHAR);
820 SQLLEN* indicator = cb.ProvideInputIndicator();
821 *indicator =
static_cast<SQLLEN
>(byteCount);
823 return SQLBindParameter(stmt,
830 (SQLPOINTER) u16String->data(),
831 static_cast<SQLLEN
>(byteCount),
835 static SQLRETURN OutputColumn(
836 SQLHSTMT stmt, SQLUSMALLINT column, Utf8StringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
838 return detail::BindOutputColumnNonUtf16Unicode<Utf8StringType>(stmt, column, result, indicator, cb);
841 static SQLRETURN GetColumn(SQLHSTMT stmt,
843 Utf8StringType* result,
845 SqlDataBinderCallback
const& cb)
noexcept
847 auto u16String = std::u16string {};
848 u16String.resize(result->size());
849 auto const sqlReturn = detail::GetColumnUtf16(stmt, column, &u16String, indicator, cb);
850 if (SQL_SUCCEEDED(sqlReturn))
851 *result =
ToUtf8(u16String);
855 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(Utf8StringType
const& value)
noexcept
858 return std::string(
reinterpret_cast<char const*
>(value.data()), value.size());
T ToUtf32(std::u8string_view u8InputString)
LIGHTWEIGHT_API std::u8string ToUtf8(std::u32string_view u32InputString)
std::u16string ToUtf16(std::basic_string_view< T > const u32InputString)