fb-cpp 0.0.1
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 <charconv>
40#include <cerrno>
41#include <cstdlib>
42#include <limits>
43#include <memory>
44#include <optional>
45#include <stdexcept>
46#include <string>
47#include <string_view>
48#include <type_traits>
49#include <vector>
50#include <cassert>
51#include <cmath>
52#include <cstddef>
53#include <cstdint>
54
55#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
56#include <boost/multiprecision/cpp_int.hpp>
57#include <boost/multiprecision/cpp_dec_float.hpp>
58#endif
59
63namespace fbcpp
64{
65 class Transaction;
66
70 class StatementOptions final
71 {
72 public:
77 {
78 return prefetchLegacyPlan;
79 }
80
87 {
88 prefetchLegacyPlan = value;
89 return *this;
90 }
91
95 bool getPrefetchPlan() const
96 {
97 return prefetchPlan;
98 }
99
106 {
107 prefetchPlan = value;
108 return *this;
109 }
110
111 private:
112 bool prefetchLegacyPlan = false;
113 bool prefetchPlan = false;
114 };
115
119 enum class StatementType : unsigned
120 {
124 SELECT = isc_info_sql_stmt_select,
128 INSERT = isc_info_sql_stmt_insert,
132 UPDATE = isc_info_sql_stmt_update,
136 DELETE = isc_info_sql_stmt_delete,
140 DDL = isc_info_sql_stmt_ddl,
144 GET_SEGMENT = isc_info_sql_stmt_get_segment,
148 PUT_SEGMENT = isc_info_sql_stmt_put_segment,
152 EXEC_PROCEDURE = isc_info_sql_stmt_exec_procedure,
156 START_TRANSACTION = isc_info_sql_stmt_start_trans,
160 COMMIT = isc_info_sql_stmt_commit,
164 ROLLBACK = isc_info_sql_stmt_rollback,
168 SELECT_FOR_UPDATE = isc_info_sql_stmt_select_for_upd,
172 SET_GENERATOR = isc_info_sql_stmt_set_generator,
176 SAVEPOINT = isc_info_sql_stmt_savepoint,
177 };
178
182 class Statement final
183 {
184 public:
192 explicit Statement(Attachment& attachment, Transaction& transaction, std::string_view sql,
193 const StatementOptions& options = {});
194
198 Statement(Statement&& o) noexcept
199 : attachment{o.attachment},
200 status{std::move(o.status)},
201 statusWrapper{std::move(o.statusWrapper)},
202 calendarConverter{std::move(o.calendarConverter)},
203 numericConverter{std::move(o.numericConverter)},
204 statementHandle{std::move(o.statementHandle)},
205 resultSetHandle{std::move(o.resultSetHandle)},
206 inMetadata{std::move(o.inMetadata)},
207 inDescriptors{std::move(o.inDescriptors)},
208 inMessage{std::move(o.inMessage)},
209 outMetadata{std::move(o.outMetadata)},
210 outDescriptors{std::move(o.outDescriptors)},
211 outMessage{std::move(o.outMessage)},
212 type{o.type}
213 {
214 }
215
216 Statement& operator=(Statement&&) = delete;
217 Statement(const Statement&) = delete;
218 Statement& operator=(const Statement&) = delete;
219
223 ~Statement() noexcept
224 {
225 if (isValid())
226 {
227 try
228 {
229 free();
230 }
231 catch (...)
232 {
233 // swallow
234 }
235 }
236 }
237
238 public:
244
248 bool isValid() noexcept
249 {
250 return statementHandle != nullptr;
251 }
252
258 {
259 return statementHandle;
260 }
261
267 {
268 return resultSetHandle;
269 }
270
275 {
276 return inMetadata;
277 }
278
283 {
284 return outMetadata;
285 }
286
291 {
292 return type;
293 }
294
298
304
308 const std::vector<Descriptor>& getInputDescriptors() noexcept
309 {
310 return inDescriptors;
311 }
312
316 const std::vector<Descriptor>& getOutputDescriptors() noexcept
317 {
318 return outDescriptors;
319 }
320
324
328 void free();
329
333 std::string getLegacyPlan();
334
338 std::string getPlan();
339
345 bool execute(Transaction& transaction);
346
350
354 bool fetchNext();
355
359 bool fetchPrior();
360
364 bool fetchFirst();
365
369 bool fetchLast();
370
374 bool fetchAbsolute(unsigned position);
375
379 bool fetchRelative(int offset);
380
384
388
393 {
394 assert(isValid());
395
396 const auto message = inMessage.data();
397
398 for (const auto& descriptor : inDescriptors)
399 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_TRUE;
400 }
401
406 void setNull(unsigned index)
407 {
408 assert(isValid());
409
410 const auto& descriptor = getInDescriptor(index);
411 const auto message = inMessage.data();
412
413 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_TRUE;
414 }
415
421 void setBool(unsigned index, std::optional<bool> optValue)
422 {
423 if (!optValue.has_value())
424 {
425 setNull(index);
426 return;
427 }
428
429 assert(isValid());
430
431 const auto& value = optValue.value();
432 const auto& descriptor = getInDescriptor(index);
433 const auto message = inMessage.data();
434
435 switch (descriptor.adjustedType)
436 {
437 case DescriptorAdjustedType::BOOLEAN:
438 message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
439 break;
440
441 default:
442 throwInvalidType("bool", descriptor.adjustedType);
443 }
444
445 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
446 }
447
451 void setInt16(unsigned index, std::optional<std::int16_t> optValue)
452 {
453 if (!optValue.has_value())
454 {
455 setNull(index);
456 return;
457 }
458
459 setNumber(index, DescriptorAdjustedType::INT16, optValue.value(), 0, "std::int16_t");
460 }
461
465 void setScaledInt16(unsigned index, std::optional<ScaledInt16> optValue)
466 {
467 if (!optValue.has_value())
468 {
469 setNull(index);
470 return;
471 }
472
473 const auto& value = optValue.value();
474 setNumber(index, DescriptorAdjustedType::INT16, value.value, value.scale, "ScaledInt16");
475 }
476
480 void setInt32(unsigned index, std::optional<std::int32_t> optValue)
481 {
482 if (!optValue.has_value())
483 {
484 setNull(index);
485 return;
486 }
487
488 setNumber(index, DescriptorAdjustedType::INT32, optValue.value(), 0, "std::int32_t");
489 }
490
494 void setScaledInt32(unsigned index, std::optional<ScaledInt32> optValue)
495 {
496 if (!optValue.has_value())
497 {
498 setNull(index);
499 return;
500 }
501
502 const auto& value = optValue.value();
503 setNumber(index, DescriptorAdjustedType::INT32, value.value, value.scale, "ScaledInt32");
504 }
505
509 void setInt64(unsigned index, std::optional<std::int64_t> optValue)
510 {
511 if (!optValue.has_value())
512 {
513 setNull(index);
514 return;
515 }
516
517 setNumber(index, DescriptorAdjustedType::INT64, optValue.value(), 0, "std::int64_t");
518 }
519
523 void setScaledInt64(unsigned index, std::optional<ScaledInt64> optValue)
524 {
525 if (!optValue.has_value())
526 {
527 setNull(index);
528 return;
529 }
530
531 const auto& value = optValue.value();
532 setNumber(index, DescriptorAdjustedType::INT64, value.value, value.scale, "ScaledInt64");
533 }
534
538 void setOpaqueInt128(unsigned index, std::optional<OpaqueInt128> optValue)
539 {
540 if (!optValue.has_value())
541 {
542 setNull(index);
543 return;
544 }
545
546 assert(isValid());
547
548 const auto& value = optValue.value();
549 const auto& descriptor = getInDescriptor(index);
550 const auto message = inMessage.data();
551
552 switch (descriptor.adjustedType)
553 {
554 case DescriptorAdjustedType::INT128:
555 *reinterpret_cast<OpaqueInt128*>(&message[descriptor.offset]) = value;
556 break;
557
558 default:
559 throwInvalidType("OpaqueInt128", descriptor.adjustedType);
560 }
561
562 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
563 }
564
565#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
569 void setBoostInt128(unsigned index, std::optional<BoostInt128> optValue)
570 {
571 if (!optValue.has_value())
572 {
573 setNull(index);
574 return;
575 }
576
577 setNumber(index, DescriptorAdjustedType::INT128, optValue.value(), 0, "BoostInt128");
578 }
579
583 void setScaledBoostInt128(unsigned index, std::optional<ScaledBoostInt128> optValue)
584 {
585 if (!optValue.has_value())
586 {
587 setNull(index);
588 return;
589 }
590
591 const auto& value = optValue.value();
592 setNumber(index, DescriptorAdjustedType::INT128, value.value, value.scale, "ScaledBoostInt128");
593 }
594#endif
595
599 void setFloat(unsigned index, std::optional<float> optValue)
600 {
601 if (!optValue.has_value())
602 {
603 setNull(index);
604 return;
605 }
606
607 setNumber(index, DescriptorAdjustedType::FLOAT, optValue.value(), 0, "float");
608 }
609
613 void setDouble(unsigned index, std::optional<double> optValue)
614 {
615 if (!optValue.has_value())
616 {
617 setNull(index);
618 return;
619 }
620
621 setNumber(index, DescriptorAdjustedType::DOUBLE, optValue.value(), 0, "double");
622 }
623
627 void setOpaqueDecFloat16(unsigned index, std::optional<OpaqueDecFloat16> optValue)
628 {
629 if (!optValue.has_value())
630 {
631 setNull(index);
632 return;
633 }
634
635 assert(isValid());
636
637 const auto& value = optValue.value();
638 const auto& descriptor = getInDescriptor(index);
639 const auto message = inMessage.data();
640
641 switch (descriptor.adjustedType)
642 {
643 case DescriptorAdjustedType::DECFLOAT16:
644 *reinterpret_cast<OpaqueDecFloat16*>(&message[descriptor.offset]) = value;
645 break;
646
647 default:
648 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
649 }
650
651 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
652 }
653
654#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
658 void setBoostDecFloat16(unsigned index, std::optional<BoostDecFloat16> optValue)
659 {
660 if (!optValue.has_value())
661 {
662 setNull(index);
663 return;
664 }
665
666 setNumber(index, DescriptorAdjustedType::DECFLOAT16, optValue.value(), 0, "BoostDecFloat16");
667 }
668#endif
669
673 void setOpaqueDecFloat34(unsigned index, std::optional<OpaqueDecFloat34> optValue)
674 {
675 if (!optValue.has_value())
676 {
677 setNull(index);
678 return;
679 }
680
681 assert(isValid());
682
683 const auto& value = optValue.value();
684 const auto& descriptor = getInDescriptor(index);
685 const auto message = inMessage.data();
686
687 switch (descriptor.adjustedType)
688 {
689 case DescriptorAdjustedType::DECFLOAT34:
690 *reinterpret_cast<OpaqueDecFloat34*>(&message[descriptor.offset]) = value;
691 break;
692
693 default:
694 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
695 }
696
697 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
698 }
699
700#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
704 void setBoostDecFloat34(unsigned index, std::optional<BoostDecFloat34> optValue)
705 {
706 if (!optValue.has_value())
707 {
708 setNull(index);
709 return;
710 }
711
712 setNumber(index, DescriptorAdjustedType::DECFLOAT34, optValue.value(), 0, "BoostDecFloat34");
713 }
714#endif
715
719 void setDate(unsigned index, std::optional<Date> optValue)
720 {
721 if (!optValue.has_value())
722 {
723 setNull(index);
724 return;
725 }
726
727 assert(isValid());
728
729 const auto& value = optValue.value();
730 const auto& descriptor = getInDescriptor(index);
731 const auto message = inMessage.data();
732
733 switch (descriptor.adjustedType)
734 {
735 case DescriptorAdjustedType::DATE:
736 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) =
737 calendarConverter.dateToOpaqueDate(value);
738 break;
739
740 default:
741 throwInvalidType("Date", descriptor.adjustedType);
742 }
743
744 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
745 }
746
750 void setOpaqueDate(unsigned index, std::optional<OpaqueDate> optValue)
751 {
752 if (!optValue.has_value())
753 {
754 setNull(index);
755 return;
756 }
757
758 assert(isValid());
759
760 const auto& value = optValue.value();
761 const auto& descriptor = getInDescriptor(index);
762 const auto message = inMessage.data();
763
764 switch (descriptor.adjustedType)
765 {
766 case DescriptorAdjustedType::DATE:
767 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) = value;
768 break;
769
770 default:
771 throwInvalidType("OpaqueDate", descriptor.adjustedType);
772 }
773
774 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
775 }
776
780 void setTime(unsigned index, std::optional<Time> optValue)
781 {
782 if (!optValue.has_value())
783 {
784 setNull(index);
785 return;
786 }
787
788 assert(isValid());
789
790 const auto& value = optValue.value();
791 const auto& descriptor = getInDescriptor(index);
792 const auto message = inMessage.data();
793
794 switch (descriptor.adjustedType)
795 {
796 case DescriptorAdjustedType::TIME:
797 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) =
798 calendarConverter.timeToOpaqueTime(value);
799 break;
800
801 default:
802 throwInvalidType("Time", descriptor.adjustedType);
803 }
804
805 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
806 }
807
811 void setOpaqueTime(unsigned index, std::optional<OpaqueTime> optValue)
812 {
813 if (!optValue.has_value())
814 {
815 setNull(index);
816 return;
817 }
818
819 assert(isValid());
820
821 const auto& value = optValue.value();
822 const auto& descriptor = getInDescriptor(index);
823 const auto message = inMessage.data();
824
825 switch (descriptor.adjustedType)
826 {
827 case DescriptorAdjustedType::TIME:
828 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) = value;
829 break;
830
831 default:
832 throwInvalidType("OpaqueTime", descriptor.adjustedType);
833 }
834
835 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
836 }
837
841 void setTimestamp(unsigned index, std::optional<Timestamp> optValue)
842 {
843 if (!optValue.has_value())
844 {
845 setNull(index);
846 return;
847 }
848
849 assert(isValid());
850
851 const auto& value = optValue.value();
852 const auto& descriptor = getInDescriptor(index);
853 const auto message = inMessage.data();
854
855 switch (descriptor.adjustedType)
856 {
857 case DescriptorAdjustedType::TIMESTAMP:
858 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) =
859 calendarConverter.timestampToOpaqueTimestamp(value);
860 break;
861
862 default:
863 throwInvalidType("Timestamp", descriptor.adjustedType);
864 }
865
866 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
867 }
868
872 void setOpaqueTimestamp(unsigned index, std::optional<OpaqueTimestamp> optValue)
873 {
874 if (!optValue.has_value())
875 {
876 setNull(index);
877 return;
878 }
879
880 assert(isValid());
881
882 const auto& value = optValue.value();
883 const auto& descriptor = getInDescriptor(index);
884 const auto message = inMessage.data();
885
886 switch (descriptor.adjustedType)
887 {
888 case DescriptorAdjustedType::TIMESTAMP:
889 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) = value;
890 break;
891
892 default:
893 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
894 }
895
896 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
897 }
898
902 void setTimeTz(unsigned index, std::optional<TimeTz> optValue)
903 {
904 if (!optValue.has_value())
905 {
906 setNull(index);
907 return;
908 }
909
910 assert(isValid());
911
912 const auto& value = optValue.value();
913 const auto& descriptor = getInDescriptor(index);
914 auto* const message = inMessage.data();
915
916 switch (descriptor.adjustedType)
917 {
918 case DescriptorAdjustedType::TIME_TZ:
919 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) =
920 calendarConverter.timeTzToOpaqueTimeTz(value);
921 break;
922
923 default:
924 throwInvalidType("TimeTz", descriptor.adjustedType);
925 }
926
927 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
928 }
929
933 void setOpaqueTimeTz(unsigned index, std::optional<OpaqueTimeTz> optValue)
934 {
935 if (!optValue.has_value())
936 {
937 setNull(index);
938 return;
939 }
940
941 assert(isValid());
942
943 const auto& value = optValue.value();
944 const auto& descriptor = getInDescriptor(index);
945 auto* const message = inMessage.data();
946
947 switch (descriptor.adjustedType)
948 {
949 case DescriptorAdjustedType::TIME_TZ:
950 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) = value;
951 break;
952
953 default:
954 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
955 }
956
957 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
958 }
959
963 void setTimestampTz(unsigned index, std::optional<TimestampTz> optValue)
964 {
965 if (!optValue.has_value())
966 {
967 setNull(index);
968 return;
969 }
970
971 assert(isValid());
972
973 const auto& value = optValue.value();
974 const auto& descriptor = getInDescriptor(index);
975 auto* const message = inMessage.data();
976
977 switch (descriptor.adjustedType)
978 {
979 case DescriptorAdjustedType::TIMESTAMP_TZ:
980 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) =
981 calendarConverter.timestampTzToOpaqueTimestampTz(value);
982 break;
983
984 default:
985 throwInvalidType("TimestampTz", descriptor.adjustedType);
986 }
987
988 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
989 }
990
994 void setOpaqueTimestampTz(unsigned index, std::optional<OpaqueTimestampTz> optValue)
995 {
996 if (!optValue.has_value())
997 {
998 setNull(index);
999 return;
1000 }
1001
1002 assert(isValid());
1003
1004 const auto& value = optValue.value();
1005 const auto& descriptor = getInDescriptor(index);
1006 auto* const message = inMessage.data();
1007
1008 switch (descriptor.adjustedType)
1009 {
1010 case DescriptorAdjustedType::TIMESTAMP_TZ:
1011 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) = value;
1012 break;
1013
1014 default:
1015 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
1016 }
1017
1018 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1019 }
1020
1024 void setString(unsigned index, std::optional<std::string_view> optValue)
1025 {
1026 if (!optValue.has_value())
1027 {
1028 setNull(index);
1029 return;
1030 }
1031
1032 assert(isValid());
1033
1034 const auto value = optValue.value();
1035 const auto& descriptor = getInDescriptor(index);
1036 const auto message = inMessage.data();
1037
1038 switch (descriptor.adjustedType)
1039 {
1040 case DescriptorAdjustedType::BOOLEAN:
1041 message[descriptor.offset] = numericConverter.stringToBoolean(value);
1042 break;
1043
1044 case DescriptorAdjustedType::INT16:
1045 case DescriptorAdjustedType::INT32:
1046 case DescriptorAdjustedType::INT64:
1047#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1048 case DescriptorAdjustedType::INT128:
1049#endif
1050 {
1051 std::string strValue(value);
1052 int scale = 0;
1053
1054 if (const auto dotPos = strValue.find_last_of('.'); dotPos != std::string_view::npos)
1055 {
1056 for (auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1057 {
1058 const char c = value[pos];
1059
1060 if (c < '0' || c > '9')
1061 break;
1062
1063 --scale;
1064 }
1065
1066 strValue.erase(dotPos, 1);
1067 }
1068
1069#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1070 const auto parseDecimalToBoostInt128 = [this](std::string_view text)
1071 {
1072 bool isNegative = false;
1073 std::size_t pos = 0;
1074
1075 if (!text.empty() && (text.front() == '+' || text.front() == '-'))
1076 {
1077 isNegative = text.front() == '-';
1078 ++pos;
1079 }
1080
1081 if (pos == text.size())
1082 this->numericConverter.throwConversionErrorFromString(std::string{text});
1083
1084 BoostInt128 result{};
1085
1086 for (; pos < text.size(); ++pos)
1087 {
1088 const char c = text[pos];
1089
1090 if (c < '0' || c > '9')
1091 this->numericConverter.throwConversionErrorFromString(std::string{text});
1092
1093 result *= 10;
1094 result += static_cast<int>(c - '0');
1095 }
1096
1097 return isNegative ? -result : result;
1098 };
1099
1100 auto scaledValue = ScaledBoostInt128{parseDecimalToBoostInt128(strValue), scale};
1101
1102 if (scale != descriptor.scale)
1103 {
1104 scaledValue.value = numericConverter.numberToNumber<BoostInt128>(scaledValue, descriptor.scale);
1105 scaledValue.scale = descriptor.scale;
1106 }
1107
1108 setScaledBoostInt128(index, scaledValue);
1109#else
1110 static_assert(sizeof(long long) == sizeof(std::int64_t));
1111 std::int64_t intValue;
1112 const auto convResult =
1113 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1114 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1115 numericConverter.throwConversionErrorFromString(strValue);
1116 auto scaledValue = ScaledInt64{intValue, scale};
1117
1118 if (scale != descriptor.scale)
1119 {
1120 scaledValue.value =
1121 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1122 scaledValue.scale = descriptor.scale;
1123 }
1124
1125 setScaledInt64(index, scaledValue);
1126#endif
1127 return;
1128 }
1129
1130 case DescriptorAdjustedType::FLOAT:
1131 case DescriptorAdjustedType::DOUBLE:
1132 {
1133 double doubleValue;
1134#if defined(__APPLE__)
1135 errno = 0;
1136 std::string valueString{value};
1137 char* parseEnd = nullptr;
1138 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1139 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1140 numericConverter.throwConversionErrorFromString(std::move(valueString));
1141#else
1142 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1143 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1144 numericConverter.throwConversionErrorFromString(std::string{value});
1145#endif
1146 setDouble(index, doubleValue);
1147 return;
1148 }
1149
1150 case DescriptorAdjustedType::DATE:
1151 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) =
1152 calendarConverter.stringToOpaqueDate(value);
1153 break;
1154
1155 case DescriptorAdjustedType::TIME:
1156 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) =
1157 calendarConverter.stringToOpaqueTime(value);
1158 break;
1159
1160 case DescriptorAdjustedType::TIMESTAMP:
1161 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) =
1162 calendarConverter.stringToOpaqueTimestamp(value);
1163 break;
1164
1165 case DescriptorAdjustedType::TIME_TZ:
1166 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) =
1167 calendarConverter.stringToOpaqueTimeTz(value);
1168 break;
1169
1170 case DescriptorAdjustedType::TIMESTAMP_TZ:
1171 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) =
1172 calendarConverter.stringToOpaqueTimestampTz(value);
1173 break;
1174#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1175 case DescriptorAdjustedType::DECFLOAT16:
1176 case DescriptorAdjustedType::DECFLOAT34:
1177 try
1178 {
1179 setBoostDecFloat34(index, BoostDecFloat34{value});
1180 }
1181 catch (...)
1182 {
1183 numericConverter.throwConversionErrorFromString(std::string{value});
1184 }
1185 return;
1186#endif
1187
1188 case DescriptorAdjustedType::STRING:
1189 if (value.length() > descriptor.length)
1190 {
1191 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1192 isc_arith_except,
1193 isc_string_truncation,
1194 isc_arg_end,
1195 };
1196
1197 throw DatabaseException(attachment.getClient(), STATUS_STRING_TRUNCATION);
1198 }
1199
1200 *reinterpret_cast<std::uint16_t*>(&message[descriptor.offset]) =
1201 static_cast<std::uint16_t>(value.length());
1202 std::copy(value.begin(), value.end(),
1203 reinterpret_cast<char*>(&message[descriptor.offset + sizeof(std::uint16_t)]));
1204 break;
1205
1206 default:
1207 throwInvalidType("std::string_view", descriptor.adjustedType);
1208 }
1209
1210 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1211 }
1212
1216 void setBlobId(unsigned index, std::optional<BlobId> optValue)
1217 {
1218 if (!optValue.has_value())
1219 {
1220 setNull(index);
1221 return;
1222 }
1223
1224 assert(isValid());
1225
1226 const auto& value = optValue.value();
1227 const auto& descriptor = getInDescriptor(index);
1228 auto* const message = inMessage.data();
1229
1230 switch (descriptor.adjustedType)
1231 {
1232 case DescriptorAdjustedType::BLOB:
1233 *reinterpret_cast<ISC_QUAD*>(&message[descriptor.offset]) = value.id;
1234 break;
1235
1236 default:
1237 throwInvalidType("BlobId", descriptor.adjustedType);
1238 }
1239
1240 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1241 }
1242
1245 void set(unsigned index, std::nullopt_t)
1246 {
1247 setNull(index);
1248 }
1249
1253 void set(unsigned index, BlobId value)
1254 {
1255 setBlobId(index, value);
1256 }
1257
1261 void set(unsigned index, std::optional<BlobId> value)
1262 {
1263 setBlobId(index, value);
1264 }
1265
1269 void set(unsigned index, bool value)
1270 {
1271 setBool(index, value);
1272 }
1273
1277 void set(unsigned index, std::int16_t value)
1278 {
1279 setInt16(index, value);
1280 }
1281
1285 void set(unsigned index, ScaledInt16 value)
1286 {
1287 setScaledInt16(index, value);
1288 }
1289
1293 void set(unsigned index, std::int32_t value)
1294 {
1295 setInt32(index, value);
1296 }
1297
1301 void set(unsigned index, ScaledInt32 value)
1302 {
1303 setScaledInt32(index, value);
1304 }
1305
1309 void set(unsigned index, std::int64_t value)
1310 {
1311 setInt64(index, value);
1312 }
1313
1317 void set(unsigned index, ScaledInt64 value)
1318 {
1319 setScaledInt64(index, value);
1320 }
1321
1325 void set(unsigned index, OpaqueInt128 value)
1326 {
1327 setOpaqueInt128(index, value);
1328 }
1329
1330#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1334 void set(unsigned index, BoostInt128 value)
1335 {
1336 setBoostInt128(index, value);
1337 }
1338
1342 void set(unsigned index, ScaledBoostInt128 value)
1343 {
1344 setScaledBoostInt128(index, value);
1345 }
1346#endif
1347
1351 void set(unsigned index, float value)
1352 {
1353 setFloat(index, value);
1354 }
1355
1359 void set(unsigned index, double value)
1360 {
1361 setDouble(index, value);
1362 }
1363
1367 void set(unsigned index, OpaqueDecFloat16 value)
1368 {
1369 setOpaqueDecFloat16(index, value);
1370 }
1371
1372#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1376 void set(unsigned index, BoostDecFloat16 value)
1377 {
1378 setBoostDecFloat16(index, value);
1379 }
1380#endif
1381
1385 void set(unsigned index, OpaqueDecFloat34 value)
1386 {
1387 setOpaqueDecFloat34(index, value);
1388 }
1389
1390#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1394 void set(unsigned index, BoostDecFloat34 value)
1395 {
1396 setBoostDecFloat34(index, value);
1397 }
1398#endif
1399
1403 void set(unsigned index, Date value)
1404 {
1405 setDate(index, value);
1406 }
1407
1411 void set(unsigned index, OpaqueDate value)
1412 {
1413 setOpaqueDate(index, value);
1414 }
1415
1419 void set(unsigned index, Time value)
1420 {
1421 setTime(index, value);
1422 }
1423
1427 void set(unsigned index, OpaqueTime value)
1428 {
1429 setOpaqueTime(index, value);
1430 }
1431
1435 void set(unsigned index, Timestamp value)
1436 {
1437 setTimestamp(index, value);
1438 }
1439
1443 void set(unsigned index, OpaqueTimestamp value)
1444 {
1445 setOpaqueTimestamp(index, value);
1446 }
1447
1451 void set(unsigned index, TimeTz value)
1452 {
1453 setTimeTz(index, value);
1454 }
1455
1459 void set(unsigned index, OpaqueTimeTz value)
1460 {
1461 setOpaqueTimeTz(index, value);
1462 }
1463
1467 void set(unsigned index, TimestampTz value)
1468 {
1469 setTimestampTz(index, value);
1470 }
1471
1475 void set(unsigned index, OpaqueTimestampTz value)
1476 {
1477 setOpaqueTimestampTz(index, value);
1478 }
1479
1483 void set(unsigned index, std::string_view value)
1484 {
1485 setString(index, value);
1486 }
1487
1491 template <typename T>
1492 void set(unsigned index, std::optional<T> value)
1493 {
1494 if (value.has_value())
1495 set(index, value.value());
1496 else
1497 setNull(index);
1498 }
1499
1503
1507
1511 bool isNull(unsigned index)
1512 {
1513 assert(isValid());
1514
1515 const auto& descriptor = getOutDescriptor(index);
1516 const auto* const message = outMessage.data();
1517
1518 return *reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE;
1519 }
1520
1524 std::optional<bool> getBool(unsigned index)
1525 {
1526 assert(isValid());
1527
1528 const auto& descriptor = getOutDescriptor(index);
1529 const auto* const message = outMessage.data();
1530
1531 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1532 return std::nullopt;
1533
1534 switch (descriptor.adjustedType)
1535 {
1536 case DescriptorAdjustedType::BOOLEAN:
1537 return message[descriptor.offset] != std::byte{0};
1538
1539 default:
1540 throwInvalidType("bool", descriptor.adjustedType);
1541 }
1542 }
1543
1547 std::optional<std::int16_t> getInt16(unsigned index)
1548 {
1549 std::optional<int> scale{0};
1550 return getNumber<std::int16_t>(index, scale, "std::int16_t");
1551 }
1552
1556 std::optional<ScaledInt16> getScaledInt16(unsigned index)
1557 {
1558 std::optional<int> scale;
1559 const auto value = getNumber<std::int16_t>(index, scale, "ScaledInt16");
1560 return value.has_value() ? std::optional{ScaledInt16{value.value(), scale.value()}} : std::nullopt;
1561 }
1562
1566 std::optional<std::int32_t> getInt32(unsigned index)
1567 {
1568 std::optional<int> scale{0};
1569 return getNumber<std::int32_t>(index, scale, "std::int32_t");
1570 }
1571
1575 std::optional<ScaledInt32> getScaledInt32(unsigned index)
1576 {
1577 std::optional<int> scale;
1578 const auto value = getNumber<std::int32_t>(index, scale, "ScaledInt32");
1579 return value.has_value() ? std::optional{ScaledInt32{value.value(), scale.value()}} : std::nullopt;
1580 }
1581
1585 std::optional<std::int64_t> getInt64(unsigned index)
1586 {
1587 std::optional<int> scale{0};
1588 return getNumber<std::int64_t>(index, scale, "std::int64_t");
1589 }
1590
1594 std::optional<ScaledInt64> getScaledInt64(unsigned index)
1595 {
1596 std::optional<int> scale;
1597 const auto value = getNumber<std::int64_t>(index, scale, "ScaledInt64");
1598 return value.has_value() ? std::optional{ScaledInt64{value.value(), scale.value()}} : std::nullopt;
1599 }
1600
1604 std::optional<ScaledOpaqueInt128> getScaledOpaqueInt128(unsigned index)
1605 {
1606 assert(isValid());
1607
1608 const auto& descriptor = getOutDescriptor(index);
1609 const auto* const message = outMessage.data();
1610
1611 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1612 return std::nullopt;
1613
1614 switch (descriptor.adjustedType)
1615 {
1616 case DescriptorAdjustedType::INT128:
1617 return ScaledOpaqueInt128{
1618 OpaqueInt128{*reinterpret_cast<const OpaqueInt128*>(&message[descriptor.offset])},
1619 descriptor.scale};
1620
1621 default:
1622 throwInvalidType("OpaqueInt128", descriptor.adjustedType);
1623 }
1624 }
1625
1626#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1630 std::optional<BoostInt128> getBoostInt128(unsigned index)
1631 {
1632 std::optional<int> scale{0};
1633 const auto value = getNumber<BoostInt128>(index, scale, "BoostInt128");
1634 return value.has_value() ? std::optional{value.value()} : std::nullopt;
1635 }
1636
1640 std::optional<ScaledBoostInt128> getScaledBoostInt128(unsigned index)
1641 {
1642 std::optional<int> scale;
1643 const auto value = getNumber<BoostInt128>(index, scale, "ScaledBoostInt128");
1644 return value.has_value() ? std::optional{ScaledBoostInt128{value.value(), scale.value()}} : std::nullopt;
1645 }
1646#endif
1647
1651 std::optional<float> getFloat(unsigned index)
1652 {
1653 std::optional<int> scale{0};
1654 return getNumber<float>(index, scale, "float");
1655 }
1656
1660 std::optional<double> getDouble(unsigned index)
1661 {
1662 std::optional<int> scale{0};
1663 return getNumber<double>(index, scale, "double");
1664 }
1665
1669 std::optional<OpaqueDecFloat16> getOpaqueDecFloat16(unsigned index)
1670 {
1671 assert(isValid());
1672
1673 const auto& descriptor = getOutDescriptor(index);
1674 const auto* const message = outMessage.data();
1675
1676 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1677 return std::nullopt;
1678
1679 switch (descriptor.adjustedType)
1680 {
1681 case DescriptorAdjustedType::DECFLOAT16:
1682 return OpaqueDecFloat16{*reinterpret_cast<const OpaqueDecFloat16*>(&message[descriptor.offset])};
1683
1684 default:
1685 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
1686 }
1687 }
1688
1689#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1693 std::optional<BoostDecFloat16> getBoostDecFloat16(unsigned index)
1694 {
1695 std::optional<int> scale{0};
1696 return getNumber<BoostDecFloat16>(index, scale, "BoostDecFloat16");
1697 }
1698#endif
1699
1703 std::optional<OpaqueDecFloat34> getOpaqueDecFloat34(unsigned index)
1704 {
1705 assert(isValid());
1706
1707 const auto& descriptor = getOutDescriptor(index);
1708 const auto* const message = outMessage.data();
1709
1710 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1711 return std::nullopt;
1712
1713 switch (descriptor.adjustedType)
1714 {
1715 case DescriptorAdjustedType::DECFLOAT34:
1716 return OpaqueDecFloat34{*reinterpret_cast<const OpaqueDecFloat34*>(&message[descriptor.offset])};
1717
1718 default:
1719 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
1720 }
1721 }
1722
1723#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1727 std::optional<BoostDecFloat34> getBoostDecFloat34(unsigned index)
1728 {
1729 std::optional<int> scale{0};
1730 return getNumber<BoostDecFloat34>(index, scale, "BoostDecFloat34");
1731 }
1732#endif
1733
1737 std::optional<Date> getDate(unsigned index)
1738 {
1739 assert(isValid());
1740
1741 const auto& descriptor = getOutDescriptor(index);
1742 const auto* const message = outMessage.data();
1743
1744 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1745 return std::nullopt;
1746
1747 switch (descriptor.adjustedType)
1748 {
1749 case DescriptorAdjustedType::DATE:
1750 return calendarConverter.opaqueDateToDate(
1751 *reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset]));
1752
1753 default:
1754 throwInvalidType("Date", descriptor.adjustedType);
1755 }
1756 }
1757
1761 std::optional<OpaqueDate> getOpaqueDate(unsigned index)
1762 {
1763 assert(isValid());
1764
1765 const auto& descriptor = getOutDescriptor(index);
1766 const auto* const message = outMessage.data();
1767
1768 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1769 return std::nullopt;
1770
1771 switch (descriptor.adjustedType)
1772 {
1773 case DescriptorAdjustedType::DATE:
1774 return OpaqueDate{*reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset])};
1775
1776 default:
1777 throwInvalidType("OpaqueDate", descriptor.adjustedType);
1778 }
1779 }
1780
1784 std::optional<Time> getTime(unsigned index)
1785 {
1786 assert(isValid());
1787
1788 const auto& descriptor = getOutDescriptor(index);
1789 const auto* const message = outMessage.data();
1790
1791 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1792 return std::nullopt;
1793
1794 switch (descriptor.adjustedType)
1795 {
1796 case DescriptorAdjustedType::TIME:
1797 return calendarConverter.opaqueTimeToTime(
1798 *reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset]));
1799
1800 default:
1801 throwInvalidType("Time", descriptor.adjustedType);
1802 }
1803 }
1804
1808 std::optional<OpaqueTime> getOpaqueTime(unsigned index)
1809 {
1810 assert(isValid());
1811
1812 const auto& descriptor = getOutDescriptor(index);
1813 const auto* const message = outMessage.data();
1814
1815 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1816 return std::nullopt;
1817
1818 switch (descriptor.adjustedType)
1819 {
1820 case DescriptorAdjustedType::TIME:
1821 return OpaqueTime{*reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset])};
1822
1823 default:
1824 throwInvalidType("OpaqueTime", descriptor.adjustedType);
1825 }
1826 }
1827
1831 std::optional<Timestamp> getTimestamp(unsigned index)
1832 {
1833 assert(isValid());
1834
1835 const auto& descriptor = getOutDescriptor(index);
1836 const auto* const message = outMessage.data();
1837
1838 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1839 return std::nullopt;
1840
1841 switch (descriptor.adjustedType)
1842 {
1843 case DescriptorAdjustedType::TIMESTAMP:
1844 return calendarConverter.opaqueTimestampToTimestamp(
1845 *reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset]));
1846
1847 default:
1848 throwInvalidType("Timestamp", descriptor.adjustedType);
1849 }
1850 }
1851
1855 std::optional<OpaqueTimestamp> getOpaqueTimestamp(unsigned index)
1856 {
1857 assert(isValid());
1858
1859 const auto& descriptor = getOutDescriptor(index);
1860 const auto* const message = outMessage.data();
1861
1862 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1863 return std::nullopt;
1864
1865 switch (descriptor.adjustedType)
1866 {
1867 case DescriptorAdjustedType::TIMESTAMP:
1868 return OpaqueTimestamp{*reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset])};
1869
1870 default:
1871 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
1872 }
1873 }
1874
1878 std::optional<TimeTz> getTimeTz(unsigned index)
1879 {
1880 assert(isValid());
1881
1882 const auto& descriptor = getOutDescriptor(index);
1883 const auto* const message = outMessage.data();
1884
1885 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1886 return std::nullopt;
1887
1888 switch (descriptor.adjustedType)
1889 {
1890 case DescriptorAdjustedType::TIME_TZ:
1891 return calendarConverter.opaqueTimeTzToTimeTz(
1892 *reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset]));
1893
1894 default:
1895 throwInvalidType("TimeTz", descriptor.adjustedType);
1896 }
1897 }
1898
1902 std::optional<OpaqueTimeTz> getOpaqueTimeTz(unsigned index)
1903 {
1904 assert(isValid());
1905
1906 const auto& descriptor = getOutDescriptor(index);
1907 const auto* const message = outMessage.data();
1908
1909 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1910 return std::nullopt;
1911
1912 switch (descriptor.adjustedType)
1913 {
1914 case DescriptorAdjustedType::TIME_TZ:
1915 return OpaqueTimeTz{*reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset])};
1916
1917 default:
1918 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
1919 }
1920 }
1921
1925 std::optional<TimestampTz> getTimestampTz(unsigned index)
1926 {
1927 assert(isValid());
1928
1929 const auto& descriptor = getOutDescriptor(index);
1930 const auto* const message = outMessage.data();
1931
1932 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1933 return std::nullopt;
1934
1935 switch (descriptor.adjustedType)
1936 {
1937 case DescriptorAdjustedType::TIMESTAMP_TZ:
1938 return calendarConverter.opaqueTimestampTzToTimestampTz(
1939 *reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset]));
1940
1941 default:
1942 throwInvalidType("TimestampTz", descriptor.adjustedType);
1943 }
1944 }
1945
1949 std::optional<OpaqueTimestampTz> getOpaqueTimestampTz(unsigned index)
1950 {
1951 assert(isValid());
1952
1953 const auto& descriptor = getOutDescriptor(index);
1954 const auto* const message = outMessage.data();
1955
1956 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1957 return std::nullopt;
1958
1959 switch (descriptor.adjustedType)
1960 {
1961 case DescriptorAdjustedType::TIMESTAMP_TZ:
1962 return OpaqueTimestampTz{*reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset])};
1963
1964 default:
1965 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
1966 }
1967 }
1968
1972 std::optional<BlobId> getBlobId(unsigned index)
1973 {
1974 assert(isValid());
1975
1976 const auto& descriptor = getOutDescriptor(index);
1977 const auto* const message = outMessage.data();
1978
1979 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1980 return std::nullopt;
1981
1982 switch (descriptor.adjustedType)
1983 {
1984 case DescriptorAdjustedType::BLOB:
1985 {
1986 BlobId value;
1987 value.id = *reinterpret_cast<const ISC_QUAD*>(&message[descriptor.offset]);
1988 return value;
1989 }
1990
1991 default:
1992 throwInvalidType("BlobId", descriptor.adjustedType);
1993 }
1994 }
1995
1999 std::optional<std::string> getString(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 const auto data = &message[descriptor.offset];
2010
2011 switch (descriptor.adjustedType)
2012 {
2013 case DescriptorAdjustedType::BOOLEAN:
2014 return (message[descriptor.offset] != std::byte{0}) ? std::string{"true"} : std::string{"false"};
2015
2016 case DescriptorAdjustedType::INT16:
2017 return numericConverter.numberToString(
2018 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale});
2019
2020 case DescriptorAdjustedType::INT32:
2021 return numericConverter.numberToString(
2022 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale});
2023
2024 case DescriptorAdjustedType::INT64:
2025 return numericConverter.numberToString(
2026 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale});
2027
2028#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2029 case DescriptorAdjustedType::INT128:
2030 return numericConverter.numberToString(ScaledBoostInt128{
2031 numericConverter.opaqueInt128ToBoostInt128(*reinterpret_cast<const OpaqueInt128*>(data)),
2032 descriptor.scale});
2033#endif
2034
2035 case DescriptorAdjustedType::FLOAT:
2036 return numericConverter.numberToString(*reinterpret_cast<const float*>(data));
2037
2038 case DescriptorAdjustedType::DOUBLE:
2039 return numericConverter.numberToString(*reinterpret_cast<const double*>(data));
2040
2041 case DescriptorAdjustedType::DATE:
2042 return calendarConverter.opaqueDateToString(*reinterpret_cast<const OpaqueDate*>(data));
2043
2044 case DescriptorAdjustedType::TIME:
2045 return calendarConverter.opaqueTimeToString(*reinterpret_cast<const OpaqueTime*>(data));
2046
2047 case DescriptorAdjustedType::TIMESTAMP:
2048 return calendarConverter.opaqueTimestampToString(*reinterpret_cast<const OpaqueTimestamp*>(data));
2049
2050 case DescriptorAdjustedType::TIME_TZ:
2051 return calendarConverter.opaqueTimeTzToString(*reinterpret_cast<const OpaqueTimeTz*>(data));
2052
2053 case DescriptorAdjustedType::TIMESTAMP_TZ:
2054 return calendarConverter.opaqueTimestampTzToString(
2055 *reinterpret_cast<const OpaqueTimestampTz*>(data));
2056
2057#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2058 case DescriptorAdjustedType::DECFLOAT16:
2059 return numericConverter.numberToString(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
2060 *reinterpret_cast<const OpaqueDecFloat16*>(data)));
2061
2062 case DescriptorAdjustedType::DECFLOAT34:
2063 return numericConverter.numberToString(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
2064 *reinterpret_cast<const OpaqueDecFloat34*>(data)));
2065#endif
2066
2067 case DescriptorAdjustedType::STRING:
2068 return std::string{reinterpret_cast<const char*>(data + sizeof(std::uint16_t)),
2069 *reinterpret_cast<const std::uint16_t*>(data)};
2070
2071 default:
2072 throwInvalidType("std::string", descriptor.adjustedType);
2073 }
2074 }
2075
2079
2083 template <typename T>
2084 T get(unsigned index);
2085
2086 private:
2090 const Descriptor& getInDescriptor(unsigned index)
2091 {
2092 if (index >= inDescriptors.size())
2093 throw std::out_of_range("index out of range");
2094
2095 return inDescriptors[index];
2096 }
2097
2101 const Descriptor& getOutDescriptor(unsigned index)
2102 {
2103 if (index >= outDescriptors.size())
2104 throw std::out_of_range("index out of range");
2105
2106 return outDescriptors[index];
2107 }
2108
2112 template <typename T>
2113 void setNumber(unsigned index, DescriptorAdjustedType valueType, T value, int scale, const char* typeName)
2114 {
2115 assert(isValid());
2116
2117 const auto& descriptor = getInDescriptor(index);
2118 auto* const message = inMessage.data();
2119
2120 const auto descriptorData = &message[descriptor.offset];
2121 std::optional<int> descriptorScale{descriptor.scale};
2122
2123 Descriptor valueDescriptor;
2124 valueDescriptor.adjustedType = valueType;
2125 valueDescriptor.scale = scale;
2126
2127 const auto valueAddress = reinterpret_cast<const std::byte*>(&value);
2128
2129 switch (descriptor.adjustedType)
2130 {
2131 case DescriptorAdjustedType::INT16:
2132 *reinterpret_cast<std::int16_t*>(descriptorData) =
2133 convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale, "std::int16_t");
2134 break;
2135
2136 case DescriptorAdjustedType::INT32:
2137 *reinterpret_cast<std::int32_t*>(descriptorData) =
2138 convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale, "std::int32_t");
2139 break;
2140
2141 case DescriptorAdjustedType::INT64:
2142 *reinterpret_cast<std::int64_t*>(descriptorData) =
2143 convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale, "std::int64_t");
2144 break;
2145
2146#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2147 case DescriptorAdjustedType::INT128:
2148 {
2149 const auto boostInt128 =
2150 convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale, "BoostInt128");
2151 *reinterpret_cast<OpaqueInt128*>(descriptorData) =
2152 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
2153 break;
2154 }
2155#endif
2156
2157 case DescriptorAdjustedType::FLOAT:
2158 *reinterpret_cast<float*>(descriptorData) =
2159 convertNumber<float>(valueDescriptor, valueAddress, descriptorScale, "float");
2160 break;
2161
2162 case DescriptorAdjustedType::DOUBLE:
2163 *reinterpret_cast<double*>(descriptorData) =
2164 convertNumber<double>(valueDescriptor, valueAddress, descriptorScale, "double");
2165 break;
2166
2167#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2168 case DescriptorAdjustedType::DECFLOAT16:
2169 {
2170 const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
2171 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat16");
2172 *reinterpret_cast<OpaqueDecFloat16*>(descriptorData) =
2173 numericConverter.boostDecFloat16ToOpaqueDecFloat16(boostDecFloat16);
2174 break;
2175 }
2176
2177 case DescriptorAdjustedType::DECFLOAT34:
2178 {
2179 const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
2180 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat34");
2181 *reinterpret_cast<OpaqueDecFloat34*>(descriptorData) =
2182 numericConverter.boostDecFloat34ToOpaqueDecFloat34(boostDecFloat34);
2183 break;
2184 }
2185#endif
2186
2187 default:
2188 throwInvalidType(typeName, descriptor.adjustedType);
2189 }
2190
2191 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
2192 }
2193
2194 // FIXME: floating to integral
2198 template <typename T>
2199 std::optional<T> getNumber(unsigned index, std::optional<int>& scale, const char* typeName)
2200 {
2201 assert(isValid());
2202
2203 const auto& descriptor = getOutDescriptor(index);
2204 const auto* const message = outMessage.data();
2205
2206 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2207 return std::nullopt;
2208
2209 auto data = &message[descriptor.offset];
2210 std::optional<BoostInt128> boostInt128;
2211 std::optional<BoostDecFloat16> boostDecFloat16;
2212 std::optional<BoostDecFloat34> boostDecFloat34;
2213
2214 switch (descriptor.adjustedType)
2215 {
2216#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2217 case DescriptorAdjustedType::INT128:
2218 boostInt128.emplace(
2219 numericConverter.opaqueInt128ToBoostInt128(*reinterpret_cast<const OpaqueInt128*>(data)));
2220 data = reinterpret_cast<const std::byte*>(&boostInt128.value());
2221 break;
2222
2223 case DescriptorAdjustedType::DECFLOAT16:
2224 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
2225 *reinterpret_cast<const OpaqueDecFloat16*>(data)));
2226 data = reinterpret_cast<const std::byte*>(&boostDecFloat16.value());
2227 break;
2228
2229 case DescriptorAdjustedType::DECFLOAT34:
2230 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
2231 *reinterpret_cast<const OpaqueDecFloat34*>(data)));
2232 data = reinterpret_cast<const std::byte*>(&boostDecFloat34.value());
2233 break;
2234#endif
2235
2236 default:
2237 break;
2238 }
2239
2240 return convertNumber<T>(descriptor, data, scale, typeName);
2241 }
2242
2243 [[noreturn]] static void throwInvalidType(const char* actualType, DescriptorAdjustedType descriptorType)
2244 {
2245 throw FbCppException("Invalid type: actual type " + std::string(actualType) + ", descriptor type " +
2246 std::to_string(static_cast<unsigned>(descriptorType)));
2247 }
2248
2249 template <typename T>
2250 T convertNumber(
2251 const Descriptor& descriptor, const std::byte* data, std::optional<int>& toScale, const char* toTypeName)
2252 {
2253 if (!toScale.has_value())
2254 {
2255 switch (descriptor.adjustedType)
2256 {
2257 case DescriptorAdjustedType::DECFLOAT16:
2258 case DescriptorAdjustedType::DECFLOAT34:
2259 case DescriptorAdjustedType::FLOAT:
2260 case DescriptorAdjustedType::DOUBLE:
2261 throwInvalidType(toTypeName, descriptor.adjustedType);
2262
2263 default:
2264 break;
2265 }
2266
2267 toScale = descriptor.scale;
2268 }
2269
2270 switch (descriptor.adjustedType)
2271 {
2272 case DescriptorAdjustedType::INT16:
2273 return numericConverter.numberToNumber<T>(
2274 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale}, toScale.value());
2275 break;
2276
2277 case DescriptorAdjustedType::INT32:
2278 return numericConverter.numberToNumber<T>(
2279 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale}, toScale.value());
2280
2281 case DescriptorAdjustedType::INT64:
2282 return numericConverter.numberToNumber<T>(
2283 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale}, toScale.value());
2284
2285#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2286 case DescriptorAdjustedType::INT128:
2287 return numericConverter.numberToNumber<T>(
2288 ScaledBoostInt128{*reinterpret_cast<const BoostInt128*>(data), descriptor.scale},
2289 toScale.value());
2290
2291 case DescriptorAdjustedType::DECFLOAT16:
2292 return numericConverter.numberToNumber<T>(
2293 *reinterpret_cast<const BoostDecFloat16*>(data), toScale.value());
2294
2295 case DescriptorAdjustedType::DECFLOAT34:
2296 return numericConverter.numberToNumber<T>(
2297 *reinterpret_cast<const BoostDecFloat34*>(data), toScale.value());
2298#endif
2299
2300 case DescriptorAdjustedType::FLOAT:
2301 return numericConverter.numberToNumber<T>(*reinterpret_cast<const float*>(data), toScale.value());
2302 break;
2303
2304 case DescriptorAdjustedType::DOUBLE:
2305 return numericConverter.numberToNumber<T>(*reinterpret_cast<const double*>(data), toScale.value());
2306 break;
2307
2308 default:
2309 throwInvalidType(toTypeName, descriptor.adjustedType);
2310 }
2311 }
2312
2313 private:
2314 Attachment& attachment;
2315 FbUniquePtr<Firebird::IStatus> status;
2316 impl::StatusWrapper statusWrapper;
2317 impl::CalendarConverter calendarConverter;
2318 impl::NumericConverter numericConverter;
2319 FbRef<fb::IStatement> statementHandle;
2320 FbRef<fb::IResultSet> resultSetHandle;
2321 FbRef<fb::IMessageMetadata> inMetadata;
2322 std::vector<Descriptor> inDescriptors;
2323 std::vector<std::byte> inMessage;
2324 FbRef<fb::IMessageMetadata> outMetadata;
2325 std::vector<Descriptor> outDescriptors;
2326 std::vector<std::byte> outMessage;
2327 StatementType type;
2328 };
2329
2334
2335 template <>
2336 inline std::optional<bool> Statement::get<std::optional<bool>>(unsigned index)
2337 {
2338 return getBool(index);
2339 }
2340
2341 template <>
2342 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(unsigned index)
2343 {
2344 return getBlobId(index);
2345 }
2346
2347 template <>
2348 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(unsigned index)
2349 {
2350 return getInt16(index);
2351 }
2352
2353 template <>
2354 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(unsigned index)
2355 {
2356 return getScaledInt16(index);
2357 }
2358
2359 template <>
2360 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(unsigned index)
2361 {
2362 return getInt32(index);
2363 }
2364
2365 template <>
2366 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(unsigned index)
2367 {
2368 return getScaledInt32(index);
2369 }
2370
2371 template <>
2372 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(unsigned index)
2373 {
2374 return getInt64(index);
2375 }
2376
2377 template <>
2378 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(unsigned index)
2379 {
2380 return getScaledInt64(index);
2381 }
2382
2383 template <>
2384 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(unsigned index)
2385 {
2386 return getScaledOpaqueInt128(index);
2387 }
2388
2389#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2390 template <>
2391 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(unsigned index)
2392 {
2393 return getBoostInt128(index);
2394 }
2395
2396 template <>
2397 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(unsigned index)
2398 {
2399 return getScaledBoostInt128(index);
2400 }
2401#endif
2402
2403 template <>
2404 inline std::optional<float> Statement::get<std::optional<float>>(unsigned index)
2405 {
2406 return getFloat(index);
2407 }
2408
2409 template <>
2410 inline std::optional<double> Statement::get<std::optional<double>>(unsigned index)
2411 {
2412 return getDouble(index);
2413 }
2414
2415 template <>
2416 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(unsigned index)
2417 {
2418 return getOpaqueDecFloat16(index);
2419 }
2420
2421#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2422 template <>
2423 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(unsigned index)
2424 {
2425 return getBoostDecFloat16(index);
2426 }
2427#endif
2428
2429 template <>
2430 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(unsigned index)
2431 {
2432 return getOpaqueDecFloat34(index);
2433 }
2434
2435#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2436 template <>
2437 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(unsigned index)
2438 {
2439 return getBoostDecFloat34(index);
2440 }
2441#endif
2442
2443 template <>
2444 inline std::optional<Date> Statement::get<std::optional<Date>>(unsigned index)
2445 {
2446 return getDate(index);
2447 }
2448
2449 template <>
2450 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(unsigned index)
2451 {
2452 return getOpaqueDate(index);
2453 }
2454
2455 template <>
2456 inline std::optional<Time> Statement::get<std::optional<Time>>(unsigned index)
2457 {
2458 return getTime(index);
2459 }
2460
2461 template <>
2462 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(unsigned index)
2463 {
2464 return getOpaqueTime(index);
2465 }
2466
2467 template <>
2468 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(unsigned index)
2469 {
2470 return getOpaqueTimestamp(index);
2471 }
2472
2473 template <>
2474 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(unsigned index)
2475 {
2476 return getTimestamp(index);
2477 }
2478
2479 template <>
2480 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(unsigned index)
2481 {
2482 return getTimeTz(index);
2483 }
2484
2485 template <>
2486 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(unsigned index)
2487 {
2488 return getOpaqueTimeTz(index);
2489 }
2490
2491 template <>
2492 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(unsigned index)
2493 {
2494 return getTimestampTz(index);
2495 }
2496
2497 template <>
2498 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(unsigned index)
2499 {
2500 return getOpaqueTimestampTz(index);
2501 }
2502
2503 template <>
2504 inline std::optional<std::string> Statement::get<std::optional<std::string>>(unsigned index)
2505 {
2506 return getString(index);
2507 }
2508
2512} // namespace fbcpp
2513
2514
2515#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:230
Represents a Firebird blob identifier.
Definition Blob.h:52
ISC_QUAD id
Stores the raw Firebird blob identifier value.
Definition Blob.h:64
Represents options used when preparing a Statement.
Definition Statement.h:71
StatementOptions & setPrefetchLegacyPlan(bool value)
Enables or disables prefetching of the legacy textual plan at prepare time.
Definition Statement.h:86
bool getPrefetchPlan() const
Reports whether the structured plan should be prefetched during prepare.
Definition Statement.h:95
StatementOptions & setPrefetchPlan(bool value)
Enables or disables prefetching of the structured plan at prepare time.
Definition Statement.h:105
bool getPrefetchLegacyPlan() const
Reports whether the legacy textual plan should be prefetched during prepare.
Definition Statement.h:76
Prepares, executes, and fetches SQL statements against a Firebird attachment.
Definition Statement.h:183
void set(unsigned index, OpaqueInt128 value)
Convenience overload that binds a Firebird 128-bit integer.
Definition Statement.h:1325
void setScaledInt16(unsigned index, std::optional< ScaledInt16 > optValue)
Binds a scaled 16-bit signed integer value or null.
Definition Statement.h:465
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:406
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:583
std::optional< OpaqueTime > getOpaqueTime(unsigned index)
Reads a raw time-of-day column in Firebird's representation.
Definition Statement.h:1808
std::optional< OpaqueDecFloat34 > getOpaqueDecFloat34(unsigned index)
Reads a Firebird 34-digit decimal floating-point column.
Definition Statement.h:1703
void setDate(unsigned index, std::optional< Date > optValue)
Binds a date value or null.
Definition Statement.h:719
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:308
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:316
bool isValid() noexcept
Returns whether the Statement object is valid.
Definition Statement.h:248
StatementType getType() noexcept
Returns the type classification reported by the server.
Definition Statement.h:290
void set(unsigned index, BoostDecFloat16 value)
Convenience overload that binds a Boost 16-digit decimal floating-point value.
Definition Statement.h:1376
std::optional< TimeTz > getTimeTz(unsigned index)
Reads a time-of-day column with timezone.
Definition Statement.h:1878
void setTime(unsigned index, std::optional< Time > optValue)
Binds a time-of-day value without timezone or null.
Definition Statement.h:780
void set(unsigned index, std::string_view value)
Convenience overload that binds a textual value.
Definition Statement.h:1483
std::optional< BoostDecFloat34 > getBoostDecFloat34(unsigned index)
Reads a Boost-based 34-digit decimal floating-point column.
Definition Statement.h:1727
void setBlobId(unsigned index, std::optional< BlobId > optValue)
Binds a blob identifier to the specified parameter or null.
Definition Statement.h:1216
void setInt16(unsigned index, std::optional< std::int16_t > optValue)
Binds a 16-bit signed integer value or null.
Definition Statement.h:451
void setString(unsigned index, std::optional< std::string_view > optValue)
Binds a textual parameter or null, performing direct conversions where supported.
Definition Statement.h:1024
void set(unsigned index, std::int32_t value)
Convenience overload that binds a 32-bit signed integer.
Definition Statement.h:1293
std::optional< Time > getTime(unsigned index)
Reads a time-of-day column without timezone.
Definition Statement.h:1784
std::optional< Date > getDate(unsigned index)
Reads a date column.
Definition Statement.h:1737
FbRef< fb::IResultSet > getResultSetHandle() noexcept
Provides access to the underlying Firebird currently open result set handle, if any.
Definition Statement.h:266
bool isNull(unsigned index)
Reports whether the most recently fetched row has a null at the given column.
Definition Statement.h:1511
void set(unsigned index, double value)
Convenience overload that binds a double precision floating-point value.
Definition Statement.h:1359
void clearParameters()
Marks all bound parameters as null values.
Definition Statement.h:392
void set(unsigned index, ScaledInt64 value)
Convenience overload that binds a scaled 64-bit signed integer.
Definition Statement.h:1317
std::optional< OpaqueDate > getOpaqueDate(unsigned index)
Reads a raw date column in Firebird's representation.
Definition Statement.h:1761
void setScaledInt32(unsigned index, std::optional< ScaledInt32 > optValue)
Binds a scaled 32-bit signed integer value or null.
Definition Statement.h:494
void set(unsigned index, std::int64_t value)
Convenience overload that binds a 64-bit signed integer.
Definition Statement.h:1309
void setTimestampTz(unsigned index, std::optional< TimestampTz > optValue)
Binds a timestamp value with timezone or null.
Definition Statement.h:963
std::optional< std::int64_t > getInt64(unsigned index)
Reads a 64-bit signed integer column.
Definition Statement.h:1585
FbRef< fb::IStatement > getStatementHandle() noexcept
Provides direct access to the underlying Firebird statement handle.
Definition Statement.h:257
std::optional< ScaledInt32 > getScaledInt32(unsigned index)
Reads a scaled 32-bit signed integer column.
Definition Statement.h:1575
void set(unsigned index, OpaqueTimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1475
void setOpaqueTime(unsigned index, std::optional< OpaqueTime > optValue)
Binds a raw time-of-day value in Firebird's representation or null.
Definition Statement.h:811
std::optional< float > getFloat(unsigned index)
Reads a single precision floating-point column.
Definition Statement.h:1651
std::optional< double > getDouble(unsigned index)
Reads a double precision floating-point column.
Definition Statement.h:1660
std::optional< OpaqueTimestampTz > getOpaqueTimestampTz(unsigned index)
Reads a raw timestamp-with-time-zone column in Firebird's representation.
Definition Statement.h:1949
std::optional< ScaledInt16 > getScaledInt16(unsigned index)
Reads a scaled 16-bit signed integer column.
Definition Statement.h:1556
std::optional< BlobId > getBlobId(unsigned index)
Reads a blob identifier column.
Definition Statement.h:1972
Statement(Statement &&o) noexcept
Transfers ownership of an existing prepared statement.
Definition Statement.h:198
void setInt64(unsigned index, std::optional< std::int64_t > optValue)
Binds a 64-bit signed integer value or null.
Definition Statement.h:509
std::optional< ScaledOpaqueInt128 > getScaledOpaqueInt128(unsigned index)
Reads a Firebird 128-bit integer column.
Definition Statement.h:1604
FbRef< fb::IMessageMetadata > getOutputMetadata() noexcept
Returns the metadata describing columns produced by the statement.
Definition Statement.h:282
void set(unsigned index, TimeTz value)
Convenience overload that binds a Firebird time with timezone value.
Definition Statement.h:1451
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:627
void setOpaqueInt128(unsigned index, std::optional< OpaqueInt128 > optValue)
Binds a raw 128-bit integer value in Firebird's representation or null.
Definition Statement.h:538
std::optional< OpaqueTimeTz > getOpaqueTimeTz(unsigned index)
Reads a raw time-of-day column with timezone in Firebird's representation.
Definition Statement.h:1902
void setBoostInt128(unsigned index, std::optional< BoostInt128 > optValue)
Binds a 128-bit integer value expressed with Boost.Multiprecision or null.
Definition Statement.h:569
void set(unsigned index, Date value)
Convenience overload that binds a Firebird date value.
Definition Statement.h:1403
void set(unsigned index, Timestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1435
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:933
void setTimestamp(unsigned index, std::optional< Timestamp > optValue)
Binds a timestamp value without timezone or null.
Definition Statement.h:841
std::optional< std::string > getString(unsigned index)
Reads a textual column, applying number-to-string conversions when needed.
Definition Statement.h:1999
std::optional< std::int32_t > getInt32(unsigned index)
Reads a 32-bit signed integer column.
Definition Statement.h:1566
void set(unsigned index, OpaqueDecFloat16 value)
Convenience overload that binds a Firebird 16-digit decimal floating-point value.
Definition Statement.h:1367
void setOpaqueTimestampTz(unsigned index, std::optional< OpaqueTimestampTz > optValue)
Binds a raw timestamp value with timezone in Firebird's representation or null.
Definition Statement.h:994
FbRef< fb::IMessageMetadata > getInputMetadata() noexcept
Returns the metadata describing prepared input parameters.
Definition Statement.h:274
~Statement() noexcept
Releases resources; ignores failures to keep destructor noexcept.
Definition Statement.h:223
void set(unsigned index, OpaqueTimeTz value)
Convenience overload that binds a Firebird time with timezone value.
Definition Statement.h:1459
void setBoostDecFloat16(unsigned index, std::optional< BoostDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value using Boost.Multiprecision or null.
Definition Statement.h:658
std::optional< ScaledBoostInt128 > getScaledBoostInt128(unsigned index)
Reads a scaled Boost 128-bit integer column.
Definition Statement.h:1640
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:1253
void set(unsigned index, BoostDecFloat34 value)
Convenience overload that binds a Boost 34-digit decimal floating-point value.
Definition Statement.h:1394
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:1385
void set(unsigned index, Time value)
Convenience overload that binds a Firebird time value.
Definition Statement.h:1419
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:1285
std::optional< BoostInt128 > getBoostInt128(unsigned index)
Reads a Boost 128-bit integer column.
Definition Statement.h:1630
std::optional< bool > getBool(unsigned index)
Reads a boolean column from the current row.
Definition Statement.h:1524
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:673
void set(unsigned index, OpaqueTimestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1443
void setInt32(unsigned index, std::optional< std::int32_t > optValue)
Binds a 32-bit signed integer value or null.
Definition Statement.h:480
void set(unsigned index, std::optional< BlobId > value)
Convenience overload that binds an optional blob identifier.
Definition Statement.h:1261
void setBool(unsigned index, std::optional< bool > optValue)
Binds a boolean parameter value or null.
Definition Statement.h:421
void set(unsigned index, TimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1467
void setDouble(unsigned index, std::optional< double > optValue)
Binds a double precision floating-point value or null.
Definition Statement.h:613
void set(unsigned index, OpaqueDate value)
Convenience overload that binds a Firebird date value.
Definition Statement.h:1411
void set(unsigned index, std::int16_t value)
Convenience overload that binds a 16-bit signed integer.
Definition Statement.h:1277
void set(unsigned index, std::optional< T > value)
Convenience template that forwards optional values to specialized overloads.
Definition Statement.h:1492
std::optional< OpaqueTimestamp > getOpaqueTimestamp(unsigned index)
Reads a raw timestamp column in Firebird's representation.
Definition Statement.h:1855
void setScaledInt64(unsigned index, std::optional< ScaledInt64 > optValue)
Binds a scaled 64-bit signed integer value or null.
Definition Statement.h:523
void set(unsigned index, std::nullopt_t)
Convenience overload that binds a null value.
Definition Statement.h:1245
void setFloat(unsigned index, std::optional< float > optValue)
Binds a single precision floating-point value or null.
Definition Statement.h:599
void setOpaqueDate(unsigned index, std::optional< OpaqueDate > optValue)
Binds a raw date value in Firebird's representation or null.
Definition Statement.h:750
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:1427
void set(unsigned index, ScaledInt32 value)
Convenience overload that binds a scaled 32-bit signed integer.
Definition Statement.h:1301
Statement(Attachment &attachment, Transaction &transaction, std::string_view sql, const StatementOptions &options={})
Prepares an SQL statement.
Definition Statement.cpp:34
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:1547
void set(unsigned index, ScaledBoostInt128 value)
Convenience overload that binds a scaled Boost-provided 128-bit integer.
Definition Statement.h:1342
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:1925
void set(unsigned index, BoostInt128 value)
Convenience overload that binds a Boost-provided 128-bit integer.
Definition Statement.h:1334
std::optional< OpaqueDecFloat16 > getOpaqueDecFloat16(unsigned index)
Reads a Firebird 16-digit decimal floating-point column.
Definition Statement.h:1669
std::optional< Timestamp > getTimestamp(unsigned index)
Reads a timestamp column without timezone.
Definition Statement.h:1831
std::optional< BoostDecFloat16 > getBoostDecFloat16(unsigned index)
Reads a Boost-based 16-digit decimal floating-point column.
Definition Statement.h:1693
void setTimeTz(unsigned index, std::optional< TimeTz > optValue)
Binds a time-of-day value with timezone or null.
Definition Statement.h:902
void setBoostDecFloat34(unsigned index, std::optional< BoostDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value using Boost.Multiprecision or null.
Definition Statement.h:704
std::optional< ScaledInt64 > getScaledInt64(unsigned index)
Reads a scaled 64-bit signed integer column.
Definition Statement.h:1594
void set(unsigned index, bool value)
Convenience overload that binds a boolean value.
Definition Statement.h:1269
void setOpaqueTimestamp(unsigned index, std::optional< OpaqueTimestamp > optValue)
Binds a raw timestamp value in Firebird's representation or null.
Definition Statement.h:872
void set(unsigned index, float value)
Convenience overload that binds a single precision floating-point value.
Definition Statement.h:1351
Represents a transaction in a Firebird database.
fb-cpp namespace.
Definition Attachment.h:42
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:67
StatementType
Distinguishes the semantic category of the prepared SQL statement.
Definition Statement.h:120
@ 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:93
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