Mon Jun 27 16:51:19 2011

Asterisk developer's documentation


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"

Go to the source code of this file.

Data Structures

struct  odbc_class
struct  odbc_tables
struct  odbc_txn_frame

Defines

#define DATA_EXPORT_ODBC_CLASS(MEMBER)
#define EOR_TX   (void *)(long)3
#define NO_TX   (void *)(long)2
#define USE_TX   (void *)(long)1

Functions

static void __init_errors_buf (void)
static void __reg_module (void)
static void __unreg_module (void)
odbc_obj_ast_odbc_request_obj (const char *name, int check, const char *file, const char *function, int lineno)
odbc_obj_ast_odbc_request_obj2 (const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
 Retrieves a connected ODBC object.
static int acf_transaction_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_transaction_write (struct ast_channel *chan, const char *cmd, char *s, const char *value)
static int aoro2_class_cb (void *obj, void *arg, int flags)
static int aoro2_obj_cb (void *vobj, void *arg, int flags)
 AST_DATA_STRUCTURE (odbc_class, DATA_EXPORT_ODBC_CLASS)
SQLRETURN ast_odbc_ast_str_SQLGetData (struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind)
 Wrapper for SQLGetData to use with dynamic strings.
int ast_odbc_backslash_is_escape (struct odbc_obj *obj)
 Checks if the database natively supports backslash as an escape character.
int ast_odbc_clear_cache (const char *database, const char *tablename)
 Remove a cache entry from memory This function may be called to clear entries created and cached by the ast_odbc_find_table() API call.
SQLHSTMT ast_odbc_direct_execute (struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data)
 Executes an non prepared statement and returns the resulting statement handle.
odbc_cache_columnsast_odbc_find_column (struct odbc_cache_tables *table, const char *colname)
 Find a column entry within a cached table structure.
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().
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)
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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, }
static const char *const app_commit = "ODBC_Commit"
static const char *const app_rollback = "ODBC_Rollback"
static struct ast_module_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 177 of file res_odbc.c.

#define EOR_TX   (void *)(long)3

Definition at line 1184 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().

#define NO_TX   (void *)(long)2

Definition at line 1183 of file res_odbc.c.

Referenced by aoro2_obj_cb().

#define USE_TX   (void *)(long)1

Definition at line 1182 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().


Function Documentation

static void __init_errors_buf ( void   )  [static]

Definition at line 153 of file res_odbc.c.

00155 {

static void __reg_module ( void   )  [static]

Definition at line 1845 of file res_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 1845 of file res_odbc.c.

struct odbc_obj* _ast_odbc_request_obj ( const char *  name,
int  check,
const char *  file,
const char *  function,
int  lineno 
)

Definition at line 1387 of file res_odbc.c.

References _ast_odbc_request_obj2(), ast_flags::flags, and RES_ODBC_SANITY_CHECK.

01388 {
01389    struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
01390    return _ast_odbc_request_obj2(name, flags, file, function, lineno);
01391 }

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

Retrieves a connected ODBC object.

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.
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 1199 of file res_odbc.c.

References ao2_alloc, ao2_callback, ao2_link, ao2_ref, aoro2_class_cb(), aoro2_obj_cb(), ast_assert, ast_atomic_fetchadd_int(), ast_debug, ast_log(), ast_mutex_init, ast_test_flag, class_container, odbc_obj::con, EOR_TX, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), RES_ODBC_INDEPENDENT_CONNECTION, and USE_TX.

Referenced by _ast_odbc_request_obj().

