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 {
1048 std::string strValue(value);
1049 int scale = 0;
1050
1051 if (const auto dotPos = strValue.find_last_of('.'); dotPos != std::string_view::npos)
1052 {
1053 for (auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1054 {
1055 const char c = value[pos];
1056
1057 if (c < '0' || c > '9')
1058 break;
1059
1060 --scale;
1061 }
1062
1063 strValue.erase(dotPos, 1);
1064 }
1065
1066 static_assert(sizeof(long long) == sizeof(std::int64_t));
1067 std::int64_t intValue;
1068 const auto convResult =
1069 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1070 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1071 numericConverter.throwConversionErrorFromString(strValue);
1072 auto scaledValue = ScaledInt64{intValue, scale};
1073
1074 if (scale != descriptor.scale)
1075 {
1076 scaledValue.value =
1077 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1078 scaledValue.scale = descriptor.scale;
1079 }
1080
1081 setScaledInt64(index, scaledValue);
1082 return;
1083 }
1084
1085 case DescriptorAdjustedType::INT128:
1086 {
1087 std::string strValue(value);
1088 attachment.getClient()
1089 .getInt128Util(&statusWrapper)
1090 ->fromString(&statusWrapper, descriptor.scale, strValue.c_str(),
1091 reinterpret_cast<OpaqueInt128*>(&message[descriptor.offset]));
1092 break;
1093 }
1094
1095 case DescriptorAdjustedType::FLOAT:
1096 case DescriptorAdjustedType::DOUBLE:
1097 {
1098 double doubleValue;
1099#if defined(__APPLE__)
1100 errno = 0;
1101 std::string valueString{value};
1102 char* parseEnd = nullptr;
1103 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1104 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1105 numericConverter.throwConversionErrorFromString(std::move(valueString));
1106#else
1107 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1108 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1109 numericConverter.throwConversionErrorFromString(std::string{value});
1110#endif
1111 setDouble(index, doubleValue);
1112 return;
1113 }
1114
1115 case DescriptorAdjustedType::DATE:
1116 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) =
1117 calendarConverter.stringToOpaqueDate(value);
1118 break;
1119
1120 case DescriptorAdjustedType::TIME:
1121 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) =
1122 calendarConverter.stringToOpaqueTime(value);
1123 break;
1124
1125 case DescriptorAdjustedType::TIMESTAMP:
1126 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) =
1127 calendarConverter.stringToOpaqueTimestamp(value);
1128 break;
1129
1130 case DescriptorAdjustedType::TIME_TZ:
1131 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) =
1132 calendarConverter.stringToOpaqueTimeTz(value);
1133 break;
1134
1135 case DescriptorAdjustedType::TIMESTAMP_TZ:
1136 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) =
1137 calendarConverter.stringToOpaqueTimestampTz(value);
1138 break;
1139#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1140 // FIXME: use IDecFloat
1141 case DescriptorAdjustedType::DECFLOAT16:
1142 case DescriptorAdjustedType::DECFLOAT34:
1143 try
1144 {
1145 setBoostDecFloat34(index, BoostDecFloat34{value});
1146 }
1147 catch (...)
1148 {
1149 numericConverter.throwConversionErrorFromString(std::string{value});
1150 }
1151 return;
1152#endif
1153
1154 case DescriptorAdjustedType::STRING:
1155 if (value.length() > descriptor.length)
1156 {
1157 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1158 isc_arith_except,
1159 isc_string_truncation,
1160 isc_arg_end,
1161 };
1162
1163 throw DatabaseException(attachment.getClient(), STATUS_STRING_TRUNCATION);
1164 }
1165
1166 *reinterpret_cast<std::uint16_t*>(&message[descriptor.offset]) =
1167 static_cast<std::uint16_t>(value.length());
1168 std::copy(value.begin(), value.end(),
1169 reinterpret_cast<char*>(&message[descriptor.offset + sizeof(std::uint16_t)]));
1170 break;
1171
1172 default:
1173 throwInvalidType("std::string_view", descriptor.adjustedType);
1174 }
1175
1176 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1177 }
1178
1182 void setBlobId(unsigned index, std::optional<BlobId> optValue)
1183 {
1184 if (!optValue.has_value())
1185 {
1186 setNull(index);
1187 return;
1188 }
1189
1190 assert(isValid());
1191
1192 const auto& value = optValue.value();
1193 const auto& descriptor = getInDescriptor(index);
1194 auto* const message = inMessage.data();
1195
1196 switch (descriptor.adjustedType)
1197 {
1198 case DescriptorAdjustedType::BLOB:
1199 *reinterpret_cast<ISC_QUAD*>(&message[descriptor.offset]) = value.id;
1200 break;
1201
1202 default:
1203 throwInvalidType("BlobId", descriptor.adjustedType);
1204 }
1205
1206 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1207 }
1208
1211 void set(unsigned index, std::nullopt_t)
1212 {
1213 setNull(index);
1214 }
1215
1219 void set(unsigned index, BlobId value)
1220 {
1221 setBlobId(index, value);
1222 }
1223
1227 void set(unsigned index, std::optional<BlobId> value)
1228 {
1229 setBlobId(index, value);
1230 }
1231
1235 void set(unsigned index, bool value)
1236 {
1237 setBool(index, value);
1238 }
1239
1243 void set(unsigned index, std::int16_t value)
1244 {
1245 setInt16(index, value);
1246 }
1247
1251 void set(unsigned index, ScaledInt16 value)
1252 {
1253 setScaledInt16(index, value);
1254 }
1255
1259 void set(unsigned index, std::int32_t value)
1260 {
1261 setInt32(index, value);
1262 }
1263
1267 void set(unsigned index, ScaledInt32 value)
1268 {
1269 setScaledInt32(index, value);
1270 }
1271
1275 void set(unsigned index, std::int64_t value)
1276 {
1277 setInt64(index, value);
1278 }
1279
1283 void set(unsigned index, ScaledInt64 value)
1284 {
1285 setScaledInt64(index, value);
1286 }
1287
1291 void set(unsigned index, OpaqueInt128 value)
1292 {
1293 setOpaqueInt128(index, value);
1294 }
1295
1296#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1300 void set(unsigned index, BoostInt128 value)
1301 {
1302 setBoostInt128(index, value);
1303 }
1304
1308 void set(unsigned index, ScaledBoostInt128 value)
1309 {
1310 setScaledBoostInt128(index, value);
1311 }
1312#endif
1313
1317 void set(unsigned index, float value)
1318 {
1319 setFloat(index, value);
1320 }
1321
1325 void set(unsigned index, double value)
1326 {
1327 setDouble(index, value);
1328 }
1329
1333 void set(unsigned index, OpaqueDecFloat16 value)
1334 {
1335 setOpaqueDecFloat16(index, value);
1336 }
1337
1338#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1342 void set(unsigned index, BoostDecFloat16 value)
1343 {
1344 setBoostDecFloat16(index, value);
1345 }
1346#endif
1347
1351 void set(unsigned index, OpaqueDecFloat34 value)
1352 {
1353 setOpaqueDecFloat34(index, value);
1354 }
1355
1356#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1360 void set(unsigned index, BoostDecFloat34 value)
1361 {
1362 setBoostDecFloat34(index, value);
1363 }
1364#endif
1365
1369 void set(unsigned index, Date value)
1370 {
1371 setDate(index, value);
1372 }
1373
1377 void set(unsigned index, OpaqueDate value)
1378 {
1379 setOpaqueDate(index, value);
1380 }
1381
1385 void set(unsigned index, Time value)
1386 {
1387 setTime(index, value);
1388 }
1389
1393 void set(unsigned index, OpaqueTime value)
1394 {
1395 setOpaqueTime(index, value);
1396 }
1397
1401 void set(unsigned index, Timestamp value)
1402 {
1403 setTimestamp(index, value);
1404 }
1405
1409 void set(unsigned index, OpaqueTimestamp value)
1410 {
1411 setOpaqueTimestamp(index, value);
1412 }
1413
1417 void set(unsigned index, TimeTz value)
1418 {
1419 setTimeTz(index, value);
1420 }
1421
1425 void set(unsigned index, OpaqueTimeTz value)
1426 {
1427 setOpaqueTimeTz(index, value);
1428 }
1429
1433 void set(unsigned index, TimestampTz value)
1434 {
1435 setTimestampTz(index, value);
1436 }
1437
1441 void set(unsigned index, OpaqueTimestampTz value)
1442 {
1443 setOpaqueTimestampTz(index, value);
1444 }
1445
1449 void set(unsigned index, std::string_view value)
1450 {
1451 setString(index, value);
1452 }
1453
1457 template <typename T>
1458 void set(unsigned index, std::optional<T> value)
1459 {
1460 if (value.has_value())
1461 set(index, value.value());
1462 else
1463 setNull(index);
1464 }
1465
1469
1473
1477 bool isNull(unsigned index)
1478 {
1479 assert(isValid());
1480
1481 const auto& descriptor = getOutDescriptor(index);
1482 const auto* const message = outMessage.data();
1483
1484 return *reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE;
1485 }
1486
1490 std::optional<bool> getBool(unsigned index)
1491 {
1492 assert(isValid());
1493
1494 const auto& descriptor = getOutDescriptor(index);
1495 const auto* const message = outMessage.data();
1496
1497 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1498 return std::nullopt;
1499
1500 switch (descriptor.adjustedType)
1501 {
1502 case DescriptorAdjustedType::BOOLEAN:
1503 return message[descriptor.offset] != std::byte{0};
1504
1505 default:
1506 throwInvalidType("bool", descriptor.adjustedType);
1507 }
1508 }
1509
1513 std::optional<std::int16_t> getInt16(unsigned index)
1514 {
1515 std::optional<int> scale{0};
1516 return getNumber<std::int16_t>(index, scale, "std::int16_t");
1517 }
1518
1522 std::optional<ScaledInt16> getScaledInt16(unsigned index)
1523 {
1524 std::optional<int> scale;
1525 const auto value = getNumber<std::int16_t>(index, scale, "ScaledInt16");
1526 return value.has_value() ? std::optional{ScaledInt16{value.value(), scale.value()}} : std::nullopt;
1527 }
1528
1532 std::optional<std::int32_t> getInt32(unsigned index)
1533 {
1534 std::optional<int> scale{0};
1535 return getNumber<std::int32_t>(index, scale, "std::int32_t");
1536 }
1537
1541 std::optional<ScaledInt32> getScaledInt32(unsigned index)
1542 {
1543 std::optional<int> scale;
1544 const auto value = getNumber<std::int32_t>(index, scale, "ScaledInt32");
1545 return value.has_value() ? std::optional{ScaledInt32{value.value(), scale.value()}} : std::nullopt;
1546 }
1547
1551 std::optional<std::int64_t> getInt64(unsigned index)
1552 {
1553 std::optional<int> scale{0};
1554 return getNumber<std::int64_t>(index, scale, "std::int64_t");
1555 }
1556
1560 std::optional<ScaledInt64> getScaledInt64(unsigned index)
1561 {
1562 std::optional<int> scale;
1563 const auto value = getNumber<std::int64_t>(index, scale, "ScaledInt64");
1564 return value.has_value() ? std::optional{ScaledInt64{value.value(), scale.value()}} : std::nullopt;
1565 }
1566
1570 std::optional<ScaledOpaqueInt128> getScaledOpaqueInt128(unsigned index)
1571 {
1572 assert(isValid());
1573
1574 const auto& descriptor = getOutDescriptor(index);
1575 const auto* const message = outMessage.data();
1576
1577 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1578 return std::nullopt;
1579
1580 switch (descriptor.adjustedType)
1581 {
1582 case DescriptorAdjustedType::INT128:
1583 return ScaledOpaqueInt128{
1584 OpaqueInt128{*reinterpret_cast<const OpaqueInt128*>(&message[descriptor.offset])},
1585 descriptor.scale};
1586
1587 default:
1588 throwInvalidType("OpaqueInt128", descriptor.adjustedType);
1589 }
1590 }
1591
1592#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1596 std::optional<BoostInt128> getBoostInt128(unsigned index)
1597 {
1598 std::optional<int> scale{0};
1599 const auto value = getNumber<BoostInt128>(index, scale, "BoostInt128");
1600 return value.has_value() ? std::optional{value.value()} : std::nullopt;
1601 }
1602
1606 std::optional<ScaledBoostInt128> getScaledBoostInt128(unsigned index)
1607 {
1608 std::optional<int> scale;
1609 const auto value = getNumber<BoostInt128>(index, scale, "ScaledBoostInt128");
1610 return value.has_value() ? std::optional{ScaledBoostInt128{value.value(), scale.value()}} : std::nullopt;
1611 }
1612#endif
1613
1617 std::optional<float> getFloat(unsigned index)
1618 {
1619 std::optional<int> scale{0};
1620 return getNumber<float>(index, scale, "float");
1621 }
1622
1626 std::optional<double> getDouble(unsigned index)
1627 {
1628 std::optional<int> scale{0};
1629 return getNumber<double>(index, scale, "double");
1630 }
1631
1635 std::optional<OpaqueDecFloat16> getOpaqueDecFloat16(unsigned index)
1636 {
1637 assert(isValid());
1638
1639 const auto& descriptor = getOutDescriptor(index);
1640 const auto* const message = outMessage.data();
1641
1642 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1643 return std::nullopt;
1644
1645 switch (descriptor.adjustedType)
1646 {
1647 case DescriptorAdjustedType::DECFLOAT16:
1648 return OpaqueDecFloat16{*reinterpret_cast<const OpaqueDecFloat16*>(&message[descriptor.offset])};
1649
1650 default:
1651 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
1652 }
1653 }
1654
1655#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1659 std::optional<BoostDecFloat16> getBoostDecFloat16(unsigned index)
1660 {
1661 std::optional<int> scale{0};
1662 return getNumber<BoostDecFloat16>(index, scale, "BoostDecFloat16");
1663 }
1664#endif
1665
1669 std::optional<OpaqueDecFloat34> getOpaqueDecFloat34(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::DECFLOAT34:
1682 return OpaqueDecFloat34{*reinterpret_cast<const OpaqueDecFloat34*>(&message[descriptor.offset])};
1683
1684 default:
1685 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
1686 }
1687 }
1688
1689#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1693 std::optional<BoostDecFloat34> getBoostDecFloat34(unsigned index)
1694 {
1695 std::optional<int> scale{0};
1696 return getNumber<BoostDecFloat34>(index, scale, "BoostDecFloat34");
1697 }
1698#endif
1699
1703 std::optional<Date> getDate(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::DATE:
1716 return calendarConverter.opaqueDateToDate(
1717 *reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset]));
1718
1719 default:
1720 throwInvalidType("Date", descriptor.adjustedType);
1721 }
1722 }
1723
1727 std::optional<OpaqueDate> getOpaqueDate(unsigned index)
1728 {
1729 assert(isValid());
1730
1731 const auto& descriptor = getOutDescriptor(index);
1732 const auto* const message = outMessage.data();
1733
1734 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1735 return std::nullopt;
1736
1737 switch (descriptor.adjustedType)
1738 {
1739 case DescriptorAdjustedType::DATE:
1740 return OpaqueDate{*reinterpret_cast<const OpaqueDate*>(&message[descriptor.offset])};
1741
1742 default:
1743 throwInvalidType("OpaqueDate", descriptor.adjustedType);
1744 }
1745 }
1746
1750 std::optional<Time> getTime(unsigned index)
1751 {
1752 assert(isValid());
1753
1754 const auto& descriptor = getOutDescriptor(index);
1755 const auto* const message = outMessage.data();
1756
1757 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1758 return std::nullopt;
1759
1760 switch (descriptor.adjustedType)
1761 {
1762 case DescriptorAdjustedType::TIME:
1763 return calendarConverter.opaqueTimeToTime(
1764 *reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset]));
1765
1766 default:
1767 throwInvalidType("Time", descriptor.adjustedType);
1768 }
1769 }
1770
1774 std::optional<OpaqueTime> getOpaqueTime(unsigned index)
1775 {
1776 assert(isValid());
1777
1778 const auto& descriptor = getOutDescriptor(index);
1779 const auto* const message = outMessage.data();
1780
1781 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1782 return std::nullopt;
1783
1784 switch (descriptor.adjustedType)
1785 {
1786 case DescriptorAdjustedType::TIME:
1787 return OpaqueTime{*reinterpret_cast<const OpaqueTime*>(&message[descriptor.offset])};
1788
1789 default:
1790 throwInvalidType("OpaqueTime", descriptor.adjustedType);
1791 }
1792 }
1793
1797 std::optional<Timestamp> getTimestamp(unsigned index)
1798 {
1799 assert(isValid());
1800
1801 const auto& descriptor = getOutDescriptor(index);
1802 const auto* const message = outMessage.data();
1803
1804 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1805 return std::nullopt;
1806
1807 switch (descriptor.adjustedType)
1808 {
1809 case DescriptorAdjustedType::TIMESTAMP:
1810 return calendarConverter.opaqueTimestampToTimestamp(
1811 *reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset]));
1812
1813 default:
1814 throwInvalidType("Timestamp", descriptor.adjustedType);
1815 }
1816 }
1817
1821 std::optional<OpaqueTimestamp> getOpaqueTimestamp(unsigned index)
1822 {
1823 assert(isValid());
1824
1825 const auto& descriptor = getOutDescriptor(index);
1826 const auto* const message = outMessage.data();
1827
1828 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1829 return std::nullopt;
1830
1831 switch (descriptor.adjustedType)
1832 {
1833 case DescriptorAdjustedType::TIMESTAMP:
1834 return OpaqueTimestamp{*reinterpret_cast<const OpaqueTimestamp*>(&message[descriptor.offset])};
1835
1836 default:
1837 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
1838 }
1839 }
1840
1844 std::optional<TimeTz> getTimeTz(unsigned index)
1845 {
1846 assert(isValid());
1847
1848 const auto& descriptor = getOutDescriptor(index);
1849 const auto* const message = outMessage.data();
1850
1851 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1852 return std::nullopt;
1853
1854 switch (descriptor.adjustedType)
1855 {
1856 case DescriptorAdjustedType::TIME_TZ:
1857 return calendarConverter.opaqueTimeTzToTimeTz(
1858 *reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset]));
1859
1860 default:
1861 throwInvalidType("TimeTz", descriptor.adjustedType);
1862 }
1863 }
1864
1868 std::optional<OpaqueTimeTz> getOpaqueTimeTz(unsigned index)
1869 {
1870 assert(isValid());
1871
1872 const auto& descriptor = getOutDescriptor(index);
1873 const auto* const message = outMessage.data();
1874
1875 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1876 return std::nullopt;
1877
1878 switch (descriptor.adjustedType)
1879 {
1880 case DescriptorAdjustedType::TIME_TZ:
1881 return OpaqueTimeTz{*reinterpret_cast<const OpaqueTimeTz*>(&message[descriptor.offset])};
1882
1883 default:
1884 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
1885 }
1886 }
1887
1891 std::optional<TimestampTz> getTimestampTz(unsigned index)
1892 {
1893 assert(isValid());
1894
1895 const auto& descriptor = getOutDescriptor(index);
1896 const auto* const message = outMessage.data();
1897
1898 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1899 return std::nullopt;
1900
1901 switch (descriptor.adjustedType)
1902 {
1903 case DescriptorAdjustedType::TIMESTAMP_TZ:
1904 return calendarConverter.opaqueTimestampTzToTimestampTz(
1905 *reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset]));
1906
1907 default:
1908 throwInvalidType("TimestampTz", descriptor.adjustedType);
1909 }
1910 }
1911
1915 std::optional<OpaqueTimestampTz> getOpaqueTimestampTz(unsigned index)
1916 {
1917 assert(isValid());
1918
1919 const auto& descriptor = getOutDescriptor(index);
1920 const auto* const message = outMessage.data();
1921
1922 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1923 return std::nullopt;
1924
1925 switch (descriptor.adjustedType)
1926 {
1927 case DescriptorAdjustedType::TIMESTAMP_TZ:
1928 return OpaqueTimestampTz{*reinterpret_cast<const OpaqueTimestampTz*>(&message[descriptor.offset])};
1929
1930 default:
1931 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
1932 }
1933 }
1934
1938 std::optional<BlobId> getBlobId(unsigned index)
1939 {
1940 assert(isValid());
1941
1942 const auto& descriptor = getOutDescriptor(index);
1943 const auto* const message = outMessage.data();
1944
1945 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1946 return std::nullopt;
1947
1948 switch (descriptor.adjustedType)
1949 {
1950 case DescriptorAdjustedType::BLOB:
1951 {
1952 BlobId value;
1953 value.id = *reinterpret_cast<const ISC_QUAD*>(&message[descriptor.offset]);
1954 return value;
1955 }
1956
1957 default:
1958 throwInvalidType("BlobId", descriptor.adjustedType);
1959 }
1960 }
1961
1965 std::optional<std::string> getString(unsigned index)
1966 {
1967 assert(isValid());
1968
1969 const auto& descriptor = getOutDescriptor(index);
1970 const auto* const message = outMessage.data();
1971
1972 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
1973 return std::nullopt;
1974
1975 const auto data = &message[descriptor.offset];
1976
1977 switch (descriptor.adjustedType)
1978 {
1979 case DescriptorAdjustedType::BOOLEAN:
1980 return (message[descriptor.offset] != std::byte{0}) ? std::string{"true"} : std::string{"false"};
1981
1982 case DescriptorAdjustedType::INT16:
1983 return numericConverter.numberToString(
1984 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale});
1985
1986 case DescriptorAdjustedType::INT32:
1987 return numericConverter.numberToString(
1988 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale});
1989
1990 case DescriptorAdjustedType::INT64:
1991 return numericConverter.numberToString(
1992 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale});
1993
1994 case DescriptorAdjustedType::INT128:
1995 return numericConverter.opaqueInt128ToString(
1996 *reinterpret_cast<const OpaqueInt128*>(data), descriptor.scale);
1997
1998 case DescriptorAdjustedType::FLOAT:
1999 return numericConverter.numberToString(*reinterpret_cast<const float*>(data));
2000
2001 case DescriptorAdjustedType::DOUBLE:
2002 return numericConverter.numberToString(*reinterpret_cast<const double*>(data));
2003
2004 case DescriptorAdjustedType::DATE:
2005 return calendarConverter.opaqueDateToString(*reinterpret_cast<const OpaqueDate*>(data));
2006
2007 case DescriptorAdjustedType::TIME:
2008 return calendarConverter.opaqueTimeToString(*reinterpret_cast<const OpaqueTime*>(data));
2009
2010 case DescriptorAdjustedType::TIMESTAMP:
2011 return calendarConverter.opaqueTimestampToString(*reinterpret_cast<const OpaqueTimestamp*>(data));
2012
2013 case DescriptorAdjustedType::TIME_TZ:
2014 return calendarConverter.opaqueTimeTzToString(*reinterpret_cast<const OpaqueTimeTz*>(data));
2015
2016 case DescriptorAdjustedType::TIMESTAMP_TZ:
2017 return calendarConverter.opaqueTimestampTzToString(
2018 *reinterpret_cast<const OpaqueTimestampTz*>(data));
2019
2020 case DescriptorAdjustedType::DECFLOAT16:
2021 return numericConverter.opaqueDecFloat16ToString(*reinterpret_cast<const OpaqueDecFloat16*>(data));
2022
2023 case DescriptorAdjustedType::DECFLOAT34:
2024 return numericConverter.opaqueDecFloat34ToString(*reinterpret_cast<const OpaqueDecFloat34*>(data));
2025
2026 case DescriptorAdjustedType::STRING:
2027 return std::string{reinterpret_cast<const char*>(data + sizeof(std::uint16_t)),
2028 *reinterpret_cast<const std::uint16_t*>(data)};
2029
2030 default:
2031 throwInvalidType("std::string", descriptor.adjustedType);
2032 }
2033 }
2034
2038
2042 template <typename T>
2043 T get(unsigned index);
2044
2045 private:
2049 const Descriptor& getInDescriptor(unsigned index)
2050 {
2051 if (index >= inDescriptors.size())
2052 throw std::out_of_range("index out of range");
2053
2054 return inDescriptors[index];
2055 }
2056
2060 const Descriptor& getOutDescriptor(unsigned index)
2061 {
2062 if (index >= outDescriptors.size())
2063 throw std::out_of_range("index out of range");
2064
2065 return outDescriptors[index];
2066 }
2067
2071 template <typename T>
2072 void setNumber(unsigned index, DescriptorAdjustedType valueType, T value, int scale, const char* typeName)
2073 {
2074 assert(isValid());
2075
2076 const auto& descriptor = getInDescriptor(index);
2077 auto* const message = inMessage.data();
2078
2079 const auto descriptorData = &message[descriptor.offset];
2080 std::optional<int> descriptorScale{descriptor.scale};
2081
2082 Descriptor valueDescriptor;
2083 valueDescriptor.adjustedType = valueType;
2084 valueDescriptor.scale = scale;
2085
2086 const auto valueAddress = reinterpret_cast<const std::byte*>(&value);
2087
2088 switch (descriptor.adjustedType)
2089 {
2090 case DescriptorAdjustedType::INT16:
2091 *reinterpret_cast<std::int16_t*>(descriptorData) =
2092 convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale, "std::int16_t");
2093 break;
2094
2095 case DescriptorAdjustedType::INT32:
2096 *reinterpret_cast<std::int32_t*>(descriptorData) =
2097 convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale, "std::int32_t");
2098 break;
2099
2100 case DescriptorAdjustedType::INT64:
2101 *reinterpret_cast<std::int64_t*>(descriptorData) =
2102 convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale, "std::int64_t");
2103 break;
2104
2105#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2106 case DescriptorAdjustedType::INT128:
2107 {
2108 const auto boostInt128 =
2109 convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale, "BoostInt128");
2110 *reinterpret_cast<OpaqueInt128*>(descriptorData) =
2111 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
2112 break;
2113 }
2114#endif
2115
2116 case DescriptorAdjustedType::FLOAT:
2117 *reinterpret_cast<float*>(descriptorData) =
2118 convertNumber<float>(valueDescriptor, valueAddress, descriptorScale, "float");
2119 break;
2120
2121 case DescriptorAdjustedType::DOUBLE:
2122 *reinterpret_cast<double*>(descriptorData) =
2123 convertNumber<double>(valueDescriptor, valueAddress, descriptorScale, "double");
2124 break;
2125
2126#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2127 case DescriptorAdjustedType::DECFLOAT16:
2128 {
2129 const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
2130 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat16");
2131 *reinterpret_cast<OpaqueDecFloat16*>(descriptorData) =
2132 numericConverter.boostDecFloat16ToOpaqueDecFloat16(boostDecFloat16);
2133 break;
2134 }
2135
2136 case DescriptorAdjustedType::DECFLOAT34:
2137 {
2138 const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
2139 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat34");
2140 *reinterpret_cast<OpaqueDecFloat34*>(descriptorData) =
2141 numericConverter.boostDecFloat34ToOpaqueDecFloat34(boostDecFloat34);
2142 break;
2143 }
2144#endif
2145
2146 default:
2147 throwInvalidType(typeName, descriptor.adjustedType);
2148 }
2149
2150 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
2151 }
2152
2153 // FIXME: floating to integral
2157 template <typename T>
2158 std::optional<T> getNumber(unsigned index, std::optional<int>& scale, const char* typeName)
2159 {
2160 assert(isValid());
2161
2162 const auto& descriptor = getOutDescriptor(index);
2163 const auto* const message = outMessage.data();
2164
2165 if (*reinterpret_cast<const std::int16_t*>(&message[descriptor.nullOffset]) != FB_FALSE)
2166 return std::nullopt;
2167
2168 auto data = &message[descriptor.offset];
2169#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2170 std::optional<BoostInt128> boostInt128;
2171 std::optional<BoostDecFloat16> boostDecFloat16;
2172 std::optional<BoostDecFloat34> boostDecFloat34;
2173#endif
2174
2175 // FIXME: Use IUtil
2176 switch (descriptor.adjustedType)
2177 {
2178#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2179 case DescriptorAdjustedType::INT128:
2180 boostInt128.emplace(
2181 numericConverter.opaqueInt128ToBoostInt128(*reinterpret_cast<const OpaqueInt128*>(data)));
2182 data = reinterpret_cast<const std::byte*>(&boostInt128.value());
2183 break;
2184
2185 case DescriptorAdjustedType::DECFLOAT16:
2186 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
2187 *reinterpret_cast<const OpaqueDecFloat16*>(data)));
2188 data = reinterpret_cast<const std::byte*>(&boostDecFloat16.value());
2189 break;
2190
2191 case DescriptorAdjustedType::DECFLOAT34:
2192 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
2193 *reinterpret_cast<const OpaqueDecFloat34*>(data)));
2194 data = reinterpret_cast<const std::byte*>(&boostDecFloat34.value());
2195 break;
2196#endif
2197
2198 default:
2199 break;
2200 }
2201
2202 return convertNumber<T>(descriptor, data, scale, typeName);
2203 }
2204
2205 [[noreturn]] static void throwInvalidType(const char* actualType, DescriptorAdjustedType descriptorType)
2206 {
2207 throw FbCppException("Invalid type: actual type " + std::string(actualType) + ", descriptor type " +
2208 std::to_string(static_cast<unsigned>(descriptorType)));
2209 }
2210
2211 template <typename T>
2212 T convertNumber(
2213 const Descriptor& descriptor, const std::byte* data, std::optional<int>& toScale, const char* toTypeName)
2214 {
2215 if (!toScale.has_value())
2216 {
2217 switch (descriptor.adjustedType)
2218 {
2219 case DescriptorAdjustedType::DECFLOAT16:
2220 case DescriptorAdjustedType::DECFLOAT34:
2221 case DescriptorAdjustedType::FLOAT:
2222 case DescriptorAdjustedType::DOUBLE:
2223 throwInvalidType(toTypeName, descriptor.adjustedType);
2224
2225 default:
2226 break;
2227 }
2228
2229 toScale = descriptor.scale;
2230 }
2231
2232 switch (descriptor.adjustedType)
2233 {
2234 case DescriptorAdjustedType::INT16:
2235 return numericConverter.numberToNumber<T>(
2236 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale}, toScale.value());
2237 break;
2238
2239 case DescriptorAdjustedType::INT32:
2240 return numericConverter.numberToNumber<T>(
2241 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale}, toScale.value());
2242
2243 case DescriptorAdjustedType::INT64:
2244 return numericConverter.numberToNumber<T>(
2245 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale}, toScale.value());
2246
2247#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2248 case DescriptorAdjustedType::INT128:
2249 return numericConverter.numberToNumber<T>(
2250 ScaledBoostInt128{*reinterpret_cast<const BoostInt128*>(data), descriptor.scale},
2251 toScale.value());
2252
2253 case DescriptorAdjustedType::DECFLOAT16:
2254 return numericConverter.numberToNumber<T>(
2255 *reinterpret_cast<const BoostDecFloat16*>(data), toScale.value());
2256
2257 case DescriptorAdjustedType::DECFLOAT34:
2258 return numericConverter.numberToNumber<T>(
2259 *reinterpret_cast<const BoostDecFloat34*>(data), toScale.value());
2260#endif
2261
2262 case DescriptorAdjustedType::FLOAT:
2263 return numericConverter.numberToNumber<T>(*reinterpret_cast<const float*>(data), toScale.value());
2264 break;
2265
2266 case DescriptorAdjustedType::DOUBLE:
2267 return numericConverter.numberToNumber<T>(*reinterpret_cast<const double*>(data), toScale.value());
2268 break;
2269
2270 default:
2271 throwInvalidType(toTypeName, descriptor.adjustedType);
2272 }
2273 }
2274
2275 private:
2276 Attachment& attachment;
2277 FbUniquePtr<Firebird::IStatus> status;
2278 impl::StatusWrapper statusWrapper;
2279 impl::CalendarConverter calendarConverter;
2280 impl::NumericConverter numericConverter;
2281 FbRef<fb::IStatement> statementHandle;
2282 FbRef<fb::IResultSet> resultSetHandle;
2283 FbRef<fb::IMessageMetadata> inMetadata;
2284 std::vector<Descriptor> inDescriptors;
2285 std::vector<std::byte> inMessage;
2286 FbRef<fb::IMessageMetadata> outMetadata;
2287 std::vector<Descriptor> outDescriptors;
2288 std::vector<std::byte> outMessage;
2289 StatementType type;
2290 };
2291
2296
2297 template <>
2298 inline std::optional<bool> Statement::get<std::optional<bool>>(unsigned index)
2299 {
2300 return getBool(index);
2301 }
2302
2303 template <>
2304 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(unsigned index)
2305 {
2306 return getBlobId(index);
2307 }
2308
2309 template <>
2310 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(unsigned index)
2311 {
2312 return getInt16(index);
2313 }
2314
2315 template <>
2316 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(unsigned index)
2317 {
2318 return getScaledInt16(index);
2319 }
2320
2321 template <>
2322 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(unsigned index)
2323 {
2324 return getInt32(index);
2325 }
2326
2327 template <>
2328 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(unsigned index)
2329 {
2330 return getScaledInt32(index);
2331 }
2332
2333 template <>
2334 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(unsigned index)
2335 {
2336 return getInt64(index);
2337 }
2338
2339 template <>
2340 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(unsigned index)
2341 {
2342 return getScaledInt64(index);
2343 }
2344
2345 template <>
2346 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(unsigned index)
2347 {
2348 return getScaledOpaqueInt128(index);
2349 }
2350
2351#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2352 template <>
2353 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(unsigned index)
2354 {
2355 return getBoostInt128(index);
2356 }
2357
2358 template <>
2359 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(unsigned index)
2360 {
2361 return getScaledBoostInt128(index);
2362 }
2363#endif
2364
2365 template <>
2366 inline std::optional<float> Statement::get<std::optional<float>>(unsigned index)
2367 {
2368 return getFloat(index);
2369 }
2370
2371 template <>
2372 inline std::optional<double> Statement::get<std::optional<double>>(unsigned index)
2373 {
2374 return getDouble(index);
2375 }
2376
2377 template <>
2378 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(unsigned index)
2379 {
2380 return getOpaqueDecFloat16(index);
2381 }
2382
2383#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2384 template <>
2385 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(unsigned index)
2386 {
2387 return getBoostDecFloat16(index);
2388 }
2389#endif
2390
2391 template <>
2392 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(unsigned index)
2393 {
2394 return getOpaqueDecFloat34(index);
2395 }
2396
2397#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2398 template <>
2399 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(unsigned index)
2400 {
2401 return getBoostDecFloat34(index);
2402 }
2403#endif
2404
2405 template <>
2406 inline std::optional<Date> Statement::get<std::optional<Date>>(unsigned index)
2407 {
2408 return getDate(index);
2409 }
2410
2411 template <>
2412 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(unsigned index)
2413 {
2414 return getOpaqueDate(index);
2415 }
2416
2417 template <>
2418 inline std::optional<Time> Statement::get<std::optional<Time>>(unsigned index)
2419 {
2420 return getTime(index);
2421 }
2422
2423 template <>
2424 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(unsigned index)
2425 {
2426 return getOpaqueTime(index);
2427 }
2428
2429 template <>
2430 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(unsigned index)
2431 {
2432 return getOpaqueTimestamp(index);
2433 }
2434
2435 template <>
2436 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(unsigned index)
2437 {
2438 return getTimestamp(index);
2439 }
2440
2441 template <>
2442 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(unsigned index)
2443 {
2444 return getTimeTz(index);
2445 }
2446
2447 template <>
2448 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(unsigned index)
2449 {
2450 return getOpaqueTimeTz(index);
2451 }
2452
2453 template <>
2454 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(unsigned index)
2455 {
2456 return getTimestampTz(index);
2457 }
2458
2459 template <>
2460 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(unsigned index)
2461 {
2462 return getOpaqueTimestampTz(index);
2463 }
2464
2465 template <>
2466 inline std::optional<std::string> Statement::get<std::optional<std::string>>(unsigned index)
2467 {
2468 return getString(index);
2469 }
2470
2474} // namespace fbcpp
2475
2476
2477#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
fb::IInt128 * getInt128Util(StatusType *status)
Returns a Firebird IInt128 interface.
Definition Client.h:158
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:1291
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:1774
std::optional< OpaqueDecFloat34 > getOpaqueDecFloat34(unsigned index)
Reads a Firebird 34-digit decimal floating-point column.
Definition Statement.h:1669
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:1342
std::optional< TimeTz > getTimeTz(unsigned index)
Reads a time-of-day column with timezone.
Definition Statement.h:1844
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:1449
std::optional< BoostDecFloat34 > getBoostDecFloat34(unsigned index)
Reads a Boost-based 34-digit decimal floating-point column.
Definition Statement.h:1693
void setBlobId(unsigned index, std::optional< BlobId > optValue)
Binds a blob identifier to the specified parameter or null.
Definition Statement.h:1182
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:1259
std::optional< Time > getTime(unsigned index)
Reads a time-of-day column without timezone.
Definition Statement.h:1750
std::optional< Date > getDate(unsigned index)
Reads a date column.
Definition Statement.h:1703
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:1477
void set(unsigned index, double value)
Convenience overload that binds a double precision floating-point value.
Definition Statement.h:1325
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:1283
std::optional< OpaqueDate > getOpaqueDate(unsigned index)
Reads a raw date column in Firebird's representation.
Definition Statement.h:1727
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:1275
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:1551
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:1541
void set(unsigned index, OpaqueTimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1441
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:1617
std::optional< double > getDouble(unsigned index)
Reads a double precision floating-point column.
Definition Statement.h:1626
std::optional< OpaqueTimestampTz > getOpaqueTimestampTz(unsigned index)
Reads a raw timestamp-with-time-zone column in Firebird's representation.
Definition Statement.h:1915
std::optional< ScaledInt16 > getScaledInt16(unsigned index)
Reads a scaled 16-bit signed integer column.
Definition Statement.h:1522
std::optional< BlobId > getBlobId(unsigned index)
Reads a blob identifier column.
Definition Statement.h:1938
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:1570
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:1417
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:1868
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:1369
void set(unsigned index, Timestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1401
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:1965
std::optional< std::int32_t > getInt32(unsigned index)
Reads a 32-bit signed integer column.
Definition Statement.h:1532
void set(unsigned index, OpaqueDecFloat16 value)
Convenience overload that binds a Firebird 16-digit decimal floating-point value.
Definition Statement.h:1333
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:1425
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:1606
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:1219
void set(unsigned index, BoostDecFloat34 value)
Convenience overload that binds a Boost 34-digit decimal floating-point value.
Definition Statement.h:1360
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:1351
void set(unsigned index, Time value)
Convenience overload that binds a Firebird time value.
Definition Statement.h:1385
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:1251
std::optional< BoostInt128 > getBoostInt128(unsigned index)
Reads a Boost 128-bit integer column.
Definition Statement.h:1596
std::optional< bool > getBool(unsigned index)
Reads a boolean column from the current row.
Definition Statement.h:1490
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:1409
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:1227
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:1433
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:1377
void set(unsigned index, std::int16_t value)
Convenience overload that binds a 16-bit signed integer.
Definition Statement.h:1243
void set(unsigned index, std::optional< T > value)
Convenience template that forwards optional values to specialized overloads.
Definition Statement.h:1458
std::optional< OpaqueTimestamp > getOpaqueTimestamp(unsigned index)
Reads a raw timestamp column in Firebird's representation.
Definition Statement.h:1821
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:1211
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:1393
void set(unsigned index, ScaledInt32 value)
Convenience overload that binds a scaled 32-bit signed integer.
Definition Statement.h:1267
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:1513
void set(unsigned index, ScaledBoostInt128 value)
Convenience overload that binds a scaled Boost-provided 128-bit integer.
Definition Statement.h:1308
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:1891
void set(unsigned index, BoostInt128 value)
Convenience overload that binds a Boost-provided 128-bit integer.
Definition Statement.h:1300
std::optional< OpaqueDecFloat16 > getOpaqueDecFloat16(unsigned index)
Reads a Firebird 16-digit decimal floating-point column.
Definition Statement.h:1635
std::optional< Timestamp > getTimestamp(unsigned index)
Reads a timestamp column without timezone.
Definition Statement.h:1797
std::optional< BoostDecFloat16 > getBoostDecFloat16(unsigned index)
Reads a Boost-based 16-digit decimal floating-point column.
Definition Statement.h:1659
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:1560
void set(unsigned index, bool value)
Convenience overload that binds a boolean value.
Definition Statement.h:1235
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:1317
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