res_odbc.c File Reference

ODBC resource manager. More...

#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/res_odbc.h"
#include "asterisk/time.h"
#include "asterisk/astobj2.h"
#include "asterisk/app.h"
#include "asterisk/strings.h"
#include "asterisk/threadstorage.h"
#include "asterisk/data.h"

Include dependency graph for res_odbc.c:

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 __fini_odbc_tables (void)
static void __init_errors_buf (void)
static void __init_odbc_tables (void)
static void __reg_module (void)
static void __unreg_module (void)
struct odbc_obj_ast_odbc_request_obj (const char *name, int check, const char *file, const char *function, int lineno)
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.
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)
static int aoro2_obj_notx_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.
struct odbc_cache_columnsast_odbc_find_column (struct odbc_cache_tables *table, const char *colname)
 Find a column entry within a cached table structure.
struct odbc_cache_tablesast_odbc_find_table (const char *database, const char *tablename)
 Find or create an entry describing the table specified.
SQLHSTMT ast_odbc_prepare_and_execute (struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
 Prepares, executes, and returns the resulting statement handle.
void ast_odbc_release_obj (struct odbc_obj *obj)
 Releases an ODBC object previously allocated by ast_odbc_request_obj().
struct odbc_objast_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_framefind_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)
 Load the module.
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_framerelease_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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .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_infoast_module_info = &__mod_info
static struct ao2_containerclass_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


Detailed Description

ODBC resource manager.

Author:
Mark Spencer <markster@digium.com>

Anthony Minessale II <anthmct@yahoo.com>

Tilghman Lesher <tilghman@digium.com>

Definition in file res_odbc.c.


Define Documentation

#define DATA_EXPORT_ODBC_CLASS ( MEMBER   ) 

Definition at line 187 of file res_odbc.c.

#define EOR_TX   (void *)(long)3

Definition at line 1207 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().

#define NO_TX   (void *)(long)2

Definition at line 1206 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().

#define USE_TX   (void *)(long)1

Definition at line 1205 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().


Function Documentation

static void __fini_odbc_tables ( void   )  [static]

Definition at line 155 of file res_odbc.c.

00165 {

static void __init_errors_buf ( void   )  [static]

Definition at line 163 of file res_odbc.c.

00165 {

static void __init_odbc_tables ( void   )  [static]

Definition at line 155 of file res_odbc.c.

00165 {

static void __reg_module ( void   )  [static]

Definition at line 1913 of file res_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 1913 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 
) [read]

Definition at line 1440 of file res_odbc.c.

References _ast_odbc_request_obj2(), and RES_ODBC_SANITY_CHECK.

01441 {
01442    struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
01443    return _ast_odbc_request_obj2(name, flags, file, function, lineno);
01444 }

struct odbc_obj* _ast_odbc_request_obj2 ( const char *  name,
struct ast_flags  flags,
const char *  file,
const char *  function,
int  lineno 
) [read]

Retrieves a connected ODBC object.

Parameters:
name The name of the ODBC class for which a connection is needed.
flags One or more of the following flags:
  • RES_ODBC_SANITY_CHECK Whether to ensure that a connection is valid before returning the handle. Usually unnecessary.
  • RES_ODBC_INDEPENDENT_CONNECTION Return a handle which is independent from all others. Usually used when starting a transaction.
  • RES_ODBC_CONNECTED Only return a connected handle. Intended for use with peers which use idlecheck, which are checked periodically for reachability.
file,function,lineno 
Returns:
ODBC object
Return values:
NULL if there is no connection available with the requested name.
Connection classes may, in fact, contain multiple connection handles. If the connection is pooled, then each connection will be dedicated to the thread which requests it. Note that all connections should be released when the thread is done by calling ast_odbc_release_obj(), below.

Definition at line 1234 of file res_odbc.c.

References ao2_alloc, ao2_callback, ao2_link, ao2_lock, ao2_ref, ao2_unlock, aoro2_class_cb(), aoro2_obj_cb(), aoro2_obj_notx_cb(), ast_assert, ast_atomic_fetchadd_int(), ast_copy_string(), ast_debug, ast_log, ast_odbc_sanity_check(), ast_test_flag, ast_tvdiff_sec(), ast_tvnow(), class_container, odbc_obj::con, odbc_class::count, EOR_TX, odbc_class::idlecheck, odbc_class::isolation, odbc_class::last_negative_connect, odbc_obj::last_used, LOG_WARNING, odbc_class::negative_connection_cache, NO_TX, NULL, odbc_class::obj_container, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), odbc_obj::parent, RES_ODBC_CONNECTED, RES_ODBC_INDEPENDENT_CONNECTION, RES_ODBC_SANITY_CHECK, odbc_obj::up, USE_TX, and odbc_obj::used.

Referenced by _ast_odbc_request_obj().

01235 {
01236    struct odbc_obj *obj = NULL;
01237    struct odbc_class *class;
01238    SQLINTEGER nativeerror=0, numfields=0;
01239    SQLSMALLINT diagbytes=0, i;
01240    unsigned char state[10], diagnostic[256];
01241 
01242    if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
01243       ast_debug(1, "Class '%s' not found!\n", name);
01244       return NULL;
01245    }
01246 
01247    ast_assert(ao2_ref(class, 0) > 1);
01248 
01249    if (class->haspool) {
01250       /* Recycle connections before building another */
01251       obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX);
01252 
01253       if (obj) {
01254          ast_assert(ao2_ref(obj, 0) > 1);
01255       }
01256       if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit) &&
01257             (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) {
01258          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
01259          if (!obj) {
01260             class->count--;
01261             ao2_ref(class, -1);
01262             ast_debug(3, "Unable to allocate object\n");
01263             ast_atomic_fetchadd_int(&class->count, -1);
01264             return NULL;
01265          }
01266          ast_assert(ao2_ref(obj, 0) == 1);
01267          /* obj inherits the outstanding reference to class */
01268          obj->parent = class;
01269          class = NULL;
01270          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01271             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01272             ast_assert(ao2_ref(obj->parent, 0) > 0);
01273             /* Because it was never within the container, we have to manually decrement the count here */
01274             ast_atomic_fetchadd_int(&obj->parent->count, -1);
01275             ao2_ref(obj, -1);
01276             obj = NULL;
01277          } else {
01278             obj->used = 1;
01279             ao2_link(obj->parent->obj_container, obj);
01280          }
01281       } else {
01282          /* If construction fails due to the limit (or negative timecache), reverse our increment. */
01283          if (!obj) {
01284             ast_atomic_fetchadd_int(&class->count, -1);
01285          }
01286          /* Object is not constructed, so delete outstanding reference to class. */
01287          ao2_ref(class, -1);
01288          class = NULL;
01289       }
01290 
01291       if (!obj) {
01292          return NULL;
01293       }
01294 
01295       ao2_lock(obj);
01296 
01297       if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
01298          /* Ensure this connection has autocommit turned off. */
01299          if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
01300             SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01301             for (i = 0; i < numfields; i++) {
01302                SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01303                ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01304                if (i > 10) {
01305                   ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01306                   break;
01307                }
01308             }
01309          }
01310       }
01311    } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
01312       /* Non-pooled connections -- but must use a separate connection handle */
01313       if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) {
01314          ast_debug(1, "Object not found\n");
01315          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
01316          if (!obj) {
01317             ao2_ref(class, -1);
01318             ast_debug(3, "Unable to allocate object\n");
01319             return NULL;
01320          }
01321          /* obj inherits the outstanding reference to class */
01322          obj->parent = class;
01323          class = NULL;
01324          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01325             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01326             ao2_ref(obj, -1);
01327             obj = NULL;
01328          } else {
01329             obj->used = 1;
01330             ao2_link(obj->parent->obj_container, obj);
01331             ast_atomic_fetchadd_int(&obj->parent->count, +1);
01332          }
01333       }
01334 
01335       if (!obj) {
01336          return NULL;
01337       }
01338 
01339       ao2_lock(obj);
01340 
01341       if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
01342          SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01343          for (i = 0; i < numfields; i++) {
01344             SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01345             ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01346             if (i > 10) {
01347                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01348                break;
01349             }
01350          }
01351       }
01352    } else {
01353       /* Non-pooled connection: multiple modules can use the same connection. */
01354       if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_notx_cb, NO_TX))) {
01355          /* Object is not constructed, so delete outstanding reference to class. */
01356          ast_assert(ao2_ref(class, 0) > 1);
01357          ao2_ref(class, -1);
01358          class = NULL;
01359       } else {
01360          /* No entry: build one */
01361          if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) {
01362             ast_assert(ao2_ref(class, 0) > 1);
01363             ao2_ref(class, -1);
01364             ast_debug(3, "Unable to allocate object\n");
01365             return NULL;
01366          }
01367          /* obj inherits the outstanding reference to class */
01368          obj->parent = class;
01369          class = NULL;
01370          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01371             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01372             ao2_ref(obj, -1);
01373             obj = NULL;
01374          } else {
01375             ao2_link(obj->parent->obj_container, obj);
01376             ast_assert(ao2_ref(obj, 0) > 1);
01377          }
01378       }
01379 
01380       if (!obj) {
01381          return NULL;
01382       }
01383 
01384       ao2_lock(obj);
01385 
01386       if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
01387          SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01388          for (i = 0; i < numfields; i++) {
01389             SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01390             ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01391             if (i > 10) {
01392                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01393                break;
01394             }
01395          }
01396       }
01397    }
01398 
01399    ast_assert(obj != NULL);
01400 
01401    /* Set the isolation property */
01402    if (SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
01403       SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01404       for (i = 0; i < numfields; i++) {
01405          SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01406          ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
01407          if (i > 10) {
01408             ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01409             break;
01410          }
01411       }
01412    }
01413 
01414    if (ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) {
01415       /* Check if this connection qualifies for reconnection, with negative connection cache time */
01416       if (time(NULL) > obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec) {
01417          odbc_obj_connect(obj);
01418       }
01419    } else if (ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
01420       ast_odbc_sanity_check(obj);
01421    } else if (obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) {
01422       odbc_obj_connect(obj);
01423    }
01424 
01425 #ifdef DEBUG_THREADS
01426    ast_copy_string(obj->file, file, sizeof(obj->file));
01427    ast_copy_string(obj->function, function, sizeof(obj->function));
01428    obj->lineno = lineno;
01429 #endif
01430 
01431    /* We had it locked because of the obj_connects we see here. */
01432    ao2_unlock(obj);
01433 
01434    ast_assert(class == NULL);
01435 
01436    ast_assert(ao2_ref(obj, 0) > 1);
01437    return obj;
01438 }

