#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_columns * | ast_odbc_find_column (struct odbc_cache_tables *table, const char *colname) |
Find a column entry within a cached table structure. | |
odbc_cache_tables * | ast_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_obj * | ast_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_info * | ast_module_info = &__mod_info |
ao2_container * | class_container |
static struct ast_cli_entry | cli_odbc [] |
Anthony Minessale II <anthmct@yahoo.com>
Definition in file res_odbc.c.
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.
obj | The ODBC object |
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.
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 |
0 | if the cache entry was removed, or -1 if no matching entry was found. |
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.
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. |
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.
table | Cached table structure, as returned from ast_odbc_find_table() | |
colname | The column name requested |
A | structure describing the column type, or NULL, if the column is not found. |
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.
obj | An active ODBC handle on which to query the table | |
table | Tablename to describe |
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.
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. |
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().
obj | The ODBC object |
Definition at line 646 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().
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 | |||
) |
Retrieves a connected ODBC object.
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. |
ODBC | object | |
NULL | if there is no connection available with the requested name. |
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, 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().
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.
obj | The ODBC object |
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.
obj | The non-NULL result of odbc_request_obj() | |
stmt | The prepared statement handle |
0 | on success | |
-1 | on failure |
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_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, 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(¤t->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(¤t->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] |
Definition at line 955 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().
00956 { 00957 if (!(class_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr))) 00958 return AST_MODULE_LOAD_DECLINE; 00959 if (load_odbc_config() == -1) 00960 return AST_MODULE_LOAD_DECLINE; 00961 ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry)); 00962 ast_log(LOG_NOTICE, "res_odbc loaded.\n"); 00963 return 0; 00964 }
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, "%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] |
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 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, LOG_WARNING, and odbc_class::name.
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(), 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] |
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 970 of file res_odbc.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 970 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 621 of file res_odbc.c.
Referenced by load_module().