Wed Oct 28 11:53:08 2009

Asterisk developer's documentation


res_odbc.c File Reference

ODBC resource manager. More...

#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/res_odbc.h"
#include "asterisk/time.h"
#include "asterisk/astobj2.h"

Include dependency graph for res_odbc.c:

Go to the source code of this file.

Data Structures

struct  odbc_class
struct  odbc_tables

Functions

static void __fini_odbc_tables (void)
static void __init_odbc_tables (void)
static void __reg_module (void)
static void __unreg_module (void)
int ast_odbc_backslash_is_escape (struct odbc_obj *obj)
 Checks if the database natively supports backslash as an escape character.
int ast_odbc_clear_cache (const char *database, const char *tablename)
 Remove a cache entry from memory.
SQLHSTMT ast_odbc_direct_execute (struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data)
 Executes an non prepared statement and returns the resulting statement handle.
struct odbc_cache_columnsast_odbc_find_column (struct odbc_cache_tables *table, const char *colname)
 Find a column entry within a cached table structure.
struct odbc_cache_tablesast_odbc_find_table (const char *database, const char *tablename)
 Find or create an entry describing the table specified.
SQLHSTMT ast_odbc_prepare_and_execute (struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
 Prepares, executes, and returns the resulting statement handle.
void ast_odbc_release_obj (struct odbc_obj *obj)
 Releases an ODBC object previously allocated by odbc_request_obj().
struct odbc_objast_odbc_request_obj (const char *name, int check)
 Retrieves a connected ODBC object.
int ast_odbc_sanity_check (struct odbc_obj *obj)
 Checks an ODBC object to ensure it is still connected.
int ast_odbc_smart_execute (struct odbc_obj *obj, SQLHSTMT stmt)
 Executes a prepared statement handle.
static void destroy_table_cache (struct odbc_cache_tables *table)
static char * handle_cli_odbc_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int load_module (void)
static int load_odbc_config (void)
static int null_hash_fn (const void *obj, const int flags)
static void odbc_class_destructor (void *data)
static odbc_status odbc_obj_connect (struct odbc_obj *obj)
static void odbc_obj_destructor (void *data)
static odbc_status odbc_obj_disconnect (struct odbc_obj *obj)
static int odbc_register_class (struct odbc_class *class, int connect)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "ODBC resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
struct ao2_containerclass_container
static struct ast_cli_entry cli_odbc []


Detailed Description

ODBC resource manager.

Author:
Mark Spencer <markster@digium.com>

Anthony Minessale II <anthmct@yahoo.com>

Definition in file res_odbc.c.


Function Documentation

static void __fini_odbc_tables ( void   )  [static]

Definition at line 72 of file res_odbc.c.

00079 {

static void __init_odbc_tables ( void   )  [static]

Definition at line 72 of file res_odbc.c.

00079 {

static void __reg_module ( void   )  [static]

Definition at line 970 of file res_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 970 of file res_odbc.c.

int ast_odbc_backslash_is_escape ( struct odbc_obj obj  ) 

Checks if the database natively supports backslash as an escape character.

Parameters:
obj The ODBC object
Returns:
Returns 1 if backslash is a native escape character, 0 if an ESCAPE clause is needed to support '\'

Definition at line 659 of file res_odbc.c.

References odbc_class::backslash_is_escape, and odbc_obj::parent.

Referenced by odbc_log(), realtime_multi_odbc(), and realtime_odbc().

00660 {
00661    return obj->parent->backslash_is_escape;
00662 }

int ast_odbc_clear_cache ( const char *  database,
const char *  tablename 
)

Remove a cache entry from memory.

Parameters:
database Name of an ODBC class (used to ensure like-named tables in different databases are not confused)
table Tablename for which a cached record should be removed
Return values:
0 if the cache entry was removed, or -1 if no matching entry was found.
Since:
1.6.1

Definition at line 254 of file res_odbc.c.

References AST_LIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, odbc_cache_tables::connection, destroy_table_cache(), odbc_class::list, and odbc_cache_tables::table.

00255 {
00256    struct odbc_cache_tables *tableptr;
00257 
00258    AST_RWLIST_WRLOCK(&odbc_tables);
00259    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
00260       if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
00261          AST_LIST_REMOVE_CURRENT(list);
00262          destroy_table_cache(tableptr);
00263          break;
00264       }
00265    }
00266    AST_RWLIST_TRAVERSE_SAFE_END
00267    AST_RWLIST_UNLOCK(&odbc_tables);
00268    return tableptr ? 0 : -1;
00269 }

SQLHSTMT ast_odbc_direct_execute ( struct odbc_obj obj,
SQLHSTMT(*)(struct odbc_obj *obj, void *data)  exec_cb,
void *  data 
)

Executes an non prepared statement and returns the resulting statement handle.

Parameters:
obj The ODBC object
exec_cb A function callback, which, when called, should return a statement handle with result columns bound.
data A parameter to be passed to the exec_cb parameter function, indicating which statement handle is to be prepared.
Return values:
a statement handle
NULL on error

Definition at line 271 of file res_odbc.c.

References ast_log(), LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), and odbc_obj::up.