static int acf_transaction_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 1572 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(), odbc_txn_frame::name, and NULL.

01573 {
01574    AST_DECLARE_APP_ARGS(args,
01575       AST_APP_ARG(property);
01576       AST_APP_ARG(opt);
01577    );
01578    struct odbc_txn_frame *tx;
01579 
01580    AST_STANDARD_APP_ARGS(args, data);
01581    if (strcasecmp(args.property, "transaction") == 0) {
01582       if ((tx = find_transaction(chan, NULL, NULL, 1))) {
01583          ast_copy_string(buf, tx->name, len);
01584          return 0;
01585       }
01586    } else if (strcasecmp(args.property, "isolation") == 0) {
01587       if (!ast_strlen_zero(args.opt)) {
01588          tx = find_transaction(chan, NULL, args.opt, 0);
01589       } else {
01590          tx = find_transaction(chan, NULL, NULL, 1);
01591       }
01592       if (tx) {
01593          ast_copy_string(buf, isolation2text(tx->isolation), len);
01594          return 0;
01595       }
01596    } else if (strcasecmp(args.property, "forcecommit") == 0) {
01597       if (!ast_strlen_zero(args.opt)) {
01598          tx = find_transaction(chan, NULL, args.opt, 0);
01599       } else {
01600          tx = find_transaction(chan, NULL, NULL, 1);
01601       }
01602       if (tx) {
01603          ast_copy_string(buf, tx->forcecommit ? "1" : "0", len);
01604          return 0;
01605       }
01606    }
01607    return -1;
01608 }

static int acf_transaction_write ( struct ast_channel chan,
const char *  cmd,
char *  s,
const char *  value 
) [static]

Definition at line 1610 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(), odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, LOG_ERROR, LOG_WARNING, mark_transaction_active(), NULL, odbc_txn_frame::obj, pbx_builtin_setvar_helper(), RES_ODBC_INDEPENDENT_CONNECTION, S_OR, text2isolation(), and odbc_obj::tx.

01611 {
01612    AST_DECLARE_APP_ARGS(args,
01613       AST_APP_ARG(property);
01614       AST_APP_ARG(opt);
01615    );
01616    struct odbc_txn_frame *tx;
01617    SQLINTEGER nativeerror=0, numfields=0;
01618    SQLSMALLINT diagbytes=0, i;
01619    unsigned char state[10], diagnostic[256];
01620 
01621    AST_STANDARD_APP_ARGS(args, s);
01622    if (strcasecmp(args.property, "transaction") == 0) {
01623       /* Set active transaction */
01624       struct odbc_obj *obj;
01625       if ((tx = find_transaction(chan, NULL, value, 0))) {
01626          mark_transaction_active(chan, tx);
01627       } else {
01628          /* No such transaction, create one */
01629          struct ast_flags flags = { RES_ODBC_INDEPENDENT_CONNECTION };
01630          if (ast_strlen_zero(args.opt) || !(obj = ast_odbc_request_obj2(args.opt, flags))) {
01631             ast_log(LOG_ERROR, "Could not create transaction: invalid database specification '%s'\n", S_OR(args.opt, ""));
01632             pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_DB");
01633             return -1;
01634          }
01635          if (!find_transaction(chan, obj, value, 0)) {
01636             pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
01637             return -1;
01638          }
01639          obj->tx = 1;
01640       }
01641       pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
01642       return 0;
01643    } else if (strcasecmp(args.property, "forcecommit") == 0) {
01644       /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */
01645       if (ast_strlen_zero(args.opt)) {
01646          tx = find_transaction(chan, NULL, NULL, 1);
01647       } else {
01648          tx = find_transaction(chan, NULL, args.opt, 0);
01649       }
01650       if (!tx) {
01651          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
01652          return -1;
01653       }
01654       if (ast_true(value)) {
01655          tx->forcecommit = 1;
01656       } else if (ast_false(value)) {
01657          tx->forcecommit = 0;
01658       } else {
01659          ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, ""));
01660          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
01661          return -1;
01662       }
01663 
01664       pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
01665       return 0;
01666    } else if (strcasecmp(args.property, "isolation") == 0) {
01667       /* How do uncommitted transactions affect reads? */
01668       int isolation = text2isolation(value);
01669       if (ast_strlen_zero(args.opt)) {
01670          tx = find_transaction(chan, NULL, NULL, 1);
01671       } else {
01672          tx = find_transaction(chan, NULL, args.opt, 0);
01673       }
01674       if (!tx) {
01675          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
01676          return -1;
01677       }
01678       if (isolation == 0) {
01679          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
01680          ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, ""));
01681       } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) {
01682          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR");
01683          SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01684          for (i = 0; i < numfields; i++) {
01685             SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01686             ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
01687             if (i > 10) {
01688                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01689                break;
01690             }
01691          }
01692       } else {
01693          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
01694          tx->isolation = isolation;
01695       }
01696       return 0;
01697    } else {
01698       ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property);
01699       return -1;
01700    }
01701 }

static int aoro2_class_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1195 of file res_odbc.c.

References CMP_MATCH, and CMP_STOP.

Referenced by _ast_odbc_request_obj2().

01196 {
01197    struct odbc_class *class = obj;
01198    char *name = arg;
01199    if (!strcmp(class->name, name) && !class->delme) {
01200       return CMP_MATCH | CMP_STOP;
01201    }
01202    return 0;
01203 }

static int aoro2_obj_cb ( void *  vobj,
void *  arg,
int  flags 
) [static]

Definition at line 1209 of file res_odbc.c.

References ao2_lock, ao2_unlock, CMP_MATCH, CMP_STOP, EOR_TX, NO_TX, odbc_obj::tx, USE_TX, and odbc_obj::used.

Referenced by _ast_odbc_request_obj2().

01210 {
01211    struct odbc_obj *obj = vobj;
01212    ao2_lock(obj);
01213    if ((arg == NO_TX && !obj->tx) || (arg == EOR_TX && !obj->used) || (arg == USE_TX && obj->tx && !obj->used)) {
01214       obj->used = 1;
01215       ao2_unlock(obj);
01216       return CMP_MATCH | CMP_STOP;
01217    }
01218    ao2_unlock(obj);
01219    return 0;
01220 }

static int aoro2_obj_notx_cb ( void *  vobj,
void *  arg,
int  flags 
) [static]

Definition at line 1225 of file res_odbc.c.

References CMP_MATCH, CMP_STOP, and odbc_obj::tx.

Referenced by _ast_odbc_request_obj2().

01226 {
01227    struct odbc_obj *obj = vobj;
01228    if (!obj->tx) {
01229       return CMP_MATCH | CMP_STOP;
01230    }
01231    return 0;
01232 }

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.

Parameters:
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 720 of file res_odbc.c.

References ast_str_buffer(), ast_str_make_space(), ast_str_size(), and ast_str_update().

