Mon Mar 19 11:30:54 2012

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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, }
static const char *const app_commit = "ODBC_Commit"
static const char *const app_rollback = "ODBC_Rollback"
static struct ast_module_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 178 of file res_odbc.c.

#define EOR_TX   (void *)(long)3

Definition at line 1186 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().

#define NO_TX   (void *)(long)2

Definition at line 1185 of file res_odbc.c.

Referenced by aoro2_obj_cb().

#define USE_TX   (void *)(long)1

Definition at line 1184 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().


Function Documentation

static void __init_errors_buf ( void   )  [static]

Definition at line 154 of file res_odbc.c.

00156 {

static void __reg_module ( void   )  [static]

Definition at line 1850 of file res_odbc.c.

static void __unreg_module ( void   )  [static]

Definition at line 1850 of file res_odbc.c.

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

Definition at line 1390 of file res_odbc.c.

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

01391 {
01392    struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
01393    return _ast_odbc_request_obj2(name, flags, file, function, lineno);
01394 }

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

Retrieves a connected ODBC object.

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

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

Referenced by _ast_odbc_request_obj().

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

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

Definition at line 1520 of file res_odbc.c.

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

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

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

Definition at line 1558 of file res_odbc.c.

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

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

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

Definition at line 1174 of file res_odbc.c.

References CMP_MATCH, and CMP_STOP.

Referenced by _ast_odbc_request_obj2().

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

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

Definition at line 1188 of file res_odbc.c.

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

Referenced by _ast_odbc_request_obj2().

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

AST_DATA_STRUCTURE ( odbc_class  ,
DATA_EXPORT_ODBC_CLASS   
)

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

Wrapper for SQLGetData to use with dynamic strings.

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

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

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

int ast_odbc_backslash_is_escape ( struct odbc_obj obj  ) 

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

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

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

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

01096 {
01097    return obj->parent->backslash_is_escape;
01098 }

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

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

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

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

Referenced by unload_odbc().

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

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

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

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

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

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

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

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

Find a column entry within a cached table structure.

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

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

Referenced by update2_prepare(), and update_odbc().

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

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

Find or create an entry describing the table specified.

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

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

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

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

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

Prepares, executes, and returns the resulting statement handle.

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

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

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

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

void ast_odbc_release_obj ( struct odbc_obj obj  ) 

Releases an ODBC object previously allocated by ast_odbc_request_obj().

Parameters:
obj The ODBC object

Definition at line 1089 of file res_odbc.c.

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

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

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

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

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

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

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

Referenced by acf_odbc_write().

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

int ast_odbc_sanity_check ( struct odbc_obj obj  ) 

Checks an ODBC object to ensure it is still connected.

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

Definition at line 716 of file res_odbc.c.

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

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

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

int ast_odbc_smart_execute ( struct odbc_obj obj,
SQLHSTMT  stmt 
)

Executes a prepared statement handle.

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

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

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

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

Definition at line 1100 of file res_odbc.c.

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

Referenced by load_module().

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

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

Definition at line 1664 of file res_odbc.c.

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

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

static void destroy_table_cache ( struct odbc_cache_tables table  )  [static]

Definition at line 423 of file res_odbc.c.

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

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

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

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

Definition at line 223 of file res_odbc.c.

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

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

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

Definition at line 912 of file res_odbc.c.

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

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

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

Definition at line 189 of file res_odbc.c.

Referenced by acf_transaction_read(), and data_odbc_provider_handler().

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

static int load_module ( void   )  [static]

Definition at line 1830 of file res_odbc.c.

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

static int load_odbc_config ( void   )  [static]

Definition at line 751 of file res_odbc.c.

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

Referenced by load_module(), and reload().

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

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

Definition at line 358 of file res_odbc.c.

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

Referenced by acf_transaction_write().

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

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

Definition at line 408 of file res_odbc.c.

Referenced by load_module().

00409 {
00410    return 0;
00411 }

static void odbc_class_destructor ( void *  data  )  [static]

Definition at line 389 of file res_odbc.c.

References ao2_ref, and ast_free.

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

static odbc_status odbc_obj_connect ( struct odbc_obj obj  )  [static]

Definition at line 1465 of file res_odbc.c.

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

Referenced by _ast_odbc_request_obj2(), and ast_odbc_sanity_check().

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

static void odbc_obj_destructor ( void *  data  )  [static]

Definition at line 413 of file res_odbc.c.

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

Referenced by _ast_odbc_request_obj2().

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

static odbc_status odbc_obj_disconnect ( struct odbc_obj obj  )  [static]

Definition at line 1428 of file res_odbc.c.

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

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

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

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

Definition at line 1008 of file res_odbc.c.

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

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

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

Definition at line 1030 of file res_odbc.c.

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

Referenced by ast_odbc_release_obj(), and release_transaction().

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

static void odbc_txn_free ( void *  data  )  [static]

Definition at line 342 of file res_odbc.c.

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

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

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

Definition at line 306 of file res_odbc.c.

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

Referenced by odbc_txn_free().

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

static int reload ( void   )  [static]

Definition at line 1750 of file res_odbc.c.

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

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

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

Definition at line 1137 of file res_odbc.c.

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

Referenced by load_module().

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

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

Definition at line 204 of file res_odbc.c.

Referenced by acf_transaction_write().

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

static int unload_module ( void   )  [static]

Definition at line 1824 of file res_odbc.c.

01825 {
01826    /* Prohibit unloading */
01827    return -1;
01828 }


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

Definition at line 1850 of file res_odbc.c.

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

Definition at line 1657 of file res_odbc.c.

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

Definition at line 1658 of file res_odbc.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1850 of file res_odbc.c.

struct ao2_container* class_container [static]

Definition at line 144 of file res_odbc.c.

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

struct ast_cli_entry cli_odbc[] [static]

Initial value:

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

Definition at line 1004 of file res_odbc.c.

Referenced by load_module().

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

Definition at line 154 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 1651 of file res_odbc.c.

Referenced by load_module().

struct ast_data_handler odbc_provider [static]

Initial value:

Definition at line 1741 of file res_odbc.c.

struct ast_data_entry odbc_providers[] [static]

Initial value:

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

Definition at line 1746 of file res_odbc.c.

Referenced by load_module().

struct ast_datastore_info txn_info [static]

Initial value:

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

Definition at line 156 of file res_odbc.c.

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


Generated on Mon Mar 19 11:30:54 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7