01200 {
01201    struct odbc_obj *obj = NULL;
01202    struct odbc_class *class;
01203    SQLINTEGER nativeerror=0, numfields=0;
01204    SQLSMALLINT diagbytes=0, i;
01205    unsigned char state[10], diagnostic[256];
01206 
01207    if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
01208       ast_debug(1, "Class '%s' not found!\n", name);
01209       return NULL;
01210    }
01211 
01212    ast_assert(ao2_ref(class, 0) > 1);
01213 
01214    if (class->haspool) {
01215       /* Recycle connections before building another */
01216       obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX);
01217 
01218       if (obj) {
01219          ast_assert(ao2_ref(obj, 0) > 1);
01220       }
01221       if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit) &&
01222             (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) {
01223          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
01224          if (!obj) {
01225             class->count--;
01226             ao2_ref(class, -1);
01227             ast_debug(3, "Unable to allocate object\n");
01228             ast_atomic_fetchadd_int(&class->count, -1);
01229             return NULL;
01230          }
01231          ast_assert(ao2_ref(obj, 0) == 1);
01232          ast_mutex_init(&obj->lock);
01233          /* obj inherits the outstanding reference to class */
01234          obj->parent = class;
01235          class = NULL;
01236          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01237             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01238             ao2_ref(obj, -1);
01239             obj = NULL;
01240             ast_assert(ao2_ref(class, 0) > 0);
01241             ast_atomic_fetchadd_int(&class->count, -1);
01242          } else {
01243             obj->used = 1;
01244             ao2_link(obj->parent->obj_container, obj);
01245          }
01246       } else {
01247          /* If construction fails due to the limit (or negative timecache), reverse our increment. */
01248          if (!obj) {
01249             ast_atomic_fetchadd_int(&class->count, -1);
01250          }
01251          /* Object is not constructed, so delete outstanding reference to class. */
01252          ao2_ref(class, -1);
01253          class = NULL;
01254       }
01255 
01256       if (obj && ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
01257          /* Ensure this connection has autocommit turned off. */
01258          if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
01259             SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01260             for (i = 0; i < numfields; i++) {
01261                SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01262                ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01263                if (i > 10) {
01264                   ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01265                   break;
01266                }
01267             }
01268          }
01269       }
01270    } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
01271       /* Non-pooled connections -- but must use a separate connection handle */
01272       if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) {
01273          ast_debug(1, "Object not found\n");
01274          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
01275          if (!obj) {
01276             ao2_ref(class, -1);
01277             ast_debug(3, "Unable to allocate object\n");
01278             return NULL;
01279          }
01280          ast_mutex_init(&obj->lock);
01281          /* obj inherits the outstanding reference to class */
01282          obj->parent = class;
01283          class = NULL;
01284          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01285             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01286             ao2_ref(obj, -1);
01287             obj = NULL;
01288          } else {
01289             obj->used = 1;
01290             ao2_link(obj->parent->obj_container, obj);
01291             ast_atomic_fetchadd_int(&obj->parent->count, +1);
01292          }
01293       }
01294 
01295       if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
01296          SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01297          for (i = 0; i < numfields; i++) {
01298             SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01299             ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01300             if (i > 10) {
01301                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01302                break;
01303             }
01304          }
01305       }
01306    } else {
01307       /* Non-pooled connection: multiple modules can use the same connection. */
01308       if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, NO_TX))) {
01309          /* Object is not constructed, so delete outstanding reference to class. */
01310          ast_assert(ao2_ref(class, 0) > 1);
01311          ao2_ref(class, -1);
01312          class = NULL;
01313       } else {
01314          /* No entry: build one */
01315          if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) {
01316             ast_assert(ao2_ref(class, 0) > 1);
01317             ao2_ref(class, -1);
01318             ast_debug(3, "Unable to allocate object\n");
01319             return NULL;
01320          }
01321          ast_mutex_init(&obj->lock);
01322          /* obj inherits the outstanding reference to class */
01323          obj->parent = class;
01324          class = NULL;
01325          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01326             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01327             ao2_ref(obj, -1);
01328             obj = NULL;
01329          } else {
01330             ao2_link(obj->parent->obj_container, obj);
01331             ast_assert(ao2_ref(obj, 0) > 1);
01332          }
01333       }
01334 
01335       if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
01336          SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01337          for (i = 0; i < numfields; i++) {
01338             SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01339             ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01340             if (i > 10) {
01341                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01342                break;
01343             }
01344          }
01345       }
01346    }
01347 
01348    /* Set the isolation property */
01349    if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
01350       SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01351       for (i = 0; i < numfields; i++) {
01352          SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01353          ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
01354          if (i > 10) {
01355             ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01356             break;
01357          }
01358       }
01359    }
01360 
01361    if (obj && ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) {
01362       /* Check if this connection qualifies for reconnection, with negative connection cache time */
01363       if (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec) {
01364          odbc_obj_connect(obj);
01365       }
01366    } else if (obj && ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
01367       ast_odbc_sanity_check(obj);
01368    } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) {
01369       odbc_obj_connect(obj);
01370    }
01371 
01372 #ifdef DEBUG_THREADS
01373    if (obj) {
01374       ast_copy_string(obj->file, file, sizeof(obj->file));
01375       ast_copy_string(obj->function, function, sizeof(obj->function));
01376       obj->lineno = lineno;
01377    }
01378 #endif
01379    ast_assert(class == NULL);
01380 
01381    if (obj) {
01382       ast_assert(ao2_ref(obj, 0) > 1);
01383    }
01384    return obj;
01385 }

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

Definition at line 1517 of file res_odbc.c.

References args, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strlen_zero(), find_transaction(), odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, isolation2text(), and odbc_txn_frame::name.

01518 {
01519    AST_DECLARE_APP_ARGS(args,
01520       AST_APP_ARG(property);
01521       AST_APP_ARG(opt);
01522    );
01523    struct odbc_txn_frame *tx;
01524 
01525    AST_STANDARD_APP_ARGS(args, data);
01526    if (strcasecmp(args.property, "transaction") == 0) {
01527       if ((tx = find_transaction(chan, NULL, NULL, 1))) {
01528          ast_copy_string(buf, tx->name, len);
01529          return 0;
01530       }
01531    } else if (strcasecmp(args.property, "isolation") == 0) {
01532       if (!ast_strlen_zero(args.opt)) {
01533          tx = find_transaction(chan, NULL, args.opt, 0);
01534       } else {
01535          tx = find_transaction(chan, NULL, NULL, 1);
01536       }
01537       if (tx) {
01538          ast_copy_string(buf, isolation2text(tx->isolation), len);
01539          return 0;
01540       }
01541    } else if (strcasecmp(args.property, "forcecommit") == 0) {
01542       if (!ast_strlen_zero(args.opt)) {
01543          tx = find_transaction(chan, NULL, args.opt, 0);
01544       } else {
01545          tx = find_transaction(chan, NULL, NULL, 1);
01546       }
01547       if (tx) {
01548          ast_copy_string(buf, tx->forcecommit ? "1" : "0", len);
01549          return 0;
01550       }
01551    }
01552    return -1;
01553 }

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

Definition at line 1555 of file res_odbc.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_false(), ast_log(), ast_odbc_request_obj2, AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_true(), odbc_obj::con, find_transaction(), ast_flags::flags, odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, LOG_ERROR, mark_transaction_active(), odbc_txn_frame::obj, pbx_builtin_setvar_helper(), RES_ODBC_INDEPENDENT_CONNECTION, S_OR, text2isolation(), and odbc_obj::tx.

