fb-cpp 0.0.2
A modern C++ wrapper for the Firebird database API
Loading...
Searching...
No Matches
Batch.cpp
1/*
2 * MIT License
3 *
4 * Copyright (c) 2026 F.D.Castel
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include "Batch.h"
26#include "Attachment.h"
27#include "Client.h"
28#include "Statement.h"
29#include "Transaction.h"
30
31using namespace fbcpp;
32using namespace fbcpp::impl;
33
34
35// --- BatchCompletionState ---
36
38 : client{&client},
39 statusWrapper{client},
40 handle{std::move(handle)}
41{
42}
43
45 : client{o.client},
46 statusWrapper{std::move(o.statusWrapper)},
47 handle{std::move(o.handle)}
48{
49}
50
52{
53 return handle->getSize(&statusWrapper);
54}
55
57{
58 return handle->getState(&statusWrapper, pos);
59}
60
61std::optional<unsigned> BatchCompletionState::findError(unsigned pos)
62{
63 const auto result = handle->findError(&statusWrapper, pos);
64
65 if (result == fb::IBatchCompletionState::NO_MORE_ERRORS)
66 return std::nullopt;
67
68 return result;
69}
70
71std::vector<std::intptr_t> BatchCompletionState::getStatus(unsigned pos)
72{
73 auto tempStatus = client->newStatus();
74
75 handle->getStatus(&statusWrapper, tempStatus.get(), pos);
76
77 std::vector<std::intptr_t> result;
78 const auto* errors = tempStatus->getErrors();
79
80 if (errors)
81 {
82 const auto* p = errors;
83
84 while (*p != isc_arg_end)
85 {
86 result.push_back(*p++);
87 result.push_back(*p++);
88 }
89
90 result.push_back(isc_arg_end);
91 }
92
93 return result;
94}
95
96
97// --- Batch ---
98
99Batch::Batch(Statement& statement, Transaction& transaction, const BatchOptions& options)
100 : client{&statement.getAttachment().getClient()},
101 transaction{&transaction},
102 statement{&statement},
103 statusWrapper{*client}
104{
105 assert(statement.isValid());
106 assert(transaction.isValid());
107
108 const auto parBlock = buildParametersBlock(options);
109
110 handle.reset(statement.getStatementHandle()->createBatch(
111 &statusWrapper, statement.getInputMetadata().get(), static_cast<unsigned>(parBlock.size()), parBlock.data()));
112}
113
114Batch::Batch(Attachment& attachment, Transaction& transaction, std::string_view sql, unsigned dialect,
115 const BatchOptions& options)
116 : client{&attachment.getClient()},
117 transaction{&transaction},
118 statusWrapper{*client}
119{
120 assert(attachment.isValid());
121 assert(transaction.isValid());
122
123 const auto parBlock = buildParametersBlock(options);
124
125 handle.reset(attachment.getHandle()->createBatch(&statusWrapper, transaction.getHandle().get(),
126 static_cast<unsigned>(sql.length()), sql.data(), dialect, nullptr, static_cast<unsigned>(parBlock.size()),
127 parBlock.data()));
128}
129
130Batch::Batch(Batch&& o) noexcept
131 : client{o.client},
132 transaction{o.transaction},
133 statement{o.statement},
134 statusWrapper{std::move(o.statusWrapper)},
135 handle{std::move(o.handle)}
136{
137}
138
139
140// --- Adding messages ---
141
142void Batch::add(unsigned count, const void* inBuffer)
143{
144 assert(isValid());
145 handle->add(&statusWrapper, count, inBuffer);
146}
147
149{
150 assert(isValid());
151 assert(statement);
152 handle->add(&statusWrapper, 1, statement->getInputMessage().data());
153}
154
155
156// --- Blob support ---
157
158BlobId Batch::addBlob(std::span<const std::byte> data, const BlobOptions& bpb)
159{
160 assert(isValid());
161
162 const auto preparedBpb = prepareBpb(bpb);
163
164 BlobId blobId;
165 handle->addBlob(&statusWrapper, static_cast<unsigned>(data.size()), data.data(), &blobId.id,
166 static_cast<unsigned>(preparedBpb.size()), preparedBpb.data());
167
168 return blobId;
169}
170
171void Batch::appendBlobData(std::span<const std::byte> data)
172{
173 assert(isValid());
174 handle->appendBlobData(&statusWrapper, static_cast<unsigned>(data.size()), data.data());
175}
176
177void Batch::addBlobStream(std::span<const std::byte> data)
178{
179 assert(isValid());
180 handle->addBlobStream(&statusWrapper, static_cast<unsigned>(data.size()), data.data());
181}
182
184{
185 assert(isValid());
186
187 BlobId batchId;
188 handle->registerBlob(&statusWrapper, &existingBlob.id, &batchId.id);
189
190 return batchId;
191}
192
194{
195 assert(isValid());
196
197 const auto preparedBpb = prepareBpb(bpb);
198 handle->setDefaultBpb(&statusWrapper, static_cast<unsigned>(preparedBpb.size()), preparedBpb.data());
199}
200
202{
203 assert(isValid());
204 return handle->getBlobAlignment(&statusWrapper);
205}
206
207
208// --- Execution ---
209
211{
212 assert(isValid());
213
214 auto completionState = fbUnique(handle->execute(&statusWrapper, transaction->getHandle().get()));
215
216 return BatchCompletionState{*client, std::move(completionState)};
217}
218
220{
221 assert(isValid());
222 handle->cancel(&statusWrapper);
223 handle.reset();
224}
225
227{
228 assert(isValid());
229 handle->close(&statusWrapper);
230 handle.reset();
231}
232
234{
235 assert(isValid());
236
238 metadata.reset(handle->getMetadata(&statusWrapper));
239
240 return metadata;
241}
242
243const std::vector<Descriptor>& Batch::getInputDescriptors()
244{
245 assert(isValid());
246
247 if (inputDescriptors.empty())
248 buildInputDescriptors();
249
250 return inputDescriptors;
251}
252
253
254// --- Internal helpers ---
255
256std::vector<std::uint8_t> Batch::buildParametersBlock(const BatchOptions& options)
257{
258 auto builder = fbUnique(client->getUtil()->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::BATCH, nullptr, 0));
259
260 if (options.getMultiError())
261 builder->insertInt(&statusWrapper, fb::IBatch::TAG_MULTIERROR, 1);
262
263 if (options.getRecordCounts())
264 builder->insertInt(&statusWrapper, fb::IBatch::TAG_RECORD_COUNTS, 1);
265
266 if (const auto bufferSize = options.getBufferBytesSize(); bufferSize.has_value())
267 builder->insertInt(&statusWrapper, fb::IBatch::TAG_BUFFER_BYTES_SIZE, static_cast<int>(bufferSize.value()));
268
269 if (options.getBlobPolicy() != BlobPolicy::NONE)
270 builder->insertInt(&statusWrapper, fb::IBatch::TAG_BLOB_POLICY, static_cast<int>(options.getBlobPolicy()));
271
272 if (options.getDetailedErrors() != 64)
273 {
274 builder->insertInt(
275 &statusWrapper, fb::IBatch::TAG_DETAILED_ERRORS, static_cast<int>(options.getDetailedErrors()));
276 }
277
278 const auto buffer = builder->getBuffer(&statusWrapper);
279 const auto length = builder->getBufferLength(&statusWrapper);
280
281 return {buffer, buffer + length};
282}
283
284std::vector<std::uint8_t> Batch::prepareBpb(const BlobOptions& bpb)
285{
286 auto builder = fbUnique(client->getUtil()->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::BPB,
287 reinterpret_cast<const std::uint8_t*>(bpb.getBpb().data()), static_cast<unsigned>(bpb.getBpb().size())));
288
289 if (const auto type = bpb.getType(); type.has_value())
290 builder->insertInt(&statusWrapper, isc_bpb_type, static_cast<int>(type.value()));
291
292 if (const auto storage = bpb.getStorage(); storage.has_value())
293 builder->insertInt(&statusWrapper, isc_bpb_storage, static_cast<int>(storage.value()));
294
295 const auto buffer = builder->getBuffer(&statusWrapper);
296 const auto length = builder->getBufferLength(&statusWrapper);
297
298 return {buffer, buffer + length};
299}
300
301void Batch::buildInputDescriptors()
302{
303 auto metadata = getInputMetadata();
304 const auto count = metadata->getCount(&statusWrapper);
305
306 inputDescriptors.reserve(count);
307
308 for (unsigned index = 0u; index < count; ++index)
309 {
310 inputDescriptors.push_back(Descriptor{
311 .originalType = static_cast<DescriptorOriginalType>(metadata->getType(&statusWrapper, index)),
312 .adjustedType = static_cast<DescriptorAdjustedType>(metadata->getType(&statusWrapper, index)),
313 .scale = metadata->getScale(&statusWrapper, index),
314 .length = metadata->getLength(&statusWrapper, index),
315 .offset = metadata->getOffset(&statusWrapper, index),
316 .nullOffset = metadata->getNullOffset(&statusWrapper, index),
317 .isNullable = static_cast<bool>(metadata->isNullable(&statusWrapper, index)),
318 .name = metadata->getField(&statusWrapper, index),
319 .relation = metadata->getRelation(&statusWrapper, index),
320 .alias = metadata->getAlias(&statusWrapper, index),
321 .owner = metadata->getOwner(&statusWrapper, index),
322 .charSetId = metadata->getCharSet(&statusWrapper, index),
323 .subType = metadata->getSubType(&statusWrapper, index),
324 });
325 }
326}
Represents a connection to a Firebird database.
Definition Attachment.h:213
FbRef< fb::IAttachment > getHandle() noexcept
Returns the internal Firebird IAttachment handle.
Definition Attachment.h:289
bool isValid() noexcept
Returns whether the Attachment object is valid.
Definition Attachment.h:273
Wraps IBatchCompletionState to provide RAII-safe access to batch execution results.
Definition Batch.h:186
std::optional< unsigned > findError(unsigned pos)
Finds the next error at or after the given position.
Definition Batch.cpp:61
int getState(unsigned pos)
Returns the per-message result at the given position.
Definition Batch.cpp:56
std::vector< std::intptr_t > getStatus(unsigned pos)
Returns the detailed error status vector for the given position.
Definition Batch.cpp:71
BatchCompletionState(Client &client, FbUniquePtr< fb::IBatchCompletionState > handle) noexcept
Constructs a BatchCompletionState from a Firebird completion state handle.
Definition Batch.cpp:37
unsigned getSize()
Returns the number of messages processed.
Definition Batch.cpp:51
Configuration options for creating a Batch.
Definition Batch.h:85
std::optional< unsigned > getBufferBytesSize() const
Returns the batch buffer size in bytes, or nullopt for the server default.
Definition Batch.h:124
bool getRecordCounts() const
Returns whether per-message affected row counts are reported.
Definition Batch.h:107
unsigned getDetailedErrors() const
Returns the maximum number of detailed error statuses to collect.
Definition Batch.h:158
BlobPolicy getBlobPolicy() const
Returns the blob handling policy.
Definition Batch.h:141
bool getMultiError() const
Returns whether multiple errors are collected per execution.
Definition Batch.h:90
Wraps the Firebird IBatch interface for bulk DML operations.
Definition Batch.h:274
void close()
Closes the batch handle and releases resources.
Definition Batch.cpp:226
void addBlobStream(std::span< const std::byte > data)
Adds blob data in stream mode (BlobPolicy::STREAM only).
Definition Batch.cpp:177
bool isValid() const noexcept
Returns whether the batch handle is valid.
Definition Batch.h:331
void appendBlobData(std::span< const std::byte > data)
Appends more data to the last blob added with addBlob().
Definition Batch.cpp:171
void addMessage()
Adds the Statement's current input-message buffer as one message.
Definition Batch.cpp:148
void add(unsigned count, const void *inBuffer)
Adds one or more raw messages to the batch buffer.
Definition Batch.cpp:142
const std::vector< Descriptor > & getInputDescriptors()
Returns cached input parameter descriptors for this batch.
Definition Batch.cpp:243
FbRef< fb::IMessageMetadata > getInputMetadata()
Returns the input metadata for this batch.
Definition Batch.cpp:233
BlobId registerBlob(const BlobId &existingBlob)
Registers an existing blob (created via the normal Blob class) for use in the batch,...
Definition Batch.cpp:183
void setDefaultBpb(const BlobOptions &bpb)
Sets the default BPB (Blob Parameter Block) for blobs in this batch.
Definition Batch.cpp:193
BlobId addBlob(std::span< const std::byte > data, const BlobOptions &bpb={})
Adds an inline blob and returns its batch-local ID.
Definition Batch.cpp:158
BatchCompletionState execute()
Executes all queued messages and returns the completion state.
Definition Batch.cpp:210
Batch(Statement &statement, Transaction &transaction, const BatchOptions &options={})
Creates a Batch from a prepared Statement.
Definition Batch.cpp:99
void cancel()
Cancels the batch, discarding all queued messages.
Definition Batch.cpp:219
unsigned getBlobAlignment()
Returns the blob alignment requirement for this batch.
Definition Batch.cpp:201
Represents a Firebird blob identifier.
Definition Blob.h:52
ISC_QUAD id
Stores the raw Firebird blob identifier value.
Definition Blob.h:64
Additional options used when creating or opening blobs.
Definition Blob.h:103
const std::optional< BlobType > getType() const
Retrieves the blob type to be used for blob operations.
Definition Blob.h:134
const std::optional< BlobStorage > getStorage() const
Retrieves the blob storage mode.
Definition Blob.h:219
const std::vector< std::uint8_t > & getBpb() const noexcept
Retrieves the blob parameter block (BPB) used during blob operations.
Definition Blob.h:108
Represents a Firebird client library instance.
Definition Client.h:53
fb::IUtil * getUtil()
Returns a Firebird IUtil interface.
Definition Client.h:144
FbUniquePtr< fb::IStatus > newStatus()
Creates and returns a Firebird IStatus instance.
Definition Client.h:199
Reference-counted smart pointer for Firebird objects using addRef/release semantics.
Definition SmartPtrs.h:70
Prepares, executes, and fetches SQL statements against a Firebird attachment.
Definition Statement.h:262
bool isValid() noexcept
Returns whether the Statement object is valid.
Definition Statement.h:368
FbRef< fb::IStatement > getStatementHandle() noexcept
Provides direct access to the underlying Firebird statement handle.
Definition Statement.h:377
FbRef< fb::IMessageMetadata > getInputMetadata() noexcept
Returns the metadata describing prepared input parameters.
Definition Statement.h:394
std::vector< std::byte > & getInputMessage() noexcept
Provides direct access to the raw input message buffer.
Definition Statement.h:402
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.
fb-cpp namespace.
Definition Attachment.h:42
DescriptorAdjustedType
Descriptor adjusted type.
Definition Descriptor.h:147
DescriptorOriginalType
Descriptor original type.
Definition Descriptor.h:41
FbUniquePtr< T > fbUnique(T *obj) noexcept
Creates a unique pointer for a Firebird disposable object.
Definition SmartPtrs.h:59
@ NONE
Blobs are not allowed in the batch.
std::unique_ptr< T, impl::FbDisposeDeleter > FbUniquePtr
Unique pointer type for Firebird disposable objects.
Definition SmartPtrs.h:53
Describes a parameter or column.
Definition Descriptor.h:248
DescriptorOriginalType originalType
Original SQL type as reported by Firebird.
Definition Descriptor.h:252