26#include "Attachment.h"
28#include "Transaction.h"
29#include "firebird/impl/inf_pub.h"
36using namespace fbcpp::impl;
39 : attachment{attachment},
40 transaction{transaction},
41 statusWrapper{attachment.getClient()}
46 const auto preparedBpb = prepareBpb(options);
48 handle.reset(attachment.
getHandle()->createBlob(&statusWrapper, transaction.
getHandle().get(), &
id.id,
49 static_cast<unsigned>(preparedBpb.size()), preparedBpb.data()));
53 : attachment{attachment},
54 transaction{transaction},
56 statusWrapper{attachment.getClient()}
61 const auto preparedBpb = prepareBpb(options);
63 handle.reset(attachment.
getHandle()->openBlob(&statusWrapper, transaction.
getHandle().get(), &
id.id,
64 static_cast<unsigned>(preparedBpb.size()), preparedBpb.data()));
67std::vector<std::uint8_t> Blob::prepareBpb(
const BlobOptions& options)
71 auto builder =
fbUnique(util->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::BPB,
72 reinterpret_cast<const std::uint8_t*
>(options.
getBpb().data()),
73 static_cast<unsigned>(options.
getBpb().size())));
75 if (
const auto type = options.
getType(); type.has_value())
76 builder->insertInt(&statusWrapper, isc_bpb_type,
static_cast<int>(type.value()));
78 if (
const auto sourceType = options.
getSourceType(); sourceType.has_value())
79 builder->insertInt(&statusWrapper, isc_bpb_source_type,
static_cast<int>(sourceType.value()));
81 if (
const auto targetType = options.
getTargetType(); targetType.has_value())
82 builder->insertInt(&statusWrapper, isc_bpb_target_type,
static_cast<int>(targetType.value()));
84 if (
const auto sourceCharSet = options.
getSourceCharSet(); sourceCharSet.has_value())
85 builder->insertInt(&statusWrapper, isc_bpb_source_interp,
static_cast<int>(sourceCharSet.value()));
87 if (
const auto targetCharSet = options.
getTargetCharSet(); targetCharSet.has_value())
88 builder->insertInt(&statusWrapper, isc_bpb_target_interp,
static_cast<int>(targetCharSet.value()));
90 if (
const auto storage = options.
getStorage(); storage.has_value())
91 builder->insertInt(&statusWrapper, isc_bpb_storage,
static_cast<int>(storage.value()));
93 const auto buffer = builder->getBuffer(&statusWrapper);
94 const auto length = builder->getBufferLength(&statusWrapper);
96 std::vector<std::uint8_t> bpb(length);
99 std::memcpy(bpb.data(), buffer, length);
108 const std::uint8_t items[] = {isc_info_blob_total_length};
109 std::uint8_t buffer[16]{};
111 handle->getInfo(&statusWrapper,
sizeof(items), items,
sizeof(buffer), buffer);
113 const auto* ptr = buffer;
114 const auto* end = buffer +
sizeof(buffer);
118 const auto item = *ptr++;
120 if (item == isc_info_end)
123 if (item == isc_info_truncated)
126 if (item == isc_info_error)
132 const auto itemLength =
static_cast<std::uint16_t
>((ptr[0]) | (ptr[1] << 8));
135 if (ptr + itemLength > end)
138 if (item == isc_info_blob_total_length)
142 for (std::uint16_t i = 0; i < itemLength; ++i)
143 result |=
static_cast<unsigned>(ptr[i]) << (8u * i);
158 unsigned totalRead = 0;
159 const unsigned maxChunkSize = std::numeric_limits<std::uint16_t>::max();
161 while (!buffer.empty())
163 const auto chunkSize = buffer.size() < maxChunkSize ? buffer.size() : maxChunkSize;
164 const auto chunk = buffer.first(chunkSize);
170 totalRead += readNow;
171 buffer = buffer.subspan(readNow);
184 unsigned segmentLength = 0;
186 handle->getSegment(&statusWrapper,
static_cast<unsigned>(buffer.size()), buffer.data(), &segmentLength);
190 case fb::IStatus::RESULT_OK:
191 case fb::IStatus::RESULT_SEGMENT:
192 return segmentLength;
194 case fb::IStatus::RESULT_NO_DATA:
206 const unsigned maxChunkSize = std::numeric_limits<std::uint16_t>::max();
208 while (!buffer.empty())
210 const auto chunkSize = buffer.size() < maxChunkSize ? buffer.size() : maxChunkSize;
211 const auto chunk = buffer.first(chunkSize);
213 buffer = buffer.subspan(chunkSize);
224 if (buffer.size() > std::numeric_limits<unsigned>::max())
227 handle->putSegment(&statusWrapper,
static_cast<unsigned>(buffer.size()), buffer.data());
233 return handle->seek(&statusWrapper,
static_cast<int>(mode), offset);
240 handle->cancel(&statusWrapper);
248 handle->close(&statusWrapper);
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.
Represents a Firebird blob identifier.
Additional options used when creating or opening blobs.
const std::optional< BlobType > getSourceType() const
Retrieves the source blob subtype.
const std::optional< BlobType > getType() const
Retrieves the blob type to be used for blob operations.
const std::optional< BlobType > getTargetType() const
Retrieves the target blob subtype.
const std::optional< BlobStorage > getStorage() const
Retrieves the blob storage mode.
const std::vector< std::uint8_t > & getBpb() const noexcept
Retrieves the blob parameter block (BPB) used during blob operations.
const std::optional< std::int16_t > getTargetCharSet() const
Retrieves the target character set identifier.
const std::optional< std::int16_t > getSourceCharSet() const
Retrieves the source character set identifier.
bool isValid() const noexcept
Returns whether the blob handle is valid.
unsigned read(std::span< std::byte > buffer)
Reads data from the blob into the provided buffer.
unsigned getLength()
Retrieves the length of the blob in bytes.
void cancel()
Cancels any changes performed on the blob and releases the handle.
void write(std::span< const std::byte > buffer)
Writes data from the buffer into the blob.
int seek(BlobSeekMode mode, int offset)
Repositions the blob read/write cursor.
unsigned readSegment(std::span< std::byte > buffer)
Reads a single segment from the blob into the provided buffer.
Blob(Attachment &attachment, Transaction &transaction, const BlobOptions &options={})
Creates and opens a new blob for writing.
void writeSegment(std::span< const std::byte > buffer)
Writes a single segment from the buffer into the blob.
void close()
Closes the blob and finalizes any pending changes.
fb::IUtil * getUtil()
Returns a Firebird IUtil interface.
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.
BlobSeekMode
Defines the origin used when repositioning a blob.
FbUniquePtr< T > fbUnique(T *obj) noexcept
Creates a unique pointer for a Firebird disposable object.