Fri Jun 19 12:10:49 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"

Go to the source code of this file.

Data Structures

struct  odbc_class
struct  odbc_tables

Functions

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.
odbc_cache_columnsast_odbc_find_column (struct odbc_cache_tables *table, const char *colname)
 Find a column entry within a cached table structure.
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().
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
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 __reg_module ( void   )  [static]

Definition at line 963 of file res_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 963 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 655 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().

00656 {
00657    return obj->parent->backslash_is_escape;
00658 }

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(), and odbc_obj_disconnect().

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 
)

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_class::list, odbc_cache_columns::name, and table.

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 
)

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, destroy_table_cache(), odbc_class::list, LOG_ERROR, LOG_WARNING, and odbc_cache_tables::table.

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(), and LOG_WARNING.

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 642 of file res_odbc.c.

References ao2_ref, and odbc_obj::used.

Referenced by 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().

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

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

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 663 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, LOG_WARNING, ao2_iterator::obj, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), and odbc_obj::parent.

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().

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

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_class::list, and 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_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, 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       if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
00568          ret = ast_strdup("all");
00569       }
00570       return ret;
00571    }
00572 
00573    ast_cli(a->fd, "\nODBC DSN Settings\n");
00574    ast_cli(a->fd,   "-----------------\n\n");
00575    aoi = ao2_iterator_init(class_container, 0);
00576    while ((class = ao2_iterator_next(&aoi))) {
00577       if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
00578          int count = 0;
00579          ast_cli(a->fd, "  Name:   %s\n  DSN:    %s\n", class->name, class->dsn);
00580 
00581          if (class->haspool) {
00582             struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
00583 
00584             ast_cli(a->fd, "  Pooled: Yes\n  Limit:  %d\n  Connections in use: %d\n", class->limit, class->count);
00585 
00586             while ((current = ao2_iterator_next(&aoi2))) {
00587                ast_mutex_lock(&current->lock);
00588 #ifdef DEBUG_THREADS
00589                ast_cli(a->fd, "    - Connection %d: %s (%s:%d %s)\n", ++count,
00590                   current->used ? "in use" :
00591                   current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected",
00592                   current->file, current->lineno, current->function);
00593 #else
00594                ast_cli(a->fd, "    - Connection %d: %s\n", ++count,
00595                   current->used ? "in use" :
00596                   current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
00597 #endif
00598                ast_mutex_unlock(&current->lock);
00599                ao2_ref(current, -1);
00600             }
00601          } else {
00602             /* Should only ever be one of these */
00603             struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
00604             while ((current = ao2_iterator_next(&aoi2))) {
00605                ast_cli(a->fd, "  Pooled: No\n  Connected: %s\n", current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
00606                ao2_ref(current, -1);
00607             }
00608          }
00609          ast_cli(a->fd, "\n");
00610       }
00611       ao2_ref(class, -1);
00612    }
00613 
00614    return CLI_SUCCESS;
00615 }

static int load_module ( void   )  [static]

Definition at line 948 of file res_odbc.c.

References ao2_container_alloc, ao2_match_by_addr, ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_DECLINE, class_container, cli_odbc, load_odbc_config(), LOG_NOTICE, and null_hash_fn().

00949 {
00950    if (!(class_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr)))
00951       return AST_MODULE_LOAD_DECLINE;
00952    if (load_odbc_config() == -1)
00953       return AST_MODULE_LOAD_DECLINE;
00954    ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry));
00955    ast_log(LOG_NOTICE, "res_odbc loaded.\n");
00956    return 0;
00957 }

static int load_odbc_config ( void   )  [static]

Definition at line 407 of file res_odbc.c.

References ast_category_browse(), ast_config_load, ast_false(), ast_log(), ast_true(), ast_variable_browse(), config, config_flags, odbc_class::dsn, enabled, odbc_class::idlecheck, odbc_class::limit, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, 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, "%d", &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, "%d", &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().

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.

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 818 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().

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

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 781 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().

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

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

Definition at line 621 of file res_odbc.c.

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

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

static int reload ( void   )  [static]

Definition at line 871 of file res_odbc.c.

References 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(), load_odbc_config(), and table.

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

static int unload_module ( void   )  [static]

Definition at line 942 of file res_odbc.c.

00943 {
00944    /* Prohibit unloading */
00945    return -1;
00946 }


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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 963 of file res_odbc.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 963 of file res_odbc.c.

struct ao2_container* class_container

Definition at line 70 of file res_odbc.c.

Referenced by ast_odbc_request_obj(), handle_cli_odbc_show(), load_module(), odbc_register_class(), and reload().

struct ast_cli_entry cli_odbc[] [static]

Initial value:

 {
   { .handler =  handle_cli_odbc_show , .summary =  "List ODBC DSN(s)" ,__VA_ARGS__ }
}

Definition at line 617 of file res_odbc.c.

Referenced by load_module().


Generated on Fri Jun 19 12:10:49 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7