From 68223ce239fd8c703cdfdf5bf16e5bbe72463741 Mon Sep 17 00:00:00 2001 From: Ravitez Dondeti Date: Tue, 7 Apr 2026 10:24:56 -0500 Subject: [PATCH] db_mysql: recover from ER_UNKNOWN_STMT_HANDLER (1243) 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 --- modules/db_mysql/dbase.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/db_mysql/dbase.c b/modules/db_mysql/dbase.c index a124876b9a7..2c1085e55f5 100644 --- a/modules/db_mysql/dbase.c +++ b/modules/db_mysql/dbase.c @@ -164,6 +164,15 @@ static inline int wrapper_single_mysql_stmt_execute(const db_con_t *conn, * while MariaDB has it as ER_REFERENCED_TRG_DOES_NOT_EXIST */ case 4031: + /* The server-side prepared-statement cache no longer knows + * about our stmt handle - e.g. after a managed-DB transparent + * failover or a zero-downtime minor version upgrade (AWS Aurora), + * where the backing instance is replaced while the client TCP + * connection is preserved. libmysqlclient auto-reprepare (which + * handles the related ER_NEED_REPREPARE case) does not kick in + * here because the server has no record of the handle at all. + * Fall back to the existing reconnect + re-prepare path. */ + case ER_UNKNOWN_STMT_HANDLER: return -1; /* reconnection error -> <0 */ default: LM_CRIT("driver error (%i): %s\n", error, mysql_stmt_error(stmt));