Referenced by acf_odbc_read(), and cli_odbc_read().

00721 {
00722    SQLRETURN res;
00723 
00724    if (pmaxlen == 0) {
00725       if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
00726          ast_str_make_space(buf, *StrLen_or_Ind + 1);
00727       }
00728    } else if (pmaxlen > 0) {
00729       ast_str_make_space(buf, pmaxlen);
00730    }
00731    res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
00732    ast_str_update(*buf);
00733 
00734    return res;
00735 }

int ast_odbc_backslash_is_escape ( struct odbc_obj obj  ) 

Checks if the database natively supports backslash as an escape character.

Parameters:
obj The ODBC object
Returns:
Returns 1 if backslash is a native escape character, 0 if an ESCAPE clause is needed to support '\'

Definition at line 1116 of file res_odbc.c.

References odbc_class::backslash_is_escape, and odbc_obj::parent.

Referenced by odbc_log(), realtime_multi_odbc(), and realtime_odbc().

01117 {
01118    return obj->parent->backslash_is_escape;
01119 }

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.

Parameters:
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
Return values:
0 if the cache entry was removed, or -1 if no matching entry was found.
Since:
1.6.1

Definition at line 579 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(), and odbc_cache_tables::table.

Referenced by unload_odbc().

00580 {
00581    struct odbc_cache_tables *tableptr;
00582 
00583    AST_RWLIST_WRLOCK(&odbc_tables);
00584    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
00585       if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
00586          AST_LIST_REMOVE_CURRENT(list);
00587          destroy_table_cache(tableptr);
00588          break;
00589       }
00590    }
00591    AST_RWLIST_TRAVERSE_SAFE_END
00592    AST_RWLIST_UNLOCK(&odbc_tables);
00593    return tableptr ? 0 : -1;
00594 }

SQLHSTMT ast_odbc_direct_execute ( struct odbc_obj obj,
SQLHSTMT(*)(struct odbc_obj *obj, void *data)  exec_cb,
void *  data 
)

Executes an non prepared statement and returns the resulting statement handle.

Parameters:
obj The ODBC object
exec_cb A function callback, which, when called, should return a statement handle with result columns bound.
data A parameter to be passed to the exec_cb parameter function, indicating which statement handle is to be prepared.
Return values:
a statement handle
NULL on error

Definition at line 596 of file res_odbc.c.

References ao2_lock, ao2_unlock, ast_log, ast_odbc_sanity_check(), odbc_class::dsn, LOG_WARNING, odbc_class::name, odbc_obj::parent, and odbc_obj::tx.

Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), cli_odbc_write(), and odbc_log().

00597 {
00598    int attempt;
00599    SQLHSTMT stmt;
00600 
00601    ao2_lock(obj);
00602 
00603    for (attempt = 0; attempt < 2; attempt++) {
00604       stmt = exec_cb(obj, data);
00605 
00606       if (stmt) {
00607          break;
00608       } else if (obj->tx) {
00609          ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n");
00610          break;
00611       } else if (attempt == 0) {
00612          ast_log(LOG_WARNING, "SQL Execute error! Verifying connection to %s [%s]...\n", obj->parent->name, obj->parent->dsn);
00613       }
00614       if (!ast_odbc_sanity_check(obj)) {
00615          break;
00616       }
00617    }
00618 
00619    ao2_unlock(obj);
00620 
00621    return stmt;
00622 }

struct odbc_cache_columns* ast_odbc_find_column ( struct odbc_cache_tables table,
const char *  colname 
) [read]

Find a column entry within a cached table structure.

Parameters:
table Cached table structure, as returned from ast_odbc_find_table()
colname The column name requested
Return values:
A structure describing the column type, or NULL, if the column is not found.
Since:
1.6.1

Definition at line 568 of file res_odbc.c.

References AST_RWLIST_TRAVERSE, odbc_cache_tables::columns, odbc_cache_columns::name, and NULL.

Referenced by update2_prepare(), and update_odbc().

00569 {
00570    struct odbc_cache_columns *col;
00571    AST_RWLIST_TRAVERSE(&table->columns, col, list) {
00572       if (strcasecmp(col->name, colname) == 0) {
00573          return col;
00574       }
00575    }
00576    return NULL;
00577 }

struct odbc_cache_tables* ast_odbc_find_table ( const char *  database,
const char *  tablename 
) [read]

Find or create an entry describing the table specified.

Parameters:
database Name of an ODBC class on which to query the table
tablename Tablename to describe
Return values:
A structure describing the table layout, or NULL, if the table is not found or another error occurs. When a structure is returned, the contained columns list will be rdlock'ed, to ensure that it will be retained in memory.
Since:
1.6.1

Definition at line 456 of file res_odbc.c.

References ao2_lock, ao2_unlock, ast_calloc, ast_debug, 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, odbc_cache_tables::columns, odbc_obj::con, odbc_cache_tables::connection, odbc_cache_columns::decimals, destroy_table_cache(), error(), LOG_ERROR, LOG_WARNING, odbc_cache_columns::name, NULL, odbc_cache_columns::nullable, odbc_cache_columns::octetlen, odbc_cache_columns::radix, odbc_cache_columns::size, odbc_cache_tables::table, and odbc_cache_columns::type.

Referenced by require_odbc(), update2_prepare(), and update_odbc().

00457 {
00458    struct odbc_cache_tables *tableptr;
00459    struct odbc_cache_columns *entry;
00460    char columnname[80];
00461    SQLLEN sqlptr;
00462    SQLHSTMT stmt = NULL;
00463    int res = 0, error = 0, try = 0;
00464    struct odbc_obj *obj;
00465 
00466    AST_RWLIST_RDLOCK(&odbc_tables);
00467    AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) {
00468       if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
00469          break;
00470       }
00471    }
00472    if (tableptr) {
00473       AST_RWLIST_RDLOCK(&tableptr->columns);
00474       AST_RWLIST_UNLOCK(&odbc_tables);
00475       return tableptr;
00476    }
00477 
00478    if (!(obj = ast_odbc_request_obj(database, 0))) {
00479       ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
00480       AST_RWLIST_UNLOCK(&odbc_tables);
00481       return NULL;
00482    }
00483 
00484    /* Table structure not already cached; build it now. */
00485    ao2_lock(obj);
00486    do {
00487       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00488       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00489          if (try == 0) {
00490             try = 1;
00491             ast_odbc_sanity_check(obj);
00492             continue;
00493          }
00494          ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
00495          break;
00496       }
00497 
00498       res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS);
00499       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00500          if (try == 0) {
00501             try = 1;
00502             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00503             ast_odbc_sanity_check(obj);
00504             continue;
00505          }
00506          ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
00507          break;
00508       }
00509 
00510       if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
00511          ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
00512          break;
00513       }
00514 
00515       tableptr->connection = (char *)tableptr + sizeof(*tableptr);
00516       tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1;
00517       strcpy(tableptr->connection, database); /* SAFE */
00518       strcpy(tableptr->table, tablename); /* SAFE */
00519       AST_RWLIST_HEAD_INIT(&(tableptr->columns));
00520 
00521       while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
00522          SQLGetData(stmt,  4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
00523 
00524          if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) {
00525             ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
00526             error = 1;
00527             break;
00528          }
00529          entry->name = (char *)entry + sizeof(*entry);
00530          strcpy(entry->name, columnname);
00531 
00532          SQLGetData(stmt,  5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
00533          SQLGetData(stmt,  7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
00534          SQLGetData(stmt,  9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
00535          SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
00536          SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
00537          SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
00538 
00539          /* Specification states that the octenlen should be the maximum number of bytes
00540           * returned in a char or binary column, but it seems that some drivers just set
00541           * it to NULL. (Bad Postgres! No biscuit!) */
00542          if (entry->octetlen == 0) {
00543             entry->octetlen = entry->size;
00544          }
00545 
00546          ast_debug(3, "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);
00547          /* Insert column info into column list */
00548          AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
00549       }
00550       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00551 
00552       AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
00553       AST_RWLIST_RDLOCK(&(tableptr->columns));
00554       break;
00555    } while (1);
00556    ao2_unlock(obj);
00557 
00558    AST_RWLIST_UNLOCK(&odbc_tables);
00559 
00560    if (error) {
00561       destroy_table_cache(tableptr);
00562       tableptr = NULL;
00563    }
00564    ast_odbc_release_obj(obj);
00565    return tableptr;
00566 }

SQLHSTMT ast_odbc_prepare_and_execute ( struct odbc_obj obj,
SQLHSTMT(*)(struct odbc_obj *obj, void *data)  prepare_cb,
void *  data 
)

Prepares, executes, and returns the resulting statement handle.

Parameters:
obj The ODBC object
prepare_cb A function callback, which, when called, should return a statement handle prepared, with any necessary parameters or result columns bound.
data A parameter to be passed to the prepare_cb parameter function, indicating which statement handle is to be prepared.
Return values:
a statement handle
NULL on error

Definition at line 624 of file res_odbc.c.

References ao2_lock, ao2_unlock, ast_log, ast_odbc_sanity_check(), ast_tvnow(), odbc_class::dsn, odbc_obj::last_used, LOG_WARNING, odbc_class::name, NULL, odbc_obj::parent, odbc_obj::tx, and odbc_obj::up.

Referenced by config_odbc(), destroy_odbc(), odbc_log(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().

00625 {
00626    int res = 0, i, attempt;
00627    SQLINTEGER nativeerror=0, numfields=0;
00628    SQLSMALLINT diagbytes=0;
00629    unsigned char state[10], diagnostic[256];
00630    SQLHSTMT stmt;
00631 
00632    ao2_lock(obj);
00633 
00634    for (attempt = 0; attempt < 2; attempt++) {
00635       /* This prepare callback may do more than just prepare -- it may also
00636        * bind parameters, bind results, etc.  The real key, here, is that
00637        * when we disconnect, all handles become invalid for most databases.
00638        * We must therefore redo everything when we establish a new
00639        * connection. */
00640       stmt = prepare_cb(obj, data);
00641 
00642       if (stmt) {
00643          res = SQLExecute(stmt);
00644          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00645             if (res == SQL_ERROR) {
00646                SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00647                for (i = 0; i < numfields; i++) {
00648                   SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00649                   ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00650                   if (i > 10) {
00651                      ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00652                      break;
00653                   }
00654                }
00655             }
00656 
00657             if (obj->tx) {
00658                ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n");
00659                break;
00660             } else {
00661                ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn);
00662                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00663                stmt = NULL;
00664 
00665                obj->up = 0;
00666                /*
00667                 * While this isn't the best way to try to correct an error, this won't automatically
00668                 * fail when the statement handle invalidates.
00669                 */
00670                if (!ast_odbc_sanity_check(obj)) {
00671                   break;
00672                }
00673                continue;
00674             }
00675          } else {
00676             obj->last_used = ast_tvnow();
00677          }
00678          break;
00679       } else if (attempt == 0) {
00680          ast_odbc_sanity_check(obj);
00681       }
00682    }
00683 
00684    ao2_unlock(obj);
00685 
00686    return stmt;
00687 }

