#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/res_odbc.h"
#include "asterisk/time.h"
#include "asterisk/astobj2.h"
#include "asterisk/app.h"
#include "asterisk/strings.h"
#include "asterisk/threadstorage.h"
#include "asterisk/data.h"
Go to the source code of this file.
Data Structures | |
struct | odbc_class |
struct | odbc_tables |
struct | odbc_txn_frame |
Defines | |
#define | DATA_EXPORT_ODBC_CLASS(MEMBER) |
#define | EOR_TX (void *)(long)3 |
#define | NO_TX (void *)(long)2 |
#define | USE_TX (void *)(long)1 |
Functions | |
static void | __init_errors_buf (void) |
static void | __reg_module (void) |
static void | __unreg_module (void) |
odbc_obj * | _ast_odbc_request_obj (const char *name, int check, const char *file, const char *function, int lineno) |
odbc_obj * | _ast_odbc_request_obj2 (const char *name, struct ast_flags flags, const char *file, const char *function, int lineno) |
Retrieves a connected ODBC object. | |
static int | acf_transaction_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | acf_transaction_write (struct ast_channel *chan, const char *cmd, char *s, const char *value) |
static int | aoro2_class_cb (void *obj, void *arg, int flags) |
static int | aoro2_obj_cb (void *vobj, void *arg, int flags) |
AST_DATA_STRUCTURE (odbc_class, DATA_EXPORT_ODBC_CLASS) | |
SQLRETURN | ast_odbc_ast_str_SQLGetData (struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind) |
Wrapper for SQLGetData to use with dynamic strings. | |
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 This function may be called to clear entries created and cached by the ast_odbc_find_table() API call. | |
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 ast_odbc_request_obj(). | |
odbc_obj * | ast_odbc_retrieve_transaction_obj (struct ast_channel *chan, const char *objname) |
Retrieve a stored ODBC object, if a transaction has been started. | |
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 int | commit_exec (struct ast_channel *chan, const char *data) |
static int | data_odbc_provider_handler (const struct ast_data_search *search, struct ast_data *root) |
static void | destroy_table_cache (struct odbc_cache_tables *table) |
static struct odbc_txn_frame * | find_transaction (struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active) |
static char * | handle_cli_odbc_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static const char * | isolation2text (int iso) |
static int | load_module (void) |
static int | load_odbc_config (void) |
static int | mark_transaction_active (struct ast_channel *chan, struct odbc_txn_frame *tx) |
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 void | odbc_release_obj2 (struct odbc_obj *obj, struct odbc_txn_frame *tx) |
static void | odbc_txn_free (void *data) |
static struct odbc_txn_frame * | release_transaction (struct odbc_txn_frame *tx) |
static int | reload (void) |
static int | rollback_exec (struct ast_channel *chan, const char *data) |
static int | text2isolation (const char *txt) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, } |
static const char *const | app_commit = "ODBC_Commit" |
static const char *const | app_rollback = "ODBC_Rollback" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ao2_container * | class_container |
static struct ast_cli_entry | cli_odbc [] |
static struct ast_threadstorage | errors_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_errors_buf , .custom_init = NULL , } |
static struct ast_custom_function | odbc_function |
static struct ast_data_handler | odbc_provider |
static struct ast_data_entry | odbc_providers [] |
static struct ast_datastore_info | txn_info |
Anthony Minessale II <anthmct@yahoo.com>
Tilghman Lesher <tilghman@digium.com>
Definition in file res_odbc.c.
#define DATA_EXPORT_ODBC_CLASS | ( | MEMBER | ) |
Definition at line 177 of file res_odbc.c.
#define EOR_TX (void *)(long)3 |
Definition at line 1184 of file res_odbc.c.
Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().
#define NO_TX (void *)(long)2 |
#define USE_TX (void *)(long)1 |
Definition at line 1182 of file res_odbc.c.
Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().
static void __init_errors_buf | ( | void | ) | [static] |
static void __reg_module | ( | void | ) | [static] |
Definition at line 1845 of file res_odbc.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1845 of file res_odbc.c.
struct odbc_obj* _ast_odbc_request_obj | ( | const char * | name, | |
int | check, | |||
const char * | file, | |||
const char * | function, | |||
int | lineno | |||
) |
Definition at line 1387 of file res_odbc.c.
References _ast_odbc_request_obj2(), ast_flags::flags, and RES_ODBC_SANITY_CHECK.
01388 { 01389 struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 }; 01390 return _ast_odbc_request_obj2(name, flags, file, function, lineno); 01391 }
struct odbc_obj* _ast_odbc_request_obj2 | ( | const char * | name, | |
struct ast_flags | flags, | |||
const char * | file, | |||
const char * | function, | |||
int | lineno | |||
) |
Retrieves a connected ODBC object.
name | The name of the ODBC class for which a connection is needed. | |
flags | One or more of the following flags:
|
NULL | if there is no connection available with the requested name. |
Definition at line 1199 of file res_odbc.c.
References ao2_alloc, ao2_callback, ao2_link, ao2_ref, aoro2_class_cb(), aoro2_obj_cb(), ast_assert, ast_atomic_fetchadd_int(), ast_debug, ast_log(), ast_mutex_init, ast_test_flag, class_container, odbc_obj::con, EOR_TX, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), RES_ODBC_INDEPENDENT_CONNECTION, and USE_TX.
Referenced by _ast_odbc_request_obj().
01200 { 01201 struct odbc_obj *obj = NULL; 01202 struct odbc_class *class; 01203 SQLINTEGER nativeerror=0, numfields=0; 01204 SQLSMALLINT diagbytes=0, i; 01205 unsigned char state[10], diagnostic[256]; 01206 01207 if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) { 01208 ast_debug(1, "Class '%s' not found!\n", name); 01209 return NULL; 01210 } 01211 01212 ast_assert(ao2_ref(class, 0) > 1); 01213 01214 if (class->haspool) { 01215 /* Recycle connections before building another */ 01216 obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX); 01217 01218 if (obj) { 01219 ast_assert(ao2_ref(obj, 0) > 1); 01220 } 01221 if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit) && 01222 (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) { 01223 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 01224 if (!obj) { 01225 class->count--; 01226 ao2_ref(class, -1); 01227 ast_debug(3, "Unable to allocate object\n"); 01228 ast_atomic_fetchadd_int(&class->count, -1); 01229 return NULL; 01230 } 01231 ast_assert(ao2_ref(obj, 0) == 1); 01232 ast_mutex_init(&obj->lock); 01233 /* obj inherits the outstanding reference to class */ 01234 obj->parent = class; 01235 class = NULL; 01236 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01237 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01238 ao2_ref(obj, -1); 01239 obj = NULL; 01240 ast_assert(ao2_ref(class, 0) > 0); 01241 ast_atomic_fetchadd_int(&class->count, -1); 01242 } else { 01243 obj->used = 1; 01244 ao2_link(obj->parent->obj_container, obj); 01245 } 01246 } else { 01247 /* If construction fails due to the limit (or negative timecache), reverse our increment. */ 01248 if (!obj) { 01249 ast_atomic_fetchadd_int(&class->count, -1); 01250 } 01251 /* Object is not constructed, so delete outstanding reference to class. */ 01252 ao2_ref(class, -1); 01253 class = NULL; 01254 } 01255 01256 if (obj && ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { 01257 /* Ensure this connection has autocommit turned off. */ 01258 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { 01259 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01260 for (i = 0; i < numfields; i++) { 01261 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01262 ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01263 if (i > 10) { 01264 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01265 break; 01266 } 01267 } 01268 } 01269 } 01270 } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { 01271 /* Non-pooled connections -- but must use a separate connection handle */ 01272 if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) { 01273 ast_debug(1, "Object not found\n"); 01274 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 01275 if (!obj) { 01276 ao2_ref(class, -1); 01277 ast_debug(3, "Unable to allocate object\n"); 01278 return NULL; 01279 } 01280 ast_mutex_init(&obj->lock); 01281 /* obj inherits the outstanding reference to class */ 01282 obj->parent = class; 01283 class = NULL; 01284 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01285 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01286 ao2_ref(obj, -1); 01287 obj = NULL; 01288 } else { 01289 obj->used = 1; 01290 ao2_link(obj->parent->obj_container, obj); 01291 ast_atomic_fetchadd_int(&obj->parent->count, +1); 01292 } 01293 } 01294 01295 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { 01296 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01297 for (i = 0; i < numfields; i++) { 01298 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01299 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01300 if (i > 10) { 01301 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01302 break; 01303 } 01304 } 01305 } 01306 } else { 01307 /* Non-pooled connection: multiple modules can use the same connection. */ 01308 if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, NO_TX))) { 01309 /* Object is not constructed, so delete outstanding reference to class. */ 01310 ast_assert(ao2_ref(class, 0) > 1); 01311 ao2_ref(class, -1); 01312 class = NULL; 01313 } else { 01314 /* No entry: build one */ 01315 if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) { 01316 ast_assert(ao2_ref(class, 0) > 1); 01317 ao2_ref(class, -1); 01318 ast_debug(3, "Unable to allocate object\n"); 01319 return NULL; 01320 } 01321 ast_mutex_init(&obj->lock); 01322 /* obj inherits the outstanding reference to class */ 01323 obj->parent = class; 01324 class = NULL; 01325 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01326 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01327 ao2_ref(obj, -1); 01328 obj = NULL; 01329 } else { 01330 ao2_link(obj->parent->obj_container, obj); 01331 ast_assert(ao2_ref(obj, 0) > 1); 01332 } 01333 } 01334 01335 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) { 01336 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01337 for (i = 0; i < numfields; i++) { 01338 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01339 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01340 if (i > 10) { 01341 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01342 break; 01343 } 01344 } 01345 } 01346 } 01347 01348 /* Set the isolation property */ 01349 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) { 01350 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01351 for (i = 0; i < numfields; i++) { 01352 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01353 ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic); 01354 if (i > 10) { 01355 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01356 break; 01357 } 01358 } 01359 } 01360 01361 if (obj && ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) { 01362 /* Check if this connection qualifies for reconnection, with negative connection cache time */ 01363 if (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec) { 01364 odbc_obj_connect(obj); 01365 } 01366 } else if (obj && ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) { 01367 ast_odbc_sanity_check(obj); 01368 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) { 01369 odbc_obj_connect(obj); 01370 } 01371 01372 #ifdef DEBUG_THREADS 01373 if (obj) { 01374 ast_copy_string(obj->file, file, sizeof(obj->file)); 01375 ast_copy_string(obj->function, function, sizeof(obj->function)); 01376 obj->lineno = lineno; 01377 } 01378 #endif 01379 ast_assert(class == NULL); 01380 01381 if (obj) { 01382 ast_assert(ao2_ref(obj, 0) > 1); 01383 } 01384 return obj; 01385 }
static int acf_transaction_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 1517 of file res_odbc.c.
References args, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strlen_zero(), find_transaction(), odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, isolation2text(), and odbc_txn_frame::name.
01518 { 01519 AST_DECLARE_APP_ARGS(args, 01520 AST_APP_ARG(property); 01521 AST_APP_ARG(opt); 01522 ); 01523 struct odbc_txn_frame *tx; 01524 01525 AST_STANDARD_APP_ARGS(args, data); 01526 if (strcasecmp(args.property, "transaction") == 0) { 01527 if ((tx = find_transaction(chan, NULL, NULL, 1))) { 01528 ast_copy_string(buf, tx->name, len); 01529 return 0; 01530 } 01531 } else if (strcasecmp(args.property, "isolation") == 0) { 01532 if (!ast_strlen_zero(args.opt)) { 01533 tx = find_transaction(chan, NULL, args.opt, 0); 01534 } else { 01535 tx = find_transaction(chan, NULL, NULL, 1); 01536 } 01537 if (tx) { 01538 ast_copy_string(buf, isolation2text(tx->isolation), len); 01539 return 0; 01540 } 01541 } else if (strcasecmp(args.property, "forcecommit") == 0) { 01542 if (!ast_strlen_zero(args.opt)) { 01543 tx = find_transaction(chan, NULL, args.opt, 0); 01544 } else { 01545 tx = find_transaction(chan, NULL, NULL, 1); 01546 } 01547 if (tx) { 01548 ast_copy_string(buf, tx->forcecommit ? "1" : "0", len); 01549 return 0; 01550 } 01551 } 01552 return -1; 01553 }
static int acf_transaction_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | s, | |||
const char * | value | |||
) | [static] |
Definition at line 1555 of file res_odbc.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_false(), ast_log(), ast_odbc_request_obj2, AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_true(), odbc_obj::con, find_transaction(), ast_flags::flags, odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, LOG_ERROR, mark_transaction_active(), odbc_txn_frame::obj, pbx_builtin_setvar_helper(), RES_ODBC_INDEPENDENT_CONNECTION, S_OR, text2isolation(), and odbc_obj::tx.
01556 { 01557 AST_DECLARE_APP_ARGS(args, 01558 AST_APP_ARG(property); 01559 AST_APP_ARG(opt); 01560 ); 01561 struct odbc_txn_frame *tx; 01562 SQLINTEGER nativeerror=0, numfields=0; 01563 SQLSMALLINT diagbytes=0, i; 01564 unsigned char state[10], diagnostic[256]; 01565 01566 AST_STANDARD_APP_ARGS(args, s); 01567 if (strcasecmp(args.property, "transaction") == 0) { 01568 /* Set active transaction */ 01569 struct odbc_obj *obj; 01570 if ((tx = find_transaction(chan, NULL, value, 0))) { 01571 mark_transaction_active(chan, tx); 01572 } else { 01573 /* No such transaction, create one */ 01574 struct ast_flags flags = { RES_ODBC_INDEPENDENT_CONNECTION }; 01575 if (ast_strlen_zero(args.opt) || !(obj = ast_odbc_request_obj2(args.opt, flags))) { 01576 ast_log(LOG_ERROR, "Could not create transaction: invalid database specification '%s'\n", S_OR(args.opt, "")); 01577 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_DB"); 01578 return -1; 01579 } 01580 if (!(tx = find_transaction(chan, obj, value, 0))) { 01581 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); 01582 return -1; 01583 } 01584 obj->tx = 1; 01585 } 01586 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); 01587 return 0; 01588 } else if (strcasecmp(args.property, "forcecommit") == 0) { 01589 /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */ 01590 if (ast_strlen_zero(args.opt)) { 01591 tx = find_transaction(chan, NULL, NULL, 1); 01592 } else { 01593 tx = find_transaction(chan, NULL, args.opt, 0); 01594 } 01595 if (!tx) { 01596 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); 01597 return -1; 01598 } 01599 if (ast_true(value)) { 01600 tx->forcecommit = 1; 01601 } else if (ast_false(value)) { 01602 tx->forcecommit = 0; 01603 } else { 01604 ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, "")); 01605 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE"); 01606 return -1; 01607 } 01608 01609 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); 01610 return 0; 01611 } else if (strcasecmp(args.property, "isolation") == 0) { 01612 /* How do uncommitted transactions affect reads? */ 01613 int isolation = text2isolation(value); 01614 if (ast_strlen_zero(args.opt)) { 01615 tx = find_transaction(chan, NULL, NULL, 1); 01616 } else { 01617 tx = find_transaction(chan, NULL, args.opt, 0); 01618 } 01619 if (!tx) { 01620 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE"); 01621 return -1; 01622 } 01623 if (isolation == 0) { 01624 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE"); 01625 ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, "")); 01626 } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) { 01627 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR"); 01628 SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01629 for (i = 0; i < numfields; i++) { 01630 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01631 ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic); 01632 if (i > 10) { 01633 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01634 break; 01635 } 01636 } 01637 } else { 01638 pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK"); 01639 tx->isolation = isolation; 01640 } 01641 return 0; 01642 } else { 01643 ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property); 01644 return -1; 01645 } 01646 }
static int aoro2_class_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1172 of file res_odbc.c.
References CMP_MATCH, and CMP_STOP.
Referenced by _ast_odbc_request_obj2().
01173 { 01174 struct odbc_class *class = obj; 01175 char *name = arg; 01176 if (!strcmp(class->name, name) && !class->delme) { 01177 return CMP_MATCH | CMP_STOP; 01178 } 01179 return 0; 01180 }
static int aoro2_obj_cb | ( | void * | vobj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1186 of file res_odbc.c.
References ast_mutex_lock, ast_mutex_unlock, CMP_MATCH, CMP_STOP, EOR_TX, odbc_obj::lock, NO_TX, odbc_obj::tx, USE_TX, and odbc_obj::used.
Referenced by _ast_odbc_request_obj2().
01187 { 01188 struct odbc_obj *obj = vobj; 01189 ast_mutex_lock(&obj->lock); 01190 if ((arg == NO_TX && !obj->tx) || (arg == EOR_TX && !obj->used) || (arg == USE_TX && obj->tx && !obj->used)) { 01191 obj->used = 1; 01192 ast_mutex_unlock(&obj->lock); 01193 return CMP_MATCH | CMP_STOP; 01194 } 01195 ast_mutex_unlock(&obj->lock); 01196 return 0; 01197 }
AST_DATA_STRUCTURE | ( | odbc_class | , | |
DATA_EXPORT_ODBC_CLASS | ||||
) |
SQLRETURN ast_odbc_ast_str_SQLGetData | ( | struct ast_str ** | buf, | |
int | pmaxlen, | |||
SQLHSTMT | StatementHandle, | |||
SQLUSMALLINT | ColumnNumber, | |||
SQLSMALLINT | TargetType, | |||
SQLLEN * | StrLen_or_Ind | |||
) |
Wrapper for SQLGetData to use with dynamic strings.
buf | Address of the pointer to the ast_str structure. | |
pmaxlen | The maximum size of the resulting string, or 0 for no limit. | |
StatementHandle | The statement handle from which to retrieve data. | |
ColumnNumber | Column number (1-based offset) for which to retrieve data. | |
TargetType | The SQL constant indicating what kind of data is to be retrieved (usually SQL_CHAR) | |
StrLen_or_Ind | A pointer to a length indicator, specifying the total length of data. |
Definition at line 698 of file res_odbc.c.
References ast_str_buffer(), ast_str_make_space(), ast_str_size(), and ast_str_update().
00699 { 00700 SQLRETURN res; 00701 00702 if (pmaxlen == 0) { 00703 if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) { 00704 ast_str_make_space(buf, *StrLen_or_Ind + 1); 00705 } 00706 } else if (pmaxlen > 0) { 00707 ast_str_make_space(buf, pmaxlen); 00708 } 00709 res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind); 00710 ast_str_update(*buf); 00711 00712 return res; 00713 }
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 1093 of file res_odbc.c.
References odbc_class::backslash_is_escape, odbc_txn_frame::obj, and odbc_obj::parent.
Referenced by odbc_log(), realtime_multi_odbc(), and realtime_odbc().
01094 { 01095 return obj->parent->backslash_is_escape; 01096 }
int ast_odbc_clear_cache | ( | const char * | database, | |
const char * | tablename | |||
) |
Remove a cache entry from memory This function may be called to clear entries created and cached by the ast_odbc_find_table() API call.
database | Name of an ODBC class (used to ensure like-named tables in different databases are not confused) | |
tablename | 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 569 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.
00570 { 00571 struct odbc_cache_tables *tableptr; 00572 00573 AST_RWLIST_WRLOCK(&odbc_tables); 00574 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) { 00575 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00576 AST_LIST_REMOVE_CURRENT(list); 00577 destroy_table_cache(tableptr); 00578 break; 00579 } 00580 } 00581 AST_RWLIST_TRAVERSE_SAFE_END 00582 AST_RWLIST_UNLOCK(&odbc_tables); 00583 return tableptr ? 0 : -1; 00584 }
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 586 of file res_odbc.c.
References ast_log(), ast_odbc_sanity_check(), and LOG_WARNING.
Referenced by acf_odbc_read(), acf_odbc_write(), and odbc_log().
00587 { 00588 int attempt; 00589 SQLHSTMT stmt; 00590 00591 for (attempt = 0; attempt < 2; attempt++) { 00592 stmt = exec_cb(obj, data); 00593 00594 if (stmt) { 00595 break; 00596 } else if (obj->tx) { 00597 ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n"); 00598 break; 00599 } else if (attempt == 0) { 00600 ast_log(LOG_WARNING, "SQL Execute error! Verifying connection to %s [%s]...\n", obj->parent->name, obj->parent->dsn); 00601 } 00602 if (!ast_odbc_sanity_check(obj)) { 00603 break; 00604 } 00605 } 00606 00607 return stmt; 00608 }
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 558 of file res_odbc.c.
References AST_RWLIST_TRAVERSE, odbc_class::list, odbc_cache_columns::name, and table.
Referenced by update2_prepare(), and update_odbc().
00559 { 00560 struct odbc_cache_columns *col; 00561 AST_RWLIST_TRAVERSE(&table->columns, col, list) { 00562 if (strcasecmp(col->name, colname) == 0) { 00563 return col; 00564 } 00565 } 00566 return NULL; 00567 }
struct odbc_cache_tables* ast_odbc_find_table | ( | const char * | database, | |
const char * | tablename | |||
) |
Find or create an entry describing the table specified.
database | Name of an ODBC class on which to query the table | |
tablename | 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 443 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(), update2_prepare(), and update_odbc().
00444 { 00445 struct odbc_cache_tables *tableptr; 00446 struct odbc_cache_columns *entry; 00447 char columnname[80]; 00448 SQLLEN sqlptr; 00449 SQLHSTMT stmt = NULL; 00450 int res = 0, error = 0, try = 0; 00451 struct odbc_obj *obj = ast_odbc_request_obj(database, 0); 00452 00453 AST_RWLIST_RDLOCK(&odbc_tables); 00454 AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) { 00455 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00456 break; 00457 } 00458 } 00459 if (tableptr) { 00460 AST_RWLIST_RDLOCK(&tableptr->columns); 00461 AST_RWLIST_UNLOCK(&odbc_tables); 00462 if (obj) { 00463 ast_odbc_release_obj(obj); 00464 } 00465 return tableptr; 00466 } 00467 00468 if (!obj) { 00469 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database); 00470 AST_RWLIST_UNLOCK(&odbc_tables); 00471 return NULL; 00472 } 00473 00474 /* Table structure not already cached; build it now. */ 00475 do { 00476 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00477 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00478 if (try == 0) { 00479 try = 1; 00480 ast_odbc_sanity_check(obj); 00481 continue; 00482 } 00483 ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database); 00484 break; 00485 } 00486 00487 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS); 00488 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00489 if (try == 0) { 00490 try = 1; 00491 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00492 ast_odbc_sanity_check(obj); 00493 continue; 00494 } 00495 ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database); 00496 break; 00497 } 00498 00499 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) { 00500 ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database); 00501 break; 00502 } 00503 00504 tableptr->connection = (char *)tableptr + sizeof(*tableptr); 00505 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1; 00506 strcpy(tableptr->connection, database); /* SAFE */ 00507 strcpy(tableptr->table, tablename); /* SAFE */ 00508 AST_RWLIST_HEAD_INIT(&(tableptr->columns)); 00509 00510 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) { 00511 SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr); 00512 00513 if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) { 00514 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database); 00515 error = 1; 00516 break; 00517 } 00518 entry->name = (char *)entry + sizeof(*entry); 00519 strcpy(entry->name, columnname); 00520 00521 SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL); 00522 SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL); 00523 SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL); 00524 SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL); 00525 SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL); 00526 SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL); 00527 00528 /* Specification states that the octenlen should be the maximum number of bytes 00529 * returned in a char or binary column, but it seems that some drivers just set 00530 * it to NULL. (Bad Postgres! No biscuit!) */ 00531 if (entry->octetlen == 0) { 00532 entry->octetlen = entry->size; 00533 } 00534 00535 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); 00536 /* Insert column info into column list */ 00537 AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list); 00538 } 00539 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00540 00541 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list); 00542 AST_RWLIST_RDLOCK(&(tableptr->columns)); 00543 break; 00544 } while (1); 00545 00546 AST_RWLIST_UNLOCK(&odbc_tables); 00547 00548 if (error) { 00549 destroy_table_cache(tableptr); 00550 tableptr = NULL; 00551 } 00552 if (obj) { 00553 ast_odbc_release_obj(obj); 00554 } 00555 return tableptr; 00556 }
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 610 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(), update2_odbc(), and update_odbc().
00611 { 00612 int res = 0, i, attempt; 00613 SQLINTEGER nativeerror=0, numfields=0; 00614 SQLSMALLINT diagbytes=0; 00615 unsigned char state[10], diagnostic[256]; 00616 SQLHSTMT stmt; 00617 00618 for (attempt = 0; attempt < 2; attempt++) { 00619 /* This prepare callback may do more than just prepare -- it may also 00620 * bind parameters, bind results, etc. The real key, here, is that 00621 * when we disconnect, all handles become invalid for most databases. 00622 * We must therefore redo everything when we establish a new 00623 * connection. */ 00624 stmt = prepare_cb(obj, data); 00625 00626 if (stmt) { 00627 res = SQLExecute(stmt); 00628 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00629 if (res == SQL_ERROR) { 00630 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00631 for (i = 0; i < numfields; i++) { 00632 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00633 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00634 if (i > 10) { 00635 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00636 break; 00637 } 00638 } 00639 } 00640 00641 if (obj->tx) { 00642 ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n"); 00643 break; 00644 } else { 00645 ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn); 00646 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00647 stmt = NULL; 00648 00649 obj->up = 0; 00650 /* 00651 * While this isn't the best way to try to correct an error, this won't automatically 00652 * fail when the statement handle invalidates. 00653 */ 00654 if (!ast_odbc_sanity_check(obj)) { 00655 break; 00656 } 00657 continue; 00658 } 00659 } else { 00660 obj->last_used = ast_tvnow(); 00661 } 00662 break; 00663 } else if (attempt == 0) { 00664 ast_odbc_sanity_check(obj); 00665 } 00666 } 00667 00668 return stmt; 00669 }
void ast_odbc_release_obj | ( | struct odbc_obj * | obj | ) |
Releases an ODBC object previously allocated by ast_odbc_request_obj().
obj | The ODBC object |
Definition at line 1087 of file res_odbc.c.
References find_transaction(), odbc_txn_frame::obj, and odbc_release_obj2().
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(), update2_odbc(), and update_odbc().
01088 { 01089 struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0); 01090 odbc_release_obj2(obj, tx); 01091 }
struct odbc_obj* ast_odbc_retrieve_transaction_obj | ( | struct ast_channel * | chan, | |
const char * | objname | |||
) |
Retrieve a stored ODBC object, if a transaction has been started.
chan | Channel associated with the transaction. | |
objname | Name of the database handle. This name corresponds to the name passed to |
A | stored ODBC object, if a transaction was already started. | |
NULL,if | no transaction yet exists. |
Definition at line 1393 of file res_odbc.c.
References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_txn_frame::list, odbc_class::name, odbc_txn_frame::obj, odbc_obj::parent, and txn_info.
Referenced by acf_odbc_write().
01394 { 01395 struct ast_datastore *txn_store; 01396 AST_LIST_HEAD(, odbc_txn_frame) *oldlist; 01397 struct odbc_txn_frame *txn = NULL; 01398 01399 if (!chan) { 01400 /* No channel == no transaction */ 01401 return NULL; 01402 } 01403 01404 ast_channel_lock(chan); 01405 if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { 01406 oldlist = txn_store->data; 01407 } else { 01408 ast_channel_unlock(chan); 01409 return NULL; 01410 } 01411 01412 AST_LIST_LOCK(oldlist); 01413 ast_channel_unlock(chan); 01414 01415 AST_LIST_TRAVERSE(oldlist, txn, list) { 01416 if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) { 01417 AST_LIST_UNLOCK(oldlist); 01418 return txn->obj; 01419 } 01420 } 01421 AST_LIST_UNLOCK(oldlist); 01422 return NULL; 01423 }
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 715 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, odbc_obj::tx, and odbc_obj::up.
Referenced by ast_odbc_direct_execute(), ast_odbc_find_table(), ast_odbc_prepare_and_execute(), data_odbc_provider_handler(), and handle_cli_odbc_show().
00716 { 00717 char *test_sql = "select 1"; 00718 SQLHSTMT stmt; 00719 int res = 0; 00720 00721 if (!ast_strlen_zero(obj->parent->sanitysql)) 00722 test_sql = obj->parent->sanitysql; 00723 00724 if (obj->up) { 00725 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00726 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00727 obj->up = 0; 00728 } else { 00729 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00730 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00731 obj->up = 0; 00732 } else { 00733 res = SQLExecute(stmt); 00734 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00735 obj->up = 0; 00736 } 00737 } 00738 } 00739 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00740 } 00741 00742 if (!obj->up && !obj->tx) { /* Try to reconnect! */ 00743 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00744 odbc_obj_disconnect(obj); 00745 odbc_obj_connect(obj); 00746 } 00747 return obj->up; 00748 }
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 671 of file res_odbc.c.
References ast_log(), ast_tvnow(), odbc_obj::last_used, and LOG_WARNING.
00672 { 00673 int res = 0, i; 00674 SQLINTEGER nativeerror=0, numfields=0; 00675 SQLSMALLINT diagbytes=0; 00676 unsigned char state[10], diagnostic[256]; 00677 00678 res = SQLExecute(stmt); 00679 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00680 if (res == SQL_ERROR) { 00681 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00682 for (i = 0; i < numfields; i++) { 00683 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00684 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00685 if (i > 10) { 00686 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00687 break; 00688 } 00689 } 00690 } 00691 } else { 00692 obj->last_used = ast_tvnow(); 00693 } 00694 00695 return res; 00696 }
static int commit_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1098 of file res_odbc.c.
References ast_log(), ast_str_append(), ast_str_buffer(), ast_str_reset(), ast_str_strlen(), ast_str_thread_get(), ast_strlen_zero(), odbc_obj::con, errors_buf, find_transaction(), LOG_WARNING, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().
Referenced by load_module().
01099 { 01100 struct odbc_txn_frame *tx; 01101 SQLINTEGER nativeerror=0, numfields=0; 01102 SQLSMALLINT diagbytes=0, i; 01103 unsigned char state[10], diagnostic[256]; 01104 01105 if (ast_strlen_zero(data)) { 01106 tx = find_transaction(chan, NULL, NULL, 1); 01107 } else { 01108 tx = find_transaction(chan, NULL, data, 0); 01109 } 01110 01111 pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK"); 01112 01113 if (tx) { 01114 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) { 01115 struct ast_str *errors = ast_str_thread_get(&errors_buf, 16); 01116 ast_str_reset(errors); 01117 01118 /* Handle possible transaction commit failure */ 01119 SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01120 for (i = 0; i < numfields; i++) { 01121 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01122 ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state); 01123 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic); 01124 if (i > 10) { 01125 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01126 break; 01127 } 01128 } 01129 pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors)); 01130 } 01131 } 01132 return 0; 01133 }
static int data_odbc_provider_handler | ( | const struct ast_data_search * | search, | |
struct ast_data * | root | |||
) | [static] |
Definition at line 1661 of file res_odbc.c.
References ao2_container_count(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_data_add_bool(), ast_data_add_int(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), ast_mutex_lock, ast_mutex_unlock, ast_odbc_sanity_check(), class_container, isolation2text(), odbc_obj::lock, odbc_obj::tx, odbc_obj::up, and odbc_obj::used.
01663 { 01664 struct ao2_iterator aoi, aoi2; 01665 struct odbc_class *class; 01666 struct odbc_obj *current; 01667 struct ast_data *data_odbc_class, *data_odbc_connections, *data_odbc_connection; 01668 struct ast_data *enum_node; 01669 int count; 01670 01671 aoi = ao2_iterator_init(class_container, 0); 01672 while ((class = ao2_iterator_next(&aoi))) { 01673 data_odbc_class = ast_data_add_node(root, "class"); 01674 if (!data_odbc_class) { 01675 ao2_ref(class, -1); 01676 continue; 01677 } 01678 01679 ast_data_add_structure(odbc_class, data_odbc_class, class); 01680 01681 if (!ao2_container_count(class->obj_container)) { 01682 ao2_ref(class, -1); 01683 continue; 01684 } 01685 01686 data_odbc_connections = ast_data_add_node(data_odbc_class, "connections"); 01687 if (!data_odbc_connections) { 01688 ao2_ref(class, -1); 01689 continue; 01690 } 01691 01692 ast_data_add_bool(data_odbc_class, "shared", !class->haspool); 01693 /* isolation */ 01694 enum_node = ast_data_add_node(data_odbc_class, "isolation"); 01695 if (!enum_node) { 01696 ao2_ref(class, -1); 01697 continue; 01698 } 01699 ast_data_add_int(enum_node, "value", class->isolation); 01700 ast_data_add_str(enum_node, "text", isolation2text(class->isolation)); 01701 01702 count = 0; 01703 aoi2 = ao2_iterator_init(class->obj_container, 0); 01704 while ((current = ao2_iterator_next(&aoi2))) { 01705 data_odbc_connection = ast_data_add_node(data_odbc_connections, "connection"); 01706 if (!data_odbc_connection) { 01707 ao2_ref(current, -1); 01708 continue; 01709 } 01710 01711 ast_mutex_lock(¤t->lock); 01712 ast_data_add_str(data_odbc_connection, "status", current->used ? "in use" : 01713 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); 01714 ast_data_add_bool(data_odbc_connection, "transactional", current->tx); 01715 ast_mutex_unlock(¤t->lock); 01716 01717 if (class->haspool) { 01718 ast_data_add_int(data_odbc_connection, "number", ++count); 01719 } 01720 01721 ao2_ref(current, -1); 01722 } 01723 ao2_ref(class, -1); 01724 01725 if (!ast_data_search_match(search, data_odbc_class)) { 01726 ast_data_remove_node(root, data_odbc_class); 01727 } 01728 } 01729 return 0; 01730 }
static void destroy_table_cache | ( | struct odbc_cache_tables * | table | ) | [static] |
Definition at line 422 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().
00422 { 00423 struct odbc_cache_columns *col; 00424 ast_debug(1, "Destroying table cache for %s\n", table->table); 00425 AST_RWLIST_WRLOCK(&table->columns); 00426 while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) { 00427 ast_free(col); 00428 } 00429 AST_RWLIST_UNLOCK(&table->columns); 00430 AST_RWLIST_HEAD_DESTROY(&table->columns); 00431 ast_free(table); 00432 }
static struct odbc_txn_frame* find_transaction | ( | struct ast_channel * | chan, | |
struct odbc_obj * | obj, | |||
const char * | name, | |||
int | active | |||
) | [static] |
Definition at line 222 of file res_odbc.c.
References odbc_txn_frame::active, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, odbc_class::forcecommit, odbc_class::isolation, odbc_class::list, LOG_ERROR, odbc_txn_frame::name, odbc_txn_frame::obj, odbc_txn_frame::owner, odbc_obj::parent, odbc_obj::tx, odbc_obj::txf, and txn_info.
00223 { 00224 struct ast_datastore *txn_store; 00225 AST_LIST_HEAD(, odbc_txn_frame) *oldlist; 00226 struct odbc_txn_frame *txn = NULL; 00227 00228 if (!chan && obj && obj->txf && obj->txf->owner) { 00229 chan = obj->txf->owner; 00230 } else if (!chan) { 00231 /* No channel == no transaction */ 00232 return NULL; 00233 } 00234 00235 ast_channel_lock(chan); 00236 if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { 00237 oldlist = txn_store->data; 00238 } else { 00239 /* Need to create a new datastore */ 00240 if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) { 00241 ast_log(LOG_ERROR, "Unable to allocate a new datastore. Cannot create a new transaction.\n"); 00242 ast_channel_unlock(chan); 00243 return NULL; 00244 } 00245 00246 if (!(oldlist = ast_calloc(1, sizeof(*oldlist)))) { 00247 ast_log(LOG_ERROR, "Unable to allocate datastore list head. Cannot create a new transaction.\n"); 00248 ast_datastore_free(txn_store); 00249 ast_channel_unlock(chan); 00250 return NULL; 00251 } 00252 00253 txn_store->data = oldlist; 00254 AST_LIST_HEAD_INIT(oldlist); 00255 ast_channel_datastore_add(chan, txn_store); 00256 } 00257 00258 AST_LIST_LOCK(oldlist); 00259 ast_channel_unlock(chan); 00260 00261 /* Scanning for an object is *fast*. Scanning for a name is much slower. */ 00262 if (obj != NULL || active == 1) { 00263 AST_LIST_TRAVERSE(oldlist, txn, list) { 00264 if (txn->obj == obj || txn->active) { 00265 AST_LIST_UNLOCK(oldlist); 00266 return txn; 00267 } 00268 } 00269 } 00270 00271 if (name != NULL) { 00272 AST_LIST_TRAVERSE(oldlist, txn, list) { 00273 if (!strcasecmp(txn->name, name)) { 00274 AST_LIST_UNLOCK(oldlist); 00275 return txn; 00276 } 00277 } 00278 } 00279 00280 /* Nothing found, create one */ 00281 if (name && obj && (txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1))) { 00282 struct odbc_txn_frame *otxn; 00283 00284 strcpy(txn->name, name); /* SAFE */ 00285 txn->obj = obj; 00286 txn->isolation = obj->parent->isolation; 00287 txn->forcecommit = obj->parent->forcecommit; 00288 txn->owner = chan; 00289 txn->active = 1; 00290 00291 /* On creation, the txn becomes active, and all others inactive */ 00292 AST_LIST_TRAVERSE(oldlist, otxn, list) { 00293 otxn->active = 0; 00294 } 00295 AST_LIST_INSERT_TAIL(oldlist, txn, list); 00296 00297 obj->txf = txn; 00298 obj->tx = 1; 00299 } 00300 AST_LIST_UNLOCK(oldlist); 00301 00302 return txn; 00303 }
static char* handle_cli_odbc_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 911 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_localtime(), ast_mutex_lock, ast_mutex_unlock, ast_odbc_sanity_check(), ast_strdup, ast_strftime(), class_container, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, odbc_obj::file, odbc_obj::function, odbc_obj::lineno, 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.
00912 { 00913 struct ao2_iterator aoi = ao2_iterator_init(class_container, 0); 00914 struct odbc_class *class; 00915 struct odbc_obj *current; 00916 int length = 0; 00917 int which = 0; 00918 char *ret = NULL; 00919 00920 switch (cmd) { 00921 case CLI_INIT: 00922 e->command = "odbc show"; 00923 e->usage = 00924 "Usage: odbc show [class]\n" 00925 " List settings of a particular ODBC class or,\n" 00926 " if not specified, all classes.\n"; 00927 return NULL; 00928 case CLI_GENERATE: 00929 if (a->pos != 2) 00930 return NULL; 00931 length = strlen(a->word); 00932 while ((class = ao2_iterator_next(&aoi))) { 00933 if (!strncasecmp(a->word, class->name, length) && ++which > a->n) { 00934 ret = ast_strdup(class->name); 00935 } 00936 ao2_ref(class, -1); 00937 if (ret) { 00938 break; 00939 } 00940 } 00941 ao2_iterator_destroy(&aoi); 00942 if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) { 00943 ret = ast_strdup("all"); 00944 } 00945 return ret; 00946 } 00947 00948 ast_cli(a->fd, "\nODBC DSN Settings\n"); 00949 ast_cli(a->fd, "-----------------\n\n"); 00950 aoi = ao2_iterator_init(class_container, 0); 00951 while ((class = ao2_iterator_next(&aoi))) { 00952 if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) { 00953 int count = 0; 00954 char timestr[80]; 00955 struct ast_tm tm; 00956 00957 ast_localtime(&class->last_negative_connect, &tm, NULL); 00958 ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm); 00959 ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn); 00960 ast_cli(a->fd, " Last connection attempt: %s\n", timestr); 00961 00962 if (class->haspool) { 00963 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0); 00964 00965 ast_cli(a->fd, " Pooled: Yes\n Limit: %d\n Connections in use: %d\n", class->limit, class->count); 00966 00967 while ((current = ao2_iterator_next(&aoi2))) { 00968 ast_mutex_lock(¤t->lock); 00969 #ifdef DEBUG_THREADS 00970 ast_cli(a->fd, " - Connection %d: %s (%s:%d %s)\n", ++count, 00971 current->used ? "in use" : 00972 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected", 00973 current->file, current->lineno, current->function); 00974 #else 00975 ast_cli(a->fd, " - Connection %d: %s\n", ++count, 00976 current->used ? "in use" : 00977 current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected"); 00978 #endif 00979 ast_mutex_unlock(¤t->lock); 00980 ao2_ref(current, -1); 00981 } 00982 ao2_iterator_destroy(&aoi2); 00983 } else { 00984 /* Should only ever be one of these (unless there are transactions) */ 00985 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0); 00986 while ((current = ao2_iterator_next(&aoi2))) { 00987 ast_cli(a->fd, " Pooled: No\n Connected: %s\n", current->used ? "In use" : 00988 current->up && ast_odbc_sanity_check(current) ? "Yes" : "No"); 00989 ao2_ref(current, -1); 00990 } 00991 ao2_iterator_destroy(&aoi2); 00992 } 00993 ast_cli(a->fd, "\n"); 00994 } 00995 ao2_ref(class, -1); 00996 } 00997 ao2_iterator_destroy(&aoi); 00998 00999 return CLI_SUCCESS; 01000 }
static const char* isolation2text | ( | int | iso | ) | [static] |
Definition at line 188 of file res_odbc.c.
Referenced by acf_transaction_read(), and data_odbc_provider_handler().
00189 { 00190 if (iso == SQL_TXN_READ_COMMITTED) { 00191 return "read_committed"; 00192 } else if (iso == SQL_TXN_READ_UNCOMMITTED) { 00193 return "read_uncommitted"; 00194 } else if (iso == SQL_TXN_SERIALIZABLE) { 00195 return "serializable"; 00196 } else if (iso == SQL_TXN_REPEATABLE_READ) { 00197 return "repeatable_read"; 00198 } else { 00199 return "unknown"; 00200 } 00201 }
static int load_module | ( | void | ) | [static] |
Definition at line 1825 of file res_odbc.c.
References ao2_container_alloc, ao2_match_by_addr, ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_data_register_multiple, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application_xml, class_container, cli_odbc, commit_exec(), load_odbc_config(), LOG_NOTICE, null_hash_fn(), odbc_function, odbc_providers, and rollback_exec().
01826 { 01827 if (!(class_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr))) 01828 return AST_MODULE_LOAD_DECLINE; 01829 if (load_odbc_config() == -1) 01830 return AST_MODULE_LOAD_DECLINE; 01831 ast_cli_register_multiple(cli_odbc, ARRAY_LEN(cli_odbc)); 01832 ast_data_register_multiple(odbc_providers, ARRAY_LEN(odbc_providers)); 01833 ast_register_application_xml(app_commit, commit_exec); 01834 ast_register_application_xml(app_rollback, rollback_exec); 01835 ast_custom_function_register(&odbc_function); 01836 ast_log(LOG_NOTICE, "res_odbc loaded.\n"); 01837 return 0; 01838 }
static int load_odbc_config | ( | void | ) | [static] |
Definition at line 750 of file res_odbc.c.
References ast_category_browse(), ast_config_load, ast_false(), ast_log(), ast_true(), ast_variable_browse(), config, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, odbc_class::conntimeout, 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().
00751 { 00752 static char *cfg = "res_odbc.conf"; 00753 struct ast_config *config; 00754 struct ast_variable *v; 00755 char *cat; 00756 const char *dsn, *username, *password, *sanitysql; 00757 int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation; 00758 struct timeval ncache = { 0, 0 }; 00759 unsigned int idlecheck; 00760 int preconnect = 0, res = 0; 00761 struct ast_flags config_flags = { 0 }; 00762 00763 struct odbc_class *new; 00764 00765 config = ast_config_load(cfg, config_flags); 00766 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) { 00767 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n"); 00768 return -1; 00769 } 00770 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { 00771 if (!strcasecmp(cat, "ENV")) { 00772 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00773 setenv(v->name, v->value, 1); 00774 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); 00775 } 00776 } else { 00777 /* Reset all to defaults for each class of odbc connections */ 00778 dsn = username = password = sanitysql = NULL; 00779 enabled = 1; 00780 preconnect = idlecheck = 0; 00781 pooling = 0; 00782 limit = 0; 00783 bse = 1; 00784 conntimeout = 10; 00785 forcecommit = 0; 00786 isolation = SQL_TXN_READ_COMMITTED; 00787 for (v = ast_variable_browse(config, cat); v; v = v->next) { 00788 if (!strcasecmp(v->name, "pooling")) { 00789 if (ast_true(v->value)) 00790 pooling = 1; 00791 } else if (!strncasecmp(v->name, "share", 5)) { 00792 /* "shareconnections" is a little clearer in meaning than "pooling" */ 00793 if (ast_false(v->value)) 00794 pooling = 1; 00795 } else if (!strcasecmp(v->name, "limit")) { 00796 sscanf(v->value, "%30d", &limit); 00797 if (ast_true(v->value) && !limit) { 00798 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); 00799 limit = 1023; 00800 } else if (ast_false(v->value)) { 00801 ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat); 00802 enabled = 0; 00803 break; 00804 } 00805 } else if (!strcasecmp(v->name, "idlecheck")) { 00806 sscanf(v->value, "%30u", &idlecheck); 00807 } else if (!strcasecmp(v->name, "enabled")) { 00808 enabled = ast_true(v->value); 00809 } else if (!strcasecmp(v->name, "pre-connect")) { 00810 preconnect = ast_true(v->value); 00811 } else if (!strcasecmp(v->name, "dsn")) { 00812 dsn = v->value; 00813 } else if (!strcasecmp(v->name, "username")) { 00814 username = v->value; 00815 } else if (!strcasecmp(v->name, "password")) { 00816 password = v->value; 00817 } else if (!strcasecmp(v->name, "sanitysql")) { 00818 sanitysql = v->value; 00819 } else if (!strcasecmp(v->name, "backslash_is_escape")) { 00820 bse = ast_true(v->value); 00821 } else if (!strcasecmp(v->name, "connect_timeout")) { 00822 if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) { 00823 ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n"); 00824 conntimeout = 10; 00825 } 00826 } else if (!strcasecmp(v->name, "negative_connection_cache")) { 00827 double dncache; 00828 if (sscanf(v->value, "%lf", &dncache) != 1 || dncache < 0) { 00829 ast_log(LOG_WARNING, "negative_connection_cache must be a non-negative integer\n"); 00830 /* 5 minutes sounds like a reasonable default */ 00831 ncache.tv_sec = 300; 00832 ncache.tv_usec = 0; 00833 } else { 00834 ncache.tv_sec = (int)dncache; 00835 ncache.tv_usec = (dncache - ncache.tv_sec) * 1000000; 00836 } 00837 } else if (!strcasecmp(v->name, "forcecommit")) { 00838 forcecommit = ast_true(v->value); 00839 } else if (!strcasecmp(v->name, "isolation")) { 00840 if ((isolation = text2isolation(v->value)) == 0) { 00841 ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat); 00842 isolation = SQL_TXN_READ_COMMITTED; 00843 } 00844 } 00845 } 00846 00847 if (enabled && !ast_strlen_zero(dsn)) { 00848 new = ao2_alloc(sizeof(*new), odbc_class_destructor); 00849 00850 if (!new) { 00851 res = -1; 00852 break; 00853 } 00854 00855 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env); 00856 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); 00857 00858 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00859 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); 00860 ao2_ref(new, -1); 00861 return res; 00862 } 00863 00864 new->obj_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr); 00865 00866 if (pooling) { 00867 new->haspool = pooling; 00868 if (limit) { 00869 new->limit = limit; 00870 } else { 00871 ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n"); 00872 new->limit = 5; 00873 } 00874 } 00875 00876 new->backslash_is_escape = bse ? 1 : 0; 00877 new->forcecommit = forcecommit ? 1 : 0; 00878 new->isolation = isolation; 00879 new->idlecheck = idlecheck; 00880 new->conntimeout = conntimeout; 00881 new->negative_connection_cache = ncache; 00882 00883 if (cat) 00884 ast_copy_string(new->name, cat, sizeof(new->name)); 00885 if (dsn) 00886 ast_copy_string(new->dsn, dsn, sizeof(new->dsn)); 00887 if (username && !(new->username = ast_strdup(username))) { 00888 ao2_ref(new, -1); 00889 break; 00890 } 00891 if (password && !(new->password = ast_strdup(password))) { 00892 ao2_ref(new, -1); 00893 break; 00894 } 00895 if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) { 00896 ao2_ref(new, -1); 00897 break; 00898 } 00899 00900 odbc_register_class(new, preconnect); 00901 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn); 00902 ao2_ref(new, -1); 00903 new = NULL; 00904 } 00905 } 00906 } 00907 ast_config_destroy(config); 00908 return res; 00909 }
static int mark_transaction_active | ( | struct ast_channel * | chan, | |
struct odbc_txn_frame * | tx | |||
) | [static] |
Definition at line 357 of file res_odbc.c.
References odbc_txn_frame::active, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_class::list, odbc_txn_frame::owner, and txn_info.
Referenced by acf_transaction_write().
00358 { 00359 struct ast_datastore *txn_store; 00360 AST_LIST_HEAD(, odbc_txn_frame) *oldlist; 00361 struct odbc_txn_frame *active = NULL, *txn; 00362 00363 if (!chan && tx && tx->owner) { 00364 chan = tx->owner; 00365 } 00366 00367 ast_channel_lock(chan); 00368 if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { 00369 ast_channel_unlock(chan); 00370 return -1; 00371 } 00372 00373 oldlist = txn_store->data; 00374 AST_LIST_LOCK(oldlist); 00375 AST_LIST_TRAVERSE(oldlist, txn, list) { 00376 if (txn == tx) { 00377 txn->active = 1; 00378 active = txn; 00379 } else { 00380 txn->active = 0; 00381 } 00382 } 00383 AST_LIST_UNLOCK(oldlist); 00384 ast_channel_unlock(chan); 00385 return active ? 0 : -1; 00386 }
static int null_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
static void odbc_class_destructor | ( | void * | data | ) | [static] |
Definition at line 388 of file res_odbc.c.
References ao2_ref, and ast_free.
00389 { 00390 struct odbc_class *class = data; 00391 /* Due to refcounts, we can safely assume that any objects with a reference 00392 * to us will prevent our destruction, so we don't need to worry about them. 00393 */ 00394 if (class->username) { 00395 ast_free(class->username); 00396 } 00397 if (class->password) { 00398 ast_free(class->password); 00399 } 00400 if (class->sanitysql) { 00401 ast_free(class->sanitysql); 00402 } 00403 ao2_ref(class->obj_container, -1); 00404 SQLFreeHandle(SQL_HANDLE_ENV, class->env); 00405 }
static odbc_status odbc_obj_connect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 1462 of file res_odbc.c.
References ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_tvnow(), odbc_obj::con, odbc_class::conntimeout, odbc_class::dsn, odbc_class::env, odbc_class::last_negative_connect, odbc_obj::last_used, odbc_obj::lock, LOG_NOTICE, odbc_class::name, odbc_txn_frame::obj, ODBC_FAIL, odbc_obj_disconnect(), ODBC_SUCCESS, odbc_obj::parent, odbc_class::password, odbc_obj::up, and odbc_class::username.
Referenced by _ast_odbc_request_obj2(), and ast_odbc_sanity_check().
01463 { 01464 int res; 01465 SQLINTEGER err; 01466 short int mlen; 01467 unsigned char msg[200], state[10]; 01468 #ifdef NEEDTRACE 01469 SQLINTEGER enable = 1; 01470 char *tracefile = "/tmp/odbc.trace"; 01471 #endif 01472 ast_mutex_lock(&obj->lock); 01473 01474 if (obj->up) { 01475 odbc_obj_disconnect(obj); 01476 ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name); 01477 } else { 01478 ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name); 01479 } 01480 01481 res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con); 01482 01483 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 01484 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res); 01485 obj->parent->last_negative_connect = ast_tvnow(); 01486 ast_mutex_unlock(&obj->lock); 01487 return ODBC_FAIL; 01488 } 01489 SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0); 01490 SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0); 01491 #ifdef NEEDTRACE 01492 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); 01493 SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); 01494 #endif 01495 01496 res = SQLConnect(obj->con, 01497 (SQLCHAR *) obj->parent->dsn, SQL_NTS, 01498 (SQLCHAR *) obj->parent->username, SQL_NTS, 01499 (SQLCHAR *) obj->parent->password, SQL_NTS); 01500 01501 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 01502 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen); 01503 obj->parent->last_negative_connect = ast_tvnow(); 01504 ast_mutex_unlock(&obj->lock); 01505 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg); 01506 return ODBC_FAIL; 01507 } else { 01508 ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn); 01509 obj->up = 1; 01510 obj->last_used = ast_tvnow(); 01511 } 01512 01513 ast_mutex_unlock(&obj->lock); 01514 return ODBC_SUCCESS; 01515 }
static void odbc_obj_destructor | ( | void * | data | ) | [static] |
Definition at line 412 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_obj2().
00413 { 00414 struct odbc_obj *obj = data; 00415 struct odbc_class *class = obj->parent; 00416 obj->parent = NULL; 00417 odbc_obj_disconnect(obj); 00418 ast_mutex_destroy(&obj->lock); 00419 ao2_ref(class, -1); 00420 }
static odbc_status odbc_obj_disconnect | ( | struct odbc_obj * | obj | ) | [static] |
Definition at line 1425 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, odbc_class::name, odbc_txn_frame::obj, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.
Referenced by ast_odbc_sanity_check(), odbc_obj_connect(), and odbc_obj_destructor().
01426 { 01427 int res; 01428 SQLINTEGER err; 01429 short int mlen; 01430 unsigned char msg[200], state[10]; 01431 01432 /* Nothing to disconnect */ 01433 if (!obj->con) { 01434 return ODBC_SUCCESS; 01435 } 01436 01437 ast_mutex_lock(&obj->lock); 01438 01439 res = SQLDisconnect(obj->con); 01440 01441 if (obj->parent) { 01442 if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) { 01443 ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn); 01444 } else { 01445 ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn); 01446 } 01447 } 01448 01449 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == SQL_SUCCESS)) { 01450 obj->con = NULL; 01451 ast_log(LOG_DEBUG, "Database handle deallocated\n"); 01452 } else { 01453 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen); 01454 ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg); 01455 } 01456 01457 obj->up = 0; 01458 ast_mutex_unlock(&obj->lock); 01459 return ODBC_SUCCESS; 01460 }
static int odbc_register_class | ( | struct odbc_class * | class, | |
int | connect | |||
) | [static] |
Definition at line 1006 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.
01007 { 01008 struct odbc_obj *obj; 01009 if (class) { 01010 ao2_link(class_container, class); 01011 /* I still have a reference in the caller, so a deref is NOT missing here. */ 01012 01013 if (preconnect) { 01014 /* Request and release builds a connection */ 01015 obj = ast_odbc_request_obj(class->name, 0); 01016 if (obj) { 01017 ast_odbc_release_obj(obj); 01018 } 01019 } 01020 01021 return 0; 01022 } else { 01023 ast_log(LOG_WARNING, "Attempted to register a NULL class?\n"); 01024 return -1; 01025 } 01026 }
static void odbc_release_obj2 | ( | struct odbc_obj * | obj, | |
struct odbc_txn_frame * | tx | |||
) | [static] |
Definition at line 1028 of file res_odbc.c.
References ast_debug, ast_log(), odbc_obj::con, LOG_WARNING, odbc_obj::tx, and odbc_obj::txf.
Referenced by ast_odbc_release_obj(), and release_transaction().
01029 { 01030 SQLINTEGER nativeerror=0, numfields=0; 01031 SQLSMALLINT diagbytes=0, i; 01032 unsigned char state[10], diagnostic[256]; 01033 01034 ast_debug(2, "odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->txf); 01035 if (tx) { 01036 ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK"); 01037 if (SQLEndTran(SQL_HANDLE_DBC, obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) { 01038 /* Handle possible transaction commit failure */ 01039 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01040 for (i = 0; i < numfields; i++) { 01041 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01042 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic); 01043 if (!strcmp((char *)state, "25S02") || !strcmp((char *)state, "08007")) { 01044 /* These codes mean that a commit failed and a transaction 01045 * is still active. We must rollback, or things will get 01046 * very, very weird for anybody using the handle next. */ 01047 SQLEndTran(SQL_HANDLE_DBC, obj->con, SQL_ROLLBACK); 01048 } 01049 if (i > 10) { 01050 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01051 break; 01052 } 01053 } 01054 } 01055 01056 /* Transaction is done, reset autocommit */ 01057 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) { 01058 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01059 for (i = 0; i < numfields; i++) { 01060 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01061 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01062 if (i > 10) { 01063 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01064 break; 01065 } 01066 } 01067 } 01068 } 01069 01070 #ifdef DEBUG_THREADS 01071 obj->file[0] = '\0'; 01072 obj->function[0] = '\0'; 01073 obj->lineno = 0; 01074 #endif 01075 01076 /* For pooled connections, this frees the connection to be 01077 * reused. For non-pooled connections, it does nothing. */ 01078 obj->used = 0; 01079 if (obj->txf) { 01080 /* Prevent recursion -- transaction is already closed out. */ 01081 obj->txf->obj = NULL; 01082 obj->txf = release_transaction(obj->txf); 01083 } 01084 ao2_ref(obj, -1); 01085 }
static void odbc_txn_free | ( | void * | data | ) | [static] |
Definition at line 341 of file res_odbc.c.
References ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, odbc_class::list, and release_transaction().
00342 { 00343 struct odbc_txn_frame *tx; 00344 AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata; 00345 00346 ast_debug(2, "odbc_txn_free(%p) called\n", vdata); 00347 00348 AST_LIST_LOCK(oldlist); 00349 while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) { 00350 release_transaction(tx); 00351 } 00352 AST_LIST_UNLOCK(oldlist); 00353 AST_LIST_HEAD_DESTROY(oldlist); 00354 ast_free(oldlist); 00355 }
static struct odbc_txn_frame* release_transaction | ( | struct odbc_txn_frame * | tx | ) | [static] |
Definition at line 305 of file res_odbc.c.
References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_datastore::data, odbc_class::list, odbc_txn_frame::obj, odbc_release_obj2(), odbc_txn_frame::owner, odbc_obj::tx, odbc_obj::txf, and txn_info.
Referenced by odbc_txn_free().
00306 { 00307 if (!tx) { 00308 return NULL; 00309 } 00310 00311 ast_debug(2, "release_transaction(%p) called (tx->obj = %p, tx->obj->txf = %p)\n", tx, tx->obj, tx->obj ? tx->obj->txf : NULL); 00312 00313 /* If we have an owner, disassociate */ 00314 if (tx->owner) { 00315 struct ast_datastore *txn_store; 00316 AST_LIST_HEAD(, odbc_txn_frame) *oldlist; 00317 00318 ast_channel_lock(tx->owner); 00319 if ((txn_store = ast_channel_datastore_find(tx->owner, &txn_info, NULL))) { 00320 oldlist = txn_store->data; 00321 AST_LIST_LOCK(oldlist); 00322 AST_LIST_REMOVE(oldlist, tx, list); 00323 AST_LIST_UNLOCK(oldlist); 00324 } 00325 ast_channel_unlock(tx->owner); 00326 tx->owner = NULL; 00327 } 00328 00329 if (tx->obj) { 00330 /* If we have any uncommitted transactions, they are handled when we release the object */ 00331 struct odbc_obj *obj = tx->obj; 00332 /* Prevent recursion during destruction */ 00333 tx->obj->txf = NULL; 00334 tx->obj = NULL; 00335 odbc_release_obj2(obj, tx); 00336 } 00337 ast_free(tx); 00338 return NULL; 00339 }
static int reload | ( | void | ) | [static] |
Definition at line 1745 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.
01746 { 01747 struct odbc_cache_tables *table; 01748 struct odbc_class *class; 01749 struct odbc_obj *current; 01750 struct ao2_iterator aoi = ao2_iterator_init(class_container, 0); 01751 01752 /* First, mark all to be purged */ 01753 while ((class = ao2_iterator_next(&aoi))) { 01754 class->delme = 1; 01755 ao2_ref(class, -1); 01756 } 01757 ao2_iterator_destroy(&aoi); 01758 01759 load_odbc_config(); 01760 01761 /* Purge remaining classes */ 01762 01763 /* Note on how this works; this is a case of circular references, so we 01764 * explicitly do NOT want to use a callback here (or we wind up in 01765 * recursive hell). 01766 * 01767 * 1. Iterate through all the classes. Note that the classes will currently 01768 * contain two classes of the same name, one of which is marked delme and 01769 * will be purged when all remaining objects of the class are released, and 01770 * the other, which was created above when we re-parsed the config file. 01771 * 2. On each class, there is a reference held by the master container and 01772 * a reference held by each connection object. There are two cases for 01773 * destruction of the class, noted below. However, in all cases, all O-refs 01774 * (references to objects) will first be freed, which will cause the C-refs 01775 * (references to classes) to be decremented (but never to 0, because the 01776 * class container still has a reference). 01777 * a) If the class has outstanding objects, the C-ref by the class 01778 * container will then be freed, which leaves only C-refs by any 01779 * outstanding objects. When the final outstanding object is released 01780 * (O-refs held by applications and dialplan functions), it will in turn 01781 * free the final C-ref, causing class destruction. 01782 * b) If the class has no outstanding objects, when the class container 01783 * removes the final C-ref, the class will be destroyed. 01784 */ 01785 aoi = ao2_iterator_init(class_container, 0); 01786 while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */ 01787 if (class->delme) { 01788 struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0); 01789 while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */ 01790 ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */ 01791 ao2_ref(current, -1); /* O-ref-- (by iterator) */ 01792 /* At this point, either 01793 * a) there's an outstanding O-ref, or 01794 * b) the object has already been destroyed. 01795 */ 01796 } 01797 ao2_iterator_destroy(&aoi2); 01798 ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */ 01799 /* At this point, either 01800 * a) there's an outstanding O-ref, which holds an outstanding C-ref, or 01801 * b) the last remaining C-ref is held by the iterator, which will be 01802 * destroyed in the next step. 01803 */ 01804 } 01805 ao2_ref(class, -1); /* C-ref-- (by iterator) */ 01806 } 01807 ao2_iterator_destroy(&aoi); 01808 01809 /* Empty the cache; it will get rebuilt the next time the tables are needed. */ 01810 AST_RWLIST_WRLOCK(&odbc_tables); 01811 while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) { 01812 destroy_table_cache(table); 01813 } 01814 AST_RWLIST_UNLOCK(&odbc_tables); 01815 01816 return 0; 01817 }
static int rollback_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1135 of file res_odbc.c.
References ast_log(), ast_str_append(), ast_str_buffer(), ast_str_reset(), ast_str_strlen(), ast_str_thread_get(), ast_strlen_zero(), odbc_obj::con, errors_buf, find_transaction(), LOG_WARNING, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().
Referenced by load_module().
01136 { 01137 struct odbc_txn_frame *tx; 01138 SQLINTEGER nativeerror=0, numfields=0; 01139 SQLSMALLINT diagbytes=0, i; 01140 unsigned char state[10], diagnostic[256]; 01141 01142 if (ast_strlen_zero(data)) { 01143 tx = find_transaction(chan, NULL, NULL, 1); 01144 } else { 01145 tx = find_transaction(chan, NULL, data, 0); 01146 } 01147 01148 pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK"); 01149 01150 if (tx) { 01151 if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) { 01152 struct ast_str *errors = ast_str_thread_get(&errors_buf, 16); 01153 ast_str_reset(errors); 01154 01155 /* Handle possible transaction commit failure */ 01156 SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01157 for (i = 0; i < numfields; i++) { 01158 SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01159 ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state); 01160 ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic); 01161 if (i > 10) { 01162 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01163 break; 01164 } 01165 } 01166 pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors)); 01167 } 01168 } 01169 return 0; 01170 }
static int text2isolation | ( | const char * | txt | ) | [static] |
Definition at line 203 of file res_odbc.c.
Referenced by acf_transaction_write().
00204 { 00205 if (strncasecmp(txt, "read_", 5) == 0) { 00206 if (strncasecmp(txt + 5, "c", 1) == 0) { 00207 return SQL_TXN_READ_COMMITTED; 00208 } else if (strncasecmp(txt + 5, "u", 1) == 0) { 00209 return SQL_TXN_READ_UNCOMMITTED; 00210 } else { 00211 return 0; 00212 } 00213 } else if (strncasecmp(txt, "ser", 3) == 0) { 00214 return SQL_TXN_SERIALIZABLE; 00215 } else if (strncasecmp(txt, "rep", 3) == 0) { 00216 return SQL_TXN_REPEATABLE_READ; 00217 } else { 00218 return 0; 00219 } 00220 }
static int unload_module | ( | void | ) | [static] |
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, } [static] |
Definition at line 1845 of file res_odbc.c.
const char* const app_commit = "ODBC_Commit" [static] |
Definition at line 1654 of file res_odbc.c.
const char* const app_rollback = "ODBC_Rollback" [static] |
Definition at line 1655 of file res_odbc.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1845 of file res_odbc.c.
struct ao2_container* class_container [static] |
Definition at line 143 of file res_odbc.c.
Referenced by _ast_odbc_request_obj2(), data_odbc_provider_handler(), 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 1002 of file res_odbc.c.
Referenced by load_module().
struct ast_threadstorage errors_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_errors_buf , .custom_init = NULL , } [static] |
struct ast_custom_function odbc_function [static] |
Initial value:
{ .name = "ODBC", .read = acf_transaction_read, .write = acf_transaction_write, }
Definition at line 1648 of file res_odbc.c.
Referenced by load_module().
struct ast_data_handler odbc_provider [static] |
Initial value:
{ .version = AST_DATA_HANDLER_VERSION, .get = data_odbc_provider_handler }
Definition at line 1736 of file res_odbc.c.
struct ast_data_entry odbc_providers[] [static] |
Initial value:
{ AST_DATA_ENTRY("/asterisk/res/odbc", &odbc_provider), }
Definition at line 1741 of file res_odbc.c.
Referenced by load_module().
struct ast_datastore_info txn_info [static] |
Initial value:
{ .type = "ODBC_Transaction", .destroy = odbc_txn_free, }
Definition at line 155 of file res_odbc.c.
Referenced by ast_odbc_retrieve_transaction_obj(), find_transaction(), mark_transaction_active(), and release_transaction().