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" 
   55#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
   56#include <boost/multiprecision/cpp_int.hpp> 
   57#include <boost/multiprecision/cpp_dec_float.hpp> 
   78            return prefetchLegacyPlan;
 
 
   88            prefetchLegacyPlan = value;
 
 
  107            prefetchPlan = value;
 
 
  112        bool prefetchLegacyPlan = 
false;
 
  113        bool prefetchPlan = 
false;
 
 
  124        SELECT = isc_info_sql_stmt_select,
 
  128        INSERT = isc_info_sql_stmt_insert,
 
  132        UPDATE = isc_info_sql_stmt_update,
 
  136        DELETE = isc_info_sql_stmt_delete,
 
  140        DDL = isc_info_sql_stmt_ddl,
 
  160        COMMIT = isc_info_sql_stmt_commit,
 
  164        ROLLBACK = isc_info_sql_stmt_rollback,
 
 
  199            : attachment{o.attachment},
 
  200              status{std::move(o.status)},
 
  201              statusWrapper{std::move(o.statusWrapper)},
 
  202              calendarConverter{std::move(o.calendarConverter)},
 
  203              numericConverter{std::move(o.numericConverter)},
 
  204              statementHandle{std::move(o.statementHandle)},
 
  205              resultSetHandle{std::move(o.resultSetHandle)},
 
  206              inMetadata{std::move(o.inMetadata)},
 
  207              inDescriptors{std::move(o.inDescriptors)},
 
  208              inMessage{std::move(o.inMessage)},
 
  209              outMetadata{std::move(o.outMetadata)},
 
  210              outDescriptors{std::move(o.outDescriptors)},
 
  211              outMessage{std::move(o.outMessage)},
 
 
  216        Statement& operator=(Statement&&) = 
delete;
 
  218        Statement& operator=(
const Statement&) = 
delete;
 
  250            return statementHandle != 
nullptr;
 
 
  259            return statementHandle;
 
 
  268            return resultSetHandle;
 
 
  310            return inDescriptors;
 
 
  318            return outDescriptors;
 
 
  396            const auto message = inMessage.data();
 
  398            for (
const auto& descriptor : inDescriptors)
 
  399                *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
 
 
  410            const auto& descriptor = getInDescriptor(index);
 
  411            const auto message = inMessage.data();
 
  413            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
 
 
  421        void setBool(
unsigned index, std::optional<bool> optValue)
 
  423            if (!optValue.has_value())
 
  431            const auto& value = optValue.value();
 
  432            const auto& descriptor = getInDescriptor(index);
 
  433            const auto message = inMessage.data();
 
  435            switch (descriptor.adjustedType)
 
  437                case DescriptorAdjustedType::BOOLEAN:
 
  438                    message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
 
  442                    throwInvalidType(
"bool", descriptor.adjustedType);
 
  445            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  451        void setInt16(
unsigned index, std::optional<std::int16_t> optValue)
 
  453            if (!optValue.has_value())
 
  459            setNumber(index, DescriptorAdjustedType::INT16, optValue.value(), 0, 
"std::int16_t");
 
 
  467            if (!optValue.has_value())
 
  473            const auto& value = optValue.value();
 
  474            setNumber(index, DescriptorAdjustedType::INT16, value.value, value.scale, 
"ScaledInt16");
 
 
  480        void setInt32(
unsigned index, std::optional<std::int32_t> optValue)
 
  482            if (!optValue.has_value())
 
  488            setNumber(index, DescriptorAdjustedType::INT32, optValue.value(), 0, 
"std::int32_t");
 
 
  496            if (!optValue.has_value())
 
  502            const auto& value = optValue.value();
 
  503            setNumber(index, DescriptorAdjustedType::INT32, value.value, value.scale, 
"ScaledInt32");
 
 
  509        void setInt64(
unsigned index, std::optional<std::int64_t> optValue)
 
  511            if (!optValue.has_value())
 
  517            setNumber(index, DescriptorAdjustedType::INT64, optValue.value(), 0, 
"std::int64_t");
 
 
  525            if (!optValue.has_value())
 
  531            const auto& value = optValue.value();
 
  532            setNumber(index, DescriptorAdjustedType::INT64, value.value, value.scale, 
"ScaledInt64");
 
 
  540            if (!optValue.has_value())
 
  548            const auto& value = optValue.value();
 
  549            const auto& descriptor = getInDescriptor(index);
 
  550            const auto message = inMessage.data();
 
  552            switch (descriptor.adjustedType)
 
  554                case DescriptorAdjustedType::INT128:
 
  555                    *