Referenced by acf_odbc_read(), acf_odbc_write(), and odbc_log().

00272 {
00273    int attempt;
00274    SQLHSTMT stmt;
00275 
00276    for (attempt = 0; attempt < 2; attempt++) {
00277       stmt = exec_cb(obj, data);
00278 
00279       if (stmt) {
00280          break;
00281       } else {
00282          obj->up = 0;
00283          ast_log(LOG_WARNING, "SQL Exec Direct failed.  Attempting a reconnect...\n");
00284 
00285          odbc_obj_disconnect(obj);
00286          odbc_obj_connect(obj);
00287       }
00288    }
00289 
00290    return stmt;
00291 }

struct odbc_cache_columns* ast_odbc_find_column ( struct odbc_cache_tables table,
const char *  colname 
) [read]

Find a column entry within a cached table structure.

Parameters:
table Cached table structure, as returned from ast_odbc_find_table()
colname The column name requested
Return values:
A structure describing the column type, or NULL, if the column is not found.
Since:
1.6.1

Definition at line 243 of file res_odbc.c.

References AST_RWLIST_TRAVERSE, odbc_cache_tables::columns, odbc_class::list, and odbc_cache_columns::name.

Referenced by update_odbc().

00244 {
00245    struct odbc_cache_columns *col;
00246    AST_RWLIST_TRAVERSE(&table->columns, col, list) {
00247       if (strcasecmp(col->name, colname) == 0) {
00248          return col;
00249       }
00250    }
00251    return NULL;
00252 }

struct odbc_cache_tables* ast_odbc_find_table ( const char *  database,
const char *  tablename 
) [read]

Find or create an entry describing the table specified.

Parameters:
obj An active ODBC handle on which to query the table
table Tablename to describe
Return values:
A structure describing the table layout, or NULL, if the table is not found or another error occurs. When a structure is returned, the contained columns list will be rdlock'ed, to ensure that it will be retained in memory.

Definition at line 129 of file res_odbc.c.

References ast_calloc, AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj(), ast_odbc_sanity_check(), AST_RWLIST_HEAD_INIT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_verb, odbc_cache_tables::columns, odbc_obj::con, odbc_cache_tables::connection, odbc_cache_columns::decimals, destroy_table_cache(), odbc_class::list, LOG_ERROR, LOG_WARNING, odbc_cache_columns::name, odbc_cache_columns::nullable, odbc_cache_columns::octetlen, odbc_cache_columns::radix, odbc_cache_columns::size, odbc_cache_tables::table, and odbc_cache_columns::type.

Referenced by require_odbc(), and update_odbc().

00130 {
00131    struct odbc_cache_tables *tableptr;
00132    struct odbc_cache_columns *entry;
00133    char columnname[80];
00134    SQLLEN sqlptr;
00135    SQLHSTMT stmt = NULL;
00136    int res = 0, error = 0, try = 0;
00137    struct odbc_obj *obj = ast_odbc_request_obj(database, 0);
00138 
00139    AST_RWLIST_RDLOCK(&odbc_tables);
00140    AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) {
00141       if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
00142          break;
00143       }
00144    }
00145    if (tableptr) {
00146       AST_RWLIST_RDLOCK(&tableptr->columns);
00147       AST_RWLIST_UNLOCK(&odbc_tables);
00148       if (obj) {
00149          ast_odbc_release_obj(obj);
00150       }
00151       return tableptr;
00152    }
00153 
00154    if (!obj) {
00155       ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
00156       return NULL;
00157    }
00158 
00159    /* Table structure not already cached; build it now. */
00160    do {
00161 retry:
00162       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00163       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00164          if (try == 0) {
00165             try = 1;
00166             ast_odbc_sanity_check(obj);
00167             goto retry;
00168          }
00169          ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
00170          break;
00171       }
00172 
00173       res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS);
00174       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00175          if (try == 0) {
00176             try = 1;
00177             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00178             ast_odbc_sanity_check(obj);
00179             goto retry;
00180          }
00181          ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
00182          break;
00183       }
00184 
00185       if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
00186          ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
00187          break;
00188       }
00189 
00190       tableptr->connection = (char *)tableptr + sizeof(*tableptr);
00191       tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1;
00192       strcpy(tableptr->connection, database); /* SAFE */
00193       strcpy(tableptr->table, tablename); /* SAFE */
00194       AST_RWLIST_HEAD_INIT(&(tableptr->columns));
00195 
00196       while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
00197          SQLGetData(stmt,  4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
00198 
00199          if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) {
00200             ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
00201             error = 1;
00202             break;
00203          }
00204          entry->name = (char *)entry + sizeof(*entry);
00205          strcpy(entry->name, columnname);
00206 
00207          SQLGetData(stmt,  5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
00208          SQLGetData(stmt,  7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
00209          SQLGetData(stmt,  9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
00210          SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
00211          SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
00212          SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
00213 
00214          /* Specification states that the octenlen should be the maximum number of bytes
00215           * returned in a char or binary column, but it seems that some drivers just set
00216           * it to NULL. (Bad Postgres! No biscuit!) */
00217          if (entry->octetlen == 0) {
00218             entry->octetlen = entry->size;
00219          }
00220 
00221          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);
00222          /* Insert column info into column list */
00223          AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
00224       }
00225       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00226 
00227       AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
00228       AST_RWLIST_RDLOCK(&(tableptr->columns));
00229    } while (0);
00230 
00231    AST_RWLIST_UNLOCK(&odbc_tables);
00232 
00233    if (error) {
00234       destroy_table_cache(tableptr);
00235       tableptr = NULL;
00236    }
00237    if (obj) {
00238       ast_odbc_release_obj(obj);
00239    }
00240    return tableptr;
00241 }

