Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions | Variables
res_odbc_transaction.c File Reference
#include "asterisk.h"
#include "asterisk/res_odbc.h"
#include "asterisk/res_odbc_transaction.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
Include dependency graph for res_odbc_transaction.c:

Go to the source code of this file.

Data Structures

struct  odbc_txn_frame
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int acf_transaction_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_transaction_write (struct ast_channel *chan, const char *cmd, char *s, const char *value)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
struct odbc_objast_odbc_retrieve_transaction_obj (struct ast_channel *chan, const char *objname)
 Retrieve an ODBC transaction connection with the given ODBC class name. More...
 
static int commit_exec (struct ast_channel *chan, const char *data)
 
static struct odbc_txn_framecreate_transaction (struct ast_channel *chan, const char *name, const char *dsn)
 
static struct odbc_txn_framefind_transaction (struct ast_channel *chan, const char *name, int active)
 
static int load_module (void)
 
static int mark_transaction_active (struct ast_channel *chan, struct odbc_txn_frame *tx)
 
static void odbc_txn_free (void *vdata)
 
static struct odbc_txn_framerelease_transaction (struct odbc_txn_frame *tx)
 
static int rollback_exec (struct ast_channel *chan, const char *data)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "ODBC transaction resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DEPEND, }
 
static const char *const app_commit = "ODBC_Commit"
 
static const char *const app_rollback = "ODBC_Rollback"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_custom_function odbc_function
 
static const struct ast_datastore_info txn_info
 

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 530 of file res_odbc_transaction.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 530 of file res_odbc_transaction.c.

◆ acf_transaction_read()

static int acf_transaction_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 316 of file res_odbc_transaction.c.

References args, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_odbc_isolation2text(), AST_STANDARD_APP_ARGS, ast_strlen_zero, find_transaction(), odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, odbc_txn_frame::name, and NULL.

317 {
319  AST_APP_ARG(property);
320  AST_APP_ARG(opt);
321  );
322  struct odbc_txn_frame *tx;
323 
325  if (strcasecmp(args.property, "transaction") == 0) {
326  if ((tx = find_transaction(chan, NULL, 1))) {
327  ast_copy_string(buf, tx->name, len);
328  return 0;
329  }
330  } else if (strcasecmp(args.property, "isolation") == 0) {
331  if (!ast_strlen_zero(args.opt)) {
332  tx = find_transaction(chan, args.opt, 0);
333  } else {
334  tx = find_transaction(chan, NULL, 1);
335  }
336  if (tx) {
338  return 0;
339  }
340  } else if (strcasecmp(args.property, "forcecommit") == 0) {
341  if (!ast_strlen_zero(args.opt)) {
342  tx = find_transaction(chan, args.opt, 0);
343  } else {
344  tx = find_transaction(chan, NULL, 1);
345  }
346  if (tx) {
347  ast_copy_string(buf, tx->forcecommit ? "1" : "0", len);
348  return 0;
349  }
350  }
351  return -1;
352 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char name[0]
Definition: res_odbc.c:129
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, const char *name, int active)
const char * args
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
const char * ast_odbc_isolation2text(int iso)
Convert from numeric transaction isolation values to their textual counterparts.
Definition: res_odbc.c:132
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
unsigned int forcecommit
Definition: res_odbc.c:127
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
unsigned int isolation
Definition: res_odbc.c:128
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ acf_transaction_write()

static int acf_transaction_write ( struct ast_channel chan,
const char *  cmd,
char *  s,
const char *  value 
)
static

Definition at line 390 of file res_odbc_transaction.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_false(), ast_log, ast_odbc_print_errors(), ast_odbc_text2isolation(), AST_STANDARD_APP_ARGS, ast_strlen_zero, ast_true(), odbc_obj::con, create_transaction(), find_transaction(), odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, LOG_ERROR, mark_transaction_active(), NULL, odbc_txn_frame::obj, pbx_builtin_setvar_helper(), and S_OR.

