Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 = AST_BUILDOPT_SUM, .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.

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))) {
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
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
const char * ast_odbc_isolation2text(int iso)
Convert from numeric transaction isolation values to their textual counterparts.
Definition: res_odbc.c:132
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, const char *name, int active)
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char name[0]
Definition: res_odbc.c:129
unsigned int isolation
Definition: res_odbc.c:128
unsigned int forcecommit
Definition: res_odbc.c:127
const char * args

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

◆ 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.

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}
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
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.
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:515
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)
static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216
SQLHDBC con
Definition: res_odbc.h:47
struct odbc_obj * obj
Definition: res_odbc.c:118
int value
Definition: syslog.c:37

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(), S_OR, and value.

◆ 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.

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:2968
#define ast_channel_unlock(chan)
Definition: channel.h:2969
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:2418
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
const char * ast_odbc_class_get_name(struct odbc_class *class)
Get the name of an ODBC class.
Definition: res_odbc.c:550
static const struct ast_datastore_info txn_info
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
struct odbc_class * parent
Definition: res_odbc.h:48
struct odbc_txn_frame::@443 list

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, odbc_obj::parent, and txn_info.

Referenced by acf_odbc_write().

◆ commit_exec()

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

Definition at line 272 of file res_odbc_transaction.c.

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}
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
Support for dynamic strings.
Definition: strings.h:623

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().

◆ 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.

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}
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2404
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
static const char name[]
Definition: format_mp3.c:68
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
unsigned int ast_odbc_class_get_isolation(struct odbc_class *class)
Get the transaction isolation setting for an ODBC class.
Definition: res_odbc.c:540
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:804
unsigned int ast_odbc_class_get_forcecommit(struct odbc_class *class)
Get the transaction forcecommit setting for an ODBC class.
Definition: res_odbc.c:545
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
Definition: res_odbc.h:120
Data source name.
Definition: func_odbc.c:167
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

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, name, NULL, odbc_txn_frame::obj, odbc_obj::parent, and txn_info.

Referenced by acf_transaction_write().

◆ 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.

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}

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, name, NULL, and txn_info.

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

◆ load_module()

static int load_module ( void  )
static

Definition at line 517 of file res_odbc_transaction.c.

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

References app_commit, app_rollback, ast_custom_function_register, ast_register_application_xml, commit_exec(), odbc_function, and rollback_exec().

◆ 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.

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}

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, NULL, and txn_info.

Referenced by acf_transaction_write().

◆ odbc_txn_free()

static void odbc_txn_free ( void *  vdata)
static

Definition at line 112 of file res_odbc_transaction.c.

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_debug(level,...)
Log a DEBUG message.
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
static struct odbc_txn_frame * release_transaction(struct odbc_txn_frame *tx)

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().

◆ 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.

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}

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().

◆ rollback_exec()

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

Definition at line 294 of file res_odbc_transaction.c.

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}

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().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 512 of file res_odbc_transaction.c.

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 = AST_BUILDOPT_SUM, .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_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)

Definition at line 498 of file res_odbc_transaction.c.

Referenced by load_module().

◆ 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.

Referenced by ast_odbc_retrieve_transaction_obj(), create_transaction(), find_transaction(), and mark_transaction_active().