Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 539 of file res_odbc_transaction.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 539 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 325 of file res_odbc_transaction.c.

326{
328 AST_APP_ARG(property);
329 AST_APP_ARG(opt);
330 );
331 struct odbc_txn_frame *tx;
332
334 if (strcasecmp(args.property, "transaction") == 0) {
335 if ((tx = find_transaction(chan, NULL, 1))) {
337 return 0;
338 }
339 } else if (strcasecmp(args.property, "isolation") == 0) {
340 if (!ast_strlen_zero(args.opt)) {
341 tx = find_transaction(chan, args.opt, 0);
342 } else {
343 tx = find_transaction(chan, NULL, 1);
344 }
345 if (tx) {
347 return 0;
348 }
349 } else if (strcasecmp(args.property, "forcecommit") == 0) {
350 if (!ast_strlen_zero(args.opt)) {
351 tx = find_transaction(chan, args.opt, 0);
352 } else {
353 tx = find_transaction(chan, NULL, 1);
354 }
355 if (tx) {
356 ast_copy_string(buf, tx->forcecommit ? "1" : "0", len);
357 return 0;
358 }
359 }
360 return -1;
361}
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 399 of file res_odbc_transaction.c.

400{
402 AST_APP_ARG(property);
403 AST_APP_ARG(opt);
404 );
405 struct odbc_txn_frame *tx;
406
408 if (strcasecmp(args.property, "transaction") == 0) {
409 /* Set active transaction */
410 if ((tx = find_transaction(chan, value, 0))) {
411 mark_transaction_active(chan, tx);
412 } else if (!create_transaction(chan, value, args.opt)) {
413 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
414 return -1;
415 }
416 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
417 return 0;
418 } else if (strcasecmp(args.property, "forcecommit") == 0) {
419 /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */
420 if (ast_strlen_zero(args.opt)) {
421 tx = find_transaction(chan, NULL, 1);
422 } else {
423 tx = find_transaction(chan, args.opt, 0);
424 }
425 if (!tx) {
426 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
427 return -1;
428 }
429 if (ast_true(value)) {
430 tx->forcecommit = 1;
431 } else if (ast_false(value)) {
432 tx->forcecommit = 0;
433 } else {
434 ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, ""));
435 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
436 return -1;
437 }
438
439 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
440 return 0;
441 } else if (strcasecmp(args.property, "isolation") == 0) {
442 /* How do uncommitted transactions affect reads? */
443 /* XXX This is completely useless. The problem is that setting the isolation here
444 * does not actually alter the connection. The only time the isolation gets set is
445 * when the transaction is created. The only way to set isolation is to set it on
446 * the ODBC class's configuration in res_odbc.conf.
447 */
449 if (ast_strlen_zero(args.opt)) {
450 tx = find_transaction(chan, NULL, 1);
451 } else {
452 tx = find_transaction(chan, args.opt, 0);
453 }
454 if (!tx) {
455 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
456 return -1;
457 }
458 if (isolation == 0) {
459 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
460 ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, ""));
461 } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) {
462 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR");
463 ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SetConnectAttr (Txn isolation)");
464 } else {
465 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
466 tx->isolation = isolation;
467 }
468 return 0;
469 } else {
470 ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property);
471 return -1;
472 }
473}
#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 539 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 475 of file res_odbc_transaction.c.

476{
477 struct ast_datastore *txn_store;
478 AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
479 struct odbc_txn_frame *txn = NULL;
480
481 if (!chan || !objname) {
482 /* No channel == no transaction */
483 return NULL;
484 }
485
486 ast_channel_lock(chan);
487 if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
488 oldlist = txn_store->data;
489 } else {
490 ast_channel_unlock(chan);
491 return NULL;
492 }
493
494 AST_LIST_LOCK(oldlist);
495 ast_channel_unlock(chan);
496
497 AST_LIST_TRAVERSE(oldlist, txn, list) {
498 if (txn->obj && txn->obj->parent && !strcmp(ast_odbc_class_get_name(txn->obj->parent), objname)) {
499 AST_LIST_UNLOCK(oldlist);
500 return txn->obj;
501 }
502 }
503 AST_LIST_UNLOCK(oldlist);
504 return NULL;
505}
#define ast_channel_lock(chan)
Definition: channel.h:2972
#define ast_channel_unlock(chan)
Definition: channel.h:2973
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:2368
#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::@446 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 281 of file res_odbc_transaction.c.

282{
283 struct odbc_txn_frame *tx;
284
285 if (ast_strlen_zero(data)) {
286 tx = find_transaction(chan, NULL, 1);
287 } else {
288 tx = find_transaction(chan, data, 0);
289 }
290
291 /* XXX COMMIT_RESULT is set to OK even if no transaction was found. Very misleading */
292 pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK");
293
294 if (tx) {
295 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) {
296 struct ast_str *errors = ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran");
297 pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
298 }
299 }
300 return 0;
301}
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 142 of file res_odbc_transaction.c.

