25#ifndef FBCPP_STATEMENT_H
26#define FBCPP_STATEMENT_H
32#include "Attachment.h"
34#include "NumericConverter.h"
35#include "CalendarConverter.h"
36#include "Descriptor.h"
39#include "StructBinding.h"
40#include "VariantTypeTraits.h"
57#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
58#include <boost/multiprecision/cpp_int.hpp>
59#include <boost/multiprecision/cpp_dec_float.hpp>
96 return prefetchLegacyPlan;
106 prefetchLegacyPlan = value;
125 prefetchPlan = value;
168 bool prefetchLegacyPlan =
false;
169 bool prefetchPlan =
false;
170 std::optional<std::string> cursorName;
182 SELECT = isc_info_sql_stmt_select,
186 INSERT = isc_info_sql_stmt_insert,
190 UPDATE = isc_info_sql_stmt_update,
194 DELETE = isc_info_sql_stmt_delete,
198 DDL = isc_info_sql_stmt_ddl,
218 COMMIT = isc_info_sql_stmt_commit,
222 ROLLBACK = isc_info_sql_stmt_rollback,
257 : attachment{o.attachment},
258 status{std::move(o.status)},
259 statusWrapper{std::move(o.statusWrapper)},
260 calendarConverter{std::move(o.calendarConverter)},
261 numericConverter{std::move(o.numericConverter)},
262 statementHandle{std::move(o.statementHandle)},
263 resultSetHandle{std::move(o.resultSetHandle)},
264 inMetadata{std::move(o.inMetadata)},
265 inDescriptors{std::move(o.inDescriptors)},
266 inMessage{std::move(o.inMessage)},
267 outMetadata{std::move(o.outMetadata)},
268 outDescriptors{std::move(o.outDescriptors)},
269 outMessage{std::move(o.outMessage)},
271 cursorFlags{o.cursorFlags}
285 attachment = o.attachment;
286 status = std::move(o.status);
287 statusWrapper = std::move(o.statusWrapper);
288 calendarConverter = std::move(o.calendarConverter);
289 numericConverter = std::move(o.numericConverter);
290 statementHandle = std::move(o.statementHandle);
291 resultSetHandle = std::move(o.resultSetHandle);
292 inMetadata = std::move(o.inMetadata);
293 inDescriptors = std::move(o.inDescriptors);
294 inMessage = std::move(o.inMessage);
295 outMetadata = std::move(o.outMetadata);
296 outDescriptors = std::move(o.outDescriptors);
297 outMessage = std::move(o.outMessage);
299 cursorFlags = o.cursorFlags;
338 return statementHandle !=
nullptr;
347 return statementHandle;
356 return resultSetHandle;
398 return inDescriptors;
406 return outDescriptors;
484 const auto message = inMessage.data();
486 for (
const auto& descriptor : inDescriptors)
487 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
498 const auto& descriptor = getInDescriptor(index);
499 const auto message = inMessage.data();
501 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
509 void setBool(
unsigned index, std::optional<bool> optValue)
511 if (!optValue.has_value())
519 const auto& value = optValue.value();
520 const auto& descriptor = getInDescriptor(index);
521 const auto message = inMessage.data();
523 switch (descriptor.adjustedType)
526 message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
530 throwInvalidType(
"bool", descriptor.adjustedType);
533 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
539 void setInt16(
unsigned index, std::optional<std::int16_t> optValue)
541 if (!optValue.has_value())
555 if (!optValue.has_value())
561 const auto& value = optValue.value();
568 void setInt32(
unsigned index, std::optional<std::int32_t> optValue)
570 if (!optValue.has_value())
584 if (!optValue.has_value())
590 const auto& value = optValue.value();
597 void setInt64(
unsigned index, std::optional<std::int64_t> optValue)
599 if (!optValue.has_value())
613 if (!optValue.has_value())
619 const auto& value = optValue.value();
628 if (!optValue.has_value())
636 const auto& value = optValue.value();
637 const auto& descriptor = getInDescriptor(index);
638 const auto message = inMessage.data();
640 switch (descriptor.adjustedType)
643 *
reinterpret_cast<OpaqueInt128*
>(&message[descriptor.offset]) = value;
647 throwInvalidType(
"OpaqueInt128", descriptor.adjustedType);
650 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
653#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
659 if (!optValue.has_value())
673 if (!optValue.has_value())
679 const auto& value = optValue.value();
687 void setFloat(
unsigned index, std::optional<float> optValue)
689 if (!optValue.has_value())
701 void setDouble(
unsigned index, std::optional<double> optValue)
703 if (!optValue.has_value())
717 if (!optValue.has_value())
725 const auto& value = optValue.value();
726 const auto& descriptor = getInDescriptor(index);
727 const auto message = inMessage.data();
729 switch (descriptor.adjustedType)
736 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
739 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
742#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
748 if (!optValue.has_value())
763 if (!optValue.has_value())
771 const auto& value = optValue.value();
772 const auto& descriptor = getInDescriptor(index);
773 const auto message = inMessage.data();
775 switch (descriptor.adjustedType)
782 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
785 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
788#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
794 if (!optValue.has_value())
807 void setDate(
unsigned index, std::optional<Date> optValue)
809 if (!optValue.has_value())
817 const auto& value = optValue.value();
818 const auto& descriptor = getInDescriptor(index);
819 const auto message = inMessage.data();
821 switch (descriptor.adjustedType)
824 *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) =
825 calendarConverter.dateToOpaqueDate(value);
829 throwInvalidType(
"Date", descriptor.adjustedType);
832 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
840 if (!optValue.has_value())
848 const auto& value = optValue.value();
849 const auto& descriptor = getInDescriptor(index);
850 const auto message = inMessage.data();
852 switch (descriptor.adjustedType)
855 *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) = value;
859 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
862 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
868 void setTime(
unsigned index, std::optional<Time> optValue)
870 if (!optValue.has_value())
878 const auto& value = optValue.value();
879 const auto& descriptor = getInDescriptor(index);
880 const auto message = inMessage.data();
882 switch (descriptor.adjustedType)
885 *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) =
886 calendarConverter.timeToOpaqueTime(value);
890 throwInvalidType(
"Time", descriptor.adjustedType);
893 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
901 if (!optValue.has_value())
909 const auto& value = optValue.value();
910 const auto& descriptor = getInDescriptor(index);
911 const auto message = inMessage.data();
913 switch (descriptor.adjustedType)
916 *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) = value;
920 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
923 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
931 if (!optValue.has_value())
939 const auto& value = optValue.value();
940 const auto& descriptor = getInDescriptor(index);
941 const auto message = inMessage.data();
943 switch (descriptor.adjustedType)
947 calendarConverter.timestampToOpaqueTimestamp(value);
951 throwInvalidType(
"Timestamp", descriptor.adjustedType);
954 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
962 if (!optValue.has_value())
970 const auto& value = optValue.value();
971 const auto& descriptor = getInDescriptor(index);
972 const auto message = inMessage.data();
974 switch (descriptor.adjustedType)
977 *
reinterpret_cast<OpaqueTimestamp*
>(&message[descriptor.offset]) = value;
981 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
984 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
990 void setTimeTz(
unsigned index, std::optional<TimeTz> optValue)
992 if (!optValue.has_value())
1000 const auto& value = optValue.value();
1001 const auto& descriptor = getInDescriptor(index);
1002 auto*
const message = inMessage.data();
1004 switch (descriptor.adjustedType)
1007 *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) =
1008 calendarConverter.timeTzToOpaqueTimeTz(value);
1012 throwInvalidType(
"TimeTz", descriptor.adjustedType);
1015 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1023 if (!optValue.has_value())
1031 const auto& value = optValue.value();
1032 const auto& descriptor = getInDescriptor(index);
1033 auto*
const message = inMessage.data();
1035 switch (descriptor.adjustedType)
1038 *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) = value;
1042 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
1045 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1053 if (!optValue.has_value())
1061 const auto& value = optValue.value();
1062 const auto& descriptor = getInDescriptor(index);
1063 auto*
const message = inMessage.data();
1065 switch (descriptor.adjustedType)
1069 calendarConverter.timestampTzToOpaqueTimestampTz(value);
1073 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
1076 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1084 if (!optValue.has_value())
1092 const auto& value = optValue.value();
1093 const auto& descriptor = getInDescriptor(index);
1094 auto*
const message = inMessage.data();
1096 switch (descriptor.adjustedType)
1103 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
1106 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1112 void setString(
unsigned index, std::optional<std::string_view> optValue)
1114 if (!optValue.has_value())
1123 const auto value = optValue.value();
1124 const auto& descriptor = getInDescriptor(index);
1125 const auto message = inMessage.data();
1126 const auto data = &message[descriptor.offset];
1128 switch (descriptor.adjustedType)
1131 message[descriptor.offset] = numericConverter.stringToBoolean(value);
1138 std::string strValue(value);
1141 if (
const auto dotPos = strValue.find_last_of(
'.'); dotPos != std::string_view::npos)
1143 for (
auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1145 const char c = value[pos];
1147 if (c <
'0' || c >
'9')
1153 strValue.erase(dotPos, 1);
1156 static_assert(
sizeof(
long long) ==
sizeof(std::int64_t));
1157 std::int64_t intValue;
1158 const auto convResult =
1159 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1160 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1161 numericConverter.throwConversionErrorFromString(strValue);
1164 if (scale != descriptor.scale)
1167 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1168 scaledValue.scale = descriptor.scale;
1177 std::string strValue(value);
1178 client.getInt128Util(&statusWrapper)
1180 &statusWrapper, descriptor.scale, strValue.c_str(),
reinterpret_cast<OpaqueInt128*
>(data));
1188#if defined(__APPLE__)
1190 std::string valueString{value};
1191 char* parseEnd =
nullptr;
1192 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1193 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1194 numericConverter.throwConversionErrorFromString(std::move(valueString));
1196 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1197 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1198 numericConverter.throwConversionErrorFromString(std::string{value});
1205 *
reinterpret_cast<OpaqueDate*
>(data) = calendarConverter.stringToOpaqueDate(value);
1209 *
reinterpret_cast<OpaqueTime*
>(data) = calendarConverter.stringToOpaqueTime(value);
1213 *
reinterpret_cast<OpaqueTimestamp*
>(data) = calendarConverter.stringToOpaqueTimestamp(value);
1217 *
reinterpret_cast<OpaqueTimeTz*
>(data) = calendarConverter.stringToOpaqueTimeTz(value);
1221 *
reinterpret_cast<OpaqueTimestampTz*
>(data) = calendarConverter.stringToOpaqueTimestampTz(value);
1224#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1227 std::string strValue{value};
1228 client.getDecFloat16Util(&statusWrapper)
1229 ->fromString(&statusWrapper, strValue.c_str(),
reinterpret_cast<OpaqueDecFloat16*
>(data));
1235 std::string strValue{value};
1236 client.getDecFloat34Util(&statusWrapper)
1237 ->fromString(&statusWrapper, strValue.c_str(),
reinterpret_cast<OpaqueDecFloat34*
>(data));
1243 if (value.length() > descriptor.length)
1245 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1247 isc_string_truncation,
1254 *
reinterpret_cast<std::uint16_t*
>(data) =
static_cast<std::uint16_t
>(value.length());
1255 std::copy(value.begin(), value.end(),
1256 reinterpret_cast<char*
>(&message[descriptor.offset +
sizeof(std::uint16_t)]));
1260 throwInvalidType(
"std::string_view", descriptor.adjustedType);
1263 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1269 void setBlobId(
unsigned index, std::optional<BlobId> optValue)
1271 if (!optValue.has_value())
1279 const auto& value = optValue.value();
1280 const auto& descriptor = getInDescriptor(index);
1281 auto*
const message = inMessage.data();
1283 switch (descriptor.adjustedType)
1286 *
reinterpret_cast<ISC_QUAD*
>(&message[descriptor.offset]) = value.id;
1290 throwInvalidType(
"BlobId", descriptor.adjustedType);
1293 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1298 void set(
unsigned index, std::nullopt_t)
1314 void set(
unsigned index, std::optional<BlobId> value)
1322 void set(
unsigned index,
bool value)
1330 void set(
unsigned index, std::int16_t value)
1346 void set(
unsigned index, std::int32_t value)
1362 void set(
unsigned index, std::int64_t value)
1383#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1404 void set(
unsigned index,
float value)
1412 void set(
unsigned index,
double value)
1425#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1443#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1536 void set(
unsigned index, std::string_view value)
1544 template <
typename T>
1545 void set(
unsigned index, std::optional<T> value)
1547 if (value.has_value())
1548 set(index, value.value());
1568 const auto& descriptor = getOutDescriptor(index);
1569 const auto*
const message = outMessage.data();
1571 return *
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE;
1581 const auto& descriptor = getOutDescriptor(index);
1582 const auto*
const message = outMessage.data();
1584 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1585 return std::nullopt;
1587 switch (descriptor.adjustedType)
1590 return message[descriptor.offset] != std::byte{0};
1593 throwInvalidType(
"bool", descriptor.adjustedType);
1602 std::optional<int> scale{0};
1603 return getNumber<std::int16_t>(index, scale,
"std::int16_t");
1611 std::optional<int> scale;
1612 const auto value = getNumber<std::int16_t>(index, scale,
"ScaledInt16");
1613 return value.has_value() ? std::optional{
ScaledInt16{value.
value(), scale.value()}} : std::nullopt;
1621 std::optional<int> scale{0};
1622 return getNumber<std::int32_t>(index, scale,
"std::int32_t");
1630 std::optional<int> scale;
1631 const auto value = getNumber<std::int32_t>(index, scale,
"ScaledInt32");
1632 return value.has_value() ? std::optional{
ScaledInt32{value.
value(), scale.value()}} : std::nullopt;
1640 std::optional<int> scale{0};
1641 return getNumber<std::int64_t>(index, scale,
"std::int64_t");
1649 std::optional<int> scale;
1650 const auto value = getNumber<std::int64_t>(index, scale,
"ScaledInt64");
1651 return value.has_value() ? std::optional{
ScaledInt64{value.
value(), scale.value()}} : std::nullopt;
1661 const auto& descriptor = getOutDescriptor(index);
1662 const auto*
const message = outMessage.data();
1664 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1665 return std::nullopt;
1667 switch (descriptor.adjustedType)
1675 throwInvalidType(
"ScaledOpaqueInt128", descriptor.adjustedType);
1679#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1685 std::optional<int> scale{0};
1686 const auto value = getNumber<BoostInt128>(index, scale,
"BoostInt128");
1687 return value.has_value() ? std::optional{value.value()} : std::nullopt;
1695 std::optional<int> scale;
1696 const auto value = getNumber<BoostInt128>(index, scale,
"ScaledBoostInt128");
1697 return value.has_value() ? std::optional{
ScaledBoostInt128{value.
value(), scale.value()}} : std::nullopt;
1706 std::optional<int> scale{0};
1707 return getNumber<float>(index, scale,
"float");
1715 std::optional<int> scale{0};
1716 return getNumber<double>(index, scale,
"double");
1726 const auto& descriptor = getOutDescriptor(index);
1727 const auto*
const message = outMessage.data();
1729 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1730 return std::nullopt;
1732 switch (descriptor.adjustedType)
1738 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
1742#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1748 std::optional<int> scale{0};
1749 return getNumber<BoostDecFloat16>(index, scale,
"BoostDecFloat16");
1760 const auto& descriptor = getOutDescriptor(index);
1761 const auto*
const message = outMessage.data();
1763 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1764 return std::nullopt;
1766 switch (descriptor.adjustedType)
1772 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
1776#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1782 std::optional<int> scale{0};
1783 return getNumber<BoostDecFloat34>(index, scale,
"BoostDecFloat34");
1794 const auto& descriptor = getOutDescriptor(index);
1795 const auto*
const message = outMessage.data();
1797 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1798 return std::nullopt;
1800 switch (descriptor.adjustedType)
1803 return calendarConverter.opaqueDateToDate(
1804 *
reinterpret_cast<const OpaqueDate*
>(&message[descriptor.offset]));
1807 throwInvalidType(
"Date", descriptor.adjustedType);
1818 const auto& descriptor = getOutDescriptor(index);
1819 const auto*
const message = outMessage.data();
1821 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1822 return std::nullopt;
1824 switch (descriptor.adjustedType)
1830 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
1841 const auto& descriptor = getOutDescriptor(index);
1842 const auto*
const message = outMessage.data();
1844 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1845 return std::nullopt;
1847 switch (descriptor.adjustedType)
1850 return calendarConverter.opaqueTimeToTime(
1851 *
reinterpret_cast<const OpaqueTime*
>(&message[descriptor.offset]));
1854 throwInvalidType(
"Time", descriptor.adjustedType);
1865 const auto& descriptor = getOutDescriptor(index);
1866 const auto*
const message = outMessage.data();
1868 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1869 return std::nullopt;
1871 switch (descriptor.adjustedType)
1877 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
1888 const auto& descriptor = getOutDescriptor(index);
1889 const auto*
const message = outMessage.data();
1891 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1892 return std::nullopt;
1894 switch (descriptor.adjustedType)
1897 return calendarConverter.opaqueTimestampToTimestamp(
1898 *
reinterpret_cast<const OpaqueTimestamp*
>(&message[descriptor.offset]));
1901 throwInvalidType(
"Timestamp", descriptor.adjustedType);
1912 const auto& descriptor = getOutDescriptor(index);
1913 const auto*
const message = outMessage.data();
1915 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1916 return std::nullopt;
1918 switch (descriptor.adjustedType)
1924 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
1935 const auto& descriptor = getOutDescriptor(index);
1936 const auto*
const message = outMessage.data();
1938 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1939 return std::nullopt;
1941 switch (descriptor.adjustedType)
1944 return calendarConverter.opaqueTimeTzToTimeTz(
1945 *
reinterpret_cast<const OpaqueTimeTz*
>(&message[descriptor.offset]));
1948 throwInvalidType(
"TimeTz", descriptor.adjustedType);
1959 const auto& descriptor = getOutDescriptor(index);
1960 const auto*
const message = outMessage.data();
1962 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1963 return std::nullopt;
1965 switch (descriptor.adjustedType)
1971 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
1982 const auto& descriptor = getOutDescriptor(index);
1983 const auto*
const message = outMessage.data();
1985 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1986 return std::nullopt;
1988 switch (descriptor.adjustedType)
1991 return calendarConverter.opaqueTimestampTzToTimestampTz(
1995 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
2006 const auto& descriptor = getOutDescriptor(index);
2007 const auto*
const message = outMessage.data();
2009 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2010 return std::nullopt;
2012 switch (descriptor.adjustedType)
2018 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
2029 const auto& descriptor = getOutDescriptor(index);
2030 const auto*
const message = outMessage.data();
2032 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2033 return std::nullopt;
2035 switch (descriptor.adjustedType)
2040 value.
id = *
reinterpret_cast<const ISC_QUAD*
>(&message[descriptor.offset]);
2045 throwInvalidType(
"BlobId", descriptor.adjustedType);
2056 const auto& descriptor = getOutDescriptor(index);
2057 const auto*
const message = outMessage.data();
2059 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2060 return std::nullopt;
2062 const auto data = &message[descriptor.offset];
2064 switch (descriptor.adjustedType)
2067 return (message[descriptor.offset] != std::byte{0}) ? std::string{
"true"} : std::string{
"false"};
2070 return numericConverter.numberToString(
2071 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.
scale});
2074 return numericConverter.numberToString(
2075 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.
scale});
2078 return numericConverter.numberToString(
2079 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.
scale});
2082 return numericConverter.opaqueInt128ToString(
2083 *
reinterpret_cast<const OpaqueInt128*
>(data), descriptor.scale);
2086 return numericConverter.numberToString(*
reinterpret_cast<const float*
>(data));
2089 return numericConverter.numberToString(*
reinterpret_cast<const double*
>(data));
2092 return calendarConverter.opaqueDateToString(*
reinterpret_cast<const OpaqueDate*
>(data));
2095 return calendarConverter.opaqueTimeToString(*
reinterpret_cast<const OpaqueTime*
>(data));
2098 return calendarConverter.opaqueTimestampToString(*
reinterpret_cast<const OpaqueTimestamp*
>(data));
2101 return calendarConverter.opaqueTimeTzToString(*
reinterpret_cast<const OpaqueTimeTz*
>(data));
2104 return calendarConverter.opaqueTimestampTzToString(
2108 return numericConverter.opaqueDecFloat16ToString(*
reinterpret_cast<const OpaqueDecFloat16*
>(data));
2111 return numericConverter.opaqueDecFloat34ToString(*
reinterpret_cast<const OpaqueDecFloat34*
>(data));
2114 return std::string{
reinterpret_cast<const char*
>(data +
sizeof(std::uint16_t)),
2115 *
reinterpret_cast<const std::uint16_t*
>(data)};
2118 throwInvalidType(
"std::string", descriptor.adjustedType);
2129 template <
typename T>
2139 template <Aggregate T>
2142 using namespace impl::reflection;
2144 constexpr std::size_t N = fieldCountV<T>;
2146 if (N != outDescriptors.size())
2148 throw FbCppException(
"Struct field count (" + std::to_string(N) +
2149 ") does not match output column count (" + std::to_string(outDescriptors.size()) +
")");
2152 return getStruct<T>(std::make_index_sequence<N>{});
2161 template <Aggregate T>
2164 using namespace impl::reflection;
2166 constexpr std::size_t N = fieldCountV<T>;
2168 if (N != inDescriptors.size())
2170 throw FbCppException(
"Struct field count (" + std::to_string(N) +
2171 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) +
")");
2174 setStruct(value, std::make_index_sequence<N>{});
2184 template <TupleLike T>
2187 using namespace impl::reflection;
2189 constexpr std::size_t N = std::tuple_size_v<T>;
2191 if (N != outDescriptors.size())
2193 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
2194 ") does not match output column count (" + std::to_string(outDescriptors.size()) +
")");
2197 return getTuple<T>(std::make_index_sequence<N>{});
2206 template <TupleLike T>
2209 constexpr std::size_t N = std::tuple_size_v<T>;
2211 if (N != inDescriptors.size())
2213 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
2214 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) +
")");
2217 setTuple(value, std::make_index_sequence<N>{});
2228 template <VariantLike V>
2231 using namespace impl::reflection;
2233 static_assert(variantAlternativesSupportedV<V>,
2234 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2235 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2236 "complete list of supported types.");
2240 const auto& descriptor = getOutDescriptor(index);
2244 if constexpr (variantContainsV<std::monostate, V>)
2245 return V{std::monostate{}};
2249 "NULL value encountered but variant does not contain std::monostate at index " +
2250 std::to_string(index));
2254 return getVariantValue<V>(index, descriptor);
2263 template <VariantLike V>
2264 void set(
unsigned index,
const V& value)
2266 using namespace impl::reflection;
2268 static_assert(variantAlternativesSupportedV<V>,
2269 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2270 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2271 "complete list of supported types.");
2274 [
this, index](
const auto& v)
2276 using T = std::decay_t<
decltype(v)>;
2278 if constexpr (std::is_same_v<T, std::monostate>)
2290 const Descriptor& getInDescriptor(
unsigned index)
2292 if (index >= inDescriptors.size())
2293 throw std::out_of_range(
"index out of range");
2295 return inDescriptors[index];
2301 const Descriptor& getOutDescriptor(
unsigned index)
2303 if (index >= outDescriptors.size())
2304 throw std::out_of_range(
"index out of range");
2306 return outDescriptors[index];
2312 template <
typename T, std::size_t... Is>
2313 T getStruct(std::index_sequence<Is...>)
2315 using namespace impl::reflection;
2317 return T{getStructField<FieldType<T, Is>>(
static_cast<unsigned>(Is))...};
2323 template <
typename F>
2324 auto getStructField(
unsigned index)
2326 using namespace impl::reflection;
2328 if constexpr (isOptionalV<F>)
2329 return get<F>(index);
2330 else if constexpr (isVariantV<F>)
2331 return get<F>(index);
2334 auto opt = get<std::optional<F>>(index);
2336 if (!opt.has_value())
2338 throw FbCppException(
2339 "Null value encountered for non-optional field at index " + std::to_string(index));
2342 return std::move(opt.value());
2349 template <
typename T, std::size_t... Is>
2350 void setStruct(
const T& value, std::index_sequence<Is...>)
2352 using namespace impl::reflection;
2354 const auto tuple = toTupleRef(value);
2355 (
set(
static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
2361 template <
typename T, std::size_t... Is>
2362 T getTuple(std::index_sequence<Is...>)
2364 using namespace impl::reflection;
2366 return T{getStructField<std::tuple_element_t<Is, T>>(
static_cast<unsigned>(Is))...};
2372 template <
typename T, std::size_t... Is>
2373 void setTuple(
const T& value, std::index_sequence<Is...>)
2375 (
set(
static_cast<unsigned>(Is), std::get<Is>(value)), ...);
2382 template <
typename V>
2383 V getVariantValue(
unsigned index,
const Descriptor& descriptor)
2385 using namespace impl::reflection;
2388 switch (descriptor.adjustedType)
2391 if constexpr (variantContainsV<bool, V>)
2392 return V{get<std::optional<bool>>(index).value()};
2396 if (descriptor.scale != 0)
2399 if constexpr (variantContainsV<ScaledInt16, V>)
2400 return V{get<std::optional<ScaledInt16>>(index).value()};
2401 if constexpr (variantContainsV<ScaledInt32, V>)
2402 return V{get<std::optional<ScaledInt32>>(index).value()};
2403 if constexpr (variantContainsV<ScaledInt64, V>)
2404 return V{get<std::optional<ScaledInt64>>(index).value()};
2405#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2406 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2407 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2410 if constexpr (variantContainsV<std::int16_t, V>)
2411 return V{get<std::optional<std::int16_t>>(index).value()};
2415 if (descriptor.scale != 0)
2418 if constexpr (variantContainsV<ScaledInt32, V>)
2419 return V{get<std::optional<ScaledInt32>>(index).value()};
2420 if constexpr (variantContainsV<ScaledInt64, V>)
2421 return V{get<std::optional<ScaledInt64>>(index).value()};
2422#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2423 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2424 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2427 if constexpr (variantContainsV<std::int32_t, V>)
2428 return V{get<std::optional<std::int32_t>>(index).value()};
2432 if (descriptor.scale != 0)
2435 if constexpr (variantContainsV<ScaledInt64, V>)
2436 return V{get<std::optional<ScaledInt64>>(index).value()};
2437#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2438 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2439 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2442 if constexpr (variantContainsV<std::int64_t, V>)
2443 return V{get<std::optional<std::int64_t>>(index).value()};
2446#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2449 if constexpr (variantContainsV<ScaledOpaqueInt128, V>)
2450 return V{get<std::optional<ScaledOpaqueInt128>>(index).value()};
2451 else if (descriptor.scale != 0)
2453 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2454 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2456 else if constexpr (variantContainsV<BoostInt128, V>)
2457 return V{get<std::optional<BoostInt128>>(index).value()};
2462 if constexpr (variantContainsV<float, V>)
2463 return V{get<std::optional<float>>(index).value()};
2467 if constexpr (variantContainsV<double, V>)
2468 return V{get<std::optional<double>>(index).value()};
2471#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2474 if constexpr (variantContainsV<OpaqueDecFloat16, V>)
2475 return V{get<std::optional<OpaqueDecFloat16>>(index).value()};
2476 else if constexpr (variantContainsV<BoostDecFloat16, V>)
2477 return V{get<std::optional<BoostDecFloat16>>(index).value()};
2482 if constexpr (variantContainsV<OpaqueDecFloat34, V>)
2483 return V{get<std::optional<OpaqueDecFloat34>>(index).value()};
2484 else if constexpr (variantContainsV<BoostDecFloat34, V>)
2485 return V{get<std::optional<BoostDecFloat34>>(index).value()};
2490 if constexpr (variantContainsV<std::string, V>)
2491 return V{get<std::optional<std::string>>(index).value()};
2496 if constexpr (variantContainsV<OpaqueDate, V>)
2497 return V{get<std::optional<OpaqueDate>>(index).value()};
2498 else if constexpr (variantContainsV<Date, V>)
2499 return V{get<std::optional<Date>>(index).value()};
2504 if constexpr (variantContainsV<OpaqueTime, V>)
2505 return V{get<std::optional<OpaqueTime>>(index).value()};
2506 else if constexpr (variantContainsV<Time, V>)
2507 return V{get<std::optional<Time>>(index).value()};
2512 if constexpr (variantContainsV<OpaqueTimestamp, V>)
2513 return V{get<std::optional<OpaqueTimestamp>>(index).value()};
2514 else if constexpr (variantContainsV<Timestamp, V>)
2515 return V{get<std::optional<Timestamp>>(index).value()};
2520 if constexpr (variantContainsV<OpaqueTimeTz, V>)
2521 return V{get<std::optional<OpaqueTimeTz>>(index).value()};
2522 else if constexpr (variantContainsV<TimeTz, V>)
2523 return V{get<std::optional<TimeTz>>(index).value()};
2528 if constexpr (variantContainsV<OpaqueTimestampTz, V>)
2529 return V{get<std::optional<OpaqueTimestampTz>>(index).value()};
2530 else if constexpr (variantContainsV<TimestampTz, V>)
2531 return V{get<std::optional<TimestampTz>>(index).value()};
2535 if constexpr (variantContainsV<BlobId, V>)
2536 return V{get<std::optional<BlobId>>(index).value()};
2544 return tryVariantAlternatives<V, 0>(index, descriptor);
2550 template <
typename V, std::
size_t I = 0>
2551 V tryVariantAlternatives(
unsigned index, [[maybe_unused]]
const Descriptor& descriptor)
2553 using namespace impl::reflection;
2555 if constexpr (I >= std::variant_size_v<V>)
2557 throw FbCppException(
2558 "Cannot convert SQL type to any variant alternative at index " + std::to_string(index));
2562 using Alt = std::variant_alternative_t<I, V>;
2564 if constexpr (std::is_same_v<Alt, std::monostate>)
2567 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2569 else if constexpr (isOpaqueTypeV<Alt>)
2572 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2577 auto opt = get<std::optional<Alt>>(index);
2578 return V{std::move(opt.value())};
2586 template <
typename T>
2587 void setNumber(
unsigned index,
DescriptorAdjustedType valueType, T value,
int scale,
const char* typeName)
2591 const auto& descriptor = getInDescriptor(index);
2592 auto*
const message = inMessage.data();
2594 const auto descriptorData = &message[descriptor.offset];
2595 std::optional<int> descriptorScale{descriptor.scale};
2597 Descriptor valueDescriptor;
2598 valueDescriptor.adjustedType = valueType;
2599 valueDescriptor.scale = scale;
2601 const auto valueAddress =
reinterpret_cast<const std::byte*
>(&value);
2603 switch (descriptor.adjustedType)
2606 *
reinterpret_cast<std::int16_t*
>(descriptorData) =
2607 convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int16_t");
2611 *
reinterpret_cast<std::int32_t*
>(descriptorData) =
2612 convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int32_t");
2616 *
reinterpret_cast<std::int64_t*
>(descriptorData) =
2617 convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int64_t");
2620#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2623 const auto boostInt128 =
2624 convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale,
"BoostInt128");
2626 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
2632 *
reinterpret_cast<float*
>(descriptorData) =
2633 convertNumber<float>(valueDescriptor, valueAddress, descriptorScale,
"float");
2637 *
reinterpret_cast<double*
>(descriptorData) =
2638 convertNumber<double>(valueDescriptor, valueAddress, descriptorScale,
"double");
2641#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2644 const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
2645 valueDescriptor, valueAddress, descriptorScale,
"BoostDecFloat16");
2647 numericConverter.boostDecFloat16ToOpaqueDecFloat16(boostDecFloat16);
2653 const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
2654 valueDescriptor, valueAddress, descriptorScale,
"BoostDecFloat34");
2656 numericConverter.boostDecFloat34ToOpaqueDecFloat34(boostDecFloat34);
2662 throwInvalidType(typeName, descriptor.adjustedType);
2665 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
2672 template <
typename T>
2673 std::optional<T> getNumber(
unsigned index, std::optional<int>& scale,
const char* typeName)
2677 const auto& descriptor = getOutDescriptor(index);
2678 const auto*
const message = outMessage.data();
2680 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2681 return std::nullopt;
2683 auto data = &message[descriptor.offset];
2684#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2685 std::optional<BoostInt128> boostInt128;
2686 std::optional<BoostDecFloat16> boostDecFloat16;
2687 std::optional<BoostDecFloat34> boostDecFloat34;
2691 switch (descriptor.adjustedType)
2693#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2695 boostInt128.emplace(
2696 numericConverter.opaqueInt128ToBoostInt128(*
reinterpret_cast<const OpaqueInt128*
>(data)));
2697 data =
reinterpret_cast<const std::byte*
>(&boostInt128.value());
2701 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
2703 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat16.value());
2707 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
2709 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat34.value());
2717 return convertNumber<T>(descriptor, data, scale, typeName);
2722 throw FbCppException(
"Invalid type: actual type " + std::string(actualType) +
", descriptor type " +
2723 std::to_string(
static_cast<unsigned>(descriptorType)));
2726 template <
typename T>
2728 const Descriptor& descriptor,
const std::byte* data, std::optional<int>& toScale,
const char* toTypeName)
2730 if (!toScale.has_value())
2732 switch (descriptor.adjustedType)
2738 throwInvalidType(toTypeName, descriptor.adjustedType);
2744 toScale = descriptor.scale;
2747 switch (descriptor.adjustedType)
2750 return numericConverter.numberToNumber<T>(
2751 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.scale}, toScale.value());
2755 return numericConverter.numberToNumber<T>(
2756 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.scale}, toScale.value());
2759 return numericConverter.numberToNumber<T>(
2760 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.scale}, toScale.value());
2762#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2764 return numericConverter.numberToNumber<T>(
2769 return numericConverter.numberToNumber<T>(
2773 return numericConverter.numberToNumber<T>(
2778 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const float*
>(data), toScale.value());
2782 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const double*
>(data), toScale.value());
2786 throwInvalidType(toTypeName, descriptor.adjustedType);
2791 Attachment* attachment;
2792 FbUniquePtr<Firebird::IStatus> status;
2793 impl::StatusWrapper statusWrapper;
2794 impl::CalendarConverter calendarConverter;
2795 impl::NumericConverter numericConverter;
2796 FbRef<fb::IStatement> statementHandle;
2797 FbRef<fb::IResultSet> resultSetHandle;
2798 FbRef<fb::IMessageMetadata> inMetadata;
2799 std::vector<Descriptor> inDescriptors;
2800 std::vector<std::byte> inMessage;
2801 FbRef<fb::IMessageMetadata> outMetadata;
2802 std::vector<Descriptor> outDescriptors;
2803 std::vector<std::byte> outMessage;
2805 unsigned cursorFlags = 0;
2814 inline std::optional<bool> Statement::get<std::optional<bool>>(
unsigned index)
2816 return getBool(index);
2820 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(
unsigned index)
2822 return getBlobId(index);
2826 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(
unsigned index)
2828 return getInt16(index);
2832 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(
unsigned index)
2834 return getScaledInt16(index);
2838 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(
unsigned index)
2840 return getInt32(index);
2844 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(
unsigned index)
2846 return getScaledInt32(index);
2850 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(
unsigned index)
2852 return getInt64(index);
2856 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(
unsigned index)
2858 return getScaledInt64(index);
2862 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(
unsigned index)
2864 return getScaledOpaqueInt128(index);
2867#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2869 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(
unsigned index)
2871 return getBoostInt128(index);
2875 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(
unsigned index)
2877 return getScaledBoostInt128(index);
2882 inline std::optional<float> Statement::get<std::optional<float>>(
unsigned index)
2884 return getFloat(index);
2888 inline std::optional<double> Statement::get<std::optional<double>>(
unsigned index)
2890 return getDouble(index);
2894 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(
unsigned index)
2896 return getOpaqueDecFloat16(index);
2899#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2901 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(
unsigned index)
2903 return getBoostDecFloat16(index);
2908 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(
unsigned index)
2910 return getOpaqueDecFloat34(index);
2913#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2915 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(
unsigned index)
2917 return getBoostDecFloat34(index);
2922 inline std::optional<Date> Statement::get<std::optional<Date>>(
unsigned index)
2924 return getDate(index);
2928 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(
unsigned index)
2930 return getOpaqueDate(index);
2934 inline std::optional<Time> Statement::get<std::optional<Time>>(
unsigned index)
2936 return getTime(index);
2940 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(
unsigned index)
2942 return getOpaqueTime(index);
2946 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(
unsigned index)
2948 return getOpaqueTimestamp(index);
2952 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(
unsigned index)
2954 return getTimestamp(index);
2958 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(
unsigned index)
2960 return getTimeTz(index);
2964 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(
unsigned index)
2966 return getOpaqueTimeTz(index);
2970 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(
unsigned index)
2972 return getTimestampTz(index);
2976 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(
unsigned index)
2978 return getOpaqueTimestampTz(index);
2982 inline std::optional<std::string> Statement::get<std::optional<std::string>>(
unsigned index)
2984 return getString(index);
Represents a connection to a Firebird database.
Client & getClient() noexcept
Returns the Client object reference used to create this Attachment object.
Represents a Firebird blob identifier.
ISC_QUAD id
Stores the raw Firebird blob identifier value.
Exception thrown when a Firebird database operation fails.
Base exception class for all fb-cpp exceptions.
Reference-counted smart pointer for Firebird objects using addRef/release semantics.
Represents options used when preparing a Statement.
const std::optional< std::string > & getCursorName() const
Returns the cursor name to be set for the statement.
StatementOptions & setCursorType(CursorType value)
Sets the cursor type used when opening a result set.
StatementOptions & setPrefetchLegacyPlan(bool value)
Enables or disables prefetching of the legacy textual plan at prepare time.
bool getPrefetchPlan() const
Reports whether the structured plan should be prefetched during prepare.
StatementOptions & setCursorName(const std::string &value)
Sets the cursor name for the statement.
StatementOptions & setPrefetchPlan(bool value)
Enables or disables prefetching of the structured plan at prepare time.
bool getPrefetchLegacyPlan() const
Reports whether the legacy textual plan should be prefetched during prepare.
CursorType getCursorType() const
Returns the cursor type to be used when opening a result set.
Prepares, executes, and fetches SQL statements against a Firebird attachment.
void set(unsigned index, OpaqueInt128 value)
Convenience overload that binds a Firebird 128-bit integer.
Statement & operator=(Statement &&o) noexcept
Transfers ownership of another prepared statement into this one.
void setScaledInt16(unsigned index, std::optional< ScaledInt16 > optValue)
Binds a scaled 16-bit signed integer value or null.
V get(unsigned index)
Retrieves a column value as a user-defined variant type.
bool fetchAbsolute(unsigned position)
Positions the cursor on the given absolute row number.
void setNull(unsigned index)
Marks the specified parameter as null.
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.
std::optional< OpaqueTime > getOpaqueTime(unsigned index)
Reads a raw time-of-day column in Firebird's representation.
std::optional< OpaqueDecFloat34 > getOpaqueDecFloat34(unsigned index)
Reads a Firebird 34-digit decimal floating-point column.
void setDate(unsigned index, std::optional< Date > optValue)
Binds a date value or null.
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.
void free()
Releases the prepared handle and any associated result set.
const std::vector< Descriptor > & getOutputDescriptors() noexcept
Provides cached descriptors for each output column.
bool isValid() noexcept
Returns whether the Statement object is valid.
StatementType getType() noexcept
Returns the type classification reported by the server.
void set(unsigned index, BoostDecFloat16 value)
Convenience overload that binds a Boost 16-digit decimal floating-point value.
std::optional< TimeTz > getTimeTz(unsigned index)
Reads a time-of-day column with timezone.
void setTime(unsigned index, std::optional< Time > optValue)
Binds a time-of-day value without timezone or null.
void set(unsigned index, std::string_view value)
Convenience overload that binds a textual value.
std::optional< BoostDecFloat34 > getBoostDecFloat34(unsigned index)
Reads a Boost-based 34-digit decimal floating-point column.
void setBlobId(unsigned index, std::optional< BlobId > optValue)
Binds a blob identifier to the specified parameter or null.
void setInt16(unsigned index, std::optional< std::int16_t > optValue)
Binds a 16-bit signed integer value or null.
void setString(unsigned index, std::optional< std::string_view > optValue)
Binds a textual parameter or null, performing direct conversions where supported.
void set(unsigned index, std::int32_t value)
Convenience overload that binds a 32-bit signed integer.
std::optional< Time > getTime(unsigned index)
Reads a time-of-day column without timezone.
std::optional< Date > getDate(unsigned index)
Reads a date column.
FbRef< fb::IResultSet > getResultSetHandle() noexcept
Provides access to the underlying Firebird currently open result set handle, if any.
bool isNull(unsigned index)
Reports whether the most recently fetched row has a null at the given column.
void set(unsigned index, double value)
Convenience overload that binds a double precision floating-point value.
void clearParameters()
Marks all bound parameters as null values.
void set(unsigned index, ScaledInt64 value)
Convenience overload that binds a scaled 64-bit signed integer.
std::optional< OpaqueDate > getOpaqueDate(unsigned index)
Reads a raw date column in Firebird's representation.
T get()
Retrieves all output columns into a user-defined aggregate struct.
void setScaledInt32(unsigned index, std::optional< ScaledInt32 > optValue)
Binds a scaled 32-bit signed integer value or null.
void set(unsigned index, std::int64_t value)
Convenience overload that binds a 64-bit signed integer.
void setTimestampTz(unsigned index, std::optional< TimestampTz > optValue)
Binds a timestamp value with timezone or null.
std::optional< std::int64_t > getInt64(unsigned index)
Reads a 64-bit signed integer column.
FbRef< fb::IStatement > getStatementHandle() noexcept
Provides direct access to the underlying Firebird statement handle.
std::optional< ScaledInt32 > getScaledInt32(unsigned index)
Reads a scaled 32-bit signed integer column.
void set(unsigned index, OpaqueTimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
void setOpaqueTime(unsigned index, std::optional< OpaqueTime > optValue)
Binds a raw time-of-day value in Firebird's representation or null.
std::optional< float > getFloat(unsigned index)
Reads a single precision floating-point column.
std::optional< double > getDouble(unsigned index)
Reads a double precision floating-point column.
std::optional< OpaqueTimestampTz > getOpaqueTimestampTz(unsigned index)
Reads a raw timestamp-with-time-zone column in Firebird's representation.
std::optional< ScaledInt16 > getScaledInt16(unsigned index)
Reads a scaled 16-bit signed integer column.
std::optional< BlobId > getBlobId(unsigned index)
Reads a blob identifier column.
Statement(Statement &&o) noexcept
Transfers ownership of an existing prepared statement.
void setInt64(unsigned index, std::optional< std::int64_t > optValue)
Binds a 64-bit signed integer value or null.
std::optional< ScaledOpaqueInt128 > getScaledOpaqueInt128(unsigned index)
Reads a Firebird scaled 128-bit integer column.
FbRef< fb::IMessageMetadata > getOutputMetadata() noexcept
Returns the metadata describing columns produced by the statement.
void set(unsigned index, TimeTz value)
Convenience overload that binds a Firebird time with timezone value.
void setOpaqueDecFloat16(unsigned index, std::optional< OpaqueDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value in Firebird's representation or null.
void setOpaqueInt128(unsigned index, std::optional< OpaqueInt128 > optValue)
Binds a raw 128-bit integer value in Firebird's representation or null.
std::optional< OpaqueTimeTz > getOpaqueTimeTz(unsigned index)
Reads a raw time-of-day column with timezone in Firebird's representation.
void setBoostInt128(unsigned index, std::optional< BoostInt128 > optValue)
Binds a 128-bit integer value expressed with Boost.Multiprecision or null.
void set(unsigned index, Date value)
Convenience overload that binds a Firebird date value.
void set(unsigned index, Timestamp value)
Convenience overload that binds a Firebird timestamp value.
void setOpaqueTimeTz(unsigned index, std::optional< OpaqueTimeTz > optValue)
Binds a raw time-of-day value with timezone in Firebird's representation or null.
void setTimestamp(unsigned index, std::optional< Timestamp > optValue)
Binds a timestamp value without timezone or null.
std::optional< std::string > getString(unsigned index)
Reads a textual column, applying number-to-string conversions when needed.
std::optional< std::int32_t > getInt32(unsigned index)
Reads a 32-bit signed integer column.
void set(unsigned index, OpaqueDecFloat16 value)
Convenience overload that binds a Firebird 16-digit decimal floating-point value.
void setOpaqueTimestampTz(unsigned index, std::optional< OpaqueTimestampTz > optValue)
Binds a raw timestamp value with timezone in Firebird's representation or null.
FbRef< fb::IMessageMetadata > getInputMetadata() noexcept
Returns the metadata describing prepared input parameters.
~Statement() noexcept
Releases resources; ignores failures to keep destructor noexcept.
void set(unsigned index, OpaqueTimeTz value)
Convenience overload that binds a Firebird time with timezone value.
void setBoostDecFloat16(unsigned index, std::optional< BoostDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value using Boost.Multiprecision or null.
std::optional< ScaledBoostInt128 > getScaledBoostInt128(unsigned index)
Reads a scaled Boost 128-bit integer column.
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.
void set(unsigned index, BoostDecFloat34 value)
Convenience overload that binds a Boost 34-digit decimal floating-point value.
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.
void set(unsigned index, Time value)
Convenience overload that binds a Firebird time value.
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.
std::optional< BoostInt128 > getBoostInt128(unsigned index)
Reads a Boost 128-bit integer column.
std::optional< bool > getBool(unsigned index)
Reads a boolean column from the current row.
void setOpaqueDecFloat34(unsigned index, std::optional< OpaqueDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value in Firebird's representation or null.
void set(unsigned index, OpaqueTimestamp value)
Convenience overload that binds a Firebird timestamp value.
void setInt32(unsigned index, std::optional< std::int32_t > optValue)
Binds a 32-bit signed integer value or null.
void set(unsigned index, std::optional< BlobId > value)
Convenience overload that binds an optional blob identifier.
void setBool(unsigned index, std::optional< bool > optValue)
Binds a boolean parameter value or null.
void set(unsigned index, const V &value)
Sets a parameter from a variant value.
void set(unsigned index, TimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
void setDouble(unsigned index, std::optional< double > optValue)
Binds a double precision floating-point value or null.
void set(unsigned index, OpaqueDate value)
Convenience overload that binds a Firebird date value.
void set(unsigned index, std::int16_t value)
Convenience overload that binds a 16-bit signed integer.
void set(unsigned index, std::optional< T > value)
Convenience template that forwards optional values to specialized overloads.
std::optional< OpaqueTimestamp > getOpaqueTimestamp(unsigned index)
Reads a raw timestamp column in Firebird's representation.
void setScaledInt64(unsigned index, std::optional< ScaledInt64 > optValue)
Binds a scaled 64-bit signed integer value or null.
void set(unsigned index, std::nullopt_t)
Convenience overload that binds a null value.
void setFloat(unsigned index, std::optional< float > optValue)
Binds a single precision floating-point value or null.
void setOpaqueDate(unsigned index, std::optional< OpaqueDate > optValue)
Binds a raw date value in Firebird's representation or null.
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.
void set(unsigned index, ScaledInt32 value)
Convenience overload that binds a scaled 32-bit signed integer.
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.
void set(unsigned index, ScaledBoostInt128 value)
Convenience overload that binds a scaled Boost-provided 128-bit integer.
bool fetchFirst()
Positions the cursor on the first row.
std::optional< TimestampTz > getTimestampTz(unsigned index)
Reads a timestamp-with-time-zone column.
void set(unsigned index, BoostInt128 value)
Convenience overload that binds a Boost-provided 128-bit integer.
std::optional< OpaqueDecFloat16 > getOpaqueDecFloat16(unsigned index)
Reads a Firebird 16-digit decimal floating-point column.
std::optional< Timestamp > getTimestamp(unsigned index)
Reads a timestamp column without timezone.
std::optional< BoostDecFloat16 > getBoostDecFloat16(unsigned index)
Reads a Boost-based 16-digit decimal floating-point column.
void setTimeTz(unsigned index, std::optional< TimeTz > optValue)
Binds a time-of-day value with timezone or null.
void setBoostDecFloat34(unsigned index, std::optional< BoostDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value using Boost.Multiprecision or null.
std::optional< ScaledInt64 > getScaledInt64(unsigned index)
Reads a scaled 64-bit signed integer column.
void set(unsigned index, bool value)
Convenience overload that binds a boolean value.
void setOpaqueTimestamp(unsigned index, std::optional< OpaqueTimestamp > optValue)
Binds a raw timestamp value in Firebird's representation or null.
void set(unsigned index, float value)
Convenience overload that binds a single precision floating-point value.
void set(const T &value)
Sets all input parameters from fields of a user-defined aggregate struct.
Represents a transaction in one or more Firebird databases.
CursorType
Selects the cursor type for a SELECT statement.
@ FORWARD_ONLY
Forward-only traversal (default, more efficient for streaming).
@ SCROLLABLE
Allows bidirectional traversal and absolute/relative positioning.
ScaledNumber< std::int64_t > ScaledInt64
Signed 64-bit scaled number.
ScaledNumber< std::int32_t > ScaledInt32
Signed 32-bit scaled number.
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 34 > > BoostDecFloat34
34-digit decimal floating point using Boost.Multiprecision.
FB_DEC16 OpaqueDecFloat16
Opaque 16-digit decimal floating point exposed by the Firebird API.
ScaledNumber< std::int16_t > ScaledInt16
Signed 16-bit scaled number.
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 16 > > BoostDecFloat16
16-digit decimal floating point using Boost.Multiprecision.
DescriptorAdjustedType
Descriptor adjusted type.
@ 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.
@ 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.
std::chrono::year_month_day Date
Firebird SQL calendar date.
FB_DEC34 OpaqueDecFloat34
Opaque 34-digit decimal floating point exposed by the Firebird API.
boost::multiprecision::int128_t BoostInt128
128-bit integer using Boost.Multiprecision.
ScaledNumber< BoostInt128 > ScaledBoostInt128
Scaled 128-bit integer backed by Boost.Multiprecision.
std::chrono::hh_mm_ss< std::chrono::microseconds > Time
Firebird SQL time-of-day with microsecond resolution.
Describes a parameter or column.
Wrapper for Firebird date values.
Wrapper for Firebird time-with-time-zone values.
Wrapper for Firebird time values.
Wrapper for Firebird timestamp-with-time-zone values.
Wrapper for Firebird timestamp values.
Represents a numeric value with an explicit decimal scale.
int scale
Decimal scale applied to value.
T value
Unscaled numeric value.
Local time bound to a time zone.
Timestamp bound to a time zone.
Combined date and time with microsecond precision.