#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 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.
obj | The ODBC object |
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.
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 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.
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 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.
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_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(¤t->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(¤t->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] |
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] |
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().