SQLHSTMT ast_odbc_prepare_and_execute ( struct odbc_obj obj,
SQLHSTMT(*)(struct odbc_obj *obj, void *data)  prepare_cb,
void *  data 
)

Prepares, executes, and returns the resulting statement handle.

Parameters:
obj The ODBC object
prepare_cb A function callback, which, when called, should return a statement handle prepared, with any necessary parameters or result columns bound.
data A parameter to be passed to the prepare_cb parameter function, indicating which statement handle is to be prepared.
Return values:
a statement handle
NULL on error

Definition at line 293 of file res_odbc.c.

References ast_log(), ast_odbc_sanity_check(), ast_tvnow(), odbc_obj::last_used, LOG_WARNING, and odbc_obj::up.

Referenced by config_odbc(), destroy_odbc(), odbc_log(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().

00294 {
00295    int res = 0, i, attempt;
00296    SQLINTEGER nativeerror=0, numfields=0;
00297    SQLSMALLINT diagbytes=0;
00298    unsigned char state[10], diagnostic[256];
00299    SQLHSTMT stmt;
00300 
00301    for (attempt = 0; attempt < 2; attempt++) {
00302       /* This prepare callback may do more than just prepare -- it may also
00303        * bind parameters, bind results, etc.  The real key, here, is that
00304        * when we disconnect, all handles become invalid for most databases.
00305        * We must therefore redo everything when we establish a new
00306        * connection. */
00307       stmt = prepare_cb(obj, data);
00308 
00309       if (stmt) {
00310          res = SQLExecute(stmt);
00311          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00312             if (res == SQL_ERROR) {
00313                SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00314                for (i = 0; i < numfields; i++) {
00315                   SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00316                   ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00317                   if (i > 10) {
00318                      ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00319                      break;
00320                   }
00321                }
00322             }
00323 
00324             ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
00325             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00326             stmt = NULL;
00327 
00328             obj->up = 0;
00329             /*
00330              * While this isn't the best way to try to correct an error, this won't automatically
00331              * fail when the statement handle invalidates.
00332              */
00333             ast_odbc_sanity_check(obj);
00334             continue;
00335          } else
00336             obj->last_used = ast_tvnow();
00337          break;
00338       } else if (attempt == 0)
00339          ast_odbc_sanity_check(obj);
00340    }
00341 
00342    return stmt;
00343 }

void ast_odbc_release_obj ( struct odbc_obj obj  ) 

Releases an ODBC object previously allocated by odbc_request_obj().

Parameters:
obj The ODBC object

Definition at line 646 of file res_odbc.c.

References ao2_ref, and odbc_obj::used.