void ast_odbc_release_obj ( struct odbc_obj obj  ) 

Releases an ODBC object previously allocated by ast_odbc_request_obj().

Parameters:
obj The ODBC object

Definition at line 1110 of file res_odbc.c.

References find_transaction(), NULL, and odbc_release_obj2().

Referenced by acf_odbc_read(), acf_odbc_write(), ast_odbc_find_table(), cli_odbc_read(), cli_odbc_write(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().

01111 {
01112    struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
01113    odbc_release_obj2(obj, tx);
01114 }

struct odbc_obj* ast_odbc_retrieve_transaction_obj ( struct ast_channel chan,
const char *  objname 
) [read]

Retrieve a stored ODBC object, if a transaction has been started.

Parameters:
chan Channel associated with the transaction.
objname Name of the database handle. This name corresponds to the name passed to
See also:
ast_odbc_request_obj2 (or formerly, to ast_odbc_request_obj). Note that the existence of this parameter name explicitly allows for multiple transactions to be open at once, albeit to different databases.
Return values:
A stored ODBC object, if a transaction was already started.
NULL,if no transaction yet exists.

Definition at line 1446 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_class::name, NULL, odbc_txn_frame::obj, odbc_obj::parent, and txn_info.

Referenced by acf_odbc_write().

01447 {
01448    struct ast_datastore *txn_store;
01449    AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
01450    struct odbc_txn_frame *txn = NULL;
01451 
01452    if (!chan) {
01453       /* No channel == no transaction */
01454       return NULL;
01455    }
01456 
01457    ast_channel_lock(chan);
01458    if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
01459       oldlist = txn_store->data;
01460    } else {
01461       ast_channel_unlock(chan);
01462       return NULL;
01463    }
01464 
01465    AST_LIST_LOCK(oldlist);
01466    ast_channel_unlock(chan);
01467 
01468    AST_LIST_TRAVERSE(oldlist, txn, list) {
01469       if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) {
01470          AST_LIST_UNLOCK(oldlist);
01471          return txn->obj;
01472       }
01473    }
01474    AST_LIST_UNLOCK(oldlist);
01475    return NULL;
01476 }

int ast_odbc_sanity_check ( struct odbc_obj obj  ) 

Checks an ODBC object to ensure it is still connected.

Parameters:
obj The ODBC object
Return values:
0 if connected
-1 otherwise.

Definition at line 737 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_request_obj2(), ast_odbc_direct_execute(), ast_odbc_find_table(), ast_odbc_prepare_and_execute(), data_odbc_provider_handler(), and handle_cli_odbc_show().

00738 {
00739    char *test_sql = "select 1";
00740    SQLHSTMT stmt;
00741    int res = 0;
00742 
00743    if (!ast_strlen_zero(obj->parent->sanitysql))
00744       test_sql = obj->parent->sanitysql;
00745 
00746    if (obj->up) {
00747       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00748       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00749          obj->up = 0;
00750       } else {
00751          res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
00752          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00753             obj->up = 0;
00754          } else {
00755             res = SQLExecute(stmt);
00756             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00757                obj->up = 0;
00758             }
00759          }
00760       }
00761       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00762    }
00763 
00764    if (!obj->up && !obj->tx) { /* Try to reconnect! */
00765       ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
00766       odbc_obj_disconnect(obj);
00767       odbc_obj_connect(obj);
00768    }
00769    return obj->up;
00770 }

int ast_odbc_smart_execute ( struct odbc_obj obj,
SQLHSTMT  stmt 
)

Executes a prepared statement handle.

Parameters:
obj The non-NULL result of odbc_request_obj()
stmt The prepared statement handle
Return values:
0 on success
-1 on failure
This function was originally designed simply to execute a prepared statement handle and to retry if the initial execution failed. Unfortunately, it did this by disconnecting and reconnecting the database handle which on most databases causes the statement handle to become invalid. Therefore, this method has been deprecated in favor of odbc_prepare_and_execute() which allows the statement to be prepared multiple times, if necessary, in case of a loss of connection.

This function really only ever worked with MySQL, where the statement handle is not prepared on the server. If you are not using MySQL, you should avoid it.

Definition at line 689 of file res_odbc.c.

References ao2_lock, ao2_unlock, ast_log, ast_tvnow(), odbc_obj::last_used, and LOG_WARNING.

00690 {
00691    int res = 0, i;
00692    SQLINTEGER nativeerror=0, numfields=0;
00693    SQLSMALLINT diagbytes=0;
00694    unsigned char state[10], diagnostic[256];
00695 
00696    ao2_lock(obj);
00697 
00698    res = SQLExecute(stmt);
00699    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00700       if (res == SQL_ERROR) {
00701          SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00702          for (i = 0; i < numfields; i++) {
00703             SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00704             ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00705             if (i > 10) {
00706                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00707                break;
00708             }
00709          }
00710       }
00711    } else {
00712       obj->last_used = ast_tvnow();
00713    }
00714 
00715    ao2_unlock(obj);
00716 
00717    return res;
00718 }

static int commit_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 1121 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, NULL, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().

Referenced by load_module().

01122 {
01123    struct odbc_txn_frame *tx;
01124    SQLINTEGER nativeerror=0, numfields=0;
01125    SQLSMALLINT diagbytes=0, i;
01126    unsigned char state[10], diagnostic[256];
01127 
01128    if (ast_strlen_zero(data)) {
01129       tx = find_transaction(chan, NULL, NULL, 1);
01130    } else {
01131       tx = find_transaction(chan, NULL, data, 0);
01132    }
01133 
01134    pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK");
01135 
01136    if (tx) {
01137       if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) {
01138          struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
01139          ast_str_reset(errors);
01140 
01141          /* Handle possible transaction commit failure */
01142          SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01143          for (i = 0; i < numfields; i++) {
01144             SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01145             ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
01146             ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
01147             if (i > 10) {
01148                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01149                break;
01150             }
01151          }
01152          pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
01153       }
01154    }
01155    return 0;
01156 }

static int data_odbc_provider_handler ( const struct ast_data_search search,
struct ast_data root 
) [static]

Definition at line 1716 of file res_odbc.c.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, 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_odbc_sanity_check(), class_container, odbc_class::count, isolation2text(), odbc_obj::tx, odbc_obj::up, and odbc_obj::used.

