75 Row(
Client& client,
const std::vector<Descriptor>& descriptors, std::span<const std::byte> message)
77 descriptors{&descriptors},
79 statusWrapper{client},
80 numericConverter{client},
81 calendarConverter{client}
95 const auto& descriptor = getDescriptor(index);
96 return *
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE;
104 const auto& descriptor = getDescriptor(index);
106 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
109 switch (descriptor.adjustedType)
112 return message[descriptor.offset] != std::byte{0};
115 throwInvalidType(
"bool", descriptor.adjustedType);
122 std::optional<std::int16_t>
getInt16(
unsigned index)
124 std::optional<int> scale{0};
125 return getNumber<std::int16_t>(index, scale,
"std::int16_t");
133 std::optional<int> scale;
134 const auto value = getNumber<std::int16_t>(index, scale,
"ScaledInt16");
135 return value.has_value() ? std::optional{
ScaledInt16{value.
value(), scale.value()}} : std::nullopt;
141 std::optional<std::int32_t>
getInt32(
unsigned index)
143 std::optional<int> scale{0};
144 return getNumber<std::int32_t>(index, scale,
"std::int32_t");
152 std::optional<int> scale;
153 const auto value = getNumber<std::int32_t>(index, scale,
"ScaledInt32");
154 return value.has_value() ? std::optional{
ScaledInt32{value.
value(), scale.value()}} : std::nullopt;
160 std::optional<std::int64_t>
getInt64(
unsigned index)
162 std::optional<int> scale{0};
163 return getNumber<std::int64_t>(index, scale,
"std::int64_t");
171 std::optional<int> scale;
172 const auto value = getNumber<std::int64_t>(index, scale,
"ScaledInt64");
173 return value.has_value() ? std::optional{
ScaledInt64{value.
value(), scale.value()}} : std::nullopt;
181 const auto& descriptor = getDescriptor(index);
183 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
186 switch (descriptor.adjustedType)
194 throwInvalidType(
"ScaledOpaqueInt128", descriptor.adjustedType);
198#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
204 std::optional<int> scale{0};
205 const auto value = getNumber<BoostInt128>(index, scale,
"BoostInt128");
206 return value.has_value() ? std::optional{value.value()} : std::nullopt;
214 std::optional<int> scale;
215 const auto value = getNumber<BoostInt128>(index, scale,
"ScaledBoostInt128");
225 std::optional<int> scale{0};
226 return getNumber<float>(index, scale,
"float");
234 std::optional<int> scale{0};
235 return getNumber<double>(index, scale,
"double");
243 const auto& descriptor = getDescriptor(index);
245 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
248 switch (descriptor.adjustedType)
254 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
258#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
264 std::optional<int> scale{0};
265 return getNumber<BoostDecFloat16>(index, scale,
"BoostDecFloat16");
274 const auto& descriptor = getDescriptor(index);
276 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
279 switch (descriptor.adjustedType)
285 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
289#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
295 std::optional<int> scale{0};
296 return getNumber<BoostDecFloat34>(index, scale,
"BoostDecFloat34");
305 const auto& descriptor = getDescriptor(index);
307 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
310 switch (descriptor.adjustedType)
313 return calendarConverter.opaqueDateToDate(
314 *
reinterpret_cast<const OpaqueDate*
>(&message[descriptor.offset]));
317 throwInvalidType(
"Date", descriptor.adjustedType);
326 const auto& descriptor = getDescriptor(index);
328 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
331 switch (descriptor.adjustedType)
337 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
346 const auto& descriptor = getDescriptor(index);
348 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
351 switch (descriptor.adjustedType)
354 return calendarConverter.opaqueTimeToTime(
355 *
reinterpret_cast<const OpaqueTime*
>(&message[descriptor.offset]));
358 throwInvalidType(
"Time", descriptor.adjustedType);
367 const auto& descriptor = getDescriptor(index);
369 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
372 switch (descriptor.adjustedType)
378 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
387 const auto& descriptor = getDescriptor(index);
389 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
392 switch (descriptor.adjustedType)
395 return calendarConverter.opaqueTimestampToTimestamp(
396 *
reinterpret_cast<const OpaqueTimestamp*
>(&message[descriptor.offset]));
399 throwInvalidType(
"Timestamp", descriptor.adjustedType);
408 const auto& descriptor = getDescriptor(index);
410 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
413 switch (descriptor.adjustedType)
419 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
428 const auto& descriptor = getDescriptor(index);
430 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
433 switch (descriptor.adjustedType)
436 return calendarConverter.opaqueTimeTzToTimeTz(
437 &statusWrapper, *
reinterpret_cast<const OpaqueTimeTz*
>(&message[descriptor.offset]));
440 throwInvalidType(
"TimeTz", descriptor.adjustedType);
449 const auto& descriptor = getDescriptor(index);
451 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
454 switch (descriptor.adjustedType)
460 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
469 const auto& descriptor = getDescriptor(index);
471 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
474 switch (descriptor.adjustedType)
477 return calendarConverter.opaqueTimestampTzToTimestampTz(
478 &statusWrapper, *
reinterpret_cast<const OpaqueTimestampTz*
>(&message[descriptor.offset]));
481 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
490 const auto& descriptor = getDescriptor(index);
492 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
495 switch (descriptor.adjustedType)
501 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
510 const auto& descriptor = getDescriptor(index);
512 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
515 switch (descriptor.adjustedType)
520 value.
id = *
reinterpret_cast<const ISC_QUAD*
>(&message[descriptor.offset]);
525 throwInvalidType(
"BlobId", descriptor.adjustedType);
534 const auto& descriptor = getDescriptor(index);
536 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
539 const auto data = &message[descriptor.offset];
541 switch (descriptor.adjustedType)
544 return (message[descriptor.offset] != std::byte{0}) ? std::string{
"true"} : std::string{
"false"};
547 return numericConverter.numberToString(
548 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.
scale});
551 return numericConverter.numberToString(
552 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.
scale});
555 return numericConverter.numberToString(
556 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.
scale});
559 return numericConverter.opaqueInt128ToString(
560 &statusWrapper, *
reinterpret_cast<const OpaqueInt128*
>(data), descriptor.scale);
563 return numericConverter.numberToString(*
reinterpret_cast<const float*
>(data));
566 return numericConverter.numberToString(*
reinterpret_cast<const double*
>(data));
569 return calendarConverter.opaqueDateToString(*
reinterpret_cast<const OpaqueDate*
>(data));
572 return calendarConverter.opaqueTimeToString(*
reinterpret_cast<const OpaqueTime*
>(data));
575 return calendarConverter.opaqueTimestampToString(*
reinterpret_cast<const OpaqueTimestamp*
>(data));
578 return calendarConverter.opaqueTimeTzToString(
579 &statusWrapper, *
reinterpret_cast<const OpaqueTimeTz*
>(data));
582 return calendarConverter.opaqueTimestampTzToString(
586 return numericConverter.opaqueDecFloat16ToString(
590 return numericConverter.opaqueDecFloat34ToString(
594 return std::string{
reinterpret_cast<const char*
>(data +
sizeof(std::uint16_t)),
595 *
reinterpret_cast<const std::uint16_t*
>(data)};
598 throwInvalidType(
"std::string", descriptor.adjustedType);
609 template <
typename T>
615 template <Aggregate T>
618 using namespace impl::reflection;
620 constexpr std::size_t N = fieldCountV<T>;
622 if (N != descriptors->size())
625 ") does not match output column count (" + std::to_string(descriptors->size()) +
")");
628 return getStruct<T>(std::make_index_sequence<N>{});
634 template <TupleLike T>
637 using namespace impl::reflection;
639 constexpr std::size_t N = std::tuple_size_v<T>;
641 if (N != descriptors->size())
643 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
644 ") does not match output column count (" + std::to_string(descriptors->size()) +
")");
647 return getTuple<T>(std::make_index_sequence<N>{});
653 template <VariantLike V>
656 using namespace impl::reflection;
658 static_assert(variantAlternativesSupportedV<V>,
659 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
660 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
661 "complete list of supported types.");
663 const auto& descriptor = getDescriptor(index);
667 if constexpr (variantContainsV<std::monostate, V>)
668 return V{std::monostate{}};
672 "NULL value encountered but variant does not contain std::monostate at index " +
673 std::to_string(index));
677 return getVariantValue<V>(index, descriptor);
681 const Descriptor& getDescriptor(
unsigned index)
683 if (index >= descriptors->size())
684 throw std::out_of_range(
"index out of range");
686 return (*descriptors)[index];
689 template <
typename T, std::size_t... Is>
690 T getStruct(std::index_sequence<Is...>)
692 using namespace impl::reflection;
694 return T{getStructField<FieldType<T, Is>>(
static_cast<unsigned>(Is))...};
697 template <
typename F>
698 auto getStructField(
unsigned index)
700 using namespace impl::reflection;
702 if constexpr (isOptionalV<F>)
703 return get<F>(index);
704 else if constexpr (isVariantV<F>)
705 return get<F>(index);
708 auto opt = get<std::optional<F>>(index);
710 if (!opt.has_value())
712 throw FbCppException(
713 "Null value encountered for non-optional field at index " + std::to_string(index));
716 return std::move(opt.value());
720 template <
typename T, std::size_t... Is>
721 T getTuple(std::index_sequence<Is...>)
723 using namespace impl::reflection;
725 return T{getStructField<std::tuple_element_t<Is, T>>(
static_cast<unsigned>(Is))...};
728 template <
typename V>
729 V getVariantValue(
unsigned index,
const Descriptor& descriptor)
731 using namespace impl::reflection;
733 switch (descriptor.adjustedType)
736 if constexpr (variantContainsV<bool, V>)
737 return V{get<std::optional<bool>>(index).value()};
741 if (descriptor.scale != 0)
743 if constexpr (variantContainsV<ScaledInt16, V>)
744 return V{get<std::optional<ScaledInt16>>(index).value()};
745 if constexpr (variantContainsV<ScaledInt32, V>)
746 return V{get<std::optional<ScaledInt32>>(index).value()};
747 if constexpr (variantContainsV<ScaledInt64, V>)
748 return V{get<std::optional<ScaledInt64>>(index).value()};
749#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
750 if constexpr (variantContainsV<ScaledBoostInt128, V>)
751 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
754 if constexpr (variantContainsV<std::int16_t, V>)
755 return V{get<std::optional<std::int16_t>>(index).value()};
759 if (descriptor.scale != 0)
761 if constexpr (variantContainsV<ScaledInt32, V>)
762 return V{get<std::optional<ScaledInt32>>(index).value()};
763 if constexpr (variantContainsV<ScaledInt64, V>)
764 return V{get<std::optional<ScaledInt64>>(index).value()};
765#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
766 if constexpr (variantContainsV<ScaledBoostInt128, V>)
767 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
770 if constexpr (variantContainsV<std::int32_t, V>)
771 return V{get<std::optional<std::int32_t>>(index).value()};
775 if (descriptor.scale != 0)
777 if constexpr (variantContainsV<ScaledInt64, V>)
778 return V{get<std::optional<ScaledInt64>>(index).value()};
779#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
780 if constexpr (variantContainsV<ScaledBoostInt128, V>)
781 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
784 if constexpr (variantContainsV<std::int64_t, V>)
785 return V{get<std::optional<std::int64_t>>(index).value()};
788#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
790 if constexpr (variantContainsV<ScaledOpaqueInt128, V>)
791 return V{get<std::optional<ScaledOpaqueInt128>>(index).value()};
792 else if (descriptor.scale != 0)
794 if constexpr (variantContainsV<ScaledBoostInt128, V>)
795 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
797 else if constexpr (variantContainsV<BoostInt128, V>)
798 return V{get<std::optional<BoostInt128>>(index).value()};
803 if constexpr (variantContainsV<float, V>)
804 return V{get<std::optional<float>>(index).value()};
808 if constexpr (variantContainsV<double, V>)
809 return V{get<std::optional<double>>(index).value()};
812#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
814 if constexpr (variantContainsV<OpaqueDecFloat16, V>)
815 return V{get<std::optional<OpaqueDecFloat16>>(index).value()};
816 else if constexpr (variantContainsV<BoostDecFloat16, V>)
817 return V{get<std::optional<BoostDecFloat16>>(index).value()};
821 if constexpr (variantContainsV<OpaqueDecFloat34, V>)
822 return V{get<std::optional<OpaqueDecFloat34>>(index).value()};
823 else if constexpr (variantContainsV<BoostDecFloat34, V>)
824 return V{get<std::optional<BoostDecFloat34>>(index).value()};
829 if constexpr (variantContainsV<std::string, V>)
830 return V{get<std::optional<std::string>>(index).value()};
834 if constexpr (variantContainsV<OpaqueDate, V>)
835 return V{get<std::optional<OpaqueDate>>(index).value()};
836 else if constexpr (variantContainsV<Date, V>)
837 return V{get<std::optional<Date>>(index).value()};
841 if constexpr (variantContainsV<OpaqueTime, V>)
842 return V{get<std::optional<OpaqueTime>>(index).value()};
843 else if constexpr (variantContainsV<Time, V>)
844 return V{get<std::optional<Time>>(index).value()};
848 if constexpr (variantContainsV<OpaqueTimestamp, V>)
849 return V{get<std::optional<OpaqueTimestamp>>(index).value()};
850 else if constexpr (variantContainsV<Timestamp, V>)
851 return V{get<std::optional<Timestamp>>(index).value()};
855 if constexpr (variantContainsV<OpaqueTimeTz, V>)
856 return V{get<std::optional<OpaqueTimeTz>>(index).value()};
857 else if constexpr (variantContainsV<TimeTz, V>)
858 return V{get<std::optional<TimeTz>>(index).value()};
862 if constexpr (variantContainsV<OpaqueTimestampTz, V>)
863 return V{get<std::optional<OpaqueTimestampTz>>(index).value()};
864 else if constexpr (variantContainsV<TimestampTz, V>)
865 return V{get<std::optional<TimestampTz>>(index).value()};
869 if constexpr (variantContainsV<BlobId, V>)
870 return V{get<std::optional<BlobId>>(index).value()};
877 return tryVariantAlternatives<V, 0>(index, descriptor);
880 template <
typename V, std::
size_t I = 0>
881 V tryVariantAlternatives(
unsigned index, [[maybe_unused]]
const Descriptor& descriptor)
883 using namespace impl::reflection;
885 if constexpr (I >= std::variant_size_v<V>)
887 throw FbCppException(
888 "Cannot convert SQL type to any variant alternative at index " + std::to_string(index));
892 using Alt = std::variant_alternative_t<I, V>;
894 if constexpr (std::is_same_v<Alt, std::monostate>)
895 return tryVariantAlternatives<V, I + 1>(index, descriptor);
896 else if constexpr (isOpaqueTypeV<Alt>)
897 return tryVariantAlternatives<V, I + 1>(index, descriptor);
900 auto opt = get<std::optional<Alt>>(index);
901 return V{std::move(opt.value())};
907 template <
typename T>
908 std::optional<T> getNumber(
unsigned index, std::optional<int>& scale,
const char* typeName)
910 const auto& descriptor = getDescriptor(index);
912 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
915 auto data = &message[descriptor.offset];
916#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
917 std::optional<BoostInt128> boostInt128;
918 std::optional<BoostDecFloat16> boostDecFloat16;
919 std::optional<BoostDecFloat34> boostDecFloat34;
923 switch (descriptor.adjustedType)
925#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
928 numericConverter.opaqueInt128ToBoostInt128(*
reinterpret_cast<const OpaqueInt128*
>(data)));
929 data =
reinterpret_cast<const std::byte*
>(&boostInt128.value());
933 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
935 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat16.value());
939 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
941 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat34.value());
949 return convertNumber<T>(descriptor, data, scale, typeName);
954 throw FbCppException(
"Invalid type: actual type " + std::string(actualType) +
", descriptor type " +
955 std::to_string(
static_cast<unsigned>(descriptorType)));
958 template <
typename T>
960 const Descriptor& descriptor,
const std::byte* data, std::optional<int>& toScale,
const char* toTypeName)
962 if (!toScale.has_value())
964 switch (descriptor.adjustedType)
970 throwInvalidType(toTypeName, descriptor.adjustedType);
976 toScale = descriptor.scale;
979 switch (descriptor.adjustedType)
982 return numericConverter.numberToNumber<T>(
983 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.scale}, toScale.value());
986 return numericConverter.numberToNumber<T>(
987 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.scale}, toScale.value());
990 return numericConverter.numberToNumber<T>(
991 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.scale}, toScale.value());
993#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
995 return numericConverter.numberToNumber<T>(
1000 return numericConverter.numberToNumber<T>(
1004 return numericConverter.numberToNumber<T>(
1009 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const float*
>(data), toScale.value());
1012 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const double*
>(data), toScale.value());
1015 throwInvalidType(toTypeName, descriptor.adjustedType);
1021 const std::vector<Descriptor>* descriptors;
1022 std::span<const std::byte> message;
1023 impl::StatusWrapper statusWrapper;
1024 impl::NumericConverter numericConverter;
1025 impl::CalendarConverter calendarConverter;