Referenced by acf_odbc_read(), acf_odbc_write(), ast_odbc_find_table(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().

00647 {
00648    /* For pooled connections, this frees the connection to be
00649     * reused.  For non-pooled connections, it does nothing. */
00650    obj->used = 0;
00651 #ifdef DEBUG_THREADS
00652    obj->file[0] = '\0';
00653    obj->function[0] = '\0';
00654    obj->lineno = 0;
00655 #endif
00656    ao2_ref(obj, -1);
00657 }

struct odbc_obj* ast_odbc_request_obj ( const char *  name,
int  check 
) [read]

Retrieves a connected ODBC object.

Parameters:
name The name of the ODBC class for which a connection is needed.
check Whether to ensure that a connection is valid before returning the handle. Usually unnecessary.
Return values:
ODBC object
NULL if there is no connection available with the requested name.
Connection classes may, in fact, contain multiple connection handles. If the connection is pooled, then each connection will be dedicated to the thread which requests it. Note that all connections should be released when the thread is done by calling odbc_release_obj(), below.

Definition at line 667 of file res_odbc.c.

References ao2_alloc, ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_assert, ast_copy_string(), ast_log(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_odbc_sanity_check(), ast_tvdiff_sec(), ast_tvnow(), class_container, odbc_class::idlecheck, odbc_obj::last_used, odbc_obj::lock, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), odbc_obj::parent, and odbc_obj::used.

Referenced by acf_odbc_read(), acf_odbc_write(), ast_odbc_find_table(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().

00669 {
00670    struct odbc_obj *obj = NULL;
00671    struct odbc_class *class;
00672    struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
00673 
00674    while ((class = ao2_iterator_next(&aoi))) {
00675       if (!strcmp(class->name, name) && !class->delme) {
00676          break;
00677       }
00678       ao2_ref(class, -1);
00679    }
00680 
00681    if (!class)
00682       return NULL;
00683 
00684    ast_assert(ao2_ref(class, 0) > 1);
00685 
00686    if (class->haspool) {
00687       /* Recycle connections before building another */
00688       aoi = ao2_iterator_init(class->obj_container, 0);
00689       while ((obj = ao2_iterator_next(&aoi))) {
00690          if (! obj->used) {
00691             ast_mutex_lock(&obj->lock);
00692             obj->used = 1;
00693             ast_mutex_unlock(&obj->lock);
00694             break;
00695          }
00696          ao2_ref(obj, -1);
00697       }
00698 
00699       if (obj) {
00700          ast_assert(ao2_ref(obj, 0) > 1);
00701       }
00702 
00703       if (!obj && (class->count < class->limit)) {
00704          class->count++;
00705          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
00706          if (!obj) {
00707             ao2_ref(class, -1);
00708             return NULL;
00709          }
00710          ast_assert(ao2_ref(obj, 0) == 1);
00711          ast_mutex_init(&obj->lock);
00712          /* obj inherits the outstanding reference to class */
00713          obj->parent = class;
00714          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00715             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00716             ao2_ref(obj, -1);
00717             ast_assert(ao2_ref(class, 0) > 0);
00718             obj = NULL;
00719          } else {
00720             obj->used = 1;
00721             ao2_link(class->obj_container, obj);
00722          }
00723          class = NULL;
00724       } else {
00725          /* Object is not constructed, so delete outstanding reference to class. */
00726          ao2_ref(class, -1);
00727          class = NULL;
00728       }
00729    } else {
00730       /* Non-pooled connection: multiple modules can use the same connection. */
00731       aoi = ao2_iterator_init(class->obj_container, 0);
00732       while ((obj = ao2_iterator_next(&aoi))) {
00733          /* Non-pooled connection: if there is an entry, return it */
00734          break;
00735       }
00736 
00737       if (obj) {
00738          /* Object is not constructed, so delete outstanding reference to class. */
00739          ast_assert(ao2_ref(class, 0) > 1);
00740          ao2_ref(class, -1);
00741          class = NULL;
00742       } else {
00743          /* No entry: build one */
00744          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
00745          if (!obj) {
00746             ast_assert(ao2_ref(class, 0) > 1);
00747             ao2_ref(class, -1);
00748             return NULL;
00749          }
00750          ast_mutex_init(&obj->lock);
00751          /* obj inherits the outstanding reference to class */
00752          obj->parent = class;
00753          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00754             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00755             ao2_ref(obj, -1);
00756             obj = NULL;
00757          } else {
00758             ao2_link(class->obj_container, obj);
00759             ast_assert(ao2_ref(obj, 0) > 1);
00760          }
00761          class = NULL;
00762       }
00763    }
00764 
00765    if (obj && check) {
00766       ast_odbc_sanity_check(obj);
00767    } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck)
00768       odbc_obj_connect(obj);
00769 
00770 #ifdef DEBUG_THREADS
00771    if (obj) {
00772       ast_copy_string(obj->file, file, sizeof(obj->file));
00773       ast_copy_string(obj->function, function, sizeof(obj->function));
00774       obj->lineno = lineno;
00775    }
00776 #endif
00777    ast_assert(class == NULL);
00778 
00779    if (obj) {
00780       ast_assert(ao2_ref(obj, 0) > 1);
00781    }
00782    return obj;
00783 }

int ast_odbc_sanity_check ( struct odbc_obj obj  ) 

Checks an ODBC object to ensure it is still connected.

Parameters:
obj The ODBC object
Return values:
0 if connected
-1 otherwise.

Definition at line 372 of file res_odbc.c.

References ast_log(), ast_strlen_zero(), odbc_obj::con, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), odbc_obj::parent, odbc_class::sanitysql, and odbc_obj::up.

Referenced by ast_odbc_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), and handle_cli_odbc_show().

00373 {
00374    char *test_sql = "select 1";
00375    SQLHSTMT stmt;
00376    int res = 0;
00377 
00378    if (!ast_strlen_zero(obj->parent->sanitysql))
00379       test_sql = obj->parent->sanitysql;
00380 
00381    if (obj->up) {
00382       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00383       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00384          obj->up = 0;
00385       } else {
00386          res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
00387          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00388             obj->up = 0;
00389          } else {
00390             res = SQLExecute(stmt);
00391             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00392                obj->up = 0;
00393             }
00394          }
00395       }
00396       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00397    }
00398 
00399    if (!obj->up) { /* Try to reconnect! */
00400       ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
00401       odbc_obj_disconnect(obj);
00402       odbc_obj_connect(obj);
00403    }
00404    return obj->up;
00405 }