01718 {
01719    struct ao2_iterator aoi, aoi2;
01720    struct odbc_class *class;
01721    struct odbc_obj *current;
01722    struct ast_data *data_odbc_class, *data_odbc_connections, *data_odbc_connection;
01723    struct ast_data *enum_node;
01724    int count;
01725 
01726    aoi = ao2_iterator_init(class_container, 0);
01727    while ((class = ao2_iterator_next(&aoi))) {
01728       data_odbc_class = ast_data_add_node(root, "class");
01729       if (!data_odbc_class) {
01730          ao2_ref(class, -1);
01731          continue;
01732       }
01733 
01734       ast_data_add_structure(odbc_class, data_odbc_class, class);
01735 
01736       if (!ao2_container_count(class->obj_container)) {
01737          ao2_ref(class, -1);
01738          continue;
01739       }
01740 
01741       data_odbc_connections = ast_data_add_node(data_odbc_class, "connections");
01742       if (!data_odbc_connections) {
01743          ao2_ref(class, -1);
01744          continue;
01745       }
01746 
01747       ast_data_add_bool(data_odbc_class, "shared", !class->haspool);
01748       /* isolation */
01749       enum_node = ast_data_add_node(data_odbc_class, "isolation");
01750       if (!enum_node) {
01751          ao2_ref(class, -1);
01752          continue;
01753       }
01754       ast_data_add_int(enum_node, "value", class->isolation);
01755       ast_data_add_str(enum_node, "text", isolation2text(class->isolation));
01756 
01757       count = 0;
01758       aoi2 = ao2_iterator_init(class->obj_container, 0);
01759       while ((current = ao2_iterator_next(&aoi2))) {
01760          data_odbc_connection = ast_data_add_node(data_odbc_connections, "connection");
01761          if (!data_odbc_connection) {
01762             ao2_ref(current, -1);
01763             continue;
01764          }
01765 
01766          ao2_lock(current);
01767          ast_data_add_str(data_odbc_connection, "status", current->used ? "in use" :
01768                current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
01769          ast_data_add_bool(data_odbc_connection, "transactional", current->tx);
01770          ao2_unlock(current);
01771 
01772          if (class->haspool) {
01773             ast_data_add_int(data_odbc_connection, "number", ++count);
01774          }
01775 
01776          ao2_ref(current, -1);
01777       }
01778       ao2_iterator_destroy(&aoi2);
01779       ao2_ref(class, -1);
01780 
01781       if (!ast_data_search_match(search, data_odbc_class)) {
01782          ast_data_remove_node(root, data_odbc_class);
01783       }
01784    }
01785    ao2_iterator_destroy(&aoi);
01786    return 0;
01787 }

static void destroy_table_cache ( struct odbc_cache_tables table  )  [static]

Definition at line 435 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_cache_tables::columns, and odbc_cache_tables::table.

Referenced by ast_odbc_clear_cache(), ast_odbc_find_table(), and reload().

00435                                                                  {
00436    struct odbc_cache_columns *col;
00437    ast_debug(1, "Destroying table cache for %s\n", table->table);
00438    AST_RWLIST_WRLOCK(&table->columns);
00439    while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
00440       ast_free(col);
00441    }
00442    AST_RWLIST_UNLOCK(&table->columns);
00443    AST_RWLIST_HEAD_DESTROY(&table->columns);
00444    ast_free(table);
00445 }

static struct odbc_txn_frame* find_transaction ( struct ast_channel chan,
struct odbc_obj obj,
const char *  name,
int  active 
) [static, read]

Definition at line 232 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_txn_frame::forcecommit, odbc_class::isolation, odbc_txn_frame::isolation, LOG_ERROR, odbc_txn_frame::name, NULL, odbc_txn_frame::obj, odbc_txn_frame::owner, odbc_obj::parent, odbc_obj::tx, odbc_obj::txf, and txn_info.

00233 {
00234    struct ast_datastore *txn_store;
00235    AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
00236    struct odbc_txn_frame *txn = NULL;
00237 
00238    if (!chan && obj && obj->txf && obj->txf->owner) {
00239       chan = obj->txf->owner;
00240    } else if (!chan) {
00241       /* No channel == no transaction */
00242       return NULL;
00243    }
00244 
00245    ast_channel_lock(chan);
00246    if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
00247       oldlist = txn_store->data;
00248    } else {
00249       /* Need to create a new datastore */
00250       if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) {
00251          ast_log(LOG_ERROR, "Unable to allocate a new datastore.  Cannot create a new transaction.\n");
00252          ast_channel_unlock(chan);
00253          return NULL;
00254       }
00255 
00256       if (!(oldlist = ast_calloc(1, sizeof(*oldlist)))) {
00257          ast_log(LOG_ERROR, "Unable to allocate datastore list head.  Cannot create a new transaction.\n");
00258          ast_datastore_free(txn_store);
00259          ast_channel_unlock(chan);
00260          return NULL;
00261       }
00262 
00263       txn_store->data = oldlist;
00264       AST_LIST_HEAD_INIT(oldlist);
00265       ast_channel_datastore_add(chan, txn_store);
00266    }
00267 
00268    AST_LIST_LOCK(oldlist);
00269    ast_channel_unlock(chan);
00270 
00271    /* Scanning for an object is *fast*.  Scanning for a name is much slower. */
00272    if (obj != NULL || active == 1) {
00273       AST_LIST_TRAVERSE(oldlist, txn, list) {
00274          if (txn->obj == obj || txn->active) {
00275             AST_LIST_UNLOCK(oldlist);
00276             return txn;
00277          }
00278       }
00279    }
00280 
00281    if (name != NULL) {
00282       AST_LIST_TRAVERSE(oldlist, txn, list) {
00283          if (!strcasecmp(txn->name, name)) {
00284             AST_LIST_UNLOCK(oldlist);
00285             return txn;
00286          }
00287       }
00288    }
00289 
00290    /* Nothing found, create one */
00291    if (name && obj && (txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1))) {
00292       struct odbc_txn_frame *otxn;
00293 
00294       strcpy(txn->name, name); /* SAFE */
00295       txn->obj = obj;
00296       txn->isolation = obj->parent->isolation;
00297       txn->forcecommit = obj->parent->forcecommit;
00298       txn->owner = chan;
00299       txn->active = 1;
00300 
00301       /* On creation, the txn becomes active, and all others inactive */
00302       AST_LIST_TRAVERSE(oldlist, otxn, list) {
00303          otxn->active = 0;
00304       }
00305       AST_LIST_INSERT_TAIL(oldlist, txn, list);
00306 
00307       obj->txf = txn;
00308       obj->tx = 1;
00309    }
00310    AST_LIST_UNLOCK(oldlist);
00311 
00312    return txn;
00313 }

static char* handle_cli_odbc_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 933 of file res_odbc.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_localtime(), ast_odbc_sanity_check(), ast_strdup, ast_strftime(), class_container, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, odbc_class::count, ast_cli_args::fd, ast_cli_args::n, NULL, ast_cli_args::pos, odbc_obj::up, ast_cli_entry::usage, odbc_obj::used, and ast_cli_args::word.

00934 {
00935    struct ao2_iterator aoi;
00936    struct odbc_class *class;
00937    struct odbc_obj *current;
00938    int length = 0;
00939    int which = 0;
00940    char *ret = NULL;
00941 
00942    switch (cmd) {
00943    case CLI_INIT:
00944       e->command = "odbc show";
00945       e->usage =
00946             "Usage: odbc show [class]\n"
00947             "       List settings of a particular ODBC class or,\n"
00948             "       if not specified, all classes.\n";
00949       return NULL;
00950    case CLI_GENERATE:
00951       if (a->pos != 2)
00952          return NULL;
00953       length = strlen(a->word);
00954       aoi = ao2_iterator_init(class_container, 0);
00955       while ((class = ao2_iterator_next(&aoi))) {
00956          if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
00957             ret = ast_strdup(class->name);
00958          }
00959          ao2_ref(class, -1);
00960          if (ret) {
00961             break;
00962          }
00963       }
00964       ao2_iterator_destroy(&aoi);
00965       if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
00966          ret = ast_strdup("all");
00967       }
00968       return ret;
00969    }
00970 
00971    ast_cli(a->fd, "\nODBC DSN Settings\n");
00972    ast_cli(a->fd,   "-----------------\n\n");
00973    aoi = ao2_iterator_init(class_container, 0);
00974    while ((class = ao2_iterator_next(&aoi))) {
00975       if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
00976          int count = 0;
00977          char timestr[80];
00978          struct ast_tm tm;
00979 
00980          ast_localtime(&class->last_negative_connect, &tm, NULL);
00981          ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm);
00982          ast_cli(a->fd, "  Name:   %s\n  DSN:    %s\n", class->name, class->dsn);
00983          ast_cli(a->fd, "    Last connection attempt: %s\n", timestr);
00984 
00985          if (class->haspool) {
00986             struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
00987 
00988             ast_cli(a->fd, "  Pooled: Yes\n  Limit:  %u\n  Connections in use: %d\n", class->limit, class->count);
00989 
00990             while ((current = ao2_iterator_next(&aoi2))) {
00991                ao2_lock(current);
00992 #ifdef DEBUG_THREADS
00993                ast_cli(a->fd, "    - Connection %d: %s (%s:%d %s)\n", ++count,
00994                   current->used ? "in use" :
00995                   current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected",
00996                   current->file, current->lineno, current->function);
00997 #else
00998                ast_cli(a->fd, "    - Connection %d: %s\n", ++count,
00999                   current->used ? "in use" :
01000                   current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
01001 #endif
01002                ao2_unlock(current);
01003                ao2_ref(current, -1);
01004             }
01005             ao2_iterator_destroy(&aoi2);
01006          } else {
01007             /* Should only ever be one of these (unless there are transactions) */
01008             struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
01009             while ((current = ao2_iterator_next(&aoi2))) {
01010                ast_cli(a->fd, "  Pooled: No\n  Connected: %s\n", current->used ? "In use" :
01011                   current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
01012                ao2_ref(current, -1);
01013             }
01014             ao2_iterator_destroy(&aoi2);
01015          }
01016          ast_cli(a->fd, "\n");
01017       }
01018       ao2_ref(class, -1);
01019    }
01020    ao2_iterator_destroy(&aoi);
01021 
01022    return CLI_SUCCESS;
01023 }