01556 {
01557    AST_DECLARE_APP_ARGS(args,
01558       AST_APP_ARG(property);
01559       AST_APP_ARG(opt);
01560    );
01561    struct odbc_txn_frame *tx;
01562    SQLINTEGER nativeerror=0, numfields=0;
01563    SQLSMALLINT diagbytes=0, i;
01564    unsigned char state[10], diagnostic[256];
01565 
01566    AST_STANDARD_APP_ARGS(args, s);
01567    if (strcasecmp(args.property, "transaction") == 0) {
01568       /* Set active transaction */
01569       struct odbc_obj *obj;
01570       if ((tx = find_transaction(chan, NULL, value, 0))) {
01571          mark_transaction_active(chan, tx);
01572       } else {
01573          /* No such transaction, create one */
01574          struct ast_flags flags = { RES_ODBC_INDEPENDENT_CONNECTION };
01575          if (ast_strlen_zero(args.opt) || !(obj = ast_odbc_request_obj2(args.opt, flags))) {
01576             ast_log(LOG_ERROR, "Could not create transaction: invalid database specification '%s'\n", S_OR(args.opt, ""));
01577             pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_DB");
01578             return -1;
01579          }
01580          if (!(tx = find_transaction(chan, obj, value, 0))) {
01581             pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
01582             return -1;
01583          }
01584          obj->tx = 1;
01585       }
01586       pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
01587       return 0;
01588    } else if (strcasecmp(args.property, "forcecommit") == 0) {
01589       /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */
01590       if (ast_strlen_zero(args.opt)) {
01591          tx = find_transaction(chan, NULL, NULL, 1);
01592       } else {
01593          tx = find_transaction(chan, NULL, args.opt, 0);
01594       }
01595       if (!tx) {
01596          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
01597          return -1;
01598       }
01599       if (ast_true(value)) {
01600          tx->forcecommit = 1;
01601       } else if (ast_false(value)) {
01602          tx->forcecommit = 0;
01603       } else {
01604          ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, ""));
01605          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
01606          return -1;
01607       }
01608 
01609       pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
01610       return 0;
01611    } else if (strcasecmp(args.property, "isolation") == 0) {
01612       /* How do uncommitted transactions affect reads? */
01613       int isolation = text2isolation(value);
01614       if (ast_strlen_zero(args.opt)) {
01615          tx = find_transaction(chan, NULL, NULL, 1);
01616       } else {
01617          tx = find_transaction(chan, NULL, args.opt, 0);
01618       }
01619       if (!tx) {
01620          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
01621          return -1;
01622       }
01623       if (isolation == 0) {
01624          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
01625          ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, ""));
01626       } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) {
01627          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR");
01628          SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01629          for (i = 0; i < numfields; i++) {
01630             SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01631             ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
01632             if (i > 10) {
01633                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01634                break;
01635             }
01636          }
01637       } else {
01638          pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
01639          tx->isolation = isolation;
01640       }
01641       return 0;
01642    } else {
01643       ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property);
01644       return -1;
01645    }
01646 }

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

Definition at line 1172 of file res_odbc.c.

References CMP_MATCH, and CMP_STOP.

Referenced by _ast_odbc_request_obj2().

01173 {
01174    struct odbc_class *class = obj;
01175    char *name = arg;
01176    if (!strcmp(class->name, name) && !class->delme) {
01177       return CMP_MATCH | CMP_STOP;
01178    }
01179    return 0;
01180 }

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

Definition at line 1186 of file res_odbc.c.

References ast_mutex_lock, ast_mutex_unlock, CMP_MATCH, CMP_STOP, EOR_TX, odbc_obj::lock, NO_TX, odbc_obj::tx, USE_TX, and odbc_obj::used.

Referenced by _ast_odbc_request_obj2().

01187 {
01188    struct odbc_obj *obj = vobj;
01189    ast_mutex_lock(&obj->lock);
01190    if ((arg == NO_TX && !obj->tx) || (arg == EOR_TX && !obj->used) || (arg == USE_TX && obj->tx && !obj->used)) {
01191       obj->used = 1;
01192       ast_mutex_unlock(&obj->lock);
01193       return CMP_MATCH | CMP_STOP;
01194    }
01195    ast_mutex_unlock(&obj->lock);
01196    return 0;
01197 }

AST_DATA_STRUCTURE ( odbc_class  ,
DATA_EXPORT_ODBC_CLASS   
)

SQLRETURN ast_odbc_ast_str_SQLGetData ( struct ast_str **  buf,
int  pmaxlen,
SQLHSTMT  StatementHandle,
SQLUSMALLINT  ColumnNumber,
SQLSMALLINT  TargetType,
SQLLEN *  StrLen_or_Ind 
)

Wrapper for SQLGetData to use with dynamic strings.

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 698 of file res_odbc.c.

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

00699 {
00700    SQLRETURN res;
00701 
00702    if (pmaxlen == 0) {
00703       if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
00704          ast_str_make_space(buf, *StrLen_or_Ind + 1);
00705       }
00706    } else if (pmaxlen > 0) {
00707       ast_str_make_space(buf, pmaxlen);
00708    }
00709    res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
00710    ast_str_update(*buf);
00711 
00712    return res;
00713 }

int ast_odbc_backslash_is_escape ( struct odbc_obj obj  ) 

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

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 1093 of file res_odbc.c.

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

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

01094 {
01095    return obj->parent->backslash_is_escape;
01096 }

int ast_odbc_clear_cache ( const char *  database,
const char *  tablename 
)

Remove a cache entry from memory This function may be called to clear entries created and cached by the ast_odbc_find_table() API call.

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 569 of file res_odbc.c.

References AST_LIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, odbc_cache_tables::connection, destroy_table_cache(), odbc_class::list, and odbc_cache_tables::table.

