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
170 unsigned getDialect() const
171 {
172 return dialect;
173 }
174
181 {
182 dialect = value;
183 return *this;
184 }
185
186 private:
187 bool prefetchLegacyPlan = false;
188 bool prefetchPlan = false;
189 std::optional<std::string> cursorName;
191 unsigned dialect = SQL_DIALECT_CURRENT;
192 };
193
197 enum class StatementType : unsigned
198 {
202 SELECT = isc_info_sql_stmt_select,
206 INSERT = isc_info_sql_stmt_insert,
210 UPDATE = isc_info_sql_stmt_update,
214 DELETE = isc_info_sql_stmt_delete,
218 DDL = isc_info_sql_stmt_ddl,
222 GET_SEGMENT = isc_info_sql_stmt_get_segment,
226 PUT_SEGMENT = isc_info_sql_stmt_put_segment,
230 EXEC_PROCEDURE = isc_info_sql_stmt_exec_procedure,
234 START_TRANSACTION = isc_info_sql_stmt_start_trans,
238 COMMIT = isc_info_sql_stmt_commit,
242 ROLLBACK = isc_info_sql_stmt_rollback,
246 SELECT_FOR_UPDATE = isc_info_sql_stmt_select_for_upd,
250 SET_GENERATOR = isc_info_sql_stmt_set_generator,
254 SAVEPOINT = isc_info_sql_stmt_savepoint,
255 };
256
260 class Statement final
261 {
262 public:
270 explicit Statement(Attachment& attachment, Transaction& transaction, std::string_view sql,
271 const StatementOptions& options = {});
272
276 Statement(Statement&& o) noexcept
277 : attachment{o.attachment},
278 status{std::move(o.status)},
279 statusWrapper{std::move(o.statusWrapper)},
280 calendarConverter{std::move(o.calendarConverter)},
281 numericConverter{std::move(o.numericConverter)},
282 statementHandle{std::move(o.statementHandle)},
283 resultSetHandle{std::move(o.resultSetHandle)},
284 inMetadata{std::move(o.inMetadata)},
285 inDescriptors{std::move(o.inDescriptors)},
286 inMessage{std::move(o.inMessage)},
287 outMetadata{std::move(o.outMetadata)},
288 outDescriptors{std::move(o.outDescriptors)},
289 outMessage{std::move(o.outMessage)},
290 type{o.type},
291 cursorFlags{o.cursorFlags}
292 {
293 }
294
302 {
303 if (this != &o)
304 {
305 attachment = o.attachment;
306 status = std::move(o.status);
307 statusWrapper = std::move(o.statusWrapper);
308 calendarConverter = std::move(o.calendarConverter);
309 numericConverter = std::move(o.numericConverter);
310 statementHandle = std::move(o.statementHandle);
311 resultSetHandle = std::move(o.resultSetHandle);
312 inMetadata = std::move(o.inMetadata);
313 inDescriptors = std::move(o.inDescriptors);
314 inMessage = std::move(o.inMessage);
315 outMetadata = std::move(o.outMetadata);
316 outDescriptors = std::move(o.outDescriptors);
317 outMessage = std::move(o.outMessage);
318 type = o.type;
319 cursorFlags = o.cursorFlags;
320 }
321
322 return *this;
323 }
324
325 Statement(const Statement&) = delete;
326 Statement& operator=(const Statement&) = delete;
327
331 ~Statement() noexcept
332 {
333 if (isValid())
334 {
335 try
336 {
337 free();
338 }
339 catch (...)
340 {
341 // swallow
342 }
343 }
344 }
345
346 public:
352
357 {
358 return *attachment;
359 }
360
364 bool isValid() noexcept
365 {
366 return statementHandle != nullptr;
367 }
368
374 {
375 return statementHandle;
376 }
377
383 {
384 return resultSetHandle;
385 }
386
391 {
392 return inMetadata;
393 }
394
398 std::vector<std::byte>& getInputMessage() noexcept
399 {
400 return inMessage;
401 }
402
407 {
408 return outMetadata;
409 }
410
414 std::vector<std::byte>& getOutputMessage() noexcept
415 {
416 return outMessage;
417 }
418
423 {
424 return type;
425 }
426
430
436
440 const std::vector<Descriptor>& getInputDescriptors() noexcept
441 {
442 return inDescriptors;
443 }
444
448 const std::vector<Descriptor>& getOutputDescriptors() noexcept
449 {
450 return outDescriptors;
451 }
452
456
460 void free();
461
465 std::string getLegacyPlan();
466
470 std::string getPlan();
471
477 bool execute(Transaction& transaction);
478
482
486 bool fetchNext();
487
491 bool fetchPrior();
492
496 bool fetchFirst();
497
501 bool fetchLast();
502
506 bool fetchAbsolute(unsigned position);
507
511 bool fetchRelative(int offset);
512
516
520
525 {
526 assert(isValid());
527
528 const auto message = inMessage.data();
529
530 for (const auto& descriptor : inDescriptors)
531 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_TRUE;
532 }
533
538 void setNull(unsigned index)
539 {
540 assert(isValid());
541
542 const auto& descriptor = getInDescriptor(index);
543 const auto message = inMessage.data();
544
545 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_TRUE;
546 }
547
553 void setBool(unsigned index, std::optional<bool> optValue)
554 {
555 if (!optValue.has_value())
556 {
557 setNull(index);
558 return;
559 }
560
561 assert(isValid());
562
563 const auto& value = optValue.value();
564 const auto& descriptor = getInDescriptor(index);
565 const auto message = inMessage.data();
566
567 switch (descriptor.adjustedType)
568 {
570 message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
571 break;
572
573 default:
574 throwInvalidType("bool", descriptor.adjustedType);
575 }
576
577 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
578 }
579
583 void setInt16(unsigned index, std::optional<std::int16_t> optValue)
584 {
585 if (!optValue.has_value())
586 {
587 setNull(index);
588 return;
589 }
590
591 setNumber(index, DescriptorAdjustedType::INT16, optValue.value(), 0, "std::int16_t");
592 }
593
597 void setScaledInt16(unsigned index, std::optional<ScaledInt16> optValue)
598 {
599 if (!optValue.has_value())
600 {
601 setNull(index);
602 return;
603 }
604
605 const auto& value = optValue.value();
606 setNumber(index, DescriptorAdjustedType::INT16, value.value, value.scale, "ScaledInt16");
607 }
608
612 void setInt32(unsigned index, std::optional<std::int32_t> optValue)
613 {
614 if (!optValue.has_value())
615 {
616 setNull(index);
617 return;
618 }
619
620 setNumber(index, DescriptorAdjustedType::INT32, optValue.value(), 0, "std::int32_t");
621 }
622
626 void setScaledInt32(unsigned index, std::optional<ScaledInt32> optValue)
627 {
628 if (!optValue.has_value())
629 {
630 setNull(index);
631 return;
632 }
633
634 const auto& value = optValue.value();
635 setNumber(index, DescriptorAdjustedType::INT32, value.value, value.scale, "ScaledInt32");
636 }
637
641 void setInt64(unsigned index, std::optional<std::int64_t> optValue)
642 {
643 if (!optValue.has_value())
644 {
645 setNull(index);
646 return;
647 }
648
649 setNumber(index, DescriptorAdjustedType::INT64, optValue.value(), 0, "std::int64_t");
650 }
651
655 void setScaledInt64(unsigned index, std::optional<ScaledInt64> optValue)
656 {
657 if (!optValue.has_value())
658 {
659 setNull(index);
660 return;
661 }
662
663 const auto& value = optValue.value();
664 setNumber(index, DescriptorAdjustedType::INT64, value.value, value.scale, "ScaledInt64");
665 }
666
670 void setOpaqueInt128(unsigned index, std::optional<OpaqueInt128> optValue)
671 {
672 if (!optValue.has_value())
673 {
674 setNull(index);
675 return;
676 }
677
678 assert(isValid());
679
680 const auto& value = optValue.value();
681 const auto& descriptor = getInDescriptor(index);
682 const auto message = inMessage.data();
683
684 switch (descriptor.adjustedType)
685 {
687 *reinterpret_cast<OpaqueInt128*>(&message[descriptor.offset]) = value;
688 break;
689
690 default:
691 throwInvalidType("OpaqueInt128", descriptor.adjustedType);
692 }
693
694 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
695 }
696
697#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
701 void setBoostInt128(unsigned index, std::optional<BoostInt128> optValue)
702 {
703 if (!optValue.has_value())
704 {
705 setNull(index);
706 return;
707 }
708
709 setNumber(index, DescriptorAdjustedType::INT128, optValue.value(), 0, "BoostInt128");
710 }
711
715 void setScaledBoostInt128(unsigned index, std::optional<ScaledBoostInt128> optValue)
716 {
717 if (!optValue.has_value())
718 {
719 setNull(index);
720 return;
721 }
722
723 const auto& value = optValue.value();
724 setNumber(index, DescriptorAdjustedType::INT128, value.value, value.scale, "ScaledBoostInt128");
725 }
726#endif
727
731 void setFloat(unsigned index, std::optional<float> optValue)
732 {
733 if (!optValue.has_value())
734 {
735 setNull(index);
736 return;
737 }
738
739 setNumber(index, DescriptorAdjustedType::FLOAT, optValue.value(), 0, "float");
740 }
741
745 void setDouble(unsigned index, std::optional<double> optValue)
746 {
747 if (!optValue.has_value())
748 {
749 setNull(index);
750 return;
751 }
752
753 setNumber(index, DescriptorAdjustedType::DOUBLE, optValue.value(), 0, "double");
754 }
755
759 void setOpaqueDecFloat16(unsigned index, std::optional<OpaqueDecFloat16> optValue)
760 {
761 if (!optValue.has_value())
762 {
763 setNull(index);
764 return;
765 }
766
767 assert(isValid());
768
769 const auto& value = optValue.value();
770 const auto& descriptor = getInDescriptor(index);
771 const auto message = inMessage.data();
772
773 switch (descriptor.adjustedType)
774 {
776 *reinterpret_cast<OpaqueDecFloat16*>(&message[descriptor.offset]) = value;
777 break;
778
779 default:
780 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
781 }
782
783 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
784 }
785
786#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
790 void setBoostDecFloat16(unsigned index, std::optional<BoostDecFloat16> optValue)
791 {
792 if (!optValue.has_value())
793 {
794 setNull(index);
795 return;
796 }
797
798 setNumber(index, DescriptorAdjustedType::DECFLOAT16, optValue.value(), 0, "BoostDecFloat16");
799 }
800#endif
801
805 void setOpaqueDecFloat34(unsigned index, std::optional<OpaqueDecFloat34> optValue)
806 {
807 if (!optValue.has_value())
808 {
809 setNull(index);
810 return;
811 }
812
813 assert(isValid());
814
815 const auto& value = optValue.value();
816 const auto& descriptor = getInDescriptor(index);
817 const auto message = inMessage.data();
818
819 switch (descriptor.adjustedType)
820 {
822 *reinterpret_cast<OpaqueDecFloat34*>(&message[descriptor.offset]) = value;
823 break;
824
825 default:
826 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
827 }
828
829 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
830 }
831
832#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
836 void setBoostDecFloat34(unsigned index, std::optional<BoostDecFloat34> optValue)
837 {
838 if (!optValue.has_value())
839 {
840 setNull(index);
841 return;
842 }
843
844 setNumber(index, DescriptorAdjustedType::DECFLOAT34, optValue.value(), 0, "BoostDecFloat34");
845 }
846#endif
847
851 void setDate(unsigned index, std::optional<Date> optValue)
852 {
853 if (!optValue.has_value())
854 {
855 setNull(index);
856 return;
857 }
858
859 assert(isValid());
860
861 const auto& value = optValue.value();
862 const auto& descriptor = getInDescriptor(index);
863 const auto message = inMessage.data();
864
865 switch (descriptor.adjustedType)
866 {
868 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) =
869 calendarConverter.dateToOpaqueDate(value);
870 break;
871
872 default:
873 throwInvalidType("Date", descriptor.adjustedType);
874 }
875
876 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
877 }
878
882 void setOpaqueDate(unsigned index, std::optional<OpaqueDate> optValue)
883 {
884 if (!optValue.has_value())
885 {
886 setNull(index);
887 return;
888 }
889
890 assert(isValid());
891
892 const auto& value = optValue.value();
893 const auto& descriptor = getInDescriptor(index);
894 const auto message = inMessage.data();
895
896 switch (descriptor.adjustedType)
897 {
899 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) = value;
900 break;
901
902 default:
903 throwInvalidType("OpaqueDate", descriptor.adjustedType);
904 }
905
906 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
907 }
908
912 void setTime(unsigned index, std::optional<Time> optValue)
913 {
914 if (!optValue.has_value())
915 {
916 setNull(index);
917 return;
918 }
919
920 assert(isValid());
921
922 const auto& value = optValue.value();
923 const auto& descriptor = getInDescriptor(index);
924 const auto message = inMessage.data();
925
926 switch (descriptor.adjustedType)
927 {
929 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) =
930 calendarConverter.timeToOpaqueTime(value);
931 break;
932
933 default:
934 throwInvalidType("Time", descriptor.adjustedType);
935 }
936
937 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
938 }
939
943 void setOpaqueTime(unsigned index, std::optional<OpaqueTime> optValue)
944 {
945 if (!optValue.has_value())
946 {
947 setNull(index);
948 return;
949 }
950
951 assert(isValid());
952
953 const auto& value = optValue.value();
954 const auto& descriptor = getInDescriptor(index);
955 const auto message = inMessage.data();
956
957 switch (descriptor.adjustedType)
958 {
960 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) = value;
961 break;
962
963 default:
964 throwInvalidType("OpaqueTime", descriptor.adjustedType);
965 }
966
967 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
968 }
969
973 void setTimestamp(unsigned index, std::optional<Timestamp> optValue)
974 {
975 if (!optValue.has_value())
976 {
977 setNull(index);
978 return;
979 }
980
981 assert(isValid());
982
983 const auto& value = optValue.value();
984 const auto& descriptor = getInDescriptor(index);
985 const auto message = inMessage.data();
986
987 switch (descriptor.adjustedType)
988 {
990 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) =
991 calendarConverter.timestampToOpaqueTimestamp(value);
992 break;
993
994 default:
995 throwInvalidType("Timestamp", descriptor.adjustedType);
996 }
997
998 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
999 }
1000
1004 void setOpaqueTimestamp(unsigned index, std::optional<OpaqueTimestamp> optValue)
1005 {
1006 if (!optValue.has_value())
1007 {
1008 setNull(index);
1009 return;
1010 }
1011
1012 assert(isValid());
1013
1014 const auto& value = optValue.value();
1015 const auto& descriptor = getInDescriptor(index);
1016 const auto message = inMessage.data();
1017
1018 switch (descriptor.adjustedType)
1019 {
1021 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) = value;
1022 break;
1023
1024 default:
1025 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
1026 }
1027
1028 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1029 }
1030
1034 void setTimeTz(unsigned index, std::optional<TimeTz> optValue)
1035 {
1036 if (!optValue.has_value())
1037 {
1038 setNull(index);
1039 return;
1040 }
1041
1042 assert(isValid());
1043
1044 const auto& value = optValue.value();
1045 const auto& descriptor = getInDescriptor(index);
1046 auto* const message = inMessage.data();
1047
1048 switch (descriptor.adjustedType)
1049 {
1051 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) =
1052 calendarConverter.timeTzToOpaqueTimeTz(value);
1053 break;
1054
1055 default:
1056 throwInvalidType("TimeTz", descriptor.adjustedType);
1057 }
1058
1059 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1060 }
1061
1065 void setOpaqueTimeTz(unsigned index, std::optional<OpaqueTimeTz> optValue)
1066 {
1067 if (!optValue.has_value())
1068 {
1069 setNull(index);
1070 return;
1071 }
1072
1073 assert(isValid());
1074
1075 const auto& value = optValue.value();
1076 const auto& descriptor = getInDescriptor(index);
1077 auto* const message = inMessage.data();
1078
1079 switch (descriptor.adjustedType)
1080 {
1082 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) = value;
1083 break;
1084
1085 default:
1086 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
1087 }
1088
1089 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1090 }
1091
1095 void setTimestampTz(unsigned index, std::optional<TimestampTz> optValue)
1096 {
1097 if (!optValue.has_value())
1098 {
1099 setNull(index);
1100 return;
1101 }
1102
1103 assert(isValid());
1104
1105 const auto& value = optValue.value();
1106 const auto& descriptor = getInDescriptor(index);
1107 auto* const message = inMessage.data();
1108
1109 switch (descriptor.adjustedType)
1110 {
1112 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) =
1113 calendarConverter.timestampTzToOpaqueTimestampTz(value);
1114 break;
1115
1116 default:
1117 throwInvalidType("TimestampTz", descriptor.adjustedType);
1118 }
1119
1120 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1121 }
1122
1126 void setOpaqueTimestampTz(unsigned index, std::optional<OpaqueTimestampTz> optValue)
1127 {
1128 if (!optValue.has_value())
1129 {
1130 setNull(index);
1131 return;
1132 }
1133
1134 assert(isValid());
1135
1136 const auto& value = optValue.value();
1137 const auto& descriptor = getInDescriptor(index);
1138 auto* const message = inMessage.data();
1139
1140 switch (descriptor.adjustedType)
1141 {
1143 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) = value;
1144 break;
1145
1146 default:
1147 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
1148 }
1149
1150 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1151 }
1152
1156 void setString(unsigned index, std::optional<std::string_view> optValue)
1157 {
1158 if (!optValue.has_value())
1159 {
1160 setNull(index);
1161 return;
1162 }
1163
1164 assert(isValid());
1165
1166 auto& client = attachment->getClient();
1167 const auto value = optValue.value();
1168 const auto& descriptor = getInDescriptor(index);
1169 const auto message = inMessage.data();
1170 const auto data = &message[descriptor.offset];
1171
1172 switch (descriptor.adjustedType)
1173 {
1175 message[descriptor.offset] = numericConverter.stringToBoolean(value);
1176 break;
1177
1181 {
1182 std::string strValue(value);
1183 int scale = 0;
1184
1185 if (const auto dotPos = strValue.find_last_of('.'); dotPos != std::string_view::npos)
1186 {
1187 for (auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1188 {
1189 const char c = value[pos];
1190
1191 if (c < '0' || c > '9')
1192 break;
1193
1194 --scale;
1195 }
1196
1197 strValue.erase(dotPos, 1);
1198 }
1199
1200 static_assert(sizeof(long long) == sizeof(std::int64_t));
1201 std::int64_t intValue;
1202 const auto convResult =
1203 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1204 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1205 numericConverter.throwConversionErrorFromString(strValue);
1206 auto scaledValue = ScaledInt64{intValue, scale};
1207
1208 if (scale != descriptor.scale)
1209 {
1210 scaledValue.value =
1211 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1212 scaledValue.scale = descriptor.scale;
1213 }
1214
1215 setScaledInt64(index, scaledValue);
1216 return;
1217 }
1218
1220 {
1221 std::string strValue(value);
1222 client.getInt128Util(&statusWrapper)
1223 ->fromString(
1224 &statusWrapper, descriptor.scale, strValue.c_str(), reinterpret_cast<OpaqueInt128*>(data));
1225 break;
1226 }
1227
1230 {
1231 double doubleValue;
1232#if defined(__APPLE__)
1233 errno = 0;
1234 std::string valueString{value};
1235 char* parseEnd = nullptr;
1236 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1237 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1238 numericConverter.throwConversionErrorFromString(std::move(valueString));
1239#else
1240 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1241 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1242 numericConverter.throwConversionErrorFromString(std::string{value});
1243#endif
1244 setDouble(index, doubleValue);
1245 return;
1246 }
1247
1249 *reinterpret_cast<OpaqueDate*>(data) = calendarConverter.stringToOpaqueDate(value);
1250 break;
1251
1253 *reinterpret_cast<OpaqueTime*>(data) = calendarConverter.stringToOpaqueTime(value);
1254 break;
1255
1257 *reinterpret_cast<OpaqueTimestamp*>(data) = calendarConverter.stringToOpaqueTimestamp(value);
1258 break;
1259
1261 *reinterpret_cast<OpaqueTimeTz*>(data) = calendarConverter.stringToOpaqueTimeTz(value);
1262 break;
1263
1265 *reinterpret_cast<OpaqueTimestampTz*>(data) = calendarConverter.stringToOpaqueTimestampTz(value);
1266 break;
1267
1268#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1270 {
1271 std::string strValue{value};
1272 client.getDecFloat16Util(&statusWrapper)
1273 ->fromString(&statusWrapper, strValue.c_str(), reinterpret_cast<OpaqueDecFloat16*>(data));
1274 break;
1275 }
1276
1278 {
1279 std::string strValue{value};
1280 client.getDecFloat34Util(&statusWrapper)
1281 ->fromString(&statusWrapper, strValue.c_str(), reinterpret_cast<OpaqueDecFloat34*>(data));
1282 break;
1283 }
1284#endif
1285
1287 if (value.length() > descriptor.length)
1288 {
1289 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1290 isc_arith_except,
1291 isc_string_truncation,
1292 isc_arg_end,
1293 };
1294
1295 throw DatabaseException(client, STATUS_STRING_TRUNCATION);
1296 }
1297
1298 *reinterpret_cast<std::uint16_t*>(data) = static_cast<std::uint16_t>(value.length());
1299 std::copy(value.begin(), value.end(),
1300 reinterpret_cast<char*>(&message[descriptor.offset + sizeof(std::uint16_t)]));
1301 break;
1302
1303 default:
1304 throwInvalidType("std::string_view", descriptor.adjustedType);
1305 }
1306
1307 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1308 }
1309
1313 void setBlobId(unsigned index, std::optional<BlobId> optValue)
1314 {
1315 if (!optValue.has_value())
1316 {
1317 setNull(index);
1318 return;
1319 }
1320
1321 assert(isValid());
1322
1323 const auto& value = optValue.value();
1324 const auto& descriptor = getInDescriptor(index);
1325 auto* const message = inMessage.data();
1326
1327 switch (descriptor.adjustedType)
1328 {
1330 *reinterpret_cast<ISC_QUAD*>(&message[descriptor.offset]) = value.id;
1331 break;
1332
1333 default:
1334 throwInvalidType("BlobId", descriptor.adjustedType);
1335 }
1336
1337 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1338 }
1339
1342 void set(unsigned index, std::nullopt_t)
1343 {
1344 setNull(index);
1345 }
1346
1350 void set(unsigned index, BlobId value)
1351 {
1352 setBlobId(index, value);
1353 }
1354
1358 void set(unsigned index, std::optional<BlobId> value)
1359 {
1360 setBlobId(index, value);
1361 }
1362
1366 void set(unsigned index, bool value)
1367 {
1368 setBool(index, value);
1369 }
1370
1374 void set(unsigned index, std::int16_t value)
1375 {
1376 setInt16(index, value);
1377 }
1378
1382 void set(unsigned index, ScaledInt16 value)
1383 {
1384 setScaledInt16(index, value);
1385 }
1386
1390 void set(unsigned index, std::int32_t value)
1391 {
1392 setInt32(index, value);
1393 }
1394
1398 void set(unsigned index, ScaledInt32 value)
1399 {
1400 setScaledInt32(index, value);
1401 }
1402
1406 void set(unsigned index, std::int64_t value)
1407 {
1408 setInt64(index, value);
1409 }
1410
1414 void set(unsigned index, ScaledInt64 value)
1415 {
1416 setScaledInt64(index, value);
1417 }
1418
1422 void set(unsigned index, OpaqueInt128 value)
1423 {
1424 setOpaqueInt128(index, value);
1425 }
1426
1427#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1431 void set(unsigned index, BoostInt128 value)
1432 {
1433 setBoostInt128(index, value);
1434 }
1435
1439 void set(unsigned index, ScaledBoostInt128 value)
1440 {
1441 setScaledBoostInt128(index, value);
1442 }
1443#endif
1444
1448 void set(unsigned index, float value)
1449 {
1450 setFloat(index, value);
1451 }
1452
1456 void set(unsigned index, double value)
1457 {
1458 setDouble(index, value);
1459 }
1460
1464 void set(unsigned index, OpaqueDecFloat16 value)
1465 {
1466 setOpaqueDecFloat16(index, value);
1467 }
1468
1469#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1473 void set(unsigned index, BoostDecFloat16 value)
1474 {
1475 setBoostDecFloat16(index, value);
1476 }
1477#endif
1478
1482 void set(unsigned index, OpaqueDecFloat34 value)
1483 {
1484 setOpaqueDecFloat34(index, value);
1485 }
1486
1487#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1491 void set(unsigned index, BoostDecFloat34 value)
1492 {
1493 setBoostDecFloat34(index, value);
1494 }
1495#endif
1496
1500 void set(unsigned index, Date value)
1501 {
1502 setDate(index, value);
1503 }
1504
1508 void set(unsigned index, OpaqueDate value)
1509 {
1510 setOpaqueDate(index, value);
1511 }
1512
1516 void set(unsigned index, Time value)
1517 {
1518 setTime(index, value);
1519 }
1520
1524 void set(unsigned index, OpaqueTime value)
1525 {
1526 setOpaqueTime(index, value);
1527 }
1528
1532 void set(unsigned index, Timestamp value)
1533 {
1534 setTimestamp(index, value);
1535 }
1536
1540 void set(unsigned index, OpaqueTimestamp value)
1541 {
1542 setOpaqueTimestamp(index, value);
1543 }
1544
1548 void set(unsigned index, TimeTz value)
1549 {
1550 setTimeTz(index, value);
1551 }
1552
1556 void set(unsigned index, OpaqueTimeTz value)
1557 {
1558 setOpaqueTimeTz(index, value);
1559 }
1560
1564 void set(unsigned index, TimestampTz value)
1565 {
1566 setTimestampTz(index, value);
1567 }
1568
1572 void set(unsigned index, OpaqueTimestampTz value)
1573 {
1574 setOpaqueTimestampTz(index, value);
1575 }
1576
1580 void set(unsigned index, std::string_view value)
1581 {
1582 setString(index, value);
1583 }
1584
1588 template <typename T>
1589 void set(unsigned index, std::optional<T> value)
1590 {
1591 if (value.has_value())
1592 set(index, value.value());
1593 else
1594 setNull(index);
1595 }
1596
1600
1604
1608 bool isNull(unsigned index)
1609 {
1610 assert(isValid());
1611
1612 const auto& descriptor = getOutDescriptor(index);
1613 const auto* const message = outMessage.data();
1614
1615 return *reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE;
1616 }
1617
1621 std::optional<bool> getBool(unsigned index)
1622 {
1623 assert(isValid());
1624
1625 const auto& descriptor = getOutDescriptor(index);
1626 const auto* const message = outMessage.data();
1627
1628 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1629 return std::nullopt;
1630
1631 switch (descriptor.adjustedType)
1632 {
1634 return message[descriptor.offset] != std::byte{0};
1635
1636 default:
1637 throwInvalidType("bool", descriptor.adjustedType);
1638 }
1639 }
1640
1644 std::optional<std::int16_t> getInt16(unsigned index)
1645 {
1646 std::optional<int> scale{0};
1647 return getNumber<std::int16_t>(index, scale, "std::int16_t");
1648 }
1649
1653 std::optional<ScaledInt16> getScaledInt16(unsigned index)
1654 {
1655 std::optional<int> scale;
1656 const auto value = getNumber<std::int16_t>(index, scale, "ScaledInt16");
1657 return value.has_value() ? std::optional{ScaledInt16{value.value(), scale.value()}} : std::nullopt;
1658 }
1659
1663 std::optional<std::int32_t> getInt32(unsigned index)
1664 {
1665 std::optional<int> scale{0};
1666 return getNumber<std::int32_t>(index, scale, "std::int32_t");
1667 }
1668
1672 std::optional<ScaledInt32> getScaledInt32(unsigned index)
1673 {
1674 std::optional<int> scale;
1675 const auto value = getNumber<std::int32_t>(index, scale, "ScaledInt32");
1676 return value.has_value() ? std::optional{ScaledInt32{value.value(), scale.value()}} : std::nullopt;
1677 }
1678
1682 std::optional<std::int64_t> getInt64(unsigned index)
1683 {
1684 std::optional<int> scale{0};
1685 return getNumber<std::int64_t>(index, scale, "std::int64_t");
1686 }
1687
1691 std::optional<ScaledInt64> getScaledInt64(unsigned index)
1692 {
1693 std::optional<int> scale;
1694 const auto value = getNumber<std::int64_t>(index, scale, "ScaledInt64");
1695 return value.has_value() ? std::optional{ScaledInt64{value.value(), scale.value()}} : std::nullopt;
1696 }
1697
1701 std::optional<ScaledOpaqueInt128> getScaledOpaqueInt128(unsigned index)
1702 {
1703 assert(isValid());
1704
1705 const auto& descriptor = getOutDescriptor(index);
1706 const auto* const message = outMessage.data();
1707
1708 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1709 return std::nullopt;
1710
1711 switch (descriptor.adjustedType)
1712 {
1714 return ScaledOpaqueInt128{
1715 OpaqueInt128{*reinterpret_cast<const OpaqueInt128*>(&message[descriptor.offset])},
1716 descriptor.scale};
1717
1718 default:
1719 throwInvalidType("ScaledOpaqueInt128", descriptor.adjustedType);
1720 }
1721 }
1722
1723#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1727 std::optional<BoostInt128> getBoostInt128(unsigned index)
1728 {
1729 std::optional<int> scale{0};
1730 const auto value = getNumber<BoostInt128>(index, scale, "BoostInt128");
1731 return value.has_value() ? std::optional{value.value()} : std::nullopt;
1732 }
1733
1737 std::optional<ScaledBoostInt128> getScaledBoostInt128(unsigned index)
1738 {
1739 std::optional<int> scale;
1740 const auto value = getNumber<BoostInt128>(index, scale, "ScaledBoostInt128");
1741 return value.has_value() ? std::optional{ScaledBoostInt128{value.value(), scale.value()}} : std::nullopt;
1742 }
1743#endif
1744
1748 std::optional<float> getFloat(unsigned index)
1749 {
1750 std::optional<int> scale{0};
1751 return getNumber<float>(index, scale, "float");
1752 }
1753
1757 std::optional<double> getDouble(unsigned index)
1758 {
1759 std::optional<int> scale{0};
1760 return getNumber<double>(index, scale, "double");
1761 }
1762
1766 std::optional<OpaqueDecFloat16> getOpaqueDecFloat16(unsigned index)
1767 {
1768 assert(isValid());
1769
1770 const auto& descriptor = getOutDescriptor(index);
1771 const auto* const message = outMessage.data();
1772
1773 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1774 return std::nullopt;
1775
1776 switch (descriptor.adjustedType)
1777 {
1779 return OpaqueDecFloat16{*reinterpret_cast<const OpaqueDecFloat16*>(&message[descriptor.offset])};
1780
1781 default:
1782 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
1783 }
1784 }
1785
1786#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1790 std::optional<BoostDecFloat16> getBoostDecFloat16(unsigned index)
1791 {
1792 std::optional<int> scale{0};
1793 return getNumber<BoostDecFloat16>(index, scale, "BoostDecFloat16");
1794 }
1795#endif
1796
1800 std::optional<OpaqueDecFloat34> getOpaqueDecFloat34(unsigned index)
1801 {
1802 assert(isValid());
1803
1804 const auto& descriptor = getOutDescriptor(index);
1805 const auto* const message = outMessage.data();
1806
1807 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1808 return std::nullopt;
1809
1810 switch (descriptor.adjustedType)
1811 {
1813 return OpaqueDecFloat34{*reinterpret_cast<const OpaqueDecFloat34*>(&message[descriptor.offset])};
1814
1815 default:
1816 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
1817 }
1818 }
1819
1820#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1824 std::optional<BoostDecFloat34> getBoostDecFloat34(unsigned index)
1825 {
1826 std::optional<int> scale{0};
1827 return getNumber<BoostDecFloat34>(index, scale, "BoostDecFloat34");
1828 }
1829#endif
1830
1834 std::optional<Date> getDate(unsigned index)
1835 {
1836 assert(isValid());
1837
1838 const auto& descriptor = getOutDescriptor(index);
1839 const auto* const message = outMessage.data();
1840
1841 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1842 return std::nullopt;
1843
1844 switch (descriptor.adjustedType)
1845 {
1847 return calendarConverter.opaqueDateToDate(
1848 *reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset]));
1849
1850 default:
1851 throwInvalidType("Date", descriptor.adjustedType);
1852 }
1853 }
1854
1858 std::optional<OpaqueDate> getOpaqueDate(unsigned index)
1859 {
1860 assert(isValid());
1861
1862 const auto& descriptor = getOutDescriptor(index);
1863 const auto* const message = outMessage.data();
1864
1865 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1866 return std::nullopt;
1867
1868 switch (descriptor.adjustedType)
1869 {
1871 return OpaqueDate{*reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset])};
1872
1873 default:
1874 throwInvalidType("OpaqueDate", descriptor.adjustedType);
1875 }
1876 }
1877
1881 std::optional<Time> getTime(unsigned index)
1882 {
1883 assert(isValid());
1884
1885 const auto& descriptor = getOutDescriptor(index);
1886 const auto* const message = outMessage.data();
1887
1888 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1889 return std::nullopt;
1890
1891 switch (descriptor.adjustedType)
1892 {
1894 return calendarConverter.opaqueTimeToTime(
1895 *reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset]));
1896
1897 default:
1898 throwInvalidType("Time", descriptor.adjustedType);
1899 }
1900 }
1901
1905 std::optional<OpaqueTime> getOpaqueTime(unsigned index)
1906 {
1907 assert(isValid());
1908
1909 const auto& descriptor = getOutDescriptor(index);
1910 const auto* const message = outMessage.data();
1911
1912 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1913 return std::nullopt;
1914
1915 switch (descriptor.adjustedType)
1916 {
1918 return OpaqueTime{*reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset])};
1919
1920 default:
1921 throwInvalidType("OpaqueTime", descriptor.adjustedType);
1922 }
1923 }
1924
1928 std::optional<Timestamp> getTimestamp(unsigned index)
1929 {
1930 assert(isValid());
1931
1932 const auto& descriptor = getOutDescriptor(index);
1933 const auto* const message = outMessage.data();
1934
1935 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1936 return std::nullopt;
1937
1938 switch (descriptor.adjustedType)
1939 {
1941 return calendarConverter.opaqueTimestampToTimestamp(
1942 *reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset]));
1943
1944 default:
1945 throwInvalidType("Timestamp", descriptor.adjustedType);
1946 }
1947 }
1948
1952 std::optional<OpaqueTimestamp> getOpaqueTimestamp(unsigned index)
1953 {
1954 assert(isValid());
1955
1956 const auto& descriptor = getOutDescriptor(index);
1957 const auto* const message = outMessage.data();
1958
1959 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1960 return std::nullopt;
1961
1962 switch (descriptor.adjustedType)
1963 {
1965 return OpaqueTimestamp{*reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset])};
1966
1967 default:
1968 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
1969 }
1970 }
1971
1975 std::optional<TimeTz> getTimeTz(unsigned index)
1976 {
1977 assert(isValid());
1978
1979 const auto& descriptor = getOutDescriptor(index);
1980 const auto* const message = outMessage.data();
1981
1982 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1983 return std::nullopt;
1984
1985 switch (descriptor.adjustedType)
1986 {
1988 return calendarConverter.opaqueTimeTzToTimeTz(
1989 *reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset]));
1990
1991 default:
1992 throwInvalidType("TimeTz", descriptor.adjustedType);
1993 }
1994 }
1995
1999 std::optional<OpaqueTimeTz> getOpaqueTimeTz(unsigned index)
2000 {
2001 assert(isValid());
2002
2003 const auto& descriptor = getOutDescriptor(index);
2004 const auto* const message = outMessage.data();
2005
2006 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2007 return std::nullopt;
2008
2009 switch (descriptor.adjustedType)
2010 {
2012 return OpaqueTimeTz{*reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset])};
2013
2014 default:
2015 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
2016 }
2017 }
2018
2022 std::optional<TimestampTz> getTimestampTz(unsigned index)
2023 {
2024 assert(isValid());
2025
2026 const auto& descriptor = getOutDescriptor(index);
2027 const auto* const message = outMessage.data();
2028
2029 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2030 return std::nullopt;
2031
2032 switch (descriptor.adjustedType)
2033 {
2035 return calendarConverter.opaqueTimestampTzToTimestampTz(
2036 *reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset]));
2037
2038 default:
2039 throwInvalidType("TimestampTz", descriptor.adjustedType);
2040 }
2041 }
2042
2046 std::optional<OpaqueTimestampTz> getOpaqueTimestampTz(unsigned index)
2047 {
2048 assert(isValid());
2049
2050 const auto& descriptor = getOutDescriptor(index);
2051 const auto* const message = outMessage.data();
2052
2053 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2054 return std::nullopt;
2055
2056 switch (descriptor.adjustedType)
2057 {
2059 return OpaqueTimestampTz{*reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset])};
2060
2061 default:
2062 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
2063 }
2064 }
2065
2069 std::optional<BlobId> getBlobId(unsigned index)
2070 {
2071 assert(isValid());
2072
2073 const auto& descriptor = getOutDescriptor(index);
2074 const auto* const message = outMessage.data();
2075
2076 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2077 return std::nullopt;
2078
2079 switch (descriptor.adjustedType)
2080 {
2082 {
2083 BlobId value;
2084 value.id = *reinterpret_cast<const ISC_QUAD*>(&message[descriptor.offset]);
2085 return value;
2086 }
2087
2088 default:
2089 throwInvalidType("BlobId", descriptor.adjustedType);
2090 }
2091 }
2092
2096 std::optional<std::string> getString(unsigned index)
2097 {
2098 assert(isValid());
2099
2100 const auto& descriptor = getOutDescriptor(index);
2101 const auto* const message = outMessage.data();
2102
2103 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2104 return std::nullopt;
2105
2106 const auto data = &message[descriptor.offset];
2107
2108 switch (descriptor.adjustedType)
2109 {
2111 return (message[descriptor.offset] != std::byte{0}) ? std::string{"true"} : std::string{"false"};
2112
2114 return numericConverter.numberToString(
2115 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale});
2116
2118 return numericConverter.numberToString(
2119 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale});
2120
2122 return numericConverter.numberToString(
2123 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale});
2124
2126 return numericConverter.opaqueInt128ToString(
2127 *reinterpret_cast<const OpaqueInt128*>(data), descriptor.scale);
2128
2130 return numericConverter.numberToString(*reinterpret_cast<const float*>(data));
2131
2133 return numericConverter.numberToString(*reinterpret_cast<const double*>(data));
2134
2136 return calendarConverter.opaqueDateToString(*reinterpret_cast<const OpaqueDate*>(data));
2137
2139 return calendarConverter.opaqueTimeToString(*reinterpret_cast<const OpaqueTime*>(data));
2140
2142 return calendarConverter.opaqueTimestampToString(*reinterpret_cast<const OpaqueTimestamp*>(data));
2143
2145 return calendarConverter.opaqueTimeTzToString(*reinterpret_cast<const OpaqueTimeTz*>(data));
2146
2148 return calendarConverter.opaqueTimestampTzToString(
2149 *reinterpret_cast<const OpaqueTimestampTz*>(data));
2150
2152 return numericConverter.opaqueDecFloat16ToString(*reinterpret_cast<const OpaqueDecFloat16*>(data));
2153
2155 return numericConverter.opaqueDecFloat34ToString(*reinterpret_cast<const OpaqueDecFloat34*>(data));
2156
2158 return std::string{reinterpret_cast<const char*>(data + sizeof(std::uint16_t)),
2159 *reinterpret_cast<const std::uint16_t*>(data)};
2160
2161 default:
2162 throwInvalidType("std::string", descriptor.adjustedType);
2163 }
2164 }
2165
2169
2173 template <typename T>
2174 T get(unsigned index);
2175
2183 template <Aggregate T>
2185 {
2186 using namespace impl::reflection;
2187
2188 constexpr std::size_t N = fieldCountV<T>;
2189
2190 if (N != outDescriptors.size())
2191 {
2192 throw FbCppException("Struct field count (" + std::to_string(N) +
2193 ") does not match output column count (" + std::to_string(outDescriptors.size()) + ")");
2194 }
2195
2196 return getStruct<T>(std::make_index_sequence<N>{});
2197 }
2198
2205 template <Aggregate T>
2206 void set(const T& value)
2207 {
2208 using namespace impl::reflection;
2209
2210 constexpr std::size_t N = fieldCountV<T>;
2211
2212 if (N != inDescriptors.size())
2213 {
2214 throw FbCppException("Struct field count (" + std::to_string(N) +
2215 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) + ")");
2216 }
2217
2218 setStruct(value, std::make_index_sequence<N>{});
2219 }
2220
2228 template <TupleLike T>
2230 {
2231 using namespace impl::reflection;
2232
2233 constexpr std::size_t N = std::tuple_size_v<T>;
2234
2235 if (N != outDescriptors.size())
2236 {
2237 throw FbCppException("Tuple element count (" + std::to_string(N) +
2238 ") does not match output column count (" + std::to_string(outDescriptors.size()) + ")");
2239 }
2240
2241 return getTuple<T>(std::make_index_sequence<N>{});
2242 }
2243
2250 template <TupleLike T>
2251 void set(const T& value)
2252 {
2253 constexpr std::size_t N = std::tuple_size_v<T>;
2254
2255 if (N != inDescriptors.size())
2256 {
2257 throw FbCppException("Tuple element count (" + std::to_string(N) +
2258 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) + ")");
2259 }
2260
2261 setTuple(value, std::make_index_sequence<N>{});
2262 }
2263
2272 template <VariantLike V>
2273 V get(unsigned index)
2274 {
2275 using namespace impl::reflection;
2276
2277 static_assert(variantAlternativesSupportedV<V>,
2278 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2279 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2280 "complete list of supported types.");
2281
2282 assert(isValid());
2283
2284 const auto& descriptor = getOutDescriptor(index);
2285
2286 if (isNull(index))
2287 {
2288 if constexpr (variantContainsV<std::monostate, V>)
2289 return V{std::monostate{}};
2290 else
2291 {
2292 throw FbCppException(
2293 "NULL value encountered but variant does not contain std::monostate at index " +
2294 std::to_string(index));
2295 }
2296 }
2297
2298 return getVariantValue<V>(index, descriptor);
2299 }
2300
2307 template <VariantLike V>
2308 void set(unsigned index, const V& value)
2309 {
2310 using namespace impl::reflection;
2311
2312 static_assert(variantAlternativesSupportedV<V>,
2313 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2314 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2315 "complete list of supported types.");
2316
2317 std::visit(
2318 [this, index](const auto& v)
2319 {
2320 using T = std::decay_t<decltype(v)>;
2321
2322 if constexpr (std::is_same_v<T, std::monostate>)
2323 setNull(index);
2324 else
2325 set(index, v);
2326 },
2327 value);
2328 }
2329
2330 private:
2334 const Descriptor& getInDescriptor(unsigned index)
2335 {
2336 if (index >= inDescriptors.size())
2337 throw std::out_of_range("index out of range");
2338
2339 return inDescriptors[index];
2340 }
2341
2345 const Descriptor& getOutDescriptor(unsigned index)
2346 {
2347 if (index >= outDescriptors.size())
2348 throw std::out_of_range("index out of range");
2349
2350 return outDescriptors[index];
2351 }
2352
2356 template <typename T, std::size_t... Is>
2357 T getStruct(std::index_sequence<Is...>)
2358 {
2359 using namespace impl::reflection;
2360
2361 return T{getStructField<FieldType<T, Is>>(static_cast<unsigned>(Is))...};
2362 }
2363
2367 template <typename F>
2368 auto getStructField(unsigned index)
2369 {
2370 using namespace impl::reflection;
2371
2372 if constexpr (isOptionalV<F>)
2373 return get<F>(index);
2374 else if constexpr (isVariantV<F>)
2375 return get<F>(index);
2376 else
2377 {
2378 auto opt = get<std::optional<F>>(index);
2379
2380 if (!opt.has_value())
2381 {
2382 throw FbCppException(
2383 "Null value encountered for non-optional field at index " + std::to_string(index));
2384 }
2385
2386 return std::move(opt.value());
2387 }
2388 }
2389
2393 template <typename T, std::size_t... Is>
2394 void setStruct(const T& value, std::index_sequence<Is...>)
2395 {
2396 using namespace impl::reflection;
2397
2398 const auto tuple = toTupleRef(value);
2399 (set(static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
2400 }
2401
2405 template <typename T, std::size_t... Is>
2406 T getTuple(std::index_sequence<Is...>)
2407 {
2408 using namespace impl::reflection;
2409
2410 return T{getStructField<std::tuple_element_t<Is, T>>(static_cast<unsigned>(Is))...};
2411 }
2412
2416 template <typename T, std::size_t... Is>
2417 void setTuple(const T& value, std::index_sequence<Is...>)
2418 {
2419 (set(static_cast<unsigned>(Is), std::get<Is>(value)), ...);
2420 }
2421
2426 template <typename V>
2427 V getVariantValue(unsigned index, const Descriptor& descriptor)
2428 {
2429 using namespace impl::reflection;
2430
2431 // Try exact type matches first based on SQL type
2432 switch (descriptor.adjustedType)
2433 {
2435 if constexpr (variantContainsV<bool, V>)
2436 return V{get<std::optional<bool>>(index).value()};
2437 break;
2438
2440 if (descriptor.scale != 0)
2441 {
2442 // For scaled numbers, prefer exact scaled type, then larger scaled types
2443 if constexpr (variantContainsV<ScaledInt16, V>)
2444 return V{get<std::optional<ScaledInt16>>(index).value()};
2445 if constexpr (variantContainsV<ScaledInt32, V>)
2446 return V{get<std::optional<ScaledInt32>>(index).value()};
2447 if constexpr (variantContainsV<ScaledInt64, V>)
2448 return V{get<std::optional<ScaledInt64>>(index).value()};
2449#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2450 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2451 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2452#endif
2453 }
2454 if constexpr (variantContainsV<std::int16_t, V>)
2455 return V{get<std::optional<std::int16_t>>(index).value()};
2456 break;
2457
2459 if (descriptor.scale != 0)
2460 {
2461 // For scaled numbers, prefer exact scaled type, then larger scaled types
2462 if constexpr (variantContainsV<ScaledInt32, V>)
2463 return V{get<std::optional<ScaledInt32>>(index).value()};
2464 if constexpr (variantContainsV<ScaledInt64, V>)
2465 return V{get<std::optional<ScaledInt64>>(index).value()};
2466#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2467 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2468 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2469#endif
2470 }
2471 if constexpr (variantContainsV<std::int32_t, V>)
2472 return V{get<std::optional<std::int32_t>>(index).value()};
2473 break;
2474
2476 if (descriptor.scale != 0)
2477 {
2478 // For scaled numbers, prefer exact scaled type, then larger scaled types
2479 if constexpr (variantContainsV<ScaledInt64, V>)
2480 return V{get<std::optional<ScaledInt64>>(index).value()};
2481#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2482 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2483 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2484#endif
2485 }
2486 if constexpr (variantContainsV<std::int64_t, V>)
2487 return V{get<std::optional<std::int64_t>>(index).value()};
2488 break;
2489
2490#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2492 // Prefer opaque (native Firebird) types first
2493 if constexpr (variantContainsV<ScaledOpaqueInt128, V>)
2494 return V{get<std::optional<ScaledOpaqueInt128>>(index).value()};
2495 else if (descriptor.scale != 0)
2496 {
2497 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2498 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2499 }
2500 else if constexpr (variantContainsV<BoostInt128, V>)
2501 return V{get<std::optional<BoostInt128>>(index).value()};
2502 break;
2503#endif
2504
2506 if constexpr (variantContainsV<float, V>)
2507 return V{get<std::optional<float>>(index).value()};
2508 break;
2509
2511 if constexpr (variantContainsV<double, V>)
2512 return V{get<std::optional<double>>(index).value()};
2513 break;
2514
2515#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2517 // Prefer opaque (native Firebird) types first
2518 if constexpr (variantContainsV<OpaqueDecFloat16, V>)
2519 return V{get<std::optional<OpaqueDecFloat16>>(index).value()};
2520 else if constexpr (variantContainsV<BoostDecFloat16, V>)
2521 return V{get<std::optional<BoostDecFloat16>>(index).value()};
2522 break;
2523
2525 // Prefer opaque (native Firebird) types first
2526 if constexpr (variantContainsV<OpaqueDecFloat34, V>)
2527 return V{get<std::optional<OpaqueDecFloat34>>(index).value()};
2528 else if constexpr (variantContainsV<BoostDecFloat34, V>)
2529 return V{get<std::optional<BoostDecFloat34>>(index).value()};
2530 break;
2531#endif
2532
2534 if constexpr (variantContainsV<std::string, V>)
2535 return V{get<std::optional<std::string>>(index).value()};
2536 break;
2537
2539 // Prefer opaque (native Firebird) types first
2540 if constexpr (variantContainsV<OpaqueDate, V>)
2541 return V{get<std::optional<OpaqueDate>>(index).value()};
2542 else if constexpr (variantContainsV<Date, V>)
2543 return V{get<std::optional<Date>>(index).value()};
2544 break;
2545
2547 // Prefer opaque (native Firebird) types first
2548 if constexpr (variantContainsV<OpaqueTime, V>)
2549 return V{get<std::optional<OpaqueTime>>(index).value()};
2550 else if constexpr (variantContainsV<Time, V>)
2551 return V{get<std::optional<Time>>(index).value()};
2552 break;
2553
2555 // Prefer opaque (native Firebird) types first
2556 if constexpr (variantContainsV<OpaqueTimestamp, V>)
2557 return V{get<std::optional<OpaqueTimestamp>>(index).value()};
2558 else if constexpr (variantContainsV<Timestamp, V>)
2559 return V{get<std::optional<Timestamp>>(index).value()};
2560 break;
2561
2563 // Prefer opaque (native Firebird) types first
2564 if constexpr (variantContainsV<OpaqueTimeTz, V>)
2565 return V{get<std::optional<OpaqueTimeTz>>(index).value()};
2566 else if constexpr (variantContainsV<TimeTz, V>)
2567 return V{get<std::optional<TimeTz>>(index).value()};
2568 break;
2569
2571 // Prefer opaque (native Firebird) types first
2572 if constexpr (variantContainsV<OpaqueTimestampTz, V>)
2573 return V{get<std::optional<OpaqueTimestampTz>>(index).value()};
2574 else if constexpr (variantContainsV<TimestampTz, V>)
2575 return V{get<std::optional<TimestampTz>>(index).value()};
2576 break;
2577
2579 if constexpr (variantContainsV<BlobId, V>)
2580 return V{get<std::optional<BlobId>>(index).value()};
2581 break;
2582
2583 default:
2584 break;
2585 }
2586
2587 // No exact match found, try variant alternatives in declaration order
2588 return tryVariantAlternatives<V, 0>(index, descriptor);
2589 }
2590
2594 template <typename V, std::size_t I = 0>
2595 V tryVariantAlternatives(unsigned index, [[maybe_unused]] const Descriptor& descriptor)
2596 {
2597 using namespace impl::reflection;
2598
2599 if constexpr (I >= std::variant_size_v<V>)
2600 {
2601 throw FbCppException(
2602 "Cannot convert SQL type to any variant alternative at index " + std::to_string(index));
2603 }
2604 else
2605 {
2606 using Alt = std::variant_alternative_t<I, V>;
2607
2608 if constexpr (std::is_same_v<Alt, std::monostate>)
2609 {
2610 // Skip monostate in non-null case
2611 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2612 }
2613 else if constexpr (isOpaqueTypeV<Alt>)
2614 {
2615 // Skip opaque types - they only match exact SQL types, no conversions
2616 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2617 }
2618 else
2619 {
2620 // Try this alternative - get<T> will throw if conversion fails
2621 auto opt = get<std::optional<Alt>>(index);
2622 return V{std::move(opt.value())};
2623 }
2624 }
2625 }
2626
2630 template <typename T>
2631 void setNumber(unsigned index, DescriptorAdjustedType valueType, T value, int scale, const char* typeName)
2632 {
2633 assert(isValid());
2634
2635 const auto& descriptor = getInDescriptor(index);
2636 auto* const message = inMessage.data();
2637
2638 const auto descriptorData = &message[descriptor.offset];
2639 std::optional<int> descriptorScale{descriptor.scale};
2640
2641 Descriptor valueDescriptor;
2642 valueDescriptor.adjustedType = valueType;
2643 valueDescriptor.scale = scale;
2644
2645 const auto valueAddress = reinterpret_cast<const std::byte*>(&value);
2646
2647 switch (descriptor.adjustedType)
2648 {
2650 *reinterpret_cast<std::int16_t*>(descriptorData) =
2651 convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale, "std::int16_t");
2652 break;
2653
2655 *reinterpret_cast<std::int32_t*>(descriptorData) =
2656 convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale, "std::int32_t");
2657 break;
2658
2660 *reinterpret_cast<std::int64_t*>(descriptorData) =
2661 convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale, "std::int64_t");
2662 break;
2663
2664#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2666 {
2667 const auto boostInt128 =
2668 convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale, "BoostInt128");
2669 *reinterpret_cast<OpaqueInt128*>(descriptorData) =
2670 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
2671 break;
2672 }
2673#endif
2674
2676 *reinterpret_cast<float*>(descriptorData) =
2677 convertNumber<float>(valueDescriptor, valueAddress, descriptorScale, "float");
2678 break;
2679
2681 *reinterpret_cast<double*>(descriptorData) =
2682 convertNumber<double>(valueDescriptor, valueAddress, descriptorScale, "double");
2683 break;
2684
2685#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2687 {
2688 const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
2689 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat16");
2690 *reinterpret_cast<OpaqueDecFloat16*>(descriptorData) =
2691 numericConverter.boostDecFloat16ToOpaqueDecFloat16(boostDecFloat16);
2692 break;
2693 }
2694
2696 {
2697 const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
2698 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat34");
2699 *reinterpret_cast<OpaqueDecFloat34*>(descriptorData) =
2700 numericConverter.boostDecFloat34ToOpaqueDecFloat34(boostDecFloat34);
2701 break;
2702 }
2703#endif
2704
2705 default:
2706 throwInvalidType(typeName, descriptor.adjustedType);
2707 }
2708
2709 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
2710 }
2711
2712 // FIXME: floating to integral
2716 template <typename T>
2717 std::optional<T> getNumber(unsigned index, std::optional<int>& scale, const char* typeName)
2718 {
2719 assert(isValid());
2720
2721 const auto& descriptor = getOutDescriptor(index);
2722 const auto* const message = outMessage.data();
2723
2724 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2725 return std::nullopt;
2726
2727 auto data = &message[descriptor.offset];
2728#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2729 std::optional<BoostInt128> boostInt128;
2730 std::optional<BoostDecFloat16> boostDecFloat16;
2731 std::optional<BoostDecFloat34> boostDecFloat34;
2732#endif
2733
2734 // FIXME: Use IUtil
2735 switch (descriptor.adjustedType)
2736 {
2737#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2739 boostInt128.emplace(
2740 numericConverter.opaqueInt128ToBoostInt128(*reinterpret_cast<const OpaqueInt128*>(data)));
2741 data = reinterpret_cast<const std::byte*>(&boostInt128.value());
2742 break;
2743
2745 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
2746 *reinterpret_cast<const OpaqueDecFloat16*>(data)));
2747 data = reinterpret_cast<const std::byte*>(&boostDecFloat16.value());
2748 break;
2749
2751 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
2752 *reinterpret_cast<const OpaqueDecFloat34*>(data)));
2753 data = reinterpret_cast<const std::byte*>(&boostDecFloat34.value());
2754 break;
2755#endif
2756
2757 default:
2758 break;
2759 }
2760
2761 return convertNumber<T>(descriptor, data, scale, typeName);
2762 }
2763
2764 [[noreturn]] static void throwInvalidType(const char* actualType, DescriptorAdjustedType descriptorType)
2765 {
2766 throw FbCppException("Invalid type: actual type " + std::string(actualType) + ", descriptor type " +
2767 std::to_string(static_cast<unsigned>(descriptorType)));
2768 }
2769
2770 template <typename T>
2771 T convertNumber(
2772 const Descriptor& descriptor, const std::byte* data, std::optional<int>& toScale, const char* toTypeName)
2773 {
2774 if (!toScale.has_value())
2775 {
2776 switch (descriptor.adjustedType)
2777 {
2782 throwInvalidType(toTypeName, descriptor.adjustedType);
2783
2784 default:
2785 break;
2786 }
2787
2788 toScale = descriptor.scale;
2789 }
2790
2791 switch (descriptor.adjustedType)
2792 {
2794 return numericConverter.numberToNumber<T>(
2795 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale}, toScale.value());
2796 break;
2797
2799 return numericConverter.numberToNumber<T>(
2800 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale}, toScale.value());
2801
2803 return numericConverter.numberToNumber<T>(
2804 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale}, toScale.value());
2805
2806#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2808 return numericConverter.numberToNumber<T>(
2809 ScaledBoostInt128{*reinterpret_cast<const BoostInt128*>(data), descriptor.scale},
2810 toScale.value());
2811
2813 return numericConverter.numberToNumber<T>(
2814 *reinterpret_cast<const BoostDecFloat16*>(data), toScale.value());
2815
2817 return numericConverter.numberToNumber<T>(
2818 *reinterpret_cast<const BoostDecFloat34*>(data), toScale.value());
2819#endif
2820
2822 return numericConverter.numberToNumber<T>(*reinterpret_cast<const float*>(data), toScale.value());
2823 break;
2824
2826 return numericConverter.numberToNumber<T>(*reinterpret_cast<const double*>(data), toScale.value());
2827 break;
2828
2829 default:
2830 throwInvalidType(toTypeName, descriptor.adjustedType);
2831 }
2832 }
2833
2834 private:
2835 Attachment* attachment;
2836 FbUniquePtr<Firebird::IStatus> status;
2837 impl::StatusWrapper statusWrapper;
2838 impl::CalendarConverter calendarConverter;
2839 impl::NumericConverter numericConverter;
2840 FbRef<fb::IStatement> statementHandle;
2841 FbRef<fb::IResultSet> resultSetHandle;
2842 FbRef<fb::IMessageMetadata> inMetadata;
2843 std::vector<Descriptor> inDescriptors;
2844 std::vector<std::byte> inMessage;
2845 FbRef<fb::IMessageMetadata> outMetadata;
2846 std::vector<Descriptor> outDescriptors;
2847 std::vector<std::byte> outMessage;
2848 StatementType type;
2849 unsigned cursorFlags = 0;
2850 };
2851
2856
2857 template <>
2858 inline std::optional<bool> Statement::get<std::optional<bool>>(unsigned index)
2859 {
2860 return getBool(index);
2861 }
2862
2863 template <>
2864 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(unsigned index)
2865 {
2866 return getBlobId(index);
2867 }
2868
2869 template <>
2870 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(unsigned index)
2871 {
2872 return getInt16(index);
2873 }
2874
2875 template <>
2876 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(unsigned index)
2877 {
2878 return getScaledInt16(index);
2879 }
2880
2881 template <>
2882 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(unsigned index)
2883 {
2884 return getInt32(index);
2885 }
2886
2887 template <>
2888 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(unsigned index)
2889 {
2890 return getScaledInt32(index);
2891 }
2892
2893 template <>
2894 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(unsigned index)
2895 {
2896 return getInt64(index);
2897 }
2898
2899 template <>
2900 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(unsigned index)
2901 {
2902 return getScaledInt64(index);
2903 }
2904
2905 template <>
2906 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(unsigned index)
2907 {
2908 return getScaledOpaqueInt128(index);
2909 }
2910
2911#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2912 template <>
2913 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(unsigned index)
2914 {
2915 return getBoostInt128(index);
2916 }
2917
2918 template <>
2919 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(unsigned index)
2920 {
2921 return getScaledBoostInt128(index);
2922 }
2923#endif
2924
2925 template <>
2926 inline std::optional<float> Statement::get<std::optional<float>>(unsigned index)
2927 {
2928 return getFloat(index);
2929 }
2930
2931 template <>
2932 inline std::optional<double> Statement::get<std::optional<double>>(unsigned index)
2933 {
2934 return getDouble(index);
2935 }
2936
2937 template <>
2938 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(unsigned index)
2939 {
2940 return getOpaqueDecFloat16(index);
2941 }
2942
2943#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2944 template <>
2945 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(unsigned index)
2946 {
2947 return getBoostDecFloat16(index);
2948 }
2949#endif
2950
2951 template <>
2952 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(unsigned index)
2953 {
2954 return getOpaqueDecFloat34(index);
2955 }
2956
2957#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2958 template <>
2959 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(unsigned index)
2960 {
2961 return getBoostDecFloat34(index);
2962 }
2963#endif
2964
2965 template <>
2966 inline std::optional<Date> Statement::get<std::optional<Date>>(unsigned index)
2967 {
2968 return getDate(index);
2969 }
2970
2971 template <>
2972 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(unsigned index)
2973 {
2974 return getOpaqueDate(index);
2975 }
2976
2977 template <>
2978 inline std::optional<Time> Statement::get<std::optional<Time>>(unsigned index)
2979 {
2980 return getTime(index);
2981 }
2982
2983 template <>
2984 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(unsigned index)
2985 {
2986 return getOpaqueTime(index);
2987 }
2988
2989 template <>
2990 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(unsigned index)
2991 {
2992 return getOpaqueTimestamp(index);
2993 }
2994
2995 template <>
2996 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(unsigned index)
2997 {
2998 return getTimestamp(index);
2999 }
3000
3001 template <>
3002 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(unsigned index)
3003 {
3004 return getTimeTz(index);
3005 }
3006
3007 template <>
3008 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(unsigned index)
3009 {
3010 return getOpaqueTimeTz(index);
3011 }
3012
3013 template <>
3014 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(unsigned index)
3015 {
3016 return getTimestampTz(index);
3017 }
3018
3019 template <>
3020 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(unsigned index)
3021 {
3022 return getOpaqueTimestampTz(index);
3023 }
3024
3025 template <>
3026 inline std::optional<std::string> Statement::get<std::optional<std::string>>(unsigned index)
3027 {
3028 return getString(index);
3029 }
3030
3034} // namespace fbcpp
3035
3036
3037#endif // FBCPP_STATEMENT_H
Represents a connection to a Firebird database.
Definition Attachment.h:213
Client & getClient() noexcept
Returns the Client object reference used to create this Attachment object.
Definition Attachment.h:281
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
unsigned getDialect() const
Returns the SQL dialect used when preparing the statement.
Definition Statement.h:170
StatementOptions & setDialect(unsigned value)
Sets the SQL dialect used when preparing the statement.
Definition Statement.h:180
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:261
void set(unsigned index, OpaqueInt128 value)
Convenience overload that binds a Firebird 128-bit integer.
Definition Statement.h:1422
Statement & operator=(Statement &&o) noexcept
Transfers ownership of another prepared statement into this one.
Definition Statement.h:301
void setScaledInt16(unsigned index, std::optional< ScaledInt16 > optValue)
Binds a scaled 16-bit signed integer value or null.
Definition Statement.h:597
V get(unsigned index)
Retrieves a column value as a user-defined variant type.
Definition Statement.h:2273
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:538
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:715
std::optional< OpaqueTime > getOpaqueTime(unsigned index)
Reads a raw time-of-day column in Firebird's representation.
Definition Statement.h:1905
std::optional< OpaqueDecFloat34 > getOpaqueDecFloat34(unsigned index)
Reads a Firebird 34-digit decimal floating-point column.
Definition Statement.h:1800
std::vector< std::byte > & getOutputMessage() noexcept
Provides direct access to the raw output message buffer.
Definition Statement.h:414
void setDate(unsigned index, std::optional< Date > optValue)
Binds a date value or null.
Definition Statement.h:851
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:440
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:448
bool isValid() noexcept
Returns whether the Statement object is valid.
Definition Statement.h:364
StatementType getType() noexcept
Returns the type classification reported by the server.
Definition Statement.h:422
void set(unsigned index, BoostDecFloat16 value)
Convenience overload that binds a Boost 16-digit decimal floating-point value.
Definition Statement.h:1473
std::optional< TimeTz > getTimeTz(unsigned index)
Reads a time-of-day column with timezone.
Definition Statement.h:1975
void setTime(unsigned index, std::optional< Time > optValue)
Binds a time-of-day value without timezone or null.
Definition Statement.h:912
void set(unsigned index, std::string_view value)
Convenience overload that binds a textual value.
Definition Statement.h:1580
std::optional< BoostDecFloat34 > getBoostDecFloat34(unsigned index)
Reads a Boost-based 34-digit decimal floating-point column.
Definition Statement.h:1824
void setBlobId(unsigned index, std::optional< BlobId > optValue)
Binds a blob identifier to the specified parameter or null.
Definition Statement.h:1313
void setInt16(unsigned index, std::optional< std::int16_t > optValue)
Binds a 16-bit signed integer value or null.
Definition Statement.h:583
void setString(unsigned index, std::optional< std::string_view > optValue)
Binds a textual parameter or null, performing direct conversions where supported.
Definition Statement.h:1156
void set(unsigned index, std::int32_t value)
Convenience overload that binds a 32-bit signed integer.
Definition Statement.h:1390
std::optional< Time > getTime(unsigned index)
Reads a time-of-day column without timezone.
Definition Statement.h:1881
std::optional< Date > getDate(unsigned index)
Reads a date column.
Definition Statement.h:1834
FbRef< fb::IResultSet > getResultSetHandle() noexcept
Provides access to the underlying Firebird currently open result set handle, if any.
Definition Statement.h:382
bool isNull(unsigned index)
Reports whether the most recently fetched row has a null at the given column.
Definition Statement.h:1608
void set(unsigned index, double value)
Convenience overload that binds a double precision floating-point value.
Definition Statement.h:1456
void clearParameters()
Marks all bound parameters as null values.
Definition Statement.h:524
void set(unsigned index, ScaledInt64 value)
Convenience overload that binds a scaled 64-bit signed integer.
Definition Statement.h:1414
std::optional< OpaqueDate > getOpaqueDate(unsigned index)
Reads a raw date column in Firebird's representation.
Definition Statement.h:1858
T get()
Retrieves all output columns into a user-defined aggregate struct.
Definition Statement.h:2184
void setScaledInt32(unsigned index, std::optional< ScaledInt32 > optValue)
Binds a scaled 32-bit signed integer value or null.
Definition Statement.h:626
void set(unsigned index, std::int64_t value)
Convenience overload that binds a 64-bit signed integer.
Definition Statement.h:1406
void setTimestampTz(unsigned index, std::optional< TimestampTz > optValue)
Binds a timestamp value with timezone or null.
Definition Statement.h:1095
std::optional< std::int64_t > getInt64(unsigned index)
Reads a 64-bit signed integer column.
Definition Statement.h:1682
FbRef< fb::IStatement > getStatementHandle() noexcept
Provides direct access to the underlying Firebird statement handle.
Definition Statement.h:373
std::optional< ScaledInt32 > getScaledInt32(unsigned index)
Reads a scaled 32-bit signed integer column.
Definition Statement.h:1672
void set(unsigned index, OpaqueTimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1572
void setOpaqueTime(unsigned index, std::optional< OpaqueTime > optValue)
Binds a raw time-of-day value in Firebird's representation or null.
Definition Statement.h:943
std::optional< float > getFloat(unsigned index)
Reads a single precision floating-point column.
Definition Statement.h:1748
std::optional< double > getDouble(unsigned index)
Reads a double precision floating-point column.
Definition Statement.h:1757
std::optional< OpaqueTimestampTz > getOpaqueTimestampTz(unsigned index)
Reads a raw timestamp-with-time-zone column in Firebird's representation.
Definition Statement.h:2046
std::optional< ScaledInt16 > getScaledInt16(unsigned index)
Reads a scaled 16-bit signed integer column.
Definition Statement.h:1653
std::optional< BlobId > getBlobId(unsigned index)
Reads a blob identifier column.
Definition Statement.h:2069
Statement(Statement &&o) noexcept
Transfers ownership of an existing prepared statement.
Definition Statement.h:276
void setInt64(unsigned index, std::optional< std::int64_t > optValue)
Binds a 64-bit signed integer value or null.
Definition Statement.h:641
std::optional< ScaledOpaqueInt128 > getScaledOpaqueInt128(unsigned index)
Reads a Firebird scaled 128-bit integer column.
Definition Statement.h:1701
FbRef< fb::IMessageMetadata > getOutputMetadata() noexcept
Returns the metadata describing columns produced by the statement.
Definition Statement.h:406
void set(unsigned index, TimeTz value)
Convenience overload that binds a Firebird time with timezone value.
Definition Statement.h:1548
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:759
void setOpaqueInt128(unsigned index, std::optional< OpaqueInt128 > optValue)
Binds a raw 128-bit integer value in Firebird's representation or null.
Definition Statement.h:670
std::optional< OpaqueTimeTz > getOpaqueTimeTz(unsigned index)
Reads a raw time-of-day column with timezone in Firebird's representation.
Definition Statement.h:1999
void setBoostInt128(unsigned index, std::optional< BoostInt128 > optValue)
Binds a 128-bit integer value expressed with Boost.Multiprecision or null.
Definition Statement.h:701
void set(unsigned index, Date value)
Convenience overload that binds a Firebird date value.
Definition Statement.h:1500
void set(unsigned index, Timestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1532
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:1065
void setTimestamp(unsigned index, std::optional< Timestamp > optValue)
Binds a timestamp value without timezone or null.
Definition Statement.h:973
std::optional< std::string > getString(unsigned index)
Reads a textual column, applying number-to-string conversions when needed.
Definition Statement.h:2096
std::optional< std::int32_t > getInt32(unsigned index)
Reads a 32-bit signed integer column.
Definition Statement.h:1663
void set(unsigned index, OpaqueDecFloat16 value)
Convenience overload that binds a Firebird 16-digit decimal floating-point value.
Definition Statement.h:1464
void setOpaqueTimestampTz(unsigned index, std::optional< OpaqueTimestampTz > optValue)
Binds a raw timestamp value with timezone in Firebird's representation or null.
Definition Statement.h:1126
FbRef< fb::IMessageMetadata > getInputMetadata() noexcept
Returns the metadata describing prepared input parameters.
Definition Statement.h:390
~Statement() noexcept
Releases resources; ignores failures to keep destructor noexcept.
Definition Statement.h:331
void set(unsigned index, OpaqueTimeTz value)
Convenience overload that binds a Firebird time with timezone value.
Definition Statement.h:1556
void setBoostDecFloat16(unsigned index, std::optional< BoostDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value using Boost.Multiprecision or null.
Definition Statement.h:790
std::optional< ScaledBoostInt128 > getScaledBoostInt128(unsigned index)
Reads a scaled Boost 128-bit integer column.
Definition Statement.h:1737
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:1350
void set(unsigned index, BoostDecFloat34 value)
Convenience overload that binds a Boost 34-digit decimal floating-point value.
Definition Statement.h:1491
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:1482
void set(unsigned index, Time value)
Convenience overload that binds a Firebird time value.
Definition Statement.h:1516
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:1382
std::optional< BoostInt128 > getBoostInt128(unsigned index)
Reads a Boost 128-bit integer column.
Definition Statement.h:1727
std::optional< bool > getBool(unsigned index)
Reads a boolean column from the current row.
Definition Statement.h:1621
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:805
void set(unsigned index, OpaqueTimestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1540
void setInt32(unsigned index, std::optional< std::int32_t > optValue)
Binds a 32-bit signed integer value or null.
Definition Statement.h:612
void set(unsigned index, std::optional< BlobId > value)
Convenience overload that binds an optional blob identifier.
Definition Statement.h:1358
void setBool(unsigned index, std::optional< bool > optValue)
Binds a boolean parameter value or null.
Definition Statement.h:553
void set(unsigned index, const V &value)
Sets a parameter from a variant value.
Definition Statement.h:2308
void set(unsigned index, TimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1564
void setDouble(unsigned index, std::optional< double > optValue)
Binds a double precision floating-point value or null.
Definition Statement.h:745
void set(unsigned index, OpaqueDate value)
Convenience overload that binds a Firebird date value.
Definition Statement.h:1508
void set(unsigned index, std::int16_t value)
Convenience overload that binds a 16-bit signed integer.
Definition Statement.h:1374
void set(unsigned index, std::optional< T > value)
Convenience template that forwards optional values to specialized overloads.
Definition Statement.h:1589
std::optional< OpaqueTimestamp > getOpaqueTimestamp(unsigned index)
Reads a raw timestamp column in Firebird's representation.
Definition Statement.h:1952
void setScaledInt64(unsigned index, std::optional< ScaledInt64 > optValue)
Binds a scaled 64-bit signed integer value or null.
Definition Statement.h:655
Attachment & getAttachment() noexcept
Returns the Attachment object reference used to create this Statement.
Definition Statement.h:356
void set(unsigned index, std::nullopt_t)
Convenience overload that binds a null value.
Definition Statement.h:1342
void setFloat(unsigned index, std::optional< float > optValue)
Binds a single precision floating-point value or null.
Definition Statement.h:731
void setOpaqueDate(unsigned index, std::optional< OpaqueDate > optValue)
Binds a raw date value in Firebird's representation or null.
Definition Statement.h:882
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:1524
void set(unsigned index, ScaledInt32 value)
Convenience overload that binds a scaled 32-bit signed integer.
Definition Statement.h:1398
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:1644
void set(unsigned index, ScaledBoostInt128 value)
Convenience overload that binds a scaled Boost-provided 128-bit integer.
Definition Statement.h:1439
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:2022
void set(unsigned index, BoostInt128 value)
Convenience overload that binds a Boost-provided 128-bit integer.
Definition Statement.h:1431
std::vector< std::byte > & getInputMessage() noexcept
Provides direct access to the raw input message buffer.
Definition Statement.h:398
std::optional< OpaqueDecFloat16 > getOpaqueDecFloat16(unsigned index)
Reads a Firebird 16-digit decimal floating-point column.
Definition Statement.h:1766
std::optional< Timestamp > getTimestamp(unsigned index)
Reads a timestamp column without timezone.
Definition Statement.h:1928
std::optional< BoostDecFloat16 > getBoostDecFloat16(unsigned index)
Reads a Boost-based 16-digit decimal floating-point column.
Definition Statement.h:1790
void setTimeTz(unsigned index, std::optional< TimeTz > optValue)
Binds a time-of-day value with timezone or null.
Definition Statement.h:1034
void setBoostDecFloat34(unsigned index, std::optional< BoostDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value using Boost.Multiprecision or null.
Definition Statement.h:836
std::optional< ScaledInt64 > getScaledInt64(unsigned index)
Reads a scaled 64-bit signed integer column.
Definition Statement.h:1691
void set(unsigned index, bool value)
Convenience overload that binds a boolean value.
Definition Statement.h:1366
void setOpaqueTimestamp(unsigned index, std::optional< OpaqueTimestamp > optValue)
Binds a raw timestamp value in Firebird's representation or null.
Definition Statement.h:1004
void set(unsigned index, float value)
Convenience overload that binds a single precision floating-point value.
Definition Statement.h:1448
void set(const T &value)
Sets all input parameters from fields of a user-defined aggregate struct.
Definition Statement.h:2206
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:198
@ 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