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 const auto& userBpb = options.
getBpb();
72 std::vector<std::uint8_t> bpb(userBpb.begin(), userBpb.end());
74 const auto addInt = [&](std::uint8_t tag,
int value)
77 bpb.push_back(isc_bpb_version1);
79 const auto unsignedValue =
static_cast<unsigned>(value);
84 for (
unsigned shift = 0u; shift < 32u; shift += 8u)
85 bpb.push_back(
static_cast<std::uint8_t
>((unsignedValue >> shift) & 0xFFu));
88 if (
const auto type = options.
getType(); type.has_value())
89 addInt(isc_bpb_type,
static_cast<int>(type.value()));
91 if (
const auto sourceType = options.
getSourceType(); sourceType.has_value())
92 addInt(isc_bpb_source_type,
static_cast<int>(sourceType.value()));
94 if (
const auto targetType = options.
getTargetType(); targetType.has_value())
95 addInt(isc_bpb_target_type,
static_cast<int>(targetType.value()));
97 if (
const auto sourceCharSet = options.
getSourceCharSet(); sourceCharSet.has_value())
98 addInt(isc_bpb_source_interp,
static_cast<int>(sourceCharSet.value()));
100 if (
const auto targetCharSet = options.
getTargetCharSet(); targetCharSet.has_value())
101 addInt(isc_bpb_target_interp,
static_cast<int>(targetCharSet.value()));
103 if (
const auto storage = options.
getStorage(); storage.has_value())
104 addInt(isc_bpb_storage,
static_cast<int>(storage.value()));
113 const std::uint8_t items[] = {isc_info_blob_total_length};
114 std::uint8_t buffer[16]{};
116 handle->getInfo(&statusWrapper,
sizeof(items), items,
sizeof(buffer), buffer);
118 const auto* ptr = buffer;
119 const auto* end = buffer +
sizeof(buffer);
123 const auto item = *ptr++;
125 if (item == isc_info_end)
128 if (item == isc_info_truncated)
131 if (item == isc_info_error)
137 const auto itemLength =
static_cast<std::uint16_t
>((ptr[0]) | (ptr[1] << 8));
140 if (ptr + itemLength > end)
143 if (item == isc_info_blob_total_length)
147 for (std::uint16_t i = 0; i < itemLength; ++i)
148 result |=
static_cast<unsigned>(ptr[i]) << (8u * i);
163 unsigned totalRead = 0;
164 const unsigned maxChunkSize = std::numeric_limits<std::uint16_t>::max();
166 while (!buffer.empty())
168 const auto chunkSize = buffer.size() < maxChunkSize ? buffer.size() : maxChunkSize;
169 const auto chunk = buffer.first(chunkSize);
175 totalRead += readNow;
176 buffer = buffer.subspan(readNow);
189 unsigned segmentLength = 0;
191 handle->getSegment(&statusWrapper,
static_cast<unsigned>(buffer.size()), buffer.data(), &segmentLength);
195 case fb::IStatus::RESULT_OK:
196 case fb::IStatus::RESULT_SEGMENT:
197 return segmentLength;
199 case fb::IStatus::RESULT_NO_DATA:
211 const unsigned maxChunkSize = std::numeric_limits<std::uint16_t>::max();
213 while (!buffer.empty())
215 const auto chunkSize = buffer.size() < maxChunkSize ? buffer.size() : maxChunkSize;
216 const auto chunk = buffer.first(chunkSize);
218 buffer = buffer.subspan(chunkSize);
229 if (buffer.size() > std::numeric_limits<unsigned>::max())
232 handle->putSegment(&statusWrapper,
static_cast<unsigned>(buffer.size()), buffer.data());
238 return handle->seek(&statusWrapper,
static_cast<int>(mode), offset);
245 handle->cancel(&statusWrapper);
253 handle->close(&statusWrapper);
Represents a connection to a Firebird database.
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.
Base exception class for all fb-cpp exceptions.
T * release() noexcept
Relinquishes ownership of the pointer without releasing it and returns it.
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.