diff --git a/include/asterisk/config.h b/include/asterisk/config.h index 954508b718..fff6890bcf 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -126,6 +126,12 @@ typedef int realtime_require(const char *database, const char *table, va_list ap */ typedef int realtime_unload(const char *database, const char *table); +/*! Special return value indicating a successful query that returned no data. + * Used by realtime backends to signal "not found" vs an actual backend failure. + * This allows the core engine to differentiate and avoid unnecessary failover. + */ +#define CONFIG_RT_NOT_FOUND (void *)-1 + /*! \brief Configuration engine structure, used to define realtime drivers */ struct ast_config_engine { char *name; diff --git a/main/config.c b/main/config.c index 900efa355a..4e5684d5f4 100644 --- a/main/config.c +++ b/main/config.c @@ -3639,8 +3639,20 @@ struct ast_variable *ast_load_realtime_all_fields(const char *family, const stru for (i = 1; ; i++) { if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) { - if (eng->realtime_func && (res = eng->realtime_func(db, table, fields))) { - return res; + if (eng->realtime_func) { + res = eng->realtime_func(db, table, fields); + + /* If a backend returns CONFIG_RT_NOT_FOUND, stop iteration and return NULL, + * indicating that the requested record does not exist and no failover should occur. + * Only continue iteration if the result is NULL and not CONFIG_RT_NOT_FOUND, + * which signals a backend failure. + */ + if (res == CONFIG_RT_NOT_FOUND) { + return NULL; + } + if (res) { + return res; + } } } else { return NULL; diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index cecbd1792f..7007baf335 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -167,7 +167,8 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data) * Sub-in the values to the prepared statement and execute it. Return results * as a ast_variable list. * - * \return var on success + * \return var on success (data found) + * \return CONFIG_RT_NOT_FOUND on success but no record * \retval NULL on failure */ static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields) @@ -237,9 +238,13 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl res = SQLFetch(stmt); if (res == SQL_NO_DATA) { + /* SQL_NO_DATA indicates that the query was valid but no record was found. + * Instead of returning NULL (which signals a backend error to the core), + * return CONFIG_RT_NOT_FOUND to prevent incorrect failover. + */ SQLFreeHandle (SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); - return NULL; + return CONFIG_RT_NOT_FOUND; } if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));