Fri Nov 12 12:08:38 2010

Asterisk developer's documentation


res_odbc.h File Reference

ODBC resource manager. More...

#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include "asterisk/linkedlists.h"
#include "asterisk/strings.h"
Include dependency graph for res_odbc.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  _columns
struct  odbc_cache_columns
struct  odbc_cache_tables
struct  odbc_obj
 ODBC container. More...

Defines

#define ast_odbc_release_table(ptr)   if (ptr) { AST_RWLIST_UNLOCK(&(ptr)->columns); }
 Release a table returned from ast_odbc_find_table.

Enumerations

enum  { RES_ODBC_SANITY_CHECK = (1 << 0), RES_ODBC_INDEPENDENT_CONNECTION = (1 << 1) }
 

Flags for use with.

More...
enum  odbc_status { ODBC_SUCCESS = 0, ODBC_FAIL = -1 }

Functions

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.
SQLHSTMT ast_odbc_direct_execute (struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data)
 Executes an non prepared statement and returns the resulting statement handle.
struct odbc_cache_columnsast_odbc_find_column (struct odbc_cache_tables *table, const char *colname)
 Find a column entry within a cached table structure.
struct odbc_cache_tablesast_odbc_find_table (const char *database, const char *tablename)
 Find or create an entry describing the table specified.
SQLHSTMT ast_odbc_prepare_and_execute (struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
 Prepares, executes, and returns the resulting statement handle.
void ast_odbc_release_obj (struct odbc_obj *obj)
 Releases an ODBC object previously allocated by odbc_request_obj().
struct odbc_objast_odbc_request_obj (const char *name, int check)
struct odbc_objast_odbc_request_obj2 (const char *name, struct ast_flags flags)
 Retrieves a connected ODBC object.
struct odbc_objast_odbc_retrieve_transaction_obj (struct ast_channel *chan, const char *objname)
 Retrieve a stored ODBC object, if a transaction has been started.
int ast_odbc_sanity_check (struct odbc_obj *obj)
 Checks an ODBC object to ensure it is still connected.
int ast_odbc_smart_execute (struct odbc_obj *obj, SQLHSTMT stmt)
 Executes a prepared statement handle.

Detailed Description

ODBC resource manager.

Definition in file res_odbc.h.


Define Documentation

#define ast_odbc_release_table ( ptr   )     if (ptr) { AST_RWLIST_UNLOCK(&(ptr)->columns); }

Release a table returned from ast_odbc_find_table.

Definition at line 212 of file res_odbc.h.

Referenced by update2_prepare(), and update_odbc().


Enumeration Type Documentation

anonymous enum

Flags for use with.

See also:
ast_odbc_request_obj2
Enumerator:
RES_ODBC_SANITY_CHECK 
RES_ODBC_INDEPENDENT_CONNECTION 

Definition at line 39 of file res_odbc.h.

00039      {
00040    RES_ODBC_SANITY_CHECK = (1 << 0),
00041    RES_ODBC_INDEPENDENT_CONNECTION = (1 << 1),
00042 };

Enumerator:
ODBC_SUCCESS 
ODBC_FAIL 

Definition at line 36 of file res_odbc.h.


Function Documentation

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

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

Referenced by acf_odbc_read(), and cli_odbc_read().

00679 {
00680    SQLRETURN res;
00681 
00682    if (pmaxlen == 0) {
00683       if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
00684          ast_str_make_space(buf, *StrLen_or_Ind + 1);
00685       }
00686    } else if (pmaxlen > 0) {
00687       ast_str_make_space(buf, pmaxlen);
00688    }
00689    res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
00690    ast_str_update(*buf);
00691 
00692    return res;
00693 }

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

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

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

01048 {
01049    return obj->parent->backslash_is_escape;
01050 }

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

Remove a cache entry from memory.

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 551 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.

00552 {
00553    struct odbc_cache_tables *tableptr;
00554 
00555    AST_RWLIST_WRLOCK(&odbc_tables);
00556    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
00557       if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
00558          AST_LIST_REMOVE_CURRENT(list);
00559          destroy_table_cache(tableptr);
00560          break;
00561       }
00562    }
00563    AST_RWLIST_TRAVERSE_SAFE_END
00564    AST_RWLIST_UNLOCK(&odbc_tables);
00565    return tableptr ? 0 : -1;
00566 }

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

References ast_log(), LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), odbc_obj::tx, and odbc_obj::up.

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

00569 {
00570    int attempt;
00571    SQLHSTMT stmt;
00572 
00573    for (attempt = 0; attempt < 2; attempt++) {
00574       stmt = exec_cb(obj, data);
00575 
00576       if (stmt) {
00577          break;
00578       } else if (obj->tx) {
00579          ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n");
00580          break;
00581       } else {
00582          obj->up = 0;
00583          ast_log(LOG_WARNING, "SQL Exec Direct failed.  Attempting a reconnect...\n");
00584 
00585          odbc_obj_disconnect(obj);
00586          odbc_obj_connect(obj);
00587       }
00588    }
00589 
00590    return stmt;
00591 }

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

Find a column entry within a cached table structure.

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