00570 {
00571    struct odbc_cache_tables *tableptr;
00572 
00573    AST_RWLIST_WRLOCK(&odbc_tables);
00574    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
00575       if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
00576          AST_LIST_REMOVE_CURRENT(list);
00577          destroy_table_cache(tableptr);
00578          break;
00579       }
00580    }
00581    AST_RWLIST_TRAVERSE_SAFE_END
00582    AST_RWLIST_UNLOCK(&odbc_tables);
00583    return tableptr ? 0 : -1;
00584 }

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

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

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 586 of file res_odbc.c.

References ast_log(), ast_odbc_sanity_check(), and LOG_WARNING.

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

00587 {
00588    int attempt;
00589    SQLHSTMT stmt;
00590 
00591    for (attempt = 0; attempt < 2; attempt++) {
00592       stmt = exec_cb(obj, data);
00593 
00594       if (stmt) {
00595          break;
00596       } else if (obj->tx) {
00597          ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n");
00598          break;
00599       } else if (attempt == 0) {
00600          ast_log(LOG_WARNING, "SQL Execute error! Verifying connection to %s [%s]...\n", obj->parent->name, obj->parent->dsn);
00601       }
00602       if (!ast_odbc_sanity_check(obj)) {
00603          break;
00604       }
00605    }
00606 
00607    return stmt;
00608 }

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

Find a column entry within a cached table structure.

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 558 of file res_odbc.c.

References AST_RWLIST_TRAVERSE, odbc_class::list, odbc_cache_columns::name, and table.

Referenced by update2_prepare(), and update_odbc().

00559 {
00560    struct odbc_cache_columns *col;
00561    AST_RWLIST_TRAVERSE(&table->columns, col, list) {
00562       if (strcasecmp(col->name, colname) == 0) {
00563          return col;
00564       }
00565    }
00566    return NULL;
00567 }

struct odbc_cache_tables* ast_odbc_find_table ( const char *  database,
const char *  tablename 
)

Find or create an entry describing the table specified.

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 443 of file res_odbc.c.

References ast_calloc, AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj, ast_odbc_sanity_check(), AST_RWLIST_HEAD_INIT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_verb, odbc_cache_tables::columns, odbc_obj::con, odbc_cache_tables::connection, destroy_table_cache(), odbc_class::list, LOG_ERROR, LOG_WARNING, and odbc_cache_tables::table.

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

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

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

Prepares, executes, and returns the resulting statement handle.

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 610 of file res_odbc.c.

References ast_log(), ast_odbc_sanity_check(), ast_tvnow(), and LOG_WARNING.

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

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

void ast_odbc_release_obj ( struct odbc_obj obj  ) 

Releases an ODBC object previously allocated by ast_odbc_request_obj().

Parameters:
obj The ODBC object

Definition at line 1087 of file res_odbc.c.

References find_transaction(), odbc_txn_frame::obj, and odbc_release_obj2().

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

01088 {
01089    struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
01090    odbc_release_obj2(obj, tx);
01091 }

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

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

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 1393 of file res_odbc.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_txn_frame::list, odbc_class::name, odbc_txn_frame::obj, odbc_obj::parent, and txn_info.

Referenced by acf_odbc_write().

01394 {
01395    struct ast_datastore *txn_store;
01396    AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
01397    struct odbc_txn_frame *txn = NULL;
01398 
01399    if (!chan) {
01400       /* No channel == no transaction */
01401       return NULL;
01402    }
01403 
01404    ast_channel_lock(chan);
01405    if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
01406       oldlist = txn_store->data;
01407    } else {
01408       ast_channel_unlock(chan);
01409       return NULL;
01410    }
01411 
01412    AST_LIST_LOCK(oldlist);
01413    ast_channel_unlock(chan);
01414 
01415    AST_LIST_TRAVERSE(oldlist, txn, list) {
01416       if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) {
01417          AST_LIST_UNLOCK(oldlist);
01418          return txn->obj;
01419       }
01420    }
01421    AST_LIST_UNLOCK(oldlist);
01422    return NULL;
01423 }

int ast_odbc_sanity_check ( struct odbc_obj obj  ) 

Checks an ODBC object to ensure it is still connected.

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

Definition at line 715 of file res_odbc.c.

References ast_log(), ast_strlen_zero(), odbc_obj::con, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), odbc_obj::parent, odbc_class::sanitysql, odbc_obj::tx, and odbc_obj::up.

Referenced by ast_odbc_direct_execute(), ast_odbc_find_table(), ast_odbc_prepare_and_execute(), data_odbc_provider_handler(), and handle_cli_odbc_show().

00716 {
00717    char *test_sql = "select 1";
00718    SQLHSTMT stmt;
00719    int res = 0;
00720 
00721    if (!ast_strlen_zero(obj->parent->sanitysql))
00722       test_sql = obj->parent->sanitysql;
00723 
00724    if (obj->up) {
00725       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00726       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00727          obj->up = 0;
00728       } else {
00729          res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
00730          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00731             obj->up = 0;
00732          } else {
00733             res = SQLExecute(stmt);
00734             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00735                obj->up = 0;
00736             }
00737          }
00738       }
00739       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00740    }
00741 
00742    if (!obj->up && !obj->tx) { /* Try to reconnect! */
00743       ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
00744       odbc_obj_disconnect(obj);
00745       odbc_obj_connect(obj);
00746    }
00747    return obj->up;
00748 }

int ast_odbc_smart_execute ( struct odbc_obj obj,
SQLHSTMT  stmt 
)

Executes a prepared statement handle.

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 671 of file res_odbc.c.

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