int ast_odbc_smart_execute ( struct odbc_obj obj,
SQLHSTMT  stmt 
)

Executes a prepared statement handle.

Parameters:
obj The non-NULL result of odbc_request_obj()
stmt The prepared statement handle
Return values:
0 on success
-1 on failure
This function was originally designed simply to execute a prepared statement handle and to retry if the initial execution failed. Unfortunately, it did this by disconnecting and reconnecting the database handle which on most databases causes the statement handle to become invalid. Therefore, this method has been deprecated in favor of odbc_prepare_and_execute() which allows the statement to be prepared multiple times, if necessary, in case of a loss of connection.

This function really only ever worked with MySQL, where the statement handle is not prepared on the server. If you are not using MySQL, you should avoid it.

Definition at line 345 of file res_odbc.c.

References ast_log(), ast_tvnow(), odbc_obj::last_used, and LOG_WARNING.

00346 {
00347    int res = 0, i;
00348    SQLINTEGER nativeerror=0, numfields=0;
00349    SQLSMALLINT diagbytes=0;
00350    unsigned char state[10], diagnostic[256];
00351 
00352    res = SQLExecute(stmt);
00353    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00354       if (res == SQL_ERROR) {
00355          SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00356          for (i = 0; i < numfields; i++) {
00357             SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00358             ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00359             if (i > 10) {
00360                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00361                break;
00362             }
00363          }
00364       }
00365    } else
00366       obj->last_used = ast_tvnow();
00367    
00368    return res;
00369 }

static void destroy_table_cache ( struct odbc_cache_tables table  )  [static]

Definition at line 109 of file res_odbc.c.

References ast_debug, ast_free, AST_RWLIST_HEAD_DESTROY, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, odbc_cache_tables::columns, odbc_class::list, and odbc_cache_tables::table.

Referenced by ast_odbc_clear_cache(), ast_odbc_find_table(), and reload().

00109                                                                  {
00110    struct odbc_cache_columns *col;
00111    ast_debug(1, "Destroying table cache for %s\n", table->table);
00112    AST_RWLIST_WRLOCK(&table->columns);
00113    while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
00114       ast_free(col);
00115    }
00116    AST_RWLIST_UNLOCK(&table->columns);
00117    AST_RWLIST_HEAD_DESTROY(&table->columns);
00118    ast_free(table);
00119 }

static char* handle_cli_odbc_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 537 of file res_odbc.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_odbc_sanity_check(), ast_strdup, class_container, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, odbc_class::count, ast_cli_args::fd, odbc_obj::lock, ast_cli_args::n, ast_cli_args::pos, odbc_obj::up, ast_cli_entry::usage, odbc_obj::used, and ast_cli_args::word.

00538 {
00539    struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
00540    struct odbc_class *class;
00541    struct odbc_obj *current;
00542    int length = 0;
00543    int which = 0;
00544    char *ret = NULL;
00545 
00546    switch (cmd) {
00547    case CLI_INIT:
00548       e->command = "odbc show";
00549       e->usage =
00550             "Usage: odbc show [class]\n"
00551             "       List settings of a particular ODBC class or,\n"
00552             "       if not specified, all classes.\n";
00553       return NULL;
00554    case CLI_GENERATE:
00555       if (a->pos != 2)
00556          return NULL;
00557       length = strlen(a->word);
00558       while ((class = ao2_iterator_next(&aoi))) {
00559          if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
00560             ret = ast_strdup(class->name);
00561          }
00562          ao2_ref(class, -1);
00563          if (ret) {
00564             break;
00565          }
00566       }
00567       ao2_iterator_destroy(&aoi);
00568       if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
00569          ret = ast_strdup("all");
00570       }
00571       return ret;
00572    }
00573 
00574    ast_cli(a->fd, "\nODBC DSN Settings\n");
00575    ast_cli(a->fd,   "-----------------\n\n");
00576    aoi = ao2_iterator_init(class_container, 0);
00577    while ((class = ao2_iterator_next(&aoi))) {
00578       if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
00579          int count = 0;
00580          ast_cli(a->fd, "  Name:   %s\n  DSN:    %s\n", class->name, class->dsn);
00581 
00582          if (class->haspool) {
00583             struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
00584 
00585             ast_cli(a->fd, "  Pooled: Yes\n  Limit:  %d\n  Connections in use: %d\n", class->limit, class->count);
00586 
00587             while ((current = ao2_iterator_next(&aoi2))) {
00588                ast_mutex_lock(&current->lock);
00589 #ifdef DEBUG_THREADS
00590                ast_cli(a->fd, "    - Connection %d: %s (%s:%d %s)\n", ++count,
00591                   current->used ? "in use" :
00592                   current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected",
00593                   current->file, current->lineno, current->function);
00594 #else
00595                ast_cli(a->fd, "    - Connection %d: %s\n", ++count,
00596                   current->used ? "in use" :
00597                   current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
00598 #endif
00599                ast_mutex_unlock(&current->lock);
00600                ao2_ref(current, -1);
00601             }
00602             ao2_iterator_destroy(&aoi2);
00603          } else {
00604             /* Should only ever be one of these */
00605             struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
00606             while ((current = ao2_iterator_next(&aoi2))) {
00607                ast_cli(a->fd, "  Pooled: No\n  Connected: %s\n", current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
00608                ao2_ref(current, -1);
00609             }
00610             ao2_iterator_destroy(&aoi2);
00611          }
00612          ast_cli(a->fd, "\n");
00613       }
00614       ao2_ref(class, -1);
00615    }
00616    ao2_iterator_destroy(&aoi);
00617 
00618    return CLI_SUCCESS;
00619 }