Definition at line 540 of file res_odbc.c.

References AST_RWLIST_TRAVERSE, odbc_cache_tables::columns, odbc_class::list, and odbc_cache_columns::name.

Referenced by update2_prepare(), and update_odbc().

00541 {
00542    struct odbc_cache_columns *col;
00543    AST_RWLIST_TRAVERSE(&table->columns, col, list) {
00544       if (strcasecmp(col->name, colname) == 0) {
00545          return col;
00546       }
00547    }
00548    return NULL;
00549 }

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

Find or create an entry describing the table specified.

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

Definition at line 425 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, odbc_cache_columns::decimals, destroy_table_cache(), odbc_class::list, LOG_ERROR, LOG_WARNING, odbc_cache_columns::name, odbc_cache_columns::nullable, odbc_cache_columns::octetlen, odbc_cache_columns::radix, odbc_cache_columns::size, odbc_cache_tables::table, and odbc_cache_columns::type.

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

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

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

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

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

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

void ast_odbc_release_obj ( struct odbc_obj obj  ) 

Releases an ODBC object previously allocated by odbc_request_obj().

Parameters:
obj The ODBC object

Definition at line 1041 of file res_odbc.c.

References find_transaction(), and odbc_release_obj2().

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

01042 {
01043    struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
01044    odbc_release_obj2(obj, tx);
01045 }

struct odbc_obj* ast_odbc_request_obj ( const char *  name,
int  check 
) [read]

Definition at line 1331 of file res_odbc.c.

References ast_odbc_request_obj2(), and RES_ODBC_SANITY_CHECK.

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

01333 {
01334    struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
01335 #ifdef DEBUG_THREADS
01336    return _ast_odbc_request_obj2(name, flags, file, function, lineno);
01337 #else
01338    return ast_odbc_request_obj2(name, flags);
01339 #endif
01340 }

struct odbc_obj* ast_odbc_request_obj2 ( const char *  name,
struct ast_flags  flags 
) [read]

Retrieves a connected ODBC object.

Parameters:
name The name of the ODBC class for which a connection is needed.
flags Set of flags used to control which connection is returned.
Return values:
ODBC object
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 odbc_release_obj(), below.

Definition at line 1156 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_copy_string(), ast_log(), ast_mutex_init(), ast_odbc_sanity_check(), ast_test_flag, ast_tvdiff_sec(), ast_tvnow(), class_container, odbc_obj::con, odbc_class::count, EOR_TX, odbc_class::idlecheck, odbc_class::isolation, odbc_obj::last_used, odbc_obj::lock, LOG_WARNING, NO_TX, odbc_class::obj_container, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), odbc_obj::parent, RES_ODBC_INDEPENDENT_CONNECTION, RES_ODBC_SANITY_CHECK, USE_TX, and odbc_obj::used.

Referenced by acf_transaction_write(), and ast_odbc_request_obj().

