26#include "Attachment.h"
28#include "Transaction.h"
29#include "firebird/impl/blr.h"
37using namespace fbcpp::impl;
44 case DescriptorOriginalType::TEXT:
47 case DescriptorOriginalType::VARYING:
50 case DescriptorOriginalType::SHORT:
53 case DescriptorOriginalType::LONG:
56 case DescriptorOriginalType::FLOAT:
59 case DescriptorOriginalType::DOUBLE:
62 case DescriptorOriginalType::TIMESTAMP:
65 case DescriptorOriginalType::TIME:
68 case DescriptorOriginalType::DATE:
71 case DescriptorOriginalType::INT64:
74 case DescriptorOriginalType::TIMESTAMP_TZ:
75 return blr_timestamp_tz;
77 case DescriptorOriginalType::TIMESTAMP_TZ_EX:
78 return blr_ex_timestamp_tz;
80 case DescriptorOriginalType::TIME_TZ:
81 return blr_sql_time_tz;
83 case DescriptorOriginalType::TIME_TZ_EX:
84 return blr_ex_time_tz;
86 case DescriptorOriginalType::INT128:
89 case DescriptorOriginalType::DEC16:
92 case DescriptorOriginalType::DEC34:
95 case DescriptorOriginalType::BOOLEAN:
105 : attachment{attachment},
106 transaction{transaction},
107 descriptor{std::move(descriptor)},
112 buildIscDescriptor();
119 for (
const auto& bound : descriptor.
bounds)
121 const auto length =
static_cast<unsigned>(bound.upper) -
static_cast<unsigned>(bound.lower) + 1u;
123 if (result > std::numeric_limits<std::size_t>::max() / length)
134 validateBuffer(buffer.size());
136 std::array<ISC_UCHAR, 1024> sdl{};
137 ISC_SHORT sdlBufferLength =
static_cast<ISC_SHORT
>(sdl.size());
138 ISC_SHORT sdlLength = 0;
139 const auto iscDescriptor = buildIscDescriptor();
140 std::array<ISC_STATUS, 20> statusVector{};
142 isc_array_gen_sdl(statusVector.data(), &iscDescriptor, &sdlBufferLength, sdl.data(), &sdlLength);
145 throw FbCppException(
"Cannot generate Firebird array SDL: " + std::to_string(status));
147 StatusWrapper statusWrapper{attachment.
getClient()};
148 const auto result = attachment.
getHandle()->getSlice(&statusWrapper, transaction.
getHandle().get(), &
id.id,
149 static_cast<unsigned>(sdlLength), sdl.data(), 0,
nullptr,
static_cast<int>(buffer.size()),
150 reinterpret_cast<unsigned char*
>(buffer.data()));
152 return static_cast<unsigned>(result);
157 validateBuffer(buffer.size());
159 std::array<ISC_UCHAR, 1024> sdl{};
160 ISC_SHORT sdlBufferLength =
static_cast<ISC_SHORT
>(sdl.size());
161 ISC_SHORT sdlLength = 0;
162 const auto iscDescriptor = buildIscDescriptor();
163 std::array<ISC_STATUS, 20> statusVector{};
165 isc_array_gen_sdl(statusVector.data(), &iscDescriptor, &sdlBufferLength, sdl.data(), &sdlLength);
168 throw FbCppException(
"Cannot generate Firebird array SDL: " + std::to_string(status));
170 StatusWrapper statusWrapper{attachment.
getClient()};
171 attachment.
getHandle()->putSlice(&statusWrapper, transaction.
getHandle().get(), &
id.id,
172 static_cast<unsigned>(sdlLength), sdl.data(), 0,
nullptr,
static_cast<int>(buffer.size()),
173 reinterpret_cast<unsigned char*
>(
const_cast<std::byte*
>(buffer.data())));
176void Array::validateBuffer(std::size_t size)
const
179 throw FbCppException(
"Firebird array buffer size does not match the complete slice length");
182ISC_ARRAY_DESC Array::buildIscDescriptor()
const
184 if (descriptor.
bounds.empty() || descriptor.
bounds.size() > 16u)
185 throw FbCppException(
"Firebird arrays must have between 1 and 16 dimensions");
190 if (descriptor.
scale < std::numeric_limits<ISC_SCHAR>::min() ||
191 descriptor.
scale > std::numeric_limits<ISC_SCHAR>::max())
196 ISC_ARRAY_DESC result{};
198 if (descriptor.
relation.size() >=
sizeof(result.array_desc_relation_name) ||
199 descriptor.
field.size() >=
sizeof(result.array_desc_field_name))
201 throw FbCppException(
"Firebird array relation or field name is too long");
204 std::memcpy(result.array_desc_relation_name, descriptor.
relation.data(), descriptor.
relation.size());
205 std::memcpy(result.array_desc_field_name, descriptor.
field.data(), descriptor.
field.size());
206 result.array_desc_dtype = arrayElementType(descriptor.
elementType);
207 result.array_desc_scale =
static_cast<ISC_SCHAR
>(descriptor.
scale);
208 result.array_desc_length =
static_cast<unsigned short>(descriptor.
elementLength);
209 result.array_desc_dimensions =
static_cast<short>(descriptor.
bounds.size());
211 for (std::size_t index = 0; index < descriptor.
bounds.size(); ++index)
213 const auto& bound = descriptor.
bounds[index];
215 if (bound.lower > bound.upper)
216 throw FbCppException(
"Firebird array lower bound exceeds upper bound");
218 result.array_desc_bounds[index] = {bound.lower, bound.upper};
Represents a Firebird array identifier.
Array(Attachment &attachment, Transaction &transaction, ArrayDescriptor descriptor, ArrayId id={})
Creates an array helper for a new array or an existing array identifier.
std::size_t getSliceLength() const
Returns the exact number of bytes in a complete array slice.
unsigned read(std::span< std::byte > buffer)
Reads the complete array slice into Firebird-format bytes.
void write(std::span< const std::byte > buffer)
Writes the complete array slice from Firebird-format bytes.
Represents a connection to a Firebird database.
Client & getClient() noexcept
Returns the Client object reference used to create this Attachment object.
FbRef< fb::IAttachment > getHandle() noexcept
Returns the internal Firebird IAttachment handle.
bool isValid() noexcept
Returns whether the Attachment object is valid.
Base exception class for all fb-cpp exceptions.
Represents a transaction in one or more Firebird databases.
bool isValid() noexcept
Returns whether the Transaction object is valid.
FbRef< fb::ITransaction > getHandle() noexcept
Returns the internal Firebird ITransaction handle.
DescriptorOriginalType
Descriptor original type.
Defines the element representation and bounds of a Firebird array.
std::string field
Array field name; required when creating a new array.
int scale
Decimal scale of each array element.
DescriptorOriginalType elementType
SQL type of each array element.
unsigned elementLength
Size in bytes of each array element in Firebird's wire representation.
std::vector< ArrayBound > bounds
Inclusive bounds for each dimension, from outermost to innermost.
std::string relation
Relation containing this array field; required when creating a new array.