6#include "UnicodeConverter.hpp"
24constexpr inline std::size_t SqlOptimalMaxColumnSize = 4000;
40 template <auto CType,
typename ArrayType,
typename GetData>
41 requires requires(ArrayType& arr) {
42 { arr.data() } -> std::convertible_to<typename ArrayType::value_type*>;
43 { arr.size() } -> std::convertible_to<std::size_t>;
44 { arr.resize(std::declval<std::size_t>()) };
46 SQLRETURN ReadRawColumnArrayData(GetData
const& getData, ArrayType* result, SQLLEN* indicator)
noexcept
48 using CharType = ArrayType::value_type;
53 constexpr size_t TrailingNulTerminators = CType == SQL_C_BINARY ? 0 : 1;
63 auto sqlResult = getData(
64 static_cast<SQLPOINTER
>(result->data()),
static_cast<SQLLEN
>(result->size() *
sizeof(CharType)), indicator);
66 if (sqlResult == SQL_SUCCESS || sqlResult == SQL_NO_DATA)
69 if (*indicator == SQL_NULL_DATA)
71 else if (*indicator < 0)
74 result->resize(
static_cast<size_t>(*indicator) /
sizeof(CharType));
78 if (sqlResult == SQL_SUCCESS_WITH_INFO && *indicator < 0 && *indicator != SQL_NO_TOTAL)
80 if (*indicator != SQL_NULL_DATA)
86 if (sqlResult == SQL_SUCCESS_WITH_INFO && *indicator != SQL_NO_TOTAL
87 && (
static_cast<size_t>(*indicator) /
sizeof(CharType)) + TrailingNulTerminators > result->size())
93 auto const totalCharCount =
static_cast<size_t>(*indicator) /
sizeof(CharType);
94 auto const charsWritten = result->size() - TrailingNulTerminators;
95 result->resize(totalCharCount + TrailingNulTerminators);
96 auto* bufferCont = result->data() + charsWritten;
97 auto const bufferCharsAvailable = (totalCharCount + TrailingNulTerminators) - charsWritten;
98 sqlResult = getData(bufferCont,
static_cast<SQLLEN
>(bufferCharsAvailable *
sizeof(CharType)), indicator);
99 if (SQL_SUCCEEDED(sqlResult))
103 result->resize(charsWritten + (
static_cast<size_t>(*indicator) /
sizeof(CharType)));
108 size_t writeIndex = 0;
110 size_t lastTransferChars = result->size();
111 while (sqlResult == SQL_SUCCESS_WITH_INFO && *indicator == SQL_NO_TOTAL)
114 writeIndex += lastTransferChars - TrailingNulTerminators;
115 result->resize(result->size() * 2);
116 auto*
const bufferStart = result->data() + writeIndex;
117 lastTransferChars = result->size() - writeIndex;
118 sqlResult = getData(bufferStart,
static_cast<SQLLEN
>(lastTransferChars *
sizeof(CharType)), indicator);
122 if (writeIndex > 0 && SQL_SUCCEEDED(sqlResult) && *indicator != SQL_NULL_DATA && *indicator != SQL_NO_TOTAL)
126 result->resize(writeIndex + (
static_cast<size_t>(*indicator) /
sizeof(CharType)));
144 template <auto CType,
typename ArrayType>
145 SQLRETURN GetRawColumnArrayData(SQLHSTMT stmt, SQLUSMALLINT column, ArrayType* result, SQLLEN* indicator)
noexcept
147 return ReadRawColumnArrayData<CType>(
148 [stmt, column](SQLPOINTER buffer, SQLLEN bufferBytes, SQLLEN* reported)
noexcept {
149 return SQLGetData(stmt, column, CType, buffer, bufferBytes, reported);
167 inline size_t InitialCharBufferSize(SQLHSTMT stmt, SQLUSMALLINT column)
noexcept
169 constexpr size_t DefaultSize = 15;
172 if (!SQL_SUCCEEDED(SQLColAttribute(stmt, column, SQL_DESC_CONCISE_TYPE,
nullptr, 0,
nullptr, &sqlType)))
178 case SQL_LONGVARCHAR:
181 case SQL_WLONGVARCHAR:
184 case SQL_LONGVARBINARY:
190 SQLLEN displaySize {};
191 if (!SQL_SUCCEEDED(SQLColAttribute(stmt, column, SQL_DESC_DISPLAY_SIZE,
nullptr, 0,
nullptr, &displaySize)))
193 return (std::max) (DefaultSize,
static_cast<size_t>((std::max) (displaySize, SQLLEN { 0 })) + 1);
196 template <
typename Utf16StringType>
197 SQLRETURN GetColumnUtf16(SQLHSTMT stmt,
199 Utf16StringType* result,
201 SqlDataBinderCallback
const& )
noexcept
203 if constexpr (
requires { Utf16StringType::Capacity; })
204 result->resize(Utf16StringType::Capacity);
205 else if (result->size() == 0)
208 return GetRawColumnArrayData<SQL_C_WCHAR>(stmt, column, result, indicator);
211 template <
typename StringType>
212 SQLRETURN BindOutputColumnNonUtf16Unicode(
213 SQLHSTMT stmt, SQLUSMALLINT column, StringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
215 using CharType = StringType::value_type;
217 auto u16String = std::make_shared<std::u16string>();
218 if (!result->empty())
219 u16String->resize(result->size());
221 u16String->resize(255);
223 cb.PlanPostProcessOutputColumn([stmt, column, result, indicator, u16String = u16String]() {
224 if (*indicator == SQL_NULL_DATA)
226 else if (*indicator == SQL_NO_TOTAL)
228 else if (std::cmp_less_equal(*indicator, u16String->size() *
sizeof(
char16_t)))
229 u16String->resize(
static_cast<size_t>(*indicator) /
sizeof(
char16_t));
232 auto const totalCharsRequired =
static_cast<size_t>(*indicator) /
sizeof(char16_t);
233 *indicator +=
sizeof(char16_t);
234 u16String->resize(totalCharsRequired);
235 auto const sqlResult = SQLGetData(stmt, column, SQL_C_WCHAR, u16String->data(), *indicator, indicator);
237 assert(SQL_SUCCEEDED(sqlResult));
238 assert(std::cmp_equal(*indicator, totalCharsRequired *
sizeof(
char16_t)));
241 if constexpr (
sizeof(
typename StringType::value_type) == 1)
242 *result =
ToUtf8(*u16String);
243 else if constexpr (
sizeof(
typename StringType::value_type) == 4)
246 auto const u32String =
ToUtf32(*u16String);
247 *result = StringType {
248 (CharType
const*) u32String.data(),
249 (CharType
const*) u32String.data() + u32String.size(),
259 using StringTraits = SqlBasicStringOperations<StringType>;
260 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
262 if (*indicator != SQL_NULL_DATA && *indicator != SQL_NO_TOTAL)
264 auto const syntheticIndicator =
static_cast<SQLLEN
>(StringTraits::Size(result) *
sizeof(CharType));
265 StringTraits::PostProcessOutputColumn(result, syntheticIndicator);
270 return SQLBindCol(stmt,
273 static_cast<SQLPOINTER
>(u16String->data()),
274 static_cast<SQLLEN
>(u16String->size() *
sizeof(
char16_t)),
281template <
typename AnsiStringType>
282 requires SqlBasicStringBinderConcept<AnsiStringType, char>
283struct SqlDataBinder<AnsiStringType>
285 using ValueType = AnsiStringType;
286 using CharType = char;
287 using StringTraits = SqlBasicStringOperations<AnsiStringType>;
289 static constexpr auto ColumnType = StringTraits::ColumnType;
291 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
293 AnsiStringType
const& value,
294 SqlDataBinderCallback& cb)
noexcept
305 if (cb.ServerType() == SqlServerType::POSTGRESQL)
307 auto u16String = std::make_shared<std::u16string>(
ToUtf16(std::u8string_view {
308 reinterpret_cast<char8_t const*
>(StringTraits::Data(&value)), StringTraits::Size(&value) }));
309 cb.PlanPostExecuteCallback([u16String = u16String]() {});
310 auto const charCount = u16String->size();
311 auto const byteCount = charCount *
sizeof(char16_t);
313 static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_WLONGVARCHAR : SQL_WVARCHAR);
315 SQLLEN* indicator = cb.ProvideInputIndicator();
316 *indicator =
static_cast<SQLLEN
>(byteCount);
318 return SQLBindParameter(stmt,
323 detail::NonZeroColumnSize(charCount),
325 (SQLPOINTER) u16String->data(),
326 static_cast<SQLLEN
>(byteCount),
330 auto const charCount = StringTraits::Size(&value);
331 auto const sqlType =
static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_LONGVARCHAR : SQL_VARCHAR);
333 SQLLEN* indicator = cb.ProvideInputIndicator();
334 *indicator =
static_cast<SQLLEN
>(charCount);
336 return SQLBindParameter(stmt,
341 detail::NonZeroColumnSize(charCount),
343 (SQLPOINTER) StringTraits::Data(&value),
348 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN BatchInputParameter(SQLHSTMT stmt,
350 AnsiStringType
const* values,
352 SqlDataBinderCallback& cb)
noexcept
355 SQLLEN* indicators = cb.ProvideInputIndicators(rowCount);
356 for (
size_t i = 0; i < rowCount; ++i)
358 auto const len = StringTraits::Size(&values[i]);
359 indicators[i] =
static_cast<SQLLEN
>(len);
364 auto const sqlType =
static_cast<SQLSMALLINT
>(maxLen > SqlOptimalMaxColumnSize ? SQL_LONGVARCHAR : SQL_VARCHAR);
366 return SQLBindParameter(stmt,
371 detail::NonZeroColumnSize(maxLen),
374 sizeof(AnsiStringType),
391 static SQLRETURN BatchRowWiseInputParameter(SQLHSTMT stmt,
393 AnsiStringType
const* elem0,
394 std::size_t rowStride,
395 std::size_t rowCount,
396 SqlDataBinderCallback& cb)
noexcept
397 requires requires { AnsiStringType::Capacity; }
399 auto const* sourceBytes =
reinterpret_cast<std::byte const*
>(elem0);
400 auto*
const indicatorBytes = cb.ProvideBatchStagingBuffer(((rowCount - 1) * rowStride) +
sizeof(SQLLEN));
401 for (
auto const i: std::views::iota(std::size_t { 0 }, rowCount))
403 auto const& str = *
reinterpret_cast<AnsiStringType const*
>(sourceBytes + (i * rowStride));
404 *
reinterpret_cast<SQLLEN*
>(indicatorBytes + (i * rowStride)) =
static_cast<SQLLEN
>(StringTraits::Size(&str));
407 return BatchRowWiseBindInline(stmt, column, elem0,
reinterpret_cast<SQLLEN*
>(indicatorBytes));
417 static SQLRETURN BatchRowWiseBindInline(SQLHSTMT stmt,
419 AnsiStringType
const* elem0,
420 SQLLEN* indicators)
noexcept
421 requires requires { AnsiStringType::Capacity; }
423 return SQLBindParameter(stmt,
428 AnsiStringType::Capacity,
430 (SQLPOINTER) StringTraits::Data(elem0),
431 static_cast<SQLLEN
>(AnsiStringType::Capacity) + 1,
448 static SQLRETURN BatchRowWiseInputParameterOptional(SQLHSTMT stmt,
450 std::optional<AnsiStringType>
const* elem0,
451 std::size_t rowStride,
452 std::size_t rowCount,
453 SqlDataBinderCallback& cb)
noexcept
454 requires requires { AnsiStringType::Capacity; }
456 using OptionalType = std::optional<AnsiStringType>;
459 auto const valueOffset = detail::OptionalValueOffset<AnsiStringType>();
461 auto const* sourceBytes =
reinterpret_cast<std::byte const*
>(elem0);
462 auto*
const indicatorBytes = cb.ProvideBatchStagingBuffer(((rowCount - 1) * rowStride) +
sizeof(SQLLEN));
463 for (
auto const i: std::views::iota(std::size_t { 0 }, rowCount))
465 auto const& optional = *
reinterpret_cast<OptionalType const*
>(sourceBytes + (i * rowStride));
466 *
reinterpret_cast<SQLLEN*
>(indicatorBytes + (i * rowStride)) =
467 optional.has_value() ?
static_cast<SQLLEN
>(StringTraits::Size(std::addressof(*optional)))
468 : SQLLEN { SQL_NULL_DATA };
472 auto const* containedRow0 =
reinterpret_cast<AnsiStringType const*
>(sourceBytes + valueOffset);
473 return BatchRowWiseBindInline(stmt, column, containedRow0,
reinterpret_cast<SQLLEN*
>(indicatorBytes));
476 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN OutputColumn(
477 SQLHSTMT stmt, SQLUSMALLINT column, AnsiStringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
485 if (cb.ServerType() == SqlServerType::POSTGRESQL)
487 auto u16String = std::make_shared<std::u16string>();
488 u16String->resize(StringTraits::Size(result) != 0 ? StringTraits::Size(result) : 255);
490 cb.PlanPostProcessOutputColumn([stmt, column, result, indicator, u16String]() {
491 if (*indicator == SQL_NULL_DATA)
493 else if (*indicator == SQL_NO_TOTAL)
495 else if (std::cmp_less_equal(*indicator, u16String->size() *
sizeof(
char16_t)))
496 u16String->resize(
static_cast<size_t>(*indicator) /
sizeof(
char16_t));
500 auto const totalChars =
static_cast<size_t>(*indicator) /
sizeof(char16_t);
501 u16String->resize(totalChars + 1);
502 auto const rv = SQLGetData(stmt,
506 static_cast<SQLLEN
>((totalChars + 1) *
sizeof(
char16_t)),
509 assert(SQL_SUCCEEDED(rv));
510 u16String->resize(totalChars);
513 auto const u8String =
ToUtf8(*u16String);
516 StringTraits::Resize(result,
static_cast<SQLLEN
>(u8String.size()));
517 std::memcpy(StringTraits::Data(result), u8String.data(), StringTraits::Size(result));
519 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
520 if (*indicator != SQL_NULL_DATA && *indicator != SQL_NO_TOTAL)
522 auto const syntheticIndicator =
static_cast<SQLLEN
>(StringTraits::Size(result));
523 StringTraits::PostProcessOutputColumn(result, syntheticIndicator);
527 return SQLBindCol(stmt,
530 static_cast<SQLPOINTER
>(u16String->data()),
531 static_cast<SQLLEN
>(u16String->size() *
sizeof(
char16_t)),
535 if constexpr (
requires { AnsiStringType::Capacity; })
536 StringTraits::Resize(result, AnsiStringType::Capacity);
537 else if (StringTraits::Size(result) == 0)
538 StringTraits::Resize(result, 255);
540 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
541 cb.PlanPostProcessOutputColumn(
542 [indicator, result]() { StringTraits::PostProcessOutputColumn(result, *indicator); });
544 cb.PlanPostProcessOutputColumn(
545 [stmt, column, indicator, result]() { PostProcessOutputColumn(stmt, column, result, indicator); });
551 SQLLEN
const bufferLength = [&]() -> SQLLEN {
552 if constexpr (
requires { AnsiStringType::Capacity; })
553 return static_cast<SQLLEN
>(AnsiStringType::Capacity) + 1;
555 return static_cast<SQLLEN
>(StringTraits::Size(result));
558 return SQLBindCol(stmt, column, SQL_C_CHAR, (SQLPOINTER) StringTraits::Data(result), bufferLength, indicator);
561 static void PostProcessOutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, AnsiStringType* result, SQLLEN* indicator)
565 if (*indicator == SQL_NO_TOTAL)
568 StringTraits::Resize(result,
static_cast<SQLLEN
>(StringTraits::Size(result)) - 1);
570 else if (*indicator == SQL_NULL_DATA)
573 StringTraits::Resize(result, 0);
575 else if (*indicator <=
static_cast<SQLLEN
>(StringTraits::Size(result)))
577 StringTraits::Resize(result, *indicator);
584 auto const totalCharsRequired = *indicator;
585 StringTraits::Resize(result, totalCharsRequired + 1);
586 auto const sqlResult =
587 SQLGetData(stmt, column, SQL_C_CHAR, StringTraits::Data(result), totalCharsRequired + 1, indicator);
589 assert(SQL_SUCCEEDED(sqlResult));
590 assert(*indicator == totalCharsRequired);
591 StringTraits::Resize(result, totalCharsRequired);
596 static SQLRETURN GetColumn(SQLHSTMT stmt,
598 AnsiStringType* result,
600 SqlDataBinderCallback
const& cb)
noexcept
605 if (cb.ServerType() == SqlServerType::POSTGRESQL)
607 auto u16String = std::u16string {};
608 auto const sqlResult = detail::GetColumnUtf16(stmt, column, &u16String, indicator, cb);
609 if (!SQL_SUCCEEDED(sqlResult))
612 auto const u8String =
ToUtf8(u16String);
615 StringTraits::Resize(result,
static_cast<SQLLEN
>(u8String.size()));
616 std::memcpy(StringTraits::Data(result), u8String.data(), StringTraits::Size(result));
620 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
621 if (*indicator != SQL_NULL_DATA && *indicator != SQL_NO_TOTAL)
622 StringTraits::PostProcessOutputColumn(result,
static_cast<SQLLEN
>(StringTraits::Size(result)));
626 if constexpr (
requires { AnsiStringType::Capacity; })
628 StringTraits::Resize(result, AnsiStringType::Capacity);
632 SQLGetData(stmt, column, SQL_C_CHAR, StringTraits::Data(result), AnsiStringType::Capacity + 1, indicator);
633 if (rv == SQL_SUCCESS || rv == SQL_NO_DATA)
635 if (*indicator == SQL_NULL_DATA)
636 StringTraits::Resize(result, 0);
637 else if (*indicator != SQL_NO_TOTAL)
638 StringTraits::Resize(
639 result,
static_cast<SQLLEN
>((std::min) (AnsiStringType::Capacity,
static_cast<size_t>(*indicator))));
641 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
642 StringTraits::PostProcessOutputColumn(result, *indicator);
647 StringTraits::Reserve(result, detail::InitialCharBufferSize(stmt, column));
648 size_t writeIndex = 0;
652 auto*
const bufferStart = StringTraits::Data(result) + writeIndex;
653 size_t const bufferSize = StringTraits::Size(result) - writeIndex;
655 SQLGetData(stmt, column, SQL_C_CHAR, bufferStart,
static_cast<SQLLEN
>(bufferSize), indicator);
661 if (*indicator != SQL_NULL_DATA)
663 StringTraits::Resize(result,
static_cast<SQLLEN
>(writeIndex) + *indicator);
664 *indicator =
static_cast<SQLLEN
>(StringTraits::Size(result));
667 case SQL_SUCCESS_WITH_INFO: {
669 if (*indicator == SQL_NO_TOTAL)
672 writeIndex += bufferSize - 1;
673 StringTraits::Resize(result,
static_cast<SQLLEN
>((2 * writeIndex) + 1));
675 else if (std::cmp_greater_equal(*indicator, bufferSize))
678 writeIndex += bufferSize - 1;
679 StringTraits::Resize(result,
static_cast<SQLLEN
>(writeIndex) + *indicator);
684 StringTraits::Resize(result,
static_cast<SQLLEN
>(writeIndex) + *indicator - 1);
690 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
691 StringTraits::PostProcessOutputColumn(result, *indicator);
698 static LIGHTWEIGHT_FORCE_INLINE std::string_view Inspect(AnsiStringType
const& value)
noexcept
700 return { StringTraits::Data(&value), StringTraits::Size(&value) };
705template <
typename Utf16StringType>
706 requires(SqlBasicStringBinderConcept<Utf16StringType, char16_t>
707 || (SqlBasicStringBinderConcept<Utf16StringType, unsigned short>)
708 || (SqlBasicStringBinderConcept<Utf16StringType, wchar_t> &&
sizeof(
wchar_t) == 2))
709struct SqlDataBinder<Utf16StringType>
711 using ValueType = Utf16StringType;
712 using CharType = std::remove_cvref_t<decltype(std::declval<Utf16StringType>()[0])>;
713 using StringTraits = SqlBasicStringOperations<Utf16StringType>;
715 static constexpr auto ColumnType = StringTraits::ColumnType;
717 static constexpr auto CType = SQL_C_WCHAR;
719 static SQLRETURN InputParameter(SQLHSTMT stmt,
721 Utf16StringType
const& value,
722 SqlDataBinderCallback& cb)
noexcept
727 using CharType = StringTraits::CharType;
728 auto const* data = StringTraits::Data(&value);
729 auto const sizeInBytes = StringTraits::Size(&value) *
sizeof(CharType);
730 auto const charCount = StringTraits::Size(&value);
731 auto const sqlType =
static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_WLONGVARCHAR : SQL_WVARCHAR);
733 SQLLEN* indicator = cb.ProvideInputIndicator();
734 *indicator =
static_cast<SQLLEN
>(sizeInBytes);
736 return SQLBindParameter(stmt,
741 detail::NonZeroColumnSize(charCount),
744 static_cast<SQLLEN
>(sizeInBytes),
748 static SQLRETURN OutputColumn(
749 SQLHSTMT stmt, SQLUSMALLINT column, Utf16StringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
751 if constexpr (
requires { Utf16StringType::Capacity; })
752 StringTraits::Resize(result, Utf16StringType::Capacity);
753 else if (StringTraits::Size(result) == 0)
754 StringTraits::Resize(result, 255);
756 if constexpr (
requires { StringTraits::PostProcessOutputColumn(result, *indicator); })
758 cb.PlanPostProcessOutputColumn(
759 [indicator, result]() { StringTraits::PostProcessOutputColumn(result, *indicator); });
763 cb.PlanPostProcessOutputColumn([stmt, column, indicator, result]() {
766 if (*indicator == SQL_NULL_DATA)
767 StringTraits::Resize(result, 0);
768 else if (*indicator == SQL_NO_TOTAL)
770 else if (*indicator <=
static_cast<SQLLEN
>(result->size() *
sizeof(
char16_t)))
771 result->resize(
static_cast<size_t>(*indicator) /
sizeof(
char16_t));
774 auto const totalCharsRequired =
static_cast<size_t>(*indicator) /
sizeof(char16_t);
775 *indicator +=
sizeof(char16_t);
776 result->resize(totalCharsRequired);
777 auto const sqlResult = SQLGetData(stmt, column, SQL_C_WCHAR, result->data(), *indicator, indicator);
779 assert(SQL_SUCCEEDED(sqlResult));
780 assert(std::cmp_equal(*indicator, totalCharsRequired *
sizeof(
char16_t)));
784 return SQLBindCol(stmt,
787 (SQLPOINTER) StringTraits::Data(result),
788 (SQLLEN) ((StringTraits::Size(result) + 1) *
sizeof(CharType)),
792 static SQLRETURN GetColumn(SQLHSTMT stmt,
794 Utf16StringType* result,
796 SqlDataBinderCallback
const& cb)
noexcept
798 return detail::GetColumnUtf16(stmt, column, result, indicator, cb);
801 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(Utf16StringType
const& value)
noexcept
803 auto u8String =
ToUtf8(detail::SqlViewHelper<Utf16StringType>::View(value));
804 return std::string(
reinterpret_cast<char const*
>(u8String.data()), u8String.size());
809template <
typename Utf32StringType>
810 requires(SqlBasicStringBinderConcept<Utf32StringType, char32_t>
811 || (SqlBasicStringBinderConcept<Utf32StringType, uint32_t>)
812 || (SqlBasicStringBinderConcept<Utf32StringType, wchar_t> &&
sizeof(
wchar_t) == 4))
813struct SqlDataBinder<Utf32StringType>
815 using ValueType = Utf32StringType;
816 using CharType = Utf32StringType::value_type;
817 using StringTraits = SqlBasicStringOperations<Utf32StringType>;
819 static constexpr auto ColumnType = StringTraits::ColumnType;
821 static SQLRETURN InputParameter(SQLHSTMT stmt,
823 Utf32StringType
const& value,
824 SqlDataBinderCallback& cb)
noexcept
828 auto u16String = std::make_shared<std::u16string>(
ToUtf16(detail::SqlViewHelper<Utf32StringType>::View(value)));
829 cb.PlanPostExecuteCallback([u16String = u16String]() {});
830 auto const* data = u16String->data();
831 auto const charCount = u16String->size();
832 auto const sizeInBytes = u16String->size() *
sizeof(char16_t);
833 auto const CType = SQLSMALLINT { SQL_C_WCHAR };
834 auto const sqlType =
static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_WLONGVARCHAR : SQL_WVARCHAR);
836 SQLLEN* indicator = cb.ProvideInputIndicator();
837 *indicator =
static_cast<SQLLEN
>(sizeInBytes);
839 return SQLBindParameter(stmt,
844 detail::NonZeroColumnSize(charCount),
847 static_cast<SQLLEN
>(sizeInBytes),
851 static SQLRETURN OutputColumn(
852 SQLHSTMT stmt, SQLUSMALLINT column, Utf32StringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
854 return detail::BindOutputColumnNonUtf16Unicode<Utf32StringType>(stmt, column, result, indicator, cb);
857 static SQLRETURN GetColumn(SQLHSTMT stmt,
859 Utf32StringType* result,
861 SqlDataBinderCallback
const& cb)
noexcept
863 auto u16String = std::u16string {};
864 auto const sqlResult = detail::GetColumnUtf16(stmt, column, &u16String, indicator, cb);
865 if (!SQL_SUCCEEDED(sqlResult))
868 auto const u32String =
ToUtf32(u16String);
869 StringTraits::Resize(result,
static_cast<SQLLEN
>(u32String.size()));
870 std::copy_n((CharType
const*) u32String.data(), u32String.size(), StringTraits::Data(result));
875 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(Utf32StringType
const& value)
noexcept
877 auto u8String =
ToUtf8(detail::SqlViewHelper<Utf32StringType>::View(value));
878 return std::string(
reinterpret_cast<char const*
>(u8String.data()), u8String.size());
883template <
typename Utf8StringType>
884 requires SqlBasicStringBinderConcept<Utf8StringType, char8_t>
885struct SqlDataBinder<Utf8StringType>
887 using ValueType = Utf8StringType;
888 using CharType = char8_t;
889 using StringTraits = SqlBasicStringOperations<Utf8StringType>;
891 static constexpr auto ColumnType = StringTraits::ColumnType;
893 static SQLRETURN InputParameter(SQLHSTMT stmt,
895 Utf8StringType
const& value,
896 SqlDataBinderCallback& cb)
noexcept
900 auto u16String = std::make_shared<std::u16string>(
ToUtf16(detail::SqlViewHelper<Utf8StringType>::View(value)));
901 cb.PlanPostExecuteCallback([u16String = u16String]() {});
903 auto const CType = SQL_C_WCHAR;
904 auto const charCount = u16String->size();
905 auto const byteCount = u16String->size() *
sizeof(char16_t);
906 auto const sqlType =
static_cast<SQLSMALLINT
>(charCount > SqlOptimalMaxColumnSize ? SQL_WLONGVARCHAR : SQL_WVARCHAR);
908 SQLLEN* indicator = cb.ProvideInputIndicator();
909 *indicator =
static_cast<SQLLEN
>(byteCount);
911 return SQLBindParameter(stmt,
916 detail::NonZeroColumnSize(charCount),
918 (SQLPOINTER) u16String->data(),
919 static_cast<SQLLEN
>(byteCount),
923 static SQLRETURN OutputColumn(
924 SQLHSTMT stmt, SQLUSMALLINT column, Utf8StringType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
noexcept
926 return detail::BindOutputColumnNonUtf16Unicode<Utf8StringType>(stmt, column, result, indicator, cb);
929 static SQLRETURN GetColumn(SQLHSTMT stmt,
931 Utf8StringType* result,
933 SqlDataBinderCallback
const& cb)
noexcept
935 auto u16String = std::u16string {};
936 u16String.resize(result->size());
937 auto const sqlReturn = detail::GetColumnUtf16(stmt, column, &u16String, indicator, cb);
938 if (SQL_SUCCEEDED(sqlReturn))
939 *result =
ToUtf8(u16String);
943 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(Utf8StringType
const& value)
noexcept
946 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)