00672 {
00673    int res = 0, i;
00674    SQLINTEGER nativeerror=0, numfields=0;
00675    SQLSMALLINT diagbytes=0;
00676    unsigned char state[10], diagnostic[256];
00677 
00678    res = SQLExecute(stmt);
00679    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00680       if (res == SQL_ERROR) {
00681          SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00682          for (i = 0; i < numfields; i++) {
00683             SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00684             ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00685             if (i > 10) {
00686                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00687                break;
00688             }
00689          }
00690       }
00691    } else {
00692       obj->last_used = ast_tvnow();
00693    }
00694 
00695    return res;
00696 }

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

Definition at line 1098 of file res_odbc.c.

References ast_log(), ast_str_append(), ast_str_buffer(), ast_str_reset(), ast_str_strlen(), ast_str_thread_get(), ast_strlen_zero(), odbc_obj::con, errors_buf, find_transaction(), LOG_WARNING, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().

Referenced by load_module().

01099 {
01100    struct odbc_txn_frame *tx;
01101    SQLINTEGER nativeerror=0, numfields=0;
01102    SQLSMALLINT diagbytes=0, i;
01103    unsigned char state[10], diagnostic[256];
01104 
01105    if (ast_strlen_zero(data)) {
01106       tx = find_transaction(chan, NULL, NULL, 1);
01107    } else {
01108       tx = find_transaction(chan, NULL, data, 0);
01109    }
01110 
01111    pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK");
01112 
01113    if (tx) {
01114       if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) {
01115          struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
01116          ast_str_reset(errors);
01117 
01118          /* Handle possible transaction commit failure */
01119          SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01120          for (i = 0; i < numfields; i++) {
01121             SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01122             ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
01123             ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
01124             if (i > 10) {
01125                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01126                break;
01127             }
01128          }
01129          pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
01130       }
01131    }
01132    return 0;
01133 }

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

Definition at line 1661 of file res_odbc.c.

References ao2_container_count(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_data_add_bool(), ast_data_add_int(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), ast_mutex_lock, ast_mutex_unlock, ast_odbc_sanity_check(), class_container, isolation2text(), odbc_obj::lock, odbc_obj::tx, odbc_obj::up, and odbc_obj::used.

01663 {
01664    struct ao2_iterator aoi, aoi2;
01665    struct odbc_class *class;
01666    struct odbc_obj *current;
01667    struct ast_data *data_odbc_class, *data_odbc_connections, *data_odbc_connection;
01668    struct ast_data *enum_node;
01669    int count;
01670 
01671    aoi = ao2_iterator_init(class_container, 0);
01672    while ((class = ao2_iterator_next(&aoi))) {
01673       data_odbc_class = ast_data_add_node(root, "class");
01674       if (!data_odbc_class) {
01675          ao2_ref(class, -1);
01676          continue;
01677       }
01678 
01679       ast_data_add_structure(odbc_class, data_odbc_class, class);
01680 
01681       if (!ao2_container_count(class->obj_container)) {
01682          ao2_ref(class, -1);
01683          continue;
01684       }
01685 
01686       data_odbc_connections = ast_data_add_node(data_odbc_class, "connections");
01687       if (!data_odbc_connections) {
01688          ao2_ref(class, -1);
01689          continue;
01690       }
01691 
01692       ast_data_add_bool(data_odbc_class, "shared", !class->haspool);
01693       /* isolation */
01694       enum_node = ast_data_add_node(data_odbc_class, "isolation");
01695       if (!enum_node) {
01696          ao2_ref(class, -1);
01697          continue;
01698       }
01699       ast_data_add_int(enum_node, "value", class->isolation);
01700       ast_data_add_str(enum_node, "text", isolation2text(class->isolation));
01701 
01702       count = 0;
01703       aoi2 = ao2_iterator_init(class->obj_container, 0);
01704       while ((current = ao2_iterator_next(&aoi2))) {
01705          data_odbc_connection = ast_data_add_node(data_odbc_connections, "connection");
01706          if (!data_odbc_connection) {
01707             ao2_ref(current, -1);
01708             continue;
01709          }
01710 
01711          ast_mutex_lock(&current->lock);
01712          ast_data_add_str(data_odbc_connection, "status", current->used ? "in use" :
01713                current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
01714          ast_data_add_bool(data_odbc_connection, "transactional", current->tx);
01715          ast_mutex_unlock(&current->lock);
01716 
01717          if (class->haspool) {
01718             ast_data_add_int(data_odbc_connection, "number", ++count);
01719          }
01720 
01721          ao2_ref(current, -1);
01722       }
01723       ao2_ref(class, -1);
01724 
01725       if (!ast_data_search_match(search, data_odbc_class)) {
01726          ast_data_remove_node(root, data_odbc_class);
01727       }
01728    }
01729    return 0;
01730 }

static void destroy_table_cache ( struct odbc_cache_tables table  )  [static]

Definition at line 422 of file res_odbc.c.

References ast_debug, ast_free, AST_RWLIST_HEAD_DESTROY, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, odbc_class::list, and table.

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

00422                                                                  {
00423    struct odbc_cache_columns *col;
00424    ast_debug(1, "Destroying table cache for %s\n", table->table);
00425    AST_RWLIST_WRLOCK(&table->columns);
00426    while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
00427       ast_free(col);
00428    }
00429    AST_RWLIST_UNLOCK(&table->columns);
00430    AST_RWLIST_HEAD_DESTROY(&table->columns);
00431    ast_free(table);
00432 }

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

Definition at line 222 of file res_odbc.c.

References odbc_txn_frame::active, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, odbc_class::forcecommit, odbc_class::isolation, odbc_class::list, LOG_ERROR, odbc_txn_frame::name, odbc_txn_frame::obj, odbc_txn_frame::owner, odbc_obj::parent, odbc_obj::tx, odbc_obj::txf, and txn_info.

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

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

Definition at line 911 of file res_odbc.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_localtime(), ast_mutex_lock, ast_mutex_unlock, ast_odbc_sanity_check(), ast_strdup, ast_strftime(), class_container, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, odbc_obj::file, odbc_obj::function, odbc_obj::lineno, odbc_obj::lock, ast_cli_args::n, ast_cli_args::pos, odbc_obj::up, ast_cli_entry::usage, odbc_obj::used, and ast_cli_args::word.

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

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

Definition at line 188 of file res_odbc.c.

Referenced by acf_transaction_read(), and data_odbc_provider_handler().

00189 {
00190    if (iso == SQL_TXN_READ_COMMITTED) {
00191       return "read_committed";
00192    } else if (iso == SQL_TXN_READ_UNCOMMITTED) {
00193       return "read_uncommitted";
00194    } else if (iso == SQL_TXN_SERIALIZABLE) {
00195       return "serializable";
00196    } else if (iso == SQL_TXN_REPEATABLE_READ) {
00197       return "repeatable_read";
00198    } else {
00199       return "unknown";
00200    }
00201 }

static int load_module ( void   )  [static]

Definition at line 1825 of file res_odbc.c.

References ao2_container_alloc, ao2_match_by_addr, ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_data_register_multiple, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application_xml, class_container, cli_odbc, commit_exec(), load_odbc_config(), LOG_NOTICE, null_hash_fn(), odbc_function, odbc_providers, and rollback_exec().

static int load_odbc_config ( void   )  [static]

Definition at line 750 of file res_odbc.c.

References ast_category_browse(), ast_config_load, ast_false(), ast_log(), ast_true(), ast_variable_browse(), config, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, odbc_class::conntimeout, odbc_class::dsn, enabled, odbc_class::idlecheck, odbc_class::limit, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, odbc_class::password, odbc_class::sanitysql, setenv(), odbc_class::username, and ast_variable::value.

Referenced by load_module(), and reload().

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

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

Definition at line 357 of file res_odbc.c.

References odbc_txn_frame::active, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_class::list, odbc_txn_frame::owner, and txn_info.

Referenced by acf_transaction_write().

00358 {
00359    struct ast_datastore *txn_store;
00360    AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
00361    struct odbc_txn_frame *active = NULL, *txn;
00362 
00363    if (!chan && tx && tx->owner) {
00364       chan = tx->owner;
00365    }
00366 
00367    ast_channel_lock(chan);
00368    if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
00369       ast_channel_unlock(chan);
00370       return -1;
00371    }
00372 
00373    oldlist = txn_store->data;
00374    AST_LIST_LOCK(oldlist);
00375    AST_LIST_TRAVERSE(oldlist, txn, list) {
00376       if (txn == tx) {
00377          txn->active = 1;
00378          active = txn;
00379       } else {
00380          txn->active = 0;
00381       }
00382    }
00383    AST_LIST_UNLOCK(oldlist);
00384    ast_channel_unlock(chan);
00385    return active ? 0 : -1;
00386 }

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