reinterpret_cast<OpaqueInt128*
>(&message[descriptor.offset]) = value;
 
  559                    throwInvalidType(
"OpaqueInt128", descriptor.adjustedType);
 
  562            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  565#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
  571            if (!optValue.has_value())
 
  577            setNumber(index, DescriptorAdjustedType::INT128, optValue.value(), 0, 
"BoostInt128");
 
 
  585            if (!optValue.has_value())
 
  591            const auto& value = optValue.value();
 
  592            setNumber(index, DescriptorAdjustedType::INT128, value.value, value.scale, 
"ScaledBoostInt128");
 
 
  599        void setFloat(
unsigned index, std::optional<float> optValue)
 
  601            if (!optValue.has_value())
 
  607            setNumber(index, DescriptorAdjustedType::FLOAT, optValue.value(), 0, 
"float");
 
 
  613        void setDouble(
unsigned index, std::optional<double> optValue)
 
  615            if (!optValue.has_value())
 
  621            setNumber(index, DescriptorAdjustedType::DOUBLE, optValue.value(), 0, 
"double");
 
 
  629            if (!optValue.has_value())
 
  637            const auto& value = optValue.value();
 
  638            const auto& descriptor = getInDescriptor(index);
 
  639            const auto message = inMessage.data();
 
  641            switch (descriptor.adjustedType)
 
  643                case DescriptorAdjustedType::DECFLOAT16:
 
  648                    throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
 
  651            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  654#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
  660            if (!optValue.has_value())
 
  666            setNumber(index, DescriptorAdjustedType::DECFLOAT16, optValue.value(), 0, 
"BoostDecFloat16");
 
 
  675            if (!optValue.has_value())
 
  683            const auto& value = optValue.value();
 
  684            const auto& descriptor = getInDescriptor(index);
 
  685            const auto message = inMessage.data();
 
  687            switch (descriptor.adjustedType)
 
  689                case DescriptorAdjustedType::DECFLOAT34:
 
  694                    throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
 
  697            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  700#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
  706            if (!optValue.has_value())
 
  712            setNumber(index, DescriptorAdjustedType::DECFLOAT34, optValue.value(), 0, 
"BoostDecFloat34");
 
 
  719        void setDate(
unsigned index, std::optional<Date> optValue)
 
  721            if (!optValue.has_value())
 
  729            const auto& value = optValue.value();
 
  730            const auto& descriptor = getInDescriptor(index);
 
  731            const auto message = inMessage.data();
 
  733            switch (descriptor.adjustedType)
 
  735                case DescriptorAdjustedType::DATE:
 
  736                    *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) =
 
  737                        calendarConverter.dateToOpaqueDate(value);
 
  741                    throwInvalidType(
"Date", descriptor.adjustedType);
 
  744            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  752            if (!optValue.has_value())
 
  760            const auto& value = optValue.value();
 
  761            const auto& descriptor = getInDescriptor(index);
 
  762            const auto message = inMessage.data();
 
  764            switch (descriptor.adjustedType)
 
  766                case DescriptorAdjustedType::DATE:
 
  767                    *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) = value;
 
  771                    throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
 
  774            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  780        void setTime(
unsigned index, std::optional<Time> optValue)
 
  782            if (!optValue.has_value())
 
  790            const auto& value = optValue.value();
 
  791            const auto& descriptor = getInDescriptor(index);
 
  792            const auto message = inMessage.data();
 
  794            switch (descriptor.adjustedType)
 
  796                case DescriptorAdjustedType::TIME:
 
  797                    *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) =
 
  798                        calendarConverter.timeToOpaqueTime(value);
 
  802                    throwInvalidType(
"Time", descriptor.adjustedType);
 
  805            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  813            if (!optValue.has_value())
 
  821            const auto& value = optValue.value();
 
  822            const auto& descriptor = getInDescriptor(index);
 
  823            const auto message = inMessage.data();
 
  825            switch (descriptor.adjustedType)
 
  827                case DescriptorAdjustedType::TIME:
 
  828                    *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) = value;
 
  832                    throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
 
  835            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  843            if (!optValue.has_value())
 
  851            const auto& value = optValue.value();
 
  852            const auto& descriptor = getInDescriptor(index);
 
  853            const auto message = inMessage.data();
 
  855            switch (descriptor.adjustedType)
 
  857                case DescriptorAdjustedType::TIMESTAMP:
 
  859                        calendarConverter.timestampToOpaqueTimestamp(value);
 
  863                    throwInvalidType(
"Timestamp", descriptor.adjustedType);
 
  866            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  874            if (!optValue.has_value())
 
  882            const auto& value = optValue.value();
 
  883            const auto& descriptor = getInDescriptor(index);
 
  884            const auto message = inMessage.data();
 
  886            switch (descriptor.adjustedType)
 
  888                case DescriptorAdjustedType::TIMESTAMP:
 
  889                    *
reinterpret_cast<OpaqueTimestamp*
>(&message[descriptor.offset]) = value;
 
  893                    throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
 
  896            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  902        void setTimeTz(
unsigned index, std::optional<TimeTz> optValue)
 
  904            if (!optValue.has_value())
 
  912            const auto& value = optValue.value();
 
  913            const auto& descriptor = getInDescriptor(index);
 
  914            auto* 
const message = inMessage.data();
 
  916            switch (descriptor.adjustedType)
 
  918                case DescriptorAdjustedType::TIME_TZ:
 
  919                    *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) =
 
  920                        calendarConverter.timeTzToOpaqueTimeTz(value);
 
  924                    throwInvalidType(
"TimeTz", descriptor.adjustedType);
 
  927            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  935            if (!optValue.has_value())
 
  943            const auto& value = optValue.value();
 
  944            const auto& descriptor = getInDescriptor(index);
 
  945            auto* 
const message = inMessage.data();
 
  947            switch (descriptor.adjustedType)
 
  949                case DescriptorAdjustedType::TIME_TZ:
 
  950                    *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) = value;
 
  954                    throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
 
  957            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  965            if (!optValue.has_value())
 
  973            const auto& value = optValue.value();
 
  974            const auto& descriptor = getInDescriptor(index);
 
  975            auto* 
