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