80 Row(
Client& client,
const std::vector<Descriptor>& descriptors, std::span<const std::byte> message)
82 descriptors{&descriptors},
84 statusWrapper{client},
85 numericConverter{client},
86 calendarConverter{client}
100 const auto& descriptor = getDescriptor(index);
101 return readNullFlag(descriptor);
109 const auto& descriptor = getDescriptor(index);
111 if (readNullFlag(descriptor))
114 switch (descriptor.adjustedType)
117 return message[descriptor.offset] != std::byte{0};
120 throwInvalidType(
"bool", descriptor.adjustedType);
127 std::optional<std::int16_t>
getInt16(
unsigned index)
129 std::optional<int> scale{0};
130 return getNumber<std::int16_t>(index, scale,
"std::int16_t");
138 std::optional<int> scale;
139 const auto value = getNumber<std::int16_t>(index, scale,
"ScaledInt16");
140 return value.has_value() ? std::optional{
ScaledInt16{value.
value(), scale.value()}} : std::nullopt;
146 std::optional<std::int32_t>
getInt32(
unsigned index)
148 std::optional<int> scale{0};
149 return getNumber<std::int32_t>(index, scale,
"std::int32_t");
157 std::optional<int> scale;
158 const auto value = getNumber<std::int32_t>(index, scale,
"ScaledInt32");
159 return value.has_value() ? std::optional{
ScaledInt32{value.
value(), scale.value()}} : std::nullopt;
165 std::optional<std::int64_t>
getInt64(
unsigned index)
167 std::optional<int> scale{0};
168 return getNumber<std::int64_t>(index, scale,
"std::int64_t");
176 std::optional<int> scale;
177 const auto value = getNumber<std::int64_t>(index, scale,
"ScaledInt64");
178 return value.has_value() ? std::optional{
ScaledInt64{value.
value(), scale.value()}} : std::nullopt;
186 const auto& descriptor = getDescriptor(index);
188 if (readNullFlag(descriptor))
191 switch (descriptor.adjustedType)
199 throwInvalidType(
"ScaledOpaqueInt128", descriptor.adjustedType);
203#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
209 std::optional<int> scale{0};
210 const auto value = getNumber<BoostInt128>(index, scale,
"BoostInt128");
211 return value.has_value() ? std::optional{value.value()} : std::nullopt;
219 std::optional<int> scale;
220 const auto value = getNumber<BoostInt128>(index, scale,
"ScaledBoostInt128");
230 std::optional<int> scale{0};
231 return getNumber<float>(index, scale,
"float");
239 std::optional<int> scale{0};
240 return getNumber<double>(index, scale,
"double");
248 const auto& descriptor = getDescriptor(index);
250 if (readNullFlag(descriptor))
253 switch (descriptor.adjustedType)
259 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
263#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
269 std::optional<int> scale{0};
270 return getNumber<BoostDecFloat16>(index, scale,
"BoostDecFloat16");
274#if FB_CPP_USE_BOOST_DECIMAL != 0
280 std::optional<int> scale{0};
281 return getNumber<BoostDecimal32>(index, scale,
"BoostDecimal32");
289 std::optional<int> scale{0};
290 return getNumber<BoostDecimal64>(index, scale,
"BoostDecimal64");
299 const auto& descriptor = getDescriptor(index);
301 if (readNullFlag(descriptor))
304 switch (descriptor.adjustedType)
310 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
314#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
320 std::optional<int> scale{0};
321 return getNumber<BoostDecFloat34>(index, scale,
"BoostDecFloat34");
325#if FB_CPP_USE_BOOST_DECIMAL != 0
331 std::optional<int> scale{0};
332 return getNumber<BoostDecimal128>(index, scale,
"BoostDecimal128");
341 const auto& descriptor = getDescriptor(index);
343 if (readNullFlag(descriptor))
346 switch (descriptor.adjustedType)
349 return calendarConverter.opaqueDateToDate(
350 *
reinterpret_cast<const OpaqueDate*
>(&message[descriptor.offset]));
353 throwInvalidType(
"Date", descriptor.adjustedType);
362 const auto& descriptor = getDescriptor(index);
364 if (readNullFlag(descriptor))
367 switch (descriptor.adjustedType)
373 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
382 const auto& descriptor = getDescriptor(index);
384 if (readNullFlag(descriptor))
387 switch (descriptor.adjustedType)
390 return calendarConverter.opaqueTimeToTime(
391 *
reinterpret_cast<const OpaqueTime*
>(&message[descriptor.offset]));
394 throwInvalidType(
"Time", descriptor.adjustedType);
403 const auto& descriptor = getDescriptor(index);
405 if (readNullFlag(descriptor))
408 switch (descriptor.adjustedType)
414 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
423 const auto& descriptor = getDescriptor(index);
425 if (readNullFlag(descriptor))
428 switch (descriptor.adjustedType)
431 return calendarConverter.opaqueTimestampToTimestamp(
432 *
reinterpret_cast<const OpaqueTimestamp*
>(&message[descriptor.offset]));
435 throwInvalidType(
"Timestamp", descriptor.adjustedType);
444 const auto& descriptor = getDescriptor(index);
446 if (readNullFlag(descriptor))
449 switch (descriptor.adjustedType)
455 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
464 const auto& descriptor = getDescriptor(index);
466 if (readNullFlag(descriptor))
469 switch (descriptor.adjustedType)
472 return calendarConverter.opaqueTimeTzToTimeTz(
473 &statusWrapper, *
reinterpret_cast<const OpaqueTimeTz*
>(&message[descriptor.offset]));
476 throwInvalidType(
"TimeTz", descriptor.adjustedType);
485 const auto& descriptor = getDescriptor(index);
487 if (readNullFlag(descriptor))
490 switch (descriptor.adjustedType)
496 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
505 const auto& descriptor = getDescriptor(index);
507 if (readNullFlag(descriptor))
510 switch (descriptor.adjustedType)
513 return calendarConverter.opaqueTimestampTzToTimestampTz(
514 &statusWrapper, *
reinterpret_cast<const OpaqueTimestampTz*
>(&message[descriptor.offset]));
517 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
526 const auto& descriptor = getDescriptor(index);
528 if (readNullFlag(descriptor))
531 switch (descriptor.adjustedType)
537 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
546 const auto& descriptor = getDescriptor(index);
548 if (readNullFlag(descriptor))
551 switch (descriptor.adjustedType)
556 value.
id = *
reinterpret_cast<const ISC_QUAD*
>(&message[descriptor.offset]);
561 throwInvalidType(
"BlobId", descriptor.adjustedType);
570 const auto& descriptor = getDescriptor(index);
572 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
575 switch (descriptor.adjustedType)
580 value.
id = *
reinterpret_cast<const ISC_QUAD*
>(&message[descriptor.offset]);
585 throwInvalidType(
"ArrayId", descriptor.adjustedType);
594 const auto& descriptor = getDescriptor(index);
596 if (readNullFlag(descriptor))
599 const auto data = &message[descriptor.offset];
601 switch (descriptor.adjustedType)
604 return (message[descriptor.offset] != std::byte{0}) ? std::string{
"true"} : std::string{
"false"};
607 return numericConverter.numberToString(
608 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.
scale});
611 return numericConverter.numberToString(
612 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.
scale});
615 return numericConverter.numberToString(
616 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.
scale});
619 return numericConverter.opaqueInt128ToString(
620 &statusWrapper, *
reinterpret_cast<const OpaqueInt128*
>(data), descriptor.scale);
623 return numericConverter.numberToString(*
reinterpret_cast<const float*
>(data));
626 return numericConverter.numberToString(*
reinterpret_cast<const double*
>(data));
629 return calendarConverter.opaqueDateToString(*
reinterpret_cast<const OpaqueDate*
>(data));
632 return calendarConverter.opaqueTimeToString(*
reinterpret_cast<const OpaqueTime*
>(data));
635 return calendarConverter.opaqueTimestampToString(*
reinterpret_cast<const OpaqueTimestamp*
>(data));
638 return calendarConverter.opaqueTimeTzToString(
639 &statusWrapper, *
reinterpret_cast<const OpaqueTimeTz*
>(data));
642 return calendarConverter.opaqueTimestampTzToString(
646 return numericConverter.opaqueDecFloat16ToString(
650 return numericConverter.opaqueDecFloat34ToString(
654 return std::string{
reinterpret_cast<const char*
>(data +
sizeof(std::uint16_t)),
655 *
reinterpret_cast<const std::uint16_t*
>(data)};
658 throwInvalidType(
"std::string", descriptor.adjustedType);
665 std::optional<std::vector<std::byte>>
getBytes(
unsigned index)
667 const auto& descriptor = getDescriptor(index);
669 if (readNullFlag(descriptor))
672 const auto data = &message[descriptor.offset];
674 switch (descriptor.adjustedType)
678 const auto length = *
reinterpret_cast<const std::uint16_t*
>(data);
679 return std::vector<std::byte>{data +
sizeof(std::uint16_t), data +
sizeof(std::uint16_t) + length};
683 throwInvalidType(
"std::vector<std::byte>", descriptor.adjustedType);
694 template <
typename T>
700 template <Aggregate T>
703 using namespace impl::reflection;
705 constexpr std::size_t N = fieldCountV<T>;
707 if (N != descriptors->size())
710 ") does not match output column count (" + std::to_string(descriptors->size()) +
")");
713 return getStruct<T>(std::make_index_sequence<N>{});
719 template <TupleLike T>
722 using namespace impl::reflection;
724 constexpr std::size_t N = std::tuple_size_v<T>;
726 if (N != descriptors->size())
728 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
729 ") does not match output column count (" + std::to_string(descriptors->size()) +
")");
732 return getTuple<T>(std::make_index_sequence<N>{});
738 template <VariantLike V>
741 using namespace impl::reflection;
743 static_assert(variantAlternativesSupportedV<V>,
744 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
745 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
746 "complete list of supported types.");
748 const auto& descriptor = getDescriptor(index);
752 if constexpr (variantContainsV<std::monostate, V>)
753 return V{std::monostate{}};
757 "NULL value encountered but variant does not contain std::monostate at index " +
758 std::to_string(index));
762 return getVariantValue<V>(index, descriptor);
766 const Descriptor& getDescriptor(
unsigned index)
768 if (index >= descriptors->size())
769 throw std::out_of_range(
"index out of range");
771 return (*descriptors)[index];
774 template <
typename T, std::size_t... Is>
775 T getStruct(std::index_sequence<Is...>)
777 using namespace impl::reflection;
779 return T{getStructField<FieldType<T, Is>>(
static_cast<unsigned>(Is))...};
782 template <
typename F>
783 auto getStructField(
unsigned index)
785 using namespace impl::reflection;
787 if constexpr (isOptionalV<F>)
788 return get<F>(index);
789 else if constexpr (isVariantV<F>)
790 return get<F>(index);
793 auto opt = get<std::optional<F>>(index);
795 if (!opt.has_value())
797 throw FbCppException(
798 "Null value encountered for non-optional field at index " + std::to_string(index));
801 return std::move(opt.value());
805 template <
typename T, std::size_t... Is>
806 T getTuple(std::index_sequence<Is...>)
808 using namespace impl::reflection;
810 return T{getStructField<std::tuple_element_t<Is, T>>(
static_cast<unsigned>(Is))...};
813 template <
typename V>
814 V getVariantValue(
unsigned index,
const Descriptor& descriptor)
816 using namespace impl::reflection;
818 switch (descriptor.adjustedType)
821 if constexpr (variantContainsV<bool, V>)
822 return V{get<std::optional<bool>>(index).value()};
826 if (descriptor.scale != 0)
828 if constexpr (variantContainsV<ScaledInt16, V>)
829 return V{get<std::optional<ScaledInt16>>(index).value()};
830 if constexpr (variantContainsV<ScaledInt32, V>)
831 return V{get<std::optional<ScaledInt32>>(index).value()};
832 if constexpr (variantContainsV<ScaledInt64, V>)
833 return V{get<std::optional<ScaledInt64>>(index).value()};
834#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
835 if constexpr (variantContainsV<ScaledBoostInt128, V>)
836 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
839 if constexpr (variantContainsV<std::int16_t, V>)
840 return V{get<std::optional<std::int16_t>>(index).value()};
844 if (descriptor.scale != 0)
846 if constexpr (variantContainsV<ScaledInt32, V>)
847 return V{get<std::optional<ScaledInt32>>(index).value()};
848 if constexpr (variantContainsV<ScaledInt64, V>)
849 return V{get<std::optional<ScaledInt64>>(index).value()};
850#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
851 if constexpr (variantContainsV<ScaledBoostInt128, V>)
852 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
855 if constexpr (variantContainsV<std::int32_t, V>)
856 return V{get<std::optional<std::int32_t>>(index).value()};
860 if (descriptor.scale != 0)
862 if constexpr (variantContainsV<ScaledInt64, V>)
863 return V{get<std::optional<ScaledInt64>>(index).value()};
864#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
865 if constexpr (variantContainsV<ScaledBoostInt128, V>)
866 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
869 if constexpr (variantContainsV<std::int64_t, V>)
870 return V{get<std::optional<std::int64_t>>(index).value()};
874 if constexpr (variantContainsV<ScaledOpaqueInt128, V>)
875 return V{get<std::optional<ScaledOpaqueInt128>>(index).value()};
876#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
877 else if (descriptor.scale != 0)
879 if constexpr (variantContainsV<ScaledBoostInt128, V>)
880 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
882 else if constexpr (variantContainsV<BoostInt128, V>)
883 return V{get<std::optional<BoostInt128>>(index).value()};
888 if constexpr (variantContainsV<float, V>)
889 return V{get<std::optional<float>>(index).value()};
893 if constexpr (variantContainsV<double, V>)
894 return V{get<std::optional<double>>(index).value()};
898 if constexpr (variantContainsV<OpaqueDecFloat16, V>)
899 return V{get<std::optional<OpaqueDecFloat16>>(index).value()};
900#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
901 else if constexpr (variantContainsV<BoostDecFloat16, V>)
902 return V{get<std::optional<BoostDecFloat16>>(index).value()};
904#if FB_CPP_USE_BOOST_DECIMAL != 0
905 else if constexpr (variantContainsV<BoostDecimal64, V>)
906 return V{get<std::optional<BoostDecimal64>>(index).value()};
911 if constexpr (variantContainsV<OpaqueDecFloat34, V>)
912 return V{get<std::optional<OpaqueDecFloat34>>(index).value()};
913#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
914 else if constexpr (variantContainsV<BoostDecFloat34, V>)
915 return V{get<std::optional<BoostDecFloat34>>(index).value()};
917#if FB_CPP_USE_BOOST_DECIMAL != 0
918 else if constexpr (variantContainsV<BoostDecimal128, V>)
919 return V{get<std::optional<BoostDecimal128>>(index).value()};
924 if (descriptor.charSetId == impl::CHARSET_OCTETS)
926 if constexpr (variantContainsV<std::vector<std::byte>, V>)
927 return V{get<std::optional<std::vector<std::byte>>>(index).value()};
928 if constexpr (variantContainsV<std::string, V>)
929 return V{get<std::optional<std::string>>(index).value()};
933 if constexpr (variantContainsV<std::string, V>)
934 return V{get<std::optional<std::string>>(index).value()};
935 if constexpr (variantContainsV<std::vector<std::byte>, V>)
936 return V{get<std::optional<std::vector<std::byte>>>(index).value()};
941 if constexpr (variantContainsV<OpaqueDate, V>)
942 return V{get<std::optional<OpaqueDate>>(index).value()};
943 else if constexpr (variantContainsV<Date, V>)
944 return V{get<std::optional<Date>>(index).value()};
948 if constexpr (variantContainsV<OpaqueTime, V>)
949 return V{get<std::optional<OpaqueTime>>(index).value()};
950 else if constexpr (variantContainsV<Time, V>)
951 return V{get<std::optional<Time>>(index).value()};
955 if constexpr (variantContainsV<OpaqueTimestamp, V>)
956 return V{get<std::optional<OpaqueTimestamp>>(index).value()};
957 else if constexpr (variantContainsV<Timestamp, V>)
958 return V{get<std::optional<Timestamp>>(index).value()};
962 if constexpr (variantContainsV<OpaqueTimeTz, V>)
963 return V{get<std::optional<OpaqueTimeTz>>(index).value()};
964 else if constexpr (variantContainsV<TimeTz, V>)
965 return V{get<std::optional<TimeTz>>(index).value()};
969 if constexpr (variantContainsV<OpaqueTimestampTz, V>)
970 return V{get<std::optional<OpaqueTimestampTz>>(index).value()};
971 else if constexpr (variantContainsV<TimestampTz, V>)
972 return V{get<std::optional<TimestampTz>>(index).value()};
976 if constexpr (variantContainsV<BlobId, V>)
977 return V{get<std::optional<BlobId>>(index).value()};
981 if constexpr (variantContainsV<ArrayId, V>)
982 return V{get<std::optional<ArrayId>>(index).value()};
989 return tryVariantAlternatives<V, 0>(index, descriptor);
992 template <
typename V, std::
size_t I = 0>
993 V tryVariantAlternatives(
unsigned index, [[maybe_unused]]
const Descriptor& descriptor)
995 using namespace impl::reflection;
997 if constexpr (I >= std::variant_size_v<V>)
999 throw FbCppException(
1000 "Cannot convert SQL type to any variant alternative at index " + std::to_string(index));
1004 using Alt = std::variant_alternative_t<I, V>;
1006 if constexpr (std::is_same_v<Alt, std::monostate>)
1007 return tryVariantAlternatives<V, I + 1>(index, descriptor);
1008 else if constexpr (isOpaqueTypeV<Alt>)
1009 return tryVariantAlternatives<V, I + 1>(index, descriptor);
1012 auto opt = get<std::optional<Alt>>(index);
1013 return V{std::move(opt.value())};
1019 template <
typename T>
1020 std::optional<T> getNumber(
unsigned index, std::optional<int>& scale,
const char* typeName)
1022 const auto& descriptor = getDescriptor(index);
1024 if (readNullFlag(descriptor))
1025 return std::nullopt;
1027 auto data = &message[descriptor.offset];
1028#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1029 std::optional<BoostInt128> boostInt128;
1031#if FB_CPP_USE_BOOST_DECIMAL != 0
1032 std::optional<BoostDecimal64> boostDecimal64;
1033 std::optional<BoostDecimal128> boostDecimal128;
1034#elif FB_CPP_USE_BOOST_MULTIPRECISION != 0
1035 std::optional<BoostDecFloat16> boostDecFloat16;
1036 std::optional<BoostDecFloat34> boostDecFloat34;
1040 switch (descriptor.adjustedType)
1042#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1044 boostInt128.emplace(numericConverter.opaqueInt128ToBoostInt128(
1045 &statusWrapper, *
reinterpret_cast<const OpaqueInt128*
>(data)));
1046 data =
reinterpret_cast<const std::byte*
>(&boostInt128.value());
1050#if FB_CPP_USE_BOOST_DECIMAL != 0
1052 boostDecimal64.emplace(numericConverter.opaqueDecFloat16ToBoostDecimal64(
1054 data =
reinterpret_cast<const std::byte*
>(&boostDecimal64.value());
1058 boostDecimal128.emplace(numericConverter.opaqueDecFloat34ToBoostDecimal128(
1060 data =
reinterpret_cast<const std::byte*
>(&boostDecimal128.value());
1062#elif FB_CPP_USE_BOOST_MULTIPRECISION != 0
1064 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
1066 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat16.value());
1070 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
1072 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat34.value());
1080 return convertNumber<T>(descriptor, data, scale, typeName);
1085 throw FbCppException(
"Invalid type: actual type " + std::string(actualType) +
", descriptor type " +
1086 std::to_string(
static_cast<unsigned>(descriptorType)));
1089 template <
typename T>
1091 const Descriptor& descriptor,
const std::byte* data, std::optional<int>& toScale,
const char* toTypeName)
1093 if (!toScale.has_value())
1095 switch (descriptor.adjustedType)
1101 throwInvalidType(toTypeName, descriptor.adjustedType);
1107 toScale = descriptor.scale;
1110 switch (descriptor.adjustedType)
1113 return numericConverter.numberToNumber<T>(
1114 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.scale}, toScale.value());
1117 return numericConverter.numberToNumber<T>(
1118 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.scale}, toScale.value());
1121 return numericConverter.numberToNumber<T>(
1122 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.scale}, toScale.value());
1124#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1126 return numericConverter.numberToNumber<T>(
1131#if FB_CPP_USE_BOOST_DECIMAL != 0
1133 return numericConverter.numberToNumber<T>(
1134 *
reinterpret_cast<const BoostDecimal64*
>(data), toScale.value());
1137 return numericConverter.numberToNumber<T>(
1139#elif FB_CPP_USE_BOOST_MULTIPRECISION != 0
1141 return numericConverter.numberToNumber<T>(
1145 return numericConverter.numberToNumber<T>(
1150 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const float*
>(data), toScale.value());
1153 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const double*
>(data), toScale.value());
1156 throwInvalidType(toTypeName, descriptor.adjustedType);
1165 bool readNullFlag(
const Descriptor& descriptor)
1167 if (!descriptor.isNullable)
1170 return *
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE;
1175 const std::vector<Descriptor>* descriptors;
1176 std::span<const std::byte> message;
1177 impl::StatusWrapper statusWrapper;
1178 impl::NumericConverter numericConverter;
1179 impl::CalendarConverter calendarConverter;