01158 {
01159    struct odbc_obj *obj = NULL;
01160    struct odbc_class *class;
01161    SQLINTEGER nativeerror=0, numfields=0;
01162    SQLSMALLINT diagbytes=0, i;
01163    unsigned char state[10], diagnostic[256];
01164 
01165    if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
01166       return NULL;
01167    }
01168 
01169    ast_assert(ao2_ref(class, 0) > 1);
01170 
01171    if (class->haspool) {
01172       /* Recycle connections before building another */
01173       obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX);
01174 
01175       if (obj) {
01176          ast_assert(ao2_ref(obj, 0) > 1);
01177       }
01178 
01179       if (!obj && (class->count < class->limit)) {
01180          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
01181          if (!obj) {
01182             ao2_ref(class, -1);
01183             return NULL;
01184          }
01185          ast_assert(ao2_ref(obj, 0) == 1);
01186          ast_mutex_init(&obj->lock);
01187          /* obj inherits the outstanding reference to class */
01188          obj->parent = class;
01189          class = NULL;
01190          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01191             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01192             ao2_ref(obj, -1);
01193             ast_assert(ao2_ref(class, 0) > 0);
01194             obj = NULL;
01195          } else {
01196             obj->used = 1;
01197             ao2_link(obj->parent->obj_container, obj);
01198             ast_atomic_fetchadd_int(&obj->parent->count, +1);
01199          }
01200       } else {
01201          /* Object is not constructed, so delete outstanding reference to class. */
01202          ao2_ref(class, -1);
01203          class = NULL;
01204       }
01205 
01206       if (obj && ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
01207          /* Ensure this connection has autocommit turned off. */
01208          if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
01209             SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01210             for (i = 0; i < numfields; i++) {
01211                SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01212                ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01213                if (i > 10) {
01214                   ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01215                   break;
01216                }
01217             }
01218          }
01219       }
01220    } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
01221       /* Non-pooled connections -- but must use a separate connection handle */
01222       if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) {
01223          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
01224          if (!obj) {
01225             ao2_ref(class, -1);
01226             return NULL;
01227          }
01228          ast_mutex_init(&obj->lock);
01229          /* obj inherits the outstanding reference to class */
01230          obj->parent = class;
01231          class = NULL;
01232          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01233             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01234             ao2_ref(obj, -1);
01235             obj = NULL;
01236          } else {
01237             obj->used = 1;
01238             ao2_link(obj->parent->obj_container, obj);
01239             ast_atomic_fetchadd_int(&obj->parent->count, +1);
01240          }
01241       }
01242 
01243       if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
01244          SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01245          for (i = 0; i < numfields; i++) {
01246             SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01247             ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01248             if (i > 10) {
01249                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01250                break;
01251             }
01252          }
01253       }
01254    } else {
01255       /* Non-pooled connection: multiple modules can use the same connection. */
01256       if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, NO_TX))) {
01257          /* Object is not constructed, so delete outstanding reference to class. */
01258          ast_assert(ao2_ref(class, 0) > 1);
01259          ao2_ref(class, -1);
01260          class = NULL;
01261       } else {
01262          /* No entry: build one */
01263          if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) {
01264             ast_assert(ao2_ref(class, 0) > 1);
01265             ao2_ref(class, -1);
01266             return NULL;
01267          }
01268          ast_mutex_init(&obj->lock);
01269          /* obj inherits the outstanding reference to class */
01270          obj->parent = class;
01271          class = NULL;
01272          if (odbc_obj_connect(obj) == ODBC_FAIL) {
01273             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
01274             ao2_ref(obj, -1);
01275             obj = NULL;
01276          } else {
01277             ao2_link(obj->parent->obj_container, obj);
01278             ast_assert(ao2_ref(obj, 0) > 1);
01279          }
01280       }
01281 
01282       if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
01283          SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01284          for (i = 0; i < numfields; i++) {
01285             SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01286             ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
01287             if (i > 10) {
01288                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01289                break;
01290             }
01291          }
01292       }
01293    }
01294 
01295    /* Set the isolation property */
01296    if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
01297       SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
01298       for (i = 0; i < numfields; i++) {
01299          SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
01300          ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
01301          if (i > 10) {
01302             ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
01303             break;
01304          }
01305       }
01306    }
01307 
01308    if (obj && ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
01309       ast_odbc_sanity_check(obj);
01310    } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck)
01311       odbc_obj_connect(obj);
01312 
01313 #ifdef DEBUG_THREADS
01314    if (obj) {
01315       ast_copy_string(obj->file, file, sizeof(obj->file));
01316       ast_copy_string(obj->function, function, sizeof(obj->function));
01317       obj->lineno = lineno;
01318    }
01319 #endif
01320    ast_assert(class == NULL);
01321 
01322    if (obj) {
01323       ast_assert(ao2_ref(obj, 0) > 1);
01324    }
01325    return obj;
01326 }

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

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

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

Definition at line 1342 of file res_odbc.c.

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

Referenced by acf_odbc_write().

01343 {
01344    struct ast_datastore *txn_store;
01345    AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
01346    struct odbc_txn_frame *txn = NULL;
01347 
01348    if (!chan) {
01349       /* No channel == no transaction */
01350       return NULL;
01351    }
01352 
01353    ast_channel_lock(chan);
01354    if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
01355       oldlist = txn_store->data;
01356    } else {
01357       ast_channel_unlock(chan);
01358       return NULL;
01359    }
01360 
01361    AST_LIST_LOCK(oldlist);
01362    ast_channel_unlock(chan);
01363 
01364    AST_LIST_TRAVERSE(oldlist, txn, list) {
01365       if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) {
01366          AST_LIST_UNLOCK(oldlist);
01367          return txn->obj;
01368       }
01369    }
01370    AST_LIST_UNLOCK(oldlist);
01371    return NULL;
01372 }

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 695 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_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_request_obj2(), and handle_cli_odbc_show().

00696 {
00697    char *test_sql = "select 1";
00698    SQLHSTMT stmt;
00699    int res = 0;
00700 
00701    if (!ast_strlen_zero(obj->parent->sanitysql))
00702       test_sql = obj->parent->sanitysql;
00703 
00704    if (obj->up) {
00705       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00706       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00707          obj->up = 0;
00708       } else {
00709          res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
00710          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00711             obj->up = 0;
00712          } else {
00713             res = SQLExecute(stmt);
00714             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00715                obj->up = 0;
00716             }
00717          }
00718       }
00719       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00720    }
00721 
00722    if (!obj->up && !obj->tx) { /* Try to reconnect! */
00723       ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
00724       odbc_obj_disconnect(obj);
00725       odbc_obj_connect(obj);
00726    }
00727    return obj->up;
00728 }

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

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

00653 {
00654    int res = 0, i;
00655    SQLINTEGER nativeerror=0, numfields=0;
00656    SQLSMALLINT diagbytes=0;
00657    unsigned char state[10], diagnostic[256];
00658 
00659    res = SQLExecute(stmt);
00660    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00661       if (res == SQL_ERROR) {
00662          SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00663          for (i = 0; i < numfields; i++) {
00664             SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00665             ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00666             if (i > 10) {
00667                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00668                break;
00669             }
00670          }
00671       }
00672    } else
00673       obj->last_used = ast_tvnow();
00674    
00675    return res;
00676 }


Generated by  doxygen 1.6.2