22 #include "asterisk/res_odbc_transaction.h"
112 static
void odbc_txn_free(
void *vdata)
117 ast_debug(2,
"odbc_txn_free(%p) called\n", vdata);
121 release_transaction(tx);
129 .
type =
"ODBC_Transaction",
130 .destroy = odbc_txn_free,
140 if (ast_strlen_zero(dsn)) {
144 ast_channel_lock(chan);
146 oldlist = txn_store->
data;
148 if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) {
149 ast_log(LOG_ERROR,
"Unable to allocate a new datastore. Cannot create a new transaction.\n");
150 ast_channel_unlock(chan);
154 if (!(oldlist =
ast_calloc(1,
sizeof(*oldlist)))) {
155 ast_log(LOG_ERROR,
"Unable to allocate datastore list head. Cannot create a new transaction.\n");
157 ast_channel_unlock(chan);
161 txn_store->
data = oldlist;
165 ast_channel_unlock(chan);
167 txn =
ast_calloc(1,
sizeof(*txn) + strlen(name) + 1);
172 strcpy(txn->
name, name);
182 if (SQLSetConnectAttr(txn->
obj->
con, SQL_ATTR_AUTOCOMMIT, (
void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
190 if (SQLSetConnectAttr(txn->
obj->
con, SQL_ATTR_TXN_ISOLATION, (
void *)(
long)txn->
isolation, 0) == SQL_ERROR) {
214 if (!chan || (!active && !name)) {
218 ast_channel_lock(chan);
220 ast_channel_unlock(chan);
227 oldlist = txn_store->
data;
235 }
else if (!strcasecmp(txn->
name, name)) {
250 ast_debug(2,
"release_transaction(%p) called (tx->obj = %p\n", tx, tx->
obj);
252 ast_debug(1,
"called on a transactional handle with %s\n", tx->
forcecommit ?
"COMMIT" :
"ROLLBACK");
253 if (SQLEndTran(SQL_HANDLE_DBC, tx->
obj->
con, tx->
forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
263 if (SQLSetConnectAttr(tx->
obj->
con, SQL_ATTR_AUTOCOMMIT, (
void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
272 static int commit_exec(
struct ast_channel *chan,
const char *data)
276 if (ast_strlen_zero(data)) {
277 tx = find_transaction(chan, NULL, 1);
279 tx = find_transaction(chan, data, 0);
286 if (SQLEndTran(SQL_HANDLE_DBC, tx->
obj->
con, SQL_COMMIT) == SQL_ERROR) {
294 static int rollback_exec(
struct ast_channel *chan,
const char *data)
298 if (ast_strlen_zero(data)) {
299 tx = find_transaction(chan, NULL, 1);
301 tx = find_transaction(chan, data, 0);
308 if (SQLEndTran(SQL_HANDLE_DBC, tx->
obj->
con, SQL_ROLLBACK) == SQL_ERROR) {
316 static int acf_transaction_read(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
325 if (strcasecmp(args.property,
"transaction") == 0) {
326 if ((tx = find_transaction(chan, NULL, 1))) {
330 }
else if (strcasecmp(args.property,
"isolation") == 0) {
331 if (!ast_strlen_zero(args.opt)) {
332 tx = find_transaction(chan, args.opt, 0);
334 tx = find_transaction(chan, NULL, 1);
340 }
else if (strcasecmp(args.property,
"forcecommit") == 0) {
341 if (!ast_strlen_zero(args.opt)) {
342 tx = find_transaction(chan, args.opt, 0);
344 tx = find_transaction(chan, NULL, 1);
369 ast_channel_lock(chan);
371 ast_channel_unlock(chan);
375 oldlist = txn_store->
data;
386 ast_channel_unlock(chan);
387 return active ? 0 : -1;
390 static int acf_transaction_write(
struct ast_channel *chan,
const char *cmd,
char *s,
const char *value)
399 if (strcasecmp(args.property,
"transaction") == 0) {
401 if ((tx = find_transaction(chan, value, 0))) {
402 mark_transaction_active(chan, tx);
403 }
else if (!create_transaction(chan, value, args.opt)) {
409 }
else if (strcasecmp(args.property,
"forcecommit") == 0) {
411 if (ast_strlen_zero(args.opt)) {
412 tx = find_transaction(chan, NULL, 1);
414 tx = find_transaction(chan, args.opt, 0);
425 ast_log(LOG_ERROR,
"Invalid value for forcecommit: '%s'\n",
S_OR(value,
""));
432 }
else if (strcasecmp(args.property,
"isolation") == 0) {
440 if (ast_strlen_zero(args.opt)) {
441 tx = find_transaction(chan, NULL, 1);
443 tx = find_transaction(chan, args.opt, 0);
449 if (isolation == 0) {
451 ast_log(LOG_ERROR,
"Invalid isolation specification: '%s'\n",
S_OR(value,
""));
452 }
else if (SQLSetConnectAttr(tx->
obj->
con, SQL_ATTR_TXN_ISOLATION, (
void *)(
long)isolation, 0) == SQL_ERROR) {
461 ast_log(LOG_ERROR,
"Unknown property: '%s'\n", args.property);
466 struct odbc_obj *ast_odbc_retrieve_transaction_obj(
struct ast_channel *chan,
const char *objname)
472 if (!chan || !objname) {
477 ast_channel_lock(chan);
479 oldlist = txn_store->
data;
481 ast_channel_unlock(chan);
486 ast_channel_unlock(chan);
500 .read = acf_transaction_read,
501 .write = acf_transaction_write,
504 static const char *
const app_commit =
"ODBC_Commit";
505 static const char *
const app_rollback =
"ODBC_Rollback";
512 static int unload_module(
void)
517 static int load_module(
void)
525 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"ODBC transaction resource",
526 .support_level = AST_MODULE_SUPPORT_CORE,
528 .unload = unload_module,
Main Channel structure associated with a channel.
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
unsigned int active
Is this record the current active transaction within the channel? Note that the active flag is really...
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Structure for a data store type.
Structure for a data store object.
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
unsigned int ast_odbc_class_get_isolation(struct odbc_class *class)
Get the transaction isolation setting for an ODBC class.
General Asterisk PBX channel definitions.
Data structure associated with a custom dialplan function.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
const char * ast_odbc_isolation2text(int iso)
Convert from numeric transaction isolation values to their textual counterparts.
struct odbc_class * parent
Core PBX routines and definitions.
struct ast_str * ast_odbc_print_errors(SQLSMALLINT handle_type, SQLHANDLE handle, const char *operation)
Shortcut for printing errors to logs after a failed SQL operation.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Support for dynamic strings.
int ast_odbc_text2isolation(const char *txt)
Convert from textual transaction isolation values to their numeric constants.
unsigned int ast_odbc_class_get_forcecommit(struct odbc_class *class)
Get the transaction forcecommit setting for an ODBC class.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
#define ast_calloc(num, len)
A wrapper for calloc()
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
const char * ast_odbc_class_get_name(struct odbc_class *class)
Get the name of an ODBC class.
#define AST_APP_ARG(name)
Define an application argument.