static int load_module ( void   )  [static]

static int load_odbc_config ( void   )  [static]

Definition at line 407 of file res_odbc.c.

References ao2_alloc, ao2_container_alloc, ao2_match_by_addr, ao2_ref, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_false(), ast_log(), ast_strdup, ast_strlen_zero(), ast_true(), ast_variable_browse(), config, odbc_class::dsn, enabled, odbc_class::idlecheck, odbc_class::limit, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, null_hash_fn(), odbc_class_destructor(), odbc_register_class(), odbc_class::password, odbc_class::sanitysql, setenv(), odbc_class::username, and ast_variable::value.

Referenced by load_module(), and reload().

00408 {
00409    static char *cfg = "res_odbc.conf";
00410    struct ast_config *config;
00411    struct ast_variable *v;
00412    char *cat;
00413    const char *dsn, *username, *password, *sanitysql;
00414    int enabled, pooling, limit, bse;
00415    unsigned int idlecheck;
00416    int preconnect = 0, res = 0;
00417    struct ast_flags config_flags = { 0 };
00418 
00419    struct odbc_class *new;
00420 
00421    config = ast_config_load(cfg, config_flags);
00422    if (!config) {
00423       ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
00424       return -1;
00425    }
00426    for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
00427       if (!strcasecmp(cat, "ENV")) {
00428          for (v = ast_variable_browse(config, cat); v; v = v->next) {
00429             setenv(v->name, v->value, 1);
00430             ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
00431          }
00432       } else {
00433          /* Reset all to defaults for each class of odbc connections */
00434          dsn = username = password = sanitysql = NULL;
00435          enabled = 1;
00436          preconnect = idlecheck = 0;
00437          pooling = 0;
00438          limit = 0;
00439          bse = 1;
00440          for (v = ast_variable_browse(config, cat); v; v = v->next) {
00441             if (!strcasecmp(v->name, "pooling")) {
00442                if (ast_true(v->value))
00443                   pooling = 1;
00444             } else if (!strncasecmp(v->name, "share", 5)) {
00445                /* "shareconnections" is a little clearer in meaning than "pooling" */
00446                if (ast_false(v->value))
00447                   pooling = 1;
00448             } else if (!strcasecmp(v->name, "limit")) {
00449                sscanf(v->value, "%30d", &limit);
00450                if (ast_true(v->value) && !limit) {
00451                   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);
00452                   limit = 1023;
00453                } else if (ast_false(v->value)) {
00454                   ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'.  Disabling ODBC class '%s'.\n", v->value, cat);
00455                   enabled = 0;
00456                   break;
00457                }
00458             } else if (!strcasecmp(v->name, "idlecheck")) {
00459                sscanf(v->value, "%30u", &idlecheck);
00460             } else if (!strcasecmp(v->name, "enabled")) {
00461                enabled = ast_true(v->value);
00462             } else if (!strcasecmp(v->name, "pre-connect")) {
00463                preconnect = ast_true(v->value);
00464             } else if (!strcasecmp(v->name, "dsn")) {
00465                dsn = v->value;
00466             } else if (!strcasecmp(v->name, "username")) {
00467                username = v->value;
00468             } else if (!strcasecmp(v->name, "password")) {
00469                password = v->value;
00470             } else if (!strcasecmp(v->name, "sanitysql")) {
00471                sanitysql = v->value;
00472             } else if (!strcasecmp(v->name, "backslash_is_escape")) {
00473                bse = ast_true(v->value);
00474             }
00475          }
00476 
00477          if (enabled && !ast_strlen_zero(dsn)) {
00478             new = ao2_alloc(sizeof(*new), odbc_class_destructor);
00479 
00480             if (!new) {
00481                res = -1;
00482                break;
00483             }
00484 
00485             SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
00486             res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
00487 
00488             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00489                ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
00490                ao2_ref(new, -1);
00491                return res;
00492             }
00493 
00494             new->obj_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr);
00495 
00496             if (pooling) {
00497                new->haspool = pooling;
00498                if (limit) {
00499                   new->limit = limit;
00500                } else {
00501                   ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless.  Changing limit from 0 to 5.\n");
00502                   new->limit = 5;
00503                }
00504             }
00505 
00506             new->backslash_is_escape = bse ? 1 : 0;
00507             new->idlecheck = idlecheck;
00508 
00509             if (cat)
00510                ast_copy_string(new->name, cat, sizeof(new->name));
00511             if (dsn)
00512                ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
00513             if (username && !(new->username = ast_strdup(username))) {
00514                ao2_ref(new, -1);
00515                break;
00516             }
00517             if (password && !(new->password = ast_strdup(password))) {
00518                ao2_ref(new, -1);
00519                break;
00520             }
00521             if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) {
00522                ao2_ref(new, -1);
00523                break;
00524             }
00525 
00526             odbc_register_class(new, preconnect);
00527             ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
00528             ao2_ref(new, -1);
00529             new = NULL;
00530          }
00531       }
00532    }
00533    ast_config_destroy(config);
00534    return res;
00535 }

