Skip to content

Commit d11300c

Browse files
committed
Refactor BlobOptions
1 parent a77b8ab commit d11300c

3 files changed

Lines changed: 181 additions & 39 deletions

File tree

src/lib/Blob.cpp

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,14 @@
2727
#include "Client.h"
2828
#include "Transaction.h"
2929
#include "fb-api/firebird/impl/inf_pub.h"
30+
#include <cstdint>
31+
#include <cstring>
3032
#include <limits>
33+
#include <vector>
3134

3235
using namespace fbcpp;
3336
using namespace fbcpp::impl;
3437

35-
namespace
36-
{
37-
std::pair<unsigned, const unsigned char*> getBpb(const BlobOptions& options)
38-
{
39-
const auto& bpb = options.getBpb();
40-
41-
if (bpb.size() > std::numeric_limits<unsigned>::max())
42-
throw FbCppException("BPB too large");
43-
44-
const auto length = static_cast<unsigned>(bpb.size());
45-
const auto data = bpb.empty() ? nullptr : reinterpret_cast<const unsigned char*>(bpb.data());
46-
47-
return {length, data};
48-
}
49-
} // namespace
50-
51-
5238
Blob::Blob(Attachment& attachment, Transaction& transaction, const BlobOptions& options)
5339
: attachment{attachment},
5440
transaction{transaction},
@@ -58,10 +44,10 @@ Blob::Blob(Attachment& attachment, Transaction& transaction, const BlobOptions&
5844
assert(attachment.isValid());
5945
assert(transaction.isValid());
6046

61-
const auto [bpbLength, bpbData] = getBpb(options);
47+
const auto preparedBpb = prepareBpb(options);
6248

63-
handle.reset(
64-
attachment.getHandle()->createBlob(&statusWrapper, transaction.getHandle().get(), &id.id, bpbLength, bpbData));
49+
handle.reset(attachment.getHandle()->createBlob(&statusWrapper, transaction.getHandle().get(), &id.id,
50+
static_cast<unsigned>(preparedBpb.size()), preparedBpb.data()));
6551
}
6652

6753
Blob::Blob(Attachment& attachment, Transaction& transaction, const BlobId& blobId, const BlobOptions& options)
@@ -74,18 +60,55 @@ Blob::Blob(Attachment& attachment, Transaction& transaction, const BlobId& blobI
7460
assert(attachment.isValid());
7561
assert(transaction.isValid());
7662

77-
const auto [bpbLength, bpbData] = getBpb(options);
63+
const auto preparedBpb = prepareBpb(options);
64+
65+
handle.reset(attachment.getHandle()->openBlob(&statusWrapper, transaction.getHandle().get(), &id.id,
66+
static_cast<unsigned>(preparedBpb.size()), preparedBpb.data()));
67+
}
68+
69+
std::vector<std::uint8_t> Blob::prepareBpb(const BlobOptions& options)
70+
{
71+
const auto util = attachment.getClient().getUtil();
72+
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())));
76+
77+
if (const auto type = options.getType(); type.has_value())
78+
builder->insertInt(&statusWrapper, isc_bpb_type, static_cast<int>(type.value()));
79+
80+
if (const auto sourceType = options.getSourceType(); sourceType.has_value())
81+
builder->insertInt(&statusWrapper, isc_bpb_source_type, static_cast<int>(sourceType.value()));
82+
83+
if (const auto targetType = options.getTargetType(); targetType.has_value())
84+
builder->insertInt(&statusWrapper, isc_bpb_target_type, static_cast<int>(targetType.value()));
85+
86+
if (const auto sourceCharSet = options.getSourceCharSet(); sourceCharSet.has_value())
87+
builder->insertInt(&statusWrapper, isc_bpb_source_interp, static_cast<int>(sourceCharSet.value()));
88+
89+
if (const auto targetCharSet = options.getTargetCharSet(); targetCharSet.has_value())
90+
builder->insertInt(&statusWrapper, isc_bpb_target_interp, static_cast<int>(targetCharSet.value()));
91+
92+
if (const auto storage = options.getStorage(); storage.has_value())
93+
builder->insertInt(&statusWrapper, isc_bpb_storage, static_cast<int>(storage.value()));
94+
95+
const auto buffer = builder->getBuffer(&statusWrapper);
96+
const auto length = builder->getBufferLength(&statusWrapper);
97+
98+
std::vector<std::uint8_t> bpb(length);
99+
100+
if (length != 0)
101+
std::memcpy(bpb.data(), buffer, length);
78102

79-
handle.reset(
80-
attachment.getHandle()->openBlob(&statusWrapper, transaction.getHandle().get(), &id.id, bpbLength, bpbData));
103+
return bpb;
81104
}
82105

83106
unsigned Blob::getLength()
84107
{
85108
assert(isValid());
86109

87-
const unsigned char items[] = {isc_info_blob_total_length};
88-
unsigned char buffer[16]{};
110+
const std::uint8_t items[] = {isc_info_blob_total_length};
111+
std::uint8_t buffer[16]{};
89112

90113
handle->getInfo(&statusWrapper, sizeof(items), items, sizeof(buffer), buffer);
91114

src/lib/Blob.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include "Exception.h"
3131
#include <cassert>
3232
#include <cstddef>
33+
#include <cstdint>
34+
#include <optional>
3335
#include <span>
3436
#include <utility>
3537
#include <vector>
@@ -62,6 +64,24 @@ namespace fbcpp
6264
ISC_QUAD id{0, 0};
6365
};
6466

