Allow Asterisk to compile under GCC 4.10
[asterisk/asterisk.git] / res / res_odbc.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2012, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * res_odbc.c <ODBC resource manager>
9  * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct@yahoo.com>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21
22 /*! \file
23  *
24  * \brief ODBC resource manager
25  * 
26  * \author Mark Spencer <markster@digium.com>
27  * \author Anthony Minessale II <anthmct@yahoo.com>
28  * \author Tilghman Lesher <tilghman@digium.com>
29  *
30  * \arg See also: \ref cdr_odbc
31  */
32
33 /*! \li \ref res_odbc.c uses the configuration file \ref res_odbc.conf
34  * \addtogroup configuration_file Configuration Files
35  */
36
37 /*! 
38  * \page res_odbc.conf res_odbc.conf
39  * \verbinclude res_odbc.conf.sample
40  */
41
42 /*** MODULEINFO
43         <depend>generic_odbc</depend>
44         <depend>ltdl</depend>
45         <support_level>core</support_level>
46  ***/
47
48 #include "asterisk.h"
49
50 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
51
52 #include "asterisk/file.h"
53 #include "asterisk/channel.h"
54 #include "asterisk/config.h"
55 #include "asterisk/pbx.h"
56 #include "asterisk/module.h"
57 #include "asterisk/cli.h"
58 #include "asterisk/lock.h"
59 #include "asterisk/res_odbc.h"
60 #include "asterisk/time.h"
61 #include "asterisk/astobj2.h"
62 #include "asterisk/app.h"
63 #include "asterisk/strings.h"
64 #include "asterisk/threadstorage.h"
65 #include "asterisk/data.h"
66
67 /*** DOCUMENTATION
68         <function name="ODBC" language="en_US">
69                 <synopsis>
70                         Controls ODBC transaction properties.
71                 </synopsis>
72                 <syntax>
73                         <parameter name="property" required="true">
74                                 <enumlist>
75                                         <enum name="transaction">
76                                                 <para>Gets or sets the active transaction ID.  If set, and the transaction ID does not
77                                                 exist and a <replaceable>database name</replaceable> is specified as an argument, it will be created.</para>
78                                         </enum>
79                                         <enum name="forcecommit">
80                                                 <para>Controls whether a transaction will be automatically committed when the channel
81                                                 hangs up.  Defaults to false.  If a <replaceable>transaction ID</replaceable> is specified in the optional argument,
82                                                 the property will be applied to that ID, otherwise to the current active ID.</para>
83                                         </enum>
84                                         <enum name="isolation">
85                                                 <para>Controls the data isolation on uncommitted transactions.  May be one of the
86                                                 following: <literal>read_committed</literal>, <literal>read_uncommitted</literal>,
87                                                 <literal>repeatable_read</literal>, or <literal>serializable</literal>.  Defaults to the
88                                                 database setting in <filename>res_odbc.conf</filename> or <literal>read_committed</literal>
89                                                 if not specified.  If a <replaceable>transaction ID</replaceable> is specified as an optional argument, it will be
90                                                 applied to that ID, otherwise the current active ID.</para>
91                                         </enum>
92                                 </enumlist>
93                         </parameter>
94                         <parameter name="argument" required="false" />
95                 </syntax>
96                 <description>
97                         <para>The ODBC() function allows setting several properties to influence how a connected
98                         database processes transactions.</para>
99                 </description>
100         </function>
101         <application name="ODBC_Commit" language="en_US">
102                 <synopsis>
103                         Commits a currently open database transaction.
104                 </synopsis>
105                 <syntax>
106                         <parameter name="transaction ID" required="no" />
107                 </syntax>
108                 <description>
109                         <para>Commits the database transaction specified by <replaceable>transaction ID</replaceable>
110                         or the current active transaction, if not specified.</para>
111                 </description>
112         </application>
113         <application name="ODBC_Rollback" language="en_US">
114                 <synopsis>
115                         Rollback a currently open database transaction.
116                 </synopsis>
117                 <syntax>
118                         <parameter name="transaction ID" required="no" />
119                 </syntax>
120                 <description>
121                         <para>Rolls back the database transaction specified by <replaceable>transaction ID</replaceable>
122                         or the current active transaction, if not specified.</para>
123                 </description>
124         </application>
125  ***/
126
127 struct odbc_class
128 {
129         AST_LIST_ENTRY(odbc_class) list;
130         char name[80];
131         char dsn[80];
132         char *username;
133         char *password;
134         char *sanitysql;
135         SQLHENV env;
136         unsigned int haspool:1;              /*!< Boolean - TDS databases need this */
137         unsigned int delme:1;                /*!< Purge the class */
138         unsigned int backslash_is_escape:1;  /*!< On this database, the backslash is a native escape sequence */
139         unsigned int forcecommit:1;          /*!< Should uncommitted transactions be auto-committed on handle release? */
140         unsigned int isolation;              /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
141         unsigned int limit;                  /*!< Maximum number of database handles we will allow */
142         int count;                           /*!< Running count of pooled connections */
143         unsigned int idlecheck;              /*!< Recheck the connection if it is idle for this long (in seconds) */
144         unsigned int conntimeout;            /*!< Maximum time the connection process should take */
145         /*! When a connection fails, cache that failure for how long? */
146         struct timeval negative_connection_cache;
147         /*! When a connection fails, when did that last occur? */
148         struct timeval last_negative_connect;
149         /*! List of handles associated with this class */
150         struct ao2_container *obj_container;
151 };
152
153 static struct ao2_container *class_container;
154
155 static AST_RWLIST_HEAD_STATIC(odbc_tables, odbc_cache_tables);
156
157 static odbc_status odbc_obj_connect(struct odbc_obj *obj);
158 static odbc_status odbc_obj_disconnect(struct odbc_obj *obj);
159 static int odbc_register_class(struct odbc_class *class, int connect);
160 static void odbc_txn_free(void *data);
161 static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx);
162
163 AST_THREADSTORAGE(errors_buf);
164
165 static const struct ast_datastore_info txn_info = {
166         .type = "ODBC_Transaction",
167         .destroy = odbc_txn_free,
168 };
169
170 struct odbc_txn_frame {
171         AST_LIST_ENTRY(odbc_txn_frame) list;
172         struct ast_channel *owner;
173         struct odbc_obj *obj;        /*!< Database handle within which transacted statements are run */
174         /*!\brief Is this record the current active transaction within the channel?
175          * Note that the active flag is really only necessary for statements which
176          * are triggered from the dialplan, as there isn't a direct correlation
177          * between multiple statements.  Applications wishing to use transactions
178          * may simply perform each statement on the same odbc_obj, which keeps the
179          * transaction persistent.
180          */
181         unsigned int active:1;
182         unsigned int forcecommit:1;     /*!< Should uncommitted transactions be auto-committed on handle release? */
183         unsigned int isolation;         /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
184         char name[0];                   /*!< Name of this transaction ID */
185 };
186
187 #define DATA_EXPORT_ODBC_CLASS(MEMBER)                          \
188         MEMBER(odbc_class, name, AST_DATA_STRING)               \
189         MEMBER(odbc_class, dsn, AST_DATA_STRING)                \
190         MEMBER(odbc_class, username, AST_DATA_STRING)           \
191         MEMBER(odbc_class, password, AST_DATA_PASSWORD)         \
192         MEMBER(odbc_class, limit, AST_DATA_INTEGER)             \
193         MEMBER(odbc_class, count, AST_DATA_INTEGER)             \
194         MEMBER(odbc_class, forcecommit, AST_DATA_BOOLEAN)
195
196 AST_DATA_STRUCTURE(odbc_class, DATA_EXPORT_ODBC_CLASS);
197
198 static const char *isolation2text(int iso)
199 {
200         if (iso == SQL_TXN_READ_COMMITTED) {
201                 return "read_committed";
202         } else if (iso == SQL_TXN_READ_UNCOMMITTED) {
203                 return "read_uncommitted";
204         } else if (iso == SQL_TXN_SERIALIZABLE) {
205                 return "serializable";
206         } else if (iso == SQL_TXN_REPEATABLE_READ) {
207                 return "repeatable_read";
208         } else {
209                 return "unknown";
210         }
211 }
212
213 static int text2isolation(const char *txt)
214 {
215         if (strncasecmp(txt, "read_", 5) == 0) {
216                 if (strncasecmp(txt + 5, "c", 1) == 0) {
217                         return SQL_TXN_READ_COMMITTED;
218                 } else if (strncasecmp(txt + 5, "u", 1) == 0) {
219                         return SQL_TXN_READ_UNCOMMITTED;
220                 } else {
221                         return 0;
222                 }
223         } else if (strncasecmp(txt, "ser", 3) == 0) {
224                 return SQL_TXN_SERIALIZABLE;
225         } else if (strncasecmp(txt, "rep", 3) == 0) {
226                 return SQL_TXN_REPEATABLE_READ;
227         } else {
228                 return 0;
229         }
230 }
231
232 static struct odbc_txn_frame *find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
233 {
234         struct ast_datastore *txn_store;
235         AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
236         struct odbc_txn_frame *txn = NULL;
237
238         if (!chan && obj && obj->txf && obj->txf->owner) {
239                 chan = obj->txf->owner;
240         } else if (!chan) {
241                 /* No channel == no transaction */
242                 return NULL;
243         }
244
245         ast_channel_lock(chan);
246         if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
247                 oldlist = txn_store->data;
248         } else {
249                 /* Need to create a new datastore */
250                 if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) {
251                         ast_log(LOG_ERROR, "Unable to allocate a new datastore.  Cannot create a new transaction.\n");
252                         ast_channel_unlock(chan);
253                         return NULL;
254                 }
255
256                 if (!(oldlist = ast_calloc(1, sizeof(*oldlist)))) {
257                         ast_log(LOG_ERROR, "Unable to allocate datastore list head.  Cannot create a new transaction.\n");
258                         ast_datastore_free(txn_store);
259                         ast_channel_unlock(chan);
260                         return NULL;
261                 }
262
263                 txn_store->data = oldlist;
264                 AST_LIST_HEAD_INIT(oldlist);
265                 ast_channel_datastore_add(chan, txn_store);
266         }
267
268         AST_LIST_LOCK(oldlist);
269         ast_channel_unlock(chan);
270
271         /* Scanning for an object is *fast*.  Scanning for a name is much slower. */
272         if (obj != NULL || active == 1) {
273                 AST_LIST_TRAVERSE(oldlist, txn, list) {
274                         if (txn->obj == obj || txn->active) {
275                                 AST_LIST_UNLOCK(oldlist);
276                                 return txn;
277                         }
278                 }
279         }
280
281         if (name != NULL) {
282                 AST_LIST_TRAVERSE(oldlist, txn, list) {
283                         if (!strcasecmp(txn->name, name)) {
284                                 AST_LIST_UNLOCK(oldlist);
285                                 return txn;
286                         }
287                 }
288         }
289
290         /* Nothing found, create one */
291         if (name && obj && (txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1))) {
292                 struct odbc_txn_frame *otxn;
293
294                 strcpy(txn->name, name); /* SAFE */
295                 txn->obj = obj;
296                 txn->isolation = obj->parent->isolation;
297                 txn->forcecommit = obj->parent->forcecommit;
298                 txn->owner = chan;
299                 txn->active = 1;
300
301                 /* On creation, the txn becomes active, and all others inactive */
302                 AST_LIST_TRAVERSE(oldlist, otxn, list) {
303                         otxn->active = 0;
304                 }
305                 AST_LIST_INSERT_TAIL(oldlist, txn, list);
306
307                 obj->txf = txn;
308                 obj->tx = 1;
309         }
310         AST_LIST_UNLOCK(oldlist);
311
312         return txn;
313 }
314
315 static struct odbc_txn_frame *release_transaction(struct odbc_txn_frame *tx)
316 {
317         if (!tx) {
318                 return NULL;
319         }
320
321         ast_debug(2, "release_transaction(%p) called (tx->obj = %p, tx->obj->txf = %p)\n", tx, tx->obj, tx->obj ? tx->obj->txf : NULL);
322
323         /* If we have an owner, disassociate */
324         if (tx->owner) {
325                 struct ast_datastore *txn_store;
326                 AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
327
328                 ast_channel_lock(tx->owner);
329                 if ((txn_store = ast_channel_datastore_find(tx->owner, &txn_info, NULL))) {
330                         oldlist = txn_store->data;
331                         AST_LIST_LOCK(oldlist);
332                         AST_LIST_REMOVE(oldlist, tx, list);
333                         AST_LIST_UNLOCK(oldlist);
334                 }
335                 ast_channel_unlock(tx->owner);
336                 tx->owner = NULL;
337         }
338
339         if (tx->obj) {
340                 /* If we have any uncommitted transactions, they are handled when we release the object */
341                 struct odbc_obj *obj = tx->obj;
342                 /* Prevent recursion during destruction */
343                 tx->obj->txf = NULL;
344                 tx->obj = NULL;
345                 odbc_release_obj2(obj, tx);
346         }
347         ast_free(tx);
348         return NULL;
349 }
350
351 static void odbc_txn_free(void *vdata)
352 {
353         struct odbc_txn_frame *tx;
354         AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata;
355
356         ast_debug(2, "odbc_txn_free(%p) called\n", vdata);
357
358         AST_LIST_LOCK(oldlist);
359         while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) {
360                 release_transaction(tx);
361         }
362         AST_LIST_UNLOCK(oldlist);
363         AST_LIST_HEAD_DESTROY(oldlist);
364         ast_free(oldlist);
365 }
366
367 static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx)
368 {
369         struct ast_datastore *txn_store;
370         AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
371         struct odbc_txn_frame *active = NULL, *txn;
372
373         if (!chan && tx && tx->owner) {
374                 chan = tx->owner;
375         }
376
377         if (!chan) {
378                 return -1;
379         }
380
381         ast_channel_lock(chan);
382         if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
383                 ast_channel_unlock(chan);
384                 return -1;
385         }
386
387         oldlist = txn_store->data;
388         AST_LIST_LOCK(oldlist);
389         AST_LIST_TRAVERSE(oldlist, txn, list) {
390                 if (txn == tx) {
391                         txn->active = 1;
392                         active = txn;
393                 } else {
394                         txn->active = 0;
395                 }
396         }
397         AST_LIST_UNLOCK(oldlist);
398         ast_channel_unlock(chan);
399         return active ? 0 : -1;
400 }
401
402 static void odbc_class_destructor(void *data)
403 {
404         struct odbc_class *class = data;
405         /* Due to refcounts, we can safely assume that any objects with a reference
406          * to us will prevent our destruction, so we don't need to worry about them.
407          */
408         if (class->username) {
409                 ast_free(class->username);
410         }
411         if (class->password) {
412                 ast_free(class->password);
413         }
414         if (class->sanitysql) {
415                 ast_free(class->sanitysql);
416         }
417         ao2_ref(class->obj_container, -1);
418         SQLFreeHandle(SQL_HANDLE_ENV, class->env);
419 }
420
421 static int null_hash_fn(const void *obj, const int flags)
422 {
423         return 0;
424 }
425
426 static void odbc_obj_destructor(void *data)
427 {
428         struct odbc_obj *obj = data;
429         struct odbc_class *class = obj->parent;
430         obj->parent = NULL;
431         odbc_obj_disconnect(obj);
432         ao2_ref(class, -1);
433 }
434
435 static void destroy_table_cache(struct odbc_cache_tables *table) {
436         struct odbc_cache_columns *col;
437         ast_debug(1, "Destroying table cache for %s\n", table->table);
438         AST_RWLIST_WRLOCK(&table->columns);
439         while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
440                 ast_free(col);
441         }
442         AST_RWLIST_UNLOCK(&table->columns);
443         AST_RWLIST_HEAD_DESTROY(&table->columns);
444         ast_free(table);
445 }
446
447 /*!
448  * \brief Find or create an entry describing the table specified.
449  * \param database Name of an ODBC class on which to query the table
450  * \param tablename Tablename to describe
451  * \retval A structure describing the table layout, or NULL, if the table is not found or another error occurs.
452  * When a structure is returned, the contained columns list will be
453  * rdlock'ed, to ensure that it will be retained in memory.
454  * \since 1.6.1
455  */
456 struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *tablename)
457 {
458         struct odbc_cache_tables *tableptr;
459         struct odbc_cache_columns *entry;
460         char columnname[80];
461         SQLLEN sqlptr;
462         SQLHSTMT stmt = NULL;
463         int res = 0, error = 0, try = 0;
464         struct odbc_obj *obj = ast_odbc_request_obj(database, 0);
465
466         AST_RWLIST_RDLOCK(&odbc_tables);
467         AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) {
468                 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
469                         break;
470                 }
471         }
472         if (tableptr) {
473                 AST_RWLIST_RDLOCK(&tableptr->columns);
474                 AST_RWLIST_UNLOCK(&odbc_tables);
475                 if (obj) {
476                         ast_odbc_release_obj(obj);
477                 }
478                 return tableptr;
479         }
480
481         if (!obj) {
482                 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
483                 AST_RWLIST_UNLOCK(&odbc_tables);
484                 return NULL;
485         }
486
487         /* Table structure not already cached; build it now. */
488         ao2_lock(obj);
489         do {
490                 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
491                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
492                         if (try == 0) {
493                                 try = 1;
494                                 ast_odbc_sanity_check(obj);
495                                 continue;
496                         }
497                         ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
498                         break;
499                 }
500
501                 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS);
502                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
503                         if (try == 0) {
504                                 try = 1;
505                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
506                                 ast_odbc_sanity_check(obj);
507                                 continue;
508                         }
509                         ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
510                         break;
511                 }
512
513                 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
514                         ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
515                         break;
516                 }
517
518                 tableptr->connection = (char *)tableptr + sizeof(*tableptr);
519                 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1;
520                 strcpy(tableptr->connection, database); /* SAFE */
521                 strcpy(tableptr->table, tablename); /* SAFE */
522                 AST_RWLIST_HEAD_INIT(&(tableptr->columns));
523
524                 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
525                         SQLGetData(stmt,  4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
526
527                         if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) {
528                                 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
529                                 error = 1;
530                                 break;
531                         }
532                         entry->name = (char *)entry + sizeof(*entry);
533                         strcpy(entry->name, columnname);
534
535                         SQLGetData(stmt,  5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
536                         SQLGetData(stmt,  7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
537                         SQLGetData(stmt,  9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
538                         SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
539                         SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
540                         SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
541
542                         /* Specification states that the octenlen should be the maximum number of bytes
543                          * returned in a char or binary column, but it seems that some drivers just set
544                          * it to NULL. (Bad Postgres! No biscuit!) */
545                         if (entry->octetlen == 0) {
546                                 entry->octetlen = entry->size;
547                         }
548
549                         ast_verb(10, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
550                         /* Insert column info into column list */
551                         AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
552                 }
553                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
554
555                 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
556                 AST_RWLIST_RDLOCK(&(tableptr->columns));
557                 break;
558         } while (1);
559         ao2_unlock(obj);
560
561         AST_RWLIST_UNLOCK(&odbc_tables);
562
563         if (error) {
564                 destroy_table_cache(tableptr);
565                 tableptr = NULL;
566         }
567         if (obj) {
568                 ast_odbc_release_obj(obj);
569         }
570         return tableptr;
571 }
572
573 struct odbc_cache_columns *ast_odbc_find_column(struct odbc_cache_tables *table, const char *colname)
574 {
575         struct odbc_cache_columns *col;
576         AST_RWLIST_TRAVERSE(&table->columns, col, list) {
577                 if (strcasecmp(col->name, colname) == 0) {
578                         return col;
579                 }
580         }
581         return NULL;
582 }
583
584 int ast_odbc_clear_cache(const char *database, const char *tablename)
585 {
586         struct odbc_cache_tables *tableptr;
587
588         AST_RWLIST_WRLOCK(&odbc_tables);
589         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
590                 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
591                         AST_LIST_REMOVE_CURRENT(list);
592                         destroy_table_cache(tableptr);
593                         break;
594                 }
595         }
596         AST_RWLIST_TRAVERSE_SAFE_END
597         AST_RWLIST_UNLOCK(&odbc_tables);
598         return tableptr ? 0 : -1;
599 }
600
601 SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT (*exec_cb)(struct odbc_obj *obj, void *data), void *data)
602 {
603         int attempt;
604         SQLHSTMT stmt;
605
606         ao2_lock(obj);
607
608         for (attempt = 0; attempt < 2; attempt++) {
609                 stmt = exec_cb(obj, data);
610
611                 if (stmt) {
612                         break;
613                 } else if (obj->tx) {
614                         ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n");
615                         break;
616                 } else if (attempt == 0) {
617                         ast_log(LOG_WARNING, "SQL Execute error! Verifying connection to %s [%s]...\n", obj->parent->name, obj->parent->dsn);
618                 }
619                 if (!ast_odbc_sanity_check(obj)) {
620                         break;
621                 }
622         }
623
624         ao2_unlock(obj);
625
626         return stmt;
627 }
628
629 SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT (*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
630 {
631         int res = 0, i, attempt;
632         SQLINTEGER nativeerror=0, numfields=0;
633         SQLSMALLINT diagbytes=0;
634         unsigned char state[10], diagnostic[256];
635         SQLHSTMT stmt;
636
637         ao2_lock(obj);
638
639         for (attempt = 0; attempt < 2; attempt++) {
640                 /* This prepare callback may do more than just prepare -- it may also
641                  * bind parameters, bind results, etc.  The real key, here, is that
642                  * when we disconnect, all handles become invalid for most databases.
643                  * We must therefore redo everything when we establish a new
644                  * connection. */
645                 stmt = prepare_cb(obj, data);
646
647                 if (stmt) {
648                         res = SQLExecute(stmt);
649                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
650                                 if (res == SQL_ERROR) {
651                                         SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
652                                         for (i = 0; i < numfields; i++) {
653                                                 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
654                                                 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
655                                                 if (i > 10) {
656                                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
657                                                         break;
658                                                 }
659                                         }
660                                 }
661
662                                 if (obj->tx) {
663                                         ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n");
664                                         break;
665                                 } else {
666                                         ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn);
667                                         SQLFreeHandle(SQL_HANDLE_STMT, stmt);
668                                         stmt = NULL;
669
670                                         obj->up = 0;
671                                         /*
672                                          * While this isn't the best way to try to correct an error, this won't automatically
673                                          * fail when the statement handle invalidates.
674                                          */
675                                         if (!ast_odbc_sanity_check(obj)) {
676                                                 break;
677                                         }
678                                         continue;
679                                 }
680                         } else {
681                                 obj->last_used = ast_tvnow();
682                         }
683                         break;
684                 } else if (attempt == 0) {
685                         ast_odbc_sanity_check(obj);
686                 }
687         }
688
689         ao2_unlock(obj);
690
691         return stmt;
692 }
693
694 int ast_odbc_smart_execute(struct odbc_obj *obj, SQLHSTMT stmt)
695 {
696         int res = 0, i;
697         SQLINTEGER nativeerror=0, numfields=0;
698         SQLSMALLINT diagbytes=0;
699         unsigned char state[10], diagnostic[256];
700
701         ao2_lock(obj);
702
703         res = SQLExecute(stmt);
704         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
705                 if (res == SQL_ERROR) {
706                         SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
707                         for (i = 0; i < numfields; i++) {
708                                 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
709                                 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
710                                 if (i > 10) {
711                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
712                                         break;
713                                 }
714                         }
715                 }
716         } else {
717                 obj->last_used = ast_tvnow();
718         }
719
720         ao2_unlock(obj);
721
722         return res;
723 }
724
725 SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind)
726 {
727         SQLRETURN res;
728
729         if (pmaxlen == 0) {
730                 if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
731                         ast_str_make_space(buf, *StrLen_or_Ind + 1);
732                 }
733         } else if (pmaxlen > 0) {
734                 ast_str_make_space(buf, pmaxlen);
735         }
736         res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
737         ast_str_update(*buf);
738
739         return res;
740 }
741
742 int ast_odbc_sanity_check(struct odbc_obj *obj) 
743 {
744         char *test_sql = "select 1";
745         SQLHSTMT stmt;
746         int res = 0;
747
748         if (!ast_strlen_zero(obj->parent->sanitysql))
749                 test_sql = obj->parent->sanitysql;
750
751         if (obj->up) {
752                 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
753                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
754                         obj->up = 0;
755                 } else {
756                         res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
757                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
758                                 obj->up = 0;
759                         } else {
760                                 res = SQLExecute(stmt);
761                                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
762                                         obj->up = 0;
763                                 }
764                         }
765                 }
766                 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
767         }
768
769         if (!obj->up && !obj->tx) { /* Try to reconnect! */
770                 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
771                 odbc_obj_disconnect(obj);
772                 odbc_obj_connect(obj);
773         }
774         return obj->up;
775 }
776
777 static int load_odbc_config(void)
778 {
779         static char *cfg = "res_odbc.conf";
780         struct ast_config *config;
781         struct ast_variable *v;
782         char *cat;
783         const char *dsn, *username, *password, *sanitysql;
784         int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation;
785         struct timeval ncache = { 0, 0 };
786         unsigned int idlecheck;
787         int preconnect = 0, res = 0;
788         struct ast_flags config_flags = { 0 };
789
790         struct odbc_class *new;
791
792         config = ast_config_load(cfg, config_flags);
793         if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
794                 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
795                 return -1;
796         }
797         for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
798                 if (!strcasecmp(cat, "ENV")) {
799                         for (v = ast_variable_browse(config, cat); v; v = v->next) {
800                                 setenv(v->name, v->value, 1);
801                                 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
802                         }
803                 } else {
804                         /* Reset all to defaults for each class of odbc connections */
805                         dsn = username = password = sanitysql = NULL;
806                         enabled = 1;
807                         preconnect = idlecheck = 0;
808                         pooling = 0;
809                         limit = 0;
810                         bse = 1;
811                         conntimeout = 10;
812                         forcecommit = 0;
813                         isolation = SQL_TXN_READ_COMMITTED;
814                         for (v = ast_variable_browse(config, cat); v; v = v->next) {
815                                 if (!strcasecmp(v->name, "pooling")) {
816                                         if (ast_true(v->value))
817                                                 pooling = 1;
818                                 } else if (!strncasecmp(v->name, "share", 5)) {
819                                         /* "shareconnections" is a little clearer in meaning than "pooling" */
820                                         if (ast_false(v->value))
821                                                 pooling = 1;
822                                 } else if (!strcasecmp(v->name, "limit")) {
823                                         sscanf(v->value, "%30d", &limit);
824                                         if (ast_true(v->value) && !limit) {
825                                                 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'.  Setting limit to 1023 for ODBC class '%s'.\n", v->value, cat);
826                                                 limit = 1023;
827                                         } else if (ast_false(v->value)) {
828                                                 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'.  Disabling ODBC class '%s'.\n", v->value, cat);
829                                                 enabled = 0;
830                                                 break;
831                                         }
832                                 } else if (!strcasecmp(v->name, "idlecheck")) {
833                                         sscanf(v->value, "%30u", &idlecheck);
834                                 } else if (!strcasecmp(v->name, "enabled")) {
835                                         enabled = ast_true(v->value);
836                                 } else if (!strcasecmp(v->name, "pre-connect")) {
837                                         preconnect = ast_true(v->value);
838                                 } else if (!strcasecmp(v->name, "dsn")) {
839                                         dsn = v->value;
840                                 } else if (!strcasecmp(v->name, "username")) {
841                                         username = v->value;
842                                 } else if (!strcasecmp(v->name, "password")) {
843                                         password = v->value;
844                                 } else if (!strcasecmp(v->name, "sanitysql")) {
845                                         sanitysql = v->value;
846                                 } else if (!strcasecmp(v->name, "backslash_is_escape")) {
847                                         bse = ast_true(v->value);
848                                 } else if (!strcasecmp(v->name, "connect_timeout")) {
849                                         if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
850                                                 ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
851                                                 conntimeout = 10;
852                                         }
853                                 } else if (!strcasecmp(v->name, "negative_connection_cache")) {
854                                         double dncache;
855                                         if (sscanf(v->value, "%lf", &dncache) != 1 || dncache < 0) {
856                                                 ast_log(LOG_WARNING, "negative_connection_cache must be a non-negative integer\n");
857                                                 /* 5 minutes sounds like a reasonable default */
858                                                 ncache.tv_sec = 300;
859                                                 ncache.tv_usec = 0;
860                                         } else {
861                                                 ncache.tv_sec = (int)dncache;
862                                                 ncache.tv_usec = (dncache - ncache.tv_sec) * 1000000;
863                                         }
864                                 } else if (!strcasecmp(v->name, "forcecommit")) {
865                                         forcecommit = ast_true(v->value);
866                                 } else if (!strcasecmp(v->name, "isolation")) {
867                                         if ((isolation = text2isolation(v->value)) == 0) {
868                                                 ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat);
869                                                 isolation = SQL_TXN_READ_COMMITTED;
870                                         }
871                                 }
872                         }
873
874                         if (enabled && !ast_strlen_zero(dsn)) {
875                                 new = ao2_alloc(sizeof(*new), odbc_class_destructor);
876
877                                 if (!new) {
878                                         res = -1;
879                                         break;
880                                 }
881
882                                 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
883                                 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
884
885                                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
886                                         ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
887                                         ao2_ref(new, -1);
888                                         return res;
889                                 }
890
891                                 new->obj_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr);
892
893                                 if (pooling) {
894                                         new->haspool = pooling;
895                                         if (limit) {
896                                                 new->limit = limit;
897                                         } else {
898                                                 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless.  Changing limit from 0 to 5.\n");
899                                                 new->limit = 5;
900                                         }
901                                 }
902
903                                 new->backslash_is_escape = bse ? 1 : 0;
904                                 new->forcecommit = forcecommit ? 1 : 0;
905                                 new->isolation = isolation;
906                                 new->idlecheck = idlecheck;
907                                 new->conntimeout = conntimeout;
908                                 new->negative_connection_cache = ncache;
909
910                                 if (cat)
911                                         ast_copy_string(new->name, cat, sizeof(new->name));
912                                 if (dsn)
913                                         ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
914                                 if (username && !(new->username = ast_strdup(username))) {
915                                         ao2_ref(new, -1);
916                                         break;
917                                 }
918                                 if (password && !(new->password = ast_strdup(password))) {
919                                         ao2_ref(new, -1);
920                                         break;
921                                 }
922                                 if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) {
923                                         ao2_ref(new, -1);
924                                         break;
925                                 }
926
927                                 odbc_register_class(new, preconnect);
928                                 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
929                                 ao2_ref(new, -1);
930                                 new = NULL;
931                         }
932                 }
933         }
934         ast_config_destroy(config);
935         return res;
936 }
937
938 static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
939 {
940         struct ao2_iterator aoi;
941         struct odbc_class *class;
942         struct odbc_obj *current;
943         int length = 0;
944         int which = 0;
945         char *ret = NULL;
946
947         switch (cmd) {
948         case CLI_INIT:
949                 e->command = "odbc show";
950                 e->usage =
951                                 "Usage: odbc show [class]\n"
952                                 "       List settings of a particular ODBC class or,\n"
953                                 "       if not specified, all classes.\n";
954                 return NULL;
955         case CLI_GENERATE:
956                 if (a->pos != 2)
957                         return NULL;
958                 length = strlen(a->word);
959                 aoi = ao2_iterator_init(class_container, 0);
960                 while ((class = ao2_iterator_next(&aoi))) {
961                         if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
962                                 ret = ast_strdup(class->name);
963                         }
964                         ao2_ref(class, -1);
965                         if (ret) {
966                                 break;
967                         }
968                 }
969                 ao2_iterator_destroy(&aoi);
970                 if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
971                         ret = ast_strdup("all");
972                 }
973                 return ret;
974         }
975
976         ast_cli(a->fd, "\nODBC DSN Settings\n");
977         ast_cli(a->fd,   "-----------------\n\n");
978         aoi = ao2_iterator_init(class_container, 0);
979         while ((class = ao2_iterator_next(&aoi))) {
980                 if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
981                         int count = 0;
982                         char timestr[80];
983                         struct ast_tm tm;
984
985                         ast_localtime(&class->last_negative_connect, &tm, NULL);
986                         ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm);
987                         ast_cli(a->fd, "  Name:   %s\n  DSN:    %s\n", class->name, class->dsn);
988                         ast_cli(a->fd, "    Last connection attempt: %s\n", timestr);
989
990                         if (class->haspool) {
991                                 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
992
993                                 ast_cli(a->fd, "  Pooled: Yes\n  Limit:  %u\n  Connections in use: %d\n", class->limit, class->count);
994
995                                 while ((current = ao2_iterator_next(&aoi2))) {
996                                         ao2_lock(current);
997 #ifdef DEBUG_THREADS
998                                         ast_cli(a->fd, "    - Connection %d: %s (%s:%d %s)\n", ++count,
999                                                 current->used ? "in use" :
1000                                                 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected",
1001                                                 current->file, current->lineno, current->function);
1002 #else
1003                                         ast_cli(a->fd, "    - Connection %d: %s\n", ++count,
1004                                                 current->used ? "in use" :
1005                                                 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
1006 #endif
1007                                         ao2_unlock(current);
1008                                         ao2_ref(current, -1);
1009                                 }
1010                                 ao2_iterator_destroy(&aoi2);
1011                         } else {
1012                                 /* Should only ever be one of these (unless there are transactions) */
1013                                 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
1014                                 while ((current = ao2_iterator_next(&aoi2))) {
1015                                         ast_cli(a->fd, "  Pooled: No\n  Connected: %s\n", current->used ? "In use" :
1016                                                 current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
1017                                         ao2_ref(current, -1);
1018                                 }
1019                                 ao2_iterator_destroy(&aoi2);
1020                         }
1021                         ast_cli(a->fd, "\n");
1022                 }
1023                 ao2_ref(class, -1);
1024         }
1025         ao2_iterator_destroy(&aoi);
1026
1027         return CLI_SUCCESS;
1028 }
1029
1030 static struct ast_cli_entry cli_odbc[] = {
1031         AST_CLI_DEFINE(handle_cli_odbc_show, "List ODBC DSN(s)")
1032 };
1033
1034 static int odbc_register_class(struct odbc_class *class, int preconnect)
1035 {
1036         struct odbc_obj *obj;
1037         if (class) {
1038                 ao2_link(class_container, class);
1039                 /* I still have a reference in the caller, so a deref is NOT missing here. */
1040
1041                 if (preconnect) {
1042                         /* Request and release builds a connection */
1043                         obj = ast_odbc_request_obj(class->name, 0);
1044                         if (obj) {
1045                                 ast_odbc_release_obj(obj);
1046                         }
1047                 }
1048
1049                 return 0;
1050         } else {
1051                 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
1052                 return -1;
1053         }
1054 }
1055
1056 static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx)
1057 {
1058         SQLINTEGER nativeerror=0, numfields=0;
1059         SQLSMALLINT diagbytes=0, i;
1060         unsigned char state[10], diagnostic[256];
1061
1062         ast_debug(2, "odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->txf);
1063         if (tx) {
1064                 ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK");
1065                 if (SQLEndTran(SQL_HANDLE_DBC, obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
1066                         /* Handle possible transaction commit failure */
1067                         SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1068                         for (i = 0; i < numfields; i++) {
1069                                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1070                                 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
1071                                 if (!strcmp((char *)state, "25S02") || !strcmp((char *)state, "08007")) {
1072                                         /* These codes mean that a commit failed and a transaction
1073                                          * is still active. We must rollback, or things will get
1074                                          * very, very weird for anybody using the handle next. */
1075                                         SQLEndTran(SQL_HANDLE_DBC, obj->con, SQL_ROLLBACK);
1076                                 }
1077                                 if (i > 10) {
1078                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1079                                         break;
1080                                 }
1081                         }
1082                 }
1083
1084                 /* Transaction is done, reset autocommit */
1085                 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
1086                         SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1087                         for (i = 0; i < numfields; i++) {
1088                                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1089                                 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1090                                 if (i > 10) {
1091                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1092                                         break;
1093                                 }
1094                         }
1095                 }
1096         }
1097
1098 #ifdef DEBUG_THREADS
1099         obj->file[0] = '\0';
1100         obj->function[0] = '\0';
1101         obj->lineno = 0;
1102 #endif
1103
1104         /* For pooled connections, this frees the connection to be
1105          * reused.  For non-pooled connections, it does nothing. */
1106         obj->used = 0;
1107         if (obj->txf) {
1108                 /* Prevent recursion -- transaction is already closed out. */
1109                 obj->txf->obj = NULL;
1110                 obj->txf = release_transaction(obj->txf);
1111         }
1112         ao2_ref(obj, -1);
1113 }
1114
1115 void ast_odbc_release_obj(struct odbc_obj *obj)
1116 {
1117         struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
1118         odbc_release_obj2(obj, tx);
1119 }
1120
1121 int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
1122 {
1123         return obj->parent->backslash_is_escape;
1124 }
1125
1126 static int commit_exec(struct ast_channel *chan, const char *data)
1127 {
1128         struct odbc_txn_frame *tx;
1129         SQLINTEGER nativeerror=0, numfields=0;
1130         SQLSMALLINT diagbytes=0, i;
1131         unsigned char state[10], diagnostic[256];
1132
1133         if (ast_strlen_zero(data)) {
1134                 tx = find_transaction(chan, NULL, NULL, 1);
1135         } else {
1136                 tx = find_transaction(chan, NULL, data, 0);
1137         }
1138
1139         pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK");
1140
1141         if (tx) {
1142                 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) {
1143                         struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
1144                         ast_str_reset(errors);
1145
1146                         /* Handle possible transaction commit failure */
1147                         SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1148                         for (i = 0; i < numfields; i++) {
1149                                 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1150                                 ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
1151                                 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
1152                                 if (i > 10) {
1153                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1154                                         break;
1155                                 }
1156                         }
1157                         pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
1158                 }
1159         }
1160         return 0;
1161 }
1162
1163 static int rollback_exec(struct ast_channel *chan, const char *data)
1164 {
1165         struct odbc_txn_frame *tx;
1166         SQLINTEGER nativeerror=0, numfields=0;
1167         SQLSMALLINT diagbytes=0, i;
1168         unsigned char state[10], diagnostic[256];
1169
1170         if (ast_strlen_zero(data)) {
1171                 tx = find_transaction(chan, NULL, NULL, 1);
1172         } else {
1173                 tx = find_transaction(chan, NULL, data, 0);
1174         }
1175
1176         pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK");
1177
1178         if (tx) {
1179                 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) {
1180                         struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
1181                         ast_str_reset(errors);
1182
1183                         /* Handle possible transaction commit failure */
1184                         SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1185                         for (i = 0; i < numfields; i++) {
1186                                 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1187                                 ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
1188                                 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
1189                                 if (i > 10) {
1190                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1191                                         break;
1192                                 }
1193                         }
1194                         pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
1195                 }
1196         }
1197         return 0;
1198 }
1199
1200 static int aoro2_class_cb(void *obj, void *arg, int flags)
1201 {
1202         struct odbc_class *class = obj;
1203         char *name = arg;
1204         if (!strcmp(class->name, name) && !class->delme) {
1205                 return CMP_MATCH | CMP_STOP;
1206         }
1207         return 0;
1208 }
1209
1210 #define USE_TX (void *)(long)1
1211 #define NO_TX  (void *)(long)2
1212 #define EOR_TX (void *)(long)3
1213
1214 static int aoro2_obj_cb(void *vobj, void *arg, int flags)
1215 {
1216         struct odbc_obj *obj = vobj;
1217         ao2_lock(obj);
1218         if ((arg == NO_TX && !obj->tx) || (arg == EOR_TX && !obj->used) || (arg == USE_TX && obj->tx && !obj->used)) {
1219                 obj->used = 1;
1220                 ao2_unlock(obj);
1221                 return CMP_MATCH | CMP_STOP;
1222         }
1223         ao2_unlock(obj);
1224         return 0;
1225 }
1226
1227 /* This function should only be called for shared connections. Otherwise, the lack of
1228  * setting vobj->used breaks EOR_TX searching. For nonshared connections, use
1229  * aoro2_obj_cb instead. */
1230 static int aoro2_obj_notx_cb(void *vobj, void *arg, int flags)
1231 {
1232         struct odbc_obj *obj = vobj;
1233         if (!obj->tx) {
1234                 return CMP_MATCH | CMP_STOP;
1235         }
1236         return 0;
1237 }
1238
1239 struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
1240 {
1241         struct odbc_obj *obj = NULL;
1242         struct odbc_class *class;
1243         SQLINTEGER nativeerror=0, numfields=0;
1244         SQLSMALLINT diagbytes=0, i;
1245         unsigned char state[10], diagnostic[256];
1246
1247         if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
1248                 ast_debug(1, "Class '%s' not found!\n", name);
1249                 return NULL;
1250         }
1251
1252         ast_assert(ao2_ref(class, 0) > 1);
1253
1254         if (class->haspool) {
1255                 /* Recycle connections before building another */
1256                 obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX);
1257
1258                 if (obj) {
1259                         ast_assert(ao2_ref(obj, 0) > 1);
1260                 }
1261                 if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit) &&
1262                                 (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) {
1263                         obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
1264                         if (!obj) {
1265                                 class->count--;
1266                                 ao2_ref(class, -1);
1267                                 ast_debug(3, "Unable to allocate object\n");
1268                                 ast_atomic_fetchadd_int(&class->count, -1);
1269                                 return NULL;
1270                         }
1271                         ast_assert(ao2_ref(obj, 0) == 1);
1272                         /* obj inherits the outstanding reference to class */
1273                         obj->parent = class;
1274                         class = NULL;
1275                         if (odbc_obj_connect(obj) == ODBC_FAIL) {
1276                                 ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1277                                 ast_assert(ao2_ref(obj->parent, 0) > 0);
1278                                 /* Because it was never within the container, we have to manually decrement the count here */
1279                                 ast_atomic_fetchadd_int(&obj->parent->count, -1);
1280                                 ao2_ref(obj, -1);
1281                                 obj = NULL;
1282                         } else {
1283                                 obj->used = 1;
1284                                 ao2_link(obj->parent->obj_container, obj);
1285                         }
1286                 } else {
1287                         /* If construction fails due to the limit (or negative timecache), reverse our increment. */
1288                         if (!obj) {
1289                                 ast_atomic_fetchadd_int(&class->count, -1);
1290                         }
1291                         /* Object is not constructed, so delete outstanding reference to class. */
1292                         ao2_ref(class, -1);
1293                         class = NULL;
1294                 }
1295
1296                 if (!obj) {
1297                         return NULL;
1298                 }
1299
1300                 ao2_lock(obj);
1301
1302                 if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
1303                         /* Ensure this connection has autocommit turned off. */
1304                         if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
1305                                 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1306                                 for (i = 0; i < numfields; i++) {
1307                                         SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1308                                         ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1309                                         if (i > 10) {
1310                                                 ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1311                                                 break;
1312                                         }
1313                                 }
1314                         }
1315                 }
1316         } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
1317                 /* Non-pooled connections -- but must use a separate connection handle */
1318                 if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) {
1319                         ast_debug(1, "Object not found\n");
1320                         obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
1321                         if (!obj) {
1322                                 ao2_ref(class, -1);
1323                                 ast_debug(3, "Unable to allocate object\n");
1324                                 return NULL;
1325                         }
1326                         /* obj inherits the outstanding reference to class */
1327                         obj->parent = class;
1328                         class = NULL;
1329                         if (odbc_obj_connect(obj) == ODBC_FAIL) {
1330                                 ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1331                                 ao2_ref(obj, -1);
1332                                 obj = NULL;
1333                         } else {
1334                                 obj->used = 1;
1335                                 ao2_link(obj->parent->obj_container, obj);
1336                                 ast_atomic_fetchadd_int(&obj->parent->count, +1);
1337                         }
1338                 }
1339
1340                 if (!obj) {
1341                         return NULL;
1342                 }
1343
1344                 ao2_lock(obj);
1345
1346                 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
1347                         SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1348                         for (i = 0; i < numfields; i++) {
1349                                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1350                                 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1351                                 if (i > 10) {
1352                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1353                                         break;
1354                                 }
1355                         }
1356                 }
1357         } else {
1358                 /* Non-pooled connection: multiple modules can use the same connection. */
1359                 if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_notx_cb, NO_TX))) {
1360                         /* Object is not constructed, so delete outstanding reference to class. */
1361                         ast_assert(ao2_ref(class, 0) > 1);
1362                         ao2_ref(class, -1);
1363                         class = NULL;
1364                 } else {
1365                         /* No entry: build one */
1366                         if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) {
1367                                 ast_assert(ao2_ref(class, 0) > 1);
1368                                 ao2_ref(class, -1);
1369                                 ast_debug(3, "Unable to allocate object\n");
1370                                 return NULL;
1371                         }
1372                         /* obj inherits the outstanding reference to class */
1373                         obj->parent = class;
1374                         class = NULL;
1375                         if (odbc_obj_connect(obj) == ODBC_FAIL) {
1376                                 ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1377                                 ao2_ref(obj, -1);
1378                                 obj = NULL;
1379                         } else {
1380                                 ao2_link(obj->parent->obj_container, obj);
1381                                 ast_assert(ao2_ref(obj, 0) > 1);
1382                         }
1383                 }
1384
1385                 if (!obj) {
1386                         return NULL;
1387                 }
1388
1389                 ao2_lock(obj);
1390
1391                 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
1392                         SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1393                         for (i = 0; i < numfields; i++) {
1394                                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1395                                 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1396                                 if (i > 10) {
1397                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1398                                         break;
1399                                 }
1400                         }
1401                 }
1402         }
1403
1404         ast_assert(obj != NULL);
1405
1406         /* Set the isolation property */
1407         if (SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
1408                 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1409                 for (i = 0; i < numfields; i++) {
1410                         SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1411                         ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
1412                         if (i > 10) {
1413                                 ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1414                                 break;
1415                         }
1416                 }
1417         }
1418
1419         if (ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) {
1420                 /* Check if this connection qualifies for reconnection, with negative connection cache time */
1421                 if (time(NULL) > obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec) {
1422                         odbc_obj_connect(obj);
1423                 }
1424         } else if (ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
1425                 ast_odbc_sanity_check(obj);
1426         } else if (obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) {
1427                 odbc_obj_connect(obj);
1428         }
1429
1430 #ifdef DEBUG_THREADS
1431         ast_copy_string(obj->file, file, sizeof(obj->file));
1432         ast_copy_string(obj->function, function, sizeof(obj->function));
1433         obj->lineno = lineno;
1434 #endif
1435
1436         /* We had it locked because of the obj_connects we see here. */
1437         ao2_unlock(obj);
1438
1439         ast_assert(class == NULL);
1440
1441         ast_assert(ao2_ref(obj, 0) > 1);
1442         return obj;
1443 }
1444
1445 struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno)
1446 {
1447         struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
1448         return _ast_odbc_request_obj2(name, flags, file, function, lineno);
1449 }
1450
1451 struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname)
1452 {
1453         struct ast_datastore *txn_store;
1454         AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
1455         struct odbc_txn_frame *txn = NULL;
1456
1457         if (!chan) {
1458                 /* No channel == no transaction */
1459                 return NULL;
1460         }
1461
1462         ast_channel_lock(chan);
1463         if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
1464                 oldlist = txn_store->data;
1465         } else {
1466                 ast_channel_unlock(chan);
1467                 return NULL;
1468         }
1469
1470         AST_LIST_LOCK(oldlist);
1471         ast_channel_unlock(chan);
1472
1473         AST_LIST_TRAVERSE(oldlist, txn, list) {
1474                 if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) {
1475                         AST_LIST_UNLOCK(oldlist);
1476                         return txn->obj;
1477                 }
1478         }
1479         AST_LIST_UNLOCK(oldlist);
1480         return NULL;
1481 }
1482
1483 static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
1484 {
1485         int res;
1486         SQLINTEGER err;
1487         short int mlen;
1488         unsigned char msg[200], state[10];
1489         SQLHDBC con;
1490
1491         /* Nothing to disconnect */
1492         if (!obj->con) {
1493                 return ODBC_SUCCESS;
1494         }
1495
1496         con = obj->con;
1497         obj->con = NULL;
1498         res = SQLDisconnect(con);
1499
1500         if (obj->parent) {
1501                 if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
1502                         ast_debug(1, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
1503                 } else {
1504                         ast_debug(1, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
1505                 }
1506         }
1507
1508         if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) == SQL_SUCCESS) {
1509                 ast_debug(1, "Database handle %p deallocated\n", con);
1510         } else {
1511                 SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1512                 ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
1513         }
1514
1515         obj->up = 0;
1516         return ODBC_SUCCESS;
1517 }
1518
1519 static odbc_status odbc_obj_connect(struct odbc_obj *obj)
1520 {
1521         int res;
1522         SQLINTEGER err;
1523         short int mlen;
1524         unsigned char msg[200], state[10];
1525 #ifdef NEEDTRACE
1526         SQLINTEGER enable = 1;
1527         char *tracefile = "/tmp/odbc.trace";
1528 #endif
1529         SQLHDBC con;
1530
1531         if (obj->up) {
1532                 odbc_obj_disconnect(obj);
1533                 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
1534         } else {
1535                 ast_assert(obj->con == NULL);
1536                 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
1537         }
1538
1539         res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &con);
1540
1541         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1542                 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
1543                 obj->parent->last_negative_connect = ast_tvnow();
1544                 return ODBC_FAIL;
1545         }
1546         SQLSetConnectAttr(con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
1547         SQLSetConnectAttr(con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
1548 #ifdef NEEDTRACE
1549         SQLSetConnectAttr(con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
1550         SQLSetConnectAttr(con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
1551 #endif
1552
1553         res = SQLConnect(con,
1554                    (SQLCHAR *) obj->parent->dsn, SQL_NTS,
1555                    (SQLCHAR *) obj->parent->username, SQL_NTS,
1556                    (SQLCHAR *) obj->parent->password, SQL_NTS);
1557
1558         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1559                 SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1560                 obj->parent->last_negative_connect = ast_tvnow();
1561                 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
1562                 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) != SQL_SUCCESS) {
1563                         SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1564                         ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
1565                 }
1566                 return ODBC_FAIL;
1567         } else {
1568                 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
1569                 obj->up = 1;
1570                 obj->last_used = ast_tvnow();
1571         }
1572
1573         obj->con = con;
1574         return ODBC_SUCCESS;
1575 }
1576
1577 static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1578 {
1579         AST_DECLARE_APP_ARGS(args,
1580                 AST_APP_ARG(property);
1581                 AST_APP_ARG(opt);
1582         );
1583         struct odbc_txn_frame *tx;
1584
1585         AST_STANDARD_APP_ARGS(args, data);
1586         if (strcasecmp(args.property, "transaction") == 0) {
1587                 if ((tx = find_transaction(chan, NULL, NULL, 1))) {
1588                         ast_copy_string(buf, tx->name, len);
1589                         return 0;
1590                 }
1591         } else if (strcasecmp(args.property, "isolation") == 0) {
1592                 if (!ast_strlen_zero(args.opt)) {
1593                         tx = find_transaction(chan, NULL, args.opt, 0);
1594                 } else {
1595                         tx = find_transaction(chan, NULL, NULL, 1);
1596                 }
1597                 if (tx) {
1598                         ast_copy_string(buf, isolation2text(tx->isolation), len);
1599                         return 0;
1600                 }
1601         } else if (strcasecmp(args.property, "forcecommit") == 0) {
1602                 if (!ast_strlen_zero(args.opt)) {
1603                         tx = find_transaction(chan, NULL, args.opt, 0);
1604                 } else {
1605                         tx = find_transaction(chan, NULL, NULL, 1);
1606                 }
1607                 if (tx) {
1608                         ast_copy_string(buf, tx->forcecommit ? "1" : "0", len);
1609                         return 0;
1610                 }
1611         }
1612         return -1;
1613 }
1614
1615 static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
1616 {
1617         AST_DECLARE_APP_ARGS(args,
1618                 AST_APP_ARG(property);
1619                 AST_APP_ARG(opt);
1620         );
1621         struct odbc_txn_frame *tx;
1622         SQLINTEGER nativeerror=0, numfields=0;
1623         SQLSMALLINT diagbytes=0, i;
1624         unsigned char state[10], diagnostic[256];
1625
1626         AST_STANDARD_APP_ARGS(args, s);
1627         if (strcasecmp(args.property, "transaction") == 0) {
1628                 /* Set active transaction */
1629                 struct odbc_obj *obj;
1630                 if ((tx = find_transaction(chan, NULL, value, 0))) {
1631                         mark_transaction_active(chan, tx);
1632                 } else {
1633                         /* No such transaction, create one */
1634                         struct ast_flags flags = { RES_ODBC_INDEPENDENT_CONNECTION };
1635                         if (ast_strlen_zero(args.opt) || !(obj = ast_odbc_request_obj2(args.opt, flags))) {
1636                                 ast_log(LOG_ERROR, "Could not create transaction: invalid database specification '%s'\n", S_OR(args.opt, ""));
1637                                 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_DB");
1638                                 return -1;
1639                         }
1640                         if (!find_transaction(chan, obj, value, 0)) {
1641                                 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1642                                 return -1;
1643                         }
1644                         obj->tx = 1;
1645                 }
1646                 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1647                 return 0;
1648         } else if (strcasecmp(args.property, "forcecommit") == 0) {
1649                 /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */
1650                 if (ast_strlen_zero(args.opt)) {
1651                         tx = find_transaction(chan, NULL, NULL, 1);
1652                 } else {
1653                         tx = find_transaction(chan, NULL, args.opt, 0);
1654                 }
1655                 if (!tx) {
1656                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1657                         return -1;
1658                 }
1659                 if (ast_true(value)) {
1660                         tx->forcecommit = 1;
1661                 } else if (ast_false(value)) {
1662                         tx->forcecommit = 0;
1663                 } else {
1664                         ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, ""));
1665                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
1666                         return -1;
1667                 }
1668
1669                 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1670                 return 0;
1671         } else if (strcasecmp(args.property, "isolation") == 0) {
1672                 /* How do uncommitted transactions affect reads? */
1673                 int isolation = text2isolation(value);
1674                 if (ast_strlen_zero(args.opt)) {
1675                         tx = find_transaction(chan, NULL, NULL, 1);
1676                 } else {
1677                         tx = find_transaction(chan, NULL, args.opt, 0);
1678                 }
1679                 if (!tx) {
1680                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1681                         return -1;
1682                 }
1683                 if (isolation == 0) {
1684                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
1685                         ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, ""));
1686                 } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) {
1687                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR");
1688                         SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1689                         for (i = 0; i < numfields; i++) {
1690                                 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1691                                 ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
1692                                 if (i > 10) {
1693                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1694                                         break;
1695                                 }
1696                         }
1697                 } else {
1698                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1699                         tx->isolation = isolation;
1700                 }
1701                 return 0;
1702         } else {
1703                 ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property);
1704                 return -1;
1705         }
1706 }
1707
1708 static struct ast_custom_function odbc_function = {
1709         .name = "ODBC",
1710         .read = acf_transaction_read,
1711         .write = acf_transaction_write,
1712 };
1713
1714 static const char * const app_commit = "ODBC_Commit";
1715 static const char * const app_rollback = "ODBC_Rollback";
1716
1717 /*!
1718  * \internal
1719  * \brief Implements the channels provider.
1720  */
1721 static int data_odbc_provider_handler(const struct ast_data_search *search,
1722                 struct ast_data *root)
1723 {
1724         struct ao2_iterator aoi, aoi2;
1725         struct odbc_class *class;
1726         struct odbc_obj *current;
1727         struct ast_data *data_odbc_class, *data_odbc_connections, *data_odbc_connection;
1728         struct ast_data *enum_node;
1729         int count;
1730
1731         aoi = ao2_iterator_init(class_container, 0);
1732         while ((class = ao2_iterator_next(&aoi))) {
1733                 data_odbc_class = ast_data_add_node(root, "class");
1734                 if (!data_odbc_class) {
1735                         ao2_ref(class, -1);
1736                         continue;
1737                 }
1738
1739                 ast_data_add_structure(odbc_class, data_odbc_class, class);
1740
1741                 if (!ao2_container_count(class->obj_container)) {
1742                         ao2_ref(class, -1);
1743                         continue;
1744                 }
1745
1746                 data_odbc_connections = ast_data_add_node(data_odbc_class, "connections");
1747                 if (!data_odbc_connections) {
1748                         ao2_ref(class, -1);
1749                         continue;
1750                 }
1751
1752                 ast_data_add_bool(data_odbc_class, "shared", !class->haspool);
1753                 /* isolation */
1754                 enum_node = ast_data_add_node(data_odbc_class, "isolation");
1755                 if (!enum_node) {
1756                         ao2_ref(class, -1);
1757                         continue;
1758                 }
1759                 ast_data_add_int(enum_node, "value", class->isolation);
1760                 ast_data_add_str(enum_node, "text", isolation2text(class->isolation));
1761
1762                 count = 0;
1763                 aoi2 = ao2_iterator_init(class->obj_container, 0);
1764                 while ((current = ao2_iterator_next(&aoi2))) {
1765                         data_odbc_connection = ast_data_add_node(data_odbc_connections, "connection");
1766                         if (!data_odbc_connection) {
1767                                 ao2_ref(current, -1);
1768                                 continue;
1769                         }
1770
1771                         ao2_lock(current);
1772                         ast_data_add_str(data_odbc_connection, "status", current->used ? "in use" :
1773                                         current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
1774                         ast_data_add_bool(data_odbc_connection, "transactional", current->tx);
1775                         ao2_unlock(current);
1776
1777                         if (class->haspool) {
1778                                 ast_data_add_int(data_odbc_connection, "number", ++count);
1779                         }
1780
1781                         ao2_ref(current, -1);
1782                 }
1783                 ao2_iterator_destroy(&aoi2);
1784                 ao2_ref(class, -1);
1785
1786                 if (!ast_data_search_match(search, data_odbc_class)) {
1787                         ast_data_remove_node(root, data_odbc_class);
1788                 }
1789         }
1790         ao2_iterator_destroy(&aoi);
1791         return 0;
1792 }
1793
1794 /*!
1795  * \internal
1796  * \brief /asterisk/res/odbc/listprovider.
1797  */
1798 static const struct ast_data_handler odbc_provider = {
1799         .version = AST_DATA_HANDLER_VERSION,
1800         .get = data_odbc_provider_handler
1801 };
1802
1803 static const struct ast_data_entry odbc_providers[] = {
1804         AST_DATA_ENTRY("/asterisk/res/odbc", &odbc_provider),
1805 };
1806
1807 static int reload(void)
1808 {
1809         struct odbc_cache_tables *table;
1810         struct odbc_class *class;
1811         struct odbc_obj *current;
1812         struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
1813
1814         /* First, mark all to be purged */
1815         while ((class = ao2_iterator_next(&aoi))) {
1816                 class->delme = 1;
1817                 ao2_ref(class, -1);
1818         }
1819         ao2_iterator_destroy(&aoi);
1820
1821         load_odbc_config();
1822
1823         /* Purge remaining classes */
1824
1825         /* Note on how this works; this is a case of circular references, so we
1826          * explicitly do NOT want to use a callback here (or we wind up in
1827          * recursive hell).
1828          *
1829          * 1. Iterate through all the classes.  Note that the classes will currently
1830          * contain two classes of the same name, one of which is marked delme and
1831          * will be purged when all remaining objects of the class are released, and
1832          * the other, which was created above when we re-parsed the config file.
1833          * 2. On each class, there is a reference held by the master container and
1834          * a reference held by each connection object.  There are two cases for
1835          * destruction of the class, noted below.  However, in all cases, all O-refs
1836          * (references to objects) will first be freed, which will cause the C-refs
1837          * (references to classes) to be decremented (but never to 0, because the
1838          * class container still has a reference).
1839          *    a) If the class has outstanding objects, the C-ref by the class
1840          *    container will then be freed, which leaves only C-refs by any
1841          *    outstanding objects.  When the final outstanding object is released
1842          *    (O-refs held by applications and dialplan functions), it will in turn
1843          *    free the final C-ref, causing class destruction.
1844          *    b) If the class has no outstanding objects, when the class container
1845          *    removes the final C-ref, the class will be destroyed.
1846          */
1847         aoi = ao2_iterator_init(class_container, 0);
1848         while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */
1849                 if (class->delme) {
1850                         struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
1851                         while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */
1852                                 ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */
1853                                 ao2_ref(current, -1); /* O-ref-- (by iterator) */
1854                                 /* At this point, either
1855                                  * a) there's an outstanding O-ref, or
1856                                  * b) the object has already been destroyed.
1857                                  */
1858                         }
1859                         ao2_iterator_destroy(&aoi2);
1860                         ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
1861                         /* At this point, either
1862                          * a) there's an outstanding O-ref, which holds an outstanding C-ref, or
1863                          * b) the last remaining C-ref is held by the iterator, which will be
1864                          * destroyed in the next step.
1865                          */
1866                 }
1867                 ao2_ref(class, -1); /* C-ref-- (by iterator) */
1868         }
1869         ao2_iterator_destroy(&aoi);
1870
1871         /* Empty the cache; it will get rebuilt the next time the tables are needed. */
1872         AST_RWLIST_WRLOCK(&odbc_tables);
1873         while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
1874                 destroy_table_cache(table);
1875         }
1876         AST_RWLIST_UNLOCK(&odbc_tables);
1877
1878         return 0;
1879 }
1880
1881 static int unload_module(void)
1882 {
1883         /* Prohibit unloading */
1884         return -1;
1885 }
1886
1887 /*!
1888  * \brief Load the module
1889  *
1890  * Module loading including tests for configuration or dependencies.
1891  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1892  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1893  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
1894  * configuration file or other non-critical problem return 
1895  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1896  */
1897 static int load_module(void)
1898 {
1899         if (!(class_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr)))
1900                 return AST_MODULE_LOAD_DECLINE;
1901         if (load_odbc_config() == -1)
1902                 return AST_MODULE_LOAD_DECLINE;
1903         ast_cli_register_multiple(cli_odbc, ARRAY_LEN(cli_odbc));
1904         ast_data_register_multiple(odbc_providers, ARRAY_LEN(odbc_providers));
1905         ast_register_application_xml(app_commit, commit_exec);
1906         ast_register_application_xml(app_rollback, rollback_exec);
1907         ast_custom_function_register(&odbc_function);
1908         ast_log(LOG_NOTICE, "res_odbc loaded.\n");
1909         return 0;
1910 }
1911
1912 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "ODBC resource",
1913                 .load = load_module,
1914                 .unload = unload_module,
1915                 .reload = reload,
1916                 .load_pri = AST_MODPRI_REALTIME_DEPEND,
1917                );