Asterisk - The Open Source Telephony Project  18.5.0
res_odbc_transaction.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2016, Digium, Inc.
5  *
6  * Mark Michelson <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 #include "asterisk.h"
20 
21 #include "asterisk/res_odbc.h"
23 #include "asterisk/channel.h"
24 #include "asterisk/pbx.h"
25 #include "asterisk/app.h"
26 #include "asterisk/module.h"
27 
28 /*** MODULEINFO
29  <depend>generic_odbc</depend>
30  <support_level>core</support_level>
31  ***/
32 
33 /*** DOCUMENTATION
34  <function name="ODBC" language="en_US">
35  <synopsis>
36  Controls ODBC transaction properties.
37  </synopsis>
38  <syntax>
39  <parameter name="property" required="true">
40  <enumlist>
41  <enum name="transaction">
42  <para>Gets or sets the active transaction ID. If set, and the transaction ID does not
43  exist and a <replaceable>database name</replaceable> is specified as an argument, it will be created.</para>
44  </enum>
45  <enum name="forcecommit">
46  <para>Controls whether a transaction will be automatically committed when the channel
47  hangs up. Defaults to forcecommit value from the relevant DSN (which defaults to false).
48  If a <replaceable>transaction ID</replaceable> is specified in the optional argument,
49  the property will be applied to that ID, otherwise to the current active ID.</para>
50  </enum>
51  <enum name="isolation">
52  <para>Controls the data isolation on uncommitted transactions. May be one of the
53  following: <literal>read_committed</literal>, <literal>read_uncommitted</literal>,
54  <literal>repeatable_read</literal>, or <literal>serializable</literal>. Defaults to the
55  database setting in <filename>res_odbc.conf</filename> or <literal>read_committed</literal>
56  if not specified. If a <replaceable>transaction ID</replaceable> is specified as an optional argument, it will be
57  applied to that ID, otherwise the current active ID.</para>
58  </enum>
59  </enumlist>
60  </parameter>
61  <parameter name="argument" required="false" />
62  </syntax>
63  <description>
64  <para>The ODBC() function allows setting several properties to influence how a connected
65  database processes transactions.</para>
66  </description>
67  </function>
68  <application name="ODBC_Commit" language="en_US">
69  <synopsis>
70  Commits a currently open database transaction.
71  </synopsis>
72  <syntax>
73  <parameter name="transaction ID" required="no" />
74  </syntax>
75  <description>
76  <para>Commits the database transaction specified by <replaceable>transaction ID</replaceable>
77  or the current active transaction, if not specified.</para>
78  </description>
79  </application>
80  <application name="ODBC_Rollback" language="en_US">
81  <synopsis>
82  Rollback a currently open database transaction.
83  </synopsis>
84  <syntax>
85  <parameter name="transaction ID" required="no" />
86  </syntax>
87  <description>
88  <para>Rolls back the database transaction specified by <replaceable>transaction ID</replaceable>
89  or the current active transaction, if not specified.</para>
90  </description>
91  </application>
92  ***/
93 
94 struct odbc_txn_frame {
96  struct odbc_obj *obj; /*!< Database handle within which transacted statements are run */
97  /*!\brief Is this record the current active transaction within the channel?
98  * Note that the active flag is really only necessary for statements which
99  * are triggered from the dialplan, as there isn't a direct correlation
100  * between multiple statements. Applications wishing to use transactions
101  * may simply perform each statement on the same odbc_obj, which keeps the
102  * transaction persistent.
103  */
104  unsigned int active:1;
105  unsigned int forcecommit:1; /*!< Should uncommitted transactions be auto-committed on handle release? */
106  unsigned int isolation; /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
107  char name[0]; /*!< Name of this transaction ID */
108 };
109 
110 static struct odbc_txn_frame *release_transaction(struct odbc_txn_frame *tx);
111 
112 static void odbc_txn_free(void *vdata)
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 }
127 
128 static const struct ast_datastore_info txn_info = {
129  .type = "ODBC_Transaction",
130  .destroy = odbc_txn_free,
131 };
132 
133 static struct odbc_txn_frame *create_transaction(struct ast_channel *chan, const char *name, const char *dsn)
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 }
207 
208 static struct odbc_txn_frame *find_transaction(struct ast_channel *chan, const char *name, int active)
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 }
243 
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 }
271 
272 static int commit_exec(struct ast_channel *chan, const char *data)
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 }
293 
294 static int rollback_exec(struct ast_channel *chan, const char *data)
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 }
315 
316 static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
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 }
353 
354 /* XXX The idea of "active" transactions is silly and makes things
355  * more prone to error. It would be much better if the transaction
356  * always had to be specified by name so that no implicit behavior
357  * occurred.
358  */
359 static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx)
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 }
389 
390 static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
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  */
439  int isolation = ast_odbc_text2isolation(value);
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 }
465 
466 struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname)
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 }
497 
499  .name = "ODBC",
500  .read = acf_transaction_read,
501  .write = acf_transaction_write,
502 };
503 
504 static const char * const app_commit = "ODBC_Commit";
505 static const char * const app_rollback = "ODBC_Rollback";
506 
507 /* XXX res_odbc takes the path of disallowing unloads from happening.
508  * It's not a great precedent, but since trying to deal with unloading the module
509  * while transactions are active seems like a huge pain to deal with, we'll go
510  * the same way here.
511  */
512 static int unload_module(void)
513 {
514  return -1;
515 }
516 
517 static int load_module(void)
518 {
521  ast_custom_function_register(&odbc_function);
522  return 0;
523 }
524 
526  .support_level = AST_MODULE_SUPPORT_CORE,
527  .load = load_module,
528  .unload = unload_module,
529  .load_pri = AST_MODPRI_REALTIME_DEPEND,
530 );
const char * name
Definition: pbx.h:119
const char * type
Definition: datastore.h:32
SQLHDBC con
Definition: res_odbc.h:47
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
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 buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx)
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
char name[0]
Definition: res_odbc.c:129
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
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)
Definition: func_odbc.c:150
static const char *const app_commit
Structure for a data store type.
Definition: datastore.h:31
static struct odbc_txn_frame * release_transaction(struct odbc_txn_frame *tx)
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
const char * args
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
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_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:652
static int load_module(void)
static int commit_exec(struct ast_channel *chan, const char *data)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#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
static void odbc_txn_free(void *vdata)
General Asterisk PBX channel definitions.
ODBC container.
Definition: res_odbc.h:46
static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
static int rollback_exec(struct ast_channel *chan, const char *data)
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
ODBC resource manager.
const char * ast_odbc_isolation2text(int iso)
Convert from numeric transaction isolation values to their textual counterparts.
Definition: res_odbc.c:132
struct odbc_class * parent
Definition: res_odbc.h:48
Core PBX routines and definitions.
static int unload_module(void)
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
static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
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.
#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
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
static const struct ast_datastore_info txn_info
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 ast_odbc_text2isolation(const char *txt)
Convert from textual transaction isolation values to their numeric constants.
Definition: res_odbc.c:147
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static struct odbc_txn_frame * create_transaction(struct ast_channel *chan, const char *name, const char *dsn)
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_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#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
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
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...
static struct ast_custom_function odbc_function
void * data
Definition: datastore.h:70
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#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_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
static const char *const app_rollback
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
const char * ast_odbc_class_get_name(struct odbc_class *class)
Get the name of an ODBC class.
Definition: res_odbc.c:559
#define AST_APP_ARG(name)
Define an application argument.