Definition at line 407 of file res_odbc.c.

Referenced by load_module().

00408 {
00409    return 0;
00410 }

static void odbc_class_destructor ( void *  data  )  [static]

Definition at line 388 of file res_odbc.c.

References ao2_ref, and ast_free.

00389 {
00390    struct odbc_class *class = data;
00391    /* Due to refcounts, we can safely assume that any objects with a reference
00392     * to us will prevent our destruction, so we don't need to worry about them.
00393     */
00394    if (class->username) {
00395       ast_free(class->username);
00396    }
00397    if (class->password) {
00398       ast_free(class->password);
00399    }
00400    if (class->sanitysql) {
00401       ast_free(class->sanitysql);
00402    }
00403    ao2_ref(class->obj_container, -1);
00404    SQLFreeHandle(SQL_HANDLE_ENV, class->env);
00405 }

static odbc_status odbc_obj_connect ( struct odbc_obj obj  )  [static]

Definition at line 1462 of file res_odbc.c.

References ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_tvnow(), odbc_obj::con, odbc_class::conntimeout, odbc_class::dsn, odbc_class::env, odbc_class::last_negative_connect, odbc_obj::last_used, odbc_obj::lock, LOG_NOTICE, odbc_class::name, odbc_txn_frame::obj, ODBC_FAIL, odbc_obj_disconnect(), ODBC_SUCCESS, odbc_obj::parent, odbc_class::password, odbc_obj::up, and odbc_class::username.

Referenced by _ast_odbc_request_obj2(), and ast_odbc_sanity_check().

01463 {
01464    int res;
01465    SQLINTEGER err;
01466    short int mlen;
01467    unsigned char msg[200], state[10];
01468 #ifdef NEEDTRACE
01469    SQLINTEGER enable = 1;
01470    char *tracefile = "/tmp/odbc.trace";
01471 #endif
01472    ast_mutex_lock(&obj->lock);
01473 
01474    if (obj->up) {
01475       odbc_obj_disconnect(obj);
01476       ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
01477    } else {
01478       ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
01479    }
01480 
01481    res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &obj->con);
01482 
01483    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01484       ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
01485       obj->parent->last_negative_connect = ast_tvnow();
01486       ast_mutex_unlock(&obj->lock);
01487       return ODBC_FAIL;
01488    }
01489    SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
01490    SQLSetConnectAttr(obj->con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
01491 #ifdef NEEDTRACE
01492    SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
01493    SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
01494 #endif
01495 
01496    res = SQLConnect(obj->con,
01497          (SQLCHAR *) obj->parent->dsn, SQL_NTS,
01498          (SQLCHAR *) obj->parent->username, SQL_NTS,
01499          (SQLCHAR *) obj->parent->password, SQL_NTS);
01500 
01501    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
01502       SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen);
01503       obj->parent->last_negative_connect = ast_tvnow();
01504       ast_mutex_unlock(&obj->lock);
01505       ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
01506       return ODBC_FAIL;
01507    } else {
01508       ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
01509       obj->up = 1;
01510       obj->last_used = ast_tvnow();
01511    }
01512 
01513    ast_mutex_unlock(&obj->lock);
01514    return ODBC_SUCCESS;
01515 }

