a few more namespace updates... res_ael_share still needs some work before this can...
[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 obj An active ODBC handle on which to query the table
419  * \param table 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  */
424 struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *tablename)
425 {
426         struct odbc_cache_tables *tableptr;
427         struct odbc_cache_columns *entry;
428         char columnname[80];
429         SQLLEN sqlptr;
430         SQLHSTMT stmt = NULL;
431         int res = 0, error = 0, try = 0;
432         struct odbc_obj *obj = ast_odbc_request_obj(database, 0);
433
434         AST_RWLIST_RDLOCK(&odbc_tables);
435         AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) {
436                 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
437                         break;
438                 }
439         }
440         if (tableptr) {
441                 AST_RWLIST_RDLOCK(&tableptr->columns);
442                 AST_RWLIST_UNLOCK(&odbc_tables);
443                 if (obj) {
444                         ast_odbc_release_obj(obj);
445                 }
446                 return tableptr;
447         }
448
449         if (!obj) {
450                 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
451                 AST_RWLIST_UNLOCK(&odbc_tables);
452                 return NULL;
453         }
454
455         /* Table structure not already cached; build it now. */
456         do {
457                 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
458                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
459                         if (try == 0) {
460                                 try = 1;
461                                 ast_odbc_sanity_check(obj);
462                                 continue;
463                         }
464                         ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
465                         break;
466                 }
467
468                 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS);
469                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
470                         if (try == 0) {
471                                 try = 1;
472                                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
473                                 ast_odbc_sanity_check(obj);
474                                 continue;
475                         }
476                         ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
477                         break;
478                 }
479
480                 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
481                         ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
482                         break;
483                 }
484
485                 tableptr->connection = (char *)tableptr + sizeof(*tableptr);
486                 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1;
487                 strcpy(tableptr->connection, database); /* SAFE */
488                 strcpy(tableptr->table, tablename); /* SAFE */
489                 AST_RWLIST_HEAD_INIT(&(tableptr->columns));
490
491                 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
492                         SQLGetData(stmt,  4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
493
494                         if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) {
495                                 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
496                                 error = 1;
497                                 break;
498                         }
499                         entry->name = (char *)entry + sizeof(*entry);
500                         strcpy(entry->name, columnname);
501
502                         SQLGetData(stmt,  5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
503                         SQLGetData(stmt,  7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
504                         SQLGetData(stmt,  9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
505                         SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
506                         SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
507                         SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
508
509                         /* Specification states that the octenlen should be the maximum number of bytes
510                          * returned in a char or binary column, but it seems that some drivers just set
511                          * it to NULL. (Bad Postgres! No biscuit!) */
512                         if (entry->octetlen == 0) {
513                                 entry->octetlen = entry->size;
514                         }
515
516                         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);
517                         /* Insert column info into column list */
518                         AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
519                 }
520                 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
521
522                 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
523                 AST_RWLIST_RDLOCK(&(tableptr->columns));
524                 break;
525         } while (1);
526
527         AST_RWLIST_UNLOCK(&odbc_tables);
528
529         if (error) {
530                 destroy_table_cache(tableptr);
531                 tableptr = NULL;
532         }
533         if (obj) {
534                 ast_odbc_release_obj(obj);
535         }
536         return tableptr;
537 }
538
539 struct odbc_cache_columns *ast_odbc_find_column(struct odbc_cache_tables *table, const char *colname)
540 {
541         struct odbc_cache_columns *col;
542         AST_RWLIST_TRAVERSE(&table->columns, col, list) {
543                 if (strcasecmp(col->name, colname) == 0) {
544                         return col;
545                 }
546         }
547         return NULL;
548 }
549
550 int ast_odbc_clear_cache(const char *database, const char *tablename)
551 {
552         struct odbc_cache_tables *tableptr;
553
554         AST_RWLIST_WRLOCK(&odbc_tables);
555         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
556                 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
557                         AST_LIST_REMOVE_CURRENT(list);
558                         destroy_table_cache(tableptr);
559                         break;
560                 }
561         }
562         AST_RWLIST_TRAVERSE_SAFE_END
563         AST_RWLIST_UNLOCK(&odbc_tables);
564         return tableptr ? 0 : -1;
565 }
566
567 SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT (*exec_cb)(struct odbc_obj *obj, void *data), void *data)
568 {
569         int attempt;
570         SQLHSTMT stmt;
571
572         for (attempt = 0; attempt < 2; attempt++) {
573                 stmt = exec_cb(obj, data);
574
575                 if (stmt) {
576                         break;
577                 } else if (obj->tx) {
578                         ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n");
579                         break;
580                 } else {
581                         obj->up = 0;
582                         ast_log(LOG_WARNING, "SQL Exec Direct failed.  Attempting a reconnect...\n");
583
584                         odbc_obj_disconnect(obj);
585                         odbc_obj_connect(obj);
586                 }
587         }
588
589         return stmt;
590 }
591
592 SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT (*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
593 {
594         int res = 0, i, attempt;
595         SQLINTEGER nativeerror=0, numfields=0;
596         SQLSMALLINT diagbytes=0;
597         unsigned char state[10], diagnostic[256];
598         SQLHSTMT stmt;
599
600         for (attempt = 0; attempt < 2; attempt++) {
601                 /* This prepare callback may do more than just prepare -- it may also
602                  * bind parameters, bind results, etc.  The real key, here, is that
603                  * when we disconnect, all handles become invalid for most databases.
604                  * We must therefore redo everything when we establish a new
605                  * connection. */
606                 stmt = prepare_cb(obj, data);
607
608                 if (stmt) {
609                         res = SQLExecute(stmt);
610                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
611                                 if (res == SQL_ERROR) {
612                                         SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
613                                         for (i = 0; i < numfields; i++) {
614                                                 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
615                                                 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
616                                                 if (i > 10) {
617                                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
618                                                         break;
619                                                 }
620                                         }
621                                 }
622
623                                 if (obj->tx) {
624                                         ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n");
625                                         break;
626                                 } else {
627                                         ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
628                                         SQLFreeHandle(SQL_HANDLE_STMT, stmt);
629                                         stmt = NULL;
630
631                                         obj->up = 0;
632                                         /*
633                                          * While this isn't the best way to try to correct an error, this won't automatically
634                                          * fail when the statement handle invalidates.
635                                          */
636                                         ast_odbc_sanity_check(obj);
637                                         continue;
638                                 }
639                         } else {
640                                 obj->last_used = ast_tvnow();
641                         }
642                         break;
643                 } else if (attempt == 0) {
644                         ast_odbc_sanity_check(obj);
645                 }
646         }
647
648         return stmt;
649 }
650
651 int ast_odbc_smart_execute(struct odbc_obj *obj, SQLHSTMT stmt) 
652 {
653         int res = 0, i;
654         SQLINTEGER nativeerror=0, numfields=0;
655         SQLSMALLINT diagbytes=0;
656         unsigned char state[10], diagnostic[256];
657
658         res = SQLExecute(stmt);
659         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
660                 if (res == SQL_ERROR) {
661                         SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
662                         for (i = 0; i < numfields; i++) {
663                                 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
664                                 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
665                                 if (i > 10) {
666                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
667                                         break;
668                                 }
669                         }
670                 }
671         } else
672                 obj->last_used = ast_tvnow();
673         
674         return res;
675 }
676
677 SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind)
678 {
679         SQLRETURN res;
680
681         if (pmaxlen == 0) {
682                 if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
683                         ast_str_make_space(buf, *StrLen_or_Ind + 1);
684                 }
685         } else if (pmaxlen > 0) {
686                 ast_str_make_space(buf, pmaxlen);
687         }
688         res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
689         ast_str_update(*buf);
690
691         return res;
692 }
693
694 int ast_odbc_sanity_check(struct odbc_obj *obj) 
695 {
696         char *test_sql = "select 1";
697         SQLHSTMT stmt;
698         int res = 0;
699
700         if (!ast_strlen_zero(obj->parent->sanitysql))
701                 test_sql = obj->parent->sanitysql;
702
703         if (obj->up) {
704                 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
705                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
706                         obj->up = 0;
707                 } else {
708                         res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
709                         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
710                                 obj->up = 0;
711                         } else {
712                                 res = SQLExecute(stmt);
713                                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
714                                         obj->up = 0;
715                                 }
716                         }
717                 }
718                 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
719         }
720
721         if (!obj->up && !obj->tx) { /* Try to reconnect! */
722                 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
723                 odbc_obj_disconnect(obj);
724                 odbc_obj_connect(obj);
725         }
726         return obj->up;
727 }
728
729 static int load_odbc_config(void)
730 {
731         static char *cfg = "res_odbc.conf";
732         struct ast_config *config;
733         struct ast_variable *v;
734         char *cat;
735         const char *dsn, *username, *password, *sanitysql;
736         int enabled, pooling, limit, bse, forcecommit, isolation;
737         unsigned int idlecheck;
738         int preconnect = 0, res = 0;
739         struct ast_flags config_flags = { 0 };
740
741         struct odbc_class *new;
742
743         config = ast_config_load(cfg, config_flags);
744         if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
745                 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
746                 return -1;
747         }
748         for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
749                 if (!strcasecmp(cat, "ENV")) {
750                         for (v = ast_variable_browse(config, cat); v; v = v->next) {
751                                 setenv(v->name, v->value, 1);
752                                 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
753                         }
754                 } else {
755                         /* Reset all to defaults for each class of odbc connections */
756                         dsn = username = password = sanitysql = NULL;
757                         enabled = 1;
758                         preconnect = idlecheck = 0;
759                         pooling = 0;
760                         limit = 0;
761                         bse = 1;
762                         forcecommit = 0;
763                         isolation = SQL_TXN_READ_COMMITTED;
764                         for (v = ast_variable_browse(config, cat); v; v = v->next) {
765                                 if (!strcasecmp(v->name, "pooling")) {
766                                         if (ast_true(v->value))
767                                                 pooling = 1;
768                                 } else if (!strncasecmp(v->name, "share", 5)) {
769                                         /* "shareconnections" is a little clearer in meaning than "pooling" */
770                                         if (ast_false(v->value))
771                                                 pooling = 1;
772                                 } else if (!strcasecmp(v->name, "limit")) {
773                                         sscanf(v->value, "%d", &limit);
774                                         if (ast_true(v->value) && !limit) {
775                                                 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);
776                                                 limit = 1023;
777                                         } else if (ast_false(v->value)) {
778                                                 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'.  Disabling ODBC class '%s'.\n", v->value, cat);
779                                                 enabled = 0;
780                                                 break;
781                                         }
782                                 } else if (!strcasecmp(v->name, "idlecheck")) {
783                                         sscanf(v->value, "%d", &idlecheck);
784                                 } else if (!strcasecmp(v->name, "enabled")) {
785                                         enabled = ast_true(v->value);
786                                 } else if (!strcasecmp(v->name, "pre-connect")) {
787                                         preconnect = ast_true(v->value);
788                                 } else if (!strcasecmp(v->name, "dsn")) {
789                                         dsn = v->value;
790                                 } else if (!strcasecmp(v->name, "username")) {
791                                         username = v->value;
792                                 } else if (!strcasecmp(v->name, "password")) {
793                                         password = v->value;
794                                 } else if (!strcasecmp(v->name, "sanitysql")) {
795                                         sanitysql = v->value;
796                                 } else if (!strcasecmp(v->name, "backslash_is_escape")) {
797                                         bse = ast_true(v->value);
798                                 } else if (!strcasecmp(v->name, "forcecommit")) {
799                                         forcecommit = ast_true(v->value);
800                                 } else if (!strcasecmp(v->name, "isolation")) {
801                                         if ((isolation = text2isolation(v->value)) == 0) {
802                                                 ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat);
803                                                 isolation = SQL_TXN_READ_COMMITTED;
804                                         }
805                                 }
806                         }
807
808                         if (enabled && !ast_strlen_zero(dsn)) {
809                                 new = ao2_alloc(sizeof(*new), odbc_class_destructor);
810
811                                 if (!new) {
812                                         res = -1;
813                                         break;
814                                 }
815
816                                 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
817                                 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
818
819                                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
820                                         ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
821                                         ao2_ref(new, -1);
822                                         return res;
823                                 }
824
825                                 new->obj_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr);
826
827                                 if (pooling) {
828                                         new->haspool = pooling;
829                                         if (limit) {
830                                                 new->limit = limit;
831                                         } else {
832                                                 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless.  Changing limit from 0 to 5.\n");
833                                                 new->limit = 5;
834                                         }
835                                 }
836
837                                 new->backslash_is_escape = bse ? 1 : 0;
838                                 new->forcecommit = forcecommit ? 1 : 0;
839                                 new->isolation = isolation;
840                                 new->idlecheck = idlecheck;
841
842                                 if (cat)
843                                         ast_copy_string(new->name, cat, sizeof(new->name));
844                                 if (dsn)
845                                         ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
846                                 if (username && !(new->username = ast_strdup(username))) {
847                                         ao2_ref(new, -1);
848                                         break;
849                                 }
850                                 if (password && !(new->password = ast_strdup(password))) {
851                                         ao2_ref(new, -1);
852                                         break;
853                                 }
854                                 if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) {
855                                         ao2_ref(new, -1);
856                                         break;
857                                 }
858
859                                 odbc_register_class(new, preconnect);
860                                 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
861                                 ao2_ref(new, -1);
862                                 new = NULL;
863                         }
864                 }
865         }
866         ast_config_destroy(config);
867         return res;
868 }
869
870 static char *handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
871 {
872         struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
873         struct odbc_class *class;
874         struct odbc_obj *current;
875         int length = 0;
876         int which = 0;
877         char *ret = NULL;
878
879         switch (cmd) {
880         case CLI_INIT:
881                 e->command = "odbc show";
882                 e->usage =
883                                 "Usage: odbc show [class]\n"
884                                 "       List settings of a particular ODBC class or,\n"
885                                 "       if not specified, all classes.\n";
886                 return NULL;
887         case CLI_GENERATE:
888                 if (a->pos != 2)
889                         return NULL;
890                 length = strlen(a->word);
891                 while ((class = ao2_iterator_next(&aoi))) {
892                         if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
893                                 ret = ast_strdup(class->name);
894                         }
895                         ao2_ref(class, -1);
896                         if (ret) {
897                                 break;
898                         }
899                 }
900                 if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
901                         ret = ast_strdup("all");
902                 }
903                 return ret;
904         }
905
906         ast_cli(a->fd, "\nODBC DSN Settings\n");
907         ast_cli(a->fd,   "-----------------\n\n");
908         aoi = ao2_iterator_init(class_container, 0);
909         while ((class = ao2_iterator_next(&aoi))) {
910                 if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
911                         int count = 0;
912                         ast_cli(a->fd, "  Name:   %s\n  DSN:    %s\n", class->name, class->dsn);
913
914                         if (class->haspool) {
915                                 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
916
917                                 ast_cli(a->fd, "  Pooled: Yes\n  Limit:  %d\n  Connections in use: %d\n", class->limit, class->count);
918
919                                 while ((current = ao2_iterator_next(&aoi2))) {
920                                         ast_mutex_lock(&current->lock);
921 #ifdef DEBUG_THREADS
922                                         ast_cli(a->fd, "    - Connection %d: %s (%s:%d %s)\n", ++count,
923                                                 current->used ? "in use" :
924                                                 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected",
925                                                 current->file, current->lineno, current->function);
926 #else
927                                         ast_cli(a->fd, "    - Connection %d: %s\n", ++count,
928                                                 current->used ? "in use" :
929                                                 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
930 #endif
931                                         ast_mutex_unlock(&current->lock);
932                                         ao2_ref(current, -1);
933                                 }
934                         } else {
935                                 /* Should only ever be one of these (unless there are transactions) */
936                                 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
937                                 while ((current = ao2_iterator_next(&aoi2))) {
938                                         ast_cli(a->fd, "  Pooled: No\n  Connected: %s\n", current->used ? "In use" :
939                                                 current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
940                                         ao2_ref(current, -1);
941                                 }
942                         }
943                         ast_cli(a->fd, "\n");
944                 }
945                 ao2_ref(class, -1);
946         }
947
948         return CLI_SUCCESS;
949 }
950
951 static struct ast_cli_entry cli_odbc[] = {
952         AST_CLI_DEFINE(handle_cli_odbc_show, "List ODBC DSN(s)")
953 };
954
955 static int odbc_register_class(struct odbc_class *class, int preconnect)
956 {
957         struct odbc_obj *obj;
958         if (class) {
959                 ao2_link(class_container, class);
960                 /* I still have a reference in the caller, so a deref is NOT missing here. */
961
962                 if (preconnect) {
963                         /* Request and release builds a connection */
964                         obj = ast_odbc_request_obj(class->name, 0);
965                         if (obj) {
966                                 ast_odbc_release_obj(obj);
967                         }
968                 }
969
970                 return 0;
971         } else {
972                 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
973                 return -1;
974         }
975 }
976
977 static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx)
978 {
979         SQLINTEGER nativeerror=0, numfields=0;
980         SQLSMALLINT diagbytes=0, i;
981         unsigned char state[10], diagnostic[256];
982
983         ast_debug(2, "odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->txf);
984         if (tx) {
985                 ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK");
986                 if (SQLEndTran(SQL_HANDLE_DBC, obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
987                         /* Handle possible transaction commit failure */
988                         SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
989                         for (i = 0; i < numfields; i++) {
990                                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
991                                 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
992                                 if (!strcmp((char *)state, "25S02") || !strcmp((char *)state, "08007")) {
993                                         /* These codes mean that a commit failed and a transaction
994                                          * is still active. We must rollback, or things will get
995                                          * very, very weird for anybody using the handle next. */
996                                         SQLEndTran(SQL_HANDLE_DBC, obj->con, SQL_ROLLBACK);
997                                 }
998                                 if (i > 10) {
999                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1000                                         break;
1001                                 }
1002                         }
1003                 }
1004
1005                 /* Transaction is done, reset autocommit */
1006                 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
1007                         SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1008                         for (i = 0; i < numfields; i++) {
1009                                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1010                                 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1011                                 if (i > 10) {
1012                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1013                                         break;
1014                                 }
1015                         }
1016                 }
1017         }
1018
1019 #ifdef DEBUG_THREADS
1020         obj->file[0] = '\0';
1021         obj->function[0] = '\0';
1022         obj->lineno = 0;
1023 #endif
1024
1025         /* For pooled connections, this frees the connection to be
1026          * reused.  For non-pooled connections, it does nothing. */
1027         obj->used = 0;
1028         if (obj->txf) {
1029                 /* Prevent recursion -- transaction is already closed out. */
1030                 obj->txf->obj = NULL;
1031                 obj->txf = release_transaction(obj->txf);
1032         }
1033         ao2_ref(obj, -1);
1034 }
1035
1036 void ast_odbc_release_obj(struct odbc_obj *obj)
1037 {
1038         struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
1039         odbc_release_obj2(obj, tx);
1040 }
1041
1042 int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
1043 {
1044         return obj->parent->backslash_is_escape;
1045 }
1046
1047 static int commit_exec(struct ast_channel *chan, void *data)
1048 {
1049         struct odbc_txn_frame *tx;
1050         SQLINTEGER nativeerror=0, numfields=0;
1051         SQLSMALLINT diagbytes=0, i;
1052         unsigned char state[10], diagnostic[256];
1053
1054         if (ast_strlen_zero(data)) {
1055                 tx = find_transaction(chan, NULL, NULL, 1);
1056         } else {
1057                 tx = find_transaction(chan, NULL, data, 0);
1058         }
1059
1060         pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK");
1061
1062         if (tx) {
1063                 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) {
1064                         struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
1065                         ast_str_reset(errors);
1066
1067                         /* Handle possible transaction commit failure */
1068                         SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1069                         for (i = 0; i < numfields; i++) {
1070                                 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1071                                 ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
1072                                 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
1073                                 if (i > 10) {
1074                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1075                                         break;
1076                                 }
1077                         }
1078                         pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
1079                 }
1080         }
1081         return 0;
1082 }
1083
1084 static int rollback_exec(struct ast_channel *chan, void *data)
1085 {
1086         struct odbc_txn_frame *tx;
1087         SQLINTEGER nativeerror=0, numfields=0;
1088         SQLSMALLINT diagbytes=0, i;
1089         unsigned char state[10], diagnostic[256];
1090
1091         if (ast_strlen_zero(data)) {
1092                 tx = find_transaction(chan, NULL, NULL, 1);
1093         } else {
1094                 tx = find_transaction(chan, NULL, data, 0);
1095         }
1096
1097         pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK");
1098
1099         if (tx) {
1100                 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) {
1101                         struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
1102                         ast_str_reset(errors);
1103
1104                         /* Handle possible transaction commit failure */
1105                         SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1106                         for (i = 0; i < numfields; i++) {
1107                                 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1108                                 ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
1109                                 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
1110                                 if (i > 10) {
1111                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1112                                         break;
1113                                 }
1114                         }
1115                         pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
1116                 }
1117         }
1118         return 0;
1119 }
1120
1121 static int aoro2_class_cb(void *obj, void *arg, int flags)
1122 {
1123         struct odbc_class *class = obj;
1124         char *name = arg;
1125         if (!strcmp(class->name, name) && !class->delme) {
1126                 return CMP_MATCH | CMP_STOP;
1127         }
1128         return 0;
1129 }
1130
1131 #define USE_TX (void *)(long)1
1132 #define NO_TX  (void *)(long)2
1133 #define EOR_TX (void *)(long)3
1134
1135 static int aoro2_obj_cb(void *vobj, void *arg, int flags)
1136 {
1137         struct odbc_obj *obj = vobj;
1138         ast_mutex_lock(&obj->lock);
1139         if ((arg == NO_TX && !obj->tx) || (arg == EOR_TX && !obj->used) || (arg == USE_TX && obj->tx && !obj->used)) {
1140                 obj->used = 1;
1141                 ast_mutex_unlock(&obj->lock);
1142                 return CMP_MATCH | CMP_STOP;
1143         }
1144         ast_mutex_unlock(&obj->lock);
1145         return 0;
1146 }
1147
1148 #ifdef DEBUG_THREADS
1149 struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
1150 #else
1151 struct odbc_obj *ast_odbc_request_obj2(const char *name, struct ast_flags flags)
1152 #endif
1153 {
1154         struct odbc_obj *obj = NULL;
1155         struct odbc_class *class;
1156         SQLINTEGER nativeerror=0, numfields=0;
1157         SQLSMALLINT diagbytes=0, i;
1158         unsigned char state[10], diagnostic[256];
1159
1160         if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
1161                 return NULL;
1162         }
1163
1164         ast_assert(ao2_ref(class, 0) > 1);
1165
1166         if (class->haspool) {
1167                 /* Recycle connections before building another */
1168                 obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX);
1169
1170                 if (obj) {
1171                         ast_assert(ao2_ref(obj, 0) > 1);
1172                 }
1173
1174                 if (!obj && (class->count < class->limit)) {
1175                         obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
1176                         if (!obj) {
1177                                 ao2_ref(class, -1);
1178                                 return NULL;
1179                         }
1180                         ast_assert(ao2_ref(obj, 0) == 1);
1181                         ast_mutex_init(&obj->lock);
1182                         /* obj inherits the outstanding reference to class */
1183                         obj->parent = class;
1184                         class = NULL;
1185                         if (odbc_obj_connect(obj) == ODBC_FAIL) {
1186                                 ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1187                                 ao2_ref(obj, -1);
1188                                 ast_assert(ao2_ref(class, 0) > 0);
1189                                 obj = NULL;
1190                         } else {
1191                                 obj->used = 1;
1192                                 ao2_link(obj->parent->obj_container, obj);
1193                                 ast_atomic_fetchadd_int(&obj->parent->count, +1);
1194                         }
1195                 } else {
1196                         /* Object is not constructed, so delete outstanding reference to class. */
1197                         ao2_ref(class, -1);
1198                         class = NULL;
1199                 }
1200
1201                 if (obj && ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
1202                         /* Ensure this connection has autocommit turned off. */
1203                         if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
1204                                 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1205                                 for (i = 0; i < numfields; i++) {
1206                                         SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1207                                         ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1208                                         if (i > 10) {
1209                                                 ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1210                                                 break;
1211                                         }
1212                                 }
1213                         }
1214                 }
1215         } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
1216                 /* Non-pooled connections -- but must use a separate connection handle */
1217                 if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) {
1218                         obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
1219                         if (!obj) {
1220                                 ao2_ref(class, -1);
1221                                 return NULL;
1222                         }
1223                         ast_mutex_init(&obj->lock);
1224                         /* obj inherits the outstanding reference to class */
1225                         obj->parent = class;
1226                         class = NULL;
1227                         if (odbc_obj_connect(obj) == ODBC_FAIL) {
1228                                 ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1229                                 ao2_ref(obj, -1);
1230                                 obj = NULL;
1231                         } else {
1232                                 obj->used = 1;
1233                                 ao2_link(obj->parent->obj_container, obj);
1234                                 ast_atomic_fetchadd_int(&obj->parent->count, +1);
1235                         }
1236                 }
1237
1238                 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
1239                         SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1240                         for (i = 0; i < numfields; i++) {
1241                                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1242                                 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1243                                 if (i > 10) {
1244                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1245                                         break;
1246                                 }
1247                         }
1248                 }
1249         } else {
1250                 /* Non-pooled connection: multiple modules can use the same connection. */
1251                 if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, NO_TX))) {
1252                         /* Object is not constructed, so delete outstanding reference to class. */
1253                         ast_assert(ao2_ref(class, 0) > 1);
1254                         ao2_ref(class, -1);
1255                         class = NULL;
1256                 } else {
1257                         /* No entry: build one */
1258                         if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) {
1259                                 ast_assert(ao2_ref(class, 0) > 1);
1260                                 ao2_ref(class, -1);
1261                                 return NULL;
1262                         }
1263                         ast_mutex_init(&obj->lock);
1264                         /* obj inherits the outstanding reference to class */
1265                         obj->parent = class;
1266                         class = NULL;
1267                         if (odbc_obj_connect(obj) == ODBC_FAIL) {
1268                                 ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1269                                 ao2_ref(obj, -1);
1270                                 obj = NULL;
1271                         } else {
1272                                 ao2_link(obj->parent->obj_container, obj);
1273                                 ast_assert(ao2_ref(obj, 0) > 1);
1274                         }
1275                 }
1276
1277                 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
1278                         SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1279                         for (i = 0; i < numfields; i++) {
1280                                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1281                                 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1282                                 if (i > 10) {
1283                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1284                                         break;
1285                                 }
1286                         }
1287                 }
1288         }
1289
1290         /* Set the isolation property */
1291         if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
1292                 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1293                 for (i = 0; i < numfields; i++) {
1294                         SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1295                         ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
1296                         if (i > 10) {
1297                                 ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1298                                 break;
1299                         }
1300                 }
1301         }
1302
1303         if (obj && ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
1304                 ast_odbc_sanity_check(obj);
1305         } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck)
1306                 odbc_obj_connect(obj);
1307
1308 #ifdef DEBUG_THREADS
1309         if (obj) {
1310                 ast_copy_string(obj->file, file, sizeof(obj->file));
1311                 ast_copy_string(obj->function, function, sizeof(obj->function));
1312                 obj->lineno = lineno;
1313         }
1314 #endif
1315         ast_assert(class == NULL);
1316
1317         if (obj) {
1318                 ast_assert(ao2_ref(obj, 0) > 1);
1319         }
1320         return obj;
1321 }
1322
1323 #ifdef DEBUG_THREADS
1324 struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno)
1325 #else
1326 struct odbc_obj *ast_odbc_request_obj(const char *name, int check)
1327 #endif
1328 {
1329         struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
1330 #ifdef DEBUG_THREADS
1331         return _ast_odbc_request_obj2(name, flags, file, function, lineno);
1332 #else
1333         return ast_odbc_request_obj2(name, flags);
1334 #endif
1335 }
1336
1337 struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname)
1338 {
1339         struct ast_datastore *txn_store;
1340         AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
1341         struct odbc_txn_frame *txn = NULL;
1342
1343         if (!chan) {
1344                 /* No channel == no transaction */
1345                 return NULL;
1346         }
1347
1348         ast_channel_lock(chan);
1349         if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
1350                 oldlist = txn_store->data;
1351         } else {
1352                 ast_channel_unlock(chan);
1353                 return NULL;
1354         }
1355
1356         AST_LIST_LOCK(oldlist);
1357         ast_channel_unlock(chan);
1358
1359         AST_LIST_TRAVERSE(oldlist, txn, list) {
1360                 if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) {
1361                         AST_LIST_UNLOCK(oldlist);
1362                         return txn->obj;
1363                 }
1364         }
1365         AST_LIST_UNLOCK(oldlist);
1366         return NULL;
1367 }
1368
1369 static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
1370 {
1371         int res;
1372         SQLINTEGER err;
1373         short int mlen;
1374         unsigned char msg[200], state[10];
1375
1376         /* Nothing to disconnect */
1377         if (!obj->con) {
1378                 return ODBC_SUCCESS;
1379         }
1380
1381         ast_mutex_lock(&obj->lock);
1382
1383         res = SQLDisconnect(obj->con);
1384
1385         if (obj->parent) {
1386                 if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
1387                         ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
1388                 } else {
1389                         ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
1390                 }
1391         }
1392
1393         if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == SQL_SUCCESS)) {
1394                 obj->con = NULL;
1395                 ast_log(LOG_DEBUG, "Database handle deallocated\n");
1396         } else {
1397                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen);
1398                 ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg);
1399         }
1400
1401         obj->up = 0;
1402         ast_mutex_unlock(&obj->lock);
1403         return ODBC_SUCCESS;
1404 }
1405
1406 static odbc_status odbc_obj_connect(struct odbc_obj *obj)
1407 {
1408         int res;
1409         SQLINTEGER err;
1410         short int mlen;
1411         unsigned char msg[200], state[10];
1412 #ifdef NEEDTRACE
1413         SQLINTEGER enable = 1;
1414         char *tracefile = "/tmp/odbc.trace";
1415 #endif
1416         ast_mutex_lock(&obj->lock);
1417
1418         if (obj->up) {
1419                 odbc_obj_disconnect(obj);
1420                 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
1421         } else {
1422                 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
1423         }
1424
1425         res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con);
1426
1427         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1428                 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
1429                 ast_mutex_unlock(&obj->lock);
1430                 return ODBC_FAIL;
1431         }
1432         SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
1433         SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0);
1434 #ifdef NEEDTRACE
1435         SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
1436         SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
1437 #endif
1438
1439         res = SQLConnect(obj->con,
1440                    (SQLCHAR *) obj->parent->dsn, SQL_NTS,
1441                    (SQLCHAR *) obj->parent->username, SQL_NTS,
1442                    (SQLCHAR *) obj->parent->password, SQL_NTS);
1443
1444         if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1445                 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen);
1446                 ast_mutex_unlock(&obj->lock);
1447                 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
1448                 return ODBC_FAIL;
1449         } else {
1450                 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
1451                 obj->up = 1;
1452                 obj->last_used = ast_tvnow();
1453         }
1454
1455         ast_mutex_unlock(&obj->lock);
1456         return ODBC_SUCCESS;
1457 }
1458
1459 static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1460 {
1461         AST_DECLARE_APP_ARGS(args,
1462                 AST_APP_ARG(property);
1463                 AST_APP_ARG(opt);
1464         );
1465         struct odbc_txn_frame *tx;
1466
1467         AST_STANDARD_APP_ARGS(args, data);
1468         if (strcasecmp(args.property, "transaction") == 0) {
1469                 if ((tx = find_transaction(chan, NULL, NULL, 1))) {
1470                         ast_copy_string(buf, tx->name, len);
1471                         return 0;
1472                 }
1473         } else if (strcasecmp(args.property, "isolation") == 0) {
1474                 if (!ast_strlen_zero(args.opt)) {
1475                         tx = find_transaction(chan, NULL, args.opt, 0);
1476                 } else {
1477                         tx = find_transaction(chan, NULL, NULL, 1);
1478                 }
1479                 if (tx) {
1480                         ast_copy_string(buf, isolation2text(tx->isolation), len);
1481                         return 0;
1482                 }
1483         } else if (strcasecmp(args.property, "forcecommit") == 0) {
1484                 if (!ast_strlen_zero(args.opt)) {
1485                         tx = find_transaction(chan, NULL, args.opt, 0);
1486                 } else {
1487                         tx = find_transaction(chan, NULL, NULL, 1);
1488                 }
1489                 if (tx) {
1490                         ast_copy_string(buf, tx->forcecommit ? "1" : "0", len);
1491                         return 0;
1492                 }
1493         }
1494         return -1;
1495 }
1496
1497 static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
1498 {
1499         AST_DECLARE_APP_ARGS(args,
1500                 AST_APP_ARG(property);
1501                 AST_APP_ARG(opt);
1502         );
1503         struct odbc_txn_frame *tx;
1504         SQLINTEGER nativeerror=0, numfields=0;
1505         SQLSMALLINT diagbytes=0, i;
1506         unsigned char state[10], diagnostic[256];
1507
1508         AST_STANDARD_APP_ARGS(args, s);
1509         if (strcasecmp(args.property, "transaction") == 0) {
1510                 /* Set active transaction */
1511                 struct odbc_obj *obj;
1512                 if ((tx = find_transaction(chan, NULL, value, 0))) {
1513                         mark_transaction_active(chan, tx);
1514                 } else {
1515                         /* No such transaction, create one */
1516                         struct ast_flags flags = { RES_ODBC_INDEPENDENT_CONNECTION };
1517                         if (ast_strlen_zero(args.opt) || !(obj = ast_odbc_request_obj2(args.opt, flags))) {
1518                                 ast_log(LOG_ERROR, "Could not create transaction: invalid database specification '%s'\n", S_OR(args.opt, ""));
1519                                 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_DB");
1520                                 return -1;
1521                         }
1522                         if (!(tx = find_transaction(chan, obj, value, 0))) {
1523                                 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1524                                 return -1;
1525                         }
1526                         obj->tx = 1;
1527                 }
1528                 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1529                 return 0;
1530         } else if (strcasecmp(args.property, "forcecommit") == 0) {
1531                 /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */
1532                 if (ast_strlen_zero(args.opt)) {
1533                         tx = find_transaction(chan, NULL, NULL, 1);
1534                 } else {
1535                         tx = find_transaction(chan, NULL, args.opt, 0);
1536                 }
1537                 if (!tx) {
1538                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1539                         return -1;
1540                 }
1541                 if (ast_true(value)) {
1542                         tx->forcecommit = 1;
1543                 } else if (ast_false(value)) {
1544                         tx->forcecommit = 0;
1545                 } else {
1546                         ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, ""));
1547                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
1548                         return -1;
1549                 }
1550
1551                 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1552                 return 0;
1553         } else if (strcasecmp(args.property, "isolation") == 0) {
1554                 /* How do uncommitted transactions affect reads? */
1555                 int isolation = text2isolation(value);
1556                 if (ast_strlen_zero(args.opt)) {
1557                         tx = find_transaction(chan, NULL, NULL, 1);
1558                 } else {
1559                         tx = find_transaction(chan, NULL, args.opt, 0);
1560                 }
1561                 if (!tx) {
1562                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1563                         return -1;
1564                 }
1565                 if (isolation == 0) {
1566                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
1567                         ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, ""));
1568                 } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) {
1569                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR");
1570                         SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1571                         for (i = 0; i < numfields; i++) {
1572                                 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1573                                 ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
1574                                 if (i > 10) {
1575                                         ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
1576                                         break;
1577                                 }
1578                         }
1579                 } else {
1580                         pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1581                         tx->isolation = isolation;
1582                 }
1583                 return 0;
1584         } else {
1585                 ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property);
1586                 return -1;
1587         }
1588 }
1589
1590 static struct ast_custom_function odbc_function = {
1591         .name = "ODBC",
1592         .read = acf_transaction_read,
1593         .write = acf_transaction_write,
1594 };
1595
1596 static const char *app_commit = "ODBC_Commit";
1597 static const char *app_rollback = "ODBC_Rollback";
1598
1599 static int reload(void)
1600 {
1601         struct odbc_cache_tables *table;
1602         struct odbc_class *class;
1603         struct odbc_obj *current;
1604         struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
1605
1606         /* First, mark all to be purged */
1607         while ((class = ao2_iterator_next(&aoi))) {
1608                 class->delme = 1;
1609                 ao2_ref(class, -1);
1610         }
1611
1612         load_odbc_config();
1613
1614         /* Purge remaining classes */
1615
1616         /* Note on how this works; this is a case of circular references, so we
1617          * explicitly do NOT want to use a callback here (or we wind up in
1618          * recursive hell).
1619          *
1620          * 1. Iterate through all the classes.  Note that the classes will currently
1621          * contain two classes of the same name, one of which is marked delme and
1622          * will be purged when all remaining objects of the class are released, and
1623          * the other, which was created above when we re-parsed the config file.
1624          * 2. On each class, there is a reference held by the master container and
1625          * a reference held by each connection object.  There are two cases for
1626          * destruction of the class, noted below.  However, in all cases, all O-refs
1627          * (references to objects) will first be freed, which will cause the C-refs
1628          * (references to classes) to be decremented (but never to 0, because the
1629          * class container still has a reference).
1630          *    a) If the class has outstanding objects, the C-ref by the class
1631          *    container will then be freed, which leaves only C-refs by any
1632          *    outstanding objects.  When the final outstanding object is released
1633          *    (O-refs held by applications and dialplan functions), it will in turn
1634          *    free the final C-ref, causing class destruction.
1635          *    b) If the class has no outstanding objects, when the class container
1636          *    removes the final C-ref, the class will be destroyed.
1637          */
1638         aoi = ao2_iterator_init(class_container, 0);
1639         while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */
1640                 if (class->delme) {
1641                         struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
1642                         while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */
1643                                 ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */
1644                                 ao2_ref(current, -1); /* O-ref-- (by iterator) */
1645                                 /* At this point, either
1646                                  * a) there's an outstanding O-ref, or
1647                                  * b) the object has already been destroyed.
1648                                  */
1649                         }
1650                         ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
1651                         /* At this point, either
1652                          * a) there's an outstanding O-ref, which holds an outstanding C-ref, or
1653                          * b) the last remaining C-ref is held by the iterator, which will be
1654                          * destroyed in the next step.
1655                          */
1656                 }
1657                 ao2_ref(class, -1); /* C-ref-- (by iterator) */
1658         }
1659
1660         /* Empty the cache; it will get rebuilt the next time the tables are needed. */
1661         AST_RWLIST_WRLOCK(&odbc_tables);
1662         while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
1663                 destroy_table_cache(table);
1664         }
1665         AST_RWLIST_UNLOCK(&odbc_tables);
1666
1667         return 0;
1668 }
1669
1670 static int unload_module(void)
1671 {
1672         /* Prohibit unloading */
1673         return -1;
1674 }
1675
1676 static int load_module(void)
1677 {
1678         if (!(class_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr)))
1679                 return AST_MODULE_LOAD_DECLINE;
1680         if (load_odbc_config() == -1)
1681                 return AST_MODULE_LOAD_DECLINE;
1682         ast_cli_register_multiple(cli_odbc, ARRAY_LEN(cli_odbc));
1683         ast_register_application_xml(app_commit, commit_exec);
1684         ast_register_application_xml(app_rollback, rollback_exec);
1685         ast_custom_function_register(&odbc_function);
1686         ast_log(LOG_NOTICE, "res_odbc loaded.\n");
1687         return 0;
1688 }
1689
1690 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "ODBC resource",
1691                 .load = load_module,
1692                 .unload = unload_module,
1693                 .reload = reload,
1694                );