391 {
393  AST_APP_ARG(property);
394  AST_APP_ARG(opt);
395  );
396  struct odbc_txn_frame *tx;
397 
399  if (strcasecmp(args.property, "transaction") == 0) {
400  /* Set active transaction */
401  if ((tx = find_transaction(chan, value, 0))) {
402  mark_transaction_active(chan, tx);
403  } else if (!create_transaction(chan, value, args.opt)) {
404  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
405  return -1;
406  }
407  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
408  return 0;
409  } else if (strcasecmp(args.property, "forcecommit") == 0) {
410  /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */
411  if (ast_strlen_zero(args.opt)) {
412  tx = find_transaction(chan, NULL, 1);
413  } else {
414  tx = find_transaction(chan, args.opt, 0);
415  }
416  if (!tx) {
417  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
418  return -1;
419  }
420  if (ast_true(value)) {
421  tx->forcecommit = 1;
422  } else if (ast_false(value)) {
423  tx->forcecommit = 0;
424  } else {
425  ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, ""));
426  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
427  return -1;
428  }
429 
430  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
431  return 0;
432  } else if (strcasecmp(args.property, "isolation") == 0) {
433  /* How do uncommitted transactions affect reads? */
434  /* XXX This is completely useless. The problem is that setting the isolation here
435  * does not actually alter the connection. The only time the isolation gets set is
436  * when the transaction is created. The only way to set isolation is to set it on
437  * the ODBC class's configuration in res_odbc.conf.
438  */
440  if (ast_strlen_zero(args.opt)) {
441  tx = find_transaction(chan, NULL, 1);
442  } else {
443  tx = find_transaction(chan, args.opt, 0);
444  }
445  if (!tx) {
446  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
447  return -1;
448  }
449  if (isolation == 0) {
450  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
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) {
453  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR");
454  ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SetConnectAttr (Txn isolation)");
455  } else {
456  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
457  tx->isolation = isolation;
458  }
459  return 0;
460  } else {
461  ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property);
462  return -1;
463  }
464 }
SQLHDBC con
Definition: res_odbc.h:47
static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx)
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, const char *name, int active)
const char * args
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
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.
Definition: res_odbc.c:524
#define LOG_ERROR
Definition: logger.h:285
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".
Definition: main/utils.c:1951
struct odbc_obj * obj
Definition: res_odbc.c:118
int ast_odbc_text2isolation(const char *txt)
Convert from textual transaction isolation values to their numeric constants.
Definition: res_odbc.c:147
static struct odbc_txn_frame * create_transaction(struct ast_channel *chan, const char *name, const char *dsn)
unsigned int forcecommit
Definition: res_odbc.c:127
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...
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
unsigned int isolation
Definition: res_odbc.c:128
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 530 of file res_odbc_transaction.c.

◆ ast_odbc_retrieve_transaction_obj()

struct odbc_obj* ast_odbc_retrieve_transaction_obj ( struct ast_channel chan,
const char *  objname 
)

Retrieve an ODBC transaction connection with the given ODBC class name.

Note
The name passed here is not the name of the transaction but the name of the ODBC class defined in res_odbc.conf.
Do not call ast_odbc_release_obj() on the retrieved connection. Calling this function does not make you the owner of the connection.

XXX This function is majorly flawed because it ignores properties of transactions and simply finds one that corresponds to the given DSN. The problem here is that transactions have names and they maintain which transaction is "active" for operations like transaction creation, commit, and rollback. However, when it comes to intermediary operations to be made on the transactions, all that is ignored. It means that if a channel has created multiple transactions for the same DSN, it's a crapshoot which of those transactions the operation will be performed on. This can potentially lead to baffling errors under the right circumstances.

XXX The semantics of this function make for writing some awkward code. If you use func_odbc as an example, it has to first try to retrieve a transactional connection, then failing that, create a non-transactional connection. The result is that it has to remember which type of connection it's using and know whether to release the connection when completed or not. It would be much better if callers did not have to jump through such hoops.

Parameters
chanChannel on which the ODBC transaction was created
objnameThe name of the ODBC class configured in res_odbc.conf
Return values
NULLTransaction connection could not be found.
non-NULLA transactional connection

Definition at line 466 of file res_odbc_transaction.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_odbc_class_get_name(), ast_datastore::data, odbc_txn_frame::list, NULL, odbc_txn_frame::obj, and odbc_obj::parent.

Referenced by acf_odbc_write().

467 {
468  struct ast_datastore *txn_store;
469  AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
470  struct odbc_txn_frame *txn = NULL;
471 
472  if (!chan || !objname) {
473  /* No channel == no transaction */
474  return NULL;
475  }
476 
477  ast_channel_lock(chan);
478  if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
479  oldlist = txn_store->data;
480  } else {
481  ast_channel_unlock(chan);
482  return NULL;
483  }
484 
485  AST_LIST_LOCK(oldlist);
486  ast_channel_unlock(chan);
487 
488  AST_LIST_TRAVERSE(oldlist, txn, list) {
489  if (txn->obj && txn->obj->parent && !strcmp(ast_odbc_class_get_name(txn->obj->parent), objname)) {
490  AST_LIST_UNLOCK(oldlist);
491  return txn->obj;
492  }
493  }
494  AST_LIST_UNLOCK(oldlist);
495  return NULL;
496 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Structure for a data store object.
Definition: datastore.h:68
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.
Definition: channel.c:2404
#define NULL
Definition: resample.c:96
struct odbc_class * parent
Definition: res_odbc.h:48
static const struct ast_datastore_info txn_info
struct odbc_obj * obj
Definition: res_odbc.c:118
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70
struct odbc_txn_frame::@470 list
const char * ast_odbc_class_get_name(struct odbc_class *class)
Get the name of an ODBC class.
Definition: res_odbc.c:559

