ODBC transaction support
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@177320 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
a150908f3f
commit
a1f583177e
1
CHANGES
1
CHANGES
|
@ -94,6 +94,7 @@ Dialplan Functions
|
|||
of "core show function AES_ENCRYPT" from the CLI
|
||||
* Added AES_DECRYPT. For information on its use, please see the output
|
||||
of "core show function AES_DECRYPT" from the CLI
|
||||
* func_odbc now supports database transactions across multiple queries.
|
||||
|
||||
Applications
|
||||
------------
|
||||
|
|
|
@ -47,6 +47,13 @@ username => oscar
|
|||
password => thegrouch
|
||||
pre-connect => yes
|
||||
sanitysql => select count(*) from systables
|
||||
; forcecommit => no ; Default to committing uncommitted transactions?
|
||||
; isolation => read_committed ; Isolation level; supported levels are:
|
||||
; read_uncommitted, read_committed, repeatable_read,
|
||||
; serializable. Note that not all databases support
|
||||
; all isolation levels (e.g. Postgres only supports
|
||||
; repeatable_read and serializable). See database
|
||||
; documentation for further information.
|
||||
;
|
||||
; Many databases have a default of '\' to escape special characters. MS SQL
|
||||
; Server does not.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2005, 2006 Tilghman Lesher
|
||||
* Copyright (c) 2008 Digium, Inc.
|
||||
*
|
||||
* Tilghman Lesher <func_odbc__200508@the-tilghman.com>
|
||||
*
|
||||
|
@ -205,6 +206,7 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|||
struct acf_odbc_query *query;
|
||||
char *t, varname[15];
|
||||
int i, dsn, bogus_chan = 0;
|
||||
int transactional = 0;
|
||||
AST_DECLARE_APP_ARGS(values,
|
||||
AST_APP_ARG(field)[100];
|
||||
);
|
||||
|
@ -293,16 +295,32 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|||
}
|
||||
pbx_builtin_setvar_helper(chan, "VALUE", NULL);
|
||||
|
||||
/*!\note
|
||||
* Okay, this part is confusing. Transactions belong to a single database
|
||||
* handle. Therefore, when working with transactions, we CANNOT failover
|
||||
* to multiple DSNs. We MUST have a single handle all the way through the
|
||||
* transaction, or else we CANNOT enforce atomicity.
|
||||
*/
|
||||
for (dsn = 0; dsn < 5; dsn++) {
|
||||
if (!ast_strlen_zero(query->writehandle[dsn])) {
|
||||
obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
|
||||
if (obj)
|
||||
stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf));
|
||||
if (transactional) {
|
||||
/* This can only happen second time through or greater. */
|
||||
ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
|
||||
}
|
||||
if (stmt) {
|
||||
status = "SUCCESS";
|
||||
SQLRowCount(stmt, &rows);
|
||||
break;
|
||||
|
||||
if (!ast_strlen_zero(query->writehandle[dsn])) {
|
||||
if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) {
|
||||
transactional = 1;
|
||||
} else {
|
||||
obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
|
||||
transactional = 0;
|
||||
}
|
||||
if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj && !transactional) {
|
||||
ast_odbc_release_obj(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,6 +340,9 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else if (stmt) {
|
||||
status = "SUCCESS";
|
||||
SQLRowCount(stmt, &rows);
|
||||
}
|
||||
|
||||
AST_RWLIST_UNLOCK(&queries);
|
||||
|
@ -338,7 +359,7 @@ static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, co
|
|||
SQLCloseCursor(stmt);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
}
|
||||
if (obj) {
|
||||
if (obj && !transactional) {
|
||||
ast_odbc_release_obj(obj);
|
||||
obj = NULL;
|
||||
}
|
||||
|
|
|
@ -35,25 +35,30 @@
|
|||
|
||||
typedef enum { ODBC_SUCCESS=0, ODBC_FAIL=-1} odbc_status;
|
||||
|
||||
/*! \brief Flags for use with ast_odbc_request_obj2 */
|
||||
enum {
|
||||
RES_ODBC_SANITY_CHECK = (1 << 0),
|
||||
RES_ODBC_INDEPENDENT_CONNECTION = (1 << 1),
|
||||
};
|
||||
|
||||
/*! \brief ODBC container */
|
||||
struct odbc_obj {
|
||||
ast_mutex_t lock;
|
||||
SQLHDBC con; /* ODBC Connection Handle */
|
||||
struct odbc_class *parent; /* Information about the connection is protected */
|
||||
struct timeval last_used;
|
||||
SQLHDBC con; /*!< ODBC Connection Handle */
|
||||
struct odbc_class *parent; /*!< Information about the connection is protected */
|
||||
struct timeval last_used; /*!< Used by idlecheck to determine if the connection should be renegotiated */
|
||||
#ifdef DEBUG_THREADS
|
||||
char file[80];
|
||||
char function[80];
|
||||
int lineno;
|
||||
#endif
|
||||
unsigned int used:1;
|
||||
unsigned int used:1; /*!< Is this connection currently in use? */
|
||||
unsigned int up:1;
|
||||
unsigned int tx:1; /*!< Should this connection be unshared, regardless of the class setting? */
|
||||
struct odbc_txn_frame *txf; /*!< Reference back to the transaction frame, if applicable */
|
||||
AST_LIST_ENTRY(odbc_obj) list;
|
||||
};
|
||||
|
||||
/*!\brief These aren't used in any API calls, but they are kept in a common
|
||||
* location, simply for convenience and to avoid duplication.
|
||||
*/
|
||||
struct odbc_cache_columns {
|
||||
char *name;
|
||||
SQLSMALLINT type;
|
||||
|
@ -106,6 +111,13 @@ int ast_odbc_smart_execute(struct odbc_obj *obj, SQLHSTMT stmt) __attribute__((d
|
|||
* thread which requests it. Note that all connections should be released
|
||||
* when the thread is done by calling odbc_release_obj(), below.
|
||||
*/
|
||||
#ifdef DEBUG_THREADS
|
||||
struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno);
|
||||
#define ast_odbc_request_obj2(a, b) _ast_odbc_request_obj2(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
||||
#else
|
||||
struct odbc_obj *ast_odbc_request_obj2(const char *name, struct ast_flags flags);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno);
|
||||
#define ast_odbc_request_obj(a, b) _ast_odbc_request_obj(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
||||
|
@ -113,6 +125,18 @@ struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *
|
|||
struct odbc_obj *ast_odbc_request_obj(const char *name, int check);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Retrieve a stored ODBC object, if a transaction has been started.
|
||||
* \param chan Channel associated with the transaction.
|
||||
* \param objname Name of the database handle. This name corresponds to the name passed
|
||||
* to ast_odbc_request_obj2 (or formerly, to ast_odbc_request_obj). Note that the
|
||||
* existence of this parameter name explicitly allows for multiple transactions to be open
|
||||
* at once, albeit to different databases.
|
||||
* \retval A stored ODBC object, if a transaction was already started.
|
||||
* \retval NULL, if no transaction yet exists.
|
||||
*/
|
||||
struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname);
|
||||
|
||||
/*!
|
||||
* \brief Releases an ODBC object previously allocated by odbc_request_obj()
|
||||
* \param obj The ODBC object
|
||||
|
|
856
res/res_odbc.c
856
res/res_odbc.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue