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 status{attachment.getClient().newStatus()},
42 statusWrapper{attachment.getClient(), status.get()}
47 const auto preparedBpb = prepareBpb(options);
49 handle.reset(attachment.
getHandle()->createBlob(&statusWrapper, transaction.
getHandle().get(), &
id.id,
50 static_cast<unsigned>(preparedBpb.size()), preparedBpb.data()));
54 : attachment{attachment},
55 transaction{transaction},
57 status{attachment.getClient().newStatus()},
58 statusWrapper{attachment.getClient(), status.get()}
63 const auto preparedBpb = prepareBpb(options);
65 handle.reset(attachment.
getHandle()->openBlob(&statusWrapper, transaction.
getHandle().get(), &
id.id,
66 static_cast<unsigned>(preparedBpb.size()), preparedBpb.data()));
69std::vector<std::uint8_t> Blob::prepareBpb(
const BlobOptions& options)
73 auto builder = fbUnique(util->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::BPB,
74 reinterpret_cast<const std::uint8_t*
>(options.
getBpb().data()),
75 static_cast<unsigned>(options.
getBpb().size())));
77 if (
const auto type = options.
getType(); type.has_value())
78 builder->insertInt(&statusWrapper, isc_bpb_type,
static_cast<int>(type.value()));
80 if (
const auto sourceType = options.
getSourceType(); sourceType.has_value())
81 builder->insertInt(&statusWrapper, isc_bpb_source_type,
static_cast<int>(sourceType.value()));
83 if (
const auto targetType = options.
getTargetType(); targetType.has_value())
84 builder->insertInt(&statusWrapper, isc_bpb_target_type,
static_cast<int>(targetType.value()));
86 if (
const auto sourceCharSet = options.
getSourceCharSet(); sourceCharSet.has_value())
87 builder->insertInt(&statusWrapper, isc_bpb_source_interp,
static_cast<int>(sourceCharSet.value()));
89 if (
const auto targetCharSet = options.
getTargetCharSet(); targetCharSet.has_value())
90 builder->insertInt(&statusWrapper, isc_bpb_target_interp,
static_cast<int>(targetCharSet.value()));
92 if (
const auto storage = options.
getStorage(); storage.has_value())
93 builder->insertInt(&statusWrapper, isc_bpb_storage,
static_cast<int>(storage.value()));
95 const auto buffer = builder->getBuffer(&statusWrapper);
96 const auto length = builder->getBufferLength(&statusWrapper);
98 std::vector<std::uint8_t> bpb(length);
101 std::memcpy(bpb.data(), buffer, length);
110 const std::uint8_t items[] = {isc_info_blob_total_length};
111 std::uint8_t buffer[16]{};
113 handle->getInfo(&statusWrapper,
sizeof(items), items,
sizeof(buffer), buffer);
115 const auto* ptr = buffer;
116 const auto* end = buffer +
sizeof(buffer);
120 const auto item = *ptr++;
122 if (item == isc_info_end)
125 if (item == isc_info_truncated)
128 if (item == isc_info_error)
134 const auto itemLength =
static_cast<std::uint16_t
>((ptr[0]) | (ptr[1] << 8));
137 if (ptr + itemLength > end)
140 if (item == isc_info_blob_total_length)
144 for (std::uint16_t i = 0; i < itemLength; ++i)
145 result |=
static_cast<unsigned>(ptr[i]) << (8u * i);
160 unsigned totalRead = 0;
161 const unsigned maxChunkSize = std::numeric_limits<std::uint16_t>::max();
163 while (!buffer.empty())
165 const auto chunkSize = buffer.size() < maxChunkSize ? buffer.size() : maxChunkSize;
166 const auto chunk = buffer.first(chunkSize);
172 totalRead += readNow;
173 buffer = buffer.subspan(readNow);
186 unsigned segmentLength = 0;
188 handle->getSegment(&statusWrapper,
static_cast<unsigned>(buffer.size()), buffer.data(), &segmentLength);
192 case fb::IStatus::RESULT_OK:
193 case fb::IStatus::RESULT_SEGMENT:
194 return segmentLength;
196 case fb::IStatus::RESULT_NO_DATA:
208 const unsigned maxChunkSize = std::numeric_limits<std::uint16_t>::max();
210 while (!buffer.empty())
212 const auto chunkSize = buffer.size() < maxChunkSize ? buffer.size() : maxChunkSize;
213 const auto chunk = buffer.first(chunkSize);
215 buffer = buffer.subspan(chunkSize);
226 if (buffer.size() > std::numeric_limits<unsigned>::max())
229 handle->putSegment(&statusWrapper,
static_cast<unsigned>(buffer.size()), buffer.data());
235 return handle->seek(&statusWrapper,
static_cast<int>(mode), offset);
242 handle->cancel(&statusWrapper);
250 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.
Represents a transaction in a Firebird database.
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.