26#include "Attachment.h" 
   28#include "Transaction.h" 
   29#include "fb-api/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.