const message = inMessage.data();
 
  977            switch (descriptor.adjustedType)
 
  979                case DescriptorAdjustedType::TIMESTAMP_TZ:
 
  981                        calendarConverter.timestampTzToOpaqueTimestampTz(value);
 
  985                    throwInvalidType(
"TimestampTz", descriptor.adjustedType);
 
  988            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
  996            if (!optValue.has_value())
 
 1004            const auto& value = optValue.value();
 
 1005            const auto& descriptor = getInDescriptor(index);
 
 1006            auto* 
const message = inMessage.data();
 
 1008            switch (descriptor.adjustedType)
 
 1010                case DescriptorAdjustedType::TIMESTAMP_TZ:
 
 1015                    throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
 
 1018            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
 1024        void setString(
unsigned index, std::optional<std::string_view> optValue)
 
 1026            if (!optValue.has_value())
 
 1034            const auto value = optValue.value();
 
 1035            const auto& descriptor = getInDescriptor(index);
 
 1036            const auto message = inMessage.data();
 
 1038            switch (descriptor.adjustedType)
 
 1040                case DescriptorAdjustedType::BOOLEAN:
 
 1041                    message[descriptor.offset] = numericConverter.stringToBoolean(value);
 
 1044                case DescriptorAdjustedType::INT16:
 
 1045                case DescriptorAdjustedType::INT32:
 
 1046                case DescriptorAdjustedType::INT64:
 
 1047#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1048                case DescriptorAdjustedType::INT128:
 
 1051                    std::string strValue(value);
 
 1054                    if (
const auto dotPos = strValue.find_last_of(
'.'); dotPos != std::string_view::npos)
 
 1056                        for (
auto pos = dotPos + 1; pos < strValue.size(); ++pos)
 
 1058                            const char c = value[pos];
 
 1060                            if (c < 
'0' || c > 
'9')
 
 1066                        strValue.erase(dotPos, 1);
 
 1069#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1070                    const auto parseDecimalToBoostInt128 = [
this](std::string_view text)
 
 1072                        bool isNegative = 
false;
 
 1073                        std::size_t pos = 0;
 
 1075                        if (!text.empty() && (text.front() == 
'+' || text.front() == 
'-'))
 
 1077                            isNegative = text.front() == 
'-';
 
 1081                        if (pos == text.size())
 
 1082                            this->numericConverter.throwConversionErrorFromString(std::string{text});
 
 1086                        for (; pos < text.size(); ++pos)
 
 1088                            const char c = text[pos];
 
 1090                            if (c < 
'0' || c > 
'9')
 
 1091                                this->numericConverter.throwConversionErrorFromString(std::string{text});
 
 1094                            result += 
static_cast<int>(c - 
'0');
 
 1097                        return isNegative ? -result : result;
 
 1100                    auto scaledValue = 
ScaledBoostInt128{parseDecimalToBoostInt128(strValue), scale};
 
 1102                    if (scale != descriptor.scale)
 
 1104                        scaledValue.
value = numericConverter.numberToNumber<
BoostInt128>(scaledValue, descriptor.scale);
 
 1105                        scaledValue.scale = descriptor.scale;
 
 1110                    static_assert(
sizeof(
long long) == 
sizeof(std::int64_t));
 
 1111                    std::int64_t intValue;
 
 1112                    const auto convResult =
 
 1113                        std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
 
 1114                    if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
 
 1115                        numericConverter.throwConversionErrorFromString(strValue);
 
 1118                    if (scale != descriptor.scale)
 
 1121                            numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
 
 1122                        scaledValue.scale = descriptor.scale;
 
 1130                case DescriptorAdjustedType::FLOAT:
 
 1131                case DescriptorAdjustedType::DOUBLE:
 
 1134#if defined(__APPLE__) 
 1136                    std::string valueString{value};
 
 1137                    char* parseEnd = 
nullptr;
 
 1138                    doubleValue = std::strtod(valueString.c_str(), &parseEnd);
 
 1139                    if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
 
 1140                        numericConverter.throwConversionErrorFromString(std::move(valueString));
 
 1142                    const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
 
 1143                    if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
 
 1144                        numericConverter.throwConversionErrorFromString(std::string{value});
 
 1150                case DescriptorAdjustedType::DATE:
 
 1151                    *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) =
 
 1152                        calendarConverter.stringToOpaqueDate(value);
 
 1155                case DescriptorAdjustedType::TIME:
 
 1156                    *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) =
 
 1157                        calendarConverter.stringToOpaqueTime(value);
 
 1160                case DescriptorAdjustedType::TIMESTAMP:
 
 1162                        calendarConverter.stringToOpaqueTimestamp(value);
 
 1165                case DescriptorAdjustedType::TIME_TZ:
 
 1166                    *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) =
 
 1167                        calendarConverter.stringToOpaqueTimeTz(value);
 
 1170                case DescriptorAdjustedType::TIMESTAMP_TZ:
 
 1172                        calendarConverter.stringToOpaqueTimestampTz(value);
 
 1174#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1175                case DescriptorAdjustedType::DECFLOAT16:
 
 1176                case DescriptorAdjustedType::DECFLOAT34:
 
 1183                        numericConverter.throwConversionErrorFromString(std::string{value});
 
 1188                case DescriptorAdjustedType::STRING:
 
 1189                    if (value.length() > descriptor.length)
 
 1191                        static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
 
 1193                            isc_string_truncation,
 
 1200                    *