static const char* isolation2text ( int  iso  )  [static]

Definition at line 198 of file res_odbc.c.

Referenced by acf_transaction_read(), and data_odbc_provider_handler().

00199 {
00200    if (iso == SQL_TXN_READ_COMMITTED) {
00201       return "read_committed";
00202    } else if (iso == SQL_TXN_READ_UNCOMMITTED) {
00203       return "read_uncommitted";
00204    } else if (iso == SQL_TXN_SERIALIZABLE) {
00205       return "serializable";
00206    } else if (iso == SQL_TXN_REPEATABLE_READ) {
00207       return "repeatable_read";
00208    } else {
00209       return "unknown";
00210    }
00211 }

static int load_module ( void   )  [static]

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 1892 of file res_odbc.c.

References ao2_container_alloc, ao2_match_by_addr(), app_commit, app_rollback, 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().

static int load_odbc_config ( void   )  [static]

Definition at line 772 of file res_odbc.c.

References ao2_alloc, ao2_container_alloc, ao2_match_by_addr(), ao2_ref, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_false(), ast_log, ast_strdup, ast_strlen_zero, ast_true(), ast_variable_browse(), config, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, odbc_class::conntimeout, odbc_class::dsn, enabled, odbc_class::idlecheck, odbc_class::limit, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, NULL, null_hash_fn(), odbc_class_destructor(), odbc_register_class(), odbc_class::password, odbc_class::sanitysql, setenv(), text2isolation(), odbc_class::username, and ast_variable::value.

Referenced by load_module(), and reload().

00773 {
00774    static char *cfg = "res_odbc.conf";
00775    struct ast_config *config;
00776    struct ast_variable *v;
00777    char *cat;
00778    const char *dsn, *username, *password, *sanitysql;
00779    int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation;
00780    struct timeval ncache = { 0, 0 };
00781    unsigned int idlecheck;
00782    int preconnect = 0, res = 0;
00783    struct ast_flags config_flags = { 0 };
00784 
00785    struct odbc_class *new;
00786 
00787    config = ast_config_load(cfg, config_flags);
00788    if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
00789       ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
00790       return -1;
00791    }
00792    for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
00793       if (!strcasecmp(cat, "ENV")) {
00794          for (v = ast_variable_browse(config, cat); v; v = v->next) {
00795             setenv(v->name, v->value, 1);
00796             ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
00797          }
00798       } else {
00799          /* Reset all to defaults for each class of odbc connections */
00800          dsn = username = password = sanitysql = NULL;
00801          enabled = 1;
00802          preconnect = idlecheck = 0;
00803          pooling = 0;
00804          limit = 0;
00805          bse = 1;
00806          conntimeout = 10;
00807          forcecommit = 0;
00808          isolation = SQL_TXN_READ_COMMITTED;
00809          for (v = ast_variable_browse(config, cat); v; v = v->next) {
00810             if (!strcasecmp(v->name, "pooling")) {
00811                if (ast_true(v->value))
00812                   pooling = 1;
00813             } else if (!strncasecmp(v->name, "share", 5)) {
00814                /* "shareconnections" is a little clearer in meaning than "pooling" */
00815                if (ast_false(v->value))
00816                   pooling = 1;
00817             } else if (!strcasecmp(v->name, "limit")) {
00818                sscanf(v->value, "%30d", &limit);
00819                if (ast_true(v->value) && !limit) {
00820                   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);
00821                   limit = 1023;
00822                } else if (ast_false(v->value)) {
00823                   ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'.  Disabling ODBC class '%s'.\n", v->value, cat);
00824                   enabled = 0;
00825                   break;
00826                }
00827             } else if (!strcasecmp(v->name, "idlecheck")) {
00828                sscanf(v->value, "%30u", &idlecheck);
00829             } else if (!strcasecmp(v->name, "enabled")) {
00830                enabled = ast_true(v->value);
00831             } else if (!strcasecmp(v->name, "pre-connect")) {
00832                preconnect = ast_true(v->value);
00833             } else if (!strcasecmp(v->name, "dsn")) {
00834                dsn = v->value;
00835             } else if (!strcasecmp(v->name, "username")) {
00836                username = v->value;
00837             } else if (!strcasecmp(v->name, "password")) {
00838                password = v->value;
00839             } else if (!strcasecmp(v->name, "sanitysql")) {
00840                sanitysql = v->value;
00841             } else if (!strcasecmp(v->name, "backslash_is_escape")) {
00842                bse = ast_true(v->value);
00843             } else if (!strcasecmp(v->name, "connect_timeout")) {
00844                if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
00845                   ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
00846                   conntimeout = 10;
00847                }
00848             } else if (!strcasecmp(v->name, "negative_connection_cache")) {
00849                double dncache;
00850                if (sscanf(v->value, "%lf", &dncache) != 1 || dncache < 0) {
00851                   ast_log(LOG_WARNING, "negative_connection_cache must be a non-negative integer\n");
00852                   /* 5 minutes sounds like a reasonable default */
00853                   ncache.tv_sec = 300;
00854                   ncache.tv_usec = 0;
00855                } else {
00856                   ncache.tv_sec = (int)dncache;
00857                   ncache.tv_usec = (dncache - ncache.tv_sec) * 1000000;
00858                }
00859             } else if (!strcasecmp(v->name, "forcecommit")) {
00860                forcecommit = ast_true(v->value);
00861             } else if (!strcasecmp(v->name, "isolation")) {
00862                if ((isolation = text2isolation(v->value)) == 0) {
00863                   ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat);
00864                   isolation = SQL_TXN_READ_COMMITTED;
00865                }
00866             }
00867          }
00868 
00869          if (enabled && !ast_strlen_zero(dsn)) {
00870             new = ao2_alloc(sizeof(*new), odbc_class_destructor);
00871 
00872             if (!new) {
00873                res = -1;
00874                break;
00875             }
00876 
00877             SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
00878             res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
00879 
00880             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00881                ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
00882                ao2_ref(new, -1);
00883                return res;
00884             }
00885 
00886             new->obj_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr);
00887 
00888             if (pooling) {
00889                new->haspool = pooling;
00890                if (limit) {
00891                   new->limit = limit;
00892                } else {
00893                   ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless.  Changing limit from 0 to 5.\n");
00894                   new->limit = 5;
00895                }
00896             }
00897 
00898             new->backslash_is_escape = bse ? 1 : 0;
00899             new->forcecommit = forcecommit ? 1 : 0;
00900             new->isolation = isolation;
00901             new->idlecheck = idlecheck;
00902             new->conntimeout = conntimeout;
00903             new->negative_connection_cache = ncache;
00904 
00905             if (cat)
00906                ast_copy_string(new->name, cat, sizeof(new->name));
00907             if (dsn)
00908                ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
00909             if (username && !(new->username = ast_strdup(username))) {
00910                ao2_ref(new, -1);
00911                break;
00912             }
00913             if (password && !(new->password = ast_strdup(password))) {
00914                ao2_ref(new, -1);
00915                break;
00916             }
00917             if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) {
00918                ao2_ref(new, -1);
00919                break;
00920             }
00921 
00922             odbc_register_class(new, preconnect);
00923             ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
00924             ao2_ref(new, -1);
00925             new = NULL;
00926          }
00927       }
00928    }
00929    ast_config_destroy(config);
00930    return res;
00931 }

