mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	func_odbc: Check connection status before executing queries.
A recent change to func_odbc made it so that a single connection was maintained per DSN. The problem was that the code was optimistic about the health of the connection after initially opening it and did nothing to re-connect in case the connection had died. This change adds a check before executing a query to ensure that the connection to the database is still up and running. ASTERISK-25963 #close Reported by Ross Beer Change-Id: Id33c86eb04ff48ca088bb2e3086c27b3b683491d
This commit is contained in:
		| @@ -243,6 +243,42 @@ static struct dsn *create_dsn(const char *name) | ||||
| 	return dsn; | ||||
| } | ||||
|  | ||||
| static SQLHSTMT silent_execute(struct odbc_obj *obj, void *data); | ||||
|  | ||||
| /*! | ||||
|  * \brief Determine if the connection has died. | ||||
|  * | ||||
|  * \param connection The connection to check | ||||
|  * \retval 1 Yep, it's dead | ||||
|  * \retval 0 It's alive and well | ||||
|  */ | ||||
| static int connection_dead(struct odbc_obj *connection) | ||||
| { | ||||
| 	SQLINTEGER dead; | ||||
| 	SQLRETURN res; | ||||
| 	SQLHSTMT stmt; | ||||
|  | ||||
| 	if (!connection) { | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0); | ||||
| 	if (SQL_SUCCEEDED(res)) { | ||||
| 		return dead == SQL_CD_TRUE ? 1 : 0; | ||||
| 	} | ||||
|  | ||||
| 	/* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a direct | ||||
| 	 * execute of a probing statement and see if that succeeds instead | ||||
| 	 */ | ||||
| 	stmt = ast_odbc_direct_execute(connection, silent_execute, "SELECT 1"); | ||||
| 	if (!stmt) { | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	SQLFreeHandle(SQL_HANDLE_STMT, stmt); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Retrieve a DSN, or create it if it does not exist. | ||||
|  * | ||||
| @@ -271,7 +307,26 @@ static struct dsn *get_dsn(const char *name) | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	ao2_lock(dsn->connection); | ||||
| 	ao2_lock(dsn); | ||||
| 	if (!dsn->connection) { | ||||
| 		dsn->connection = ast_odbc_request_obj(name, 0); | ||||
| 		if (!dsn->connection) { | ||||
| 			ao2_unlock(dsn); | ||||
| 			ao2_ref(dsn, -1); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		return dsn; | ||||
| 	} | ||||
|  | ||||
| 	if (connection_dead(dsn->connection)) { | ||||
| 		ast_odbc_release_obj(dsn->connection); | ||||
| 		dsn->connection = ast_odbc_request_obj(name, 0); | ||||
| 		if (!dsn->connection) { | ||||
| 			ao2_unlock(dsn); | ||||
| 			ao2_ref(dsn, -1); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return dsn; | ||||
| } | ||||
| @@ -288,7 +343,7 @@ static void *release_dsn(struct dsn *dsn) | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	ao2_unlock(dsn->connection); | ||||
| 	ao2_unlock(dsn); | ||||
| 	ao2_ref(dsn, -1); | ||||
|  | ||||
| 	return NULL; | ||||
| @@ -323,7 +378,16 @@ static void odbc_datastore_free(void *data) | ||||
| 	ast_free(result); | ||||
| } | ||||
|  | ||||
| static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data) | ||||
| /*! | ||||
|  * \brief Common execution function for SQL queries. | ||||
|  * | ||||
|  * \param obj DB connection | ||||
|  * \param data The query to execute | ||||
|  * \param silent If true, do not print warnings on failure | ||||
|  * \retval NULL Failed to execute query | ||||
|  * \retval non-NULL The executed statement | ||||
|  */ | ||||
| static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent) | ||||
| { | ||||
| 	int res; | ||||
| 	char *sql = data; | ||||
| @@ -337,7 +401,7 @@ static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data) | ||||
|  | ||||
| 	res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS); | ||||
| 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { | ||||
| 		if (res == SQL_ERROR) { | ||||
| 		if (res == SQL_ERROR && !silent) { | ||||
| 			int i; | ||||
| 			SQLINTEGER nativeerror=0, numfields=0; | ||||
| 			SQLSMALLINT diagbytes=0; | ||||
| @@ -354,7 +418,9 @@ static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql); | ||||
| 		if (!silent) { | ||||
| 			ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql); | ||||
| 		} | ||||
| 		SQLCloseCursor(stmt); | ||||
| 		SQLFreeHandle(SQL_HANDLE_STMT, stmt); | ||||
| 		return NULL; | ||||
| @@ -363,6 +429,16 @@ static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data) | ||||
| 	return stmt; | ||||
| } | ||||
|  | ||||
| static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data) | ||||
| { | ||||
| 	return execute(obj, data, 0); | ||||
| } | ||||
|  | ||||
| static SQLHSTMT silent_execute(struct odbc_obj *obj, void *data) | ||||
| { | ||||
| 	return execute(obj, data, 1); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Master control routine | ||||
|  */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user