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