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