reinterpret_cast<std::uint16_t*
>(&message[descriptor.offset]) =
 
 1201                        static_cast<std::uint16_t
>(value.length());
 
 1202                    std::copy(value.begin(), value.end(),
 
 1203                        reinterpret_cast<char*
>(&message[descriptor.offset + 
sizeof(std::uint16_t)]));
 
 1207                    throwInvalidType(
"std::string_view", descriptor.adjustedType);
 
 1210            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
 1216        void setBlobId(
unsigned index, std::optional<BlobId> optValue)
 
 1218            if (!optValue.has_value())
 
 1226            const auto& value = optValue.value();
 
 1227            const auto& descriptor = getInDescriptor(index);
 
 1228            auto* 
const message = inMessage.data();
 
 1230            switch (descriptor.adjustedType)
 
 1232                case DescriptorAdjustedType::BLOB:
 
 1233                    *
reinterpret_cast<ISC_QUAD*
>(&message[descriptor.offset]) = value.id;
 
 1237                    throwInvalidType(
"BlobId", descriptor.adjustedType);
 
 1240            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 
 1245        void set(
unsigned index, std::nullopt_t)
 
 
 1255            setBlobId(index, value);
 
 
 1261        void set(
unsigned index, std::optional<BlobId> value)
 
 1263            setBlobId(index, value);
 
 
 1269        void set(
unsigned index, 
bool value)
 
 1271            setBool(index, value);
 
 
 1277        void set(
unsigned index, std::int16_t value)
 
 1279            setInt16(index, value);
 
 
 1287            setScaledInt16(index, value);
 
 
 1293        void set(
unsigned index, std::int32_t value)
 
 1295            setInt32(index, value);
 
 
 1303            setScaledInt32(index, value);
 
 
 1309        void set(
unsigned index, std::int64_t value)
 
 1311            setInt64(index, value);
 
 
 1319            setScaledInt64(index, value);
 
 
 1327            setOpaqueInt128(index, value);
 
 
 1330#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1336            setBoostInt128(index, value);
 
 
 1344            setScaledBoostInt128(index, value);
 
 
 1351        void set(
unsigned index, 
float value)
 
 1353            setFloat(index, value);
 
 
 1359        void set(
unsigned index, 
double value)
 
 1361            setDouble(index, value);
 
 
 1369            setOpaqueDecFloat16(index, value);
 
 
 1372#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1378            setBoostDecFloat16(index, value);
 
 
 1387            setOpaqueDecFloat34(index, value);
 
 
 1390#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1396            setBoostDecFloat34(index, value);
 
 
 1405            setDate(index, value);
 
 
 1413            setOpaqueDate(index, value);
 
 
 1421            setTime(index, value);
 
 
 1429            setOpaqueTime(index, value);
 
 
 1437            setTimestamp(index, value);
 
 
 1445            setOpaqueTimestamp(index, value);
 
 
 1453            setTimeTz(index, value);
 
 
 1461            setOpaqueTimeTz(index, value);
 
 
 1469            setTimestampTz(index, value);
 
 
 1477            setOpaqueTimestampTz(index, value);
 
 
 1483        void set(
unsigned index, std::string_view value)
 
 1485            setString(index, value);
 
 
 1491        template <
typename T>
 
 1492        void set(
unsigned index, std::optional<T> value)
 
 1494            if (value.has_value())
 
 1495                set(index, value.value());
 
 
 1515            const auto& descriptor = getOutDescriptor(index);
 
 1516            const auto* 
const message = outMessage.data();
 
 1518            return *
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE;
 
 
 1528            const auto& descriptor = getOutDescriptor(index);
 
 1529            const auto* 
const message = outMessage.data();
 
 1531            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1532                return std::nullopt;
 
 1534            switch (descriptor.adjustedType)
 
 1536                case DescriptorAdjustedType::BOOLEAN:
 
 1537                    return message[descriptor.offset] != std::byte{0};
 
 1540                    throwInvalidType(
"bool", descriptor.adjustedType);
 
 
 1549            std::optional<int> scale{0};
 
 1550            return getNumber<std::int16_t>(index, scale, 
"std::int16_t");
 
 
 1558            std::optional<int> scale;
 
 1559            const auto value = getNumber<std::int16_t>(index, scale, 
"ScaledInt16");
 
 1560            return value.has_value() ? std::optional{
ScaledInt16{value.
value(), scale.value()}} : std::nullopt;
 
 
 1568            std::optional<int> scale{0};
 
 1569            return getNumber<std::int32_t>(index, scale, 
"std::int32_t");
 
 
 1577            std::optional<int> scale;
 
 1578            const auto value = getNumber<std::int32_t>(index, scale, 
"ScaledInt32");
 
 1579            return value.has_value() ? std::optional{
ScaledInt32{value.
value(), scale.value()}} : std::nullopt;
 
 
 1587            std::optional<int> scale{0};
 
 1588            return getNumber<std::int64_t>(index, scale, 
"std::int64_t");
 
 
 1596            std::optional<int> scale;
 
 1597            const auto value = getNumber<std::int64_t>(index, scale, 
"ScaledInt64");
 
 1598            return value.has_value() ? std::optional{
ScaledInt64{value.
value(), scale.value()}} : std::nullopt;
 
 
 1608            const auto& descriptor = getOutDescriptor(index);
 
 1609            const auto* 
