fb-cpp 0.0.2
A modern C++ wrapper for the Firebird database API
Loading...
Searching...
No Matches
Attachment.cpp
1/*
2 * MIT License
3 *
4 * Copyright (c) 2025 Adriano dos Santos Fernandes
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 "Attachment.h"
26#include "Client.h"
27#include "Exception.h"
28#include "RowSet.h"
29#include "Statement.h"
30#include "Transaction.h"
31
32using namespace fbcpp;
33using namespace fbcpp::impl;
34
35
36Attachment::Attachment(Client& client, const std::string& uri, const AttachmentOptions& options)
37 : client{&client}
38{
39 const auto master = client.getMaster();
40
41 StatusWrapper statusWrapper{client};
42
43 auto dpbBuilder = fbUnique(client.getUtil()->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::DPB,
44 reinterpret_cast<const std::uint8_t*>(options.getDpb().data()),
45 static_cast<unsigned>(options.getDpb().size())));
46
47 if (const auto connectionCharSet = options.getConnectionCharSet())
48 dpbBuilder->insertString(&statusWrapper, isc_dpb_lc_ctype, connectionCharSet->c_str());
49
50 if (const auto userName = options.getUserName())
51 dpbBuilder->insertString(&statusWrapper, isc_dpb_user_name, userName->c_str());
52
53 if (const auto password = options.getPassword())
54 dpbBuilder->insertString(&statusWrapper, isc_dpb_password, password->c_str());
55
56 if (const auto role = options.getRole())
57 dpbBuilder->insertString(&statusWrapper, isc_dpb_sql_role_name, role->c_str());
58
59 if (const auto sqlDialect = options.getSqlDialect())
60 dpbBuilder->insertInt(&statusWrapper, isc_dpb_sql_dialect, static_cast<int>(*sqlDialect));
61
62 if (const auto forcedWrites = options.getForcedWrites())
63 dpbBuilder->insertInt(&statusWrapper, isc_dpb_force_write, *forcedWrites ? 1 : 0);
64
65 auto dispatcher = fbRef(master->getDispatcher());
66 const auto dpbBuffer = dpbBuilder->getBuffer(&statusWrapper);
67 const auto dpbBufferLen = dpbBuilder->getBufferLength(&statusWrapper);
68
69 if (options.getCreateDatabase())
70 handle.reset(dispatcher->createDatabase(&statusWrapper, uri.c_str(), dpbBufferLen, dpbBuffer));
71 else
72 handle.reset(dispatcher->attachDatabase(&statusWrapper, uri.c_str(), dpbBufferLen, dpbBuffer));
73}
74
75void Attachment::disconnectOrDrop(bool drop)
76{
77 assert(isValid());
78
79 StatusWrapper statusWrapper{*client};
80
81 if (drop)
82 handle->dropDatabase(&statusWrapper);
83 else
84 handle->detach(&statusWrapper);
85
86 handle.reset();
87}
88
89
91{
92 disconnectOrDrop(false);
93}
94
96{
97 disconnectOrDrop(true);
98}
99
101{
102 assert(isValid());
103
104 StatusWrapper statusWrapper{*client};
105
106 handle->ping(&statusWrapper);
107}
108
110{
111 assert(isValid());
112
113 StatusWrapper statusWrapper{*client};
114
115 handle->execute(
116 &statusWrapper, nullptr, 0, "alter session reset", SQL_DIALECT_V6, nullptr, nullptr, nullptr, nullptr);
117}
118
119std::optional<std::string> Attachment::blobIdToString(
120 Transaction& transaction, std::optional<BlobId> blobId, const BlobOptions& options)
121{
122 if (!blobId.has_value())
123 return std::nullopt;
124
125 Blob reader{*this, transaction, blobId.value(), options};
126 const auto lengthHint = reader.getLength();
127 std::string value;
128 value.reserve(lengthHint);
129 std::vector<char> buffer(std::numeric_limits<std::uint16_t>::max());
130
131 for (;;)
132 {
133 const auto read = reader.readSegment(buffer);
134
135 if (read == 0u)
136 break;
137
138 value.append(buffer.data(), read);
139 }
140
141 reader.close();
142
143 return value;
144}
145
146std::optional<std::vector<std::byte>> Attachment::blobIdToBytes(
147 Transaction& transaction, std::optional<BlobId> blobId, const BlobOptions& options)
148{
149 if (!blobId.has_value())
150 return std::nullopt;
151
152 Blob reader{*this, transaction, blobId.value(), options};
153 const auto lengthHint = reader.getLength();
154 std::vector<std::byte> value;
155 value.reserve(lengthHint);
156 std::vector<std::byte> buffer(std::numeric_limits<std::uint16_t>::max());
157
158 for (;;)
159 {
160 const auto read = reader.readSegment(buffer);
161
162 if (read == 0u)
163 break;
164
165 value.insert(value.end(), buffer.data(), buffer.data() + read);
166 }
167
168 reader.close();
169
170 return value;
171}
172
173std::optional<BlobId> Attachment::blobIdFromString(
174 Transaction& transaction, std::optional<std::string_view> value, const BlobOptions& options)
175{
176 if (!value.has_value())
177 return std::nullopt;
178
179 Blob writer{*this, transaction, options};
180 writer.write(std::span<const char>{value->data(), value->size()});
181 writer.close();
182
183 return writer.getId();
184}
185
186std::optional<BlobId> Attachment::blobIdFromBytes(
187 Transaction& transaction, std::optional<std::span<const std::byte>> value, const BlobOptions& options)
188{
189 if (!value.has_value())
190 return std::nullopt;
191
192 Blob writer{*this, transaction, options};
193 writer.write(value.value());
194 writer.close();
195
196 return writer.getId();
197}
198
199bool Attachment::execute(Transaction& transaction, std::string_view sql, const StatementOptions& options)
200{
201 Statement statement{*this, transaction, sql, options};
202 return statement.execute(transaction);
203}
204
206 Transaction& transaction, std::string_view sql, unsigned maxRows, const StatementOptions& options)
207{
208 Statement statement{*this, transaction, sql, options};
209 return queryPreparedRowSet(statement, transaction, maxRows);
210}
211
212RowSet Attachment::queryPreparedRowSet(Statement& statement, Transaction& transaction, unsigned maxRows)
213{
214 switch (statement.getType())
215 {
218 break;
219
221 if (!statement.getOutputDescriptors().empty())
222 break;
223
224 throw FbCppException("Cannot use procedure without output columns with Attachment::queryRowSet");
225
226 default:
227 throw FbCppException("Cannot use non-query SQL with Attachment::queryRowSet");
228 }
229
230 statement.execute(transaction);
231 const auto effectiveMaxRows = statement.getType() == StatementType::EXEC_PROCEDURE ? 1u : maxRows;
232
233 return RowSet{statement, effectiveMaxRows};
234}
Represents options used when creating an Attachment object.
Definition Attachment.h:56
const std::optional< std::string > & getPassword() const
Returns the password which will be used to connect to the database.
Definition Attachment.h:95
const std::optional< std::string > & getRole() const
Returns the role which will be used to connect to the database.
Definition Attachment.h:112
const std::vector< std::uint8_t > & getDpb() const
Returns the DPB (Database Parameter Block) which will be used to connect to the database.
Definition Attachment.h:146
const std::optional< std::string > & getUserName() const
Returns the user name which will be used to connect to the database.
Definition Attachment.h:78
bool getCreateDatabase() const
Returns whether the database should be created instead of connected to.
Definition Attachment.h:172
const std::optional< std::string > & getConnectionCharSet() const
Returns the character set which will be used for the connection.
Definition Attachment.h:61
const std::optional< bool > & getForcedWrites() const
Returns whether forced writes should be enabled when creating the database.
Definition Attachment.h:189
const std::optional< std::uint32_t > & getSqlDialect() const
Returns the SQL dialect which will be used to connect to the database.
Definition Attachment.h:129
Attachment(Client &client, const std::string &uri, const AttachmentOptions &options={})
Constructs an Attachment object that connects to (or creates) the database specified by the URI using...
std::optional< std::vector< std::byte > > blobIdToBytes(Transaction &transaction, std::optional< BlobId > blobId, const BlobOptions &options={})
Reads a blob as bytes, or returns nullopt for a null identifier.
bool execute(Transaction &transaction, std::string_view sql, const StatementOptions &options={})
Prepares and executes an SQL statement using the supplied transaction.
void disconnect()
Disconnects from the database.
void ping()
Checks if the connection to the database is alive.
bool isValid() noexcept
Returns whether the Attachment object is valid.
Definition Attachment.h:280
std::optional< BlobId > blobIdFromBytes(Transaction &transaction, std::optional< std::span< const std::byte > > value, const BlobOptions &options={})
Creates a blob from bytes, or returns nullopt for a null value.
std::optional< BlobId > blobIdFromString(Transaction &transaction, std::optional< std::string_view > value, const BlobOptions &options={})
Creates a blob from a string, or returns nullopt for a null value.
void dropDatabase()
Drops the database.
std::optional< std::string > blobIdToString(Transaction &transaction, std::optional< BlobId > blobId, const BlobOptions &options={})
Reads a blob as a string, or returns nullopt for a null identifier.
void resetSession()
Resets the session state.
RowSet queryRowSet(Transaction &transaction, std::string_view sql, unsigned maxRows, const StatementOptions &options={})
Prepares and executes a query using the supplied transaction and returns up to maxRows rows.
Additional options used when creating or opening blobs.
Definition Blob.h:104
Provides read and write access to Firebird blobs.
Definition Blob.h:269
Represents a Firebird client library instance.
Definition Client.h:54
fb::IUtil * getUtil()
Returns a Firebird IUtil interface.
Definition Client.h:145
fb::IMaster * getMaster() noexcept
Returns the Firebird IMaster interface.
Definition Client.h:137
Base exception class for all fb-cpp exceptions.
Definition Exception.h:231
A disconnected buffer of rows fetched from a Statement's result set.
Definition RowSet.h:57
Represents options used when preparing a Statement.
Prepares, executes, and fetches SQL statements against a Firebird attachment.
Definition Statement.h:146
const std::vector< Descriptor > & getOutputDescriptors() noexcept
Provides cached descriptors for each output column.
Definition Statement.h:308
StatementType getType() noexcept
Returns the type classification reported by the server.
Definition Statement.h:282
bool execute(Transaction &transaction)
Executes a prepared statement using the supplied transaction.
Represents a transaction in one or more Firebird databases.
fb-cpp namespace.
Definition Array.h:43
FbRef< T > fbRef(T *arg) noexcept
Creates a reference-counted smart pointer for a Firebird object.
Definition SmartPtrs.h:229
@ EXEC_PROCEDURE
Statement executes a stored procedure.
@ SELECT
Server classified the statement as a SELECT.
@ SELECT_FOR_UPDATE
Cursor-based SELECT that allows updates.
FbUniquePtr< T > fbUnique(T *obj) noexcept
Creates a unique pointer for a Firebird disposable object.
Definition SmartPtrs.h:59