◆ commit_exec()

static int commit_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 272 of file res_odbc_transaction.c.

References ast_odbc_print_errors(), ast_str_buffer(), ast_strlen_zero, odbc_obj::con, find_transaction(), NULL, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().

Referenced by load_module().

273 {
274  struct odbc_txn_frame *tx;
275 
276  if (ast_strlen_zero(data)) {
277  tx = find_transaction(chan, NULL, 1);
278  } else {
279  tx = find_transaction(chan, data, 0);
280  }
281 
282  /* XXX COMMIT_RESULT is set to OK even if no transaction was found. Very misleading */
283  pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK");
284 
285  if (tx) {
286  if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) {
287  struct ast_str *errors = ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran");
288  pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
289  }
290  }
291  return 0;
292 }
SQLHDBC con
Definition: res_odbc.h:47
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, const char *name, int active)
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
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.
Definition: res_odbc.c:524
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
struct odbc_obj * obj
Definition: res_odbc.c:118
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...

◆ create_transaction()

static struct odbc_txn_frame* create_transaction ( struct ast_channel chan,
const char *  name,
const char *  dsn 
)
static

Definition at line 133 of file res_odbc_transaction.c.

References odbc_txn_frame::active, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_free, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_odbc_class_get_forcecommit(), ast_odbc_class_get_isolation(), ast_odbc_print_errors(), ast_odbc_release_obj(), ast_odbc_request_obj, ast_strlen_zero, odbc_obj::con, ast_datastore::data, odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, odbc_txn_frame::list, LOG_ERROR, odbc_txn_frame::name, NULL, odbc_txn_frame::obj, and odbc_obj::parent.

Referenced by acf_transaction_write().

134 {
135  struct ast_datastore *txn_store;
136  AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
137  struct odbc_txn_frame *txn = NULL;
138  struct odbc_txn_frame *otxn;
139 
140  if (ast_strlen_zero(dsn)) {
141  return NULL;
142  }
143 
144  ast_channel_lock(chan);
145  if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
146  oldlist = txn_store->data;
147  } else {
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);
151  return NULL;
152  }
153 
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");
156  ast_datastore_free(txn_store);
157  ast_channel_unlock(chan);
158  return NULL;
159  }
160 
161  txn_store->data = oldlist;
162  AST_LIST_HEAD_INIT(oldlist);
163  ast_channel_datastore_add(chan, txn_store);
164  }
165  ast_channel_unlock(chan);
166 
167  txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1);
168  if (!txn) {
169  return NULL;
170  }
171 
172  strcpy(txn->name, name); /* SAFE */
173  txn->obj = ast_odbc_request_obj(dsn, 0);
174  if (!txn->obj) {
175  ast_free(txn);
176  return NULL;
177  }
180  txn->active = 1;
181 
182  if (SQLSetConnectAttr(txn->obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
183  ast_odbc_print_errors(SQL_HANDLE_DBC, txn->obj->con, "SetConnectAttr (Autocommit)");
185  ast_free(txn);
186  return NULL;
187  }
188 
189  /* Set the isolation property */
190  if (SQLSetConnectAttr(txn->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)txn->isolation, 0) == SQL_ERROR) {
191  ast_odbc_print_errors(SQL_HANDLE_DBC, txn->obj->con, "SetConnectAttr");
193  ast_free(txn);
194  return NULL;
195  }
196 
197  /* On creation, the txn becomes active, and all others inactive */
198  AST_LIST_LOCK(oldlist);
199  AST_LIST_TRAVERSE(oldlist, otxn, list) {
200  otxn->active = 0;
201  }
202  AST_LIST_INSERT_TAIL(oldlist, txn, list);
203  AST_LIST_UNLOCK(oldlist);
204 
205  return txn;
206 }
SQLHDBC con
Definition: res_odbc.h:47
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
unsigned int active
Is this record the current active transaction within the channel? Note that the active flag is really...
Definition: res_odbc.c:126
char name[0]
Definition: res_odbc.c:129
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Definition: func_odbc.c:150
Structure for a data store object.
Definition: datastore.h:68
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.
Definition: channel.c:2404
#define NULL
Definition: resample.c:96
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
unsigned int ast_odbc_class_get_isolation(struct odbc_class *class)
Get the transaction isolation setting for an ODBC class.
Definition: res_odbc.c:549
struct odbc_class * parent
Definition: res_odbc.h:48
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.
Definition: res_odbc.c:524
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
static const struct ast_datastore_info txn_info
struct odbc_obj * obj
Definition: res_odbc.c:118
unsigned int ast_odbc_class_get_forcecommit(struct odbc_class *class)
Get the transaction forcecommit setting for an ODBC class.
Definition: res_odbc.c:554
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static const char name[]
Definition: cdr_mysql.c:74
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:625
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:122
unsigned int forcecommit
Definition: res_odbc.c:127
void * data
Definition: datastore.h:70
unsigned int isolation
Definition: res_odbc.c:128
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
struct odbc_txn_frame::@470 list
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:813
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390