67+
///
68+
/// Blob storage options.
69+
///
70+
enum class BlobStorage : std::uint8_t
71+
{
72+
MAIN = isc_bpb_storage_main,
73+
TEMPORARY = isc_bpb_storage_temp
74+
};
75+
76+
///
77+
/// Blob type.
78+
///
79+
enum class BlobType : std::uint8_t
80+
{
81+
SEGMENTED = isc_bpb_type_segmented,
82+
STREAM = isc_bpb_type_stream
83+
};
84+
6585
///
6686
/// Additional options used when creating or opening blobs.
6787
///
@@ -95,8 +115,116 @@ namespace fbcpp
95115
return *this;
96116
}
97117

118+
///
119+
/// Retrieves the blob type to be used for blob operations.
120+
///
121+
const std::optional<BlobType> getType() const
122+
{
123+
return type;
124+
}
125+
126+
///
127+
/// Sets the blob type to be used for blob operations.
128+
///
129+
BlobOptions& setType(BlobType value)
130+
{
131+
type = value;
132+
return *this;
133+
}
134+
135+
///
136+
/// Retrieves the source blob subtype.
137+
///
138+
const std::optional<BlobType> getSourceType() const
139+
{
140+
return sourceType;
141+
}
142+
143+
///
144+
/// Sets the source blob subtype.
145+
///
146+
BlobOptions& setSourceType(BlobType value)
147+
{
148+
sourceType = value;
149+
return *this;
150+
}
151+
152+
///
153+
/// Retrieves the target blob subtype.
154+
///
155+
const std::optional<BlobType> getTargetType() const
156+
{
157+
return targetType;
158+
}
159+
160+
///
161+
/// Sets the target blob subtype.
162+
///
163+
BlobOptions& setTargetType(BlobType value)
164+
{
165+
targetType = value;
166+
return *this;
167+
}
168+
169+
///
170+
/// Retrieves the source character set identifier.
171+
///
172+
const std::optional<std::int16_t> getSourceCharSet() const
173+
{
174+
return sourceCharSet;
175+
}
176+
177+
///
178+
/// Sets the source character set identifier.
179+
///
180+
BlobOptions& setSourceCharSet(std::int16_t value)
181+
{
182+
sourceCharSet = value;
183+
return *this;
184+
}
185+
186+
///
187+
/// Retrieves the target character set identifier.
188+
///
189+
const std::optional<std::int16_t> getTargetCharSet() const
190+
{
191+
return targetCharSet;
192+
}
193+
194+
///
195+
/// Sets the target character set identifier.
196+
///
197+
BlobOptions& setTargetCharSet(std::int16_t value)
198+
{
199+
targetCharSet = value;
200+
return *this;
201+
}
202+
203+
///
204+
/// Retrieves the blob storage mode.
205+
///
206+
const std::optional<BlobStorage> getStorage() const
207+
{
208+
return storage;
209+
}
210+
211+
///
212+
/// Sets the blob storage mode.
213+
///
214+
BlobOptions& setStorage(BlobStorage value)
215+
{
216+
storage = value;
217+
return *this;
218+
}
219+
98220
private:
99221
std::vector<std::byte> bpb;
222+
std::optional<BlobType> type;
223+
std::optional<BlobType> sourceType;
224+
std::optional<BlobType> targetType;
225+
std::optional<std::int16_t> sourceCharSet;
226+
std::optional<std::int16_t> targetCharSet;
227+
std::optional<BlobStorage> storage;
100228
};
101229

102230
///
@@ -236,6 +364,9 @@ namespace fbcpp
236364
///
237365
void close();
238366

367+
private:
368+
std::vector<std::uint8_t> prepareBpb(const BlobOptions& options);
369+
239370
private:
240371
Attachment& attachment;
241372
Transaction& transaction;

src/test/Blob.cpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,6 @@
3434
#include <vector>
3535

3636

37-
static BlobOptions makeStreamOptions()
38-
{
39-
return BlobOptions().setBpb({
40-
std::byte{isc_bpb_version1},
41-
std::byte{isc_bpb_type},
42-
std::byte{1},
43-
std::byte{isc_bpb_type_stream},
44-
});
45-
}
46-
47-
4837
BOOST_AUTO_TEST_SUITE(BlobSuite)
4938

5039
BOOST_AUTO_TEST_CASE(readWriteMultiSegment)
@@ -62,7 +51,7 @@ BOOST_AUTO_TEST_CASE(readWriteMultiSegment)
6251
transaction.commit();
6352
}
6453

65-
const auto streamOptions = makeStreamOptions();
54+
const auto streamOptions = BlobOptions().setType(BlobType::STREAM);
6655

6756
const auto multiSegmentSize =
6857
static_cast<std::size_t>(std::numeric_limits<std::uint16_t>::max()) + std::size_t{1024};
@@ -146,8 +135,7 @@ BOOST_AUTO_TEST_CASE(createWriteRead)
146135
const std::string text = "Firebird blob support!";
147136
const auto firstPartSize = text.size() / 2;
148137

149-
// FIXME: Add to BlobOptions
150-
const auto streamOptions = makeStreamOptions();
138+
const auto streamOptions = BlobOptions().setType(BlobType::STREAM);
151139

152140
BlobId blobId;
153141

0 commit comments

Comments
 (0)