static int mark_transaction_active ( struct ast_channel chan,
struct odbc_txn_frame tx 
) [static]

Definition at line 367 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, NULL, odbc_txn_frame::owner, and txn_info.

Referenced by acf_transaction_write().

00368 {
00369    struct ast_datastore *txn_store;
00370    AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
00371    struct odbc_txn_frame *active = NULL, *txn;
00372 
00373    if (!chan && tx && tx->owner) {
00374       chan = tx->owner;
00375    }
00376 
00377    if (!chan) {
00378       return -1;
00379    }
00380 
00381    ast_channel_lock(chan);
00382    if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
00383       ast_channel_unlock(chan);
00384       return -1;
00385    }
00386 
00387    oldlist = txn_store->data;
00388    AST_LIST_LOCK(oldlist);
00389    AST_LIST_TRAVERSE(oldlist, txn, list) {
00390       if (txn == tx) {
00391          txn->active = 1;
00392          active = txn;
00393       } else {
00394          txn->active = 0;
00395       }
00396    }
00397    AST_LIST_UNLOCK(oldlist);
00398    ast_channel_unlock(chan);
00399    return active ? 0 : -1;
00400 }

static int null_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 421 of file res_odbc.c.

Referenced by load_module(), and load_odbc_config().

00422 {
00423    return 0;
00424 }

static void odbc_class_destructor ( void *  data  )  [static]

Definition at line 402 of file res_odbc.c.

References ao2_ref, and ast_free.

Referenced by load_odbc_config().

00403 {
00404    struct odbc_class *class = data;
00405    /* Due to refcounts, we can safely assume that any objects with a reference
00406     * to us will prevent our destruction, so we don't need to worry about them.
00407     */
00408    if (class->username) {
00409       ast_free(class->username);
00410    }
00411    if (class->password) {
00412       ast_free(class->password);
00413    }
00414    if (class->sanitysql) {
00415       ast_free(class->sanitysql);
00416    }
00417    ao2_ref(class->obj_container, -1);
00418    SQLFreeHandle(SQL_HANDLE_ENV, class->env);
00419 }

static odbc_status odbc_obj_connect ( struct odbc_obj obj  )  [static]

Definition at line 1514 of file res_odbc.c.

References ast_assert, ast_log, ast_tvnow(), odbc_obj::con, odbc_class::conntimeout, odbc_class::dsn, odbc_class::env, odbc_class::last_negative_connect, odbc_obj::last_used, LOG_NOTICE, LOG_WARNING, odbc_class::name, NULL, 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().

01515 {
01516    int res;
01517    SQLINTEGER err;
01518    short int mlen;
01519    unsigned char msg[200], state[10];
01520 #ifdef NEEDTRACE
01521    SQLINTEGER enable = 1;
01522    char *tracefile = "/tmp/odbc.trace";
01523 #endif
01524    SQLHDBC con;
01525 
01526    if (obj->up) {
01527       odbc_obj_disconnect(obj);
01528       ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
01529    } else {
01530       ast_assert(obj->con == NULL);
01531       ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
01532    }
01533 
01534    res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &con);
01535 
01536    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01537       ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
01538       obj->parent->last_negative_connect = ast_tvnow();
01539       return ODBC_FAIL;
01540    }
01541    SQLSetConnectAttr(con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
01542    SQLSetConnectAttr(con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
01543 #ifdef NEEDTRACE
01544    SQLSetConnectAttr(con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
01545    SQLSetConnectAttr(con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
01546 #endif
01547 
01548    res = SQLConnect(con,
01549          (SQLCHAR *) obj->parent->dsn, SQL_NTS,
01550          (SQLCHAR *) obj->parent->username, SQL_NTS,
01551          (SQLCHAR *) obj->parent->password, SQL_NTS);
01552 
01553    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01554       SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
01555       obj->parent->last_negative_connect = ast_tvnow();
01556       ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
01557       if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) != SQL_SUCCESS) {
01558          SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
01559          ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
01560       }
01561       return ODBC_FAIL;
01562    } else {
01563       ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
01564       obj->up = 1;
01565       obj->last_used = ast_tvnow();
01566    }
01567 
01568    obj->con = con;
01569    return ODBC_SUCCESS;
01570 }

static void odbc_obj_destructor ( void *  data  )  [static]

Definition at line 426 of file res_odbc.c.

References ao2_ref, NULL, odbc_obj_disconnect(), and odbc_obj::parent.

Referenced by _ast_odbc_request_obj2().

00427 {
00428    struct odbc_obj *obj = data;
00429    struct odbc_class *class = obj->parent;
00430    obj->parent = NULL;
00431    odbc_obj_disconnect(obj);
00432    ao2_ref(class, -1);
00433 }

static odbc_status odbc_obj_disconnect ( struct odbc_obj obj  )  [static]

Definition at line 1478 of file res_odbc.c.

References ast_debug, ast_log, odbc_obj::con, odbc_class::dsn, LOG_WARNING, odbc_class::name, NULL, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.

Referenced by ast_odbc_sanity_check(), odbc_obj_connect(), and odbc_obj_destructor().

01479 {
01480    int res;
01481    SQLINTEGER err;
01482    short int mlen;
01483    unsigned char msg[200], state[10];
01484    SQLHDBC con;
01485 
01486    /* Nothing to disconnect */
01487    if (!obj->con) {
01488       return ODBC_SUCCESS;
01489    }
01490 
01491    con = obj->con;
01492    obj->con = NULL;
01493    res = SQLDisconnect(con);
01494 
01495    if (obj->parent) {
01496       if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
01497          ast_debug(1, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
01498       } else {
01499          ast_debug(1, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
01500       }
01501    }
01502 
01503    if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) == SQL_SUCCESS) {
01504       ast_debug(1, "Database handle %p deallocated\n", con);
01505    } else {
01506       SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
01507       ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
01508    }
01509 
01510    obj->up = 0;
01511    return ODBC_SUCCESS;
01512 }

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

Definition at line 1029 of file res_odbc.c.

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

Referenced by load_odbc_config().

01030 {
01031    struct odbc_obj *obj;
01032    if (class) {
01033       ao2_link(class_container, class);
01034       /* I still have a reference in the caller, so a deref is NOT missing here. */
01035 
01036       if (preconnect) {
01037          /* Request and release builds a connection */
01038          obj = ast_odbc_request_obj(class->name, 0);
01039          if (obj) {
01040             ast_odbc_release_obj(obj);
01041          }
01042       }
01043 
01044       return 0;
01045    } else {
01046       ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
01047       return -1;
01048    }
01049 }

static void odbc_release_obj2 ( struct odbc_obj obj,
struct odbc_txn_frame tx 
) [static]

Definition at line 1051 of file res_odbc.c.

References ao2_ref, ast_debug, ast_log, odbc_obj::con, odbc_txn_frame::forcecommit, LOG_WARNING, NULL, odbc_txn_frame::obj, release_transaction(), odbc_obj::txf, and odbc_obj::used.

Referenced by ast_odbc_release_obj(), and release_transaction().

01052 {
01053    SQLINTEGER nativeerror=0, numfields=0;
01054    SQLSMALLINT diagbytes=0, i;
01055    unsigned char state[10], diagnostic[256];
01056 
01057    ast_debug(2, "odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->txf);
01058    if (tx) {
01059       ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK");
01060       if (SQLEndTran(SQL_HANDLE_DBC, obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
01061          /* Handle possible transaction commit failure */
01062          SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01063          for (i = 0; i < numfields; i++) {
01064             SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01065             ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
01066             if (!strcmp((char *)state, "25S02") || !strcmp((char *)state, "08007")) {
01067                /* These codes mean that a commit failed and a transaction
01068                 * is still active. We must rollback, or things will get
01069                 * very, very weird for anybody using the handle next. */
01070                SQLEndTran(SQL_HANDLE_DBC, obj->con, SQL_ROLLBACK);
01071             }
01072             if (i > 10) {
01073                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01074                break;
01075             }
01076          }
01077       }
01078 
01079       /* Transaction is done, reset autocommit */
01080       if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
01081          SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01082          for (i = 0; i < numfields; i++) {
01083             SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01084             ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01085             if (i > 10) {
01086                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01087                break;
01088             }
01089          }
01090       }
01091    }
01092 
01093 #ifdef DEBUG_THREADS
01094    obj->file[0] = '\0';
01095    obj->function[0] = '\0';
01096    obj->lineno = 0;
01097 #endif
01098 
01099    /* For pooled connections, this frees the connection to be
01100     * reused.  For non-pooled connections, it does nothing. */
01101    obj->used = 0;
01102    if (obj->txf) {
01103       /* Prevent recursion -- transaction is already closed out. */
01104       obj->txf->obj = NULL;
01105       obj->txf = release_transaction(obj->txf);
01106    }
01107    ao2_ref(obj, -1);
01108 }

static void odbc_txn_free ( void *  data  )  [static]

Definition at line 351 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, and release_transaction().

00352 {
00353    struct odbc_txn_frame *tx;
00354    AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata;
00355 
00356    ast_debug(2, "odbc_txn_free(%p) called\n", vdata);
00357 
00358    AST_LIST_LOCK(oldlist);
00359    while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) {
00360       release_transaction(tx);
00361    }
00362    AST_LIST_UNLOCK(oldlist);
00363    AST_LIST_HEAD_DESTROY(oldlist);
00364    ast_free(oldlist);
00365 }

