fb-cpp 0.0.2
A modern C++ wrapper for the Firebird database API
Loading...
Searching...
No Matches
Statement.h
1/*
2 * MIT License
3 *
4 * Copyright (c) 2025 Adriano dos Santos Fernandes
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_STATEMENT_H
26#define FBCPP_STATEMENT_H
27
28#include "config.h"
29#include "fb-api.h"
30#include "types.h"
31#include "Blob.h"
32#include "Attachment.h"
33#include "Client.h"
34#include "NumericConverter.h"
35#include "CalendarConverter.h"
36#include "Descriptor.h"
37#include "SmartPtrs.h"
38#include "Exception.h"
39#include "StructBinding.h"
40#include "VariantTypeTraits.h"
41#include <charconv>
42#include <cerrno>
43#include <cstdlib>
44#include <limits>
45#include <memory>
46#include <optional>
47#include <stdexcept>
48#include <string>
49#include <string_view>
50#include <type_traits>
51#include <vector>
52#include <cassert>
53#include <cmath>
54#include <cstddef>
55#include <cstdint>
56
57#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
58#include <boost/multiprecision/cpp_int.hpp>
59#include <boost/multiprecision/cpp_dec_float.hpp>
60#endif
61
65namespace fbcpp
66{
67 class Transaction;
68
72 enum class CursorType
73 {
78
83 };
84
88 class StatementOptions final
89 {
90 public:
95 {
96 return prefetchLegacyPlan;
97 }
98
105 {
106 prefetchLegacyPlan = value;
107 return *this;
108 }
109
113 bool getPrefetchPlan() const
114 {
115 return prefetchPlan;
116 }
117
124 {
125 prefetchPlan = value;
126 return *this;
127 }
128
132 const std::optional<std::string>& getCursorName() const
133 {
134 return cursorName;
135 }
136
142 StatementOptions& setCursorName(const std::string& value)
143 {
144 cursorName = value;
145 return *this;
146 }
147
152 {
153 return cursorType;
154 }
155
162 {
163 cursorType = value;
164 return *this;
165 }
166
167 private:
168 bool prefetchLegacyPlan = false;
169 bool prefetchPlan = false;
170 std::optional<std::string> cursorName;
172 };
173
177 enum class StatementType : unsigned
178 {
182 SELECT = isc_info_sql_stmt_select,
186 INSERT = isc_info_sql_stmt_insert,
190 UPDATE = isc_info_sql_stmt_update,
194 DELETE = isc_info_sql_stmt_delete,
198 DDL = isc_info_sql_stmt_ddl,
202 GET_SEGMENT = isc_info_sql_stmt_get_segment,
206 PUT_SEGMENT = isc_info_sql_stmt_put_segment,
210 EXEC_PROCEDURE = isc_info_sql_stmt_exec_procedure,
214 START_TRANSACTION = isc_info_sql_stmt_start_trans,
218 COMMIT = isc_info_sql_stmt_commit,
222 ROLLBACK = isc_info_sql_stmt_rollback,
226 SELECT_FOR_UPDATE = isc_info_sql_stmt_select_for_upd,
230 SET_GENERATOR = isc_info_sql_stmt_set_generator,
234 SAVEPOINT = isc_info_sql_stmt_savepoint,
235 };
236
240 class Statement final
241 {
242 public:
250 explicit Statement(Attachment& attachment, Transaction& transaction, std::string_view sql,
251 const StatementOptions& options = {});
252
256 Statement(Statement&& o) noexcept
257 : attachment{o.attachment},
258 status{std::move(o.status)},
259 statusWrapper{std::move(o.statusWrapper)},
260 calendarConverter{std::move(o.calendarConverter)},
261 numericConverter{std::move(o.numericConverter)},
262 statementHandle{std::move(o.statementHandle)},
263 resultSetHandle{std::move(o.resultSetHandle)},
264 inMetadata{std::move(o.inMetadata)},
265 inDescriptors{std::move(o.inDescriptors)},
266 inMessage{std::move(o.inMessage)},
267 outMetadata{std::move(o.outMetadata)},
268 outDescriptors{std::move(o.outDescriptors)},
269 outMessage{std::move(o.outMessage)},
270 type{o.type},
271 cursorFlags{o.cursorFlags}
272 {
273 }
274
282 {
283 if (this != &o)
284 {
285 attachment = o.attachment;
286 status = std::move(o.status);
287 statusWrapper = std::move(o.statusWrapper);
288 calendarConverter = std::move(o.calendarConverter);
289 numericConverter = std::move(o.numericConverter);
290 statementHandle = std::move(o.statementHandle);
291 resultSetHandle = std::move(o.resultSetHandle);
292 inMetadata = std::move(o.inMetadata);
293 inDescriptors = std::move(o.inDescriptors);
294 inMessage = std::move(o.inMessage);
295 outMetadata = std::move(o.outMetadata);
296 outDescriptors = std::move(o.outDescriptors);
297 outMessage = std::move(o.outMessage);
298 type = o.type;
299 cursorFlags = o.cursorFlags;
300 }
301
302 return *this;
303 }
304
305 Statement(const Statement&) = delete;
306 Statement& operator=(const Statement&) = delete;
307
311 ~Statement() noexcept
312 {
313 if (isValid())
314 {
315 try
316 {
317 free();
318 }
319 catch (...)
320 {
321 // swallow
322 }
323 }
324 }
325
326 public:
332
336 bool isValid() noexcept
337 {
338 return statementHandle != nullptr;
339 }
340
346 {
347 return statementHandle;
348 }
349
355 {
356 return resultSetHandle;
357 }
358
363 {
364 return inMetadata;
365 }
366
371 {
372 return outMetadata;
373 }
374
379 {
380 return type;
381 }
382
386
392
396 const std::vector<Descriptor>& getInputDescriptors() noexcept
397 {
398 return inDescriptors;
399 }
400
404 const std::vector<Descriptor>& getOutputDescriptors() noexcept
405 {
406 return outDescriptors;
407 }
408
412
416 void free();
417
421 std::string getLegacyPlan();
422
426 std::string getPlan();
427
433 bool execute(Transaction& transaction);
434
438
442 bool fetchNext();
443
447 bool fetchPrior();
448
452 bool fetchFirst();
453
457 bool fetchLast();
458
462 bool fetchAbsolute(unsigned position);
463
467 bool fetchRelative(int offset);
468
472
476
481 {
482 assert(isValid());
483
484 const auto message = inMessage.data();
485
486 for (const auto& descriptor : inDescriptors)
487 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_TRUE;
488 }
489
494 void setNull(unsigned index)
495 {
496 assert(isValid());
497
498 const auto& descriptor = getInDescriptor(index);
499 const auto message = inMessage.data();
500
501 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_TRUE;
502 }
503
509 void setBool(unsigned index, std::optional<bool> optValue)
510 {
511 if (!optValue.has_value())
512 {
513 setNull(index);
514 return;
515 }
516
517 assert(isValid());
518
519 const auto& value = optValue.value();
520 const auto& descriptor = getInDescriptor(index);
521 const auto message = inMessage.data();
522
523 switch (descriptor.adjustedType)
524 {
526 message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
527 break;
528
529 default:
530 throwInvalidType("bool", descriptor.adjustedType);
531 }
532
533 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
534 }
535
539 void setInt16(unsigned index, std::optional<std::int16_t> optValue)
540 {
541 if (!optValue.has_value())
542 {
543 setNull(index);
544 return;
545 }
546
547 setNumber(index, DescriptorAdjustedType::INT16, optValue.value(), 0, "std::int16_t");
548 }
549
553 void setScaledInt16(unsigned index, std::optional<ScaledInt16> optValue)
554 {
555 if (!optValue.has_value())
556 {
557 setNull(index);
558 return;
559 }
560
561 const auto& value = optValue.value();
562 setNumber(index, DescriptorAdjustedType::INT16, value.value, value.scale, "ScaledInt16");
563 }
564
568 void setInt32(unsigned index, std::optional<std::int32_t> optValue)
569 {
570 if (!optValue.has_value())
571 {
572 setNull(index);
573 return;
574 }
575
576 setNumber(index, DescriptorAdjustedType::INT32, optValue.value(), 0, "std::int32_t");
577 }
578
582 void setScaledInt32(unsigned index, std::optional<ScaledInt32> optValue)
583 {
584 if (!optValue.has_value())
585 {
586 setNull(index);
587 return;
588 }
589
590 const auto& value = optValue.value();
591 setNumber(index, DescriptorAdjustedType::INT32, value.value, value.scale, "ScaledInt32");
592 }
593
597 void setInt64(unsigned index, std::optional<std::int64_t> optValue)
598 {
599 if (!optValue.has_value())
600 {
601 setNull(index);
602 return;
603 }
604
605 setNumber(index, DescriptorAdjustedType::INT64, optValue.value(), 0, "std::int64_t");
606 }
607
611 void setScaledInt64(unsigned index, std::optional<ScaledInt64> optValue)
612 {
613 if (!optValue.has_value())
614 {
615 setNull(index);
616 return;
617 }
618
619 const auto& value = optValue.value();
620 setNumber(index, DescriptorAdjustedType::INT64, value.value, value.scale, "ScaledInt64");
621 }
622
626 void setOpaqueInt128(unsigned index, std::optional<OpaqueInt128> optValue)
627 {
628 if (!optValue.has_value())
629 {
630 setNull(index);
631 return;
632 }
633
634 assert(isValid());
635
636 const auto& value = optValue.value();
637 const auto& descriptor = getInDescriptor(index);
638 const auto message = inMessage.data();
639
640 switch (descriptor.adjustedType)
641 {
643 *reinterpret_cast<OpaqueInt128*>(&message[descriptor.offset]) = value;
644 break;
645
646 default:
647 throwInvalidType("OpaqueInt128", descriptor.adjustedType);
648 }
649
650 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
651 }
652
653#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
657 void setBoostInt128(unsigned index, std::optional<BoostInt128> optValue)
658 {
659 if (!optValue.has_value())
660 {
661 setNull(index);
662 return;
663 }
664
665 setNumber(index, DescriptorAdjustedType::INT128, optValue.value(), 0, "BoostInt128");
666 }
667
671 void setScaledBoostInt128(unsigned index, std::optional<ScaledBoostInt128> optValue)
672 {
673 if (!optValue.has_value())
674 {
675 setNull(index);
676 return;
677 }
678
679 const auto& value = optValue.value();
680 setNumber(index, DescriptorAdjustedType::INT128, value.value, value.scale, "ScaledBoostInt128");
681 }
682#endif
683
687 void setFloat(unsigned index, std::optional<float> optValue)
688 {
689 if (!optValue.has_value())
690 {
691 setNull(index);
692 return;
693 }
694
695 setNumber(index, DescriptorAdjustedType::FLOAT, optValue.value(), 0, "float");
696 }
697
701 void setDouble(unsigned index, std::optional<double> optValue)
702 {
703 if (!optValue.has_value())
704 {
705 setNull(index);
706 return;
707 }
708
709 setNumber(index, DescriptorAdjustedType::DOUBLE, optValue.value(), 0, "double");
710 }
711
715 void setOpaqueDecFloat16(unsigned index, std::optional<OpaqueDecFloat16> optValue)
716 {
717 if (!optValue.has_value())
718 {
719 setNull(index);
720 return;
721 }
722
723 assert(isValid());
724
725 const auto& value = optValue.value();
726 const auto& descriptor = getInDescriptor(index);
727 const auto message = inMessage.data();
728
729 switch (descriptor.adjustedType)
730 {
732 *reinterpret_cast<OpaqueDecFloat16*>(&message[descriptor.offset]) = value;
733 break;
734
735 default:
736 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
737 }
738
739 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
740 }
741
742#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
746 void setBoostDecFloat16(unsigned index, std::optional<BoostDecFloat16> optValue)
747 {
748 if (!optValue.has_value())
749 {
750 setNull(index);
751 return;
752 }
753
754 setNumber(index, DescriptorAdjustedType::DECFLOAT16, optValue.value(), 0, "BoostDecFloat16");
755 }
756#endif
757
761 void setOpaqueDecFloat34(unsigned index, std::optional<OpaqueDecFloat34> optValue)
762 {
763 if (!optValue.has_value())
764 {
765 setNull(index);
766 return;
767 }
768
769 assert(isValid());
770
771 const auto& value = optValue.value();
772 const auto& descriptor = getInDescriptor(index);
773 const auto message = inMessage.data();
774
775 switch (descriptor.adjustedType)
776 {
778 *reinterpret_cast<OpaqueDecFloat34*>(&message[descriptor.offset]) = value;
779 break;
780
781 default:
782 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
783 }
784
785 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
786 }
787
788#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
792 void setBoostDecFloat34(unsigned index, std::optional<BoostDecFloat34> optValue)
793 {
794 if (!optValue.has_value())
795 {
796 setNull(index);
797 return;
798 }
799
800 setNumber(index, DescriptorAdjustedType::DECFLOAT34, optValue.value(), 0, "BoostDecFloat34");
801 }
802#endif
803
807 void setDate(unsigned index, std::optional<Date> optValue)
808 {
809 if (!optValue.has_value())
810 {
811 setNull(index);
812 return;
813 }
814
815 assert(isValid());
816
817 const auto& value = optValue.value();
818 const auto& descriptor = getInDescriptor(index);
819 const auto message = inMessage.data();
820
821 switch (descriptor.adjustedType)
822 {
824 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) =
825 calendarConverter.dateToOpaqueDate(value);
826 break;
827
828 default:
829 throwInvalidType("Date", descriptor.adjustedType);
830 }
831
832 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
833 }
834
838 void setOpaqueDate(unsigned index, std::optional<OpaqueDate> optValue)
839 {
840 if (!optValue.has_value())
841 {
842 setNull(index);
843 return;
844 }
845
846 assert(isValid());
847
848 const auto& value = optValue.value();
849 const auto& descriptor = getInDescriptor(index);
850 const auto message = inMessage.data();
851
852 switch (descriptor.adjustedType)
853 {
855 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) = value;
856 break;
857
858 default:
859 throwInvalidType("OpaqueDate", descriptor.adjustedType);
860 }
861
862 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
863 }
864
868 void setTime(unsigned index, std::optional<Time> optValue)
869 {
870 if (!optValue.has_value())
871 {
872 setNull(index);
873 return;
874 }
875
876 assert(isValid());
877
878 const auto& value = optValue.value();
879 const auto& descriptor = getInDescriptor(index);
880 const auto message = inMessage.data();
881
882 switch (descriptor.adjustedType)
883 {
885 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) =
886 calendarConverter.timeToOpaqueTime(value);
887 break;
888
889 default:
890 throwInvalidType("Time", descriptor.adjustedType);
891 }
892
893 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
894 }
895
899 void setOpaqueTime(unsigned index, std::optional<OpaqueTime> optValue)
900 {
901 if (!optValue.has_value())
902 {
903 setNull(index);
904 return;
905 }
906
907 assert(isValid());
908
909 const auto& value = optValue.value();
910 const auto& descriptor = getInDescriptor(index);
911 const auto message = inMessage.data();
912
913 switch (descriptor.adjustedType)
914 {
916 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) = value;
917 break;
918
919 default:
920 throwInvalidType("OpaqueTime", descriptor.adjustedType);
921 }
922
923 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
924 }
925
929 void setTimestamp(unsigned index, std::optional<Timestamp> optValue)
930 {
931 if (!optValue.has_value())
932 {
933 setNull(index);
934 return;
935 }
936
937 assert(isValid());
938
939 const auto& value = optValue.value();
940 const auto& descriptor = getInDescriptor(index);
941 const auto message = inMessage.data();
942
943 switch (descriptor.adjustedType)
944 {
946 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) =
947 calendarConverter.timestampToOpaqueTimestamp(value);
948 break;
949
950 default:
951 throwInvalidType("Timestamp", descriptor.adjustedType);
952 }
953
954 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
955 }
956
960 void setOpaqueTimestamp(unsigned index, std::optional<OpaqueTimestamp> optValue)
961 {
962 if (!optValue.has_value())
963 {
964 setNull(index);
965 return;
966 }
967
968 assert(isValid());
969
970 const auto& value = optValue.value();
971 const auto& descriptor = getInDescriptor(index);
972 const auto message = inMessage.data();
973
974 switch (descriptor.adjustedType)
975 {
977 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) = value;
978 break;
979
980 default:
981 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
982 }
983
984 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
985 }
986
990 void setTimeTz(unsigned index, std::optional<TimeTz> optValue)
991 {
992 if (!optValue.has_value())
993 {
994 setNull(index);
995 return;
996 }
997
998 assert(isValid());
999
1000 const auto& value = optValue.value();
1001 const auto& descriptor = getInDescriptor(index);
1002 auto* const message = inMessage.data();
1003
1004 switch (descriptor.adjustedType)
1005 {
1007 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) =
1008 calendarConverter.timeTzToOpaqueTimeTz(value);
1009 break;
1010
1011 default:
1012 throwInvalidType("TimeTz", descriptor.adjustedType);
1013 }
1014
1015 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1016 }
1017
1021 void setOpaqueTimeTz(unsigned index, std::optional<OpaqueTimeTz> optValue)
1022 {
1023 if (!optValue.has_value())
1024 {
1025 setNull(index);
1026 return;
1027 }
1028
1029 assert(isValid());
1030
1031 const auto& value = optValue.value();
1032 const auto& descriptor = getInDescriptor(index);
1033 auto* const message = inMessage.data();
1034
1035 switch (descriptor.adjustedType)
1036 {
1038 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) = value;
1039 break;
1040
1041 default:
1042 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
1043 }
1044
1045 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1046 }
1047
1051 void setTimestampTz(unsigned index, std::optional<TimestampTz> optValue)
1052 {
1053 if (!optValue.has_value())
1054 {
1055 setNull(index);
1056 return;
1057 }
1058
1059 assert(isValid());
1060
1061 const auto& value = optValue.value();
1062 const auto& descriptor = getInDescriptor(index);
1063 auto* const message = inMessage.data();
1064
1065 switch (descriptor.adjustedType)
1066 {
1068 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) =
1069 calendarConverter.timestampTzToOpaqueTimestampTz(value);
1070 break;
1071
1072 default:
1073 throwInvalidType("TimestampTz", descriptor.adjustedType);
1074 }
1075
1076 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1077 }
1078
1082 void setOpaqueTimestampTz(unsigned index, std::optional<OpaqueTimestampTz> optValue)
1083 {
1084 if (!optValue.has_value())
1085 {
1086 setNull(index);
1087 return;
1088 }
1089
1090 assert(isValid());
1091
1092 const auto& value = optValue.value();
1093 const auto& descriptor = getInDescriptor(index);
1094 auto* const message = inMessage.data();
1095
1096 switch (descriptor.adjustedType)
1097 {
1099 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) = value;
1100 break;
1101
1102 default:
1103 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
1104 }
1105
1106 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1107 }
1108
1112 void setString(unsigned index, std::optional<std::string_view> optValue)
1113 {
1114 if (!optValue.has_value())
1115 {
1116 setNull(index);
1117 return;
1118 }
1119
1120 assert(isValid());
1121
1122 auto& client = attachment->getClient();
1123 const auto value = optValue.value();
1124 const auto& descriptor = getInDescriptor(index);
1125 const auto message = inMessage.data();
1126 const auto data = &message[descriptor.offset];
1127
1128 switch (descriptor.adjustedType)
1129 {
1131 message[descriptor.offset] = numericConverter.stringToBoolean(value);
1132 break;
1133
1137 {
1138 std::string strValue(value);
1139 int scale = 0;
1140
1141 if (const auto dotPos = strValue.find_last_of('.'); dotPos != std::string_view::npos)
1142 {
1143 for (auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1144 {
1145 const char c = value[pos];
1146
1147 if (c < '0' || c > '9')
1148 break;
1149
1150 --scale;
1151 }
1152
1153 strValue.erase(dotPos, 1);
1154 }
1155
1156 static_assert(sizeof(long long) == sizeof(std::int64_t));
1157 std::int64_t intValue;
1158 const auto convResult =
1159 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1160 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1161 numericConverter.throwConversionErrorFromString(strValue);
1162 auto scaledValue = ScaledInt64{intValue, scale};
1163
1164 if (scale != descriptor.scale)
1165 {
1166 scaledValue.value =
1167 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1168 scaledValue.scale = descriptor.scale;
1169 }
1170
1171 setScaledInt64(index, scaledValue);
1172 return;
1173 }
1174
1176 {
1177 std::string strValue(value);
1178 client.getInt128Util(&statusWrapper)
1179 ->fromString(
1180 &statusWrapper, descriptor.scale, strValue.c_str(), reinterpret_cast<OpaqueInt128*>(data));
1181 break;
1182 }
1183
1186 {
1187 double doubleValue;
1188#if defined(__APPLE__)
1189 errno = 0;
1190 std::string valueString{value};
1191 char* parseEnd = nullptr;
1192 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1193 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1194 numericConverter.throwConversionErrorFromString(std::move(valueString));
1195#else
1196 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1197 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1198 numericConverter.throwConversionErrorFromString(std::string{value});
1199#endif
1200 setDouble(index, doubleValue);
1201 return;
1202 }
1203
1205 *reinterpret_cast<OpaqueDate*>(data) = calendarConverter.stringToOpaqueDate(value);
1206 break;
1207
1209 *reinterpret_cast<OpaqueTime*>(data) = calendarConverter.stringToOpaqueTime(value);
1210 break;
1211
1213 *reinterpret_cast<OpaqueTimestamp*>(data) = calendarConverter.stringToOpaqueTimestamp(value);
1214 break;
1215
1217 *reinterpret_cast<OpaqueTimeTz*>(data) = calendarConverter.stringToOpaqueTimeTz(value);
1218 break;
1219
1221 *reinterpret_cast<OpaqueTimestampTz*>(data) = calendarConverter.stringToOpaqueTimestampTz(value);
1222 break;
1223
1224#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1226 {
1227 std::string strValue{value};
1228 client.getDecFloat16Util(&statusWrapper)
1229 ->fromString(&statusWrapper, strValue.c_str(), reinterpret_cast<OpaqueDecFloat16*>(data));
1230 break;
1231 }
1232
1234 {
1235 std::string strValue{value};
1236 client.getDecFloat34Util(&statusWrapper)
1237 ->fromString(&statusWrapper, strValue.c_str(), reinterpret_cast<OpaqueDecFloat34*>(data));
1238 break;
1239 }
1240#endif
1241
1243 if (value.length() > descriptor.length)
1244 {
1245 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1246 isc_arith_except,
1247 isc_string_truncation,
1248 isc_arg_end,
1249 };
1250
1251 throw DatabaseException(client, STATUS_STRING_TRUNCATION);
1252 }
1253
1254 *reinterpret_cast<std::uint16_t*>(data) = static_cast<std::uint16_t>(value.length());
1255 std::copy(value.begin(), value.end(),
1256 reinterpret_cast<char*>(&message[descriptor.offset + sizeof(std::uint16_t)]));
1257 break;
1258
1259 default:
1260 throwInvalidType("std::string_view", descriptor.adjustedType);
1261 }
1262
1263 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1264 }
1265
1269 void setBlobId(unsigned index, std::optional<BlobId> optValue)
1270 {
1271 if (!optValue.has_value())
1272 {
1273 setNull(index);
1274 return;
1275 }
1276
1277 assert(isValid());
1278
1279 const auto& value = optValue.value();
1280 const auto& descriptor = getInDescriptor(index);
1281 auto* const message = inMessage.data();
1282
1283 switch (descriptor.adjustedType)
1284 {
1286 *reinterpret_cast<ISC_QUAD*>(&message[descriptor.offset]) = value.id;
1287 break;
1288
1289 default:
1290 throwInvalidType("BlobId", descriptor.adjustedType);
1291 }
1292
1293 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1294 }
1295
1298 void set(unsigned index, std::nullopt_t)
1299 {
1300 setNull(index);
1301 }
1302
1306 void set(unsigned index, BlobId value)
1307 {
1308 setBlobId(index, value);
1309 }
1310
1314 void set(unsigned index, std::optional<BlobId> value)
1315 {
1316 setBlobId(index, value);
1317 }
1318
1322 void set(unsigned index, bool value)
1323 {
1324 setBool(index, value);
1325 }
1326
1330 void set(unsigned index, std::int16_t value)
1331 {
1332 setInt16(index, value);
1333 }
1334
1338 void set(unsigned index, ScaledInt16 value)
1339 {
1340 setScaledInt16(index, value);
1341 }
1342
1346 void set(unsigned index, std::int32_t value)
1347 {
1348 setInt32(index, value);
1349 }
1350
1354 void set(unsigned index, ScaledInt32 value)
1355 {
1356 setScaledInt32(index, value);
1357 }
1358
1362 void set(unsigned index, std::int64_t value)
1363 {
1364 setInt64(index, value);
1365 }
1366
1370 void set(unsigned index, ScaledInt64 value)
1371 {
1372 setScaledInt64(index, value);
1373 }
1374
1378 void set(unsigned index, OpaqueInt128 value)
1379 {
1380 setOpaqueInt128(index, value);
1381 }
1382
1383#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1387 void set(unsigned index, BoostInt128 value)
1388 {
1389 setBoostInt128(index, value);
1390 }
1391
1395 void set(unsigned index, ScaledBoostInt128 value)
1396 {
1397 setScaledBoostInt128(index, value);
1398 }
1399#endif
1400
1404 void set(unsigned index, float value)
1405 {
1406 setFloat(index, value);
1407 }
1408
1412 void set(unsigned index, double value)
1413 {
1414 setDouble(index, value);
1415 }
1416
1420 void set(unsigned index, OpaqueDecFloat16 value)
1421 {
1422 setOpaqueDecFloat16(index, value);
1423 }
1424
1425#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1429 void set(unsigned index, BoostDecFloat16 value)
1430 {
1431 setBoostDecFloat16(index, value);
1432 }
1433#endif
1434
1438 void set(unsigned index, OpaqueDecFloat34 value)
1439 {
1440 setOpaqueDecFloat34(index, value);
1441 }
1442
1443#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1447 void set(unsigned index, BoostDecFloat34 value)
1448 {
1449 setBoostDecFloat34(index, value);
1450 }
1451#endif
1452
1456 void set(unsigned index, Date value)
1457 {
1458 setDate(index, value);
1459 }
1460
1464 void set(unsigned index, OpaqueDate value)
1465 {
1466 setOpaqueDate(index, value);
1467 }
1468
1472 void set(unsigned index, Time value)
1473 {
1474 setTime(index, value);
1475 }
1476
1480 void set(unsigned index, OpaqueTime value)
1481 {
1482 setOpaqueTime(index, value);
1483 }
1484
1488 void set(unsigned index, Timestamp value)
1489 {
1490 setTimestamp(index, value);
1491 }
1492
1496 void set(unsigned index, OpaqueTimestamp value)
1497 {
1498 setOpaqueTimestamp(index, value);
1499 }
1500
1504 void set(unsigned index, TimeTz value)
1505 {
1506 setTimeTz(index, value);
1507 }
1508
1512 void set(unsigned index, OpaqueTimeTz value)
1513 {
1514 setOpaqueTimeTz(index, value);
1515 }
1516
1520 void set(unsigned index, TimestampTz value)
1521 {
1522 setTimestampTz(index, value);
1523 }
1524
1528 void set(unsigned index, OpaqueTimestampTz value)
1529 {
1530 setOpaqueTimestampTz(index, value);
1531 }
1532
1536 void set(unsigned index, std::string_view value)
1537 {
1538 setString(index, value);
1539 }
1540
1544 template <typename T>
1545 void set(unsigned index, std::optional<T> value)
1546 {
1547 if (value.has_value())
1548 set(index, value.value());
1549 else
1550 setNull(index);
1551 }
1552
1556
1560
1564 bool isNull(unsigned index)
1565 {
1566 assert(isValid());
1567
1568 const auto& descriptor = getOutDescriptor(index);
1569 const auto* const message = outMessage.data();
1570
1571 return *reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE;
1572 }
1573
1577 std::optional<bool> getBool(unsigned index)
1578 {
1579 assert(isValid());
1580
1581 const auto& descriptor = getOutDescriptor(index);
1582 const auto* const message = outMessage.data();
1583
1584 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1585 return std::nullopt;
1586
1587 switch (descriptor.adjustedType)
1588 {
1590 return message[descriptor.offset] != std::byte{0};
1591
1592 default:
1593 throwInvalidType("bool", descriptor.adjustedType);
1594 }
1595 }
1596
1600 std::optional<std::int16_t> getInt16(unsigned index)
1601 {
1602 std::optional<int> scale{0};
1603 return getNumber<std::int16_t>(index, scale, "std::int16_t");
1604 }
1605
1609 std::optional<ScaledInt16> getScaledInt16(unsigned index)
1610 {
1611 std::optional<int> scale;
1612 const auto value = getNumber<std::int16_t>(index, scale, "ScaledInt16");
1613 return value.has_value() ? std::optional{ScaledInt16{value.value(), scale.value()}} : std::nullopt;
1614 }
1615
1619 std::optional<std::int32_t> getInt32(unsigned index)
1620 {
1621 std::optional<int> scale{0};
1622 return getNumber<std::int32_t>(index, scale, "std::int32_t");
1623 }
1624
1628 std::optional<ScaledInt32> getScaledInt32(unsigned index)
1629 {
1630 std::optional<int> scale;
1631 const auto value = getNumber<std::int32_t>(index, scale, "ScaledInt32");
1632 return value.has_value() ? std::optional{ScaledInt32{value.value(), scale.value()}} : std::nullopt;
1633 }
1634
1638 std::optional<std::int64_t> getInt64(unsigned index)
1639 {
1640 std::optional<int> scale{0};
1641 return getNumber<std::int64_t>(index, scale, "std::int64_t");
1642 }
1643
1647 std::optional<ScaledInt64> getScaledInt64(unsigned index)
1648 {
1649 std::optional<int> scale;
1650 const auto value = getNumber<std::int64_t>(index, scale, "ScaledInt64");
1651 return value.has_value() ? std::optional{ScaledInt64{value.value(), scale.value()}} : std::nullopt;
1652 }
1653
1657 std::optional<ScaledOpaqueInt128> getScaledOpaqueInt128(unsigned index)
1658 {
1659 assert(isValid());
1660
1661 const auto& descriptor = getOutDescriptor(index);
1662 const auto* const message = outMessage.data();
1663
1664 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1665 return std::nullopt;
1666
1667 switch (descriptor.adjustedType)
1668 {
1670 return ScaledOpaqueInt128{
1671 OpaqueInt128{*reinterpret_cast<const OpaqueInt128*>(&message[descriptor.offset])},
1672 descriptor.scale};
1673
1674 default:
1675 throwInvalidType("ScaledOpaqueInt128", descriptor.adjustedType);
1676 }
1677 }
1678
1679#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1683 std::optional<BoostInt128> getBoostInt128(unsigned index)
1684 {
1685 std::optional<int> scale{0};
1686 const auto value = getNumber<BoostInt128>(index, scale, "BoostInt128");
1687 return value.has_value() ? std::optional{value.value()} : std::nullopt;
1688 }
1689
1693 std::optional<ScaledBoostInt128> getScaledBoostInt128(unsigned index)
1694 {
1695 std::optional<int> scale;
1696 const auto value = getNumber<BoostInt128>(index, scale, "ScaledBoostInt128");
1697 return value.has_value() ? std::optional{ScaledBoostInt128{value.value(), scale.value()}} : std::nullopt;
1698 }
1699#endif
1700
1704 std::optional<float> getFloat(unsigned index)
1705 {
1706 std::optional<int> scale{0};
1707 return getNumber<float>(index, scale, "float");
1708 }
1709
1713 std::optional<double> getDouble(unsigned index)
1714 {
1715 std::optional<int> scale{0};
1716 return getNumber<double>(index, scale, "double");
1717 }
1718
1722 std::optional<OpaqueDecFloat16> getOpaqueDecFloat16(unsigned index)
1723 {
1724 assert(isValid());
1725
1726 const auto& descriptor = getOutDescriptor(index);
1727 const auto* const message = outMessage.data();
1728
1729 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1730 return std::nullopt;
1731
1732 switch (descriptor.adjustedType)
1733 {
1735 return OpaqueDecFloat16{*reinterpret_cast<const OpaqueDecFloat16*>(&message[descriptor.offset])};
1736
1737 default:
1738 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
1739 }
1740 }
1741
1742#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1746 std::optional<BoostDecFloat16> getBoostDecFloat16(unsigned index)
1747 {
1748 std::optional<int> scale{0};
1749 return getNumber<BoostDecFloat16>(index, scale, "BoostDecFloat16");
1750 }
1751#endif
1752
1756 std::optional<OpaqueDecFloat34> getOpaqueDecFloat34(unsigned index)
1757 {
1758 assert(isValid());
1759
1760 const auto& descriptor = getOutDescriptor(index);
1761 const auto* const message = outMessage.data();
1762
1763 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1764 return std::nullopt;
1765
1766 switch (descriptor.adjustedType)
1767 {
1769 return OpaqueDecFloat34{*reinterpret_cast<const OpaqueDecFloat34*>(&message[descriptor.offset])};
1770
1771 default:
1772 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
1773 }
1774 }
1775
1776#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1780 std::optional<BoostDecFloat34> getBoostDecFloat34(unsigned index)
1781 {
1782 std::optional<int> scale{0};
1783 return getNumber<BoostDecFloat34>(index, scale, "BoostDecFloat34");
1784 }
1785#endif
1786
1790 std::optional<Date> getDate(unsigned index)
1791 {
1792 assert(isValid());
1793
1794 const auto& descriptor = getOutDescriptor(index);
1795 const auto* const message = outMessage.data();
1796
1797 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1798 return std::nullopt;
1799
1800 switch (descriptor.adjustedType)
1801 {
1803 return calendarConverter.opaqueDateToDate(
1804 *reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset]));
1805
1806 default:
1807 throwInvalidType("Date", descriptor.adjustedType);
1808 }
1809 }
1810
1814 std::optional<OpaqueDate> getOpaqueDate(unsigned index)
1815 {
1816 assert(isValid());
1817
1818 const auto& descriptor = getOutDescriptor(index);
1819 const auto* const message = outMessage.data();
1820
1821 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1822 return std::nullopt;
1823
1824 switch (descriptor.adjustedType)
1825 {
1827 return OpaqueDate{*reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset])};
1828
1829 default:
1830 throwInvalidType("OpaqueDate", descriptor.adjustedType);
1831 }
1832 }
1833
1837 std::optional<Time> getTime(unsigned index)
1838 {
1839 assert(isValid());
1840
1841 const auto& descriptor = getOutDescriptor(index);
1842 const auto* const message = outMessage.data();
1843
1844 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1845 return std::nullopt;
1846
1847 switch (descriptor.adjustedType)
1848 {
1850 return calendarConverter.opaqueTimeToTime(
1851 *reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset]));
1852
1853 default:
1854 throwInvalidType("Time", descriptor.adjustedType);
1855 }
1856 }
1857
1861 std::optional<OpaqueTime> getOpaqueTime(unsigned index)
1862 {
1863 assert(isValid());
1864
1865 const auto& descriptor = getOutDescriptor(index);
1866 const auto* const message = outMessage.data();
1867
1868 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1869 return std::nullopt;
1870
1871 switch (descriptor.adjustedType)
1872 {
1874 return OpaqueTime{*reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset])};
1875
1876 default:
1877 throwInvalidType("OpaqueTime", descriptor.adjustedType);
1878 }
1879 }
1880
1884 std::optional<Timestamp> getTimestamp(unsigned index)
1885 {
1886 assert(isValid());
1887
1888 const auto& descriptor = getOutDescriptor(index);
1889 const auto* const message = outMessage.data();
1890
1891 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1892 return std::nullopt;
1893
1894 switch (descriptor.adjustedType)
1895 {
1897 return calendarConverter.opaqueTimestampToTimestamp(
1898 *reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset]));
1899
1900 default:
1901 throwInvalidType("Timestamp", descriptor.adjustedType);
1902 }
1903 }
1904
1908 std::optional<OpaqueTimestamp> getOpaqueTimestamp(unsigned index)
1909 {
1910 assert(isValid());
1911
1912 const auto& descriptor = getOutDescriptor(index);
1913 const auto* const message = outMessage.data();
1914
1915 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1916 return std::nullopt;
1917
1918 switch (descriptor.adjustedType)
1919 {
1921 return OpaqueTimestamp{*reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset])};
1922
1923 default:
1924 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
1925 }
1926 }
1927
1931 std::optional<TimeTz> getTimeTz(unsigned index)
1932 {
1933 assert(isValid());
1934
1935 const auto& descriptor = getOutDescriptor(index);
1936 const auto* const message = outMessage.data();
1937
1938 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1939 return std::nullopt;
1940
1941 switch (descriptor.adjustedType)
1942 {
1944 return calendarConverter.opaqueTimeTzToTimeTz(
1945 *reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset]));
1946
1947 default:
1948 throwInvalidType("TimeTz", descriptor.adjustedType);
1949 }
1950 }
1951
1955 std::optional<OpaqueTimeTz> getOpaqueTimeTz(unsigned index)
1956 {
1957 assert(isValid());
1958
1959 const auto& descriptor = getOutDescriptor(index);
1960 const auto* const message = outMessage.data();
1961
1962 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1963 return std::nullopt;
1964
1965 switch (descriptor.adjustedType)
1966 {
1968 return OpaqueTimeTz{*reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset])};
1969
1970 default:
1971 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
1972 }
1973 }
1974
1978 std::optional<TimestampTz> getTimestampTz(unsigned index)
1979 {
1980 assert(isValid());
1981
1982 const auto& descriptor = getOutDescriptor(index);
1983 const auto* const message = outMessage.data();
1984
1985 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1986 return std::nullopt;
1987
1988 switch (descriptor.adjustedType)
1989 {
1991 return calendarConverter.opaqueTimestampTzToTimestampTz(
1992 *reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset]));
1993
1994 default:
1995 throwInvalidType("TimestampTz", descriptor.adjustedType);
1996 }
1997 }
1998
2002 std::optional<OpaqueTimestampTz> getOpaqueTimestampTz(unsigned index)
2003 {
2004 assert(isValid());
2005
2006 const auto& descriptor = getOutDescriptor(index);
2007 const auto* const message = outMessage.data();
2008
2009 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2010 return std::nullopt;
2011
2012 switch (descriptor.adjustedType)
2013 {
2015 return OpaqueTimestampTz{*reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset])};
2016
2017 default:
2018 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
2019 }
2020 }
2021
2025 std::optional<BlobId> getBlobId(unsigned index)
2026 {
2027 assert(isValid());
2028
2029 const auto& descriptor = getOutDescriptor(index);
2030 const auto* const message = outMessage.data();
2031
2032 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2033 return std::nullopt;
2034
2035 switch (descriptor.adjustedType)
2036 {
2038 {
2039 BlobId value;
2040 value.id = *reinterpret_cast<const ISC_QUAD*>(&message[descriptor.offset]);
2041 return value;
2042 }
2043
2044 default:
2045 throwInvalidType("BlobId", descriptor.adjustedType);
2046 }
2047 }
2048
2052 std::optional<std::string> getString(unsigned index)
2053 {
2054 assert(isValid());
2055
2056 const auto& descriptor = getOutDescriptor(index);
2057 const auto* const message = outMessage.data();
2058
2059 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2060 return std::nullopt;
2061
2062 const auto data = &message[descriptor.offset];
2063
2064 switch (descriptor.adjustedType)
2065 {
2067 return (message[descriptor.offset] != std::byte{0}) ? std::string{"true"} : std::string{"false"};
2068
2070 return numericConverter.numberToString(
2071 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale});
2072
2074 return numericConverter.numberToString(
2075 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale});
2076
2078 return numericConverter.numberToString(
2079 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale});
2080
2082 return numericConverter.opaqueInt128ToString(
2083 *reinterpret_cast<const OpaqueInt128*>(data), descriptor.scale);
2084
2086 return numericConverter.numberToString(*reinterpret_cast<const float*>(data));
2087
2089 return numericConverter.numberToString(*reinterpret_cast<const double*>(data));
2090
2092 return calendarConverter.opaqueDateToString(*reinterpret_cast<const OpaqueDate*>(data));
2093
2095 return calendarConverter.opaqueTimeToString(*reinterpret_cast<const OpaqueTime*>(data));
2096
2098 return calendarConverter.opaqueTimestampToString(*reinterpret_cast<const OpaqueTimestamp*>(data));
2099
2101 return calendarConverter.opaqueTimeTzToString(*reinterpret_cast<const OpaqueTimeTz*>(data));
2102
2104 return calendarConverter.opaqueTimestampTzToString(
2105 *reinterpret_cast<const OpaqueTimestampTz*>(data));
2106
2108 return numericConverter.opaqueDecFloat16ToString(*reinterpret_cast<const OpaqueDecFloat16*>(data));
2109
2111 return numericConverter.opaqueDecFloat34ToString(*reinterpret_cast<const OpaqueDecFloat34*>(data));
2112
2114 return std::string{reinterpret_cast<const char*>(data + sizeof(std::uint16_t)),
2115 *reinterpret_cast<const std::uint16_t*>(data)};
2116
2117 default:
2118 throwInvalidType("std::string", descriptor.adjustedType);
2119 }
2120 }
2121
2125
2129 template <typename T>
2130 T get(unsigned index);
2131
2139 template <Aggregate T>
2141 {
2142 using namespace impl::reflection;
2143
2144 constexpr std::size_t N = fieldCountV<T>;
2145
2146 if (N != outDescriptors.size())
2147 {
2148 throw FbCppException("Struct field count (" + std::to_string(N) +
2149 ") does not match output column count (" + std::to_string(outDescriptors.size()) + ")");
2150 }
2151
2152 return getStruct<T>(std::make_index_sequence<N>{});
2153 }
2154
2161 template <Aggregate T>
2162 void set(const T& value)
2163 {
2164 using namespace impl::reflection;
2165
2166 constexpr std::size_t N = fieldCountV<T>;
2167
2168 if (N != inDescriptors.size())
2169 {
2170 throw FbCppException("Struct field count (" + std::to_string(N) +
2171 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) + ")");
2172 }
2173
2174 setStruct(value, std::make_index_sequence<N>{});
2175 }
2176
2184 template <TupleLike T>
2186 {
2187 using namespace impl::reflection;
2188
2189 constexpr std::size_t N = std::tuple_size_v<T>;
2190
2191 if (N != outDescriptors.size())
2192 {
2193 throw FbCppException("Tuple element count (" + std::to_string(N) +
2194 ") does not match output column count (" + std::to_string(outDescriptors.size()) + ")");
2195 }
2196
2197 return getTuple<T>(std::make_index_sequence<N>{});
2198 }
2199
2206 template <TupleLike T>
2207 void set(const T& value)
2208 {
2209 constexpr std::size_t N = std::tuple_size_v<T>;
2210
2211 if (N != inDescriptors.size())
2212 {
2213 throw FbCppException("Tuple element count (" + std::to_string(N) +
2214 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) + ")");
2215 }
2216
2217 setTuple(value, std::make_index_sequence<N>{});
2218 }
2219
2228 template <VariantLike V>
2229 V get(unsigned index)
2230 {
2231 using namespace impl::reflection;
2232
2233 static_assert(variantAlternativesSupportedV<V>,
2234 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2235 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2236 "complete list of supported types.");
2237
2238 assert(isValid());
2239
2240 const auto& descriptor = getOutDescriptor(index);
2241
2242 if (isNull(index))
2243 {
2244 if constexpr (variantContainsV<std::monostate, V>)
2245 return V{std::monostate{}};
2246 else
2247 {
2248 throw FbCppException(
2249 "NULL value encountered but variant does not contain std::monostate at index " +
2250 std::to_string(index));
2251 }
2252 }
2253
2254 return getVariantValue<V>(index, descriptor);
2255 }
2256
2263 template <VariantLike V>
2264 void set(unsigned index, const V& value)
2265 {
2266 using namespace impl::reflection;
2267
2268 static_assert(variantAlternativesSupportedV<V>,
2269 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2270 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2271 "complete list of supported types.");
2272
2273 std::visit(
2274 [this, index](const auto& v)
2275 {
2276 using T = std::decay_t<decltype(v)>;
2277
2278 if constexpr (std::is_same_v<T, std::monostate>)
2279 setNull(index);
2280 else
2281 set(index, v);
2282 },
2283 value);
2284 }
2285
2286 private:
2290 const Descriptor& getInDescriptor(unsigned index)
2291 {
2292 if (index >= inDescriptors.size())
2293 throw std::out_of_range("index out of range");
2294
2295 return inDescriptors[index];
2296 }
2297
2301 const Descriptor& getOutDescriptor(unsigned index)
2302 {
2303 if (index >= outDescriptors.size())
2304 throw std::out_of_range("index out of range");
2305
2306 return outDescriptors[index];
2307 }
2308
2312 template <typename T, std::size_t... Is>
2313 T getStruct(std::index_sequence<Is...>)
2314 {
2315 using namespace impl::reflection;
2316
2317 return T{getStructField<FieldType<T, Is>>(static_cast<unsigned>(Is))...};
2318 }
2319
2323 template <typename F>
2324 auto getStructField(unsigned index)
2325 {
2326 using namespace impl::reflection;
2327
2328 if constexpr (isOptionalV<F>)
2329 return get<F>(index);
2330 else if constexpr (isVariantV<F>)
2331 return get<F>(index);
2332 else
2333 {
2334 auto opt = get<std::optional<F>>(index);
2335
2336 if (!opt.has_value())
2337 {
2338 throw FbCppException(
2339 "Null value encountered for non-optional field at index " + std::to_string(index));
2340 }
2341
2342 return std::move(opt.value());
2343 }
2344 }
2345
2349 template <typename T, std::size_t... Is>
2350 void setStruct(const T& value, std::index_sequence<Is...>)
2351 {
2352 using namespace impl::reflection;
2353
2354 const auto tuple = toTupleRef(value);
2355 (set(static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
2356 }
2357
2361 template <typename T, std::size_t... Is>
2362 T getTuple(std::index_sequence<Is...>)
2363 {
2364 using namespace impl::reflection;
2365
2366 return T{getStructField<std::tuple_element_t<Is, T>>(static_cast<unsigned>(Is))...};
2367 }
2368
2372 template <typename T, std::size_t... Is>
2373 void setTuple(const T& value, std::index_sequence<Is...>)
2374 {
2375 (set(static_cast<unsigned>(Is), std::get<Is>(value)), ...);
2376 }
2377
2382 template <typename V>
2383 V getVariantValue(unsigned index, const Descriptor& descriptor)
2384 {
2385 using namespace impl::reflection;
2386
2387 // Try exact type matches first based on SQL type
2388 switch (descriptor.adjustedType)
2389 {
2391 if constexpr (variantContainsV<bool, V>)
2392 return V{get<std::optional<bool>>(index).value()};
2393 break;
2394
2396 if (descriptor.scale != 0)
2397 {
2398 // For scaled numbers, prefer exact scaled type, then larger scaled types
2399 if constexpr (variantContainsV<ScaledInt16, V>)
2400 return V{get<std::optional<ScaledInt16>>(index).value()};
2401 if constexpr (variantContainsV<ScaledInt32, V>)
2402 return V{get<std::optional<ScaledInt32>>(index).value()};
2403 if constexpr (variantContainsV<ScaledInt64, V>)
2404 return V{get<std::optional<ScaledInt64>>(index).value()};
2405#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2406 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2407 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2408#endif
2409 }
2410 if constexpr (variantContainsV<std::int16_t, V>)
2411 return V{get<std::optional<std::int16_t>>(index).value()};
2412 break;
2413
2415 if (descriptor.scale != 0)
2416 {
2417 // For scaled numbers, prefer exact scaled type, then larger scaled types
2418 if constexpr (variantContainsV<ScaledInt32, V>)
2419 return V{get<std::optional<ScaledInt32>>(index).value()};
2420 if constexpr (variantContainsV<ScaledInt64, V>)
2421 return V{get<std::optional<ScaledInt64>>(index).value()};
2422#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2423 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2424 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2425#endif
2426 }
2427 if constexpr (variantContainsV<std::int32_t, V>)
2428 return V{get<std::optional<std::int32_t>>(index).value()};
2429 break;
2430
2432 if (descriptor.scale != 0)
2433 {
2434 // For scaled numbers, prefer exact scaled type, then larger scaled types
2435 if constexpr (variantContainsV<ScaledInt64, V>)
2436 return V{get<std::optional<ScaledInt64>>(index).value()};
2437#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2438 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2439 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2440#endif
2441 }
2442 if constexpr (variantContainsV<std::int64_t, V>)
2443 return V{get<std::optional<std::int64_t>>(index).value()};
2444 break;
2445
2446#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2448 // Prefer opaque (native Firebird) types first
2449 if constexpr (variantContainsV<ScaledOpaqueInt128, V>)
2450 return V{get<std::optional<ScaledOpaqueInt128>>(index).value()};
2451 else if (descriptor.scale != 0)
2452 {
2453 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2454 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2455 }
2456 else if constexpr (variantContainsV<BoostInt128, V>)
2457 return V{get<std::optional<BoostInt128>>(index).value()};
2458 break;
2459#endif
2460
2462 if constexpr (variantContainsV<float, V>)
2463 return V{get<std::optional<float>>(index).value()};
2464 break;
2465
2467 if constexpr (variantContainsV<double, V>)
2468 return V{get<std::optional<double>>(index).value()};
2469 break;
2470
2471#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2473 // Prefer opaque (native Firebird) types first
2474 if constexpr (variantContainsV<OpaqueDecFloat16, V>)
2475 return V{get<std::optional<OpaqueDecFloat16>>(index).value()};
2476 else if constexpr (variantContainsV<BoostDecFloat16, V>)
2477 return V{get<std::optional<BoostDecFloat16>>(index).value()};
2478 break;
2479
2481 // Prefer opaque (native Firebird) types first
2482 if constexpr (variantContainsV<OpaqueDecFloat34, V>)
2483 return V{get<std::optional<OpaqueDecFloat34>>(index).value()};
2484 else if constexpr (variantContainsV<BoostDecFloat34, V>)
2485 return V{get<std::optional<BoostDecFloat34>>(index).value()};
2486 break;
2487#endif
2488
2490 if constexpr (variantContainsV<std::string, V>)
2491 return V{get<std::optional<std::string>>(index).value()};
2492 break;
2493
2495 // Prefer opaque (native Firebird) types first
2496 if constexpr (variantContainsV<OpaqueDate, V>)
2497 return V{get<std::optional<OpaqueDate>>(index).value()};
2498 else if constexpr (variantContainsV<Date, V>)
2499 return V{get<std::optional<Date>>(index).value()};
2500 break;
2501
2503 // Prefer opaque (native Firebird) types first
2504 if constexpr (variantContainsV<OpaqueTime, V>)
2505 return V{get<std::optional<OpaqueTime>>(index).value()};
2506 else if constexpr (variantContainsV<Time, V>)
2507 return V{get<std::optional<Time>>(index).value()};
2508 break;
2509
2511 // Prefer opaque (native Firebird) types first
2512 if constexpr (variantContainsV<OpaqueTimestamp, V>)
2513 return V{get<std::optional<OpaqueTimestamp>>(index).value()};
2514 else if constexpr (variantContainsV<Timestamp, V>)
2515 return V{get<std::optional<Timestamp>>(index).value()};
2516 break;
2517
2519 // Prefer opaque (native Firebird) types first
2520 if constexpr (variantContainsV<OpaqueTimeTz, V>)
2521 return V{get<std::optional<OpaqueTimeTz>>(index).value()};
2522 else if constexpr (variantContainsV<TimeTz, V>)
2523 return V{get<std::optional<TimeTz>>(index).value()};
2524 break;
2525
2527 // Prefer opaque (native Firebird) types first
2528 if constexpr (variantContainsV<OpaqueTimestampTz, V>)
2529 return V{get<std::optional<OpaqueTimestampTz>>(index).value()};
2530 else if constexpr (variantContainsV<TimestampTz, V>)
2531 return V{get<std::optional<TimestampTz>>(index).value()};
2532 break;
2533
2535 if constexpr (variantContainsV<BlobId, V>)
2536 return V{get<std::optional<BlobId>>(index).value()};
2537 break;
2538
2539 default:
2540 break;
2541 }
2542
2543 // No exact match found, try variant alternatives in declaration order
2544 return tryVariantAlternatives<V, 0>(index, descriptor);
2545 }
2546
2550 template <typename V, std::size_t I = 0>
2551 V tryVariantAlternatives(unsigned index, [[maybe_unused]] const Descriptor& descriptor)
2552 {
2553 using namespace impl::reflection;
2554
2555 if constexpr (I >= std::variant_size_v<V>)
2556 {
2557 throw FbCppException(
2558 "Cannot convert SQL type to any variant alternative at index " + std::to_string(index));
2559 }
2560 else
2561 {
2562 using Alt = std::variant_alternative_t<I, V>;
2563
2564 if constexpr (std::is_same_v<Alt, std::monostate>)
2565 {
2566 // Skip monostate in non-null case
2567 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2568 }
2569 else if constexpr (isOpaqueTypeV<Alt>)
2570 {
2571 // Skip opaque types - they only match exact SQL types, no conversions
2572 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2573 }
2574 else
2575 {
2576 // Try this alternative - get<T> will throw if conversion fails
2577 auto opt = get<std::optional<Alt>>(index);
2578 return V{std::move(opt.value())};
2579 }
2580 }
2581 }
2582
2586 template <typename T>
2587 void setNumber(unsigned index, DescriptorAdjustedType valueType, T value, int scale, const char* typeName)
2588 {
2589 assert(isValid());
2590
2591 const auto& descriptor = getInDescriptor(index);
2592 auto* const message = inMessage.data();
2593
2594 const auto descriptorData = &message[descriptor.offset];
2595 std::optional<int> descriptorScale{descriptor.scale};
2596
2597 Descriptor valueDescriptor;
2598 valueDescriptor.adjustedType = valueType;
2599 valueDescriptor.scale = scale;
2600
2601 const auto valueAddress = reinterpret_cast<const std::byte*>(&value);
2602
2603 switch (descriptor.adjustedType)
2604 {
2606 *reinterpret_cast<std::int16_t*>(descriptorData) =
2607 convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale, "std::int16_t");
2608 break;
2609
2611 *reinterpret_cast<std::int32_t*>(descriptorData) =
2612 convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale, "std::int32_t");
2613 break;
2614
2616 *reinterpret_cast<std::int64_t*>(descriptorData) =
2617 convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale, "std::int64_t");
2618 break;
2619
2620#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2622 {
2623 const auto boostInt128 =
2624 convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale, "BoostInt128");
2625 *reinterpret_cast<OpaqueInt128*>(descriptorData) =
2626 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
2627 break;
2628 }
2629#endif
2630
2632 *reinterpret_cast<float*>(descriptorData) =
2633 convertNumber<float>(valueDescriptor, valueAddress, descriptorScale, "float");
2634 break;
2635
2637 *reinterpret_cast<double*>(descriptorData) =
2638 convertNumber<double>(valueDescriptor, valueAddress, descriptorScale, "double");
2639 break;
2640
2641#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2643 {
2644 const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
2645 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat16");
2646 *reinterpret_cast<OpaqueDecFloat16*>(descriptorData) =
2647 numericConverter.boostDecFloat16ToOpaqueDecFloat16(boostDecFloat16);
2648 break;
2649 }
2650
2652 {
2653 const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
2654 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat34");
2655 *reinterpret_cast<OpaqueDecFloat34*>(descriptorData) =
2656 numericConverter.boostDecFloat34ToOpaqueDecFloat34(boostDecFloat34);
2657 break;
2658 }
2659#endif
2660
2661 default:
2662 throwInvalidType(typeName, descriptor.adjustedType);
2663 }
2664
2665 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
2666 }
2667
2668 // FIXME: floating to integral
2672 template <typename T>
2673 std::optional<T> getNumber(unsigned index, std::optional<int>& scale, const char* typeName)
2674 {
2675 assert(isValid());
2676
2677 const auto& descriptor = getOutDescriptor(index);
2678 const auto* const message = outMessage.data();
2679
2680 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2681 return std::nullopt;
2682
2683 auto data = &message[descriptor.offset];
2684#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2685 std::optional<BoostInt128> boostInt128;
2686 std::optional<BoostDecFloat16> boostDecFloat16;
2687 std::optional<BoostDecFloat34> boostDecFloat34;
2688#endif
2689
2690 // FIXME: Use IUtil
2691 switch (descriptor.adjustedType)
2692 {
2693#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2695 boostInt128.emplace(
2696 numericConverter.opaqueInt128ToBoostInt128(*reinterpret_cast<const OpaqueInt128*>(data)));
2697 data = reinterpret_cast<const std::byte*>(&boostInt128.value());
2698 break;
2699
2701 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
2702 *reinterpret_cast<const OpaqueDecFloat16*>(data)));
2703 data = reinterpret_cast<const std::byte*>(&boostDecFloat16.value());
2704 break;
2705
2707 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
2708 *reinterpret_cast<const OpaqueDecFloat34*>(data)));
2709 data = reinterpret_cast<const std::byte*>(&boostDecFloat34.value());
2710 break;
2711#endif
2712
2713 default:
2714 break;
2715 }
2716
2717 return convertNumber<T>(descriptor, data, scale, typeName);
2718 }
2719
2720 [[noreturn]] static void throwInvalidType(const char* actualType, DescriptorAdjustedType descriptorType)
2721 {
2722 throw FbCppException("Invalid type: actual type " + std::string(actualType) + ", descriptor type " +
2723 std::to_string(static_cast<unsigned>(descriptorType)));
2724 }
2725
2726 template <typename T>
2727 T convertNumber(
2728 const Descriptor& descriptor, const std::byte* data, std::optional<int>& toScale, const char* toTypeName)
2729 {
2730 if (!toScale.has_value())
2731 {
2732 switch (descriptor.adjustedType)
2733 {
2738 throwInvalidType(toTypeName, descriptor.adjustedType);
2739
2740 default:
2741 break;
2742 }
2743
2744 toScale = descriptor.scale;
2745 }
2746
2747 switch (descriptor.adjustedType)
2748 {
2750 return numericConverter.numberToNumber<T>(
2751 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale}, toScale.value());
2752 break;
2753
2755 return numericConverter.numberToNumber<T>(
2756 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale}, toScale.value());
2757
2759 return numericConverter.numberToNumber<T>(
2760 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale}, toScale.value());
2761
2762#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2764 return numericConverter.numberToNumber<T>(
2765 ScaledBoostInt128{*reinterpret_cast<const BoostInt128*>(data), descriptor.scale},
2766 toScale.value());
2767
2769 return numericConverter.numberToNumber<T>(
2770 *reinterpret_cast<const BoostDecFloat16*>(data), toScale.value());
2771
2773 return numericConverter.numberToNumber<T>(
2774 *reinterpret_cast<const BoostDecFloat34*>(data), toScale.value());
2775#endif
2776
2778 return numericConverter.numberToNumber<T>(*reinterpret_cast<const float*>(data), toScale.value());
2779 break;
2780
2782 return numericConverter.numberToNumber<T>(*reinterpret_cast<const double*>(data), toScale.value());
2783 break;
2784
2785 default:
2786 throwInvalidType(toTypeName, descriptor.adjustedType);
2787 }
2788 }
2789
2790 private:
2791 Attachment* attachment;
2792 FbUniquePtr<Firebird::IStatus> status;
2793 impl::StatusWrapper statusWrapper;
2794 impl::CalendarConverter calendarConverter;
2795 impl::NumericConverter numericConverter;
2796 FbRef<fb::IStatement> statementHandle;
2797 FbRef<fb::IResultSet> resultSetHandle;
2798 FbRef<fb::IMessageMetadata> inMetadata;
2799 std::vector<Descriptor> inDescriptors;
2800 std::vector<std::byte> inMessage;
2801 FbRef<fb::IMessageMetadata> outMetadata;
2802 std::vector<Descriptor> outDescriptors;
2803 std::vector<std::byte> outMessage;
2804 StatementType type;
2805 unsigned cursorFlags = 0;
2806 };
2807
2812
2813 template <>
2814 inline std::optional<bool> Statement::get<std::optional<bool>>(unsigned index)
2815 {
2816 return getBool(index);
2817 }
2818
2819 template <>
2820 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(unsigned index)
2821 {
2822 return getBlobId(index);
2823 }
2824
2825 template <>
2826 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(unsigned index)
2827 {
2828 return getInt16(index);
2829 }
2830
2831 template <>
2832 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(unsigned index)
2833 {
2834 return getScaledInt16(index);
2835 }
2836
2837 template <>
2838 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(unsigned index)
2839 {
2840 return getInt32(index);
2841 }
2842
2843 template <>
2844 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(unsigned index)
2845 {
2846 return getScaledInt32(index);
2847 }
2848
2849 template <>
2850 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(unsigned index)
2851 {
2852 return getInt64(index);
2853 }
2854
2855 template <>
2856 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(unsigned index)
2857 {
2858 return getScaledInt64(index);
2859 }
2860
2861 template <>
2862 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(unsigned index)
2863 {
2864 return getScaledOpaqueInt128(index);
2865 }
2866
2867#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2868 template <>
2869 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(unsigned index)
2870 {
2871 return getBoostInt128(index);
2872 }
2873
2874 template <>
2875 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(unsigned index)
2876 {
2877 return getScaledBoostInt128(index);
2878 }
2879#endif
2880
2881 template <>
2882 inline std::optional<float> Statement::get<std::optional<float>>(unsigned index)
2883 {
2884 return getFloat(index);
2885 }
2886
2887 template <>
2888 inline std::optional<double> Statement::get<std::optional<double>>(unsigned index)
2889 {
2890 return getDouble(index);
2891 }
2892
2893 template <>
2894 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(unsigned index)
2895 {
2896 return getOpaqueDecFloat16(index);
2897 }
2898
2899#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2900 template <>
2901 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(unsigned index)
2902 {
2903 return getBoostDecFloat16(index);
2904 }
2905#endif
2906
2907 template <>
2908 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(unsigned index)
2909 {
2910 return getOpaqueDecFloat34(index);
2911 }
2912
2913#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2914 template <>
2915 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(unsigned index)
2916 {
2917 return getBoostDecFloat34(index);
2918 }
2919#endif
2920
2921 template <>
2922 inline std::optional<Date> Statement::get<std::optional<Date>>(unsigned index)
2923 {
2924 return getDate(index);
2925 }
2926
2927 template <>
2928 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(unsigned index)
2929 {
2930 return getOpaqueDate(index);
2931 }
2932
2933 template <>
2934 inline std::optional<Time> Statement::get<std::optional<Time>>(unsigned index)
2935 {
2936 return getTime(index);
2937 }
2938
2939 template <>
2940 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(unsigned index)
2941 {
2942 return getOpaqueTime(index);
2943 }
2944
2945 template <>
2946 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(unsigned index)
2947 {
2948 return getOpaqueTimestamp(index);
2949 }
2950
2951 template <>
2952 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(unsigned index)
2953 {
2954 return getTimestamp(index);
2955 }
2956
2957 template <>
2958 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(unsigned index)
2959 {
2960 return getTimeTz(index);
2961 }
2962
2963 template <>
2964 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(unsigned index)
2965 {
2966 return getOpaqueTimeTz(index);
2967 }
2968
2969 template <>
2970 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(unsigned index)
2971 {
2972 return getTimestampTz(index);
2973 }
2974
2975 template <>
2976 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(unsigned index)
2977 {
2978 return getOpaqueTimestampTz(index);
2979 }
2980
2981 template <>
2982 inline std::optional<std::string> Statement::get<std::optional<std::string>>(unsigned index)
2983 {
2984 return getString(index);
2985 }
2986
2990} // namespace fbcpp
2991
2992
2993#endif // FBCPP_STATEMENT_H
Represents a connection to a Firebird database.
Definition Attachment.h:177
Client & getClient() noexcept
Returns the Client object reference used to create this Attachment object.
Definition Attachment.h:245
Represents a Firebird blob identifier.
Definition Blob.h:52
ISC_QUAD id
Stores the raw Firebird blob identifier value.
Definition Blob.h:64
Exception thrown when a Firebird database operation fails.
Definition Exception.h:201
Base exception class for all fb-cpp exceptions.
Definition Exception.h:184
Reference-counted smart pointer for Firebird objects using addRef/release semantics.
Definition SmartPtrs.h:70
Represents options used when preparing a Statement.
Definition Statement.h:89
const std::optional< std::string > & getCursorName() const
Returns the cursor name to be set for the statement.
Definition Statement.h:132
StatementOptions & setCursorType(CursorType value)
Sets the cursor type used when opening a result set.
Definition Statement.h:161
StatementOptions & setPrefetchLegacyPlan(bool value)
Enables or disables prefetching of the legacy textual plan at prepare time.
Definition Statement.h:104
bool getPrefetchPlan() const
Reports whether the structured plan should be prefetched during prepare.
Definition Statement.h:113
StatementOptions & setCursorName(const std::string &value)
Sets the cursor name for the statement.
Definition Statement.h:142
StatementOptions & setPrefetchPlan(bool value)
Enables or disables prefetching of the structured plan at prepare time.
Definition Statement.h:123
bool getPrefetchLegacyPlan() const
Reports whether the legacy textual plan should be prefetched during prepare.
Definition Statement.h:94
CursorType getCursorType() const
Returns the cursor type to be used when opening a result set.
Definition Statement.h:151
Prepares, executes, and fetches SQL statements against a Firebird attachment.
Definition Statement.h:241
void set(unsigned index, OpaqueInt128 value)
Convenience overload that binds a Firebird 128-bit integer.
Definition Statement.h:1378
Statement & operator=(Statement &&o) noexcept
Transfers ownership of another prepared statement into this one.
Definition Statement.h:281
void setScaledInt16(unsigned index, std::optional< ScaledInt16 > optValue)
Binds a scaled 16-bit signed integer value or null.
Definition Statement.h:553
V get(unsigned index)
Retrieves a column value as a user-defined variant type.
Definition Statement.h:2229
bool fetchAbsolute(unsigned position)
Positions the cursor on the given absolute row number.
void setNull(unsigned index)
Marks the specified parameter as null.
Definition Statement.h:494
bool fetchRelative(int offset)
Moves the cursor by the requested relative offset.
void setScaledBoostInt128(unsigned index, std::optional< ScaledBoostInt128 > optValue)
Binds a scaled 128-bit integer value expressed with Boost.Multiprecision or null.
Definition Statement.h:671
std::optional< OpaqueTime > getOpaqueTime(unsigned index)
Reads a raw time-of-day column in Firebird's representation.
Definition Statement.h:1861
std::optional< OpaqueDecFloat34 > getOpaqueDecFloat34(unsigned index)
Reads a Firebird 34-digit decimal floating-point column.
Definition Statement.h:1756
void setDate(unsigned index, std::optional< Date > optValue)
Binds a date value or null.
Definition Statement.h:807
std::string getLegacyPlan()
Retrieves the textual legacy plan if the server produced one.
const std::vector< Descriptor > & getInputDescriptors() noexcept
Provides cached descriptors for each input column.
Definition Statement.h:396
void free()
Releases the prepared handle and any associated result set.
const std::vector< Descriptor > & getOutputDescriptors() noexcept
Provides cached descriptors for each output column.
Definition Statement.h:404
bool isValid() noexcept
Returns whether the Statement object is valid.
Definition Statement.h:336
StatementType getType() noexcept
Returns the type classification reported by the server.
Definition Statement.h:378
void set(unsigned index, BoostDecFloat16 value)
Convenience overload that binds a Boost 16-digit decimal floating-point value.
Definition Statement.h:1429
std::optional< TimeTz > getTimeTz(unsigned index)
Reads a time-of-day column with timezone.
Definition Statement.h:1931
void setTime(unsigned index, std::optional< Time > optValue)
Binds a time-of-day value without timezone or null.
Definition Statement.h:868
void set(unsigned index, std::string_view value)
Convenience overload that binds a textual value.
Definition Statement.h:1536
std::optional< BoostDecFloat34 > getBoostDecFloat34(unsigned index)
Reads a Boost-based 34-digit decimal floating-point column.
Definition Statement.h:1780
void setBlobId(unsigned index, std::optional< BlobId > optValue)
Binds a blob identifier to the specified parameter or null.
Definition Statement.h:1269
void setInt16(unsigned index, std::optional< std::int16_t > optValue)
Binds a 16-bit signed integer value or null.
Definition Statement.h:539
void setString(unsigned index, std::optional< std::string_view > optValue)
Binds a textual parameter or null, performing direct conversions where supported.
Definition Statement.h:1112
void set(unsigned index, std::int32_t value)
Convenience overload that binds a 32-bit signed integer.
Definition Statement.h:1346
std::optional< Time > getTime(unsigned index)
Reads a time-of-day column without timezone.
Definition Statement.h:1837
std::optional< Date > getDate(unsigned index)
Reads a date column.
Definition Statement.h:1790
FbRef< fb::IResultSet > getResultSetHandle() noexcept
Provides access to the underlying Firebird currently open result set handle, if any.
Definition Statement.h:354
bool isNull(unsigned index)
Reports whether the most recently fetched row has a null at the given column.
Definition Statement.h:1564
void set(unsigned index, double value)
Convenience overload that binds a double precision floating-point value.
Definition Statement.h:1412
void clearParameters()
Marks all bound parameters as null values.
Definition Statement.h:480
void set(unsigned index, ScaledInt64 value)
Convenience overload that binds a scaled 64-bit signed integer.
Definition Statement.h:1370
std::optional< OpaqueDate > getOpaqueDate(unsigned index)
Reads a raw date column in Firebird's representation.
Definition Statement.h:1814
T get()
Retrieves all output columns into a user-defined aggregate struct.
Definition Statement.h:2140
void setScaledInt32(unsigned index, std::optional< ScaledInt32 > optValue)
Binds a scaled 32-bit signed integer value or null.
Definition Statement.h:582
void set(unsigned index, std::int64_t value)
Convenience overload that binds a 64-bit signed integer.
Definition Statement.h:1362
void setTimestampTz(unsigned index, std::optional< TimestampTz > optValue)
Binds a timestamp value with timezone or null.
Definition Statement.h:1051
std::optional< std::int64_t > getInt64(unsigned index)
Reads a 64-bit signed integer column.
Definition Statement.h:1638
FbRef< fb::IStatement > getStatementHandle() noexcept
Provides direct access to the underlying Firebird statement handle.
Definition Statement.h:345
std::optional< ScaledInt32 > getScaledInt32(unsigned index)
Reads a scaled 32-bit signed integer column.
Definition Statement.h:1628
void set(unsigned index, OpaqueTimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1528
void setOpaqueTime(unsigned index, std::optional< OpaqueTime > optValue)
Binds a raw time-of-day value in Firebird's representation or null.
Definition Statement.h:899
std::optional< float > getFloat(unsigned index)
Reads a single precision floating-point column.
Definition Statement.h:1704
std::optional< double > getDouble(unsigned index)
Reads a double precision floating-point column.
Definition Statement.h:1713
std::optional< OpaqueTimestampTz > getOpaqueTimestampTz(unsigned index)
Reads a raw timestamp-with-time-zone column in Firebird's representation.
Definition Statement.h:2002
std::optional< ScaledInt16 > getScaledInt16(unsigned index)
Reads a scaled 16-bit signed integer column.
Definition Statement.h:1609
std::optional< BlobId > getBlobId(unsigned index)
Reads a blob identifier column.
Definition Statement.h:2025
Statement(Statement &&o) noexcept
Transfers ownership of an existing prepared statement.
Definition Statement.h:256
void setInt64(unsigned index, std::optional< std::int64_t > optValue)
Binds a 64-bit signed integer value or null.
Definition Statement.h:597
std::optional< ScaledOpaqueInt128 > getScaledOpaqueInt128(unsigned index)
Reads a Firebird scaled 128-bit integer column.
Definition Statement.h:1657
FbRef< fb::IMessageMetadata > getOutputMetadata() noexcept
Returns the metadata describing columns produced by the statement.
Definition Statement.h:370
void set(unsigned index, TimeTz value)
Convenience overload that binds a Firebird time with timezone value.
Definition Statement.h:1504
void setOpaqueDecFloat16(unsigned index, std::optional< OpaqueDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value in Firebird's representation or null.
Definition Statement.h:715
void setOpaqueInt128(unsigned index, std::optional< OpaqueInt128 > optValue)
Binds a raw 128-bit integer value in Firebird's representation or null.
Definition Statement.h:626
std::optional< OpaqueTimeTz > getOpaqueTimeTz(unsigned index)
Reads a raw time-of-day column with timezone in Firebird's representation.
Definition Statement.h:1955
void setBoostInt128(unsigned index, std::optional< BoostInt128 > optValue)
Binds a 128-bit integer value expressed with Boost.Multiprecision or null.
Definition Statement.h:657
void set(unsigned index, Date value)
Convenience overload that binds a Firebird date value.
Definition Statement.h:1456
void set(unsigned index, Timestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1488
void setOpaqueTimeTz(unsigned index, std::optional< OpaqueTimeTz > optValue)
Binds a raw time-of-day value with timezone in Firebird's representation or null.
Definition Statement.h:1021
void setTimestamp(unsigned index, std::optional< Timestamp > optValue)
Binds a timestamp value without timezone or null.
Definition Statement.h:929
std::optional< std::string > getString(unsigned index)
Reads a textual column, applying number-to-string conversions when needed.
Definition Statement.h:2052
std::optional< std::int32_t > getInt32(unsigned index)
Reads a 32-bit signed integer column.
Definition Statement.h:1619
void set(unsigned index, OpaqueDecFloat16 value)
Convenience overload that binds a Firebird 16-digit decimal floating-point value.
Definition Statement.h:1420
void setOpaqueTimestampTz(unsigned index, std::optional< OpaqueTimestampTz > optValue)
Binds a raw timestamp value with timezone in Firebird's representation or null.
Definition Statement.h:1082
FbRef< fb::IMessageMetadata > getInputMetadata() noexcept
Returns the metadata describing prepared input parameters.
Definition Statement.h:362
~Statement() noexcept
Releases resources; ignores failures to keep destructor noexcept.
Definition Statement.h:311
void set(unsigned index, OpaqueTimeTz value)
Convenience overload that binds a Firebird time with timezone value.
Definition Statement.h:1512
void setBoostDecFloat16(unsigned index, std::optional< BoostDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value using Boost.Multiprecision or null.
Definition Statement.h:746
std::optional< ScaledBoostInt128 > getScaledBoostInt128(unsigned index)
Reads a scaled Boost 128-bit integer column.
Definition Statement.h:1693
std::string getPlan()
Retrieves the structured textual plan if the server produced one.
void set(unsigned index, BlobId value)
Convenience overload that binds a blob identifier.
Definition Statement.h:1306
void set(unsigned index, BoostDecFloat34 value)
Convenience overload that binds a Boost 34-digit decimal floating-point value.
Definition Statement.h:1447
bool fetchNext()
Fetches the next row in the current result set.
void set(unsigned index, OpaqueDecFloat34 value)
Convenience overload that binds a Firebird 34-digit decimal floating-point value.
Definition Statement.h:1438
void set(unsigned index, Time value)
Convenience overload that binds a Firebird time value.
Definition Statement.h:1472
T get(unsigned index)
Retrieves a column using the most appropriate typed accessor specialization.
void set(unsigned index, ScaledInt16 value)
Convenience overload that binds a scaled 16-bit signed integer.
Definition Statement.h:1338
std::optional< BoostInt128 > getBoostInt128(unsigned index)
Reads a Boost 128-bit integer column.
Definition Statement.h:1683
std::optional< bool > getBool(unsigned index)
Reads a boolean column from the current row.
Definition Statement.h:1577
void setOpaqueDecFloat34(unsigned index, std::optional< OpaqueDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value in Firebird's representation or null.
Definition Statement.h:761
void set(unsigned index, OpaqueTimestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1496
void setInt32(unsigned index, std::optional< std::int32_t > optValue)
Binds a 32-bit signed integer value or null.
Definition Statement.h:568
void set(unsigned index, std::optional< BlobId > value)
Convenience overload that binds an optional blob identifier.
Definition Statement.h:1314
void setBool(unsigned index, std::optional< bool > optValue)
Binds a boolean parameter value or null.
Definition Statement.h:509
void set(unsigned index, const V &value)
Sets a parameter from a variant value.
Definition Statement.h:2264
void set(unsigned index, TimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1520
void setDouble(unsigned index, std::optional< double > optValue)
Binds a double precision floating-point value or null.
Definition Statement.h:701
void set(unsigned index, OpaqueDate value)
Convenience overload that binds a Firebird date value.
Definition Statement.h:1464
void set(unsigned index, std::int16_t value)
Convenience overload that binds a 16-bit signed integer.
Definition Statement.h:1330
void set(unsigned index, std::optional< T > value)
Convenience template that forwards optional values to specialized overloads.
Definition Statement.h:1545
std::optional< OpaqueTimestamp > getOpaqueTimestamp(unsigned index)
Reads a raw timestamp column in Firebird's representation.
Definition Statement.h:1908
void setScaledInt64(unsigned index, std::optional< ScaledInt64 > optValue)
Binds a scaled 64-bit signed integer value or null.
Definition Statement.h:611
void set(unsigned index, std::nullopt_t)
Convenience overload that binds a null value.
Definition Statement.h:1298
void setFloat(unsigned index, std::optional< float > optValue)
Binds a single precision floating-point value or null.
Definition Statement.h:687
void setOpaqueDate(unsigned index, std::optional< OpaqueDate > optValue)
Binds a raw date value in Firebird's representation or null.
Definition Statement.h:838
bool fetchLast()
Positions the cursor on the last row.
bool execute(Transaction &transaction)
Executes a prepared statement using the supplied transaction.
void set(unsigned index, OpaqueTime value)
Convenience overload that binds a Firebird time value.
Definition Statement.h:1480
void set(unsigned index, ScaledInt32 value)
Convenience overload that binds a scaled 32-bit signed integer.
Definition Statement.h:1354
bool fetchPrior()
Fetches the previous row in the current result set.
std::optional< std::int16_t > getInt16(unsigned index)
Reads a 16-bit signed integer column.
Definition Statement.h:1600
void set(unsigned index, ScaledBoostInt128 value)
Convenience overload that binds a scaled Boost-provided 128-bit integer.
Definition Statement.h:1395
bool fetchFirst()
Positions the cursor on the first row.
std::optional< TimestampTz > getTimestampTz(unsigned index)
Reads a timestamp-with-time-zone column.
Definition Statement.h:1978
void set(unsigned index, BoostInt128 value)
Convenience overload that binds a Boost-provided 128-bit integer.
Definition Statement.h:1387
std::optional< OpaqueDecFloat16 > getOpaqueDecFloat16(unsigned index)
Reads a Firebird 16-digit decimal floating-point column.
Definition Statement.h:1722
std::optional< Timestamp > getTimestamp(unsigned index)
Reads a timestamp column without timezone.
Definition Statement.h:1884
std::optional< BoostDecFloat16 > getBoostDecFloat16(unsigned index)
Reads a Boost-based 16-digit decimal floating-point column.
Definition Statement.h:1746
void setTimeTz(unsigned index, std::optional< TimeTz > optValue)
Binds a time-of-day value with timezone or null.
Definition Statement.h:990
void setBoostDecFloat34(unsigned index, std::optional< BoostDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value using Boost.Multiprecision or null.
Definition Statement.h:792
std::optional< ScaledInt64 > getScaledInt64(unsigned index)
Reads a scaled 64-bit signed integer column.
Definition Statement.h:1647
void set(unsigned index, bool value)
Convenience overload that binds a boolean value.
Definition Statement.h:1322
void setOpaqueTimestamp(unsigned index, std::optional< OpaqueTimestamp > optValue)
Binds a raw timestamp value in Firebird's representation or null.
Definition Statement.h:960
void set(unsigned index, float value)
Convenience overload that binds a single precision floating-point value.
Definition Statement.h:1404
void set(const T &value)
Sets all input parameters from fields of a user-defined aggregate struct.
Definition Statement.h:2162
Represents a transaction in one or more Firebird databases.
fb-cpp namespace.
Definition Attachment.h:42
CursorType
Selects the cursor type for a SELECT statement.
Definition Statement.h:73
@ FORWARD_ONLY
Forward-only traversal (default, more efficient for streaming).
@ SCROLLABLE
Allows bidirectional traversal and absolute/relative positioning.
ScaledNumber< std::int64_t > ScaledInt64
Signed 64-bit scaled number.
Definition types.h:79
ScaledNumber< std::int32_t > ScaledInt32
Signed 32-bit scaled number.
Definition types.h:74
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 34 > > BoostDecFloat34
34-digit decimal floating point using Boost.Multiprecision.
Definition types.h:102
FB_DEC16 OpaqueDecFloat16
Opaque 16-digit decimal floating point exposed by the Firebird API.
Definition types.h:205
ScaledNumber< std::int16_t > ScaledInt16
Signed 16-bit scaled number.
Definition types.h:69
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 16 > > BoostDecFloat16
16-digit decimal floating point using Boost.Multiprecision.
Definition types.h:97
DescriptorAdjustedType
Descriptor adjusted type.
Definition Descriptor.h:147
@ 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.
@ FLOAT
Single-precision floating point.
@ DOUBLE
Double-precision floating point.
StatementType
Distinguishes the semantic category of the prepared SQL statement.
Definition Statement.h:178
@ SAVEPOINT
Statement manages a savepoint.
@ PUT_SEGMENT
Statement writes a blob segment - legacy feature.
@ UPDATE
Server classified the statement as an UPDATE.
@ COMMIT
Statement commits a transaction.
@ ROLLBACK
Statement rolls back a transaction.
@ EXEC_PROCEDURE
Statement executes a stored procedure.
@ DELETE
Server classified the statement as a DELETE.
@ DDL
Statement performs data definition operations.
@ GET_SEGMENT
Statement reads a blob segment - legacy feature.
@ INSERT
Server classified the statement as an INSERT.
@ SELECT
Server classified the statement as a SELECT.
@ SET_GENERATOR
Statement sets a generator (sequence) value.
@ START_TRANSACTION
Statement starts a new transaction.
@ SELECT_FOR_UPDATE
Cursor-based SELECT that allows updates.
FB_I128 OpaqueInt128
Opaque 128-bit integer exposed by the Firebird API.
Definition types.h:200
std::chrono::year_month_day Date
Firebird SQL calendar date.
Definition types.h:108
FB_DEC34 OpaqueDecFloat34
Opaque 34-digit decimal floating point exposed by the Firebird API.
Definition types.h:210
boost::multiprecision::int128_t BoostInt128
128-bit integer using Boost.Multiprecision.
Definition types.h:85
ScaledNumber< BoostInt128 > ScaledBoostInt128
Scaled 128-bit integer backed by Boost.Multiprecision.
Definition types.h:90
std::chrono::hh_mm_ss< std::chrono::microseconds > Time
Firebird SQL time-of-day with microsecond resolution.
Definition types.h:113
Describes a parameter or column.
Definition Descriptor.h:248
Wrapper for Firebird date values.
Definition types.h:221
Wrapper for Firebird time-with-time-zone values.
Definition types.h:263
Wrapper for Firebird time values.
Definition types.h:234
Wrapper for Firebird timestamp-with-time-zone values.
Definition types.h:279
Wrapper for Firebird timestamp values.
Definition types.h:247
Represents a numeric value with an explicit decimal scale.
Definition types.h:52
int scale
Decimal scale applied to value.
Definition types.h:63
T value
Unscaled numeric value.
Definition types.h:58
Local time bound to a time zone.
Definition types.h:162
Timestamp bound to a time zone.
Definition types.h:183
Combined date and time with microsecond precision.
Definition types.h:119