static void odbc_obj_destructor ( void *  data  )  [static]

Definition at line 412 of file res_odbc.c.

References ao2_ref, ast_mutex_destroy, odbc_obj::lock, odbc_obj_disconnect(), and odbc_obj::parent.

Referenced by _ast_odbc_request_obj2().

00413 {
00414    struct odbc_obj *obj = data;
00415    struct odbc_class *class = obj->parent;
00416    obj->parent = NULL;
00417    odbc_obj_disconnect(obj);
00418    ast_mutex_destroy(&obj->lock);
00419    ao2_ref(class, -1);
00420 }

static odbc_status odbc_obj_disconnect ( struct odbc_obj obj  )  [static]

Definition at line 1425 of file res_odbc.c.

References ast_log(), ast_mutex_lock, ast_mutex_unlock, odbc_obj::con, odbc_class::dsn, odbc_obj::lock, LOG_DEBUG, odbc_class::name, odbc_txn_frame::obj, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.

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

01426 {
01427    int res;
01428    SQLINTEGER err;
01429    short int mlen;
01430    unsigned char msg[200], state[10];
01431 
01432    /* Nothing to disconnect */
01433    if (!obj->con) {
01434       return ODBC_SUCCESS;
01435    }
01436 
01437    ast_mutex_lock(&obj->lock);
01438 
01439    res = SQLDisconnect(obj->con);
01440 
01441    if (obj->parent) {
01442       if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
01443          ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
01444       } else {
01445          ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
01446       }
01447    }
01448 
01449    if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == SQL_SUCCESS)) {
01450       obj->con = NULL;
01451       ast_log(LOG_DEBUG, "Database handle deallocated\n");
01452    } else {
01453       SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen);
01454       ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg);
01455    }
01456 
01457    obj->up = 0;
01458    ast_mutex_unlock(&obj->lock);
01459    return ODBC_SUCCESS;
01460 }

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

Definition at line 1006 of file res_odbc.c.

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

01007 {
01008    struct odbc_obj *obj;
01009    if (class) {
01010       ao2_link(class_container, class);
01011       /* I still have a reference in the caller, so a deref is NOT missing here. */
01012 
01013       if (preconnect) {
01014          /* Request and release builds a connection */
01015          obj = ast_odbc_request_obj(class->name, 0);
01016          if (obj) {
01017             ast_odbc_release_obj(obj);
01018          }
01019       }
01020 
01021       return 0;
01022    } else {
01023       ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
01024       return -1;
01025    }
01026 }

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

Definition at line 1028 of file res_odbc.c.

References ast_debug, ast_log(), odbc_obj::con, LOG_WARNING, odbc_obj::tx, and odbc_obj::txf.

Referenced by ast_odbc_release_obj(), and release_transaction().

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

static void odbc_txn_free ( void *  data  )  [static]

Definition at line 341 of file res_odbc.c.

References ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, odbc_class::list, and release_transaction().

00342 {
00343    struct odbc_txn_frame *tx;
00344    AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata;
00345 
00346    ast_debug(2, "odbc_txn_free(%p) called\n", vdata);
00347 
00348    AST_LIST_LOCK(oldlist);
00349    while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) {
00350       release_transaction(tx);
00351    }
00352    AST_LIST_UNLOCK(oldlist);
00353    AST_LIST_HEAD_DESTROY(oldlist);
00354    ast_free(oldlist);
00355 }

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

Definition at line 305 of file res_odbc.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_datastore::data, odbc_class::list, odbc_txn_frame::obj, odbc_release_obj2(), odbc_txn_frame::owner, odbc_obj::tx, odbc_obj::txf, and txn_info.

Referenced by odbc_txn_free().

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

static int reload ( void   )  [static]

Definition at line 1745 of file res_odbc.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, class_container, destroy_table_cache(), load_odbc_config(), and table.

