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>
80 return prefetchLegacyPlan;
90 prefetchLegacyPlan = value;
109 prefetchPlan = value;
133 bool prefetchLegacyPlan =
false;
134 bool prefetchPlan =
false;
135 std::optional<std::string> cursorName;
146 SELECT = isc_info_sql_stmt_select,
150 INSERT = isc_info_sql_stmt_insert,
154 UPDATE = isc_info_sql_stmt_update,
158 DELETE = isc_info_sql_stmt_delete,
162 DDL = isc_info_sql_stmt_ddl,
182 COMMIT = isc_info_sql_stmt_commit,
186 ROLLBACK = isc_info_sql_stmt_rollback,
221 : attachment{o.attachment},
222 status{std::move(o.status)},
223 statusWrapper{std::move(o.statusWrapper)},
224 calendarConverter{std::move(o.calendarConverter)},
225 numericConverter{std::move(o.numericConverter)},
226 statementHandle{std::move(o.statementHandle)},
227 resultSetHandle{std::move(o.resultSetHandle)},
228 inMetadata{std::move(o.inMetadata)},
229 inDescriptors{std::move(o.inDescriptors)},
230 inMessage{std::move(o.inMessage)},
231 outMetadata{std::move(o.outMetadata)},
232 outDescriptors{std::move(o.outDescriptors)},
233 outMessage{std::move(o.outMessage)},
238 Statement& operator=(Statement&&) =
delete;
240 Statement& operator=(
const Statement&) =
delete;
272 return statementHandle !=
nullptr;
281 return statementHandle;
290 return resultSetHandle;
332 return inDescriptors;
340 return outDescriptors;
418 const auto message = inMessage.data();
420 for (
const auto& descriptor : inDescriptors)
421 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
432 const auto& descriptor = getInDescriptor(index);
433 const auto message = inMessage.data();
435 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
443 void setBool(
unsigned index, std::optional<bool> optValue)
445 if (!optValue.has_value())
453 const auto& value = optValue.value();
454 const auto& descriptor = getInDescriptor(index);
455 const auto message = inMessage.data();
457 switch (descriptor.adjustedType)
460 message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
464 throwInvalidType(
"bool", descriptor.adjustedType);
467 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
473 void setInt16(
unsigned index, std::optional<std::int16_t> optValue)
475 if (!optValue.has_value())
489 if (!optValue.has_value())
495 const auto& value = optValue.value();
502 void setInt32(
unsigned index, std::optional<std::int32_t> optValue)
504 if (!optValue.has_value())
518 if (!optValue.has_value())
524 const auto& value = optValue.value();
531 void setInt64(
unsigned index, std::optional<std::int64_t> optValue)
533 if (!optValue.has_value())
547 if (!optValue.has_value())
553 const auto& value = optValue.value();
562 if (!optValue.has_value())
570 const auto& value = optValue.value();
571 const auto& descriptor = getInDescriptor(index);
572 const auto message = inMessage.data();
574 switch (descriptor.adjustedType)
577 *
reinterpret_cast<OpaqueInt128*
>(&message[descriptor.offset]) = value;
581 throwInvalidType(
"OpaqueInt128", descriptor.adjustedType);
584 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
587#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
593 if (!optValue.has_value())
607 if (!optValue.has_value())
613 const auto& value = optValue.value();
621 void setFloat(
unsigned index, std::optional<float> optValue)
623 if (!optValue.has_value())
635 void setDouble(
unsigned index, std::optional<double> optValue)
637 if (!optValue.has_value())
651 if (!optValue.has_value())
659 const auto& value = optValue.value();
660 const auto& descriptor = getInDescriptor(index);
661 const auto message = inMessage.data();
663 switch (descriptor.adjustedType)
670 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
673 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
676#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
682 if (!optValue.has_value())
697 if (!optValue.has_value())
705 const auto& value = optValue.value();
706 const auto& descriptor = getInDescriptor(index);
707 const auto message = inMessage.data();
709 switch (descriptor.adjustedType)
716 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
719 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
722#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
728 if (!optValue.has_value())
741 void setDate(
unsigned index, std::optional<Date> optValue)
743 if (!optValue.has_value())
751 const auto& value = optValue.value();
752 const auto& descriptor = getInDescriptor(index);
753 const auto message = inMessage.data();
755 switch (descriptor.adjustedType)
758 *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) =
759 calendarConverter.dateToOpaqueDate(value);
763 throwInvalidType(
"Date", descriptor.adjustedType);
766 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
774 if (!optValue.has_value())
782 const auto& value = optValue.value();
783 const auto& descriptor = getInDescriptor(index);
784 const auto message = inMessage.data();
786 switch (descriptor.adjustedType)
789 *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) = value;
793 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
796 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
802 void setTime(
unsigned index, std::optional<Time> optValue)
804 if (!optValue.has_value())
812 const auto& value = optValue.value();
813 const auto& descriptor = getInDescriptor(index);
814 const auto message = inMessage.data();
816 switch (descriptor.adjustedType)
819 *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) =
820 calendarConverter.timeToOpaqueTime(value);
824 throwInvalidType(
"Time", descriptor.adjustedType);
827 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
835 if (!optValue.has_value())
843 const auto& value = optValue.value();
844 const auto& descriptor = getInDescriptor(index);
845 const auto message = inMessage.data();
847 switch (descriptor.adjustedType)
850 *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) = value;
854 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
857 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
865 if (!optValue.has_value())
873 const auto& value = optValue.value();
874 const auto& descriptor = getInDescriptor(index);
875 const auto message = inMessage.data();
877 switch (descriptor.adjustedType)
881 calendarConverter.timestampToOpaqueTimestamp(value);
885 throwInvalidType(
"Timestamp", descriptor.adjustedType);
888 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
896 if (!optValue.has_value())
904 const auto& value = optValue.value();
905 const auto& descriptor = getInDescriptor(index);
906 const auto message = inMessage.data();
908 switch (descriptor.adjustedType)
911 *
reinterpret_cast<OpaqueTimestamp*
>(&message[descriptor.offset]) = value;
915 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
918 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
924 void setTimeTz(
unsigned index, std::optional<TimeTz> optValue)
926 if (!optValue.has_value())
934 const auto& value = optValue.value();
935 const auto& descriptor = getInDescriptor(index);
936 auto*
const message = inMessage.data();
938 switch (descriptor.adjustedType)
941 *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) =
942 calendarConverter.timeTzToOpaqueTimeTz(value);
946 throwInvalidType(
"TimeTz", descriptor.adjustedType);
949 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
957 if (!optValue.has_value())
965 const auto& value = optValue.value();
966 const auto& descriptor = getInDescriptor(index);
967 auto*
const message = inMessage.data();
969 switch (descriptor.adjustedType)
972 *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) = value;
976 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
979 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
987 if (!optValue.has_value())
995 const auto& value = optValue.value();
996 const auto& descriptor = getInDescriptor(index);
997 auto*
const message = inMessage.data();
999 switch (descriptor.adjustedType)
1003 calendarConverter.timestampTzToOpaqueTimestampTz(value);
1007 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
1010 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1018 if (!optValue.has_value())
1026 const auto& value = optValue.value();
1027 const auto& descriptor = getInDescriptor(index);
1028 auto*
const message = inMessage.data();
1030 switch (descriptor.adjustedType)
1037 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
1040 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1046 void setString(
unsigned index, std::optional<std::string_view> optValue)
1048 if (!optValue.has_value())
1057 const auto value = optValue.value();
1058 const auto& descriptor = getInDescriptor(index);
1059 const auto message = inMessage.data();
1060 const auto data = &message[descriptor.offset];
1062 switch (descriptor.adjustedType)
1065 message[descriptor.offset] = numericConverter.stringToBoolean(value);
1072 std::string strValue(value);
1075 if (
const auto dotPos = strValue.find_last_of(
'.'); dotPos != std::string_view::npos)
1077 for (
auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1079 const char c = value[pos];
1081 if (c <
'0' || c >
'9')
1087 strValue.erase(dotPos, 1);
1090 static_assert(
sizeof(
long long) ==
sizeof(std::int64_t));
1091 std::int64_t intValue;
1092 const auto convResult =
1093 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1094 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1095 numericConverter.throwConversionErrorFromString(strValue);
1098 if (scale != descriptor.scale)
1101 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1102 scaledValue.scale = descriptor.scale;
1111 std::string strValue(value);
1112 client.getInt128Util(&statusWrapper)
1114 &statusWrapper, descriptor.scale, strValue.c_str(),
reinterpret_cast<OpaqueInt128*
>(data));
1122#if defined(__APPLE__)
1124 std::string valueString{value};
1125 char* parseEnd =
nullptr;
1126 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1127 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1128 numericConverter.throwConversionErrorFromString(std::move(valueString));
1130 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1131 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1132 numericConverter.throwConversionErrorFromString(std::string{value});
1139 *
reinterpret_cast<OpaqueDate*
>(data) = calendarConverter.stringToOpaqueDate(value);
1143 *
reinterpret_cast<OpaqueTime*
>(data) = calendarConverter.stringToOpaqueTime(value);
1147 *
reinterpret_cast<OpaqueTimestamp*
>(data) = calendarConverter.stringToOpaqueTimestamp(value);
1151 *
reinterpret_cast<OpaqueTimeTz*
>(data) = calendarConverter.stringToOpaqueTimeTz(value);
1155 *
reinterpret_cast<OpaqueTimestampTz*
>(data) = calendarConverter.stringToOpaqueTimestampTz(value);
1158#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1161 std::string strValue{value};
1162 client.getDecFloat16Util(&statusWrapper)
1163 ->fromString(&statusWrapper, strValue.c_str(),
reinterpret_cast<OpaqueDecFloat16*
>(data));
1169 std::string strValue{value};
1170 client.getDecFloat34Util(&statusWrapper)
1171 ->fromString(&statusWrapper, strValue.c_str(),
reinterpret_cast<OpaqueDecFloat34*
>(data));
1177 if (value.length() > descriptor.length)
1179 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1181 isc_string_truncation,
1188 *
reinterpret_cast<std::uint16_t*
>(data) =
static_cast<std::uint16_t
>(value.length());
1189 std::copy(value.begin(), value.end(),
1190 reinterpret_cast<char*
>(&message[descriptor.offset +
sizeof(std::uint16_t)]));
1194 throwInvalidType(
"std::string_view", descriptor.adjustedType);
1197 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1203 void setBlobId(
unsigned index, std::optional<BlobId> optValue)
1205 if (!optValue.has_value())
1213 const auto& value = optValue.value();
1214 const auto& descriptor = getInDescriptor(index);
1215 auto*
const message = inMessage.data();
1217 switch (descriptor.adjustedType)
1220 *
reinterpret_cast<ISC_QUAD*
>(&message[descriptor.offset]) = value.id;
1224 throwInvalidType(
"BlobId", descriptor.adjustedType);
1227 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1232 void set(
unsigned index, std::nullopt_t)
1248 void set(
unsigned index, std::optional<BlobId> value)
1256 void set(
unsigned index,
bool value)
1264 void set(
unsigned index, std::int16_t value)
1280 void set(
unsigned index, std::int32_t value)
1296 void set(
unsigned index, std::int64_t value)
1317#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1338 void set(
unsigned index,
float value)
1346 void set(
unsigned index,
double value)
1359#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1377#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1470 void set(
unsigned index, std::string_view value)
1478 template <
typename T>
1479 void set(
unsigned index, std::optional<T> value)
1481 if (value.has_value())
1482 set(index, value.value());
1502 const auto& descriptor = getOutDescriptor(index);
1503 const auto*
const message = outMessage.data();
1505 return *
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE;
1515 const auto& descriptor = getOutDescriptor(index);
1516 const auto*
const message = outMessage.data();
1518 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1519 return std::nullopt;
1521 switch (descriptor.adjustedType)
1524 return message[descriptor.offset] != std::byte{0};
1527 throwInvalidType(
"bool", descriptor.adjustedType);
1536 std::optional<int> scale{0};
1537 return getNumber<std::int16_t>(index, scale,
"std::int16_t");
1545 std::optional<int> scale;
1546 const auto value = getNumber<std::int16_t>(index, scale,
"ScaledInt16");
1547 return value.has_value() ? std::optional{
ScaledInt16{value.
value(), scale.value()}} : std::nullopt;
1555 std::optional<int> scale{0};
1556 return getNumber<std::int32_t>(index, scale,
"std::int32_t");
1564 std::optional<int> scale;
1565 const auto value = getNumber<std::int32_t>(index, scale,
"ScaledInt32");
1566 return value.has_value() ? std::optional{
ScaledInt32{value.
value(), scale.value()}} : std::nullopt;
1574 std::optional<int> scale{0};
1575 return getNumber<std::int64_t>(index, scale,
"std::int64_t");
1583 std::optional<int> scale;
1584 const auto value = getNumber<std::int64_t>(index, scale,
"ScaledInt64");
1585 return value.has_value() ? std::optional{
ScaledInt64{value.
value(), scale.value()}} : std::nullopt;
1595 const auto& descriptor = getOutDescriptor(index);
1596 const auto*
const message = outMessage.data();
1598 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1599 return std::nullopt;
1601 switch (descriptor.adjustedType)
1609 throwInvalidType(
"ScaledOpaqueInt128", descriptor.adjustedType);
1613#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1619 std::optional<int> scale{0};
1620 const auto value = getNumber<BoostInt128>(index, scale,
"BoostInt128");
1621 return value.has_value() ? std::optional{value.value()} : std::nullopt;
1629 std::optional<int> scale;
1630 const auto value = getNumber<BoostInt128>(index, scale,
"ScaledBoostInt128");
1631 return value.has_value() ? std::optional{
ScaledBoostInt128{value.
value(), scale.value()}} : std::nullopt;
1640 std::optional<int> scale{0};
1641 return getNumber<float>(index, scale,
"float");
1649 std::optional<int> scale{0};
1650 return getNumber<double>(index, scale,
"double");
1660 const auto& descriptor = getOutDescriptor(index);
1661 const auto*
const message = outMessage.data();
1663 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1664 return std::nullopt;
1666 switch (descriptor.adjustedType)
1672 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
1676#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1682 std::optional<int> scale{0};
1683 return getNumber<BoostDecFloat16>(index, scale,
"BoostDecFloat16");
1694 const auto& descriptor = getOutDescriptor(index);
1695 const auto*
const message = outMessage.data();
1697 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1698 return std::nullopt;
1700 switch (descriptor.adjustedType)
1706 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
1710#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1716 std::optional<int> scale{0};
1717 return getNumber<BoostDecFloat34>(index, scale,
"BoostDecFloat34");
1728 const auto& descriptor = getOutDescriptor(index);
1729 const auto*
const message = outMessage.data();
1731 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1732 return std::nullopt;
1734 switch (descriptor.adjustedType)
1737 return calendarConverter.opaqueDateToDate(
1738 *
reinterpret_cast<const OpaqueDate*
>(&message[descriptor.offset]));
1741 throwInvalidType(
"Date", descriptor.adjustedType);
1752 const auto& descriptor = getOutDescriptor(index);
1753 const auto*
const message = outMessage.data();
1755 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1756 return std::nullopt;
1758 switch (descriptor.adjustedType)
1764 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
1775 const auto& descriptor = getOutDescriptor(index);
1776 const auto*
const message = outMessage.data();
1778 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1779 return std::nullopt;
1781 switch (descriptor.adjustedType)
1784 return calendarConverter.opaqueTimeToTime(
1785 *
reinterpret_cast<const OpaqueTime*
>(&message[descriptor.offset]));
1788 throwInvalidType(
"Time", descriptor.adjustedType);
1799 const auto& descriptor = getOutDescriptor(index);
1800 const auto*
const message = outMessage.data();
1802 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1803 return std::nullopt;
1805 switch (descriptor.adjustedType)
1811 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
1822 const auto& descriptor = getOutDescriptor(index);
1823 const auto*
const message = outMessage.data();
1825 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1826 return std::nullopt;
1828 switch (descriptor.adjustedType)
1831 return calendarConverter.opaqueTimestampToTimestamp(
1832 *
reinterpret_cast<const OpaqueTimestamp*
>(&message[descriptor.offset]));
1835 throwInvalidType(
"Timestamp", descriptor.adjustedType);
1846 const auto& descriptor = getOutDescriptor(index);
1847 const auto*
const message = outMessage.data();
1849 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1850 return std::nullopt;
1852 switch (descriptor.adjustedType)
1858 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
1869 const auto& descriptor = getOutDescriptor(index);
1870 const auto*
const message = outMessage.data();
1872 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1873 return std::nullopt;
1875 switch (descriptor.adjustedType)
1878 return calendarConverter.opaqueTimeTzToTimeTz(
1879 *
reinterpret_cast<const OpaqueTimeTz*
>(&message[descriptor.offset]));
1882 throwInvalidType(
"TimeTz", descriptor.adjustedType);
1893 const auto& descriptor = getOutDescriptor(index);
1894 const auto*
const message = outMessage.data();
1896 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1897 return std::nullopt;
1899 switch (descriptor.adjustedType)
1905 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
1916 const auto& descriptor = getOutDescriptor(index);
1917 const auto*
const message = outMessage.data();
1919 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1920 return std::nullopt;
1922 switch (descriptor.adjustedType)
1925 return calendarConverter.opaqueTimestampTzToTimestampTz(
1929 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
1940 const auto& descriptor = getOutDescriptor(index);
1941 const auto*
const message = outMessage.data();
1943 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1944 return std::nullopt;
1946 switch (descriptor.adjustedType)
1952 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
1963 const auto& descriptor = getOutDescriptor(index);
1964 const auto*
const message = outMessage.data();
1966 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1967 return std::nullopt;
1969 switch (descriptor.adjustedType)
1974 value.
id = *
reinterpret_cast<const ISC_QUAD*
>(&message[descriptor.offset]);
1979 throwInvalidType(
"BlobId", descriptor.adjustedType);
1990 const auto& descriptor = getOutDescriptor(index);
1991 const auto*
const message = outMessage.data();
1993 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
1994 return std::nullopt;
1996 const auto data = &message[descriptor.offset];
1998 switch (descriptor.adjustedType)
2001 return (message[descriptor.offset] != std::byte{0}) ? std::string{
"true"} : std::string{
"false"};
2004 return numericConverter.numberToString(
2005 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.
scale});
2008 return numericConverter.numberToString(
2009 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.
scale});
2012 return numericConverter.numberToString(
2013 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.
scale});
2016 return numericConverter.opaqueInt128ToString(
2017 *
reinterpret_cast<const OpaqueInt128*
>(data), descriptor.scale);
2020 return numericConverter.numberToString(*
reinterpret_cast<const float*
>(data));
2023 return numericConverter.numberToString(*
reinterpret_cast<const double*
>(data));
2026 return calendarConverter.opaqueDateToString(*
reinterpret_cast<const OpaqueDate*
>(data));
2029 return calendarConverter.opaqueTimeToString(*
reinterpret_cast<const OpaqueTime*
>(data));
2032 return calendarConverter.opaqueTimestampToString(*
reinterpret_cast<const OpaqueTimestamp*
>(data));
2035 return calendarConverter.opaqueTimeTzToString(*
reinterpret_cast<const OpaqueTimeTz*
>(data));
2038 return calendarConverter.opaqueTimestampTzToString(
2042 return numericConverter.opaqueDecFloat16ToString(*
reinterpret_cast<const OpaqueDecFloat16*
>(data));
2045 return numericConverter.opaqueDecFloat34ToString(*
reinterpret_cast<const OpaqueDecFloat34*
>(data));
2048 return std::string{
reinterpret_cast<const char*
>(data +
sizeof(std::uint16_t)),
2049 *
reinterpret_cast<const std::uint16_t*
>(data)};
2052 throwInvalidType(
"std::string", descriptor.adjustedType);
2063 template <
typename T>
2073 template <Aggregate T>
2076 using namespace impl::reflection;
2078 constexpr std::size_t N = fieldCountV<T>;
2080 if (N != outDescriptors.size())
2082 throw FbCppException(
"Struct field count (" + std::to_string(N) +
2083 ") does not match output column count (" + std::to_string(outDescriptors.size()) +
")");
2086 return getStruct<T>(std::make_index_sequence<N>{});
2095 template <Aggregate T>
2098 using namespace impl::reflection;
2100 constexpr std::size_t N = fieldCountV<T>;
2102 if (N != inDescriptors.size())
2104 throw FbCppException(
"Struct field count (" + std::to_string(N) +
2105 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) +
")");
2108 setStruct(value, std::make_index_sequence<N>{});
2118 template <TupleLike T>
2121 using namespace impl::reflection;
2123 constexpr std::size_t N = std::tuple_size_v<T>;
2125 if (N != outDescriptors.size())
2127 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
2128 ") does not match output column count (" + std::to_string(outDescriptors.size()) +
")");
2131 return getTuple<T>(std::make_index_sequence<N>{});
2140 template <TupleLike T>
2143 constexpr std::size_t N = std::tuple_size_v<T>;
2145 if (N != inDescriptors.size())
2147 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
2148 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) +
")");
2151 setTuple(value, std::make_index_sequence<N>{});
2162 template <VariantLike V>
2165 using namespace impl::reflection;
2167 static_assert(variantAlternativesSupportedV<V>,
2168 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2169 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2170 "complete list of supported types.");
2174 const auto& descriptor = getOutDescriptor(index);
2178 if constexpr (variantContainsV<std::monostate, V>)
2179 return V{std::monostate{}};
2183 "NULL value encountered but variant does not contain std::monostate at index " +
2184 std::to_string(index));
2188 return getVariantValue<V>(index, descriptor);
2197 template <VariantLike V>
2198 void set(
unsigned index,
const V& value)
2200 using namespace impl::reflection;
2202 static_assert(variantAlternativesSupportedV<V>,
2203 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
2204 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
2205 "complete list of supported types.");
2208 [
this, index](
const auto& v)
2210 using T = std::decay_t<
decltype(v)>;
2212 if constexpr (std::is_same_v<T, std::monostate>)
2224 const Descriptor& getInDescriptor(
unsigned index)
2226 if (index >= inDescriptors.size())
2227 throw std::out_of_range(
"index out of range");
2229 return inDescriptors[index];
2235 const Descriptor& getOutDescriptor(
unsigned index)
2237 if (index >= outDescriptors.size())
2238 throw std::out_of_range(
"index out of range");
2240 return outDescriptors[index];
2246 template <
typename T, std::size_t... Is>
2247 T getStruct(std::index_sequence<Is...>)
2249 using namespace impl::reflection;
2251 return T{getStructField<FieldType<T, Is>>(
static_cast<unsigned>(Is))...};
2257 template <
typename F>
2258 auto getStructField(
unsigned index)
2260 using namespace impl::reflection;
2262 if constexpr (isOptionalV<F>)
2263 return get<F>(index);
2264 else if constexpr (isVariantV<F>)
2265 return get<F>(index);
2268 auto opt = get<std::optional<F>>(index);
2270 if (!opt.has_value())
2272 throw FbCppException(
2273 "Null value encountered for non-optional field at index " + std::to_string(index));
2276 return std::move(opt.value());
2283 template <
typename T, std::size_t... Is>
2284 void setStruct(
const T& value, std::index_sequence<Is...>)
2286 using namespace impl::reflection;
2288 const auto tuple = toTupleRef(value);
2289 (
set(
static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
2295 template <
typename T, std::size_t... Is>
2296 T getTuple(std::index_sequence<Is...>)
2298 using namespace impl::reflection;
2300 return T{getStructField<std::tuple_element_t<Is, T>>(
static_cast<unsigned>(Is))...};
2306 template <
typename T, std::size_t... Is>
2307 void setTuple(
const T& value, std::index_sequence<Is...>)
2309 (
set(
static_cast<unsigned>(Is), std::get<Is>(value)), ...);
2316 template <
typename V>
2317 V getVariantValue(
unsigned index,
const Descriptor& descriptor)
2319 using namespace impl::reflection;
2322 switch (descriptor.adjustedType)
2325 if constexpr (variantContainsV<bool, V>)
2326 return V{get<std::optional<bool>>(index).value()};
2330 if (descriptor.scale != 0)
2333 if constexpr (variantContainsV<ScaledInt16, V>)
2334 return V{get<std::optional<ScaledInt16>>(index).value()};
2335 if constexpr (variantContainsV<ScaledInt32, V>)
2336 return V{get<std::optional<ScaledInt32>>(index).value()};
2337 if constexpr (variantContainsV<ScaledInt64, V>)
2338 return V{get<std::optional<ScaledInt64>>(index).value()};
2339#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2340 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2341 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2344 if constexpr (variantContainsV<std::int16_t, V>)
2345 return V{get<std::optional<std::int16_t>>(index).value()};
2349 if (descriptor.scale != 0)
2352 if constexpr (variantContainsV<ScaledInt32, V>)
2353 return V{get<std::optional<ScaledInt32>>(index).value()};
2354 if constexpr (variantContainsV<ScaledInt64, V>)
2355 return V{get<std::optional<ScaledInt64>>(index).value()};
2356#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2357 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2358 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2361 if constexpr (variantContainsV<std::int32_t, V>)
2362 return V{get<std::optional<std::int32_t>>(index).value()};
2366 if (descriptor.scale != 0)
2369 if constexpr (variantContainsV<ScaledInt64, V>)
2370 return V{get<std::optional<ScaledInt64>>(index).value()};
2371#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2372 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2373 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2376 if constexpr (variantContainsV<std::int64_t, V>)
2377 return V{get<std::optional<std::int64_t>>(index).value()};
2380#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2383 if constexpr (variantContainsV<ScaledOpaqueInt128, V>)
2384 return V{get<std::optional<ScaledOpaqueInt128>>(index).value()};
2385 else if (descriptor.scale != 0)
2387 if constexpr (variantContainsV<ScaledBoostInt128, V>)
2388 return V{get<std::optional<ScaledBoostInt128>>(index).value()};
2390 else if constexpr (variantContainsV<BoostInt128, V>)
2391 return V{get<std::optional<BoostInt128>>(index).value()};
2396 if constexpr (variantContainsV<float, V>)
2397 return V{get<std::optional<float>>(index).value()};
2401 if constexpr (variantContainsV<double, V>)
2402 return V{get<std::optional<double>>(index).value()};
2405#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2408 if constexpr (variantContainsV<OpaqueDecFloat16, V>)
2409 return V{get<std::optional<OpaqueDecFloat16>>(index).value()};
2410 else if constexpr (variantContainsV<BoostDecFloat16, V>)
2411 return V{get<std::optional<BoostDecFloat16>>(index).value()};
2416 if constexpr (variantContainsV<OpaqueDecFloat34, V>)
2417 return V{get<std::optional<OpaqueDecFloat34>>(index).value()};
2418 else if constexpr (variantContainsV<BoostDecFloat34, V>)
2419 return V{get<std::optional<BoostDecFloat34>>(index).value()};
2424 if constexpr (variantContainsV<std::string, V>)
2425 return V{get<std::optional<std::string>>(index).value()};
2430 if constexpr (variantContainsV<OpaqueDate, V>)
2431 return V{get<std::optional<OpaqueDate>>(index).value()};
2432 else if constexpr (variantContainsV<Date, V>)
2433 return V{get<std::optional<Date>>(index).value()};
2438 if constexpr (variantContainsV<OpaqueTime, V>)
2439 return V{get<std::optional<OpaqueTime>>(index).value()};
2440 else if constexpr (variantContainsV<Time, V>)
2441 return V{get<std::optional<Time>>(index).value()};
2446 if constexpr (variantContainsV<OpaqueTimestamp, V>)
2447 return V{get<std::optional<OpaqueTimestamp>>(index).value()};
2448 else if constexpr (variantContainsV<Timestamp, V>)
2449 return V{get<std::optional<Timestamp>>(index).value()};
2454 if constexpr (variantContainsV<OpaqueTimeTz, V>)
2455 return V{get<std::optional<OpaqueTimeTz>>(index).value()};
2456 else if constexpr (variantContainsV<TimeTz, V>)
2457 return V{get<std::optional<TimeTz>>(index).value()};
2462 if constexpr (variantContainsV<OpaqueTimestampTz, V>)
2463 return V{get<std::optional<OpaqueTimestampTz>>(index).value()};
2464 else if constexpr (variantContainsV<TimestampTz, V>)
2465 return V{get<std::optional<TimestampTz>>(index).value()};
2469 if constexpr (variantContainsV<BlobId, V>)
2470 return V{get<std::optional<BlobId>>(index).value()};
2478 return tryVariantAlternatives<V, 0>(index, descriptor);
2484 template <
typename V, std::
size_t I = 0>
2485 V tryVariantAlternatives(
unsigned index, [[maybe_unused]]
const Descriptor& descriptor)
2487 using namespace impl::reflection;
2489 if constexpr (I >= std::variant_size_v<V>)
2491 throw FbCppException(
2492 "Cannot convert SQL type to any variant alternative at index " + std::to_string(index));
2496 using Alt = std::variant_alternative_t<I, V>;
2498 if constexpr (std::is_same_v<Alt, std::monostate>)
2501 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2503 else if constexpr (isOpaqueTypeV<Alt>)
2506 return tryVariantAlternatives<V, I + 1>(index, descriptor);
2511 auto opt = get<std::optional<Alt>>(index);
2512 return V{std::move(opt.value())};
2520 template <
typename T>
2521 void setNumber(
unsigned index,
DescriptorAdjustedType valueType, T value,
int scale,
const char* typeName)
2525 const auto& descriptor = getInDescriptor(index);
2526 auto*
const message = inMessage.data();
2528 const auto descriptorData = &message[descriptor.offset];
2529 std::optional<int> descriptorScale{descriptor.scale};
2531 Descriptor valueDescriptor;
2532 valueDescriptor.adjustedType = valueType;
2533 valueDescriptor.scale = scale;
2535 const auto valueAddress =
reinterpret_cast<const std::byte*
>(&value);
2537 switch (descriptor.adjustedType)
2540 *
reinterpret_cast<std::int16_t*
>(descriptorData) =
2541 convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int16_t");
2545 *
reinterpret_cast<std::int32_t*
>(descriptorData) =
2546 convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int32_t");
2550 *
reinterpret_cast<std::int64_t*
>(descriptorData) =
2551 convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int64_t");
2554#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2557 const auto boostInt128 =
2558 convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale,
"BoostInt128");
2560 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
2566 *
reinterpret_cast<float*
>(descriptorData) =
2567 convertNumber<float>(valueDescriptor, valueAddress, descriptorScale,
"float");
2571 *
reinterpret_cast<double*
>(descriptorData) =
2572 convertNumber<double>(valueDescriptor, valueAddress, descriptorScale,
"double");
2575#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2578 const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
2579 valueDescriptor, valueAddress, descriptorScale,
"BoostDecFloat16");
2581 numericConverter.boostDecFloat16ToOpaqueDecFloat16(boostDecFloat16);
2587 const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
2588 valueDescriptor, valueAddress, descriptorScale,
"BoostDecFloat34");
2590 numericConverter.boostDecFloat34ToOpaqueDecFloat34(boostDecFloat34);
2596 throwInvalidType(typeName, descriptor.adjustedType);
2599 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
2606 template <
typename T>
2607 std::optional<T> getNumber(
unsigned index, std::optional<int>& scale,
const char* typeName)
2611 const auto& descriptor = getOutDescriptor(index);
2612 const auto*
const message = outMessage.data();
2614 if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
2615 return std::nullopt;
2617 auto data = &message[descriptor.offset];
2618#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2619 std::optional<BoostInt128> boostInt128;
2620 std::optional<BoostDecFloat16> boostDecFloat16;
2621 std::optional<BoostDecFloat34> boostDecFloat34;
2625 switch (descriptor.adjustedType)
2627#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2629 boostInt128.emplace(
2630 numericConverter.opaqueInt128ToBoostInt128(*
reinterpret_cast<const OpaqueInt128*
>(data)));
2631 data =
reinterpret_cast<const std::byte*
>(&boostInt128.value());
2635 boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
2637 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat16.value());
2641 boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
2643 data =
reinterpret_cast<const std::byte*
>(&boostDecFloat34.value());
2651 return convertNumber<T>(descriptor, data, scale, typeName);
2656 throw FbCppException(
"Invalid type: actual type " + std::string(actualType) +
", descriptor type " +
2657 std::to_string(
static_cast<unsigned>(descriptorType)));
2660 template <
typename T>
2662 const Descriptor& descriptor,
const std::byte* data, std::optional<int>& toScale,
const char* toTypeName)
2664 if (!toScale.has_value())
2666 switch (descriptor.adjustedType)
2672 throwInvalidType(toTypeName, descriptor.adjustedType);
2678 toScale = descriptor.scale;
2681 switch (descriptor.adjustedType)
2684 return numericConverter.numberToNumber<T>(
2685 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.scale}, toScale.value());
2689 return numericConverter.numberToNumber<T>(
2690 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.scale}, toScale.value());
2693 return numericConverter.numberToNumber<T>(
2694 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.scale}, toScale.value());
2696#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2698 return numericConverter.numberToNumber<T>(
2703 return numericConverter.numberToNumber<T>(
2707 return numericConverter.numberToNumber<T>(
2712 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const float*
>(data), toScale.value());
2716 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const double*
>(data), toScale.value());
2720 throwInvalidType(toTypeName, descriptor.adjustedType);
2725 Attachment& attachment;
2726 FbUniquePtr<Firebird::IStatus> status;
2727 impl::StatusWrapper statusWrapper;
2728 impl::CalendarConverter calendarConverter;
2729 impl::NumericConverter numericConverter;
2730 FbRef<fb::IStatement> statementHandle;
2731 FbRef<fb::IResultSet> resultSetHandle;
2732 FbRef<fb::IMessageMetadata> inMetadata;
2733 std::vector<Descriptor> inDescriptors;
2734 std::vector<std::byte> inMessage;
2735 FbRef<fb::IMessageMetadata> outMetadata;
2736 std::vector<Descriptor> outDescriptors;
2737 std::vector<std::byte> outMessage;
2747 inline std::optional<bool> Statement::get<std::optional<bool>>(
unsigned index)
2749 return getBool(index);
2753 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(
unsigned index)
2755 return getBlobId(index);
2759 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(
unsigned index)
2761 return getInt16(index);
2765 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(
unsigned index)
2767 return getScaledInt16(index);
2771 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(
unsigned index)
2773 return getInt32(index);
2777 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(
unsigned index)
2779 return getScaledInt32(index);
2783 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(
unsigned index)
2785 return getInt64(index);
2789 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(
unsigned index)
2791 return getScaledInt64(index);
2795 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(
unsigned index)
2797 return getScaledOpaqueInt128(index);
2800#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2802 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(
unsigned index)
2804 return getBoostInt128(index);
2808 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(
unsigned index)
2810 return getScaledBoostInt128(index);
2815 inline std::optional<float> Statement::get<std::optional<float>>(
unsigned index)
2817 return getFloat(index);
2821 inline std::optional<double> Statement::get<std::optional<double>>(
unsigned index)
2823 return getDouble(index);
2827 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(
unsigned index)
2829 return getOpaqueDecFloat16(index);
2832#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2834 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(
unsigned index)
2836 return getBoostDecFloat16(index);
2841 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(
unsigned index)
2843 return getOpaqueDecFloat34(index);
2846#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2848 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(
unsigned index)
2850 return getBoostDecFloat34(index);
2855 inline std::optional<Date> Statement::get<std::optional<Date>>(
unsigned index)
2857 return getDate(index);
2861 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(
unsigned index)
2863 return getOpaqueDate(index);
2867 inline std::optional<Time> Statement::get<std::optional<Time>>(
unsigned index)
2869 return getTime(index);
2873 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(
unsigned index)
2875 return getOpaqueTime(index);
2879 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(
unsigned index)
2881 return getOpaqueTimestamp(index);
2885 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(
unsigned index)
2887 return getTimestamp(index);
2891 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(
unsigned index)
2893 return getTimeTz(index);
2897 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(
unsigned index)
2899 return getOpaqueTimeTz(index);
2903 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(
unsigned index)
2905 return getTimestampTz(index);
2909 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(
unsigned index)
2911 return getOpaqueTimestampTz(index);
2915 inline std::optional<std::string> Statement::get<std::optional<std::string>>(
unsigned index)
2917 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 & 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.
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.
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.
Statement(Attachment &attachment, Transaction &transaction, std::string_view sql, const StatementOptions &options={})
Prepares an SQL statement.
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.
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.