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;
187 bool prefetchLegacyPlan =
false;
188 bool prefetchPlan =
false;
189 std::optional<std::string> cursorName;
191 unsigned dialect = SQL_DIALECT_CURRENT;
202 SELECT = isc_info_sql_stmt_select,
206 INSERT = isc_info_sql_stmt_insert,
210 UPDATE = isc_info_sql_stmt_update,
214 DELETE = isc_info_sql_stmt_delete,
218 DDL = isc_info_sql_stmt_ddl,
238 COMMIT = isc_info_sql_stmt_commit,
242 ROLLBACK = isc_info_sql_stmt_rollback,
277 : attachment{o.attachment},
278 status{std::move(o.status)},
279 statusWrapper{std::move(o.statusWrapper)},
280 calendarConverter{std::move(o.calendarConverter)},
281 numericConverter{std::move(o.numericConverter)},
282 statementHandle{std::move(o.statementHandle)},
283 resultSetHandle{std::move(o.resultSetHandle)},
284 inMetadata{std::move(o.inMetadata)},
285 inDescriptors{std::move(o.inDescriptors)},
286 inMessage{std::move(o.inMessage)},
287 outMetadata{std::move(o.outMetadata)},
288 outDescriptors{std::move(o.outDescriptors)},
289 outMessage{std::move(o.outMessage)},
291 cursorFlags{o.cursorFlags}
305 attachment = o.attachment;
306 status = std::move(o.status);
307 statusWrapper = std::move(o.statusWrapper);
308 calendarConverter = std::move(o.calendarConverter);
309 numericConverter = std::move(o.numericConverter);
310 statementHandle = std::move(o.statementHandle);
311 resultSetHandle = std::move(o.resultSetHandle);
312 inMetadata = std::move(o.inMetadata);
313 inDescriptors = std::move(o.inDescriptors);
314 inMessage = std::move(o.inMessage);
315 outMetadata = std::move(o.outMetadata);
316 outDescriptors = std::move(o.outDescriptors);
317 outMessage = std::move(o.outMessage);
319 cursorFlags = o.cursorFlags;
366 return statementHandle !=
nullptr;
375 return statementHandle;
384 return resultSetHandle;
442 return inDescriptors;
450 return outDescriptors;
528 const auto message = inMessage.data();
530 for (
const auto& descriptor : inDescriptors)
531 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
542 const auto& descriptor = getInDescriptor(index);
543 const auto message = inMessage.data();
545 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
553 void setBool(
unsigned index, std::optional<bool> optValue)
555 if (!optValue.has_value())
563 const auto& value = optValue.value();
564 const auto& descriptor = getInDescriptor(index);
565 const auto message = inMessage.data();
567 switch (descriptor.adjustedType)
570 message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
574 throwInvalidType(
"bool", descriptor.adjustedType);
577 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
583 void setInt16(
unsigned index, std::optional<std::int16_t> optValue)
585 if (!optValue.has_value())
599 if (!optValue.has_value())
605 const auto& value = optValue.value();
612 void setInt32(
unsigned index, std::optional<std::int32_t> optValue)
614 if (!optValue.has_value())
628 if (!optValue.has_value())
634 const auto& value = optValue.value();
641 void setInt64(
unsigned index, std::optional<std::int64_t> optValue)
643 if (!optValue.has_value())
657 if (!optValue.has_value())
663 const auto& value = optValue.value();
672 if (!optValue.has_value())
680 const auto& value = optValue.value();
681 const auto& descriptor = getInDescriptor(index);
682 const auto message = inMessage.data();
684 switch (descriptor.adjustedType)
687 *
reinterpret_cast<OpaqueInt128*
>(&message[descriptor.offset]) = value;
691 throwInvalidType(
"OpaqueInt128", descriptor.adjustedType);
694 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
697#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
703 if (!optValue.has_value())
717 if (!optValue.has_value())
723 const auto& value = optValue.value();
731 void setFloat(
unsigned index, std::optional<float> optValue)
733 if (!optValue.has_value())
745 void setDouble(
unsigned index, std::optional<double> optValue)
747 if (!optValue.has_value())
761 if (!optValue.has_value())
769 const auto& value = optValue.value();
770 const auto& descriptor = getInDescriptor(index);
771 const auto message = inMessage.data();
773 switch (descriptor.adjustedType)
780 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
783 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
786#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
792 if (!optValue.has_value())
807 if (!optValue.has_value())
815 const auto& value = optValue.value();
816 const auto& descriptor = getInDescriptor(index);
817 const auto message = inMessage.data();
819 switch (descriptor.adjustedType)
826 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
829 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
832#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
838 if (!optValue.has_value())
851 void setDate(
unsigned index, std::optional<Date> optValue)
853 if (!optValue.has_value())
861 const auto& value = optValue.value();
862 const auto& descriptor = getInDescriptor(index);
863 const auto message = inMessage.data();
865 switch (descriptor.adjustedType)
868 *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) =
869 calendarConverter.dateToOpaqueDate(value);
873 throwInvalidType(
"Date", descriptor.adjustedType);
876 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
884 if (!optValue.has_value())
892 const auto& value = optValue.value();
893 const auto& descriptor = getInDescriptor(index);
894 const auto message = inMessage.data();
896 switch (descriptor.adjustedType)
899 *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) = value;
903 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
906 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
912 void setTime(
unsigned index, std::optional<Time> optValue)
914 if (!optValue.has_value())
922 const auto& value = optValue.value();
923 const auto& descriptor = getInDescriptor(index);
924 const auto message = inMessage.data();
926 switch (descriptor.adjustedType)
929 *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) =
930 calendarConverter.timeToOpaqueTime(value);
934 throwInvalidType(
"Time", descriptor.adjustedType);
937 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
945 if (!optValue.has_value())
953 const auto& value = optValue.value();
954 const auto& descriptor = getInDescriptor(index);
955 const auto message = inMessage.data();
957 switch (descriptor.adjustedType)
960 *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) = value;
964 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
967 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
975 if (!optValue.has_value())
983 const auto& value = optValue.value();
984 const auto& descriptor = getInDescriptor(index);
985 const auto message = inMessage.data();
987 switch (descriptor.adjustedType)
991 calendarConverter.timestampToOpaqueTimestamp(value);
995 throwInvalidType(
"Timestamp", descriptor.adjustedType);
998 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1006 if (!optValue.has_value())
1014 const auto& value = optValue.value();
1015 const auto& descriptor = getInDescriptor(index);
1016 const auto message = inMessage.data();
1018 switch (descriptor.adjustedType)
1021 *
reinterpret_cast<OpaqueTimestamp*
>(&message[descriptor.offset]) = value;
1025 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
1028 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1034 void setTimeTz(
unsigned index, std::optional<TimeTz> optValue)
1036 if (!optValue.has_value())
1044 const auto& value = optValue.value();
1045 const auto& descriptor = getInDescriptor(index);
1046 auto*
const message = inMessage.data();
1048 switch (descriptor.adjustedType)
1051 *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) =
1052 calendarConverter.timeTzToOpaqueTimeTz(value);
1056 throwInvalidType(
"TimeTz", descriptor.adjustedType);
1059 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1067 if (!optValue.has_value())
1075 const auto& value = optValue.value();
1076 const auto& descriptor = getInDescriptor(index);
1077 auto*
const message = inMessage.data();
1079 switch (descriptor.adjustedType)
1082 *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) = value;
1086 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
1089 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1097 if (!optValue.has_value())
1105 const auto& value = optValue.value();
1106 const auto& descriptor = getInDescriptor(index);
1107 auto*
const message = inMessage.data();
1109 switch (descriptor.adjustedType)
1113 calendarConverter.timestampTzToOpaqueTimestampTz(value);
1117 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
1120 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1128 if (!optValue.has_value())
1136 const auto& value = optValue.value();
1137 const auto& descriptor = getInDescriptor(index);
1138 auto*
const message = inMessage.data();
1140 switch (descriptor.adjustedType)
1147 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
1150 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1156 void setString(
unsigned index, std::optional<std::string_view> optValue)
1158 if (!optValue.has_value())
1167 const auto value = optValue.value();
1168 const auto& descriptor = getInDescriptor(index);
1169 const auto message = inMessage.data();
1170 const auto data = &message[descriptor.offset];
1172 switch (descriptor.adjustedType)
1175 message[descriptor.offset] = numericConverter.stringToBoolean(value);
1182 std::string strValue(value);
1185 if (
const auto dotPos = strValue.find_last_of(
'.'); dotPos != std::string_view::npos)
1187 for (
auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1189 const char c = value[pos];
1191 if (c <
'0' || c >
'9')
1197 strValue.erase(dotPos, 1);
1200 static_assert(
sizeof(
long long) ==
sizeof(std::int64_t));
1201 std::int64_t intValue;
1202 const auto convResult =
1203 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1204 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1205 numericConverter.throwConversionErrorFromString(strValue);
1208 if (scale != descriptor.scale)
1211 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1212 scaledValue.scale = descriptor.scale;
1221 std::string strValue(value);
1222 client.getInt128Util(&statusWrapper)
1224 &statusWrapper, descriptor.scale, strValue.c_str(),
reinterpret_cast<OpaqueInt128*
>(data));
1232#if defined(__APPLE__)
1234 std::string valueString{value};
1235 char* parseEnd =
nullptr;
1236 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1237 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1238 numericConverter.throwConversionErrorFromString(std::move(valueString));
1240 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1241 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1242 numericConverter.throwConversionErrorFromString(std::string{value});
1249 *
reinterpret_cast<OpaqueDate*
>(data) = calendarConverter.stringToOpaqueDate(value);
1253 *
reinterpret_cast<OpaqueTime*
>(data) = calendarConverter.stringToOpaqueTime(value);
1257 *
reinterpret_cast<OpaqueTimestamp*
>(data) = calendarConverter.stringToOpaqueTimestamp(value);
1261 *
reinterpret_cast<OpaqueTimeTz*
>(data) = calendarConverter.stringToOpaqueTimeTz(value);
1265 *
reinterpret_cast<OpaqueTimestampTz*
>(data) = calendarConverter.stringToOpaqueTimestampTz(value);
1268#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1271 std::string strValue{value};
1272 client.getDecFloat16Util(&statusWrapper)
1273 ->fromString(&statusWrapper, strValue.c_str(),
reinterpret_cast<OpaqueDecFloat16*
>(data));
1279 std::string strValue{value};
1280 client.getDecFloat34Util(&statusWrapper)
1281 ->fromString(&statusWrapper, strValue.c_str(),
reinterpret_cast<OpaqueDecFloat34*
>(data));
1287 if (value.length() > descriptor.length)
1289 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1291 isc_string_truncation,
1298 *
reinterpret_cast<std::uint16_t*
>(data) =
static_cast<std::uint16_t
>(value.length());
1299 std::copy(value.begin(), value.end(),
1300 reinterpret_cast<char*
>(&message[descriptor.offset +
sizeof(std::uint16_t)]));
1304 throwInvalidType(
"std::string_view", descriptor.adjustedType);
1307 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1313 void setBlobId(
unsigned index, std::optional<BlobId> optValue)
1315 if (!optValue.has_value())
1323 const auto& value = optValue.value();
1324 const auto& descriptor = getInDescriptor(index);
1325 auto*
const message = inMessage.data();
1327 switch (descriptor.adjustedType)
1330 *
reinterpret_cast<ISC_QUAD*
>(&message[descriptor.offset]) = value.id;
1334 throwInvalidType(
"BlobId", descriptor.adjustedType);
1337 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1342 void set(
unsigned index, std::nullopt_t)
1358 void set(
unsigned index, std::optional<BlobId> value)
1366 void set(
unsigned index,
bool value)
1374 void set(
unsigned index, std::int16_t value)
1390 void set(
unsigned index, std::int32_t value)
1406 void set(
unsigned index, std::int64_t value)
1427#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1448 void set(
unsigned index,
float value)
1456 void set(
unsigned index,
double value)
1469#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1487#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1580 void set(
unsigned index, std::string_view value)
1588 template <
typename T>
1589 void set(
unsigned index, std::optional<T> value)
1591 if (value.has_value())
1592 set(index, value.value());
1612 const auto& descriptor = getOutDescriptor(index);
1613 const auto*
const message = outMessage.data();
1615 return *
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE;
1625 const auto& descriptor = getOutDescriptor(index);
1626 const auto*
const message = outMessage.data();
1628 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1629 return std::nullopt;
1631 switch (descriptor.adjustedType)
1634 return message[descriptor.offset] != std::byte{0};
1637 throwInvalidType(
"bool", descriptor.adjustedType);
1646 std::optional<int> scale{0};
1647 return getNumber<std::int16_t>(index, scale,
"std::int16_t");
1655 std::optional<int> scale;
1656 const auto value = getNumber<std::int16_t>(index, scale,
"ScaledInt16");
1657 return value.has_value() ? std::optional{
ScaledInt16{value.
value(), scale.value()}} : std::nullopt;
1665 std::optional<int> scale{0};
1666 return getNumber<std::int32_t>(index, scale,
"std::int32_t");
1674 std::optional<int> scale;
1675 const auto value = getNumber<std::int32_t>(index, scale,
"ScaledInt32");
1676 return value.has_value() ? std::optional{
ScaledInt32{value.
value(), scale.value()}} : std::nullopt;
1684 std::optional<int> scale{0};
1685 return getNumber<std::int64_t>(index, scale,
"std::int64_t");
1693 std::optional<int> scale;
1694 const auto value = getNumber<std::int64_t>(index, scale,
"ScaledInt64");
1695 return value.has_value() ? std::optional{
ScaledInt64{value.
value(), scale.value()}} : std::nullopt;
1705 const auto& descriptor = getOutDescriptor(index);
1706 const auto*
const message = outMessage.data();
1708 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1709 return std::nullopt;
1711 switch (descriptor.adjustedType)
1719 throwInvalidType(
"ScaledOpaqueInt128", descriptor.adjustedType);
1723#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1729 std::optional<int> scale{0};
1730 const auto value = getNumber<BoostInt128>(index, scale,
"BoostInt128");
1731 return value.has_value() ? std::optional{value.value()} : std::nullopt;
1739 std::optional<int> scale;
1740 const auto value = getNumber<BoostInt128>(index, scale,
"ScaledBoostInt128");
1741 return value.has_value() ? std::optional{
ScaledBoostInt128{value.
value(), scale.value()}} : std::nullopt;
1750 std::optional<int> scale{0};
1751 return getNumber<float>(index, scale,
"float");
1759 std::optional<int> scale{0};
1760 return getNumber<double>(index, scale,
"double");
1770 const auto& descriptor = getOutDescriptor(index);
1771 const auto*
const message = outMessage.data();
1773 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1774 return std::nullopt;
1776 switch (descriptor.adjustedType)
1782 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
1786#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1792 std::optional<int> scale{0};
1793 return getNumber<BoostDecFloat16>(index, scale,
"BoostDecFloat16");
1804 const auto& descriptor = getOutDescriptor(index);
1805 const auto*
const message = outMessage.data();
1807 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1808 return std::nullopt;
1810 switch (descriptor.adjustedType)
1816 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
1820#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1826 std::optional<int> scale{0};
1827 return getNumber<BoostDecFloat34>(index, scale,
"BoostDecFloat34");
1838 const auto& descriptor = getOutDescriptor(index);
1839 const auto*
const message = outMessage.data();
1841 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1842 return std::nullopt;
1844 switch (descriptor.adjustedType)
1847 return calendarConverter.opaqueDateToDate(
1848 *
reinterpret_cast<const OpaqueDate*
>(&message[descriptor.offset]));
1851 throwInvalidType(
"Date", descriptor.adjustedType);
1862 const auto& descriptor = getOutDescriptor(index);
1863 const auto*
const message = outMessage.data();
1865 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1866 return std::nullopt;
1868 switch (descriptor.adjustedType)
1874 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
1885 const auto& descriptor = getOutDescriptor(index);
1886 const auto*
const message = outMessage.data();
1888 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1889 return std::nullopt;
1891 switch (descriptor.adjustedType)
1894 return calendarConverter.opaqueTimeToTime(
1895 *
reinterpret_cast<const OpaqueTime*
>(&message[descriptor.offset]));
1898 throwInvalidType(
"Time", descriptor.adjustedType);
1909 const auto& descriptor = getOutDescriptor(index);
1910 const auto*
const message = outMessage.data();
1912 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1913 return std::nullopt;
1915 switch (descriptor.adjustedType)
1921 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
1932 const auto& descriptor = getOutDescriptor(index);
1933 const auto*
const message = outMessage.data();
1935 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1936 return std::nullopt;
1938 switch (descriptor.adjustedType)
1941 return calendarConverter.opaqueTimestampToTimestamp(
1942 *
reinterpret_cast<const OpaqueTimestamp*
>(&message[descriptor.offset]));
1945 throwInvalidType(
"Timestamp", descriptor.adjustedType);
1956 const auto& descriptor = getOutDescriptor(index);
1957 const auto*
const message = outMessage.data();
1959 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1960 return std::nullopt;
1962 switch (descriptor.adjustedType)
1968 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
1979 const auto& descriptor = getOutDescriptor(index);
1980 const auto*
const message = outMessage.data();
1982 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1983 return std::nullopt;
1985 switch (descriptor.adjustedType)
1988 return calendarConverter.opaqueTimeTzToTimeTz(
1989 *
reinterpret_cast<const OpaqueTimeTz*
>(&message[descriptor.offset]));
1992 throwInvalidType(
"TimeTz", descriptor.adjustedType);
2003 const auto& descriptor = getOutDescriptor(index);
2004 const auto*
const message = outMessage.data();
2006 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2007 return std::nullopt;
2009 switch (descriptor.adjustedType)
2015 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
2026 const auto& descriptor = getOutDescriptor(index);
2027 const auto*
const message = outMessage.data();
2029 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2030 return std::nullopt;
2032 switch (descriptor.adjustedType)
2035 return calendarConverter.opaqueTimestampTzToTimestampTz(
2039 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
2050 const auto& descriptor = getOutDescriptor(index);
2051 const auto*
const message = outMessage.data();
2053 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2054 return std::nullopt;
2056 switch (descriptor.adjustedType)
2062 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
2073 const auto& descriptor = getOutDescriptor(index);
2074 const auto*
const message = outMessage.data();
2076 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2077 return std::nullopt;
2079 switch (descriptor.adjustedType)
2084 value.
id = *
reinterpret_cast<const ISC_QUAD*
>(&message[descriptor.offset]);
2089 throwInvalidType(
"BlobId", descriptor.adjustedType);
2100 const auto& descriptor = getOutDescriptor(index);
2101 const auto*
const message = outMessage.data();
2103 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2104 return std::nullopt;
2106 const auto data = &message[descriptor.offset];
2108 switch (descriptor.adjustedType)
2111 return (message[descriptor.offset] != std::byte{0}) ? std::string{
"true"} : std::string{
"false"};
2114 return numericConverter.numberToString(
2115 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.
scale});
2118 return numericConverter.numberToString(
2119 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.
scale});
2122 return numericConverter.numberToString(
2123 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.
scale});
2126 return numericConverter.opaqueInt128ToString(
2127 *
reinterpret_cast<const OpaqueInt128*
>(data), descriptor.scale);
2130 return numericConverter.numberToString(*
reinterpret_cast<const float*
>(data));
2133 return numericConverter.numberToString(*
reinterpret_cast<const double*
>(data));
2136 return calendarConverter.opaqueDateToString(*
reinterpret_cast<const OpaqueDate*
>(data));
2139 return calendarConverter.opaqueTimeToString(*
reinterpret_cast<const OpaqueTime*
>(data));
2142 return calendarConverter.opaqueTimestampToString(*
reinterpret_cast<const OpaqueTimestamp*
>(data));
2145 return calendarConverter.opaqueTimeTzToString(*
reinterpret_cast<const OpaqueTimeTz*
>(data));
2148 return calendarConverter.opaqueTimestampTzToString(
2152 return numericConverter.opaqueDecFloat16ToString(*
reinterpret_cast<const OpaqueDecFloat16*
>(data));
2155 return numericConverter.opaqueDecFloat34ToString(*
reinterpret_cast<const OpaqueDecFloat34*
>(data));
2158 return std::string{
reinterpret_cast<const char*
>(data +
sizeof(std::uint16_t)),
2159 *
reinterpret_cast<const std::uint16_t*
>(data)};
2162 throwInvalidType(
"std::string", descriptor.adjustedType);
2173 template <
typename T>
2183 template <Aggregate T>
2186 using namespace impl::reflection;
2188 constexpr std::size_t N = fieldCountV<T>;
2190 if (N != outDescriptors.size())
2192 throw FbCppException(
"Struct field count (" + std::to_string(N) +
2193 ") does not match output column count (" + std::to_string(outDescriptors.size()) +
")");
2196 return getStruct<T>(std::make_index_sequence<N>{});
2205 template <Aggregate T>
2208 using namespace impl::reflection;
2210 constexpr std::size_t N = fieldCountV<T>;
2212 if (N != inDescriptors.size())
2214 throw FbCppException(
"Struct field count (" + std::to_string(N) +
2215 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) +
")");
2218 setStruct(value, std::make_index_sequence<N>{});
2228 template <TupleLike T>
2231 using namespace impl::reflection;
2233 constexpr std::size_t N = std::tuple_size_v<T>;
2235 if (N != outDescriptors.size())
2237 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
2238 ") does not match output column count (" + std::to_string(outDescriptors.size()) +
")");
2241 return getTuple<T>(std::make_index_sequence<N>{});
2250 template <TupleLike T>
2253 constexpr std::size_t N = std::tuple_size_v<T>;
2255 if (N != inDescriptors.size())
2257 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
2258 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) +
")");
2261 setTuple(value, std::make_index_sequence<N>{});
2272 template <VariantLike V>
2275 using namespace impl::reflection;
2277 static_assert(variantAlternativesSupportedV<V>,
2278 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2279 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2280 "complete list of supported types.");
2284 const auto& descriptor = getOutDescriptor(index);
2288 if constexpr (variantContainsV<std::monostate, V>)
2289 return V{std::monostate{}};
2293 "NULL value encountered but variant does not contain std::monostate at index " +
2294 std::to_string(index));
2298 return getVariantValue<V>(index, descriptor);
2307 template <VariantLike V>
2308 void set(
unsigned index,
const V& value)
2310 using namespace impl::reflection;
2312 static_assert(variantAlternativesSupportedV<V>,
2313 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2314 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2315 "complete list of supported types.");
2318 [
this, index](
const auto& v)
2320 using T = std::decay_t<
decltype(v)>;
2322 if constexpr (std::is_same_v<T, std::monostate>)
2334 const Descriptor& getInDescriptor(
unsigned index)
2336 if (index >= inDescriptors.size())
2337 throw std::out_of_range(
"index out of range");
2339 return inDescriptors[index];
2345 const Descriptor& getOutDescriptor(
unsigned index)
2347 if (index >= outDescriptors.size())
2348 throw std::out_of_range(
"index out of range");
2350 return outDescriptors[index];
2356 template <
typename T, std::size_t... Is>
2357 T getStruct(std::index_sequence<Is...>)
2359 using namespace impl::reflection;
2361 return T{getStructField<FieldType<T, Is>>(
static_cast<unsigned>(Is))...};
2367 template <
typename F>
2368 auto getStructField(
unsigned index)
2370 using namespace impl::reflection;
2372 if constexpr (isOptionalV<F>)
2373 return get<F>(index);
2374 else if constexpr (isVariantV<F>)
2375 return get<F>(index);
2378 auto opt = get<std::optional<F>>(index);
2380 if (!opt.has_value())
2382 throw FbCppException(
2383 "Null value encountered for non-optional field at index " + std::to_string(index));
2386 return std::move(opt.value());
2393 template <
typename T, std::size_t... Is>
2394 void setStruct(
const T& value, std::index_sequence<Is...>)
2396 using namespace impl::reflection;
2398 const auto tuple = toTupleRef(value);
2399 (
set(
static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
2405 template <
typename T, std::size_t... Is>
2406 T getTuple(std::index_sequence<Is...>)
2408 using namespace impl::reflection;
2410 return T{getStructField<std::tuple_element_t<Is, T>>(
static_cast<unsigned>(Is))...};
2416 template <
typename T, std::size_t... Is>
2417 void setTuple(
const T& value, std::index_sequence<Is...>)
2419 (
set(
static_cast<unsigned>(Is), std::get<Is>(value)), ...);
2426 template <
typename V>
2427 V getVariantValue(
unsigned index,
const Descriptor& descriptor)
2429 using namespace impl::reflection;
2432 switch (descriptor.adjustedType)
2435 if constexpr (variantContainsV<bool, V>)
2436 return V{get<std::optional<bool>>(index).value()};
2440 if (descriptor.scale != 0)
2443 if constexpr (variantContainsV<ScaledInt16, V>)
2444 return V{get<std::optional<ScaledInt16>>(index).value()};
2445 if constexpr (variantContainsV<ScaledInt32, V>)
2446 return V{get<std::optional<ScaledInt32>>(index).value()};
2447 if constexpr (variantContainsV<ScaledInt64, V>)
2448 return V{get<std::optional<ScaledInt64>>(index).value()};
2449#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2450 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2451 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2454 if constexpr (variantContainsV<std::int16_t, V>)
2455 return V{get<std::optional<std::int16_t>>(index).value()};
2459 if (descriptor.scale != 0)
2462 if constexpr (variantContainsV<ScaledInt32, V>)
2463 return V{get<std::optional<ScaledInt32>>(index).value()};
2464 if constexpr (variantContainsV<ScaledInt64, V>)
2465 return V{get<std::optional<ScaledInt64>>(index).value()};
2466#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2467 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2468 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2471 if constexpr (variantContainsV<std::int32_t, V>)
2472 return V{get<std::optional<std::int32_t>>(index).value()};
2476 if (descriptor.scale != 0)
2479 if constexpr (variantContainsV<ScaledInt64, V>)
2480 return V{get<std::optional<ScaledInt64>>(index).value()};
2481#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2482 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2483 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2486 if constexpr (variantContainsV<std::int64_t, V>)
2487 return V{get<std::optional<std::int64_t>>(index).value()};
2490#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2493 if constexpr (variantContainsV<ScaledOpaqueInt128, V>)
2494 return V{get<std::optional<ScaledOpaqueInt128>>(index).value()};
2495 else if (descriptor.scale != 0)
2497 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2498 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2500 else if constexpr (variantContainsV<BoostInt128, V>)
2501 return V{get<std::optional<BoostInt128>>(index).value()};
2506 if constexpr (variantContainsV<float, V>)
2507 return V{get<std::optional<float>>(index).value()};
2511 if constexpr (variantContainsV<double, V>)
2512 return V{get<std::optional<double>>(index).value()};
2515#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2518 if constexpr (variantContainsV<OpaqueDecFloat16, V>)
2519 return V{get<std::optional<OpaqueDecFloat16>>(index).value()};
2520 else if constexpr (variantContainsV<BoostDecFloat16, V>)
2521 return V{get<std::optional<BoostDecFloat16>>(index).value()};
2526 if constexpr (variantContainsV<OpaqueDecFloat34, V>)
2527 return V{get<std::optional<OpaqueDecFloat34>>(index).value()};
2528 else if constexpr (variantContainsV<BoostDecFloat34, V>)
2529 return V{get<std::optional<BoostDecFloat34>>(index).value()};
2534 if constexpr (variantContainsV<std::string, V>)
2535 return V{get<std::optional<std::string>>(index).value()};
2540 if constexpr (variantContainsV<OpaqueDate, V>)
2541 return V{get<std::optional<OpaqueDate>>(index).value()};
2542 else if constexpr (variantContainsV<Date, V>)
2543 return V{get<std::optional<Date>>(index).value()};
2548 if constexpr (variantContainsV<OpaqueTime, V>)
2549 return V{get<std::optional<OpaqueTime>>(index).value()};
2550 else if constexpr (variantContainsV<Time, V>)
2551 return V{get<std::optional<Time>>(index).value()};
2556 if constexpr (variantContainsV<OpaqueTimestamp, V>)
2557 return V{get<std::optional<OpaqueTimestamp>>(index).value()};
2558 else if constexpr (variantContainsV<Timestamp, V>)
2559 return V{get<std::optional<Timestamp>>(index).value()};
2564 if constexpr (variantContainsV<OpaqueTimeTz, V>)
2565 return V{get<std::optional<OpaqueTimeTz>>(index).value()};
2566 else if constexpr (variantContainsV<TimeTz, V>)
2567 return V{get<std::optional<TimeTz>>(index).value()};
2572 if constexpr (variantContainsV<OpaqueTimestampTz, V>)
2573 return V{get<std::optional<OpaqueTimestampTz>>(index).value()};
2574 else if constexpr (variantContainsV<TimestampTz, V>)
2575 return V{get<std::optional<TimestampTz>>(index).value()};
2579 if constexpr (variantContainsV<BlobId, V>)
2580 return V{get<std::optional<BlobId>>(index).value()};
2588 return tryVariantAlternatives<V, 0>(index, descriptor);
2594 template <
typename V, std::
size_t I = 0>
2595 V tryVariantAlternatives(
unsigned index, [[maybe_unused]]
const Descriptor& descriptor)
2597 using namespace impl::reflection;
2599 if constexpr (I >= std::variant_size_v<V>)
2601 throw FbCppException(
2602 "Cannot convert SQL type to any variant alternative at index " + std::to_string(index));
2606 using Alt = std::variant_alternative_t<I, V>;
2608 if constexpr (std::is_same_v<Alt, std::monostate>)
2611 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2613 else if constexpr (isOpaqueTypeV<Alt>)
2616 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2621 auto opt = get<std::optional<Alt>>(index);
2622 return V{std::move(opt.value())};
2630 template <
typename T>
2631 void setNumber(
unsigned index,
DescriptorAdjustedType valueType, T value,
int scale,
const char* typeName)
2635 const auto& descriptor = getInDescriptor(index);
2636 auto*
const message = inMessage.data();
2638 const auto descriptorData = &message[descriptor.offset];
2639 std::optional<int> descriptorScale{descriptor.scale};
2641 Descriptor valueDescriptor;
2642 valueDescriptor.adjustedType = valueType;
2643 valueDescriptor.scale = scale;
2645 const auto valueAddress =
reinterpret_cast<const std::byte*
>(&value);
2647 switch (descriptor.adjustedType)
2650 *
reinterpret_cast<std::int16_t*
>(descriptorData) =
2651 convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int16_t");
2655 *
reinterpret_cast<std::int32_t*
>(descriptorData) =
2656 convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int32_t");
2660 *
reinterpret_cast<std::int64_t*
>(descriptorData) =
2661 convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int64_t");
2664#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2667 const auto boostInt128 =
2668 convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale,
"BoostInt128");
2670 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
2676 *
reinterpret_cast<float*
>(descriptorData) =
2677 convertNumber<float>(valueDescriptor, valueAddress, descriptorScale,
"float");
2681 *
reinterpret_cast<double*
>(descriptorData) =
2682 convertNumber<double>(valueDescriptor, valueAddress, descriptorScale,
"double");
2685#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2688 const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
2689 valueDescriptor, valueAddress, descriptorScale,
"BoostDecFloat16");
2691 numericConverter.boostDecFloat16ToOpaqueDecFloat16(boostDecFloat16);
2697 const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
2698 valueDescriptor, valueAddress, descriptorScale,
"BoostDecFloat34");
2700 numericConverter.boostDecFloat34ToOpaqueDecFloat34(boostDecFloat34);
2706 throwInvalidType(typeName, descriptor.adjustedType);
2709 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
2716 template <
typename T>
2717 std::optional<T> getNumber(
unsigned index, std::optional<int>& scale,
const char* typeName)
2721 const auto& descriptor = getOutDescriptor(index);
2722 const auto*
const message = outMessage.data();
2724 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2725 return std::nullopt;
2727 auto data = &message[descriptor.offset];
2728#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2729 std::optional<BoostInt128> boostInt128;
2730 std::optional<BoostDecFloat16> boostDecFloat16;
2731 std::optional<BoostDecFloat34> boostDecFloat34;
2735 switch (descriptor.adjustedType)
2737#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2739 boostInt128.emplace(
2740 numericConverter.opaqueInt128ToBoostInt128(*
reinterpret_cast<const OpaqueInt128*
>(data)));
2741 data =
reinterpret_cast<const std::byte*
>(&boostInt128.value());
2745 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
2747 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat16.value());
2751 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
2753 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat34.value());
2761 return convertNumber<T>(descriptor, data, scale, typeName);
2766 throw FbCppException(
"Invalid type: actual type " + std::string(actualType) +
", descriptor type " +
2767 std::to_string(
static_cast<unsigned>(descriptorType)));
2770 template <
typename T>
2772 const Descriptor& descriptor,
const std::byte* data, std::optional<int>& toScale,
const char* toTypeName)
2774 if (!toScale.has_value())
2776 switch (descriptor.adjustedType)
2782 throwInvalidType(toTypeName, descriptor.adjustedType);
2788 toScale = descriptor.scale;
2791 switch (descriptor.adjustedType)
2794 return numericConverter.numberToNumber<T>(
2795 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.scale}, toScale.value());
2799 return numericConverter.numberToNumber<T>(
2800 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.scale}, toScale.value());
2803 return numericConverter.numberToNumber<T>(
2804 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.scale}, toScale.value());
2806#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2808 return numericConverter.numberToNumber<T>(
2813 return numericConverter.numberToNumber<T>(
2817 return numericConverter.numberToNumber<T>(
2822 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const float*
>(data), toScale.value());
2826 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const double*
>(data), toScale.value());
2830 throwInvalidType(toTypeName, descriptor.adjustedType);
2835 Attachment* attachment;
2836 FbUniquePtr<Firebird::IStatus> status;
2837 impl::StatusWrapper statusWrapper;
2838 impl::CalendarConverter calendarConverter;
2839 impl::NumericConverter numericConverter;
2840 FbRef<fb::IStatement> statementHandle;
2841 FbRef<fb::IResultSet> resultSetHandle;
2842 FbRef<fb::IMessageMetadata> inMetadata;
2843 std::vector<Descriptor> inDescriptors;
2844 std::vector<std::byte> inMessage;
2845 FbRef<fb::IMessageMetadata> outMetadata;
2846 std::vector<Descriptor> outDescriptors;
2847 std::vector<std::byte> outMessage;
2849 unsigned cursorFlags = 0;
2858 inline std::optional<bool> Statement::get<std::optional<bool>>(
unsigned index)
2860 return getBool(index);
2864 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(
unsigned index)
2866 return getBlobId(index);
2870 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(
unsigned index)
2872 return getInt16(index);
2876 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(
unsigned index)
2878 return getScaledInt16(index);
2882 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(
unsigned index)
2884 return getInt32(index);
2888 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(
unsigned index)
2890 return getScaledInt32(index);
2894 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(
unsigned index)
2896 return getInt64(index);
2900 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(
unsigned index)
2902 return getScaledInt64(index);
2906 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(
unsigned index)
2908 return getScaledOpaqueInt128(index);
2911#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2913 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(
unsigned index)
2915 return getBoostInt128(index);
2919 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(
unsigned index)
2921 return getScaledBoostInt128(index);
2926 inline std::optional<float> Statement::get<std::optional<float>>(
unsigned index)
2928 return getFloat(index);
2932 inline std::optional<double> Statement::get<std::optional<double>>(
unsigned index)
2934 return getDouble(index);
2938 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(
unsigned index)
2940 return getOpaqueDecFloat16(index);
2943#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2945 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(
unsigned index)
2947 return getBoostDecFloat16(index);
2952 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(
unsigned index)
2954 return getOpaqueDecFloat34(index);
2957#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2959 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(
unsigned index)
2961 return getBoostDecFloat34(index);
2966 inline std::optional<Date> Statement::get<std::optional<Date>>(
unsigned index)
2968 return getDate(index);
2972 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(
unsigned index)
2974 return getOpaqueDate(index);
2978 inline std::optional<Time> Statement::get<std::optional<Time>>(
unsigned index)
2980 return getTime(index);
2984 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(
unsigned index)
2986 return getOpaqueTime(index);
2990 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(
unsigned index)
2992 return getOpaqueTimestamp(index);
2996 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(
unsigned index)
2998 return getTimestamp(index);
3002 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(
unsigned index)
3004 return getTimeTz(index);
3008 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(
unsigned index)
3010 return getOpaqueTimeTz(index);
3014 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(
unsigned index)
3016 return getTimestampTz(index);
3020 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(
unsigned index)
3022 return getOpaqueTimestampTz(index);
3026 inline std::optional<std::string> Statement::get<std::optional<std::string>>(
unsigned index)
3028 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.
unsigned getDialect() const
Returns the SQL dialect used when preparing the statement.
StatementOptions & setDialect(unsigned value)
Sets the SQL dialect used when preparing 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.
std::vector< std::byte > & getOutputMessage() noexcept
Provides direct access to the raw output message buffer.
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.
Attachment & getAttachment() noexcept
Returns the Attachment object reference used to create this Statement.
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::vector< std::byte > & getInputMessage() noexcept
Provides direct access to the raw input message buffer.
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.