Skip to content

Store error vector and SQL state in DatabaseException - #27

Merged
asfernandes merged 5 commits into
asfernandes:mainfrom
fdcastel:issue-24
Feb 23, 2026
Merged

Store error vector and SQL state in DatabaseException#27
asfernandes merged 5 commits into
asfernandes:mainfrom
fdcastel:issue-24

Conversation

@fdcastel

Copy link
Copy Markdown
Contributor

Store error vector in DatabaseException

Fixes #24

Summary

DatabaseException now stores the Firebird error vector (ISC error codes) and SQL state from the original status vector, making them available for programmatic error handling.

Previously, DatabaseException only stored the formatted message string (via what()), discarding the raw error codes. This made it impossible to map Firebird errors to SQLSTATE codes — a requirement for ODBC drivers and other consumers that need structured error information.

Changes

Exception.h

  • Added #include <vector>.
  • DatabaseException constructor now deep-copies the error vector and extracts the SQL state before the IStatus is reused.
  • New public methods:
    • getErrors() — returns the error vector containing isc_arg_gds and isc_arg_number entries, terminated by isc_arg_end. String arguments are excluded to avoid dangling pointers (formatted text is already in what()).
    • getErrorCode() — convenience that returns the primary ISC error code (first isc_arg_gds value), or 0 if none.
    • getSqlState() — returns the SQL state string (e.g. "42000") if present in the original status vector, or empty otherwise.
  • New private members: errorVector_, sqlState_.

Exception.cpp

  • copyErrorVector() — walks the Firebird status vector and copies only safe numeric entries (isc_arg_gds, isc_arg_number), skipping string pointers that would dangle after IStatus reuse.
  • extractSqlState() — extracts the isc_arg_sql_state string from the status vector while it is still valid.

src/test/Exception.cpp (new)

Seven test cases covering:

  • Syntax errors produce a non-zero error code
  • Error vector contains isc_arg_gds entries
  • Error vector is terminated by isc_arg_end
  • getErrorCode() returns the first GDS code from the vector
  • SQL state is extracted for syntax errors
  • Default-constructed exceptions have empty error info
  • what() message is preserved

Backward Compatibility

This is a non-breaking, additive change. Existing code that catches DatabaseException and uses what() continues to work unchanged. The inherited FbCppException(const std::string&) constructor still works — the new members are value-initialized (empty vector, empty string).

@fdcastel

Copy link
Copy Markdown
Contributor Author

I’m reviewing the failed tests on CI now.

Yesterday, the CI runs on my fork kept running for over 30 minutes without producing any results.

@fdcastel

fdcastel commented Feb 18, 2026

Copy link
Copy Markdown
Contributor Author

EDIT: Unrelated. Moved to #31

Comment thread src/fb-cpp/Exception.cpp
Comment thread src/fb-cpp/Exception.cpp
Comment thread src/fb-cpp/Exception.h Outdated
Comment thread src/test/Exception.cpp Outdated
Comment thread src/fb-cpp/Exception.cpp Outdated
Comment thread src/fb-cpp/Exception.cpp Outdated
Comment thread src/fb-cpp/Exception.h Outdated
Comment thread src/fb-cpp/Exception.h Outdated
@fdcastel

Copy link
Copy Markdown
Contributor Author

Pushed fixes from review.

  • Reworked copyErrorVector to preserve all status vector entries, including string arguments (isc_arg_string, isc_arg_interpreted, isc_arg_sql_state, isc_arg_cstring). String values are deep-copied into a std::vector<std::string> errorStrings member, and the error vector stores pointers to these owned copies.
  • A fixupStringPointers() helper re-establishes the pointers after construction or copy. The isc_arg_cstring entries (length + pointer) are normalized to isc_arg_string in the stored vector.
  • A custom copy constructor was added to ensure pointer validity when the exception is copied (e.g., throw ex;). Default move semantics are safe since vector move transfers the backing array without relocating string contents.
  • added a separate private: label before the data members, separating them from the static/member function declarations in Exceptions.h
  • Renamed all member variables to remove trailing underscores.
  • Removed extra blank lines
  • Removed unnecessary clang directives
  • Fixed copyright on new file.

@fdcastel
fdcastel requested a review from asfernandes February 22, 2026 23:20
Comment thread src/test/Exception.cpp Outdated
Comment thread src/test/Exception.cpp Outdated
DatabaseException now deep-copies the Firebird error vector (ISC error
codes) and extracts the SQL state from the original status vector before
the IStatus is reused.

New public methods:
- getErrors(): returns isc_arg_gds/isc_arg_number entries (terminated
  by isc_arg_end). String arguments are excluded to avoid dangling
  pointers.
- getErrorCode(): returns the primary ISC error code, or 0.
- getSqlState(): returns the SQL state string (e.g. 42000), or empty.

This is a non-breaking, additive change. Existing code continues to
work unchanged.

Fixes asfernandes#24
…tting

- Copy and store string arguments in DatabaseException instead of skipping them
- Add errorStrings member with deep-copied strings, fixup pointers after copy
- Add custom copy constructor for pointer safety on exception copy
- Remove trailing underscores from member variables (errorVector, sqlState)
- Remove unnecessary clang-format off/on directives
- Remove extra blank lines between functions
- Update getErrors() doc (strings are now preserved)
- Add separate private: label for data members
- Fix copyright in test file.
…tate

The SQL state entry is not guaranteed to be present in the error vector
returned by IStatus::getErrors(). Soften the test assertion accordingly.
- Consolidate 7 separate test cases into one comprehensive test
- Remove using FbCppException::FbCppException inherited constructor
@fdcastel

Copy link
Copy Markdown
Contributor Author

Rebased with latest main

  • Consolidated the 7 separate test cases into a single comprehensive syntaxErrorExceptionProperties test that verifies all properties in one pass
  • Removed using FbCppException::FbCppException; from DatabaseException.
    • Now DatabaseException can only be constructed with (Client&, const intptr_t*) (which makes sense: a database exception should always come from a status vector).

The defaultConstructedHasEmptyErrorVector test was also removed since it's no longer possible to construct a DatabaseException from a plain string.

@asfernandes
asfernandes merged commit 8be6ce5 into asfernandes:main Feb 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error Vector in DatabaseException

2 participants