const message = outMessage.data();
 
 1611            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1612                return std::nullopt;
 
 1614            switch (descriptor.adjustedType)
 
 1616                case DescriptorAdjustedType::INT128:
 
 1622                    throwInvalidType(
"OpaqueInt128", descriptor.adjustedType);
 
 
 1626#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1632            std::optional<int> scale{0};
 
 1633            const auto value = getNumber<BoostInt128>(index, scale, 
"BoostInt128");
 
 1634            return value.has_value() ? std::optional{value.value()} : std::nullopt;
 
 
 1642            std::optional<int> scale;
 
 1643            const auto value = getNumber<BoostInt128>(index, scale, 
"ScaledBoostInt128");
 
 1644            return value.has_value() ? std::optional{
ScaledBoostInt128{value.
value(), scale.value()}} : std::nullopt;
 
 
 1653            std::optional<int> scale{0};
 
 1654            return getNumber<float>(index, scale, 
"float");
 
 
 1662            std::optional<int> scale{0};
 
 1663            return getNumber<double>(index, scale, 
"double");
 
 
 1673            const auto& descriptor = getOutDescriptor(index);
 
 1674            const auto* 
const message = outMessage.data();
 
 1676            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1677                return std::nullopt;
 
 1679            switch (descriptor.adjustedType)
 
 1681                case DescriptorAdjustedType::DECFLOAT16:
 
 1685                    throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
 
 
 1689#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1695            std::optional<int> scale{0};
 
 1696            return getNumber<BoostDecFloat16>(index, scale, 
"BoostDecFloat16");
 
 
 1707            const auto& descriptor = getOutDescriptor(index);
 
 1708            const auto* 
const message = outMessage.data();
 
 1710            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1711                return std::nullopt;
 
 1713            switch (descriptor.adjustedType)
 
 1715                case DescriptorAdjustedType::DECFLOAT34:
 
 1719                    throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
 
 
 1723#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 1729            std::optional<int> scale{0};
 
 1730            return getNumber<BoostDecFloat34>(index, scale, 
"BoostDecFloat34");
 
 
 1741            const auto& descriptor = getOutDescriptor(index);
 
 1742            const auto* 
const message = outMessage.data();
 
 1744            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1745                return std::nullopt;
 
 1747            switch (descriptor.adjustedType)
 
 1749                case DescriptorAdjustedType::DATE:
 
 1750                    return calendarConverter.opaqueDateToDate(
 
 1751                        *
reinterpret_cast<const OpaqueDate*
>(&message[descriptor.offset]));
 
 1754                    throwInvalidType(
"Date", descriptor.adjustedType);
 
 
 1765            const auto& descriptor = getOutDescriptor(index);
 
 1766            const auto* 
const message = outMessage.data();
 
 1768            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1769                return std::nullopt;
 
 1771            switch (descriptor.adjustedType)
 
 1773                case DescriptorAdjustedType::DATE:
 
 1777                    throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
 
 
 1788            const auto& descriptor = getOutDescriptor(index);
 
 1789            const auto* 
const message = outMessage.data();
 
 1791            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1792                return std::nullopt;
 
 1794            switch (descriptor.adjustedType)
 
 1796                case DescriptorAdjustedType::TIME:
 
 1797                    return calendarConverter.opaqueTimeToTime(
 
 1798                        *
reinterpret_cast<const OpaqueTime*
>(&message[descriptor.offset]));
 
 1801                    throwInvalidType(
"Time", descriptor.adjustedType);
 
 
 1812            const auto& descriptor = getOutDescriptor(index);
 
 1813            const auto* 
const message = outMessage.data();
 
 1815            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1816                return std::nullopt;
 
 1818            switch (descriptor.adjustedType)
 
 1820                case DescriptorAdjustedType::TIME:
 
 1824                    throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
 
 
 1835            const auto& descriptor = getOutDescriptor(index);
 
 1836            const auto* 
const message = outMessage.data();
 
 1838            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1839                return std::nullopt;
 
 1841            switch (descriptor.adjustedType)
 
 1843                case DescriptorAdjustedType::TIMESTAMP:
 
 1844                    return calendarConverter.opaqueTimestampToTimestamp(
 
 1845                        *
reinterpret_cast<const OpaqueTimestamp*
>(&message[descriptor.offset]));
 
 1848                    throwInvalidType(
"Timestamp", descriptor.adjustedType);
 
 
 1859            const auto& descriptor = getOutDescriptor(index);
 
 1860            const auto* 
const message = outMessage.data();
 
 1862            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1863                return std::nullopt;
 
 1865            switch (descriptor.adjustedType)
 
 1867                case DescriptorAdjustedType::TIMESTAMP:
 
 1871                    throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
 
 
 1882            const auto& descriptor = getOutDescriptor(index);
 
 1883            const auto* 
const message = outMessage.data();
 
 1885            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1886                return std::nullopt;
 
 1888            switch (descriptor.adjustedType)
 
 1890                case DescriptorAdjustedType::TIME_TZ:
 
 1891                    return calendarConverter.opaqueTimeTzToTimeTz(
 
 1892                        *
reinterpret_cast<const OpaqueTimeTz*
>(&message[descriptor.offset]));
 
 1895                    throwInvalidType(
"TimeTz", descriptor.adjustedType);
 
 
 1906            const auto& descriptor = getOutDescriptor(index);
 
 1907            const auto* 