◆ find_transaction()

static struct odbc_txn_frame* find_transaction ( struct ast_channel chan,
const char *  name,
int  active 
)
static

Definition at line 208 of file res_odbc_transaction.c.

References odbc_txn_frame::active, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_txn_frame::list, odbc_txn_frame::name, and NULL.

Referenced by acf_transaction_read(), acf_transaction_write(), commit_exec(), and rollback_exec().

209 {
210  struct ast_datastore *txn_store;
211  AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
212  struct odbc_txn_frame *txn = NULL;
213 
214  if (!chan || (!active && !name)) {
215  return NULL;
216  }
217 
218  ast_channel_lock(chan);
219  txn_store = ast_channel_datastore_find(chan, &txn_info, NULL);
220  ast_channel_unlock(chan);
221 
222  if (!txn_store) {
223  /* No datastore? Definitely no transaction then */
224  return NULL;
225  }
226 
227  oldlist = txn_store->data;
228  AST_LIST_LOCK(oldlist);
229 
230  AST_LIST_TRAVERSE(oldlist, txn, list) {
231  if (active) {
232  if (txn->active) {
233  break;
234  }
235  } else if (!strcasecmp(txn->name, name)) {
236  break;
237  }
238  }
239  AST_LIST_UNLOCK(oldlist);
240 
241  return txn;
242 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
unsigned int active
Is this record the current active transaction within the channel? Note that the active flag is really...
Definition: res_odbc.c:126
char name[0]
Definition: res_odbc.c:129
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Structure for a data store object.
Definition: datastore.h:68
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.
Definition: channel.c:2404
#define NULL
Definition: resample.c:96
static const struct ast_datastore_info txn_info
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static const char name[]
Definition: cdr_mysql.c:74
void * data
Definition: datastore.h:70
struct odbc_txn_frame::@470 list

◆ load_module()

static int load_module ( void  )
static

Definition at line 517 of file res_odbc_transaction.c.

References app_commit, app_rollback, ast_custom_function_register, AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_REALTIME_DEPEND, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ast_register_application_xml, ASTERISK_GPL_KEY, commit_exec(), rollback_exec(), and unload_module().

518 {
522  return 0;
523 }
static const char *const app_commit
static int commit_exec(struct ast_channel *chan, const char *data)
static int rollback_exec(struct ast_channel *chan, const char *data)
static struct ast_custom_function odbc_function
static const char *const app_rollback
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ mark_transaction_active()

static int mark_transaction_active ( struct ast_channel chan,
struct odbc_txn_frame tx 
)
static

Definition at line 359 of file res_odbc_transaction.c.

References odbc_txn_frame::active, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_txn_frame::list, and NULL.

Referenced by acf_transaction_write().

360 {
361  struct ast_datastore *txn_store;
362  AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
363  struct odbc_txn_frame *active = NULL, *txn;
364 
365  if (!chan) {
366  return -1;
367  }
368 
369  ast_channel_lock(chan);
370  if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
371  ast_channel_unlock(chan);
372  return -1;
373  }
374 
375  oldlist = txn_store->data;
376  AST_LIST_LOCK(oldlist);
377  AST_LIST_TRAVERSE(oldlist, txn, list) {
378  if (txn == tx) {
379  txn->active = 1;
380  active = txn;
381  } else {
382  txn->active = 0;
383  }
384  }
385  AST_LIST_UNLOCK(oldlist);
386  ast_channel_unlock(chan);
387  return active ? 0 : -1;
388 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
unsigned int active
Is this record the current active transaction within the channel? Note that the active flag is really...
Definition: res_odbc.c:126
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Structure for a data store object.
Definition: datastore.h:68
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.
Definition: channel.c:2404
#define NULL
Definition: resample.c:96
static const struct ast_datastore_info txn_info
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70
struct odbc_txn_frame::@470 list

◆ odbc_txn_free()

static void odbc_txn_free ( void *  vdata)
static

Definition at line 112 of file res_odbc_transaction.c.

References ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, odbc_txn_frame::list, and release_transaction().

113 {
114  struct odbc_txn_frame *tx;
115  AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata;
116 
117  ast_debug(2, "odbc_txn_free(%p) called\n", vdata);
118 
119  AST_LIST_LOCK(oldlist);
120  while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) {
122  }
123  AST_LIST_UNLOCK(oldlist);
124  AST_LIST_HEAD_DESTROY(oldlist);
125  ast_free(oldlist);
126 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static struct odbc_txn_frame * release_transaction(struct odbc_txn_frame *tx)
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:652
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define ast_free(a)
Definition: astmm.h:182
struct odbc_txn_frame::@470 list

◆ release_transaction()

static struct odbc_txn_frame * release_transaction ( struct odbc_txn_frame tx)
static

Definition at line 244 of file res_odbc_transaction.c.

References ast_debug, ast_free, ast_odbc_print_errors(), ast_odbc_release_obj(), odbc_obj::con, odbc_txn_frame::forcecommit, NULL, and odbc_txn_frame::obj.

Referenced by odbc_txn_free().

245 {
246  if (!tx) {
247  return NULL;
248  }
249 
250  ast_debug(2, "release_transaction(%p) called (tx->obj = %p\n", tx, tx->obj);
251 
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) {
254  ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran");
255  }
256 
257  /* Transaction is done, reset autocommit
258  *
259  * XXX I'm unsure if this is actually necessary, since we're releasing
260  * the connection back to unixODBC. However, if unixODBC pooling is enabled,
261  * it can't hurt to do just in case.
262  */
263  if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
264  ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLSetAttr");
265  }
266 
268  ast_free(tx);
269  return NULL;
270 }
SQLHDBC con
Definition: res_odbc.h:47
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
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.
Definition: res_odbc.c:524
struct odbc_obj * obj
Definition: res_odbc.c:118
#define ast_free(a)
Definition: astmm.h:182
unsigned int forcecommit
Definition: res_odbc.c:127
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:813