143{
144 struct ast_datastore *txn_store;
145 AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
146 struct odbc_txn_frame *txn = NULL;
147 struct odbc_txn_frame *otxn;
148
149 if (ast_strlen_zero(dsn)) {
150 return NULL;
151 }
152
153 ast_channel_lock(chan);
154 if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
155 oldlist = txn_store->data;
156 } else {
157 if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) {
158 ast_log(LOG_ERROR, "Unable to allocate a new datastore. Cannot create a new transaction.\n");
159 ast_channel_unlock(chan);
160 return NULL;
161 }
162
163 if (!(oldlist = ast_calloc(1, sizeof(*oldlist)))) {
164 ast_log(LOG_ERROR, "Unable to allocate datastore list head. Cannot create a new transaction.\n");
165 ast_datastore_free(txn_store);
166 ast_channel_unlock(chan);
167 return NULL;
168 }
169
170 txn_store->data = oldlist;
171 AST_LIST_HEAD_INIT(oldlist);
172 ast_channel_datastore_add(chan, txn_store);
173 }
174 ast_channel_unlock(chan);
175
176 txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1);
177 if (!txn) {
178 return NULL;
179 }
180
181 strcpy(txn->name, name); /* SAFE */
182 txn->obj = ast_odbc_request_obj(dsn, 0);
183 if (!txn->obj) {
184 ast_free(txn);
185 return NULL;
186 }
189 txn->active = 1;
190
191 if (SQLSetConnectAttr(txn->obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
192 ast_odbc_print_errors(SQL_HANDLE_DBC, txn->obj->con, "SetConnectAttr (Autocommit)");
194 ast_free(txn);
195 return NULL;
196 }
197
198 /* Set the isolation property */
199 if (SQLSetConnectAttr(txn->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)txn->isolation, 0) == SQL_ERROR) {
200 ast_odbc_print_errors(SQL_HANDLE_DBC, txn->obj->con, "SetConnectAttr");
202 ast_free(txn);
203 return NULL;
204 }
205
206 /* On creation, the txn becomes active, and all others inactive */
207 AST_LIST_LOCK(oldlist);
208 AST_LIST_TRAVERSE(oldlist, otxn, list) {
209 otxn->active = 0;
210 }
211 AST_LIST_INSERT_TAIL(oldlist, txn, list);
212 AST_LIST_UNLOCK(oldlist);
213
214 return txn;
215}
#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:2354
#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:181
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 217 of file res_odbc_transaction.c.

218{
219 struct ast_datastore *txn_store;
220 AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
221 struct odbc_txn_frame *txn = NULL;
222
223 if (!chan || (!active && !name)) {
224 return NULL;
225 }
226
227 ast_channel_lock(chan);
228 txn_store = ast_channel_datastore_find(chan, &txn_info, NULL);
229 ast_channel_unlock(chan);
230
231 if (!txn_store) {
232 /* No datastore? Definitely no transaction then */
233 return NULL;
234 }
235
236 oldlist = txn_store->data;
237 AST_LIST_LOCK(oldlist);
238
239 AST_LIST_TRAVERSE(oldlist, txn, list) {
240 if (active) {
241 if (txn->active) {
242 break;
243 }
244 } else if (!strcasecmp(txn->name, name)) {
245 break;
246 }
247 }
248 AST_LIST_UNLOCK(oldlist);
249
250 return txn;
251}

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 526 of file res_odbc_transaction.c.

527{
531 return 0;
532}
#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:1559
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 368 of file res_odbc_transaction.c.

369{
370 struct ast_datastore *txn_store;
371 AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
372 struct odbc_txn_frame *active = NULL, *txn;
373
374 if (!chan) {
375 return -1;
376 }
377
378 ast_channel_lock(chan);
379 if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
380 ast_channel_unlock(chan);
381 return -1;
382 }
383
384 oldlist = txn_store->data;
385 AST_LIST_LOCK(oldlist);
386 AST_LIST_TRAVERSE(oldlist, txn, list) {
387 if (txn == tx) {
388 txn->active = 1;
389 active = txn;
390 } else {
391 txn->active = 0;
392 }
393 }
394 AST_LIST_UNLOCK(oldlist);
395 ast_channel_unlock(chan);
396 return active ? 0 : -1;
397}

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 121 of file res_odbc_transaction.c.

122{
123 struct odbc_txn_frame *tx;
124 AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata;
125
126 ast_debug(2, "odbc_txn_free(%p) called\n", vdata);
127
128 AST_LIST_LOCK(oldlist);
129 while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) {
131 }
132 AST_LIST_UNLOCK(oldlist);
133 AST_LIST_HEAD_DESTROY(oldlist);
134 ast_free(oldlist);
135}
#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 253 of file res_odbc_transaction.c.

254{
255 if (!tx) {
256 return NULL;
257 }
258
259 ast_debug(2, "release_transaction(%p) called (tx->obj = %p\n", tx, tx->obj);
260
261 ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK");
262 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
263 ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran");
264 }
265
266 /* Transaction is done, reset autocommit
267 *
268 * XXX I'm unsure if this is actually necessary, since we're releasing
269 * the connection back to unixODBC. However, if unixODBC pooling is enabled,
270 * it can't hurt to do just in case.
271 */
272 if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
273 ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLSetAttr");
274 }
275
277 ast_free(tx);
278 return NULL;
279}

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 303 of file res_odbc_transaction.c.

304{
305 struct odbc_txn_frame *tx;
306
307 if (ast_strlen_zero(data)) {
308 tx = find_transaction(chan, NULL, 1);
309 } else {
310 tx = find_transaction(chan, data, 0);
311 }
312
313 /* XXX ROLLBACK_RESULT is set to OK even if no transaction was found. Very misleading */
314 pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK");
315
316 if (tx) {
317 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) {
318 struct ast_str *errors = ast_odbc_print_errors(SQL_HANDLE_DBC, tx->obj->con, "SQLEndTran");
319 pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
320 }
321 }
322 return 0;
323}

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 521 of file res_odbc_transaction.c.

522{
523 return -1;
524}

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 539 of file res_odbc_transaction.c.

◆ app_commit

const char* const app_commit = "ODBC_Commit"
static

Definition at line 513 of file res_odbc_transaction.c.

Referenced by load_module().

◆ app_rollback

const char* const app_rollback = "ODBC_Rollback"
static

Definition at line 514 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 539 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 507 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 137 of file res_odbc_transaction.c.

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