const message = outMessage.data();
 
 1909            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1910                return std::nullopt;
 
 1912            switch (descriptor.adjustedType)
 
 1914                case DescriptorAdjustedType::TIME_TZ:
 
 1918                    throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
 
 
 1929            const auto& descriptor = getOutDescriptor(index);
 
 1930            const auto* 
const message = outMessage.data();
 
 1932            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1933                return std::nullopt;
 
 1935            switch (descriptor.adjustedType)
 
 1937                case DescriptorAdjustedType::TIMESTAMP_TZ:
 
 1938                    return calendarConverter.opaqueTimestampTzToTimestampTz(
 
 1942                    throwInvalidType(
"TimestampTz", descriptor.adjustedType);
 
 
 1953            const auto& descriptor = getOutDescriptor(index);
 
 1954            const auto* 
const message = outMessage.data();
 
 1956            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1957                return std::nullopt;
 
 1959            switch (descriptor.adjustedType)
 
 1961                case DescriptorAdjustedType::TIMESTAMP_TZ:
 
 1965                    throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
 
 
 1976            const auto& descriptor = getOutDescriptor(index);
 
 1977            const auto* 
const message = outMessage.data();
 
 1979            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 1980                return std::nullopt;
 
 1982            switch (descriptor.adjustedType)
 
 1984                case DescriptorAdjustedType::BLOB:
 
 1987                    value.
id = *
reinterpret_cast<const ISC_QUAD*
>(&message[descriptor.offset]);
 
 1992                    throwInvalidType(
"BlobId", 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            const auto data = &message[descriptor.offset];
 
 2011            switch (descriptor.adjustedType)
 
 2013                case DescriptorAdjustedType::BOOLEAN:
 
 2014                    return (message[descriptor.offset] != std::byte{0}) ? std::string{
"true"} : std::string{
"false"};
 
 2016                case DescriptorAdjustedType::INT16:
 
 2017                    return numericConverter.numberToString(
 
 2018                        ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.
scale});
 
 2020                case DescriptorAdjustedType::INT32:
 
 2021                    return numericConverter.numberToString(
 
 2022                        ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.
scale});
 
 2024                case DescriptorAdjustedType::INT64:
 
 2025                    return numericConverter.numberToString(
 
 2026                        ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.
scale});
 
 2028#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2029                case DescriptorAdjustedType::INT128:
 
 2031                        numericConverter.opaqueInt128ToBoostInt128(*
reinterpret_cast<const OpaqueInt128*
>(data)),
 
 2035                case DescriptorAdjustedType::FLOAT:
 
 2036                    return numericConverter.numberToString(*
reinterpret_cast<const float*
>(data));
 
 2038                case DescriptorAdjustedType::DOUBLE:
 
 2039                    return numericConverter.numberToString(*
reinterpret_cast<const double*
>(data));
 
 2041                case DescriptorAdjustedType::DATE:
 
 2042                    return calendarConverter.opaqueDateToString(*
reinterpret_cast<const OpaqueDate*
>(data));
 
 2044                case DescriptorAdjustedType::TIME:
 
 2045                    return calendarConverter.opaqueTimeToString(*
reinterpret_cast<const OpaqueTime*
>(data));
 
 2047                case DescriptorAdjustedType::TIMESTAMP:
 
 2048                    return calendarConverter.opaqueTimestampToString(*
reinterpret_cast<const OpaqueTimestamp*
>(data));
 
 2050                case DescriptorAdjustedType::TIME_TZ:
 
 2051                    return calendarConverter.opaqueTimeTzToString(*
reinterpret_cast<const OpaqueTimeTz*
>(data));
 
 2053                case DescriptorAdjustedType::TIMESTAMP_TZ:
 
 2054                    return calendarConverter.opaqueTimestampTzToString(
 
 2057#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2058                case DescriptorAdjustedType::DECFLOAT16:
 
 2059                    return numericConverter.numberToString(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
 
 2062                case DescriptorAdjustedType::DECFLOAT34:
 
 2063                    return numericConverter.numberToString(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
 
 2067                case DescriptorAdjustedType::STRING:
 
 2068                    return std::string{
reinterpret_cast<const char*
>(data + 
sizeof(std::uint16_t)),
 
 2069                        *
reinterpret_cast<const std::uint16_t*
>(data)};
 
 2072                    throwInvalidType(
"std::string", descriptor.adjustedType);
 
 
 2083        template <
typename T>
 
 2090        const Descriptor& getInDescriptor(
unsigned index)
 
 2092            if (index >= inDescriptors.size())
 
 2093                throw std::out_of_range(
"index out of range");
 
 2095            return inDescriptors[index];
 
 2101        const Descriptor& getOutDescriptor(
unsigned index)
 
 2103            if (index >= outDescriptors.size())
 
 2104                throw std::out_of_range(
"index out of range");
 
 2106            return outDescriptors[index];
 
 2112        template <
typename T>
 
 2113        void setNumber(
unsigned index, 
DescriptorAdjustedType valueType, T value, 
int scale, 
const char* typeName)
 
 2117            const auto& descriptor = getInDescriptor(index);
 
 2118            auto* 
const message = inMessage.data();
 
 2120            const auto descriptorData = &message[descriptor.offset];
 
 2121            std::optional<int> descriptorScale{descriptor.scale};
 
 2123            Descriptor valueDescriptor;
 
 2124            valueDescriptor.adjustedType = valueType;
 
 2125            valueDescriptor.scale = scale;
 
 2127            const auto valueAddress = 
reinterpret_cast<const std::byte*
>(&value);
 
 2129            switch (descriptor.adjustedType)
 
 2131                case DescriptorAdjustedType::INT16:
 
 2132                    *
reinterpret_cast<std::int16_t*
>(descriptorData) =
 
 2133                        convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale, 
"std::int16_t");
 
 2136                case DescriptorAdjustedType::INT32:
 
 2137                    *
reinterpret_cast<std::int32_t*
>(descriptorData) =
 
 2138                        convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale, 
"std::int32_t");
 
 2141                case DescriptorAdjustedType::INT64:
 
 2142                    *
reinterpret_cast<std::int64_t*
>(descriptorData) =
 
 2143                        convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale, 
"std::int64_t");
 
 2146#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2147                case DescriptorAdjustedType::INT128:
 
 2149                    const auto boostInt128 =
 
 2150                        convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale, 
