fb-cpp 0.0.2
A modern C++ wrapper for the Firebird database API
Loading...
Searching...
No Matches
Exception.h
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#ifndef FBCPP_EXCEPTION_H
26#define FBCPP_EXCEPTION_H
27
28#include "fb-api.h"
29#include "fb-cpp-export.h"
30#include <stdexcept>
31#include <string>
32#include <vector>
33#include <cstdint>
34
35
39namespace fbcpp
40{
41 class Client;
42}
43
44namespace fbcpp::impl
45{
46 class FB_CPP_EXPORT StatusWrapper : public fb::IStatusImpl<StatusWrapper, StatusWrapper>
47 {
48 public:
49 explicit StatusWrapper(Client& client, IStatus* status = nullptr)
50 : client{&client},
51 status{status}
52 {
53 }
54
55 StatusWrapper(StatusWrapper&& o) noexcept
56 : client{o.client},
57 status{o.status},
58 statusOwner{o.statusOwner},
59 dirty{o.dirty}
60 {
61 o.status = nullptr;
62 o.statusOwner = false;
63 o.dirty = false;
64 }
65
66 StatusWrapper& operator=(StatusWrapper&& o) noexcept
67 {
68 if (this != &o)
69 {
70 if (statusOwner && status)
71 status->dispose();
72
73 client = o.client;
74 status = o.status;
75 statusOwner = o.statusOwner;
76 dirty = o.dirty;
77
78 o.status = nullptr;
79 o.statusOwner = false;
80 o.dirty = false;
81 }
82
83 return *this;
84 }
85
86 StatusWrapper(const StatusWrapper&) = delete;
87 StatusWrapper& operator=(const StatusWrapper&) = delete;
88
89 ~StatusWrapper()
90 {
91 if (statusOwner && status)
92 status->dispose();
93 }
94
95 public:
96 static void checkException(StatusWrapper* status);
97
98 static void catchException(IStatus* status) noexcept;
99
100 static void clearException(StatusWrapper* status) noexcept
101 {
102 status->clearException();
103 }
104
105 void clearException()
106 {
107 if (dirty)
108 {
109 dirty = false;
110 getStatus()->init();
111 }
112 }
113
114 bool isDirty() const noexcept
115 {
116 return dirty;
117 }
118
119 bool hasData() const noexcept
120 {
121 return getState() & IStatus::STATE_ERRORS;
122 }
123
124 bool isEmpty() const noexcept
125 {
126 return !hasData();
127 }
128
129 static void setVersionError(
130 IStatus* status, const char* interfaceName, uintptr_t currentVersion, uintptr_t expectedVersion) noexcept
131 {
132 // clang-format off
133 const intptr_t codes[] = {
134 isc_arg_gds, isc_interface_version_too_old,
135 isc_arg_number, (intptr_t) expectedVersion,
136 isc_arg_number, (intptr_t) currentVersion,
137 isc_arg_string, (intptr_t) interfaceName,
138 isc_arg_end,
139 };
140 // clang-format on
141
142 status->setErrors(codes);
143 }
144
145 public:
146 void dispose() noexcept override
147 {
148 // Disposes only the delegated status. Let the user destroy this instance.
149 if (status)
150 status->dispose();
151
152 status = nullptr;
153 statusOwner = false;
154 }
155
156 void init() noexcept override
157 {
158 clearException();
159 }
160
161 unsigned getState() const noexcept override
162 {
163 return dirty ? getStatus()->getState() : 0;
164 }
165
166 void setErrors2(unsigned length, const intptr_t* value) noexcept override
167 {
168 dirty = true;
169 getStatus()->setErrors2(length, value);
170 }
171
172 void setWarnings2(unsigned length, const intptr_t* value) noexcept override
173 {
174 dirty = true;
175 getStatus()->setWarnings2(length, value);
176 }
177
178 void setErrors(const intptr_t* value) noexcept override
179 {
180 dirty = true;
181 getStatus()->setErrors(value);
182 }
183
184 void setWarnings(const intptr_t* value) noexcept override
185 {
186 dirty = true;
187 getStatus()->setWarnings(value);
188 }
189
190 const intptr_t* getErrors() const noexcept override
191 {
192 return dirty ? getStatus()->getErrors() : cleanStatus();
193 }
194
195 const intptr_t* getWarnings() const noexcept override
196 {
197 return dirty ? getStatus()->getWarnings() : cleanStatus();
198 }
199
200 IStatus* clone() const noexcept override
201 {
202 return getStatus()->clone();
203 }
204
205 protected:
206 Client* client;
207 mutable IStatus* status;
208 mutable bool statusOwner = false;
209 bool dirty = false;
210
211 IStatus* getStatus() const;
212
213 static const intptr_t* cleanStatus() noexcept
214 {
215 static intptr_t clean[3] = {1, 0, 0};
216 return clean;
217 }
218 };
219} // namespace fbcpp::impl
220
221
225namespace fbcpp
226{
230 class FB_CPP_EXPORT FbCppException : public std::runtime_error
231 {
232 public:
233 using std::runtime_error::runtime_error;
234
238 explicit FbCppException(const std::string& message)
239 : std::runtime_error{message}
240 {
241 }
242 };
243
247 class FB_CPP_EXPORT DatabaseException final : public FbCppException
248 {
249 public:
253 explicit DatabaseException(Client& client, const std::intptr_t* statusVector)
254 : FbCppException{buildMessage(client, statusVector)},
255 sqlState{extractSqlState(statusVector)}
256 {
257 copyErrorVector(statusVector);
258 }
259
261 : FbCppException{static_cast<const FbCppException&>(other)},
262 errorVector{other.errorVector},
263 errorStrings{other.errorStrings},
264 sqlState{other.sqlState}
265 {
266 fixupStringPointers();
267 }
268
269 DatabaseException(DatabaseException&&) = default;
270
271 DatabaseException& operator=(const DatabaseException&) = delete;
272 DatabaseException& operator=(DatabaseException&&) = delete;
273
278 const std::vector<std::intptr_t>& getErrors() const noexcept
279 {
280 return errorVector;
281 }
282
286 std::intptr_t getErrorCode() const noexcept
287 {
288 if (errorVector.size() >= 2 && errorVector[0] == isc_arg_gds)
289 return errorVector[1];
290 return 0;
291 }
292
297 const std::string& getSqlState() const noexcept
298 {
299 return sqlState;
300 }
301
302 private:
303 static std::string buildMessage(Client& client, const std::intptr_t* statusVector);
304 static std::string extractSqlState(const std::intptr_t* statusVector);
305
306 void copyErrorVector(const std::intptr_t* statusVector);
307 void fixupStringPointers();
308
309 private:
310 std::vector<std::intptr_t> errorVector;
311 std::vector<std::string> errorStrings;
312 std::string sqlState;
313 };
314} // namespace fbcpp
315
316
317#endif // FBCPP_EXCEPTION_H
Represents a Firebird client library instance.
Definition Client.h:54
Exception thrown when a Firebird database operation fails.
Definition Exception.h:248
const std::vector< std::intptr_t > & getErrors() const noexcept
Returns the Firebird error vector.
Definition Exception.h:278
std::intptr_t getErrorCode() const noexcept
Returns the primary ISC error code (first isc_arg_gds value), or 0 if none.
Definition Exception.h:286
DatabaseException(Client &client, const std::intptr_t *statusVector)
Constructs a DatabaseException from a Firebird status vector.
Definition Exception.h:253
const std::string & getSqlState() const noexcept
Returns the SQL state string (e.g.
Definition Exception.h:297
Base exception class for all fb-cpp exceptions.
Definition Exception.h:231
FbCppException(const std::string &message)
Constructs an FbCppException with the specified error message.
Definition Exception.h:238
fb-cpp namespace.
Definition Attachment.h:46