Skip to content

Commit eb61a4e

Browse files
committed
Merge branch 'firebird-errors'
Improve Firebird errors generation too. See #1242.
2 parents 93ddffb + ac622e4 commit eb61a4e

File tree

4 files changed

+93
-27
lines changed

4 files changed

+93
-27
lines changed

include/soci/firebird/soci-firebird.h

+2-13
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,16 @@
3030
namespace soci
3131
{
3232

33-
std::size_t const stat_size = 20;
34-
35-
// size of buffer for error messages. All examples use this value.
36-
// Anyone knows, where it is stated that 512 bytes is enough ?
37-
std::size_t const SOCI_FIREBIRD_ERRMSG = 512;
38-
3933
class SOCI_FIREBIRD_DECL firebird_soci_error : public soci_error
4034
{
4135
public:
4236
firebird_soci_error(std::string const & msg,
4337
ISC_STATUS const * status = 0);
4438

45-
~firebird_soci_error() noexcept override {};
39+
error_category get_error_category() const override;
4640

4741
std::string get_backend_name() const override { return "firebird"; }
48-
int get_backend_error_code() const override
49-
{
50-
// We can't return the full vector using this generic interface, so
51-
// return just the first status.
52-
return status_.empty() ? 0 : status_[0];
53-
}
42+
int get_backend_error_code() const override;
5443

5544
std::vector<ISC_STATUS> status_;
5645
};

src/backends/firebird/error-firebird.cpp

+78-1
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,87 @@ firebird_soci_error::firebird_soci_error(std::string const & msg, ISC_STATUS con
2121
if (status != 0)
2222
{
2323
std::size_t i = 0;
24-
while (i < stat_size && status[i] != 0)
24+
while (i < ISC_STATUS_LENGTH && status[i] != isc_arg_end)
2525
{
2626
status_.push_back(status[i++]);
2727
}
2828
}
2929
}
3030

31+
int firebird_soci_error::get_backend_error_code() const
32+
{
33+
// Search for the InterBase error code in the status vector, which consists
34+
// of clusters of 2 (mostly) or 3 (exceptionally, see below) elements.
35+
for (std::size_t i = 0; i < status_.size(); i += 2)
36+
{
37+
switch (status_[i])
38+
{
39+
case isc_arg_end:
40+
// This is never supposed to happen due to the way status_ is
41+
// filled in the ctor above.
42+
return 0;
43+
44+
case isc_arg_gds:
45+
// Cluster starting with this value contains the error code
46+
// we're looking for in the next element.
47+
if (i + 1 < status_.size())
48+
{
49+
return static_cast<int>(status_[i + 1]);
50+
}
51+
break;
52+
53+
case isc_arg_cstring:
54+
// This is the only cluster consisting of 3 elements, so skip
55+
// an extra one.
56+
++i;
57+
break;
58+
}
59+
}
60+
61+
return 0;
62+
}
63+
64+
soci_error::error_category firebird_soci_error::get_error_category() const
65+
{
66+
switch (get_backend_error_code())
67+
{
68+
case isc_bad_db_format:
69+
case isc_unavailable:
70+
case isc_wrong_ods:
71+
case isc_badodsver:
72+
case isc_connect_reject:
73+
case isc_login:
74+
case isc_network_error:
75+
case isc_net_connect_err:
76+
case isc_lost_db_connection:
77+
return connection_error;
78+
79+
case isc_syntaxerr:
80+
case isc_dsql_error:
81+
case isc_command_end_err:
82+
return invalid_statement;
83+
84+
case isc_no_priv:
85+
return no_privilege;
86+
87+
case isc_not_valid:
88+
case isc_no_dup:
89+
case isc_foreign_key:
90+
case isc_primary_key_ref:
91+
case isc_primary_key_notnull:
92+
return constraint_violation;
93+
94+
case isc_tra_state:
95+
return unknown_transaction_state;
96+
97+
case isc_io_error:
98+
case isc_virmemexh:
99+
return system_error;
100+
}
101+
102+
return unknown;
103+
}
104+
31105
namespace details
32106
{
33107

@@ -36,6 +110,9 @@ namespace firebird
36110

37111
void get_iscerror_details(ISC_STATUS * status_vector, std::string &msg)
38112
{
113+
// Size of buffer for error messages: 4K should be enough for everybody.
114+
constexpr std::size_t const SOCI_FIREBIRD_ERRMSG = 4096;
115+
39116
char msg_buffer[SOCI_FIREBIRD_ERRMSG];
40117
const ISC_STATUS *pvector = status_vector;
41118

src/backends/firebird/session.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ firebird_session_backend::firebird_session_backend(
4242
auto params = parameters;
4343
params.extract_options_from_space_separated_string();
4444

45-
ISC_STATUS stat[stat_size];
45+
ISC_STATUS stat[ISC_STATUS_LENGTH];
4646
std::string param;
4747

4848
// preparing connection options
@@ -91,7 +91,7 @@ void firebird_session_backend::begin()
9191
{
9292
if (trhp_ == 0)
9393
{
94-
ISC_STATUS stat[stat_size];
94+
ISC_STATUS stat[ISC_STATUS_LENGTH];
9595
if (isc_start_transaction(stat, &trhp_, 1, &dbhp_, 0, NULL))
9696
{
9797
throw_iscerror(stat);
@@ -106,7 +106,7 @@ firebird_session_backend::~firebird_session_backend()
106106

107107
bool firebird_session_backend::is_connected()
108108
{
109-
ISC_STATUS stat[stat_size];
109+
ISC_STATUS stat[ISC_STATUS_LENGTH];
110110
ISC_SCHAR req[] = { isc_info_ods_version, isc_info_end };
111111
ISC_SCHAR res[256];
112112

@@ -115,7 +115,7 @@ bool firebird_session_backend::is_connected()
115115

116116
void firebird_session_backend::commit()
117117
{
118-
ISC_STATUS stat[stat_size];
118+
ISC_STATUS stat[ISC_STATUS_LENGTH];
119119

120120
if (trhp_ != 0)
121121
{
@@ -130,7 +130,7 @@ void firebird_session_backend::commit()
130130

131131
void firebird_session_backend::rollback()
132132
{
133-
ISC_STATUS stat[stat_size];
133+
ISC_STATUS stat[ISC_STATUS_LENGTH];
134134

135135
if (trhp_ != 0)
136136
{
@@ -153,7 +153,7 @@ isc_tr_handle* firebird_session_backend::current_transaction()
153153

154154
void firebird_session_backend::cleanUp()
155155
{
156-
ISC_STATUS stat[stat_size];
156+
ISC_STATUS stat[ISC_STATUS_LENGTH];
157157

158158
// at the end of session our transaction is finally commited.
159159
if (trhp_ != 0)

src/backends/firebird/statement.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ void firebird_statement_backend::prepareSQLDA(XSQLDA ** sqldap, short size)
4040

4141
void firebird_statement_backend::alloc()
4242
{
43-
ISC_STATUS stat[stat_size];
43+
ISC_STATUS stat[ISC_STATUS_LENGTH];
4444

4545
if (isc_dsql_allocate_statement(stat, &session_.dbhp_, &stmtp_))
4646
{
@@ -52,7 +52,7 @@ void firebird_statement_backend::clean_up()
5252
{
5353
rowsAffectedBulk_ = -1LL;
5454

55-
ISC_STATUS stat[stat_size];
55+
ISC_STATUS stat[ISC_STATUS_LENGTH];
5656

5757
if (stmtp_ != 0)
5858
{
@@ -155,7 +155,7 @@ namespace
155155
char type_item[] = {isc_info_sql_stmt_type};
156156
char res_buffer[8];
157157

158-
ISC_STATUS stat[stat_size];
158+
ISC_STATUS stat[ISC_STATUS_LENGTH];
159159

160160
if (isc_dsql_sql_info(stat, &stmt, sizeof(type_item),
161161
type_item, sizeof(res_buffer), res_buffer))
@@ -217,7 +217,7 @@ void firebird_statement_backend::rewriteQuery(
217217
prepareSQLDA(&sqldap_);
218218
}
219219

220-
ISC_STATUS stat[stat_size];
220+
ISC_STATUS stat[ISC_STATUS_LENGTH];
221221
isc_stmt_handle tmpStmtp = 0;
222222

223223
// allocate temporary statement to determine its type
@@ -300,7 +300,7 @@ void firebird_statement_backend::prepare(std::string const & query,
300300
// firebird's api
301301
rewriteQuery(query, queryBuffer);
302302

303-
ISC_STATUS stat[stat_size];
303+
ISC_STATUS stat[ISC_STATUS_LENGTH];
304304

305305
// prepare real statement
306306
if (isc_dsql_prepare(stat, session_.current_transaction(), &stmtp_, 0,
@@ -374,7 +374,7 @@ namespace
374374
statement_backend::exec_fetch_result
375375
firebird_statement_backend::execute(int number)
376376
{
377-
ISC_STATUS stat[stat_size];
377+
ISC_STATUS stat[ISC_STATUS_LENGTH];
378378
XSQLDA *t = NULL;
379379

380380
std::size_t usize = uses_.size();
@@ -481,7 +481,7 @@ firebird_statement_backend::fetch(int number)
481481
if (endOfRowSet_)
482482
return ef_no_data;
483483

484-
ISC_STATUS stat[stat_size];
484+
ISC_STATUS stat[ISC_STATUS_LENGTH];
485485

486486
for (size_t i = 0; i<static_cast<unsigned int>(sqldap_->sqld); ++i)
487487
{

0 commit comments

Comments
 (0)