"BoostInt128");
 
 2152                        numericConverter.boostInt128ToOpaqueInt128(boostInt128);
 
 2157                case DescriptorAdjustedType::FLOAT:
 
 2158                    *
reinterpret_cast<float*
>(descriptorData) =
 
 2159                        convertNumber<float>(valueDescriptor, valueAddress, descriptorScale, 
"float");
 
 2162                case DescriptorAdjustedType::DOUBLE:
 
 2163                    *
reinterpret_cast<double*
>(descriptorData) =
 
 2164                        convertNumber<double>(valueDescriptor, valueAddress, descriptorScale, 
"double");
 
 2167#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2168                case DescriptorAdjustedType::DECFLOAT16:
 
 2170                    const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
 
 2171                        valueDescriptor, valueAddress, descriptorScale, 
"BoostDecFloat16");
 
 2173                        numericConverter.boostDecFloat16ToOpaqueDecFloat16(boostDecFloat16);
 
 2177                case DescriptorAdjustedType::DECFLOAT34:
 
 2179                    const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
 
 2180                        valueDescriptor, valueAddress, descriptorScale, 
"BoostDecFloat34");
 
 2182                        numericConverter.boostDecFloat34ToOpaqueDecFloat34(boostDecFloat34);
 
 2188                    throwInvalidType(typeName, descriptor.adjustedType);
 
 2191            *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
 
 2198        template <
typename T>
 
 2199        std::optional<T> getNumber(
unsigned index, std::optional<int>& scale, 
const char* typeName)
 
 2203            const auto& descriptor = getOutDescriptor(index);
 
 2204            const auto* 
const message = outMessage.data();
 
 2206            if (*
reinterpret_cast<const std::int16_t*
>(&message[descriptor.nullOffset]) != FB_FALSE)
 
 2207                return std::nullopt;
 
 2209            auto data = &message[descriptor.offset];
 
 2210            std::optional<BoostInt128> boostInt128;
 
 2211            std::optional<BoostDecFloat16> boostDecFloat16;
 
 2212            std::optional<BoostDecFloat34> boostDecFloat34;
 
 2214            switch (descriptor.adjustedType)
 
 2216#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2217                case DescriptorAdjustedType::INT128:
 
 2218                    boostInt128.emplace(
 
 2219                        numericConverter.opaqueInt128ToBoostInt128(*
reinterpret_cast<const OpaqueInt128*
>(data)));
 
 2220                    data = 
