db_mysql: recover from ER_UNKNOWN_STMT_HANDLER (1243)#3865
Open
dondetir wants to merge 1 commit intoOpenSIPS:masterfrom
Open
db_mysql: recover from ER_UNKNOWN_STMT_HANDLER (1243)#3865dondetir wants to merge 1 commit intoOpenSIPS:masterfrom
dondetir wants to merge 1 commit intoOpenSIPS:masterfrom
Conversation
The prepared-statement execute wrapper treats MySQL error 1243 (ER_UNKNOWN_STMT_HANDLER) as a hard failure and skips the existing reconnect + re-prepare path. This surfaces in production when the backing database is replaced underneath a live client connection - for example during an AWS Aurora zero-downtime minor-version upgrade, which preserves the TCP connection but drops the server-side prepared-statement cache. The next stmt_execute returns 1243, OpenSIPS logs CRITICAL and the query fails instead of transparently recovering. Add the case to wrapper_single_mysql_stmt_execute so it funnels into the same switch_state_to_disconnected -> connect_with_retry -> re_init_statement recovery path that already handles CR_SERVER_GONE_ERROR and friends. ER_NEED_REPREPARE (1615) is intentionally not added: libmysqlclient auto-reprepare already handles that case. 1243 bypasses auto-reprepare because the server has no record of the handle at all. The companion prepare wrapper is not modified: it starts from a fresh mysql_stmt_init() handle that carries no server-side ID, so the server cannot return 1243 in response to a prepare request. Reported-by: Sasmita Panda <spanda@3clogic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When MySQL returns error 1243 (
ER_UNKNOWN_STMT_HANDLER) frommysql_stmt_execute(), the currentwrapper_single_mysql_stmt_execute()switch drops it into thedefault:branch, logsLM_CRITand returns the error up to the caller without triggering the existing reconnect + re-prepare recovery path. This patch adds the case so 1243 funnels into the same recovery flow that already handlesCR_SERVER_GONE_ERROR,CR_SERVER_LOST,CR_COMMANDS_OUT_OF_SYNC, and 4031.Why this matters — real production impact
This was reported by Sasmita Panda (3CLogic) on the opensips-users list (thread: "Need some help on mysql error on opensips", 2025-10-21). Their setup runs OpenSIPS on EKS against AWS RDS Aurora MySQL. When Aurora performs a minor-version zero-downtime upgrade, the backing database instance is replaced while the client TCP connection is preserved. The server-side prepared-statement cache is lost on the new instance, so the next
mysql_stmt_executeusing an existing handle returns 1243. libmysqlclient's auto-reprepare (which handles the relatedER_NEED_REPREPAREcase for DDL invalidation) does not kick in here because the server has no record of the handle at all. With the current code OpenSIPS logs:and the query fails silently. The operator has to restart OpenSIPS to recover.
What the fix does
The recovery path already exists and is proven. When the wrapper returns
-1, callers likedb_do_prepared_query()run:This closes all cached statements, opens a fresh MYSQL connection (which correctly routes to the new Aurora backend), re-prepares the statement, and retries the caller's loop up to
max_db_queriestimes. All we need to do is tell the error classifier that 1243 is a reconnect-worthy error.The fix is a one-case addition to the switch.
ER_UNKNOWN_STMT_HANDLERis defined identically in both MySQL (mysqld_error.h) and MariaDB (mariadb_error.h) as 1243, so no magic-number comment is needed (unlike the 4031 case above it).Scope discipline
wrapper_single_mysql_stmt_executeis modified. The companionwrapper_single_mysql_stmt_prepareis intentionally left alone: it starts from a freshmysql_stmt_init()handle that carries no server-side ID, so the server cannot return 1243 in response to aCOM_STMT_PREPARE. Adding the case there would be unreachable defensive code.wrapper_single_mysql_real_query/wrapper_single_mysql_send_querydo not need the case — they don't use prepared statement handles.ER_NEED_REPREPARE(1615) is intentionally not added — libmysqlclient auto-reprepare already handles that scenario.Verification
db_mysql.sobefore/after: exactly 1 newcmp $0x4db, %eaxinstruction inside thewrapper_single_mysql_stmt_executeinlined call site. All 5 existing error-code comparisons (0x7d6,0x7de,0xfbf) preserved bit-for-bit — zero regression on any existing error classification.CR_SERVER_GONE_ERROR,CR_SERVER_LOST,CR_COMMANDS_OUT_OF_SYNC, 4031,ER_UNKNOWN_STMT_HANDLER,ER_NEED_REPREPARE, syntax error, dup entry). Before the fix, 1243 classifies as+1 HARD ERROR; after the fix, 1243 classifies as-1 RECONNECT. Every other error code is classified identically in both versions.opensipsloads the patcheddb_mysql.so, registers theE_MYSQL_CONNECTIONevent, initializesusrlocinsql-onlymode against a live MySQL container, and runs the reactor cleanly.Credit
Reported-by: Sasmita Panda spanda@3clogic.com