fb-cpp 0.0.2
A modern C++ wrapper for the Firebird database API
Loading...
Searching...
No Matches
Row.h
1/*
2 * MIT License
3 *
4 * Copyright (c) 2026 F.D.Castel
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#ifndef FBCPP_ROW_H
26#define FBCPP_ROW_H
27
28#include "config.h"
29#include "fb-api.h"
30#include "types.h"
31#include "Blob.h"
32#include "Array.h"
33#include "NumericConverter.h"
34#include "CalendarConverter.h"
35#include "Descriptor.h"
36#include "Exception.h"
37#include "StructBinding.h"
38#include "VariantTypeTraits.h"
39#include <cassert>
40#include <cstddef>
41#include <cstdint>
42#include <optional>
43#include <span>
44#include <stdexcept>
45#include <string>
46#include <vector>
47
48#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
49#include <boost/multiprecision/cpp_int.hpp>
50#include <boost/multiprecision/cpp_dec_float.hpp>
51#endif
52
53#if FB_CPP_USE_BOOST_DECIMAL != 0
54#include <boost/decimal.hpp>
55#endif
56
57
61namespace fbcpp
62{
70 class Row final
71 {
72 public:
80 Row(Client& client, const std::vector<Descriptor>& descriptors, std::span<const std::byte> message)
81 : client{&client},
82 descriptors{&descriptors},
83 message{message},
84 statusWrapper{client},
85 numericConverter{client},
86 calendarConverter{client}
87 {
88 }
89
90 public:
94
98 bool isNull(unsigned index)
99 {
100 const auto& descriptor = getDescriptor(index);
101 return readNullFlag(descriptor);
102 }
103
107 std::optional<bool> getBool(unsigned index)
108 {
109 const auto& descriptor = getDescriptor(index);
110
111 if (readNullFlag(descriptor))
112 return std::nullopt;
113
114 switch (descriptor.adjustedType)
115 {
117 return message[descriptor.offset] != std::byte{0};
118
119 default:
120 throwInvalidType("bool", descriptor.adjustedType);
121 }
122 }
123
127 std::optional<std::int16_t> getInt16(unsigned index)
128 {
129 std::optional<int> scale{0};
130 return getNumber<std::int16_t>(index, scale, "std::int16_t");
131 }
132
136 std::optional<ScaledInt16> getScaledInt16(unsigned index)
137 {
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;
141 }
142
146 std::optional<std::int32_t> getInt32(unsigned index)
147 {
148 std::optional<int> scale{0};
149 return getNumber<std::int32_t>(index, scale, "std::int32_t");
150 }
151
155 std::optional<ScaledInt32> getScaledInt32(unsigned index)
156 {
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;
160 }
161
165 std::optional<std::int64_t> getInt64(unsigned index)
166 {
167 std::optional<int> scale{0};
168 return getNumber<std::int64_t>(index, scale, "std::int64_t");
169 }
170
174 std::optional<ScaledInt64> getScaledInt64(unsigned index)
175 {
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;
179 }
180
184 std::optional<ScaledOpaqueInt128> getScaledOpaqueInt128(unsigned index)
185 {
186 const auto& descriptor = getDescriptor(index);
187
188 if (readNullFlag(descriptor))
189 return std::nullopt;
190
191 switch (descriptor.adjustedType)
192 {
194 return ScaledOpaqueInt128{
195 OpaqueInt128{*reinterpret_cast<const OpaqueInt128*>(&message[descriptor.offset])},
196 descriptor.scale};
197
198 default:
199 throwInvalidType("ScaledOpaqueInt128", descriptor.adjustedType);
200 }
201 }
202
203#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
207 std::optional<BoostInt128> getBoostInt128(unsigned index)
208 {
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;
212 }
213
217 std::optional<ScaledBoostInt128> getScaledBoostInt128(unsigned index)
218 {
219 std::optional<int> scale;
220 const auto value = getNumber<BoostInt128>(index, scale, "ScaledBoostInt128");
221 return value.has_value() ? std::optional{ScaledBoostInt128{value.value(), scale.value()}} : std::nullopt;
222 }
223#endif
224
228 std::optional<float> getFloat(unsigned index)
229 {
230 std::optional<int> scale{0};
231 return getNumber<float>(index, scale, "float");
232 }
233
237 std::optional<double> getDouble(unsigned index)
238 {
239 std::optional<int> scale{0};
240 return getNumber<double>(index, scale, "double");
241 }
242
246 std::optional<OpaqueDecFloat16> getOpaqueDecFloat16(unsigned index)
247 {
248 const auto& descriptor = getDescriptor(index);
249
250 if (readNullFlag(descriptor))
251 return std::nullopt;
252
253 switch (descriptor.adjustedType)
254 {
256 return OpaqueDecFloat16{*reinterpret_cast<const OpaqueDecFloat16*>(&message[descriptor.offset])};
257
258 default:
259 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
260 }
261 }
262
263#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
267 std::optional<BoostDecFloat16> getBoostDecFloat16(unsigned index)
268 {
269 std::optional<int> scale{0};
270 return getNumber<BoostDecFloat16>(index, scale, "BoostDecFloat16");
271 }
272#endif
273
274#if FB_CPP_USE_BOOST_DECIMAL != 0
278 std::optional<BoostDecimal32> getBoostDecimal32(unsigned index)
279 {
280 std::optional<int> scale{0};
281 return getNumber<BoostDecimal32>(index, scale, "BoostDecimal32");
282 }
283
287 std::optional<BoostDecimal64> getBoostDecimal64(unsigned index)
288 {
289 std::optional<int> scale{0};
290 return getNumber<BoostDecimal64>(index, scale, "BoostDecimal64");
291 }
292#endif
293
297 std::optional<OpaqueDecFloat34> getOpaqueDecFloat34(unsigned index)
298 {
299 const auto& descriptor = getDescriptor(index);
300
301 if (readNullFlag(descriptor))
302 return std::nullopt;
303
304 switch (descriptor.adjustedType)
305 {
307 return OpaqueDecFloat34{*reinterpret_cast<const OpaqueDecFloat34*>(&message[descriptor.offset])};
308
309 default:
310 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
311 }
312 }
313
314#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
318 std::optional<BoostDecFloat34> getBoostDecFloat34(unsigned index)
319 {
320 std::optional<int> scale{0};
321 return getNumber<BoostDecFloat34>(index, scale, "BoostDecFloat34");
322 }
323#endif
324
325#if FB_CPP_USE_BOOST_DECIMAL != 0
329 std::optional<BoostDecimal128> getBoostDecimal128(unsigned index)
330 {
331 std::optional<int> scale{0};
332 return getNumber<BoostDecimal128>(index, scale, "BoostDecimal128");
333 }
334#endif
335
339 std::optional<Date> getDate(unsigned index)
340 {
341 const auto& descriptor = getDescriptor(index);
342
343 if (readNullFlag(descriptor))
344 return std::nullopt;
345
346 switch (descriptor.adjustedType)
347 {
349 return calendarConverter.opaqueDateToDate(
350 *reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset]));
351
352 default:
353 throwInvalidType("Date", descriptor.adjustedType);
354 }
355 }
356
360 std::optional<OpaqueDate> getOpaqueDate(unsigned index)
361 {
362 const auto& descriptor = getDescriptor(index);
363
364 if (readNullFlag(descriptor))
365 return std::nullopt;
366
367 switch (descriptor.adjustedType)
368 {
370 return OpaqueDate{*reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset])};
371
372 default:
373 throwInvalidType("OpaqueDate", descriptor.adjustedType);
374 }
375 }
376
380 std::optional<Time> getTime(unsigned index)
381 {
382 const auto& descriptor = getDescriptor(index);
383
384 if (readNullFlag(descriptor))
385 return std::nullopt;
386
387 switch (descriptor.adjustedType)
388 {
390 return calendarConverter.opaqueTimeToTime(
391 *reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset]));
392
393 default:
394 throwInvalidType("Time", descriptor.adjustedType);
395 }
396 }
397
401 std::optional<OpaqueTime> getOpaqueTime(unsigned index)
402 {
403 const auto& descriptor = getDescriptor(index);
404
405 if (readNullFlag(descriptor))
406 return std::nullopt;
407
408 switch (descriptor.adjustedType)
409 {
411 return OpaqueTime{*reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset])};
412
413 default:
414 throwInvalidType("OpaqueTime", descriptor.adjustedType);
415 }
416 }
417
421 std::optional<Timestamp> getTimestamp(unsigned index)
422 {
423 const auto& descriptor = getDescriptor(index);
424
425 if (readNullFlag(descriptor))
426 return std::nullopt;
427
428 switch (descriptor.adjustedType)
429 {
431 return calendarConverter.opaqueTimestampToTimestamp(
432 *reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset]));
433
434 default:
435 throwInvalidType("Timestamp", descriptor.adjustedType);
436 }
437 }
438
442 std::optional<OpaqueTimestamp> getOpaqueTimestamp(unsigned index)
443 {
444 const auto& descriptor = getDescriptor(index);
445
446 if (readNullFlag(descriptor))
447 return std::nullopt;
448
449 switch (descriptor.adjustedType)
450 {
452 return OpaqueTimestamp{*reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset])};
453
454 default:
455 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
456 }
457 }
458
462 std::optional<TimeTz> getTimeTz(unsigned index)
463 {
464 const auto& descriptor = getDescriptor(index);
465
466 if (readNullFlag(descriptor))
467 return std::nullopt;
468
469 switch (descriptor.adjustedType)
470 {
472 return calendarConverter.opaqueTimeTzToTimeTz(
473 &statusWrapper, *reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset]));
474
475 default:
476 throwInvalidType("TimeTz", descriptor.adjustedType);
477 }
478 }
479
483 std::optional<OpaqueTimeTz> getOpaqueTimeTz(unsigned index)
484 {
485 const auto& descriptor = getDescriptor(index);
486
487 if (readNullFlag(descriptor))
488 return std::nullopt;
489
490 switch (descriptor.adjustedType)
491 {
493 return OpaqueTimeTz{*reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset])};
494
495 default:
496 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
497 }
498 }
499
503 std::optional<TimestampTz> getTimestampTz(unsigned index)
504 {
505 const auto& descriptor = getDescriptor(index);
506
507 if (readNullFlag(descriptor))
508 return std::nullopt;
509
510 switch (descriptor.adjustedType)
511 {
513 return calendarConverter.opaqueTimestampTzToTimestampTz(
514 &statusWrapper, *reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset]));
515
516 default:
517 throwInvalidType("TimestampTz", descriptor.adjustedType);
518 }
519 }
520
524 std::optional<OpaqueTimestampTz> getOpaqueTimestampTz(unsigned index)
525 {
526 const auto& descriptor = getDescriptor(index);
527
528 if (readNullFlag(descriptor))
529 return std::nullopt;
530
531 switch (descriptor.adjustedType)
532 {
534 return OpaqueTimestampTz{*reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset])};
535
536 default:
537 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
538 }
539 }
540
544 std::optional<BlobId> getBlobId(unsigned index)
545 {
546 const auto& descriptor = getDescriptor(index);
547
548 if (readNullFlag(descriptor))
549 return std::nullopt;
550
551 switch (descriptor.adjustedType)
552 {
554 {
555 BlobId value;
556 value.id = *reinterpret_cast<const ISC_QUAD*>(&message[descriptor.offset]);
557 return value;
558 }
559
560 default:
561 throwInvalidType("BlobId", descriptor.adjustedType);
562 }
563 }
564
568 std::optional<ArrayId> getArrayId(unsigned index)
569 {
570 const auto& descriptor = getDescriptor(index);
571
572 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
573 return std::nullopt;
574
575 switch (descriptor.adjustedType)
576 {
578 {
579 ArrayId value;
580 value.id = *reinterpret_cast<const ISC_QUAD*>(&message[descriptor.offset]);
581 return value;
582 }
583
584 default:
585 throwInvalidType("ArrayId", descriptor.adjustedType);
586 }
587 }
588
592 std::optional<std::string> getString(unsigned index)
593 {
594 const auto& descriptor = getDescriptor(index);
595
596 if (readNullFlag(descriptor))
597 return std::nullopt;
598
599 const auto data = &message[descriptor.offset];
600
601 switch (descriptor.adjustedType)
602 {
604 return (message[descriptor.offset] != std::byte{0}) ? std::string{"true"} : std::string{"false"};
605
607 return numericConverter.numberToString(
608 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale});
609
611 return numericConverter.numberToString(
612 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale});
613
615 return numericConverter.numberToString(
616 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale});
617
619 return numericConverter.opaqueInt128ToString(
620 &statusWrapper, *reinterpret_cast<const OpaqueInt128*>(data), descriptor.scale);
621
623 return numericConverter.numberToString(*reinterpret_cast<const float*>(data));
624
626 return numericConverter.numberToString(*reinterpret_cast<const double*>(data));
627
629 return calendarConverter.opaqueDateToString(*reinterpret_cast<const OpaqueDate*>(data));
630
632 return calendarConverter.opaqueTimeToString(*reinterpret_cast<const OpaqueTime*>(data));
633
635 return calendarConverter.opaqueTimestampToString(*reinterpret_cast<const OpaqueTimestamp*>(data));
636
638 return calendarConverter.opaqueTimeTzToString(
639 &statusWrapper, *reinterpret_cast<const OpaqueTimeTz*>(data));
640
642 return calendarConverter.opaqueTimestampTzToString(
643 &statusWrapper, *reinterpret_cast<const OpaqueTimestampTz*>(data));
644
646 return numericConverter.opaqueDecFloat16ToString(
647 &statusWrapper, *reinterpret_cast<const OpaqueDecFloat16*>(data));
648
650 return numericConverter.opaqueDecFloat34ToString(
651 &statusWrapper, *reinterpret_cast<const OpaqueDecFloat34*>(data));
652
654 return std::string{reinterpret_cast<const char*>(data + sizeof(std::uint16_t)),
655 *reinterpret_cast<const std::uint16_t*>(data)};
656
657 default:
658 throwInvalidType("std::string", descriptor.adjustedType);
659 }
660 }
661
665 std::optional<std::vector<std::byte>> getBytes(unsigned index)
666 {
667 const auto& descriptor = getDescriptor(index);
668
669 if (readNullFlag(descriptor))
670 return std::nullopt;
671
672 const auto data = &message[descriptor.offset];
673
674 switch (descriptor.adjustedType)
675 {
677 {
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};
680 }
681
682 default:
683 throwInvalidType("std::vector<std::byte>", descriptor.adjustedType);
684 }
685 }
686
690
694 template <typename T>
695 T get(unsigned index);
696
700 template <Aggregate T>
701 T get()
702 {
703 using namespace impl::reflection;
704
705 constexpr std::size_t N = fieldCountV<T>;
706
707 if (N != descriptors->size())
708 {
709 throw FbCppException("Struct field count (" + std::to_string(N) +
710 ") does not match output column count (" + std::to_string(descriptors->size()) + ")");
711 }
712
713 return getStruct<T>(std::make_index_sequence<N>{});
714 }
715
719 template <TupleLike T>
720 T get()
721 {
722 using namespace impl::reflection;
723
724 constexpr std::size_t N = std::tuple_size_v<T>;
725
726 if (N != descriptors->size())
727 {
728 throw FbCppException("Tuple element count (" + std::to_string(N) +
729 ") does not match output column count (" + std::to_string(descriptors->size()) + ")");
730 }
731
732 return getTuple<T>(std::make_index_sequence<N>{});
733 }
734
738 template <VariantLike V>
739 V get(unsigned index)
740 {
741 using namespace impl::reflection;
742
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.");
747
748 const auto& descriptor = getDescriptor(index);
749
750 if (isNull(index))
751 {
752 if constexpr (variantContainsV<std::monostate, V>)
753 return V{std::monostate{}};
754 else
755 {
756 throw FbCppException(
757 "NULL value encountered but variant does not contain std::monostate at index " +
758 std::to_string(index));
759 }
760 }
761
762 return getVariantValue<V>(index, descriptor);
763 }
764
765 private:
766 const Descriptor& getDescriptor(unsigned index)
767 {
768 if (index >= descriptors->size())
769 throw std::out_of_range("index out of range");
770
771 return (*descriptors)[index];
772 }
773
774 template <typename T, std::size_t... Is>
775 T getStruct(std::index_sequence<Is...>)
776 {
777 using namespace impl::reflection;
778
779 return T{getStructField<FieldType<T, Is>>(static_cast<unsigned>(Is))...};
780 }
781
782 template <typename F>
783 auto getStructField(unsigned index)
784 {
785 using namespace impl::reflection;
786
787 if constexpr (isOptionalV<F>)
788 return get<F>(index);
789 else if constexpr (isVariantV<F>)
790 return get<F>(index);
791 else
792 {
793 auto opt = get<std::optional<F>>(index);
794
795 if (!opt.has_value())
796 {
797 throw FbCppException(
798 "Null value encountered for non-optional field at index " + std::to_string(index));
799 }
800
801 return std::move(opt.value());
802 }
803 }
804
805 template <typename T, std::size_t... Is>
806 T getTuple(std::index_sequence<Is...>)
807 {
808 using namespace impl::reflection;
809
810 return T{getStructField<std::tuple_element_t<Is, T>>(static_cast<unsigned>(Is))...};
811 }
812
813 template <typename V>
814 V getVariantValue(unsigned index, const Descriptor& descriptor)
815 {
816 using namespace impl::reflection;
817
818 switch (descriptor.adjustedType)
819 {
821 if constexpr (variantContainsV<bool, V>)
822 return V{get<std::optional<bool>>(index).value()};
823 break;
824
826 if (descriptor.scale != 0)
827 {
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()};
837#endif
838 }
839 if constexpr (variantContainsV<std::int16_t, V>)
840 return V{get<std::optional<std::int16_t>>(index).value()};
841 break;
842
844 if (descriptor.scale != 0)
845 {
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()};
853#endif
854 }
855 if constexpr (variantContainsV<std::int32_t, V>)
856 return V{get<std::optional<std::int32_t>>(index).value()};
857 break;
858
860 if (descriptor.scale != 0)
861 {
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()};
867#endif
868 }
869 if constexpr (variantContainsV<std::int64_t, V>)
870 return V{get<std::optional<std::int64_t>>(index).value()};
871 break;
872
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)
878 {
879 if constexpr (variantContainsV<ScaledBoostInt128, V>)
880 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
881 }
882 else if constexpr (variantContainsV<BoostInt128, V>)
883 return V{get<std::optional<BoostInt128>>(index).value()};
884#endif
885 break;
886
888 if constexpr (variantContainsV<float, V>)
889 return V{get<std::optional<float>>(index).value()};
890 break;
891
893 if constexpr (variantContainsV<double, V>)
894 return V{get<std::optional<double>>(index).value()};
895 break;
896
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()};
903#endif
904#if FB_CPP_USE_BOOST_DECIMAL != 0
905 else if constexpr (variantContainsV<BoostDecimal64, V>)
906 return V{get<std::optional<BoostDecimal64>>(index).value()};
907#endif
908 break;
909
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()};
916#endif
917#if FB_CPP_USE_BOOST_DECIMAL != 0
918 else if constexpr (variantContainsV<BoostDecimal128, V>)
919 return V{get<std::optional<BoostDecimal128>>(index).value()};
920#endif
921 break;
922
924 if (descriptor.charSetId == impl::CHARSET_OCTETS)
925 {
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()};
930 }
931 else
932 {
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()};
937 }
938 break;
939
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()};
945 break;
946
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()};
952 break;
953
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()};
959 break;
960
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()};
966 break;
967
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()};
973 break;
974
976 if constexpr (variantContainsV<BlobId, V>)
977 return V{get<std::optional<BlobId>>(index).value()};
978 break;
979
981 if constexpr (variantContainsV<ArrayId, V>)
982 return V{get<std::optional<ArrayId>>(index).value()};
983 break;
984
985 default:
986 break;
987 }
988
989 return tryVariantAlternatives<V, 0>(index, descriptor);
990 }
991
992 template <typename V, std::size_t I = 0>
993 V tryVariantAlternatives(unsigned index, [[maybe_unused]] const Descriptor& descriptor)
994 {
995 using namespace impl::reflection;
996
997 if constexpr (I >= std::variant_size_v<V>)
998 {
999 throw FbCppException(
1000 "Cannot convert SQL type to any variant alternative at index " + std::to_string(index));
1001 }
1002 else
1003 {
1004 using Alt = std::variant_alternative_t<I, V>;
1005
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);
1010 else
1011 {
1012 auto opt = get<std::optional<Alt>>(index);
1013 return V{std::move(opt.value())};
1014 }
1015 }
1016 }
1017
1018 // FIXME: floating to integral
1019 template <typename T>
1020 std::optional<T> getNumber(unsigned index, std::optional<int>& scale, const char* typeName)
1021 {
1022 const auto& descriptor = getDescriptor(index);
1023
1024 if (readNullFlag(descriptor))
1025 return std::nullopt;
1026
1027 auto data = &message[descriptor.offset];
1028#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1029 std::optional<BoostInt128> boostInt128;
1030#endif
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;
1037#endif
1038
1039 // FIXME: Use IUtil
1040 switch (descriptor.adjustedType)
1041 {
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());
1047 break;
1048#endif
1049
1050#if FB_CPP_USE_BOOST_DECIMAL != 0
1052 boostDecimal64.emplace(numericConverter.opaqueDecFloat16ToBoostDecimal64(
1053 &statusWrapper, *reinterpret_cast<const OpaqueDecFloat16*>(data)));
1054 data = reinterpret_cast<const std::byte*>(&boostDecimal64.value());
1055 break;
1056
1058 boostDecimal128.emplace(numericConverter.opaqueDecFloat34ToBoostDecimal128(
1059 &statusWrapper, *reinterpret_cast<const OpaqueDecFloat34*>(data)));
1060 data = reinterpret_cast<const std::byte*>(&boostDecimal128.value());
1061 break;
1062#elif FB_CPP_USE_BOOST_MULTIPRECISION != 0
1064 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
1065 &statusWrapper, *reinterpret_cast<const OpaqueDecFloat16*>(data)));
1066 data = reinterpret_cast<const std::byte*>(&boostDecFloat16.value());
1067 break;
1068
1070 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
1071 &statusWrapper, *reinterpret_cast<const OpaqueDecFloat34*>(data)));
1072 data = reinterpret_cast<const std::byte*>(&boostDecFloat34.value());
1073 break;
1074#endif
1075
1076 default:
1077 break;
1078 }
1079
1080 return convertNumber<T>(descriptor, data, scale, typeName);
1081 }
1082
1083 [[noreturn]] static void throwInvalidType(const char* actualType, DescriptorAdjustedType descriptorType)
1084 {
1085 throw FbCppException("Invalid type: actual type " + std::string(actualType) + ", descriptor type " +
1086 std::to_string(static_cast<unsigned>(descriptorType)));
1087 }
1088
1089 template <typename T>
1090 T convertNumber(
1091 const Descriptor& descriptor, const std::byte* data, std::optional<int>& toScale, const char* toTypeName)
1092 {
1093 if (!toScale.has_value())
1094 {
1095 switch (descriptor.adjustedType)
1096 {
1101 throwInvalidType(toTypeName, descriptor.adjustedType);
1102
1103 default:
1104 break;
1105 }
1106
1107 toScale = descriptor.scale;
1108 }
1109
1110 switch (descriptor.adjustedType)
1111 {
1113 return numericConverter.numberToNumber<T>(
1114 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale}, toScale.value());
1115
1117 return numericConverter.numberToNumber<T>(
1118 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale}, toScale.value());
1119
1121 return numericConverter.numberToNumber<T>(
1122 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale}, toScale.value());
1123
1124#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1126 return numericConverter.numberToNumber<T>(
1127 ScaledBoostInt128{*reinterpret_cast<const BoostInt128*>(data), descriptor.scale},
1128 toScale.value());
1129#endif
1130
1131#if FB_CPP_USE_BOOST_DECIMAL != 0
1133 return numericConverter.numberToNumber<T>(
1134 *reinterpret_cast<const BoostDecimal64*>(data), toScale.value());
1135
1137 return numericConverter.numberToNumber<T>(
1138 *reinterpret_cast<const BoostDecimal128*>(data), toScale.value());
1139#elif FB_CPP_USE_BOOST_MULTIPRECISION != 0
1141 return numericConverter.numberToNumber<T>(
1142 *reinterpret_cast<const BoostDecFloat16*>(data), toScale.value());
1143
1145 return numericConverter.numberToNumber<T>(
1146 *reinterpret_cast<const BoostDecFloat34*>(data), toScale.value());
1147#endif
1148
1150 return numericConverter.numberToNumber<T>(*reinterpret_cast<const float*>(data), toScale.value());
1151
1153 return numericConverter.numberToNumber<T>(*reinterpret_cast<const double*>(data), toScale.value());
1154
1155 default:
1156 throwInvalidType(toTypeName, descriptor.adjustedType);
1157 }
1158 }
1159
1160 private:
1165 bool readNullFlag(const Descriptor& descriptor)
1166 {
1167 if (!descriptor.isNullable)
1168 return false;
1169
1170 return *reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE;
1171 }
1172
1173 private:
1174 Client* client;
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;
1180 };
1181
1186
1187 template <>
1188 inline std::optional<bool> Row::get<std::optional<bool>>(unsigned index)
1189 {
1190 return getBool(index);
1191 }
1192
1193 template <>
1194 inline std::optional<BlobId> Row::get<std::optional<BlobId>>(unsigned index)
1195 {
1196 return getBlobId(index);
1197 }
1198
1199 template <>
1200 inline std::optional<ArrayId> Row::get<std::optional<ArrayId>>(unsigned index)
1201 {
1202 return getArrayId(index);
1203 }
1204
1205 template <>
1206 inline std::optional<std::int16_t> Row::get<std::optional<std::int16_t>>(unsigned index)
1207 {
1208 return getInt16(index);
1209 }
1210
1211 template <>
1212 inline std::optional<ScaledInt16> Row::get<std::optional<ScaledInt16>>(unsigned index)
1213 {
1214 return getScaledInt16(index);
1215 }
1216
1217 template <>
1218 inline std::optional<std::int32_t> Row::get<std::optional<std::int32_t>>(unsigned index)
1219 {
1220 return getInt32(index);
1221 }
1222
1223 template <>
1224 inline std::optional<ScaledInt32> Row::get<std::optional<ScaledInt32>>(unsigned index)
1225 {
1226 return getScaledInt32(index);
1227 }
1228
1229 template <>
1230 inline std::optional<std::int64_t> Row::get<std::optional<std::int64_t>>(unsigned index)
1231 {
1232 return getInt64(index);
1233 }
1234
1235 template <>
1236 inline std::optional<ScaledInt64> Row::get<std::optional<ScaledInt64>>(unsigned index)
1237 {
1238 return getScaledInt64(index);
1239 }
1240
1241 template <>
1242 inline std::optional<ScaledOpaqueInt128> Row::get<std::optional<ScaledOpaqueInt128>>(unsigned index)
1243 {
1244 return getScaledOpaqueInt128(index);
1245 }
1246
1247#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1248 template <>
1249 inline std::optional<BoostInt128> Row::get<std::optional<BoostInt128>>(unsigned index)
1250 {
1251 return getBoostInt128(index);
1252 }
1253
1254 template <>
1255 inline std::optional<ScaledBoostInt128> Row::get<std::optional<ScaledBoostInt128>>(unsigned index)
1256 {
1257 return getScaledBoostInt128(index);
1258 }
1259#endif
1260
1261 template <>
1262 inline std::optional<float> Row::get<std::optional<float>>(unsigned index)
1263 {
1264 return getFloat(index);
1265 }
1266
1267 template <>
1268 inline std::optional<double> Row::get<std::optional<double>>(unsigned index)
1269 {
1270 return getDouble(index);
1271 }
1272
1273 template <>
1274 inline std::optional<OpaqueDecFloat16> Row::get<std::optional<OpaqueDecFloat16>>(unsigned index)
1275 {
1276 return getOpaqueDecFloat16(index);
1277 }
1278
1279#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1280 template <>
1281 inline std::optional<BoostDecFloat16> Row::get<std::optional<BoostDecFloat16>>(unsigned index)
1282 {
1283 return getBoostDecFloat16(index);
1284 }
1285#endif
1286
1287#if FB_CPP_USE_BOOST_DECIMAL != 0
1288 template <>
1289 inline std::optional<BoostDecimal32> Row::get<std::optional<BoostDecimal32>>(unsigned index)
1290 {
1291 return getBoostDecimal32(index);
1292 }
1293
1294 template <>
1295 inline std::optional<BoostDecimal64> Row::get<std::optional<BoostDecimal64>>(unsigned index)
1296 {
1297 return getBoostDecimal64(index);
1298 }
1299#endif
1300
1301 template <>
1302 inline std::optional<OpaqueDecFloat34> Row::get<std::optional<OpaqueDecFloat34>>(unsigned index)
1303 {
1304 return getOpaqueDecFloat34(index);
1305 }
1306
1307#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1308 template <>
1309 inline std::optional<BoostDecFloat34> Row::get<std::optional<BoostDecFloat34>>(unsigned index)
1310 {
1311 return getBoostDecFloat34(index);
1312 }
1313#endif
1314
1315#if FB_CPP_USE_BOOST_DECIMAL != 0
1316 template <>
1317 inline std::optional<BoostDecimal128> Row::get<std::optional<BoostDecimal128>>(unsigned index)
1318 {
1319 return getBoostDecimal128(index);
1320 }
1321#endif
1322
1323 template <>
1324 inline std::optional<Date> Row::get<std::optional<Date>>(unsigned index)
1325 {
1326 return getDate(index);
1327 }
1328
1329 template <>
1330 inline std::optional<OpaqueDate> Row::get<std::optional<OpaqueDate>>(unsigned index)
1331 {
1332 return getOpaqueDate(index);
1333 }
1334
1335 template <>
1336 inline std::optional<Time> Row::get<std::optional<Time>>(unsigned index)
1337 {
1338 return getTime(index);
1339 }
1340
1341 template <>
1342 inline std::optional<OpaqueTime> Row::get<std::optional<OpaqueTime>>(unsigned index)
1343 {
1344 return getOpaqueTime(index);
1345 }
1346
1347 template <>
1348 inline std::optional<OpaqueTimestamp> Row::get<std::optional<OpaqueTimestamp>>(unsigned index)
1349 {
1350 return getOpaqueTimestamp(index);
1351 }
1352
1353 template <>
1354 inline std::optional<Timestamp> Row::get<std::optional<Timestamp>>(unsigned index)
1355 {
1356 return getTimestamp(index);
1357 }
1358
1359 template <>
1360 inline std::optional<TimeTz> Row::get<std::optional<TimeTz>>(unsigned index)
1361 {
1362 return getTimeTz(index);
1363 }
1364
1365 template <>
1366 inline std::optional<OpaqueTimeTz> Row::get<std::optional<OpaqueTimeTz>>(unsigned index)
1367 {
1368 return getOpaqueTimeTz(index);
1369 }
1370
1371 template <>
1372 inline std::optional<TimestampTz> Row::get<std::optional<TimestampTz>>(unsigned index)
1373 {
1374 return getTimestampTz(index);
1375 }
1376
1377 template <>
1378 inline std::optional<OpaqueTimestampTz> Row::get<std::optional<OpaqueTimestampTz>>(unsigned index)
1379 {
1380 return getOpaqueTimestampTz(index);
1381 }
1382
1383 template <>
1384 inline std::optional<std::string> Row::get<std::optional<std::string>>(unsigned index)
1385 {
1386 return getString(index);
1387 }
1388
1389 template <>
1390 inline std::optional<std::vector<std::byte>> Row::get<std::optional<std::vector<std::byte>>>(unsigned index)
1391 {
1392 return getBytes(index);
1393 }
1394
1398} // namespace fbcpp
1399
1400
1401#endif // FBCPP_ROW_H
Represents a Firebird array identifier.
Definition Array.h:51
ISC_QUAD id
Stores the raw Firebird array identifier value.
Definition Array.h:61
Represents a Firebird blob identifier.
Definition Blob.h:53
ISC_QUAD id
Stores the raw Firebird blob identifier value.
Definition Blob.h:65
Represents a Firebird client library instance.
Definition Client.h:54
Base exception class for all fb-cpp exceptions.
Definition Exception.h:231
A lightweight, non-owning view of a single row's data with typed accessors.
Definition Row.h:71
std::optional< BoostDecFloat16 > getBoostDecFloat16(unsigned index)
Reads a Boost-based 16-digit decimal floating-point column.
Definition Row.h:267
std::optional< std::int32_t > getInt32(unsigned index)
Reads a 32-bit signed integer column.
Definition Row.h:146
std::optional< OpaqueTimestamp > getOpaqueTimestamp(unsigned index)
Reads a raw timestamp column in Firebird's representation.
Definition Row.h:442
T get()
Retrieves all output columns into a user-defined aggregate struct.
Definition Row.h:701
std::optional< Timestamp > getTimestamp(unsigned index)
Reads a timestamp column without timezone.
Definition Row.h:421
std::optional< Time > getTime(unsigned index)
Reads a time-of-day column without timezone.
Definition Row.h:380
std::optional< TimestampTz > getTimestampTz(unsigned index)
Reads a timestamp-with-time-zone column.
Definition Row.h:503
std::optional< ScaledInt16 > getScaledInt16(unsigned index)
Reads a scaled 16-bit signed integer column.
Definition Row.h:136
std::optional< float > getFloat(unsigned index)
Reads a single precision floating-point column.
Definition Row.h:228
Row(Client &client, const std::vector< Descriptor > &descriptors, std::span< const std::byte > message)
Constructs a Row view over the given message buffer.
Definition Row.h:80
std::optional< OpaqueTimestampTz > getOpaqueTimestampTz(unsigned index)
Reads a raw timestamp-with-time-zone column in Firebird's representation.
Definition Row.h:524
std::optional< BoostInt128 > getBoostInt128(unsigned index)
Reads a Boost 128-bit integer column.
Definition Row.h:207
std::optional< TimeTz > getTimeTz(unsigned index)
Reads a time-of-day column with timezone.
Definition Row.h:462
V get(unsigned index)
Retrieves a column value as a user-defined variant type.
Definition Row.h:739
std::optional< OpaqueTimeTz > getOpaqueTimeTz(unsigned index)
Reads a raw time-of-day column with timezone in Firebird's representation.
Definition Row.h:483
std::optional< ArrayId > getArrayId(unsigned index)
Reads an array identifier column.
Definition Row.h:568
std::optional< ScaledOpaqueInt128 > getScaledOpaqueInt128(unsigned index)
Reads a Firebird scaled 128-bit integer column.
Definition Row.h:184
std::optional< std::int64_t > getInt64(unsigned index)
Reads a 64-bit signed integer column.
Definition Row.h:165
std::optional< ScaledBoostInt128 > getScaledBoostInt128(unsigned index)
Reads a scaled Boost 128-bit integer column.
Definition Row.h:217
std::optional< ScaledInt32 > getScaledInt32(unsigned index)
Reads a scaled 32-bit signed integer column.
Definition Row.h:155
std::optional< BoostDecimal64 > getBoostDecimal64(unsigned index)
Reads a Boost.Decimal 16-digit decimal floating-point column.
Definition Row.h:287
std::optional< OpaqueDecFloat16 > getOpaqueDecFloat16(unsigned index)
Reads a Firebird 16-digit decimal floating-point column.
Definition Row.h:246
std::optional< double > getDouble(unsigned index)
Reads a double precision floating-point column.
Definition Row.h:237
std::optional< BoostDecimal32 > getBoostDecimal32(unsigned index)
Reads a Boost.Decimal 7-digit decimal floating-point column.
Definition Row.h:278
bool isNull(unsigned index)
Reports whether the row has a null at the given column.
Definition Row.h:98
std::optional< BlobId > getBlobId(unsigned index)
Reads a blob identifier column.
Definition Row.h:544
std::optional< std::int16_t > getInt16(unsigned index)
Reads a 16-bit signed integer column.
Definition Row.h:127
std::optional< OpaqueDate > getOpaqueDate(unsigned index)
Reads a raw date column in Firebird's representation.
Definition Row.h:360
std::optional< OpaqueDecFloat34 > getOpaqueDecFloat34(unsigned index)
Reads a Firebird 34-digit decimal floating-point column.
Definition Row.h:297
std::optional< std::vector< std::byte > > getBytes(unsigned index)
Reads a text or varying column as its raw bytes.
Definition Row.h:665
std::optional< Date > getDate(unsigned index)
Reads a date column.
Definition Row.h:339
std::optional< ScaledInt64 > getScaledInt64(unsigned index)
Reads a scaled 64-bit signed integer column.
Definition Row.h:174
std::optional< BoostDecFloat34 > getBoostDecFloat34(unsigned index)
Reads a Boost-based 34-digit decimal floating-point column.
Definition Row.h:318
std::optional< std::string > getString(unsigned index)
Reads a textual column, applying number-to-string conversions when needed.
Definition Row.h:592
std::optional< bool > getBool(unsigned index)
Reads a boolean column.
Definition Row.h:107
std::optional< OpaqueTime > getOpaqueTime(unsigned index)
Reads a raw time-of-day column in Firebird's representation.
Definition Row.h:401
std::optional< BoostDecimal128 > getBoostDecimal128(unsigned index)
Reads a Boost.Decimal 34-digit decimal floating-point column.
Definition Row.h:329
T get(unsigned index)
Retrieves a column using the most appropriate typed accessor specialization.
fb-cpp namespace.
Definition Array.h:43
ScaledNumber< std::int64_t > ScaledInt64
Signed 64-bit scaled number.
Definition types.h:93
ScaledNumber< std::int32_t > ScaledInt32
Signed 32-bit scaled number.
Definition types.h:88
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 34 > > BoostDecFloat34
34-digit decimal floating point using Boost.Multiprecision.
Definition types.h:116
FB_DEC16 OpaqueDecFloat16
Opaque 16-digit decimal floating point exposed by the Firebird API.
Definition types.h:236
ScaledNumber< std::int16_t > ScaledInt16
Signed 16-bit scaled number.
Definition types.h:83
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 16 > > BoostDecFloat16
16-digit decimal floating point using Boost.Multiprecision.
Definition types.h:111
boost::decimal::decimal128_t BoostDecimal128
34-digit decimal floating point using Boost.Decimal.
Definition types.h:133
DescriptorAdjustedType
Descriptor adjusted type.
Definition Descriptor.h:161
@ BLOB
Binary large object.
@ TIME
Time of day without time zone.
@ DECFLOAT34
34-digit decimal floating point.
@ INT64
64-bit signed integer.
@ TIME_TZ
Time of day with time zone.
@ DECFLOAT16
16-digit decimal floating point.
@ INT16
16-bit signed integer.
@ STRING
String type (variable-length).
@ INT32
32-bit signed integer.
@ TIMESTAMP
Timestamp without time zone.
@ TIMESTAMP_TZ
Timestamp with time zone.
@ INT128
128-bit signed integer.
@ ARRAY
Array value represented by an array identifier.
@ FLOAT
Single-precision floating point.
@ DOUBLE
Double-precision floating point.
FB_I128 OpaqueInt128
Opaque 128-bit integer exposed by the Firebird API.
Definition types.h:231
FB_DEC34 OpaqueDecFloat34
Opaque 34-digit decimal floating point exposed by the Firebird API.
Definition types.h:241
boost::multiprecision::int128_t BoostInt128
128-bit integer using Boost.Multiprecision.
Definition types.h:99
ScaledNumber< BoostInt128 > ScaledBoostInt128
Scaled 128-bit integer backed by Boost.Multiprecision.
Definition types.h:104
boost::decimal::decimal64_t BoostDecimal64
16-digit decimal floating point using Boost.Decimal.
Definition types.h:128
Describes a parameter or column.
Definition Descriptor.h:267
Wrapper for Firebird date values.
Definition types.h:252
Wrapper for Firebird time-with-time-zone values.
Definition types.h:294
Wrapper for Firebird time values.
Definition types.h:265
Wrapper for Firebird timestamp-with-time-zone values.
Definition types.h:310
Wrapper for Firebird timestamp values.
Definition types.h:278
Represents a numeric value with an explicit decimal scale.
Definition types.h:57
int scale
Decimal scale applied to value.
Definition types.h:77
T value
Unscaled numeric value.
Definition types.h:72