reinterpret_cast<const std::byte*
>(&boostInt128.value());
 
 2223                case DescriptorAdjustedType::DECFLOAT16:
 
 2224                    boostDecFloat16.emplace(numericConverter.opaqueDecFloat16ToBoostDecFloat16(
 
 2226                    data = 
reinterpret_cast<const std::byte*
>(&boostDecFloat16.value());
 
 2229                case DescriptorAdjustedType::DECFLOAT34:
 
 2230                    boostDecFloat34.emplace(numericConverter.opaqueDecFloat34ToBoostDecFloat34(
 
 2232                    data = 
reinterpret_cast<const std::byte*
>(&boostDecFloat34.value());
 
 2240            return convertNumber<T>(descriptor, data, scale, typeName);
 
 2245            throw FbCppException(
"Invalid type: actual type " + std::string(actualType) + 
", descriptor type " +
 
 2246                std::to_string(
static_cast<unsigned>(descriptorType)));
 
 2249        template <
typename T>
 
 2251            const Descriptor& descriptor, 
const std::byte* data, std::optional<int>& toScale, 
const char* toTypeName)
 
 2253            if (!toScale.has_value())
 
 2255                switch (descriptor.adjustedType)
 
 2257                    case DescriptorAdjustedType::DECFLOAT16:
 
 2258                    case DescriptorAdjustedType::DECFLOAT34:
 
 2259                    case DescriptorAdjustedType::FLOAT:
 
 2260                    case DescriptorAdjustedType::DOUBLE:
 
 2261                        throwInvalidType(toTypeName, descriptor.adjustedType);
 
 2267                toScale = descriptor.scale;
 
 2270            switch (descriptor.adjustedType)
 
 2272                case DescriptorAdjustedType::INT16:
 
 2273                    return numericConverter.numberToNumber<T>(
 
 2274                        ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.scale}, toScale.value());
 
 2277                case DescriptorAdjustedType::INT32:
 
 2278                    return numericConverter.numberToNumber<T>(
 
 2279                        ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.scale}, toScale.value());
 
 2281                case DescriptorAdjustedType::INT64:
 
 2282                    return numericConverter.numberToNumber<T>(
 
 2283                        ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.scale}, toScale.value());
 
 2285#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2286                case DescriptorAdjustedType::INT128:
 
 2287                    return numericConverter.numberToNumber<T>(
 
 2291                case DescriptorAdjustedType::DECFLOAT16:
 
 2292                    return numericConverter.numberToNumber<T>(
 
 2295                case DescriptorAdjustedType::DECFLOAT34:
 
 2296                    return numericConverter.numberToNumber<T>(
 
 2300                case DescriptorAdjustedType::FLOAT:
 
 2301                    return numericConverter.numberToNumber<T>(*
reinterpret_cast<const float*
>(data), toScale.value());
 
 2304                case DescriptorAdjustedType::DOUBLE:
 
 2305                    return numericConverter.numberToNumber<T>(*
reinterpret_cast<const double*
>(data), toScale.value());
 
 2309                    throwInvalidType(toTypeName, descriptor.adjustedType);
 
 2314        Attachment& attachment;
 
 2315        FbUniquePtr<Firebird::IStatus> status;
 
 2316        impl::StatusWrapper statusWrapper;
 
 2317        impl::CalendarConverter calendarConverter;
 
 2318        impl::NumericConverter numericConverter;
 
 2319        FbRef<fb::IStatement> statementHandle;
 
 2320        FbRef<fb::IResultSet> resultSetHandle;
 
 2321        FbRef<fb::IMessageMetadata> inMetadata;
 
 2322        std::vector<Descriptor> inDescriptors;
 
 2323        std::vector<std::byte> inMessage;
 
 2324        FbRef<fb::IMessageMetadata> outMetadata;
 
 2325        std::vector<Descriptor> outDescriptors;
 
 2326        std::vector<std::byte> outMessage;
 
 
 2336    inline std::optional<bool> Statement::get<std::optional<bool>>(
unsigned index)
 
 2338        return getBool(index);
 
 2342    inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(
unsigned index)
 
 2344        return getBlobId(index);
 
 2348    inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(
unsigned index)
 
 2350        return getInt16(index);
 
 2354    inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(
unsigned index)
 
 2356        return getScaledInt16(index);
 
 2360    inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(
unsigned index)
 
 2362        return getInt32(index);
 
 2366    inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(
unsigned index)
 
 2368        return getScaledInt32(index);
 
 2372    inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(
unsigned index)
 
 2374        return getInt64(index);
 
 2378    inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(
unsigned index)
 
 2380        return getScaledInt64(index);
 
 2384    inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(
unsigned index)
 
 2386        return getScaledOpaqueInt128(index);
 
 2389#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2391    inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(
unsigned index)
 
 2393        return getBoostInt128(index);
 
 2397    inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(
unsigned index)
 
 2399        return getScaledBoostInt128(index);
 
 2404    inline std::optional<float> Statement::get<std::optional<float>>(
unsigned index)
 
 2406        return getFloat(index);
 
 2410    inline std::optional<double> Statement::get<std::optional<double>>(
unsigned index)
 
 2412        return getDouble(index);
 
 2416    inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(
unsigned index)
 
 2418        return getOpaqueDecFloat16(index);
 
 2421#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2423    inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(
unsigned index)
 
 2425        return getBoostDecFloat16(index);
 
 2430    inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(
unsigned index)
 
 2432        return getOpaqueDecFloat34(index);
 
 2435#if FB_CPP_USE_BOOST_MULTIPRECISION != 0 
 2437    inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(
unsigned index)
 
 2439        return getBoostDecFloat34(index);
 
 2444    inline std::optional<Date> Statement::get<std::optional<Date>>(
unsigned index)
 
 2446        return getDate(index);
 
 2450    inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(
unsigned index)
 
 2452        return getOpaqueDate(index);
 
 2456    inline std::optional<Time> Statement::get<std::optional<Time>>(
unsigned index)
 
 2458        return getTime(index);
 
 2462    inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(
unsigned index)
 
 2464        return getOpaqueTime(index);
 
 2468    inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(
unsigned index)
 
 2470        return getOpaqueTimestamp(index);
 
 2474    inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(
unsigned index)
 
 2476        return getTimestamp(index);
 
 2480    inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(
unsigned index)
 
 2482        return getTimeTz(index);
 
 2486    inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(
unsigned index)
 
 2488        return getOpaqueTimeTz(index);
 
 2492    inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(
unsigned index)
 
 2494        return getTimestampTz(index);
 
 2498    inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(
unsigned index)
 
 2500        return getOpaqueTimestampTz(index);
 
 2504    inline std::optional<std::string> Statement::get<std::optional<std::string>>(
unsigned index)
 
 2506        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.
Represents options used when preparing a 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 & 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.
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.
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 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, 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.
Represents a transaction in a Firebird database.
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.
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.