From 29daaa07b0cdab12ce856c7520cde5270c68effc Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 10 Jan 2011 11:27:26 -0600 Subject: [PATCH] FS-2960 --- src/include/switch_odbc.h | 3 + src/switch_odbc.c | 114 +++++++++++++++++++++++++++----------- 2 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/include/switch_odbc.h b/src/include/switch_odbc.h index f76384003a..103fe0f0d7 100644 --- a/src/include/switch_odbc.h +++ b/src/include/switch_odbc.h @@ -34,6 +34,8 @@ #include +#define DEFAULT_ODBC_RETRIES 120 + SWITCH_BEGIN_EXTERN_C struct switch_odbc_handle; typedef void *switch_odbc_statement_handle_t; @@ -50,6 +52,7 @@ typedef enum { } switch_odbc_status_t; SWITCH_DECLARE(switch_odbc_handle_t *) switch_odbc_handle_new(const char *dsn, const char *username, const char *password); +SWITCH_DECLARE(void) switch_odbc_set_num_retries(switch_odbc_handle_t *handle, int num_retries); SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_disconnect(switch_odbc_handle_t *handle); SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_connect(switch_odbc_handle_t *handle); SWITCH_DECLARE(void) switch_odbc_handle_destroy(switch_odbc_handle_t **handlep); diff --git a/src/switch_odbc.c b/src/switch_odbc.c index 48ba62ce03..a7c2153304 100644 --- a/src/switch_odbc.c +++ b/src/switch_odbc.c @@ -57,6 +57,7 @@ struct switch_odbc_handle { char odbc_driver[256]; BOOL is_firebird; int affected_rows; + int num_retries; }; #endif @@ -90,6 +91,7 @@ SWITCH_DECLARE(switch_odbc_handle_t *) switch_odbc_handle_new(const char *dsn, c new_handle->env = SQL_NULL_HANDLE; new_handle->state = SWITCH_ODBC_STATE_INIT; new_handle->affected_rows = 0; + new_handle->num_retries = DEFAULT_ODBC_RETRIES; return new_handle; @@ -104,6 +106,15 @@ SWITCH_DECLARE(switch_odbc_handle_t *) switch_odbc_handle_new(const char *dsn, c return NULL; } +SWITCH_DECLARE(void) switch_odbc_set_num_retries(switch_odbc_handle_t *handle, int num_retries) +{ +#ifdef SWITCH_HAVE_ODBC + if (handle) { + handle->num_retries = num_retries; + } +#endif +} + SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_disconnect(switch_odbc_handle_t *handle) { #ifdef SWITCH_HAVE_ODBC @@ -133,6 +144,53 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_disconnect(switch_odbc_h #ifdef SWITCH_HAVE_ODBC +static switch_odbc_status_t init_odbc_handles(switch_odbc_handle_t *handle, switch_bool_t do_reinit) +{ + int result; + + if (!handle) { + return SWITCH_ODBC_FAIL; + } + + /* if handle is already initialized, and we're supposed to reinit - free old handle first */ + if (do_reinit == SWITCH_TRUE && handle->env != SQL_NULL_HANDLE) { + SQLFreeHandle(SQL_HANDLE_DBC, handle->con); + SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + handle->env = SQL_NULL_HANDLE; + } + + if (handle->env == SQL_NULL_HANDLE) { + result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handle->env); + + if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error AllocHandle\n"); + handle->env = SQL_NULL_HANDLE; /* Reset handle value, just in case */ + return SWITCH_ODBC_FAIL; + } + + result = SQLSetEnvAttr(handle->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); + + if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error SetEnv\n"); + SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + handle->env = SQL_NULL_HANDLE; /* Reset handle value after it's freed */ + return SWITCH_ODBC_FAIL; + } + + result = SQLAllocHandle(SQL_HANDLE_DBC, handle->env, &handle->con); + + if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error AllocHDB %d\n", result); + SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + handle->env = SQL_NULL_HANDLE; /* Reset handle value after it's freed */ + return SWITCH_ODBC_FAIL; + } + SQLSetConnectAttr(handle->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); + } + + return SWITCH_ODBC_SUCCESS; +} + static int db_is_up(switch_odbc_handle_t *handle) { int ret = 0; @@ -143,12 +201,18 @@ static int db_is_up(switch_odbc_handle_t *handle) switch_odbc_status_t recon = 0; char *err_str = NULL; SQLCHAR sql[255] = ""; - int max_tries = 120; + int max_tries = DEFAULT_ODBC_RETRIES; int code = 0; SQLRETURN rc; SQLSMALLINT nresultcols; + if (handle) { + max_tries = handle->num_retries; + if (max_tries < 1) + max_tries = DEFAULT_ODBC_RETRIES; + } + top: if (!handle) { @@ -199,6 +263,13 @@ static int db_is_up(switch_odbc_handle_t *handle) error: err_str = switch_odbc_handle_get_error(handle, stmt); + + /* Make sure to free the handle before we try to reconnect */ + if (stmt) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + stmt = NULL; + } + recon = switch_odbc_handle_connect(handle); max_tries--; @@ -228,11 +299,6 @@ static int db_is_up(switch_odbc_handle_t *handle) goto done; } - if (stmt) { - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - stmt = NULL; - } - switch_safe_free(err_str); switch_yield(1000000); goto top; @@ -274,31 +340,8 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_connect(switch_odbc_hand SQLSMALLINT valueLength = 0; int i = 0; - if (handle->env == SQL_NULL_HANDLE) { - result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handle->env); + init_odbc_handles(handle, SWITCH_FALSE); /* Init ODBC handles, if they are already initialized, don't do it again */ - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error AllocHandle\n"); - return SWITCH_ODBC_FAIL; - } - - result = SQLSetEnvAttr(handle->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); - - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error SetEnv\n"); - SQLFreeHandle(SQL_HANDLE_ENV, handle->env); - return SWITCH_ODBC_FAIL; - } - - result = SQLAllocHandle(SQL_HANDLE_DBC, handle->env, &handle->con); - - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error AllocHDB %d\n", result); - SQLFreeHandle(SQL_HANDLE_ENV, handle->env); - return SWITCH_ODBC_FAIL; - } - SQLSetConnectAttr(handle->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); - } if (handle->state == SWITCH_ODBC_STATE_CONNECTED) { switch_odbc_handle_disconnect(handle); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Re-connecting %s\n", handle->dsn); @@ -325,7 +368,9 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_connect(switch_odbc_hand SQLGetDiagRec(SQL_HANDLE_DBC, handle->con, 1, stat, &err, msg, 100, &mlen); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error SQLConnect=%d errno=%d %s\n", result, (int) err, msg); } - SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + + /* Deallocate handles again, more chanses to succeed when reconnecting */ + init_odbc_handles(handle, SWITCH_TRUE); /* Reinit ODBC handles */ return SWITCH_ODBC_FAIL; } @@ -554,6 +599,7 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec_detailed(c } SQLFreeHandle(SQL_HANDLE_STMT, stmt); + stmt = NULL; /* Make sure we don't try to free this handle again */ if (!err_cnt) { return SWITCH_ODBC_SUCCESS; @@ -593,8 +639,10 @@ SWITCH_DECLARE(void) switch_odbc_handle_destroy(switch_odbc_handle_t **handlep) if (handle) { switch_odbc_handle_disconnect(handle); - SQLFreeHandle(SQL_HANDLE_DBC, handle->con); - SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + if (handle->env != SQL_NULL_HANDLE) { + SQLFreeHandle(SQL_HANDLE_DBC, handle->con); + SQLFreeHandle(SQL_HANDLE_ENV, handle->env); + } switch_safe_free(handle->dsn); switch_safe_free(handle->username); switch_safe_free(handle->password);