static int null_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 94 of file res_odbc.c.

Referenced by load_module(), and load_odbc_config().

00095 {
00096    return 0;
00097 }

static void odbc_class_destructor ( void *  data  )  [static]

Definition at line 78 of file res_odbc.c.

References ao2_ref, and ast_free.

Referenced by load_odbc_config().

00079 {
00080    struct odbc_class *class = data;
00081    /* Due to refcounts, we can safely assume that any objects with a reference
00082     * to us will prevent our destruction, so we don't need to worry about them.
00083     */
00084    if (class->username)
00085       ast_free(class->username);
00086    if (class->password)
00087       ast_free(class->password);
00088    if (class->sanitysql)
00089       ast_free(class->sanitysql);
00090    ao2_ref(class->obj_container, -1);
00091    SQLFreeHandle(SQL_HANDLE_ENV, class->env);
00092 }

static odbc_status odbc_obj_connect ( struct odbc_obj obj  )  [static]

Definition at line 822 of file res_odbc.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvnow(), odbc_obj::con, odbc_class::dsn, odbc_class::env, odbc_obj::last_used, odbc_obj::lock, LOG_NOTICE, LOG_WARNING, msg, odbc_class::name, ODBC_FAIL, odbc_obj_disconnect(), ODBC_SUCCESS, odbc_obj::parent, odbc_class::password, odbc_obj::up, and odbc_class::username.

Referenced by ast_odbc_direct_execute(), ast_odbc_request_obj(), and ast_odbc_sanity_check().

00823 {
00824    int res;
00825    SQLINTEGER err;
00826    short int mlen;
00827    unsigned char msg[200], state[10];
00828 #ifdef NEEDTRACE
00829    SQLINTEGER enable = 1;
00830    char *tracefile = "/tmp/odbc.trace";
00831 #endif
00832    ast_mutex_lock(&obj->lock);
00833 
00834    if (obj->up) {
00835       odbc_obj_disconnect(obj);
00836       ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
00837    } else {
00838       ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
00839    }
00840 
00841    res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con);
00842 
00843    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00844       ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
00845       ast_mutex_unlock(&obj->lock);
00846       return ODBC_FAIL;
00847    }
00848    SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
00849    SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *) 10, 0);
00850 #ifdef NEEDTRACE
00851    SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
00852    SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
00853 #endif
00854 
00855    res = SQLConnect(obj->con,
00856          (SQLCHAR *) obj->parent->dsn, SQL_NTS,
00857          (SQLCHAR *) obj->parent->username, SQL_NTS,
00858          (SQLCHAR *) obj->parent->password, SQL_NTS);
00859 
00860    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00861       SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen);
00862       ast_mutex_unlock(&obj->lock);
00863       ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
00864       return ODBC_FAIL;
00865    } else {
00866       ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
00867       obj->up = 1;
00868       obj->last_used = ast_tvnow();
00869    }
00870 
00871    ast_mutex_unlock(&obj->lock);
00872    return ODBC_SUCCESS;
00873 }

static void odbc_obj_destructor ( void *  data  )  [static]

Definition at line 99 of file res_odbc.c.

References ao2_ref, ast_mutex_destroy(), odbc_obj::lock, odbc_obj_disconnect(), and odbc_obj::parent.

Referenced by ast_odbc_request_obj().

00100 {
00101    struct odbc_obj *obj = data;
00102    struct odbc_class *class = obj->parent;
00103    obj->parent = NULL;
00104    odbc_obj_disconnect(obj);
00105    ast_mutex_destroy(&obj->lock);
00106    ao2_ref(class, -1);
00107 }

static odbc_status odbc_obj_disconnect ( struct odbc_obj obj  )  [static]

Definition at line 785 of file res_odbc.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), odbc_obj::con, odbc_class::dsn, odbc_obj::lock, LOG_DEBUG, LOG_WARNING, msg, odbc_class::name, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.

Referenced by ast_odbc_direct_execute(), ast_odbc_sanity_check(), odbc_obj_connect(), and odbc_obj_destructor().

