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