25#ifndef FBCPP_STATEMENT_H
26#define FBCPP_STATEMENT_H
32#include "Attachment.h"
35#include "NumericConverter.h"
36#include "CalendarConverter.h"
37#include "Descriptor.h"
40#include "StructBinding.h"
41#include "VariantTypeTraits.h"
58#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
59#include <boost/multiprecision/cpp_int.hpp>
60#include <boost/multiprecision/cpp_dec_float.hpp>
97 return prefetchLegacyPlan;
107 prefetchLegacyPlan = value;
126 prefetchPlan = value;
188 bool prefetchLegacyPlan =
false;
189 bool prefetchPlan =
false;
190 std::optional<std::string> cursorName;
192 unsigned dialect = SQL_DIALECT_CURRENT;
203 SELECT = isc_info_sql_stmt_select,
207 INSERT = isc_info_sql_stmt_insert,
211 UPDATE = isc_info_sql_stmt_update,
215 DELETE = isc_info_sql_stmt_delete,
219 DDL = isc_info_sql_stmt_ddl,
239 COMMIT = isc_info_sql_stmt_commit,
243 ROLLBACK = isc_info_sql_stmt_rollback,
278 : attachment{o.attachment},
279 statusWrapper{std::move(o.statusWrapper)},
280 calendarConverter{std::move(o.calendarConverter)},
281 numericConverter{std::move(o.numericConverter)},
282 statementHandle{std::move(o.statementHandle)},
283 resultSetHandle{std::move(o.resultSetHandle)},
284 inMetadata{std::move(o.inMetadata)},
285 inDescriptors{std::move(o.inDescriptors)},
286 inMessage{std::move(o.inMessage)},
287 outMetadata{std::move(o.outMetadata)},
288 outDescriptors{std::move(o.outDescriptors)},
289 outMessage{std::move(o.outMessage)},
290 outRow{std::make_unique<Row>(attachment->
getClient(), outDescriptors, std::span{outMessage})},
292 cursorFlags{o.cursorFlags}
307 attachment = o.attachment;
308 statusWrapper = std::move(o.statusWrapper);
309 calendarConverter = std::move(o.calendarConverter);
310 numericConverter = std::move(o.numericConverter);
311 statementHandle = std::move(o.statementHandle);
312 resultSetHandle = std::move(o.resultSetHandle);
313 inMetadata = std::move(o.inMetadata);
314 inDescriptors = std::move(o.inDescriptors);
315 inMessage = std::move(o.inMessage);
316 outMetadata = std::move(o.outMetadata);
317 outDescriptors = std::move(o.outDescriptors);
318 outMessage = std::move(o.outMessage);
319 outRow = std::make_unique<Row>(attachment->
getClient(), outDescriptors, std::span{outMessage});
321 cursorFlags = o.cursorFlags;
370 return statementHandle !=
nullptr;
379 return statementHandle;
388 return resultSetHandle;
446 return inDescriptors;
454 return outDescriptors;
532 const auto message = inMessage.data();
534 for (
const auto& descriptor : inDescriptors)
535 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
546 const auto& descriptor = getInDescriptor(index);
547 const auto message = inMessage.data();
549 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_TRUE;
557 void setBool(
unsigned index, std::optional<bool> optValue)
559 if (!optValue.has_value())
567 const auto& value = optValue.value();
568 const auto& descriptor = getInDescriptor(index);
569 const auto message = inMessage.data();
571 switch (descriptor.adjustedType)
574 message[descriptor.offset] = value ? std::byte{1} : std::byte{0};
578 throwInvalidType(
"bool", descriptor.adjustedType);
581 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
587 void setInt16(
unsigned index, std::optional<std::int16_t> optValue)
589 if (!optValue.has_value())
603 if (!optValue.has_value())
609 const auto& value = optValue.value();
616 void setInt32(
unsigned index, std::optional<std::int32_t> optValue)
618 if (!optValue.has_value())
632 if (!optValue.has_value())
638 const auto& value = optValue.value();
645 void setInt64(
unsigned index, std::optional<std::int64_t> optValue)
647 if (!optValue.has_value())
661 if (!optValue.has_value())
667 const auto& value = optValue.value();
676 if (!optValue.has_value())
684 const auto& value = optValue.value();
685 const auto& descriptor = getInDescriptor(index);
686 const auto message = inMessage.data();
688 switch (descriptor.adjustedType)
691 *
reinterpret_cast<OpaqueInt128*
>(&message[descriptor.offset]) = value;
695 throwInvalidType(
"OpaqueInt128", descriptor.adjustedType);
698 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
701#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
707 if (!optValue.has_value())
721 if (!optValue.has_value())
727 const auto& value = optValue.value();
735 void setFloat(
unsigned index, std::optional<float> optValue)
737 if (!optValue.has_value())
749 void setDouble(
unsigned index, std::optional<double> optValue)
751 if (!optValue.has_value())
765 if (!optValue.has_value())
773 const auto& value = optValue.value();
774 const auto& descriptor = getInDescriptor(index);
775 const auto message = inMessage.data();
777 switch (descriptor.adjustedType)
784 throwInvalidType(
"OpaqueDecFloat16", descriptor.adjustedType);
787 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
790#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
796 if (!optValue.has_value())
811 if (!optValue.has_value())
819 const auto& value = optValue.value();
820 const auto& descriptor = getInDescriptor(index);
821 const auto message = inMessage.data();
823 switch (descriptor.adjustedType)
830 throwInvalidType(
"OpaqueDecFloat34", descriptor.adjustedType);
833 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
836#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
842 if (!optValue.has_value())
855 void setDate(
unsigned index, std::optional<Date> optValue)
857 if (!optValue.has_value())
865 const auto& value = optValue.value();
866 const auto& descriptor = getInDescriptor(index);
867 const auto message = inMessage.data();
869 switch (descriptor.adjustedType)
872 *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) =
873 calendarConverter.dateToOpaqueDate(value);
877 throwInvalidType(
"Date", descriptor.adjustedType);
880 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
888 if (!optValue.has_value())
896 const auto& value = optValue.value();
897 const auto& descriptor = getInDescriptor(index);
898 const auto message = inMessage.data();
900 switch (descriptor.adjustedType)
903 *
reinterpret_cast<OpaqueDate*
>(&message[descriptor.offset]) = value;
907 throwInvalidType(
"OpaqueDate", descriptor.adjustedType);
910 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
916 void setTime(
unsigned index, std::optional<Time> optValue)
918 if (!optValue.has_value())
926 const auto& value = optValue.value();
927 const auto& descriptor = getInDescriptor(index);
928 const auto message = inMessage.data();
930 switch (descriptor.adjustedType)
933 *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) =
934 calendarConverter.timeToOpaqueTime(value);
938 throwInvalidType(
"Time", descriptor.adjustedType);
941 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
949 if (!optValue.has_value())
957 const auto& value = optValue.value();
958 const auto& descriptor = getInDescriptor(index);
959 const auto message = inMessage.data();
961 switch (descriptor.adjustedType)
964 *
reinterpret_cast<OpaqueTime*
>(&message[descriptor.offset]) = value;
968 throwInvalidType(
"OpaqueTime", descriptor.adjustedType);
971 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
979 if (!optValue.has_value())
987 const auto& value = optValue.value();
988 const auto& descriptor = getInDescriptor(index);
989 const auto message = inMessage.data();
991 switch (descriptor.adjustedType)
995 calendarConverter.timestampToOpaqueTimestamp(value);
999 throwInvalidType(
"Timestamp", descriptor.adjustedType);
1002 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1010 if (!optValue.has_value())
1018 const auto& value = optValue.value();
1019 const auto& descriptor = getInDescriptor(index);
1020 const auto message = inMessage.data();
1022 switch (descriptor.adjustedType)
1025 *
reinterpret_cast<OpaqueTimestamp*
>(&message[descriptor.offset]) = value;
1029 throwInvalidType(
"OpaqueTimestamp", descriptor.adjustedType);
1032 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1038 void setTimeTz(
unsigned index, std::optional<TimeTz> optValue)
1040 if (!optValue.has_value())
1048 const auto& value = optValue.value();
1049 const auto& descriptor = getInDescriptor(index);
1050 auto*
const message = inMessage.data();
1052 switch (descriptor.adjustedType)
1055 *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) =
1056 calendarConverter.timeTzToOpaqueTimeTz(&statusWrapper, value);
1060 throwInvalidType(
"TimeTz", descriptor.adjustedType);
1063 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1071 if (!optValue.has_value())
1079 const auto& value = optValue.value();
1080 const auto& descriptor = getInDescriptor(index);
1081 auto*
const message = inMessage.data();
1083 switch (descriptor.adjustedType)
1086 *
reinterpret_cast<OpaqueTimeTz*
>(&message[descriptor.offset]) = value;
1090 throwInvalidType(
"OpaqueTimeTz", descriptor.adjustedType);
1093 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1101 if (!optValue.has_value())
1109 const auto& value = optValue.value();
1110 const auto& descriptor = getInDescriptor(index);
1111 auto*
const message = inMessage.data();
1113 switch (descriptor.adjustedType)
1117 calendarConverter.timestampTzToOpaqueTimestampTz(&statusWrapper, value);
1121 throwInvalidType(
"TimestampTz", descriptor.adjustedType);
1124 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1132 if (!optValue.has_value())
1140 const auto& value = optValue.value();
1141 const auto& descriptor = getInDescriptor(index);
1142 auto*
const message = inMessage.data();
1144 switch (descriptor.adjustedType)
1151 throwInvalidType(
"OpaqueTimestampTz", descriptor.adjustedType);
1154 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1160 void setString(
unsigned index, std::optional<std::string_view> optValue)
1162 if (!optValue.has_value())
1171 const auto value = optValue.value();
1172 const auto& descriptor = getInDescriptor(index);
1173 const auto message = inMessage.data();
1174 const auto data = &message[descriptor.offset];
1176 switch (descriptor.adjustedType)
1179 message[descriptor.offset] = numericConverter.stringToBoolean(value);
1186 std::string strValue(value);
1189 if (
const auto dotPos = strValue.find_last_of(
'.'); dotPos != std::string_view::npos)
1191 for (
auto pos = dotPos + 1; pos < strValue.size(); ++pos)
1193 const char c = value[pos];
1195 if (c <
'0' || c >
'9')
1201 strValue.erase(dotPos, 1);
1204 static_assert(
sizeof(
long long) ==
sizeof(std::int64_t));
1205 std::int64_t intValue;
1206 const auto convResult =
1207 std::from_chars(strValue.data(), strValue.data() + strValue.size(), intValue);
1208 if (convResult.ec != std::errc{} || convResult.ptr != strValue.data() + strValue.size())
1209 numericConverter.throwConversionErrorFromString(strValue);
1212 if (scale != descriptor.scale)
1215 numericConverter.numberToNumber<std::int64_t>(scaledValue, descriptor.scale);
1216 scaledValue.scale = descriptor.scale;
1225 std::string strValue(value);
1226 client.getInt128Util(&statusWrapper)
1228 &statusWrapper, descriptor.scale, strValue.c_str(),
reinterpret_cast<OpaqueInt128*
>(data));
1236#if defined(__APPLE__)
1238 std::string valueString{value};
1239 char* parseEnd =
nullptr;
1240 doubleValue = std::strtod(valueString.c_str(), &parseEnd);
1241 if (parseEnd != valueString.c_str() + valueString.size() || errno == ERANGE)
1242 numericConverter.throwConversionErrorFromString(std::move(valueString));
1244 const auto convResult = std::from_chars(value.data(), value.data() + value.size(), doubleValue);
1245 if (convResult.ec != std::errc{} || convResult.ptr != value.data() + value.size())
1246 numericConverter.throwConversionErrorFromString(std::string{value});
1253 *
reinterpret_cast<OpaqueDate*
>(data) = calendarConverter.stringToOpaqueDate(value);
1257 *
reinterpret_cast<OpaqueTime*
>(data) = calendarConverter.stringToOpaqueTime(value);
1261 *
reinterpret_cast<OpaqueTimestamp*
>(data) = calendarConverter.stringToOpaqueTimestamp(value);
1266 calendarConverter.stringToOpaqueTimeTz(&statusWrapper, value);
1271 calendarConverter.stringToOpaqueTimestampTz(&statusWrapper, value);
1274#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1277 std::string strValue{value};
1278 client.getDecFloat16Util(&statusWrapper)
1279 ->fromString(&statusWrapper, strValue.c_str(),
reinterpret_cast<OpaqueDecFloat16*
>(data));
1285 std::string strValue{value};
1286 client.getDecFloat34Util(&statusWrapper)
1287 ->fromString(&statusWrapper, strValue.c_str(),
reinterpret_cast<OpaqueDecFloat34*
>(data));
1293 if (value.length() > descriptor.length)
1295 static constexpr std::intptr_t STATUS_STRING_TRUNCATION[] = {
1297 isc_string_truncation,
1304 *
reinterpret_cast<std::uint16_t*
>(data) =
static_cast<std::uint16_t
>(value.length());
1305 std::copy(value.begin(), value.end(),
1306 reinterpret_cast<char*
>(&message[descriptor.offset +
sizeof(std::uint16_t)]));
1310 throwInvalidType(
"std::string_view", descriptor.adjustedType);
1313 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1319 void setBlobId(
unsigned index, std::optional<BlobId> optValue)
1321 if (!optValue.has_value())
1329 const auto& value = optValue.value();
1330 const auto& descriptor = getInDescriptor(index);
1331 auto*
const message = inMessage.data();
1333 switch (descriptor.adjustedType)
1336 *
reinterpret_cast<ISC_QUAD*
>(&message[descriptor.offset]) = value.id;
1340 throwInvalidType(
"BlobId", descriptor.adjustedType);
1343 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
1348 void set(
unsigned index, std::nullopt_t)
1364 void set(
unsigned index, std::optional<BlobId> value)
1372 void set(
unsigned index,
bool value)
1380 void set(
unsigned index, std::int16_t value)
1396 void set(
unsigned index, std::int32_t value)
1412 void set(
unsigned index, std::int64_t value)
1433#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1454 void set(
unsigned index,
float value)
1462 void set(
unsigned index,
double value)
1475#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1493#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1586 void set(
unsigned index, std::string_view value)
1594 template <
typename T>
1595 void set(
unsigned index, std::optional<T> value)
1597 if (value.has_value())
1598 set(index, value.value());
1617 return outRow->isNull(index);
1626 return outRow->getBool(index);
1635 return outRow->getInt16(index);
1644 return outRow->getScaledInt16(index);
1653 return outRow->getInt32(index);
1662 return outRow->getScaledInt32(index);
1671 return outRow->getInt64(index);
1680 return outRow->getScaledInt64(index);
1689 return outRow->getScaledOpaqueInt128(index);
1692#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1699 return outRow->getBoostInt128(index);
1708 return outRow->getScaledBoostInt128(index);
1718 return outRow->getFloat(index);
1727 return outRow->getDouble(index);
1736 return outRow->getOpaqueDecFloat16(index);
1739#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1746 return outRow->getBoostDecFloat16(index);
1756 return outRow->getOpaqueDecFloat34(index);
1759#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
1766 return outRow->getBoostDecFloat34(index);
1776 return outRow->getDate(index);
1785 return outRow->getOpaqueDate(index);
1794 return outRow->getTime(index);
1803 return outRow->getOpaqueTime(index);
1812 return outRow->getTimestamp(index);
1821 return outRow->getOpaqueTimestamp(index);
1830 return outRow->getTimeTz(index);
1839 return outRow->getOpaqueTimeTz(index);
1848 return outRow->getTimestampTz(index);
1857 return outRow->getOpaqueTimestampTz(index);
1866 return outRow->getBlobId(index);
1875 return outRow->getString(index);
1885 template <
typename T>
1889 return outRow->get<T>(index);
1899 template <Aggregate T>
1903 return outRow->get<T>();
1912 template <Aggregate T>
1915 using namespace impl::reflection;
1917 constexpr std::size_t N = fieldCountV<T>;
1919 if (N != inDescriptors.size())
1921 throw FbCppException(
"Struct field count (" + std::to_string(N) +
1922 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) +
")");
1925 setStruct(value, std::make_index_sequence<N>{});
1935 template <TupleLike T>
1939 return outRow->get<T>();
1948 template <TupleLike T>
1951 constexpr std::size_t N = std::tuple_size_v<T>;
1953 if (N != inDescriptors.size())
1955 throw FbCppException(
"Tuple element count (" + std::to_string(N) +
1956 ") does not match input parameter count (" + std::to_string(inDescriptors.size()) +
")");
1959 setTuple(value, std::make_index_sequence<N>{});
1970 template <VariantLike V>
1974 return outRow->get<V>(index);
1983 template <VariantLike V>
1984 void set(
unsigned index,
const V& value)
1986 using namespace impl::reflection;
1988 static_assert(variantAlternativesSupportedV<V>,
1989 "Variant contains unsupported types. All variant alternatives must be types supported by fb-cpp "
1990 "(e.g., std::int32_t, std::string, Date, ScaledOpaqueInt128, etc.). Check VariantTypeTraits.h for the "
1991 "complete list of supported types.");
1994 [
this, index](
const auto& v)
1996 using T = std::decay_t<
decltype(v)>;
1998 if constexpr (std::is_same_v<T, std::monostate>)
2010 const Descriptor& getInDescriptor(
unsigned index)
2012 if (index >= inDescriptors.size())
2013 throw std::out_of_range(
"index out of range");
2015 return inDescriptors[index];
2021 template <
typename T, std::size_t... Is>
2022 void setStruct(
const T& value, std::index_sequence<Is...>)
2024 using namespace impl::reflection;
2026 const auto tuple = toTupleRef(value);
2027 (
set(
static_cast<unsigned>(Is), std::get<Is>(tuple)), ...);
2033 template <
typename T, std::size_t... Is>
2034 void setTuple(
const T& value, std::index_sequence<Is...>)
2036 (
set(
static_cast<unsigned>(Is), std::get<Is>(value)), ...);
2042 template <
typename T>
2043 void setNumber(
unsigned index,
DescriptorAdjustedType valueType, T value,
int scale,
const char* typeName)
2047 const auto& descriptor = getInDescriptor(index);
2048 auto*
const message = inMessage.data();
2050 const auto descriptorData = &message[descriptor.offset];
2051 std::optional<int> descriptorScale{descriptor.scale};
2053 Descriptor valueDescriptor;
2054 valueDescriptor.adjustedType = valueType;
2055 valueDescriptor.scale = scale;
2057 const auto valueAddress =
reinterpret_cast<const std::byte*
>(&value);
2059 switch (descriptor.adjustedType)
2062 *
reinterpret_cast<std::int16_t*
>(descriptorData) =
2063 convertNumber<std::int16_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int16_t");
2067 *
reinterpret_cast<std::int32_t*
>(descriptorData) =
2068 convertNumber<std::int32_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int32_t");
2072 *
reinterpret_cast<std::int64_t*
>(descriptorData) =
2073 convertNumber<std::int64_t>(valueDescriptor, valueAddress, descriptorScale,
"std::int64_t");
2076#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2079 const auto boostInt128 =
2080 convertNumber<BoostInt128>(valueDescriptor, valueAddress, descriptorScale,
"BoostInt128");
2082 numericConverter.boostInt128ToOpaqueInt128(boostInt128);
2088 *
reinterpret_cast<float*
>(descriptorData) =
2089 convertNumber<float>(valueDescriptor, valueAddress, descriptorScale,
"float");
2093 *
reinterpret_cast<double*
>(descriptorData) =
2094 convertNumber<double>(valueDescriptor, valueAddress, descriptorScale,
"double");
2097#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2100 const auto boostDecFloat16 = convertNumber<BoostDecFloat16>(
2101 valueDescriptor, valueAddress, descriptorScale,
"BoostDecFloat16");
2103 numericConverter.boostDecFloat16ToOpaqueDecFloat16(&statusWrapper, boostDecFloat16);
2109 const auto boostDecFloat34 = convertNumber<BoostDecFloat34>(
2110 valueDescriptor, valueAddress, descriptorScale,
"BoostDecFloat34");
2112 numericConverter.boostDecFloat34ToOpaqueDecFloat34(&statusWrapper, boostDecFloat34);
2118 throwInvalidType(typeName, descriptor.adjustedType);
2121 *
reinterpret_cast<std::int16_t*
>(&message[descriptor.nullOffset]) = FB_FALSE;
2126 throw FbCppException(
"Invalid type: actual type " + std::string(actualType) +
", descriptor type " +
2127 std::to_string(
static_cast<unsigned>(descriptorType)));
2130 template <
typename T>
2132 const Descriptor& descriptor,
const std::byte* data, std::optional<int>& toScale,
const char* toTypeName)
2134 if (!toScale.has_value())
2136 switch (descriptor.adjustedType)
2142 throwInvalidType(toTypeName, descriptor.adjustedType);
2148 toScale = descriptor.scale;
2151 switch (descriptor.adjustedType)
2154 return numericConverter.numberToNumber<T>(
2155 ScaledInt16{*
reinterpret_cast<const std::int16_t*
>(data), descriptor.scale}, toScale.value());
2159 return numericConverter.numberToNumber<T>(
2160 ScaledInt32{*
reinterpret_cast<const std::int32_t*
>(data), descriptor.scale}, toScale.value());
2163 return numericConverter.numberToNumber<T>(
2164 ScaledInt64{*
reinterpret_cast<const std::int64_t*
>(data), descriptor.scale}, toScale.value());
2166#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2168 return numericConverter.numberToNumber<T>(
2173 return numericConverter.numberToNumber<T>(
2177 return numericConverter.numberToNumber<T>(
2182 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const float*
>(data), toScale.value());
2186 return numericConverter.numberToNumber<T>(*
reinterpret_cast<const double*
>(data), toScale.value());
2190 throwInvalidType(toTypeName, descriptor.adjustedType);
2195 Attachment* attachment;
2196 impl::StatusWrapper statusWrapper;
2197 impl::CalendarConverter calendarConverter;
2198 impl::NumericConverter numericConverter;
2199 FbRef<fb::IStatement> statementHandle;
2200 FbRef<fb::IResultSet> resultSetHandle;
2201 FbRef<fb::IMessageMetadata> inMetadata;
2202 std::vector<Descriptor> inDescriptors;
2203 std::vector<std::byte> inMessage;
2204 FbRef<fb::IMessageMetadata> outMetadata;
2205 std::vector<Descriptor> outDescriptors;
2206 std::vector<std::byte> outMessage;
2207 std::unique_ptr<Row> outRow;
2209 unsigned cursorFlags = 0;
2218 inline std::optional<bool> Statement::get<std::optional<bool>>(
unsigned index)
2220 return getBool(index);
2224 inline std::optional<BlobId> Statement::get<std::optional<BlobId>>(
unsigned index)
2226 return getBlobId(index);
2230 inline std::optional<std::int16_t> Statement::get<std::optional<std::int16_t>>(
unsigned index)
2232 return getInt16(index);
2236 inline std::optional<ScaledInt16> Statement::get<std::optional<ScaledInt16>>(
unsigned index)
2238 return getScaledInt16(index);
2242 inline std::optional<std::int32_t> Statement::get<std::optional<std::int32_t>>(
unsigned index)
2244 return getInt32(index);
2248 inline std::optional<ScaledInt32> Statement::get<std::optional<ScaledInt32>>(
unsigned index)
2250 return getScaledInt32(index);
2254 inline std::optional<std::int64_t> Statement::get<std::optional<std::int64_t>>(
unsigned index)
2256 return getInt64(index);
2260 inline std::optional<ScaledInt64> Statement::get<std::optional<ScaledInt64>>(
unsigned index)
2262 return getScaledInt64(index);
2266 inline std::optional<ScaledOpaqueInt128> Statement::get<std::optional<ScaledOpaqueInt128>>(
unsigned index)
2268 return getScaledOpaqueInt128(index);
2271#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2273 inline std::optional<BoostInt128> Statement::get<std::optional<BoostInt128>>(
unsigned index)
2275 return getBoostInt128(index);
2279 inline std::optional<ScaledBoostInt128> Statement::get<std::optional<ScaledBoostInt128>>(
unsigned index)
2281 return getScaledBoostInt128(index);
2286 inline std::optional<float> Statement::get<std::optional<float>>(
unsigned index)
2288 return getFloat(index);
2292 inline std::optional<double> Statement::get<std::optional<double>>(
unsigned index)
2294 return getDouble(index);
2298 inline std::optional<OpaqueDecFloat16> Statement::get<std::optional<OpaqueDecFloat16>>(
unsigned index)
2300 return getOpaqueDecFloat16(index);
2303#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2305 inline std::optional<BoostDecFloat16> Statement::get<std::optional<BoostDecFloat16>>(
unsigned index)
2307 return getBoostDecFloat16(index);
2312 inline std::optional<OpaqueDecFloat34> Statement::get<std::optional<OpaqueDecFloat34>>(
unsigned index)
2314 return getOpaqueDecFloat34(index);
2317#if FB_CPP_USE_BOOST_MULTIPRECISION != 0
2319 inline std::optional<BoostDecFloat34> Statement::get<std::optional<BoostDecFloat34>>(
unsigned index)
2321 return getBoostDecFloat34(index);
2326 inline std::optional<Date> Statement::get<std::optional<Date>>(
unsigned index)
2328 return getDate(index);
2332 inline std::optional<OpaqueDate> Statement::get<std::optional<OpaqueDate>>(
unsigned index)
2334 return getOpaqueDate(index);
2338 inline std::optional<Time> Statement::get<std::optional<Time>>(
unsigned index)
2340 return getTime(index);
2344 inline std::optional<OpaqueTime> Statement::get<std::optional<OpaqueTime>>(
unsigned index)
2346 return getOpaqueTime(index);
2350 inline std::optional<OpaqueTimestamp> Statement::get<std::optional<OpaqueTimestamp>>(
unsigned index)
2352 return getOpaqueTimestamp(index);
2356 inline std::optional<Timestamp> Statement::get<std::optional<Timestamp>>(
unsigned index)
2358 return getTimestamp(index);
2362 inline std::optional<TimeTz> Statement::get<std::optional<TimeTz>>(
unsigned index)
2364 return getTimeTz(index);
2368 inline std::optional<OpaqueTimeTz> Statement::get<std::optional<OpaqueTimeTz>>(
unsigned index)
2370 return getOpaqueTimeTz(index);
2374 inline std::optional<TimestampTz> Statement::get<std::optional<TimestampTz>>(
unsigned index)
2376 return getTimestampTz(index);
2380 inline std::optional<OpaqueTimestampTz> Statement::get<std::optional<OpaqueTimestampTz>>(
unsigned index)
2382 return getOpaqueTimestampTz(index);
2386 inline std::optional<std::string> Statement::get<std::optional<std::string>>(
unsigned index)
2388 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.
Exception thrown when a Firebird database operation fails.
Base exception class for all fb-cpp exceptions.
Reference-counted smart pointer for Firebird objects using addRef/release semantics.
Represents options used when preparing a Statement.
const std::optional< std::string > & getCursorName() const
Returns the cursor name to be set for the statement.
unsigned getDialect() const
Returns the SQL dialect used when preparing the statement.
StatementOptions & setDialect(unsigned value)
Sets the SQL dialect used when preparing the statement.
StatementOptions & setCursorType(CursorType value)
Sets the cursor type used when opening a result set.
StatementOptions & setPrefetchLegacyPlan(bool value)
Enables or disables prefetching of the legacy textual plan at prepare time.
bool getPrefetchPlan() const
Reports whether the structured plan should be prefetched during prepare.
StatementOptions & setCursorName(const std::string &value)
Sets the cursor name for the statement.
StatementOptions & setPrefetchPlan(bool value)
Enables or disables prefetching of the structured plan at prepare time.
bool getPrefetchLegacyPlan() const
Reports whether the legacy textual plan should be prefetched during prepare.
CursorType getCursorType() const
Returns the cursor type to be used when opening a result set.
Prepares, executes, and fetches SQL statements against a Firebird attachment.
void set(unsigned index, OpaqueInt128 value)
Convenience overload that binds a Firebird 128-bit integer.
Statement & operator=(Statement &&o) noexcept
Transfers ownership of another prepared statement into this one.
void setScaledInt16(unsigned index, std::optional< ScaledInt16 > optValue)
Binds a scaled 16-bit signed integer value or null.
V get(unsigned index)
Retrieves a column value as a user-defined variant type.
bool fetchAbsolute(unsigned position)
Positions the cursor on the given absolute row number.
void setNull(unsigned index)
Marks the specified parameter as null.
bool fetchRelative(int offset)
Moves the cursor by the requested relative offset.
void setScaledBoostInt128(unsigned index, std::optional< ScaledBoostInt128 > optValue)
Binds a scaled 128-bit integer value expressed with Boost.Multiprecision or null.
std::optional< OpaqueTime > getOpaqueTime(unsigned index)
Reads a raw time-of-day column in Firebird's representation.
std::optional< OpaqueDecFloat34 > getOpaqueDecFloat34(unsigned index)
Reads a Firebird 34-digit decimal floating-point column.
std::vector< std::byte > & getOutputMessage() noexcept
Provides direct access to the raw output message buffer.
void setDate(unsigned index, std::optional< Date > optValue)
Binds a date value or null.
std::string getLegacyPlan()
Retrieves the textual legacy plan if the server produced one.
const std::vector< Descriptor > & getInputDescriptors() noexcept
Provides cached descriptors for each input column.
void free()
Releases the prepared handle and any associated result set.
const std::vector< Descriptor > & getOutputDescriptors() noexcept
Provides cached descriptors for each output column.
bool isValid() noexcept
Returns whether the Statement object is valid.
StatementType getType() noexcept
Returns the type classification reported by the server.
void set(unsigned index, BoostDecFloat16 value)
Convenience overload that binds a Boost 16-digit decimal floating-point value.
std::optional< TimeTz > getTimeTz(unsigned index)
Reads a time-of-day column with timezone.
void setTime(unsigned index, std::optional< Time > optValue)
Binds a time-of-day value without timezone or null.
void set(unsigned index, std::string_view value)
Convenience overload that binds a textual value.
std::optional< BoostDecFloat34 > getBoostDecFloat34(unsigned index)
Reads a Boost-based 34-digit decimal floating-point column.
void setBlobId(unsigned index, std::optional< BlobId > optValue)
Binds a blob identifier to the specified parameter or null.
void setInt16(unsigned index, std::optional< std::int16_t > optValue)
Binds a 16-bit signed integer value or null.
void setString(unsigned index, std::optional< std::string_view > optValue)
Binds a textual parameter or null, performing direct conversions where supported.
void set(unsigned index, std::int32_t value)
Convenience overload that binds a 32-bit signed integer.
std::optional< Time > getTime(unsigned index)
Reads a time-of-day column without timezone.
std::optional< Date > getDate(unsigned index)
Reads a date column.
FbRef< fb::IResultSet > getResultSetHandle() noexcept
Provides access to the underlying Firebird currently open result set handle, if any.
bool isNull(unsigned index)
Reports whether the most recently fetched row has a null at the given column.
void set(unsigned index, double value)
Convenience overload that binds a double precision floating-point value.
void clearParameters()
Marks all bound parameters as null values.
void set(unsigned index, ScaledInt64 value)
Convenience overload that binds a scaled 64-bit signed integer.
std::optional< OpaqueDate > getOpaqueDate(unsigned index)
Reads a raw date column in Firebird's representation.
T get()
Retrieves all output columns into a user-defined aggregate struct.
void setScaledInt32(unsigned index, std::optional< ScaledInt32 > optValue)
Binds a scaled 32-bit signed integer value or null.
void set(unsigned index, std::int64_t value)
Convenience overload that binds a 64-bit signed integer.
void setTimestampTz(unsigned index, std::optional< TimestampTz > optValue)
Binds a timestamp value with timezone or null.
std::optional< std::int64_t > getInt64(unsigned index)
Reads a 64-bit signed integer column.
FbRef< fb::IStatement > getStatementHandle() noexcept
Provides direct access to the underlying Firebird statement handle.
std::optional< ScaledInt32 > getScaledInt32(unsigned index)
Reads a scaled 32-bit signed integer column.
void set(unsigned index, OpaqueTimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
void setOpaqueTime(unsigned index, std::optional< OpaqueTime > optValue)
Binds a raw time-of-day value in Firebird's representation or null.
std::optional< float > getFloat(unsigned index)
Reads a single precision floating-point column.
std::optional< double > getDouble(unsigned index)
Reads a double precision floating-point column.
std::optional< OpaqueTimestampTz > getOpaqueTimestampTz(unsigned index)
Reads a raw timestamp-with-time-zone column in Firebird's representation.
std::optional< ScaledInt16 > getScaledInt16(unsigned index)
Reads a scaled 16-bit signed integer column.
std::optional< BlobId > getBlobId(unsigned index)
Reads a blob identifier column.
Statement(Statement &&o) noexcept
Transfers ownership of an existing prepared statement.
void setInt64(unsigned index, std::optional< std::int64_t > optValue)
Binds a 64-bit signed integer value or null.
std::optional< ScaledOpaqueInt128 > getScaledOpaqueInt128(unsigned index)
Reads a Firebird scaled 128-bit integer column.
FbRef< fb::IMessageMetadata > getOutputMetadata() noexcept
Returns the metadata describing columns produced by the statement.
void set(unsigned index, TimeTz value)
Convenience overload that binds a Firebird time with timezone value.
void setOpaqueDecFloat16(unsigned index, std::optional< OpaqueDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value in Firebird's representation or null.
void setOpaqueInt128(unsigned index, std::optional< OpaqueInt128 > optValue)
Binds a raw 128-bit integer value in Firebird's representation or null.
std::optional< OpaqueTimeTz > getOpaqueTimeTz(unsigned index)
Reads a raw time-of-day column with timezone in Firebird's representation.
void setBoostInt128(unsigned index, std::optional< BoostInt128 > optValue)
Binds a 128-bit integer value expressed with Boost.Multiprecision or null.
void set(unsigned index, Date value)
Convenience overload that binds a Firebird date value.
void set(unsigned index, Timestamp value)
Convenience overload that binds a Firebird timestamp value.
void setOpaqueTimeTz(unsigned index, std::optional< OpaqueTimeTz > optValue)
Binds a raw time-of-day value with timezone in Firebird's representation or null.
void setTimestamp(unsigned index, std::optional< Timestamp > optValue)
Binds a timestamp value without timezone or null.
std::optional< std::string > getString(unsigned index)
Reads a textual column, applying number-to-string conversions when needed.
std::optional< std::int32_t > getInt32(unsigned index)
Reads a 32-bit signed integer column.
void set(unsigned index, OpaqueDecFloat16 value)
Convenience overload that binds a Firebird 16-digit decimal floating-point value.
void setOpaqueTimestampTz(unsigned index, std::optional< OpaqueTimestampTz > optValue)
Binds a raw timestamp value with timezone in Firebird's representation or null.
FbRef< fb::IMessageMetadata > getInputMetadata() noexcept
Returns the metadata describing prepared input parameters.
~Statement() noexcept
Releases resources; ignores failures to keep destructor noexcept.
void set(unsigned index, OpaqueTimeTz value)
Convenience overload that binds a Firebird time with timezone value.
void setBoostDecFloat16(unsigned index, std::optional< BoostDecFloat16 > optValue)
Binds a 16-digit decimal floating-point value using Boost.Multiprecision or null.
std::optional< ScaledBoostInt128 > getScaledBoostInt128(unsigned index)
Reads a scaled Boost 128-bit integer column.
std::string getPlan()
Retrieves the structured textual plan if the server produced one.
void set(unsigned index, BlobId value)
Convenience overload that binds a blob identifier.
void set(unsigned index, BoostDecFloat34 value)
Convenience overload that binds a Boost 34-digit decimal floating-point value.
bool fetchNext()
Fetches the next row in the current result set.
void set(unsigned index, OpaqueDecFloat34 value)
Convenience overload that binds a Firebird 34-digit decimal floating-point value.
void set(unsigned index, Time value)
Convenience overload that binds a Firebird time value.
T get(unsigned index)
Retrieves a column using the most appropriate typed accessor specialization.
void set(unsigned index, ScaledInt16 value)
Convenience overload that binds a scaled 16-bit signed integer.
std::optional< BoostInt128 > getBoostInt128(unsigned index)
Reads a Boost 128-bit integer column.
std::optional< bool > getBool(unsigned index)
Reads a boolean column from the current row.
void setOpaqueDecFloat34(unsigned index, std::optional< OpaqueDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value in Firebird's representation or null.
void set(unsigned index, OpaqueTimestamp value)
Convenience overload that binds a Firebird timestamp value.
void setInt32(unsigned index, std::optional< std::int32_t > optValue)
Binds a 32-bit signed integer value or null.
void set(unsigned index, std::optional< BlobId > value)
Convenience overload that binds an optional blob identifier.
void setBool(unsigned index, std::optional< bool > optValue)
Binds a boolean parameter value or null.
void set(unsigned index, const V &value)
Sets a parameter from a variant value.
void set(unsigned index, TimestampTz value)
Convenience overload that binds a Firebird timestamp with timezone value.
void setDouble(unsigned index, std::optional< double > optValue)
Binds a double precision floating-point value or null.
void set(unsigned index, OpaqueDate value)
Convenience overload that binds a Firebird date value.
void set(unsigned index, std::int16_t value)
Convenience overload that binds a 16-bit signed integer.
void set(unsigned index, std::optional< T > value)
Convenience template that forwards optional values to specialized overloads.
std::optional< OpaqueTimestamp > getOpaqueTimestamp(unsigned index)
Reads a raw timestamp column in Firebird's representation.
void setScaledInt64(unsigned index, std::optional< ScaledInt64 > optValue)
Binds a scaled 64-bit signed integer value or null.
Attachment & getAttachment() noexcept
Returns the Attachment object reference used to create this Statement.
void set(unsigned index, std::nullopt_t)
Convenience overload that binds a null value.
void setFloat(unsigned index, std::optional< float > optValue)
Binds a single precision floating-point value or null.
void setOpaqueDate(unsigned index, std::optional< OpaqueDate > optValue)
Binds a raw date value in Firebird's representation or null.
bool fetchLast()
Positions the cursor on the last row.
bool execute(Transaction &transaction)
Executes a prepared statement using the supplied transaction.
void set(unsigned index, OpaqueTime value)
Convenience overload that binds a Firebird time value.
void set(unsigned index, ScaledInt32 value)
Convenience overload that binds a scaled 32-bit signed integer.
bool fetchPrior()
Fetches the previous row in the current result set.
std::optional< std::int16_t > getInt16(unsigned index)
Reads a 16-bit signed integer column.
void set(unsigned index, ScaledBoostInt128 value)
Convenience overload that binds a scaled Boost-provided 128-bit integer.
bool fetchFirst()
Positions the cursor on the first row.
std::optional< TimestampTz > getTimestampTz(unsigned index)
Reads a timestamp-with-time-zone column.
void set(unsigned index, BoostInt128 value)
Convenience overload that binds a Boost-provided 128-bit integer.
std::vector< std::byte > & getInputMessage() noexcept
Provides direct access to the raw input message buffer.
std::optional< OpaqueDecFloat16 > getOpaqueDecFloat16(unsigned index)
Reads a Firebird 16-digit decimal floating-point column.
std::optional< Timestamp > getTimestamp(unsigned index)
Reads a timestamp column without timezone.
std::optional< BoostDecFloat16 > getBoostDecFloat16(unsigned index)
Reads a Boost-based 16-digit decimal floating-point column.
void setTimeTz(unsigned index, std::optional< TimeTz > optValue)
Binds a time-of-day value with timezone or null.
void setBoostDecFloat34(unsigned index, std::optional< BoostDecFloat34 > optValue)
Binds a 34-digit decimal floating-point value using Boost.Multiprecision or null.
std::optional< ScaledInt64 > getScaledInt64(unsigned index)
Reads a scaled 64-bit signed integer column.
void set(unsigned index, bool value)
Convenience overload that binds a boolean value.
void setOpaqueTimestamp(unsigned index, std::optional< OpaqueTimestamp > optValue)
Binds a raw timestamp value in Firebird's representation or null.
void set(unsigned index, float value)
Convenience overload that binds a single precision floating-point value.
void set(const T &value)
Sets all input parameters from fields of a user-defined aggregate struct.
Represents a transaction in one or more Firebird databases.
CursorType
Selects the cursor type for a SELECT statement.
@ FORWARD_ONLY
Forward-only traversal (default, more efficient for streaming).
@ SCROLLABLE
Allows bidirectional traversal and absolute/relative positioning.
ScaledNumber< std::int64_t > ScaledInt64
Signed 64-bit scaled number.
ScaledNumber< std::int32_t > ScaledInt32
Signed 32-bit scaled number.
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 34 > > BoostDecFloat34
34-digit decimal floating point using Boost.Multiprecision.
FB_DEC16 OpaqueDecFloat16
Opaque 16-digit decimal floating point exposed by the Firebird API.
ScaledNumber< std::int16_t > ScaledInt16
Signed 16-bit scaled number.
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 16 > > BoostDecFloat16
16-digit decimal floating point using Boost.Multiprecision.
DescriptorAdjustedType
Descriptor adjusted type.
@ BLOB
Binary large object.
@ TIME
Time of day without time zone.
@ DECFLOAT34
34-digit decimal floating point.
@ INT64
64-bit signed integer.
@ TIME_TZ
Time of day with time zone.
@ DECFLOAT16
16-digit decimal floating point.
@ INT16
16-bit signed integer.
@ STRING
String type (variable-length).
@ INT32
32-bit signed integer.
@ TIMESTAMP
Timestamp without time zone.
@ TIMESTAMP_TZ
Timestamp with time zone.
@ INT128
128-bit signed integer.
@ FLOAT
Single-precision floating point.
@ DOUBLE
Double-precision floating point.
StatementType
Distinguishes the semantic category of the prepared SQL statement.
@ SAVEPOINT
Statement manages a savepoint.
@ PUT_SEGMENT
Statement writes a blob segment - legacy feature.
@ UPDATE
Server classified the statement as an UPDATE.
@ COMMIT
Statement commits a transaction.
@ ROLLBACK
Statement rolls back a transaction.
@ EXEC_PROCEDURE
Statement executes a stored procedure.
@ DELETE
Server classified the statement as a DELETE.
@ DDL
Statement performs data definition operations.
@ GET_SEGMENT
Statement reads a blob segment - legacy feature.
@ INSERT
Server classified the statement as an INSERT.
@ SELECT
Server classified the statement as a SELECT.
@ SET_GENERATOR
Statement sets a generator (sequence) value.
@ START_TRANSACTION
Statement starts a new transaction.
@ SELECT_FOR_UPDATE
Cursor-based SELECT that allows updates.
FB_I128 OpaqueInt128
Opaque 128-bit integer exposed by the Firebird API.
std::chrono::year_month_day Date
Firebird SQL calendar date.
FB_DEC34 OpaqueDecFloat34
Opaque 34-digit decimal floating point exposed by the Firebird API.
boost::multiprecision::int128_t BoostInt128
128-bit integer using Boost.Multiprecision.
ScaledNumber< BoostInt128 > ScaledBoostInt128
Scaled 128-bit integer backed by Boost.Multiprecision.
std::chrono::hh_mm_ss< std::chrono::microseconds > Time
Firebird SQL time-of-day with microsecond resolution.
Describes a parameter or column.
Wrapper for Firebird date values.
Wrapper for Firebird time-with-time-zone values.
Wrapper for Firebird time values.
Wrapper for Firebird timestamp-with-time-zone values.
Wrapper for Firebird timestamp values.
Represents a numeric value with an explicit decimal scale.
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.