Repository navigation
fix: clear transaction state when reconnect() replaces the socket - #10650
KevinBlakeLopez wants to merge 3 commits into
Conversation
|
Hi there, @KevinBlakeLopez! 👋 Thank you for sending this PR! We expect the following in all Pull Requests (PRs).
Important We expect all code changes or bug-fixes to be accompanied by one or more tests added to our test suite to prove the code works. If pull requests do not comply with the above, they will likely be closed. Since we are a team of volunteers, we don't have any more time to work See https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md |
2dc7af6 to
6369d6b
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Failed reconnection attempts bypass transaction invalidation, and OCI8 recovery leaves autocommit disabled.
2 open issues
What changed in this PR
Addresses #10648 by invalidating transaction state when reconnect() replaces a lost database connection. Reviewed under the assumed develop patch-release policy.
Changes:
- Clears transaction depth and marks interrupted transactions as failed.
- Adds MySQLi live tests for lost and healthy connections during transactions.
- Documents the behavior in the connection guide and changelog.
Validation used targeted source inspection; automated tests and the database-driver matrix remain for CI.
| File | Description |
|---|---|
user_guide_src/source/database/connecting.rst |
Explains transaction invalidation after reconnection. |
user_guide_src/source/changelogs/v4.7.6.rst |
Records the fix for #10648. |
tests/system/Database/Live/ReconnectDuringTransactionTest.php |
Tests interrupted and preserved MySQLi transactions. |
system/Database/BaseConnection.php |
Resets transaction state after replacing a connection. |
Review effort: Balanced
The server rolls the open transaction back with the dead connection. Keeping transDepth and transStatus made transComplete() return true. Fixes codeigniter4#10648 Co-authored-by: Cursor <cursoragent@cursor.com>
reconnect() cleared transDepth and transStatus only after initialize() returned. When initialize() threw, the old transaction state survived, and a later query() that reconnected on its own let transComplete() report success. The state is now cleared before initialize() runs. OCI8 keeps its commit mode in PHP. Clearing the depth skipped _transRollback(), so commitMode stayed OCI_NO_AUTO_COMMIT and later writes were never committed. OCI8 now restores OCI_COMMIT_ON_SUCCESS when the transaction is abandoned. The guide and changelog now say this applies only when ping() reports the connection lost. On PostgreSQL, pg_ping() re-establishes a broken connection itself and returns true, so reconnect() does not clear the state there. Refs codeigniter4#10648 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1a7668c to
4a25d53
Compare
michalsn
left a comment
There was a problem hiding this comment.
Looks good overall. Please clarify that reconnect() does not resume the lost transaction and that failure handling must cover the entire operation, including nested transaction groups.
Apply the review suggestion. The transaction-state reset only happens when ping() returns false, and PostgreSQL's pg_ping() can re-establish a broken connection and return true. The lost transaction is not resumed, later writes may autocommit, and the code that owns the whole transaction has to handle the failure before retrying. Drop the issue link from the changelog entry to match the changelog style. Co-authored-by: Michal Sniatala <459185+michalsn@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Description
Fixes #10648.
reconnect()closes a dead socket and opens a new one. The server has already rolled back the transaction that was open on the old socket.transDepthandtransStatuswere left as they were, andping()goes throughsimpleQuery(), which does not callhandleTransStatus().transComplete()then returned true while the pre-timeout insert was gone.When the socket is replaced during a transaction,
reconnect()now clearstransDepthand marks the transaction failed. A laterreconnect()whileping()is still true leaves the open transaction alone.On
develop(df8b96bee) the new live test failed before this change:After the change,
ReconnectDuringTransactionTestandPingTestpass (local MySQL 8.0.45, PHP 8.5.12, MySQLi).Checklist:
Made with Cursor