00786 {
00787    int res;
00788    SQLINTEGER err;
00789    short int mlen;
00790    unsigned char msg[200], stat[10];
00791 
00792    /* Nothing to disconnect */
00793    if (!obj->con) {
00794       return ODBC_SUCCESS;
00795    }
00796 
00797    ast_mutex_lock(&obj->lock);
00798 
00799    res = SQLDisconnect(obj->con);
00800 
00801    if (obj->parent) {
00802       if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
00803          ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
00804       } else {
00805          ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
00806       }
00807    }
00808 
00809    if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == SQL_SUCCESS)) {
00810       obj->con = NULL;
00811       ast_log(LOG_DEBUG, "Database handle deallocated\n");
00812    } else {
00813       SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
00814       ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg);
00815    }
00816 
00817    obj->up = 0;
00818    ast_mutex_unlock(&obj->lock);
00819    return ODBC_SUCCESS;
00820 }

static int odbc_register_class ( struct odbc_class class,
int  connect 
) [static]

Definition at line 625 of file res_odbc.c.

References ao2_link, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj(), class_container, and LOG_WARNING.

Referenced by load_odbc_config().

00626 {
00627    struct odbc_obj *obj;
00628    if (class) {
00629       ao2_link(class_container, class);
00630       /* I still have a reference in the caller, so a deref is NOT missing here. */
00631 
00632       if (preconnect) {
00633          /* Request and release builds a connection */
00634          obj = ast_odbc_request_obj(class->name, 0);
00635          if (obj)
00636             ast_odbc_release_obj(obj);
00637       }
00638 
00639       return 0;
00640    } else {
00641       ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
00642       return -1;
00643    }
00644 }

static int reload ( void   )  [static]

Definition at line 875 of file res_odbc.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, class_container, destroy_table_cache(), odbc_class::list, load_odbc_config(), and table.

00876 {
00877    struct odbc_cache_tables *table;
00878    struct odbc_class *class;
00879    struct odbc_obj *current;
00880    struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
00881 
00882    /* First, mark all to be purged */
00883    while ((class = ao2_iterator_next(&aoi))) {
00884       class->delme = 1;
00885       ao2_ref(class, -1);
00886    }
00887    ao2_iterator_destroy(&aoi);
00888 
00889    load_odbc_config();
00890 
00891    /* Purge remaining classes */
00892 
00893    /* Note on how this works; this is a case of circular references, so we
00894     * explicitly do NOT want to use a callback here (or we wind up in
00895     * recursive hell).
00896     *
00897     * 1. Iterate through all the classes.  Note that the classes will currently
00898     * contain two classes of the same name, one of which is marked delme and
00899     * will be purged when all remaining objects of the class are released, and
00900     * the other, which was created above when we re-parsed the config file.
00901     * 2. On each class, there is a reference held by the master container and
00902     * a reference held by each connection object.  There are two cases for
00903     * destruction of the class, noted below.  However, in all cases, all O-refs
00904     * (references to objects) will first be freed, which will cause the C-refs
00905     * (references to classes) to be decremented (but never to 0, because the
00906     * class container still has a reference).
00907     *    a) If the class has outstanding objects, the C-ref by the class
00908     *    container will then be freed, which leaves only C-refs by any
00909     *    outstanding objects.  When the final outstanding object is released
00910     *    (O-refs held by applications and dialplan functions), it will in turn
00911     *    free the final C-ref, causing class destruction.
00912     *    b) If the class has no outstanding objects, when the class container
00913     *    removes the final C-ref, the class will be destroyed.
00914     */
00915    aoi = ao2_iterator_init(class_container, 0);
00916    while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */
00917       if (class->delme) {
00918          struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
00919          while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */
00920             ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */
00921             ao2_ref(current, -1); /* O-ref-- (by iterator) */
00922             /* At this point, either
00923              * a) there's an outstanding O-ref, or
00924              * b) the object has already been destroyed.
00925              */
00926          }
00927          ao2_iterator_destroy(&aoi2);
00928          ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
00929          /* At this point, either
00930           * a) there's an outstanding O-ref, which holds an outstanding C-ref, or
00931           * b) the last remaining C-ref is held by the iterator, which will be
00932           * destroyed in the next step.
00933           */
00934       }
00935       ao2_ref(class, -1); /* C-ref-- (by iterator) */
00936    }
00937    ao2_iterator_destroy(&aoi);
00938 
00939    /* Empty the cache; it will get rebuilt the next time the tables are needed. */
00940    AST_RWLIST_WRLOCK(&odbc_tables);
00941    while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
00942       destroy_table_cache(table);
00943    }
00944    AST_RWLIST_UNLOCK(&odbc_tables);
00945 
00946    return 0;
00947 }

static int unload_module ( void   )  [static]

Definition at line 949 of file res_odbc.c.

00950 {
00951    /* Prohibit unloading */
00952    return -1;
00953 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "ODBC resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 970 of file res_odbc.c.

Definition at line 970 of file res_odbc.c.

struct ast_cli_entry cli_odbc[] [static]

Initial value:

 {
   AST_CLI_DEFINE(handle_cli_odbc_show, "List ODBC DSN(s)")
}

Definition at line 621 of file res_odbc.c.

Referenced by load_module().


Generated on Wed Oct 28 11:53:09 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6