◆ rollback_exec()

static int rollback_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 294 of file res_odbc_transaction.c.

References ast_odbc_print_errors(), ast_str_buffer(), ast_strlen_zero, odbc_obj::con, find_transaction(), NULL, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().

Referenced by load_module().

295 {
296  struct odbc_txn_frame *tx;
297 
298  if (ast_strlen_zero(data)) {
299  tx = find_transaction(chan, NULL, 1);
300  } else {
301  tx = find_transaction(chan, data, 0);
302  }
303 
304  /* XXX ROLLBACK_RESULT is set to OK even if no transaction was found. Very misleading */
305  pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK");
306 
307  if (tx) {
308  if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) {
309  struct ast_str *errors = ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran");
310  pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
311  }
312  }
313  return 0;
314 }
SQLHDBC con
Definition: res_odbc.h:47
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, const char *name, int active)
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
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.
Definition: res_odbc.c:524
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
struct odbc_obj * obj
Definition: res_odbc.c:118
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...

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 512 of file res_odbc_transaction.c.

Referenced by load_module().

513 {
514  return -1;
515 }

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "ODBC transaction resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DEPEND, }
static

Definition at line 530 of file res_odbc_transaction.c.

◆ app_commit

const char* const app_commit = "ODBC_Commit"
static

Definition at line 504 of file res_odbc_transaction.c.

Referenced by load_module().

◆ app_rollback

const char* const app_rollback = "ODBC_Rollback"
static

Definition at line 505 of file res_odbc_transaction.c.

Referenced by load_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 530 of file res_odbc_transaction.c.

◆ odbc_function

struct ast_custom_function odbc_function
static
Initial value:
= {
.name = "ODBC",
}
static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)

Definition at line 498 of file res_odbc_transaction.c.

◆ txn_info

const struct ast_datastore_info txn_info
static
Initial value:
= {
.type = "ODBC_Transaction",
.destroy = odbc_txn_free,
}
static void odbc_txn_free(void *vdata)

Definition at line 128 of file res_odbc_transaction.c.