01746 {
01747    struct odbc_cache_tables *table;
01748    struct odbc_class *class;
01749    struct odbc_obj *current;
01750    struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
01751 
01752    /* First, mark all to be purged */
01753    while ((class = ao2_iterator_next(&aoi))) {
01754       class->delme = 1;
01755       ao2_ref(class, -1);
01756    }
01757    ao2_iterator_destroy(&aoi);
01758 
01759    load_odbc_config();
01760 
01761    /* Purge remaining classes */
01762 
01763    /* Note on how this works; this is a case of circular references, so we
01764     * explicitly do NOT want to use a callback here (or we wind up in
01765     * recursive hell).
01766     *
01767     * 1. Iterate through all the classes.  Note that the classes will currently
01768     * contain two classes of the same name, one of which is marked delme and
01769     * will be purged when all remaining objects of the class are released, and
01770     * the other, which was created above when we re-parsed the config file.
01771     * 2. On each class, there is a reference held by the master container and
01772     * a reference held by each connection object.  There are two cases for
01773     * destruction of the class, noted below.  However, in all cases, all O-refs
01774     * (references to objects) will first be freed, which will cause the C-refs
01775     * (references to classes) to be decremented (but never to 0, because the
01776     * class container still has a reference).
01777     *    a) If the class has outstanding objects, the C-ref by the class
01778     *    container will then be freed, which leaves only C-refs by any
01779     *    outstanding objects.  When the final outstanding object is released
01780     *    (O-refs held by applications and dialplan functions), it will in turn
01781     *    free the final C-ref, causing class destruction.
01782     *    b) If the class has no outstanding objects, when the class container
01783     *    removes the final C-ref, the class will be destroyed.
01784     */
01785    aoi = ao2_iterator_init(class_container, 0);
01786    while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */
01787       if (class->delme) {
01788          struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
01789          while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */
01790             ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */
01791             ao2_ref(current, -1); /* O-ref-- (by iterator) */
01792             /* At this point, either
01793              * a) there's an outstanding O-ref, or
01794              * b) the object has already been destroyed.
01795              */
01796          }
01797          ao2_iterator_destroy(&aoi2);
01798          ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
01799          /* At this point, either
01800           * a) there's an outstanding O-ref, which holds an outstanding C-ref, or
01801           * b) the last remaining C-ref is held by the iterator, which will be
01802           * destroyed in the next step.
01803           */
01804       }
01805       ao2_ref(class, -1); /* C-ref-- (by iterator) */
01806    }
01807    ao2_iterator_destroy(&aoi);
01808 
01809    /* Empty the cache; it will get rebuilt the next time the tables are needed. */
01810    AST_RWLIST_WRLOCK(&odbc_tables);
01811    while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
01812       destroy_table_cache(table);
01813    }
01814    AST_RWLIST_UNLOCK(&odbc_tables);
01815 
01816    return 0;
01817 }

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

Definition at line 1135 of file res_odbc.c.

References ast_log(), ast_str_append(), ast_str_buffer(), ast_str_reset(), ast_str_strlen(), ast_str_thread_get(), ast_strlen_zero(), odbc_obj::con, errors_buf, find_transaction(), LOG_WARNING, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().

Referenced by load_module().

01136 {
01137    struct odbc_txn_frame *tx;
01138    SQLINTEGER nativeerror=0, numfields=0;
01139    SQLSMALLINT diagbytes=0, i;
01140    unsigned char state[10], diagnostic[256];
01141 
01142    if (ast_strlen_zero(data)) {
01143       tx = find_transaction(chan, NULL, NULL, 1);
01144    } else {
01145       tx = find_transaction(chan, NULL, data, 0);
01146    }
01147 
01148    pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK");
01149 
01150    if (tx) {
01151       if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) {
01152          struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
01153          ast_str_reset(errors);
01154 
01155          /* Handle possible transaction commit failure */
01156          SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01157          for (i = 0; i < numfields; i++) {
01158             SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01159             ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
01160             ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
01161             if (i > 10) {
01162                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01163                break;
01164             }
01165          }
01166          pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
01167       }
01168    }
01169    return 0;
01170 }

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

Definition at line 203 of file res_odbc.c.

Referenced by acf_transaction_write().

00204 {
00205    if (strncasecmp(txt, "read_", 5) == 0) {
00206       if (strncasecmp(txt + 5, "c", 1) == 0) {
00207          return SQL_TXN_READ_COMMITTED;
00208       } else if (strncasecmp(txt + 5, "u", 1) == 0) {
00209          return SQL_TXN_READ_UNCOMMITTED;
00210       } else {
00211          return 0;
00212       }
00213    } else if (strncasecmp(txt, "ser", 3) == 0) {
00214       return SQL_TXN_SERIALIZABLE;
00215    } else if (strncasecmp(txt, "rep", 3) == 0) {
00216       return SQL_TXN_REPEATABLE_READ;
00217    } else {
00218       return 0;
00219    }
00220 }

static int unload_module ( void   )  [static]

Definition at line 1819 of file res_odbc.c.

01820 {
01821    /* Prohibit unloading */
01822    return -1;
01823 }


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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, } [static]

Definition at line 1845 of file res_odbc.c.

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

Definition at line 1654 of file res_odbc.c.

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

Definition at line 1655 of file res_odbc.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1845 of file res_odbc.c.

struct ao2_container* class_container [static]

Definition at line 143 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), data_odbc_provider_handler(), handle_cli_odbc_show(), load_module(), odbc_register_class(), and reload().

struct ast_cli_entry cli_odbc[] [static]

Initial value:

 {
   { .handler =  handle_cli_odbc_show , .summary =  "List ODBC DSN(s)" ,__VA_ARGS__ }
}

Definition at line 1002 of file res_odbc.c.

Referenced by load_module().

struct ast_threadstorage errors_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_errors_buf , .custom_init = NULL , } [static]

Definition at line 153 of file res_odbc.c.

Referenced by commit_exec(), and rollback_exec().

struct ast_custom_function odbc_function [static]

Initial value:

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

Definition at line 1648 of file res_odbc.c.

Referenced by load_module().

struct ast_data_handler odbc_provider [static]

Initial value:

Definition at line 1736 of file res_odbc.c.

struct ast_data_entry odbc_providers[] [static]

Initial value:

 {
   AST_DATA_ENTRY("/asterisk/res/odbc", &odbc_provider),
}

Definition at line 1741 of file res_odbc.c.

Referenced by load_module().

struct ast_datastore_info txn_info [static]

Initial value:

 {
   .type = "ODBC_Transaction",
   .destroy = odbc_txn_free,
}

Definition at line 155 of file res_odbc.c.

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


Generated on Mon Jun 27 16:51:19 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7