fb-cpp 0.0.2
A modern C++ wrapper for the Firebird database API
Loading...
Searching...
No Matches
Statement.h
1/*
2 * MIT License
3 *
4 * Copyright (c) 2025 Adriano dos Santos Fernandes
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#ifndef FBCPP_STATEMENT_H
26#define FBCPP_STATEMENT_H
27
28#include "config.h"
29#include "fb-api.h"
30#include "types.h"
31#include "Blob.h"
32#include "Client.h"
33#include "Row.h"
34#include "StatementOptions.h"
35#include "NumericConverter.h"
36#include "CalendarConverter.h"
37#include "Descriptor.h"
38#include "SmartPtrs.h"
39#include "Exception.h"
40#include "StructBinding.h"
41#include "VariantTypeTraits.h"
42#include <charconv>
43#include <cerrno>
44#include <cstdlib>
45#include <limits>
46#include <memory>
47#include <optional>
48#include <stdexcept>
49#include <string>
50#include <string_view>
51#include <type_traits>
52#include <vector>
53#include <cassert>
54#include <cmath>
55#include <cstddef>
56#include <cstdint>
57
58#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
59#include <boost/multiprecision/cpp_int.hpp>
60#include <boost/multiprecision/cpp_dec_float.hpp>
61#endif
62
66namespace fbcpp
67{
68 class Attachment;
69 class Transaction;
70
74 enum class StatementType : unsigned
75 {
79 SELECT = isc_info_sql_stmt_select,
83 INSERT = isc_info_sql_stmt_insert,
87 UPDATE = isc_info_sql_stmt_update,
91 DELETE = isc_info_sql_stmt_delete,
95 DDL = isc_info_sql_stmt_ddl,
99 GET_SEGMENT = isc_info_sql_stmt_get_segment,
103 PUT_SEGMENT = isc_info_sql_stmt_put_segment,
107 EXEC_PROCEDURE = isc_info_sql_stmt_exec_procedure,
111 START_TRANSACTION = isc_info_sql_stmt_start_trans,
115 COMMIT = isc_info_sql_stmt_commit,
119 ROLLBACK = isc_info_sql_stmt_rollback,
123 SELECT_FOR_UPDATE = isc_info_sql_stmt_select_for_upd,
127 SET_GENERATOR = isc_info_sql_stmt_set_generator,
131 SAVEPOINT = isc_info_sql_stmt_savepoint,
132 };
133
137 class Statement final
138 {
139 public:
147 explicit Statement(Attachment& attachment, Transaction& transaction, std::string_view sql,
148 const StatementOptions& options = {});
149
153 Statement(Statement&& o) noexcept;
154
161 Statement& operator=(Statement&& o) noexcept;
162
163 Statement(const Statement&) = delete;
164 Statement& operator=(const Statement&) = delete;
165
170 {
171 if (isValid())
172 {
173 try
174 {
175 free();
176 }
177 catch (...)
178 {
179 // swallow
180 }
181 }
182 }
183
184 public:
190
195 {
196 return *attachment;
197 }
198
203 {
204 return statementHandle != nullptr;
205 }
206
212 {
213 return statementHandle;
214 }
215
221 {
222 return resultSetHandle;
223 }
224
229 {
230 return inMetadata;
231 }
232
236 std::vector<std::byte>& getInputMessage() noexcept
237 {
238 return inMessage;
239 }
240
245 {
246 return outMetadata;
247 }
248
252 std::vector<std::byte>& getOutputMessage() noexcept
253 {
254 return outMessage;
255 }
256
261 {
262 return type;
263 }
264
268
274
278 const std::vector<Descriptor>& getInputDescriptors() noexcept
279 {
280 return inDescriptors;
281 }
282
286 const std::vector<Descriptor>& getOutputDescriptors() noexcept
287 {
288 return outDescriptors;
289 }
290
294
298 void free();
299
303 std::string getLegacyPlan();
304
308 std::string getPlan();
309
315 bool execute(Transaction& transaction);
316
320
324 bool fetchNext();
325
329 bool fetchPrior();
330
334 bool fetchFirst();
335
339 bool fetchLast();
340
344 bool fetchAbsolute(unsigned position);
345
349 bool fetchRelative(int offset);
350
354
358
363 {
364 assert(isValid());
365
366 const auto message = inMessage.data();
367
368 for (const auto& descriptor : inDescriptors)
369 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_TRUE;
370 }
371
376 void setNull(unsigned index)
377 {
378 assert(isValid());
379
380 const auto& descriptor = getInDescriptor(index);
381 const auto message = inMessage.data();
382
383 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_TRUE;
384 }
385
391 void setBool(unsigned index, std::optional<bool> optValue)
392 {
393 if (!optValue.has_value())
394 {
395 setNull(index);
396 return;
397 }
398
399 assert(isValid());
400
401 const auto& value = optValue.value();
402 const auto& descriptor = getInDescriptor(index);
403 const auto message = inMessage.data();
404
405 switch (descriptor.adjustedType)
406 {
408 message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
409 break;
410
411 default:
412 throwInvalidType("bool", descriptor.adjustedType);
413 }
414
415 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
416 }
417
421 void setInt16(unsigned index, std::optional<std::int16_t> optValue)
422 {
423 if (!optValue.has_value())
424 {
425 setNull(index);
426 return;
427 }
428
429 setNumber(index, DescriptorAdjustedType::INT16, optValue.value(), 0, "std::int16_t");
430 }
431
435 void setScaledInt16(unsigned index, std::optional<ScaledInt16> optValue)
436 {
437 if (!optValue.has_value())
438 {
439 setNull(index);
440 return;
441 }
442
443 const auto& value = optValue.value();
444 setNumber(index, DescriptorAdjustedType::INT16, value.value, value.scale, "ScaledInt16");
445 }
446
450 void setInt32(unsigned index, std::optional<std::int32_t> optValue)
451 {
452 if (!optValue.has_value())
453 {
454 setNull(index);
455 return;
456 }
457
458 setNumber(index, DescriptorAdjustedType::INT32, optValue.value(), 0, "std::int32_t");
459 }
460
464 void setScaledInt32(unsigned index, std::optional<ScaledInt32> optValue)
465 {
466 if (!optValue.has_value())
467 {
468 setNull(index);
469 return;
470 }
471
472 const auto& value = optValue.value();
473 setNumber(index, DescriptorAdjustedType::INT32, value.value, value.scale, "ScaledInt32");
474 }
475
479 void setInt64(unsigned index, std::optional<std::int64_t> optValue)
480 {
481 if (!optValue.has_value())
482 {
483 setNull(index);
484 return;
485 }
486
487 setNumber(index, DescriptorAdjustedType::INT64, optValue.value(), 0, "std::int64_t");
488 }
489
493 void setScaledInt64(unsigned index, std::optional<ScaledInt64> optValue)
494 {
495 if (!optValue.has_value())
496 {
497 setNull(index);
498 return;
499 }
500
501 const auto& value = optValue.value();
502 setNumber(index, DescriptorAdjustedType::INT64, value.value, value.scale, "ScaledInt64");
503 }
504
508 void setOpaqueInt128(unsigned index, std::optional<OpaqueInt128> optValue)
509 {
510 if (!optValue.has_value())
511 {
512 setNull(index);
513 return;
514 }
515
516 assert(isValid());
517
518 const auto& value = optValue.value();
519 const auto& descriptor = getInDescriptor(index);
520 const auto message = inMessage.data();
521
522 switch (descriptor.adjustedType)
523 {
525 *reinterpret_cast<OpaqueInt128*>(&message[descriptor.offset]) = value;
526 break;
527
528 default:
529 throwInvalidType("OpaqueInt128", descriptor.adjustedType);
530 }
531
532 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
533 }
534
535#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
539 void setBoostInt128(unsigned index, std::optional<BoostInt128> optValue)
540 {
541 if (!optValue.has_value())
542 {
543 setNull(index);
544 return;
545 }
546
547 setNumber(index, DescriptorAdjustedType::INT128, optValue.value(), 0, "BoostInt128");
548 }
549
553 void setScaledBoostInt128(unsigned index, std::optional<ScaledBoostInt128> optValue)
554 {
555 if (!optValue.has_value())
556 {
557 setNull(index);
558 return;
559 }
560
561 const auto& value = optValue.value();
562 setNumber(index, DescriptorAdjustedType::INT128, value.value, value.scale, "ScaledBoostInt128");
563 }
564#endif
565
569 void setFloat(unsigned index, std::optional<float> optValue)
570 {
571 if (!optValue.has_value())
572 {
573 setNull(index);
574 return;
575 }
576
577 setNumber(index, DescriptorAdjustedType::FLOAT, optValue.value(), 0, "float");
578 }
579
583 void setDouble(unsigned index, std::optional<double> optValue)
584 {
585 if (!optValue.has_value())
586 {
587 setNull(index);
588 return;
589 }
590
591 setNumber(index, DescriptorAdjustedType::DOUBLE, optValue.value(), 0, "double");
592 }
593
597 void setOpaqueDecFloat16(unsigned index, std::optional<OpaqueDecFloat16> optValue)
598 {
599 if (!optValue.has_value())
600 {
601 setNull(index);
602 return;
603 }
604
605 assert(isValid());
606
607 const auto& value = optValue.value();
608 const auto& descriptor = getInDescriptor(index);
609 const auto message = inMessage.data();
610
611 switch (descriptor.adjustedType)
612 {
614 *reinterpret_cast<OpaqueDecFloat16*>(&message[descriptor.offset]) = value;
615 break;
616
617 default:
618 throwInvalidType("OpaqueDecFloat16", descriptor.adjustedType);
619 }
620
621 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
622 }
623
624#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
628 void setBoostDecFloat16(unsigned index, std::optional<BoostDecFloat16> optValue)
629 {
630 if (!optValue.has_value())
631 {
632 setNull(index);
633 return;
634 }
635
636 setNumber(index, DescriptorAdjustedType::DECFLOAT16, optValue.value(), 0, "BoostDecFloat16");
637 }
638#endif
639
643 void setOpaqueDecFloat34(unsigned index, std::optional<OpaqueDecFloat34> optValue)
644 {
645 if (!optValue.has_value())
646 {
647 setNull(index);
648 return;
649 }
650
651 assert(isValid());
652
653 const auto& value = optValue.value();
654 const auto& descriptor = getInDescriptor(index);
655 const auto message = inMessage.data();
656
657 switch (descriptor.adjustedType)
658 {
660 *reinterpret_cast<OpaqueDecFloat34*>(&message[descriptor.offset]) = value;
661 break;
662
663 default:
664 throwInvalidType("OpaqueDecFloat34", descriptor.adjustedType);
665 }
666
667 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
668 }
669
670#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
674 void setBoostDecFloat34(unsigned index, std::optional<BoostDecFloat34> optValue)
675 {
676 if (!optValue.has_value())
677 {
678 setNull(index);
679 return;
680 }
681
682 setNumber(index, DescriptorAdjustedType::DECFLOAT34, optValue.value(), 0, "BoostDecFloat34");
683 }
684#endif
685
689 void setDate(unsigned index, std::optional<Date> optValue)
690 {
691 if (!optValue.has_value())
692 {
693 setNull(index);
694 return;
695 }
696
697 assert(isValid());
698
699 const auto& value = optValue.value();
700 const auto& descriptor = getInDescriptor(index);
701 const auto message = inMessage.data();
702
703 switch (descriptor.adjustedType)
704 {
706 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) =
707 calendarConverter.dateToOpaqueDate(value);
708 break;
709
710 default:
711 throwInvalidType("Date", descriptor.adjustedType);
712 }
713
714 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
715 }
716
720 void setOpaqueDate(unsigned index, std::optional<OpaqueDate> optValue)
721 {
722 if (!optValue.has_value())
723 {
724 setNull(index);
725 return;
726 }
727
728 assert(isValid());
729
730 const auto& value = optValue.value();
731 const auto& descriptor = getInDescriptor(index);
732 const auto message = inMessage.data();
733
734 switch (descriptor.adjustedType)
735 {
737 *reinterpret_cast<OpaqueDate*>(&message[descriptor.offset]) = value;
738 break;
739
740 default:
741 throwInvalidType("OpaqueDate", descriptor.adjustedType);
742 }
743
744 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
745 }
746
750 void setTime(unsigned index, std::optional<Time> 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 {
767 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) =
768 calendarConverter.timeToOpaqueTime(value);
769 break;
770
771 default:
772 throwInvalidType("Time", descriptor.adjustedType);
773 }
774
775 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
776 }
777
781 void setOpaqueTime(unsigned index, std::optional<OpaqueTime> optValue)
782 {
783 if (!optValue.has_value())
784 {
785 setNull(index);
786 return;
787 }
788
789 assert(isValid());
790
791 const auto& value = optValue.value();
792 const auto& descriptor = getInDescriptor(index);
793 const auto message = inMessage.data();
794
795 switch (descriptor.adjustedType)
796 {
798 *reinterpret_cast<OpaqueTime*>(&message[descriptor.offset]) = value;
799 break;
800
801 default:
802 throwInvalidType("OpaqueTime", descriptor.adjustedType);
803 }
804
805 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
806 }
807
811 void setTimestamp(unsigned index, std::optional<Timestamp> 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 {
828 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) =
829 calendarConverter.timestampToOpaqueTimestamp(value);
830 break;
831
832 default:
833 throwInvalidType("Timestamp", descriptor.adjustedType);
834 }
835
836 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
837 }
838
842 void setOpaqueTimestamp(unsigned index, std::optional<OpaqueTimestamp> optValue)
843 {
844 if (!optValue.has_value())
845 {
846 setNull(index);
847 return;
848 }
849
850 assert(isValid());
851
852 const auto& value = optValue.value();
853 const auto& descriptor = getInDescriptor(index);
854 const auto message = inMessage.data();
855
856 switch (descriptor.adjustedType)
857 {
859 *reinterpret_cast<OpaqueTimestamp*>(&message[descriptor.offset]) = value;
860 break;
861
862 default:
863 throwInvalidType("OpaqueTimestamp", descriptor.adjustedType);
864 }
865
866 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
867 }
868
872 void setTimeTz(unsigned index, std::optional<TimeTz> 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 auto* const message = inMessage.data();
885
886 switch (descriptor.adjustedType)
887 {
889 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) =
890 calendarConverter.timeTzToOpaqueTimeTz(&statusWrapper, value);
891 break;
892
893 default:
894 throwInvalidType("TimeTz", descriptor.adjustedType);
895 }
896
897 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
898 }
899
903 void setOpaqueTimeTz(unsigned index, std::optional<OpaqueTimeTz> optValue)
904 {
905 if (!optValue.has_value())
906 {
907 setNull(index);
908 return;
909 }
910
911 assert(isValid());
912
913 const auto& value = optValue.value();
914 const auto& descriptor = getInDescriptor(index);
915 auto* const message = inMessage.data();
916
917 switch (descriptor.adjustedType)
918 {
920 *reinterpret_cast<OpaqueTimeTz*>(&message[descriptor.offset]) = value;
921 break;
922
923 default:
924 throwInvalidType("OpaqueTimeTz", descriptor.adjustedType);
925 }
926
927 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
928 }
929
933 void setTimestampTz(unsigned index, std::optional<TimestampTz> 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 {
950 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) =
951 calendarConverter.timestampTzToOpaqueTimestampTz(&statusWrapper, value);
952 break;
953
954 default:
955 throwInvalidType("TimestampTz", descriptor.adjustedType);
956 }
957
958 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
959 }
960
964 void setOpaqueTimestampTz(unsigned index, std::optional<OpaqueTimestampTz> optValue)
965 {
966 if (!optValue.has_value())
967 {
968 setNull(index);
969 return;
970 }
971
972 assert(isValid());
973
974 const auto& value = optValue.value();
975 const auto& descriptor = getInDescriptor(index);
976 auto* const message = inMessage.data();
977
978 switch (descriptor.adjustedType)
979 {
981 *reinterpret_cast<OpaqueTimestampTz*>(&message[descriptor.offset]) = value;
982 break;
983
984 default:
985 throwInvalidType("OpaqueTimestampTz", descriptor.adjustedType);
986 }
987
988 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
989 }
990
994 void setString(unsigned index, std::optional<std::string_view> optValue)
995 {
996 if (!optValue.has_value())
997 {
998 setNull(index);
999 return;
1000 }
1001
1002 assert(isValid());
1003
1004 auto& client = getClient();
1005 const auto value = optValue.value();
1006 const auto& descriptor = getInDescriptor(index);
1007 const auto message = inMessage.data();
1008 const auto data = &message[descriptor.offset];
1009
1010 switch (descriptor.adjustedType)
1011 {
1013 message[descriptor.offset] = numericConverter.stringToBoolean(value);
1014 break;
1015
1019 {
1020 std::string strValue(value);
1021 int scale = 0;
1022
1023 if (const auto dotPos = strValue.find_last_of('.'); dotPos != std::string_view::npos)
1024 {
1025 for (auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1026 {
1027 const char c = value[pos];
1028
1029 if (c < '0' || c > '9')
1030 break;
1031
1032 --scale;
1033 }
1034
1035 strValue.erase(dotPos, 1);
1036 }
1037
1038 static_assert(sizeof(long long) == sizeof(std::int64_t));
1039 std::int64_t intValue;
1040 const auto convResult =
1041 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1042 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1043 numericConverter.throwConversionErrorFromString(strValue);
1044 auto scaledValue = ScaledInt64{intValue, scale};
1045
1046 if (scale != descriptor.scale)
1047 {
1049 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1050 scaledValue.scale = descriptor.scale;
1051 }
1052
1054 return;
1055 }
1056
1058 {
1059 std::string strValue(value);
1060 client.getInt128Util(&statusWrapper)
1061 ->fromString(
1062 &statusWrapper, descriptor.scale, strValue.c_str(), reinterpret_cast<OpaqueInt128*>(data));
1063 break;
1064 }
1065
1068 {
1069 double doubleValue;
1070#if defined(__APPLE__)
1071 errno = 0;
1072 std::string valueString{value};
1073 char* parseEnd = nullptr;
1074 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1075 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1076 numericConverter.throwConversionErrorFromString(std::move(valueString));
1077#else
1078 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1079 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1080 numericConverter.throwConversionErrorFromString(std::string{value});
1081#endif
1082 setDouble(index, doubleValue);
1083 return;
1084 }
1085
1087 *reinterpret_cast<OpaqueDate*>(data) = calendarConverter.stringToOpaqueDate(value);
1088 break;
1089
1091 *reinterpret_cast<OpaqueTime*>(data) = calendarConverter.stringToOpaqueTime(value);
1092 break;
1093
1095 *reinterpret_cast<OpaqueTimestamp*>(data) = calendarConverter.stringToOpaqueTimestamp(value);
1096 break;
1097
1099 *reinterpret_cast<OpaqueTimeTz*>(data) =
1100 calendarConverter.stringToOpaqueTimeTz(&statusWrapper, value);
1101 break;
1102
1104 *reinterpret_cast<OpaqueTimestampTz*>(data) =
1105 calendarConverter.stringToOpaqueTimestampTz(&statusWrapper, value);
1106 break;
1107
1108#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1110 {
1111 std::string strValue{value};
1112 client.getDecFloat16Util(&statusWrapper)
1113 ->fromString(&statusWrapper, strValue.c_str(), reinterpret_cast<OpaqueDecFloat16*>(data));
1114 break;
1115 }
1116
1118 {
1119 std::string strValue{value};
1120 client.getDecFloat34Util(&statusWrapper)
1121 ->fromString(&statusWrapper, strValue.c_str(), reinterpret_cast<OpaqueDecFloat34*>(data));
1122 break;
1123 }
1124#endif
1125
1127 if (value.length() > descriptor.length)
1128 {
1129 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1133 };
1134
1136 }
1137
1138 *reinterpret_cast<std::uint16_t*>(data) = static_cast<std::uint16_t>(value.length());
1139 std::copy(value.begin(), value.end(),
1140 reinterpret_cast<char*>(&message[descriptor.offset + sizeof(std::uint16_t)]));
1141 break;
1142
1143 default:
1144 throwInvalidType("std::string_view", descriptor.adjustedType);
1145 }
1146
1147 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1148 }
1149
1153 void setBlobId(unsigned index, std::optional<BlobId> optValue)
1154 {
1155 if (!optValue.has_value())
1156 {
1157 setNull(index);
1158 return;
1159 }
1160
1161 assert(isValid());
1162
1163 const auto& value = optValue.value();
1164 const auto& descriptor = getInDescriptor(index);
1165 auto* const message = inMessage.data();
1166
1167 switch (descriptor.adjustedType)
1168 {
1170 *reinterpret_cast<ISC_QUAD*>(&message[descriptor.offset]) = value.id;
1171 break;
1172
1173 default:
1174 throwInvalidType("BlobId", descriptor.adjustedType);
1175 }
1176
1177 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1178 }
1179
1182 void set(unsigned index, std::nullopt_t)
1183 {
1184 setNull(index);
1185 }
1186
1190 void set(unsigned index, BlobId value)
1191 {
1192 setBlobId(index, value);
1193 }
1194
1198 void set(unsigned index, std::optional<BlobId> value)
1199 {
1200 setBlobId(index, value);
1201 }
1202
1206 void set(unsigned index, bool value)
1207 {
1208 setBool(index, value);
1209 }
1210
1214 void set(unsigned index, std::int16_t value)
1215 {
1216 setInt16(index, value);
1217 }
1218
1222 void set(unsigned index, ScaledInt16 value)
1223 {
1224 setScaledInt16(index, value);
1225 }
1226
1230 void set(unsigned index, std::int32_t value)
1231 {
1232 setInt32(index, value);
1233 }
1234
1238 void set(unsigned index, ScaledInt32 value)
1239 {
1240 setScaledInt32(index, value);
1241 }
1242
1246 void set(unsigned index, std::int64_t value)
1247 {
1248 setInt64(index, value);
1249 }
1250
1254 void set(unsigned index, ScaledInt64 value)
1255 {
1256 setScaledInt64(index, value);
1257 }
1258
1262 void set(unsigned index, OpaqueInt128 value)
1263 {
1264 setOpaqueInt128(index, value);
1265 }
1266
1267#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1271 void set(unsigned index, BoostInt128 value)
1272 {
1273 setBoostInt128(index, value);
1274 }
1275
1279 void set(unsigned index, ScaledBoostInt128 value)
1280 {
1281 setScaledBoostInt128(index, value);
1282 }
1283#endif
1284
1288 void set(unsigned index, float value)
1289 {
1290 setFloat(index, value);
1291 }
1292
1296 void set(unsigned index, double value)
1297 {
1298 setDouble(index, value);
1299 }
1300
1304 void set(unsigned index, OpaqueDecFloat16 value)
1305 {
1306 setOpaqueDecFloat16(index, value);
1307 }
1308
1309#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1313 void set(unsigned index, BoostDecFloat16 value)
1314 {
1315 setBoostDecFloat16(index, value);
1316 }
1317#endif
1318
1322 void set(unsigned index, OpaqueDecFloat34 value)
1323 {
1324 setOpaqueDecFloat34(index, value);
1325 }
1326
1327#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1331 void set(unsigned index, BoostDecFloat34 value)
1332 {
1333 setBoostDecFloat34(index, value);
1334 }
1335#endif
1336
1340 void set(unsigned index, Date value)
1341 {
1342 setDate(index, value);
1343 }
1344
1348 void set(unsigned index, OpaqueDate value)
1349 {
1350 setOpaqueDate(index, value);
1351 }
1352
1356 void set(unsigned index, Time value)
1357 {
1358 setTime(index, value);
1359 }
1360
1364 void set(unsigned index, OpaqueTime value)
1365 {
1366 setOpaqueTime(index, value);
1367 }
1368
1372 void set(unsigned index, Timestamp value)
1373 {
1374 setTimestamp(index, value);
1375 }
1376
1380 void set(unsigned index, OpaqueTimestamp value)
1381 {
1382 setOpaqueTimestamp(index, value);
1383 }
1384
1388 void set(unsigned index, TimeTz value)
1389 {
1390 setTimeTz(index, value);
1391 }
1392
1396 void set(unsigned index, OpaqueTimeTz value)
1397 {
1398 setOpaqueTimeTz(index, value);
1399 }
1400
1404 void set(unsigned index, TimestampTz value)
1405 {
1406 setTimestampTz(index, value);
1407 }
1408
1412 void set(unsigned index, OpaqueTimestampTz value)
1413 {
1414 setOpaqueTimestampTz(index, value);
1415 }
1416
1420 void set(unsigned index, std::string_view value)
1421 {
1422 setString(index, value);
1423 }
1424
1428 template <typename T>
1429 void set(unsigned index, std::optional<T> value)
1430 {
1431 if (value.has_value())
1432 set(index, value.value());
1433 else
1434 setNull(index);
1435 }
1436
1440
1444
1448 bool isNull(unsigned index)
1449 {
1450 assert(isValid());
1451 return outRow->isNull(index);
1452 }
1453
1457 std::optional<bool> getBool(unsigned index)
1458 {
1459 assert(isValid());
1460 return outRow->getBool(index);
1461 }
1462
1466 std::optional<std::int16_t> getInt16(unsigned index)
1467 {
1468 assert(isValid());
1469 return outRow->getInt16(index);
1470 }
1471
1475 std::optional<ScaledInt16> getScaledInt16(unsigned index)
1476 {
1477 assert(isValid());
1478 return outRow->getScaledInt16(index);
1479 }
1480
1484 std::optional<std::int32_t> getInt32(unsigned index)
1485 {
1486 assert(isValid());
1487 return outRow->getInt32(index);
1488 }
1489
1493 std::optional<ScaledInt32> getScaledInt32(unsigned index)
1494 {
1495 assert(isValid());
1496 return outRow->getScaledInt32(index);
1497 }
1498
1502 std::optional<std::int64_t> getInt64(unsigned index)
1503 {
1504 assert(isValid());
1505 return outRow->getInt64(index);
1506 }
1507
1511 std::optional<ScaledInt64> getScaledInt64(unsigned index)
1512 {
1513 assert(isValid());
1514 return outRow->getScaledInt64(index);
1515 }
1516
1520 std::optional<ScaledOpaqueInt128> getScaledOpaqueInt128(unsigned index)
1521 {
1522 assert(isValid());
1523 return outRow->getScaledOpaqueInt128(index);
1524 }
1525
1526#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1530 std::optional<BoostInt128> getBoostInt128(unsigned index)
1531 {
1532 assert(isValid());
1533 return outRow->getBoostInt128(index);
1534 }
1535
1539 std::optional<ScaledBoostInt128> getScaledBoostInt128(unsigned index)
1540 {
1541 assert(isValid());
1542 return outRow->getScaledBoostInt128(index);
1543 }
1544#endif
1545
1549 std::optional<float> getFloat(unsigned index)
1550 {
1551 assert(isValid());
1552 return outRow->getFloat(index);
1553 }
1554
1558 std::optional<double> getDouble(unsigned index)
1559 {
1560 assert(isValid());
1561 return outRow->getDouble(index);
1562 }
1563
1567 std::optional<OpaqueDecFloat16> getOpaqueDecFloat16(unsigned index)
1568 {
1569 assert(isValid());
1570 return outRow->getOpaqueDecFloat16(index);
1571 }
1572
1573#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1577 std::optional<BoostDecFloat16> getBoostDecFloat16(unsigned index)
1578 {
1579 assert(isValid());
1580 return outRow->getBoostDecFloat16(index);
1581 }
1582#endif
1583
1587 std::optional<OpaqueDecFloat34> getOpaqueDecFloat34(unsigned index)
1588 {
1589 assert(isValid());
1590 return outRow->getOpaqueDecFloat34(index);
1591 }
1592
1593#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1597 std::optional<BoostDecFloat34> getBoostDecFloat34(unsigned index)
1598 {
1599 assert(isValid());
1600 return outRow->getBoostDecFloat34(index);
1601 }
1602#endif
1603
1607 std::optional<Date> getDate(unsigned index)
1608 {
1609 assert(isValid());
1610 return outRow->getDate(index);
1611 }
1612
1616 std::optional<OpaqueDate> getOpaqueDate(unsigned index)
1617 {
1618 assert(isValid());
1619 return outRow->getOpaqueDate(index);
1620 }
1621
1625 std::optional<Time> getTime(unsigned index)
1626 {
1627 assert(isValid());
1628 return outRow->getTime(index);
1629 }
1630
1634 std::optional<OpaqueTime> getOpaqueTime(unsigned index)
1635 {
1636 assert(isValid());
1637 return outRow->getOpaqueTime(index);
1638 }
1639
1643 std::optional<Timestamp> getTimestamp(unsigned index)
1644 {
1645 assert(isValid());
1646 return outRow->getTimestamp(index);
1647 }
1648
1652 std::optional<OpaqueTimestamp> getOpaqueTimestamp(unsigned index)
1653 {
1654 assert(isValid());
1655 return outRow->getOpaqueTimestamp(index);
1656 }
1657
1661 std::optional<TimeTz> getTimeTz(unsigned index)
1662 {
1663 assert(isValid());
1664 return outRow->getTimeTz(index);
1665 }
1666
1670 std::optional<OpaqueTimeTz> getOpaqueTimeTz(unsigned index)
1671 {
1672 assert(isValid());
1673 return outRow->getOpaqueTimeTz(index);
1674 }
1675
1679 std::optional<TimestampTz> getTimestampTz(unsigned index)
1680 {
1681 assert(isValid());
1682 return outRow->getTimestampTz(index);
1683 }
1684
1688 std::optional<OpaqueTimestampTz> getOpaqueTimestampTz(unsigned index)
1689 {
1690 assert(isValid());
1691 return outRow->getOpaqueTimestampTz(index);
1692 }
1693
1697 std::optional<BlobId> getBlobId(unsigned index)
1698 {
1699 assert(isValid());
1700 return outRow->getBlobId(index);
1701 }
1702
1706 std::optional<std::string> getString(unsigned index)
1707 {
1708 assert(isValid());
1709 return outRow->getString(index);
1710 }
1711
1715
1719 template <typename T>
1720 T get(unsigned index)
1721 {
1722 assert(isValid());
1723 return outRow->get<T>(index);
1724 }
1725
1733 template <Aggregate T>
1735 {
1736 assert(isValid());
1737 return outRow->get<T>();
1738 }
1739
1746 template <Aggregate T>
1747 void set(const T& value)
1748 {
1749 using namespace impl::reflection;
1750
1751 constexpr std::size_t N = fieldCountV<T>;
1752
1753 if (N != inDescriptors.size())
1754 {
1755 throw FbCppException("Struct field count (" + std::to_string(N) +
1756 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) + ")");
1757 }
1758
1759 setStruct(value, std::make_index_sequence<N>{});
1760 }
1761
1769 template <TupleLike T>
1771 {
1772 assert(isValid());
1773 return outRow->get<T>();
1774 }
1775
1782 template <TupleLike T>
1783 void set(const T& value)
1784 {
1785 constexpr std::size_t N = std::tuple_size_v<T>;
1786
1787 if (N != inDescriptors.size())
1788 {
1789 throw FbCppException("Tuple element count (" + std::to_string(N) +
1790 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) + ")");
1791 }
1792
1793 setTuple(value, std::make_index_sequence<N>{});
1794 }
1795
1804 template <VariantLike V>
1805 V get(unsigned index)
1806 {
1807 assert(isValid());
1808 return outRow->get<V>(index);
1809 }
1810
1817 template <VariantLike V>
1818 void set(unsigned index, const V& value)
1819 {
1820 using namespace impl::reflection;
1821
1823 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
1824 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
1825 "complete list of supported types.");
1826
1827 std::visit(
1828 [this, index](const auto& v)
1829 {
1830 using T = std::decay_t<decltype(v)>;
1831
1832 if constexpr (std::is_same_v<T, std::monostate>)
1833 setNull(index);
1834 else
1835 set(index, v);
1836 },
1837 value);
1838 }
1839
1840 private:
1844 const Descriptor& getInDescriptor(unsigned index)
1845 {
1846 if (index >= inDescriptors.size())
1847 throw std::out_of_range("index out of range");
1848
1849 return inDescriptors[index];
1850 }
1851
1855 template <typename T, std::size_t... Is>
1856 void setStruct(const T& value, std::index_sequence<Is...>)
1857 {
1858 using namespace impl::reflection;
1859
1860 const auto tuple = toTupleRef(value);
1861 (set(static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
1862 }
1863
1867 template <typename T, std::size_t... Is>
1868 void setTuple(const T& value, std::index_sequence<Is...>)
1869 {
1870 (set(static_cast<unsigned>(Is), std::get<Is>(value)), ...);
1871 }
1872
1876 template <typename T>
1877 void setNumber(unsigned index, DescriptorAdjustedType valueType, T value, int scale, const char* typeName)
1878 {
1879 assert(isValid());
1880
1881 const auto& descriptor = getInDescriptor(index);
1882 auto* const message = inMessage.data();
1883
1884 const auto descriptorData = &message[descriptor.offset];
1885 std::optional<int> descriptorScale{descriptor.scale};
1886
1887 Descriptor valueDescriptor;
1888 valueDescriptor.adjustedType = valueType;
1889 valueDescriptor.scale = scale;
1890
1891 const auto valueAddress = reinterpret_cast<const std::byte*>(&value);
1892
1893 switch (descriptor.adjustedType)
1894 {
1896 *reinterpret_cast<std::int16_t*>(descriptorData) =
1898 break;
1899
1901 *reinterpret_cast<std::int32_t*>(descriptorData) =
1903 break;
1904
1906 *reinterpret_cast<std::int64_t*>(descriptorData) =
1908 break;
1909
1910#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1912 {
1913 const auto boostInt128 =
1915 *reinterpret_cast<OpaqueInt128*>(descriptorData) =
1916 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
1917 break;
1918 }
1919#endif
1920
1922 *reinterpret_cast<float*>(descriptorData) =
1924 break;
1925
1927 *reinterpret_cast<double*>(descriptorData) =
1929 break;
1930
1931#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1933 {
1935 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat16");
1936 *reinterpret_cast<OpaqueDecFloat16*>(descriptorData) =
1937 numericConverter.boostDecFloat16ToOpaqueDecFloat16(&statusWrapper, boostDecFloat16);
1938 break;
1939 }
1940
1942 {
1944 valueDescriptor, valueAddress, descriptorScale, "BoostDecFloat34");
1945 *reinterpret_cast<OpaqueDecFloat34*>(descriptorData) =
1946 numericConverter.boostDecFloat34ToOpaqueDecFloat34(&statusWrapper, boostDecFloat34);
1947 break;
1948 }
1949#endif
1950
1951 default:
1952 throwInvalidType(typeName, descriptor.adjustedType);
1953 }
1954
1955 *reinterpret_cast<std::int16_t*>(&message[descriptor.nullOffset]) = FB_FALSE;
1956 }
1957
1958 [[noreturn]] static void throwInvalidType(const char* actualType, DescriptorAdjustedType descriptorType)
1959 {
1960 throw FbCppException("Invalid type: actual type " + std::string(actualType) + ", descriptor type " +
1961 std::to_string(static_cast<unsigned>(descriptorType)));
1962 }
1963
1964 template <typename T>
1965 T convertNumber(
1966 const Descriptor& descriptor, const std::byte* data, std::optional<int>& toScale, const char* toTypeName)
1967 {
1968 if (!toScale.has_value())
1969 {
1970 switch (descriptor.adjustedType)
1971 {
1976 throwInvalidType(toTypeName, descriptor.adjustedType);
1977
1978 default:
1979 break;
1980 }
1981
1982 toScale = descriptor.scale;
1983 }
1984
1985 switch (descriptor.adjustedType)
1986 {
1988 return numericConverter.numberToNumber<T>(
1989 ScaledInt16{*reinterpret_cast<const std::int16_t*>(data), descriptor.scale}, toScale.value());
1990 break;
1991
1993 return numericConverter.numberToNumber<T>(
1994 ScaledInt32{*reinterpret_cast<const std::int32_t*>(data), descriptor.scale}, toScale.value());
1995
1997 return numericConverter.numberToNumber<T>(
1998 ScaledInt64{*reinterpret_cast<const std::int64_t*>(data), descriptor.scale}, toScale.value());
1999
2000#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2002 return numericConverter.numberToNumber<T>(
2003 ScaledBoostInt128{*reinterpret_cast<const BoostInt128*>(data), descriptor.scale},
2004 toScale.value());
2005
2007 return numericConverter.numberToNumber<T>(
2008 *reinterpret_cast<const BoostDecFloat16*>(data), toScale.value());
2009
2011 return numericConverter.numberToNumber<T>(
2012 *reinterpret_cast<const BoostDecFloat34*>(data), toScale.value());
2013#endif
2014
2016 return numericConverter.numberToNumber<T>(*reinterpret_cast<const float*>(data), toScale.value());
2017 break;
2018
2020 return numericConverter.numberToNumber<T>(*reinterpret_cast<const double*>(data), toScale.value());
2021 break;
2022
2023 default:
2024 throwInvalidType(toTypeName, descriptor.adjustedType);
2025 }
2026 }
2027
2028 private:
2029 Client& getClient() noexcept;
2030
2031 private:
2032 Attachment* attachment;
2033 impl::StatusWrapper statusWrapper;
2034 impl::CalendarConverter calendarConverter;
2035 impl::NumericConverter numericConverter;
2036 FbRef<fb::IStatement> statementHandle;
2037 FbRef<fb::IResultSet> resultSetHandle;
2038 FbRef<fb::IMessageMetadata> inMetadata;
2039 std::vector<Descriptor> inDescriptors;
2040 std::vector<std::byte> inMessage;
2041 FbRef<fb::IMessageMetadata> outMetadata;
2042 std::vector<Descriptor> outDescriptors;
2043 std::vector<std::byte> outMessage;
2044 std::unique_ptr<Row> outRow;
2045 StatementType type;
2046 unsigned cursorFlags = 0;
2047 };
2048
2053
2054 template <>
2055 inline std::optional<bool> Statement::get<std::optional<bool>>(unsigned index)
2056 {
2057 return getBool(index);
2058 }
2059
2060 template <>
2061 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(unsigned index)
2062 {
2063 return getBlobId(index);
2064 }
2065
2066 template <>
2067 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(unsigned index)
2068 {
2069 return getInt16(index);
2070 }
2071
2072 template <>
2073 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(unsigned index)
2074 {
2075 return getScaledInt16(index);
2076 }
2077
2078 template <>
2079 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(unsigned index)
2080 {
2081 return getInt32(index);
2082 }
2083
2084 template <>
2085 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(unsigned index)
2086 {
2087 return getScaledInt32(index);
2088 }
2089
2090 template <>
2091 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(unsigned index)
2092 {
2093 return getInt64(index);
2094 }
2095
2096 template <>
2097 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(unsigned index)
2098 {
2099 return getScaledInt64(index);
2100 }
2101
2102 template <>
2103 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(unsigned index)
2104 {
2105 return getScaledOpaqueInt128(index);
2106 }
2107
2108#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2109 template <>
2110 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(unsigned index)
2111 {
2112 return getBoostInt128(index);
2113 }
2114
2115 template <>
2116 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(unsigned index)
2117 {
2118 return getScaledBoostInt128(index);
2119 }
2120#endif
2121
2122 template <>
2123 inline std::optional<float> Statement::get<std::optional<float>>(unsigned index)
2124 {
2125 return getFloat(index);
2126 }
2127
2128 template <>
2129 inline std::optional<double> Statement::get<std::optional<double>>(unsigned index)
2130 {
2131 return getDouble(index);
2132 }
2133
2134 template <>
2135 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(unsigned index)
2136 {
2137 return getOpaqueDecFloat16(index);
2138 }
2139
2140#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2141 template <>
2142 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(unsigned index)
2143 {
2144 return getBoostDecFloat16(index);
2145 }
2146#endif
2147
2148 template <>
2149 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(unsigned index)
2150 {
2151 return getOpaqueDecFloat34(index);
2152 }
2153
2154#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2155 template <>
2156 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(unsigned index)
2157 {
2158 return getBoostDecFloat34(index);
2159 }
2160#endif
2161
2162 template <>
2163 inline std::optional<Date> Statement::get<std::optional<Date>>(unsigned index)
2164 {
2165 return getDate(index);
2166 }
2167
2168 template <>
2169 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(unsigned index)
2170 {
2171 return getOpaqueDate(index);
2172 }
2173
2174 template <>
2175 inline std::optional<Time> Statement::get<std::optional<Time>>(unsigned index)
2176 {
2177 return getTime(index);
2178 }
2179
2180 template <>
2181 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(unsigned index)
2182 {
2183 return getOpaqueTime(index);
2184 }
2185
2186 template <>
2187 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(unsigned index)
2188 {
2189 return getOpaqueTimestamp(index);
2190 }
2191
2192 template <>
2193 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(unsigned index)
2194 {
2195 return getTimestamp(index);
2196 }
2197
2198 template <>
2199 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(unsigned index)
2200 {
2201 return getTimeTz(index);
2202 }
2203
2204 template <>
2205 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(unsigned index)
2206 {
2207 return getOpaqueTimeTz(index);
2208 }
2209
2210 template <>
2211 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(unsigned index)
2212 {
2213 return getTimestampTz(index);
2214 }
2215
2216 template <>
2217 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(unsigned index)
2218 {
2219 return getOpaqueTimestampTz(index);
2220 }
2221
2222 template <>
2223 inline std::optional<std::string> Statement::get<std::optional<std::string>>(unsigned index)
2224 {
2225 return getString(index);
2226 }
2227
2231} // namespace fbcpp
2232
2233
2234#endif // FBCPP_STATEMENT_H
Represents a connection to a Firebird database.
Definition Attachment.h:218
Represents a Firebird blob identifier.
Definition Blob.h:52
Exception thrown when a Firebird database operation fails.
Definition Exception.h:247
Base exception class for all fb-cpp exceptions.
Definition Exception.h:230
Reference-counted smart pointer for Firebird objects using addRef/release semantics.
Definition SmartPtrs.h:70
Represents options used when preparing a Statement.
Prepares, executes, and fetches SQL statements against a Firebird attachment.
Definition Statement.h:138
void set(unsigned index, OpaqueInt128 value)
Convenience overload that binds a Firebird 128-bit integer.
Definition Statement.h:1262
void setScaledInt16(unsigned index, std::optional< ScaledInt16 > optValue)
Binds a scaled 16-bit signed integer value or null.
Definition Statement.h:435
V get(unsigned index)
Retrieves a column value as a user-defined variant type.
Definition Statement.h:1805
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:376
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:553
std::optional< OpaqueTime > getOpaqueTime(unsigned index)
Reads a raw time-of-day column in Firebird's representation.
Definition Statement.h:1634
std::optional< OpaqueDecFloat34 > getOpaqueDecFloat34(unsigned index)
Reads a Firebird 34-digit decimal floating-point column.
Definition Statement.h:1587
std::vector< std::byte > & getOutputMessage() noexcept
Provides direct access to the raw output message buffer.
Definition Statement.h:252
void setDate(unsigned index, std::optional< Date > optValue)
Binds a date value or null.
Definition Statement.h:689
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:278
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:286
bool isValid() noexcept
Returns whether the Statement object is valid.
Definition Statement.h:202
StatementType getType() noexcept
Returns the type classification reported by the server.
Definition Statement.h:260
void set(unsigned index, BoostDecFloat16 value)
Convenience overload that binds a Boost 16-digit decimal floating-point value.
Definition Statement.h:1313
std::optional< TimeTz > getTimeTz(unsigned index)
Reads a time-of-day column with timezone.
Definition Statement.h:1661
void setTime(unsigned index, std::optional< Time > optValue)
Binds a time-of-day value without timezone or null.
Definition Statement.h:750
void set(unsigned index, std::string_view value)
Convenience overload that binds a textual value.
Definition Statement.h:1420
std::optional< BoostDecFloat34 > getBoostDecFloat34(unsigned index)
Reads a Boost-based 34-digit decimal floating-point column.
Definition Statement.h:1597
void setBlobId(unsigned index, std::optional< BlobId > optValue)
Binds a blob identifier to the specified parameter or null.
Definition Statement.h:1153
void setInt16(unsigned index, std::optional< std::int16_t > optValue)
Binds a 16-bit signed integer value or null.
Definition Statement.h:421
void setString(unsigned index, std::optional< std::string_view > optValue)
Binds a textual parameter or null, performing direct conversions where supported.
Definition Statement.h:994
void set(unsigned index, std::int32_t value)
Convenience overload that binds a 32-bit signed integer.
Definition Statement.h:1230
std::optional< Time > getTime(unsigned index)
Reads a time-of-day column without timezone.
Definition Statement.h:1625
std::optional< Date > getDate(unsigned index)
Reads a date column.
Definition Statement.h:1607
FbRef< fb::IResultSet > getResultSetHandle() noexcept
Provides access to the underlying Firebird currently open result set handle, if any.
Definition Statement.h:220
bool isNull(unsigned index)
Reports whether the most recently fetched row has a null at the given column.
Definition Statement.h:1448
void set(unsigned index, double value)
Convenience overload that binds a double precision floating-point value.
Definition Statement.h:1296
void clearParameters()
Marks all bound parameters as null values.
Definition Statement.h:362
void set(unsigned index, ScaledInt64 value)
Convenience overload that binds a scaled 64-bit signed integer.
Definition Statement.h:1254
std::optional< OpaqueDate > getOpaqueDate(unsigned index)
Reads a raw date column in Firebird's representation.
Definition Statement.h:1616
T get()
Retrieves all output columns into a user-defined aggregate struct.
Definition Statement.h:1734
void setScaledInt32(unsigned index, std::optional< ScaledInt32 > optValue)
Binds a scaled 32-bit signed integer value or null.
Definition Statement.h:464
void set(unsigned index, std::int64_t value)
Convenience overload that binds a 64-bit signed integer.
Definition Statement.h:1246
void setTimestampTz(unsigned index, std::optional< TimestampTz > optValue)
Binds a timestamp value with timezone or null.
Definition Statement.h:933
std::optional< std::int64_t > getInt64(unsigned index)
Reads a 64-bit signed integer column.
Definition Statement.h:1502
FbRef< fb::IStatement > getStatementHandle() noexcept
Provides direct access to the underlying Firebird statement handle.
Definition Statement.h:211
std::optional< ScaledInt32 > getScaledInt32(unsigned index)
Reads a scaled 32-bit signed integer column.
Definition Statement.h:1493
void set(unsigned index, OpaqueTimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1412
void setOpaqueTime(unsigned index, std::optional< OpaqueTime > optValue)
Binds a raw time-of-day value in Firebird's representation or null.
Definition Statement.h:781
std::optional< float > getFloat(unsigned index)
Reads a single precision floating-point column.
Definition Statement.h:1549
std::optional< double > getDouble(unsigned index)
Reads a double precision floating-point column.
Definition Statement.h:1558
std::optional< OpaqueTimestampTz > getOpaqueTimestampTz(unsigned index)
Reads a raw timestamp-with-time-zone column in Firebird's representation.
Definition Statement.h:1688
std::optional< ScaledInt16 > getScaledInt16(unsigned index)
Reads a scaled 16-bit signed integer column.
Definition Statement.h:1475
std::optional< BlobId > getBlobId(unsigned index)
Reads a blob identifier column.
Definition Statement.h:1697
void setInt64(unsigned index, std::optional< std::int64_t > optValue)
Binds a 64-bit signed integer value or null.
Definition Statement.h:479
std::optional< ScaledOpaqueInt128 > getScaledOpaqueInt128(unsigned index)
Reads a Firebird scaled 128-bit integer column.
Definition Statement.h:1520
FbRef< fb::IMessageMetadata > getOutputMetadata() noexcept
Returns the metadata describing columns produced by the statement.
Definition Statement.h:244
void set(unsigned index, TimeTz value)
Convenience overload that binds a Firebird time with timezone value.
Definition Statement.h:1388
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:597
void setOpaqueInt128(unsigned index, std::optional< OpaqueInt128 > optValue)
Binds a raw 128-bit integer value in Firebird's representation or null.
Definition Statement.h:508
std::optional< OpaqueTimeTz > getOpaqueTimeTz(unsigned index)
Reads a raw time-of-day column with timezone in Firebird's representation.
Definition Statement.h:1670
void setBoostInt128(unsigned index, std::optional< BoostInt128 > optValue)
Binds a 128-bit integer value expressed with Boost.Multiprecision or null.
Definition Statement.h:539
Statement & operator=(Statement &&o) noexcept
Transfers ownership of another prepared statement into this one.
void set(unsigned index, Date value)
Convenience overload that binds a Firebird date value.
Definition Statement.h:1340
void set(unsigned index, Timestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1372
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:903
void setTimestamp(unsigned index, std::optional< Timestamp > optValue)
Binds a timestamp value without timezone or null.
Definition Statement.h:811
std::optional< std::string > getString(unsigned index)
Reads a textual column, applying number-to-string conversions when needed.
Definition Statement.h:1706
std::optional< std::int32_t > getInt32(unsigned index)
Reads a 32-bit signed integer column.
Definition Statement.h:1484
void set(unsigned index, OpaqueDecFloat16 value)
Convenience overload that binds a Firebird 16-digit decimal floating-point value.
Definition Statement.h:1304
void setOpaqueTimestampTz(unsigned index, std::optional< OpaqueTimestampTz > optValue)
Binds a raw timestamp value with timezone in Firebird's representation or null.
Definition Statement.h:964
FbRef< fb::IMessageMetadata > getInputMetadata() noexcept
Returns the metadata describing prepared input parameters.
Definition Statement.h:228
~Statement() noexcept
Releases resources; ignores failures to keep destructor noexcept.
Definition Statement.h:169
void set(unsigned index, OpaqueTimeTz value)
Convenience overload that binds a Firebird time with timezone value.
Definition Statement.h:1396
void setBoostDecFloat16(unsigned index, std::optional< BoostDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value using Boost.Multiprecision or null.
Definition Statement.h:628
std::optional< ScaledBoostInt128 > getScaledBoostInt128(unsigned index)
Reads a scaled Boost 128-bit integer column.
Definition Statement.h:1539
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:1190
void set(unsigned index, BoostDecFloat34 value)
Convenience overload that binds a Boost 34-digit decimal floating-point value.
Definition Statement.h:1331
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:1322
void set(unsigned index, Time value)
Convenience overload that binds a Firebird time value.
Definition Statement.h:1356
T get(unsigned index)
Retrieves a column using the most appropriate typed accessor specialization.
Definition Statement.h:1720
void set(unsigned index, ScaledInt16 value)
Convenience overload that binds a scaled 16-bit signed integer.
Definition Statement.h:1222
std::optional< BoostInt128 > getBoostInt128(unsigned index)
Reads a Boost 128-bit integer column.
Definition Statement.h:1530
std::optional< bool > getBool(unsigned index)
Reads a boolean column from the current row.
Definition Statement.h:1457
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:643
void set(unsigned index, OpaqueTimestamp value)
Convenience overload that binds a Firebird timestamp value.
Definition Statement.h:1380
void setInt32(unsigned index, std::optional< std::int32_t > optValue)
Binds a 32-bit signed integer value or null.
Definition Statement.h:450
void set(unsigned index, std::optional< BlobId > value)
Convenience overload that binds an optional blob identifier.
Definition Statement.h:1198
void setBool(unsigned index, std::optional< bool > optValue)
Binds a boolean parameter value or null.
Definition Statement.h:391
void set(unsigned index, const V &value)
Sets a parameter from a variant value.
Definition Statement.h:1818
void set(unsigned index, TimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
Definition Statement.h:1404
void setDouble(unsigned index, std::optional< double > optValue)
Binds a double precision floating-point value or null.
Definition Statement.h:583
void set(unsigned index, OpaqueDate value)
Convenience overload that binds a Firebird date value.
Definition Statement.h:1348
void set(unsigned index, std::int16_t value)
Convenience overload that binds a 16-bit signed integer.
Definition Statement.h:1214
void set(unsigned index, std::optional< T > value)
Convenience template that forwards optional values to specialized overloads.
Definition Statement.h:1429
std::optional< OpaqueTimestamp > getOpaqueTimestamp(unsigned index)
Reads a raw timestamp column in Firebird's representation.
Definition Statement.h:1652
void setScaledInt64(unsigned index, std::optional< ScaledInt64 > optValue)
Binds a scaled 64-bit signed integer value or null.
Definition Statement.h:493
Attachment & getAttachment() noexcept
Returns the Attachment object reference used to create this Statement.
Definition Statement.h:194
void set(unsigned index, std::nullopt_t)
Convenience overload that binds a null value.
Definition Statement.h:1182
void setFloat(unsigned index, std::optional< float > optValue)
Binds a single precision floating-point value or null.
Definition Statement.h:569
void setOpaqueDate(unsigned index, std::optional< OpaqueDate > optValue)
Binds a raw date value in Firebird's representation or null.
Definition Statement.h:720
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:1364
void set(unsigned index, ScaledInt32 value)
Convenience overload that binds a scaled 32-bit signed integer.
Definition Statement.h:1238
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:1466
void set(unsigned index, ScaledBoostInt128 value)
Convenience overload that binds a scaled Boost-provided 128-bit integer.
Definition Statement.h:1279
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:1679
void set(unsigned index, BoostInt128 value)
Convenience overload that binds a Boost-provided 128-bit integer.
Definition Statement.h:1271
std::vector< std::byte > & getInputMessage() noexcept
Provides direct access to the raw input message buffer.
Definition Statement.h:236
std::optional< OpaqueDecFloat16 > getOpaqueDecFloat16(unsigned index)
Reads a Firebird 16-digit decimal floating-point column.
Definition Statement.h:1567
std::optional< Timestamp > getTimestamp(unsigned index)
Reads a timestamp column without timezone.
Definition Statement.h:1643
std::optional< BoostDecFloat16 > getBoostDecFloat16(unsigned index)
Reads a Boost-based 16-digit decimal floating-point column.
Definition Statement.h:1577
void setTimeTz(unsigned index, std::optional< TimeTz > optValue)
Binds a time-of-day value with timezone or null.
Definition Statement.h:872
void setBoostDecFloat34(unsigned index, std::optional< BoostDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value using Boost.Multiprecision or null.
Definition Statement.h:674
std::optional< ScaledInt64 > getScaledInt64(unsigned index)
Reads a scaled 64-bit signed integer column.
Definition Statement.h:1511
void set(unsigned index, bool value)
Convenience overload that binds a boolean value.
Definition Statement.h:1206
void setOpaqueTimestamp(unsigned index, std::optional< OpaqueTimestamp > optValue)
Binds a raw timestamp value in Firebird's representation or null.
Definition Statement.h:842
void set(unsigned index, float value)
Convenience overload that binds a single precision floating-point value.
Definition Statement.h:1288
void set(const T &value)
Sets all input parameters from fields of a user-defined aggregate struct.
Definition Statement.h:1747
Represents a transaction in one or more Firebird databases.
fb-cpp namespace.
Definition Attachment.h:45
ScaledNumber< std::int64_t > ScaledInt64
Signed 64-bit scaled number.
Definition types.h:79
ScaledNumber< std::int32_t > ScaledInt32
Signed 32-bit scaled number.
Definition types.h:74
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 34 > > BoostDecFloat34
34-digit decimal floating point using Boost.Multiprecision.
Definition types.h:102
FB_DEC16 OpaqueDecFloat16
Opaque 16-digit decimal floating point exposed by the Firebird API.
Definition types.h:205
ScaledNumber< std::int16_t > ScaledInt16
Signed 16-bit scaled number.
Definition types.h:69
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 16 > > BoostDecFloat16
16-digit decimal floating point using Boost.Multiprecision.
Definition types.h:97
DescriptorAdjustedType
Descriptor adjusted type.
Definition Descriptor.h:147
@ BLOB
Binary large object.
@ TIME
Time of day without time zone.
@ DECFLOAT34
34-digit decimal floating point.
@ INT64
64-bit signed integer.
@ TIME_TZ
Time of day with time zone.
@ DECFLOAT16
16-digit decimal floating point.
@ INT16
16-bit signed integer.
@ STRING
String type (variable-length).
@ INT32
32-bit signed integer.
@ TIMESTAMP
Timestamp without time zone.
@ TIMESTAMP_TZ
Timestamp with time zone.
@ INT128
128-bit signed integer.
@ FLOAT
Single-precision floating point.
@ DOUBLE
Double-precision floating point.
StatementType
Distinguishes the semantic category of the prepared SQL statement.
Definition Statement.h:75
@ SAVEPOINT
Statement manages a savepoint.
@ PUT_SEGMENT
Statement writes a blob segment - legacy feature.
@ UPDATE
Server classified the statement as an UPDATE.
@ COMMIT
Statement commits a transaction.
@ ROLLBACK
Statement rolls back a transaction.
@ EXEC_PROCEDURE
Statement executes a stored procedure.
@ DELETE
Server classified the statement as a DELETE.
@ DDL
Statement performs data definition operations.
@ GET_SEGMENT
Statement reads a blob segment - legacy feature.
@ INSERT
Server classified the statement as an INSERT.
@ SELECT
Server classified the statement as a SELECT.
@ SET_GENERATOR
Statement sets a generator (sequence) value.
@ START_TRANSACTION
Statement starts a new transaction.
@ SELECT_FOR_UPDATE
Cursor-based SELECT that allows updates.
FB_I128 OpaqueInt128
Opaque 128-bit integer exposed by the Firebird API.
Definition types.h:200
std::chrono::year_month_day Date
Firebird SQL calendar date.
Definition types.h:108
FB_DEC34 OpaqueDecFloat34
Opaque 34-digit decimal floating point exposed by the Firebird API.
Definition types.h:210
boost::multiprecision::int128_t BoostInt128
128-bit integer using Boost.Multiprecision.
Definition types.h:85
ScaledNumber< BoostInt128 > ScaledBoostInt128
Scaled 128-bit integer backed by Boost.Multiprecision.
Definition types.h:90
std::chrono::hh_mm_ss< std::chrono::microseconds > Time
Firebird SQL time-of-day with microsecond resolution.
Definition types.h:113
Describes a parameter or column.
Definition Descriptor.h:248
Wrapper for Firebird date values.
Definition types.h:221
Wrapper for Firebird time-with-time-zone values.
Definition types.h:263
Wrapper for Firebird time values.
Definition types.h:234
Wrapper for Firebird timestamp-with-time-zone values.
Definition types.h:279
Wrapper for Firebird timestamp values.
Definition types.h:247
Represents a numeric value with an explicit decimal scale.
Definition types.h:52
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