Merge branch 'firebird-errors'

Improve Firebird errors generation too.

See #1242.
This commit is contained in:
Vadim Zeitlin
2025-04-24 20:58:10 +02:00
4 changed files with 93 additions and 27 deletions
+2 -13
View File
@@ -30,27 +30,16 @@
namespace soci
{
std::size_t const stat_size = 20;
// size of buffer for error messages. All examples use this value.
// Anyone knows, where it is stated that 512 bytes is enough ?
std::size_t const SOCI_FIREBIRD_ERRMSG = 512;
class SOCI_FIREBIRD_DECL firebird_soci_error : public soci_error
{
public:
firebird_soci_error(std::string const & msg,
ISC_STATUS const * status = 0);
~firebird_soci_error() noexcept override {};
error_category get_error_category() const override;
std::string get_backend_name() const override { return "firebird"; }
int get_backend_error_code() const override
{
// We can't return the full vector using this generic interface, so
// return just the first status.
return status_.empty() ? 0 : status_[0];
}
int get_backend_error_code() const override;
std::vector<ISC_STATUS> status_;
};
+78 -1
View File
@@ -21,13 +21,87 @@ firebird_soci_error::firebird_soci_error(std::string const & msg, ISC_STATUS con
if (status != 0)
{
std::size_t i = 0;
while (i < stat_size && status[i] != 0)
while (i < ISC_STATUS_LENGTH && status[i] != isc_arg_end)
{
status_.push_back(status[i++]);
}
}
}
int firebird_soci_error::get_backend_error_code() const
{
// Search for the InterBase error code in the status vector, which consists
// of clusters of 2 (mostly) or 3 (exceptionally, see below) elements.
for (std::size_t i = 0; i < status_.size(); i += 2)
{
switch (status_[i])
{
case isc_arg_end:
// This is never supposed to happen due to the way status_ is
// filled in the ctor above.
return 0;
case isc_arg_gds:
// Cluster starting with this value contains the error code
// we're looking for in the next element.
if (i + 1 < status_.size())
{
return static_cast<int>(status_[i + 1]);
}
break;
case isc_arg_cstring:
// This is the only cluster consisting of 3 elements, so skip
// an extra one.
++i;
break;
}
}
return 0;
}
soci_error::error_category firebird_soci_error::get_error_category() const
{
switch (get_backend_error_code())
{
case isc_bad_db_format:
case isc_unavailable:
case isc_wrong_ods:
case isc_badodsver:
case isc_connect_reject:
case isc_login:
case isc_network_error:
case isc_net_connect_err:
case isc_lost_db_connection:
return connection_error;
case isc_syntaxerr:
case isc_dsql_error:
case isc_command_end_err:
return invalid_statement;
case isc_no_priv:
return no_privilege;
case isc_not_valid:
case isc_no_dup:
case isc_foreign_key:
case isc_primary_key_ref:
case isc_primary_key_notnull:
return constraint_violation;
case isc_tra_state:
return unknown_transaction_state;
case isc_io_error:
case isc_virmemexh:
return system_error;
}
return unknown;
}
namespace details
{
@@ -36,6 +110,9 @@ namespace firebird
void get_iscerror_details(ISC_STATUS * status_vector, std::string &msg)
{
// Size of buffer for error messages: 4K should be enough for everybody.
constexpr std::size_t const SOCI_FIREBIRD_ERRMSG = 4096;
char msg_buffer[SOCI_FIREBIRD_ERRMSG];
const ISC_STATUS *pvector = status_vector;
+6 -6
View File
@@ -42,7 +42,7 @@ firebird_session_backend::firebird_session_backend(
auto params = parameters;
params.extract_options_from_space_separated_string();
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
std::string param;
// preparing connection options
@@ -91,7 +91,7 @@ void firebird_session_backend::begin()
{
if (trhp_ == 0)
{
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
if (isc_start_transaction(stat, &trhp_, 1, &dbhp_, 0, NULL))
{
throw_iscerror(stat);
@@ -106,7 +106,7 @@ firebird_session_backend::~firebird_session_backend()
bool firebird_session_backend::is_connected()
{
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
ISC_SCHAR req[] = { isc_info_ods_version, isc_info_end };
ISC_SCHAR res[256];
@@ -115,7 +115,7 @@ bool firebird_session_backend::is_connected()
void firebird_session_backend::commit()
{
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
if (trhp_ != 0)
{
@@ -130,7 +130,7 @@ void firebird_session_backend::commit()
void firebird_session_backend::rollback()
{
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
if (trhp_ != 0)
{
@@ -153,7 +153,7 @@ isc_tr_handle* firebird_session_backend::current_transaction()
void firebird_session_backend::cleanUp()
{
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
// at the end of session our transaction is finally commited.
if (trhp_ != 0)
+7 -7
View File
@@ -40,7 +40,7 @@ void firebird_statement_backend::prepareSQLDA(XSQLDA ** sqldap, short size)
void firebird_statement_backend::alloc()
{
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
if (isc_dsql_allocate_statement(stat, &session_.dbhp_, &stmtp_))
{
@@ -52,7 +52,7 @@ void firebird_statement_backend::clean_up()
{
rowsAffectedBulk_ = -1LL;
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
if (stmtp_ != 0)
{
@@ -155,7 +155,7 @@ namespace
char type_item[] = {isc_info_sql_stmt_type};
char res_buffer[8];
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
if (isc_dsql_sql_info(stat, &stmt, sizeof(type_item),
type_item, sizeof(res_buffer), res_buffer))
@@ -217,7 +217,7 @@ void firebird_statement_backend::rewriteQuery(
prepareSQLDA(&sqldap_);
}
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
isc_stmt_handle tmpStmtp = 0;
// allocate temporary statement to determine its type
@@ -300,7 +300,7 @@ void firebird_statement_backend::prepare(std::string const & query,
// firebird's api
rewriteQuery(query, queryBuffer);
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
// prepare real statement
if (isc_dsql_prepare(stat, session_.current_transaction(), &stmtp_, 0,
@@ -374,7 +374,7 @@ namespace
statement_backend::exec_fetch_result
firebird_statement_backend::execute(int number)
{
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
XSQLDA *t = NULL;
std::size_t usize = uses_.size();
@@ -481,7 +481,7 @@ firebird_statement_backend::fetch(int number)
if (endOfRowSet_)
return ef_no_data;
ISC_STATUS stat[stat_size];
ISC_STATUS stat[ISC_STATUS_LENGTH];
for (size_t i = 0; i<static_cast<unsigned int>(sqldap_->sqld); ++i)
{