fb-cpp 0.0.2
A modern C++ wrapper for the Firebird database API
Loading...
Searching...
No Matches
Exception.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 "Exception.h"
26#include "Client.h"
27#include <string>
28#include <vector>
29#include <cassert>
30
31using namespace fbcpp;
32using namespace fbcpp::impl;
33
34
35void StatusWrapper::checkException(StatusWrapper* status)
36{
37 if (status->dirty && (status->getState() & fb::IStatus::STATE_ERRORS))
38 throw DatabaseException{*status->client, status->getErrors()};
39}
40
41void StatusWrapper::catchException(fb::IStatus* status) noexcept
42{
43 assert(false);
44}
45
46
47std::string DatabaseException::buildMessage(Client& client, const std::intptr_t* statusVector)
48{
49 constexpr char DEFAULT_MESSAGE[] = "Unknown database error";
50
51 if (!statusVector)
52 return DEFAULT_MESSAGE;
53
54 const auto util = client.getUtil();
55
56 const auto status = client.newStatus();
57 status->setErrors(statusVector);
58
59 constexpr unsigned MAX_BUFFER_SIZE = 32u * 1024u;
60 unsigned bufferSize = 256u;
61 std::string message;
62
63 while (bufferSize <= MAX_BUFFER_SIZE)
64 {
65 std::string buffer(bufferSize, '\0');
66 const auto written = util->formatStatus(buffer.data(), bufferSize, status.get());
67
68 if (written < bufferSize && buffer[0] != '\0')
69 {
70 message = written == 0 ? std::string{buffer.c_str()} : std::string{buffer.data(), written};
71 break;
72 }
73
74 if (bufferSize == MAX_BUFFER_SIZE)
75 {
76 message = buffer.c_str();
77 break;
78 }
79
80 bufferSize = (bufferSize > MAX_BUFFER_SIZE / 2u) ? MAX_BUFFER_SIZE : bufferSize * 2u;
81 }
82
83 if (message.empty())
84 message = DEFAULT_MESSAGE;
85
86 return message;
87}
88
89void DatabaseException::copyErrorVector(const std::intptr_t* statusVector)
90{
91 if (!statusVector)
92 return;
93
94 const auto* p = statusVector;
95
96 while (*p != isc_arg_end)
97 {
98 const auto argType = *p++;
99
100 switch (argType)
101 {
102 case isc_arg_gds:
103 case isc_arg_number:
104 errorVector.push_back(argType);
105 errorVector.push_back(*p++);
106 break;
107
108 case isc_arg_string:
109 case isc_arg_interpreted:
110 case isc_arg_sql_state:
111 errorVector.push_back(argType);
112 errorStrings.emplace_back(reinterpret_cast<const char*>(*p++));
113 errorVector.push_back(0); // placeholder for string pointer
114 break;
115
116 case isc_arg_cstring:
117 {
118 const auto len = static_cast<size_t>(*p++);
119 const auto str = reinterpret_cast<const char*>(*p++);
120 errorVector.push_back(isc_arg_string);
121 errorStrings.emplace_back(str, len);
122 errorVector.push_back(0); // placeholder for string pointer
123 break;
124 }
125
126 default:
127 errorVector.push_back(argType);
128 errorVector.push_back(*p++);
129 break;
130 }
131 }
132
133 errorVector.push_back(isc_arg_end);
134
135 fixupStringPointers();
136}
137
138void DatabaseException::fixupStringPointers()
139{
140 size_t strIdx = 0;
141 size_t i = 0;
142
143 while (i < errorVector.size() && errorVector[i] != isc_arg_end)
144 {
145 const auto argType = errorVector[i];
146
147 if (argType == isc_arg_string || argType == isc_arg_interpreted || argType == isc_arg_sql_state)
148 errorVector[i + 1] = reinterpret_cast<std::intptr_t>(errorStrings[strIdx++].c_str());
149
150 i += 2;
151 }
152}
153
154std::string DatabaseException::extractSqlState(const std::intptr_t* statusVector)
155{
156 if (!statusVector)
157 return {};
158
159 const auto* p = statusVector;
160
161 while (*p != isc_arg_end)
162 {
163 const auto argType = *p++;
164
165 if (argType == isc_arg_sql_state)
166 return reinterpret_cast<const char*>(*p);
167
168 if (argType == isc_arg_cstring)
169 p += 2;
170 else
171 p++;
172 }
173
174 return {};
175}
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
Exception thrown when a Firebird database operation fails.
Definition Exception.h:201
const std::vector< std::intptr_t > & getErrors() const noexcept
Returns the Firebird error vector.
Definition Exception.h:231
fb-cpp namespace.
Definition Attachment.h:42