static struct odbc_txn_frame* release_transaction ( struct odbc_txn_frame tx  )  [static, read]

Definition at line 315 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, NULL, odbc_txn_frame::obj, odbc_release_obj2(), odbc_txn_frame::owner, odbc_obj::txf, and txn_info.

Referenced by odbc_release_obj2(), and odbc_txn_free().

00316 {
00317    if (!tx) {
00318       return NULL;
00319    }
00320 
00321    ast_debug(2, "release_transaction(%p) called (tx->obj = %p, tx->obj->txf = %p)\n", tx, tx->obj, tx->obj ? tx->obj->txf : NULL);
00322 
00323    /* If we have an owner, disassociate */
00324    if (tx->owner) {
00325       struct ast_datastore *txn_store;
00326       AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
00327 
00328       ast_channel_lock(tx->owner);
00329       if ((txn_store = ast_channel_datastore_find(tx->owner, &txn_info, NULL))) {
00330          oldlist = txn_store->data;
00331          AST_LIST_LOCK(oldlist);
00332          AST_LIST_REMOVE(oldlist, tx, list);
00333          AST_LIST_UNLOCK(oldlist);
00334       }
00335       ast_channel_unlock(tx->owner);
00336       tx->owner = NULL;
00337    }
00338 
00339    if (tx->obj) {
00340       /* If we have any uncommitted transactions, they are handled when we release the object */
00341       struct odbc_obj *obj = tx->obj;
00342       /* Prevent recursion during destruction */
00343       tx->obj->txf = NULL;
00344       tx->obj = NULL;
00345       odbc_release_obj2(obj, tx);
00346    }
00347    ast_free(tx);
00348    return NULL;
00349 }

static int reload ( void   )  [static]

Definition at line 1802 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.

01803 {
01804    struct odbc_cache_tables *table;
01805    struct odbc_class *class;
01806    struct odbc_obj *current;
01807    struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
01808 
01809    /* First, mark all to be purged */
01810    while ((class = ao2_iterator_next(&aoi))) {
01811       class->delme = 1;
01812       ao2_ref(class, -1);
01813    }
01814    ao2_iterator_destroy(&aoi);
01815 
01816    load_odbc_config();
01817 
01818    /* Purge remaining classes */
01819 
01820    /* Note on how this works; this is a case of circular references, so we
01821     * explicitly do NOT want to use a callback here (or we wind up in
01822     * recursive hell).
01823     *
01824     * 1. Iterate through all the classes.  Note that the classes will currently
01825     * contain two classes of the same name, one of which is marked delme and
01826     * will be purged when all remaining objects of the class are released, and
01827     * the other, which was created above when we re-parsed the config file.
01828     * 2. On each class, there is a reference held by the master container and
01829     * a reference held by each connection object.  There are two cases for
01830     * destruction of the class, noted below.  However, in all cases, all O-refs
01831     * (references to objects) will first be freed, which will cause the C-refs
01832     * (references to classes) to be decremented (but never to 0, because the
01833     * class container still has a reference).
01834     *    a) If the class has outstanding objects, the C-ref by the class
01835     *    container will then be freed, which leaves only C-refs by any
01836     *    outstanding objects.  When the final outstanding object is released
01837     *    (O-refs held by applications and dialplan functions), it will in turn
01838     *    free the final C-ref, causing class destruction.
01839     *    b) If the class has no outstanding objects, when the class container
01840     *    removes the final C-ref, the class will be destroyed.
01841     */
01842    aoi = ao2_iterator_init(class_container, 0);
01843    while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */
01844       if (class->delme) {
01845          struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
01846          while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */
01847             ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */
01848             ao2_ref(current, -1); /* O-ref-- (by iterator) */
01849             /* At this point, either
01850              * a) there's an outstanding O-ref, or
01851              * b) the object has already been destroyed.
01852              */
01853          }
01854          ao2_iterator_destroy(&aoi2);
01855          ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
01856          /* At this point, either
01857           * a) there's an outstanding O-ref, which holds an outstanding C-ref, or
01858           * b) the last remaining C-ref is held by the iterator, which will be
01859           * destroyed in the next step.
01860           */
01861       }
01862       ao2_ref(class, -1); /* C-ref-- (by iterator) */
01863    }
01864    ao2_iterator_destroy(&aoi);
01865 
01866    /* Empty the cache; it will get rebuilt the next time the tables are needed. */
01867    AST_RWLIST_WRLOCK(&odbc_tables);
01868    while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
01869       destroy_table_cache(table);
01870    }
01871    AST_RWLIST_UNLOCK(&odbc_tables);
01872 
01873    return 0;
01874 }

static int rollback_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 1158 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, NULL, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().

Referenced by load_module().

01159 {
01160    struct odbc_txn_frame *tx;
01161    SQLINTEGER nativeerror=0, numfields=0;
01162    SQLSMALLINT diagbytes=0, i;
01163    unsigned char state[10], diagnostic[256];
01164 
01165    if (ast_strlen_zero(data)) {
01166       tx = find_transaction(chan, NULL, NULL, 1);
01167    } else {
01168       tx = find_transaction(chan, NULL, data, 0);
01169    }
01170 
01171    pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK");
01172 
01173    if (tx) {
01174       if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) {
01175          struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
01176          ast_str_reset(errors);
01177 
01178          /* Handle possible transaction commit failure */
01179          SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01180          for (i = 0; i < numfields; i++) {
01181             SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01182             ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
01183             ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
01184             if (i > 10) {
01185                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01186                break;
01187             }
01188          }
01189          pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
01190       }
01191    }
01192    return 0;
01193 }

static int text2isolation ( const char *  txt  )  [static]

Definition at line 213 of file res_odbc.c.

Referenced by acf_transaction_write(), and load_odbc_config().

00214 {
00215    if (strncasecmp(txt, "read_", 5) == 0) {
00216       if (strncasecmp(txt + 5, "c", 1) == 0) {
00217          return SQL_TXN_READ_COMMITTED;
00218       } else if (strncasecmp(txt + 5, "u", 1) == 0) {
00219          return SQL_TXN_READ_UNCOMMITTED;
00220       } else {
00221          return 0;
00222       }
00223    } else if (strncasecmp(txt, "ser", 3) == 0) {
00224       return SQL_TXN_SERIALIZABLE;
00225    } else if (strncasecmp(txt, "rep", 3) == 0) {
00226       return SQL_TXN_REPEATABLE_READ;
00227    } else {
00228       return 0;
00229    }
00230 }

static int unload_module ( void   )  [static]

Definition at line 1876 of file res_odbc.c.

01877 {
01878    /* Prohibit unloading */
01879    return -1;
01880 }


Variable Documentation

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, } [static]

Definition at line 1913 of file res_odbc.c.

const char* const app_commit = "ODBC_Commit" [static]

Definition at line 1709 of file res_odbc.c.

Referenced by load_module().

const char* const app_rollback = "ODBC_Rollback" [static]

Definition at line 1710 of file res_odbc.c.

Referenced by load_module().

Definition at line 1913 of file res_odbc.c.

struct ao2_container* class_container [static]

struct ast_cli_entry cli_odbc[] [static]

Initial value:

 {
   AST_CLI_DEFINE(handle_cli_odbc_show, "List ODBC DSN(s)")
}

Definition at line 1025 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]

Definition at line 163 of file res_odbc.c.

Referenced by commit_exec(), and rollback_exec().

Initial value:

 {
   .name = "ODBC",
   .read = acf_transaction_read,
   .write = acf_transaction_write,
}

Definition at line 1703 of file res_odbc.c.

Referenced by load_module().

Initial value:

Definition at line 1793 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 1798 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 165 of file res_odbc.c.

Referenced by ast_odbc_retrieve_transaction_obj(), find_transaction(), mark_transaction_active(), and release_transaction().


Generated on Thu Apr 16 06:32:56 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6