Wed Aug 18 22:34:31 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"

Go to the source code of this file.

Data Structures

struct  odbc_cache_columns
 These aren't used in any API calls, but they are kept in a common location, simply for convenience and to avoid duplication. More...
struct  odbc_cache_tables
struct  odbc_cache_tables::_columns
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  odbc_status { ODBC_SUCCESS = 0, ODBC_FAIL = -1 }

Functions

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.
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 odbc_request_obj().
odbc_objast_odbc_request_obj (const char *name, int check)
 Retrieves a connected ODBC object.
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 187 of file res_odbc.h.

Referenced by update_odbc().


Enumeration Type Documentation

enum odbc_status

Enumerator:
ODBC_SUCCESS 
ODBC_FAIL 

Definition at line 35 of file res_odbc.h.


Function Documentation

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 659 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().

00660 {
00661    return obj->parent->backslash_is_escape;
00662 }

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)
table 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 254 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.

00255 {
00256    struct odbc_cache_tables *tableptr;
00257 
00258    AST_RWLIST_WRLOCK(&odbc_tables);
00259    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
00260       if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
00261          AST_LIST_REMOVE_CURRENT(list);
00262          destroy_table_cache(tableptr);
00263          break;
00264       }
00265    }
00266    AST_RWLIST_TRAVERSE_SAFE_END
00267    AST_RWLIST_UNLOCK(&odbc_tables);
00268    return tableptr ? 0 : -1;
00269 }

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

References ast_log(), LOG_WARNING, odbc_obj_connect(), and odbc_obj_disconnect().

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

00272 {
00273    int attempt;
00274    SQLHSTMT stmt;
00275 
00276    for (attempt = 0; attempt < 2; attempt++) {
00277       stmt = exec_cb(obj, data);
00278 
00279       if (stmt) {
00280          break;
00281       } else {
00282          obj->up = 0;
00283          ast_log(LOG_WARNING, "SQL Exec Direct failed.  Attempting a reconnect...\n");
00284 
00285          odbc_obj_disconnect(obj);
00286          odbc_obj_connect(obj);
00287       }
00288    }
00289 
00290    return stmt;
00291 }

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

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

Referenced by update_odbc().

00244 {
00245    struct odbc_cache_columns *col;
00246    AST_RWLIST_TRAVERSE(&table->columns, col, list) {
00247       if (strcasecmp(col->name, colname) == 0) {
00248          return col;
00249       }
00250    }
00251    return NULL;
00252 }

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

Find or create an entry describing the table specified.

Parameters:
obj An active ODBC handle on which to query the table
table 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.

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

00130 {
00131    struct odbc_cache_tables *tableptr;
00132    struct odbc_cache_columns *entry;
00133    char columnname[80];
00134    SQLLEN sqlptr;
00135    SQLHSTMT stmt = NULL;
00136    int res = 0, error = 0, try = 0;
00137    struct odbc_obj *obj = ast_odbc_request_obj(database, 0);
00138 
00139    AST_RWLIST_RDLOCK(&odbc_tables);
00140    AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) {
00141       if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
00142          break;
00143       }
00144    }
00145    if (tableptr) {
00146       AST_RWLIST_RDLOCK(&tableptr->columns);
00147       AST_RWLIST_UNLOCK(&odbc_tables);
00148       if (obj) {
00149          ast_odbc_release_obj(obj);
00150       }
00151       return tableptr;
00152    }
00153 
00154    if (!obj) {
00155       ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
00156       return NULL;
00157    }
00158 
00159    /* Table structure not already cached; build it now. */
00160    do {
00161 retry:
00162       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00163       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00164          if (try == 0) {
00165             try = 1;
00166             ast_odbc_sanity_check(obj);
00167             goto retry;
00168          }
00169          ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
00170          break;
00171       }
00172 
00173       res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS);
00174       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00175          if (try == 0) {
00176             try = 1;
00177             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00178             ast_odbc_sanity_check(obj);
00179             goto retry;
00180          }
00181          ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
00182          break;
00183       }
00184 
00185       if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
00186          ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
00187          break;
00188       }
00189 
00190       tableptr->connection = (char *)tableptr + sizeof(*tableptr);
00191       tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1;
00192       strcpy(tableptr->connection, database); /* SAFE */
00193       strcpy(tableptr->table, tablename); /* SAFE */
00194       AST_RWLIST_HEAD_INIT(&(tableptr->columns));
00195 
00196       while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
00197          SQLGetData(stmt,  4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
00198 
00199          if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) {
00200             ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
00201             error = 1;
00202             break;
00203          }
00204          entry->name = (char *)entry + sizeof(*entry);
00205          strcpy(entry->name, columnname);
00206 
00207          SQLGetData(stmt,  5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
00208          SQLGetData(stmt,  7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
00209          SQLGetData(stmt,  9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
00210          SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
00211          SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
00212          SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
00213 
00214          /* Specification states that the octenlen should be the maximum number of bytes
00215           * returned in a char or binary column, but it seems that some drivers just set
00216           * it to NULL. (Bad Postgres! No biscuit!) */
00217          if (entry->octetlen == 0) {
00218             entry->octetlen = entry->size;
00219          }
00220 
00221          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);
00222          /* Insert column info into column list */
00223          AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
00224       }
00225       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00226 
00227       AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
00228       AST_RWLIST_RDLOCK(&(tableptr->columns));
00229    } while (0);
00230 
00231    AST_RWLIST_UNLOCK(&odbc_tables);
00232 
00233    if (error) {
00234       destroy_table_cache(tableptr);
00235       tableptr = NULL;
00236    }
00237    if (obj) {
00238       ast_odbc_release_obj(obj);
00239    }
00240    return tableptr;
00241 }

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 293 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(), and update_odbc().

00294 {
00295    int res = 0, i, attempt;
00296    SQLINTEGER nativeerror=0, numfields=0;
00297    SQLSMALLINT diagbytes=0;
00298    unsigned char state[10], diagnostic[256];
00299    SQLHSTMT stmt;
00300 
00301    for (attempt = 0; attempt < 2; attempt++) {
00302       /* This prepare callback may do more than just prepare -- it may also
00303        * bind parameters, bind results, etc.  The real key, here, is that
00304        * when we disconnect, all handles become invalid for most databases.
00305        * We must therefore redo everything when we establish a new
00306        * connection. */
00307       stmt = prepare_cb(obj, data);
00308 
00309       if (stmt) {
00310          res = SQLExecute(stmt);
00311          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00312             if (res == SQL_ERROR) {
00313                SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00314                for (i = 0; i < numfields; i++) {
00315                   SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00316                   ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00317                   if (i > 10) {
00318                      ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00319                      break;
00320                   }
00321                }
00322             }
00323 
00324             ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
00325             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00326             stmt = NULL;
00327 
00328             obj->up = 0;
00329             /*
00330              * While this isn't the best way to try to correct an error, this won't automatically
00331              * fail when the statement handle invalidates.
00332              */
00333             ast_odbc_sanity_check(obj);
00334             continue;
00335          } else
00336             obj->last_used = ast_tvnow();
00337          break;
00338       } else if (attempt == 0)
00339          ast_odbc_sanity_check(obj);
00340    }
00341 
00342    return stmt;
00343 }

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

References ao2_ref, and odbc_obj::used.

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

00647 {
00648    /* For pooled connections, this frees the connection to be
00649     * reused.  For non-pooled connections, it does nothing. */
00650    obj->used = 0;
00651 #ifdef DEBUG_THREADS
00652    obj->file[0] = '\0';
00653    obj->function[0] = '\0';
00654    obj->lineno = 0;
00655 #endif
00656    ao2_ref(obj, -1);
00657 }

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

Retrieves a connected ODBC object.

Parameters:
name The name of the ODBC class for which a connection is needed.
check Whether to ensure that a connection is valid before returning the handle. Usually unnecessary.
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 667 of file res_odbc.c.

References ao2_alloc, ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_assert, ast_copy_string(), ast_log(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_odbc_sanity_check(), ast_tvdiff_sec(), ast_tvnow(), class_container, odbc_class::idlecheck, odbc_obj::last_used, LOG_WARNING, ao2_iterator::obj, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), and odbc_obj::parent.

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(), and update_odbc().

00669 {
00670    struct odbc_obj *obj = NULL;
00671    struct odbc_class *class;
00672    struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
00673 
00674    while ((class = ao2_iterator_next(&aoi))) {
00675       if (!strcmp(class->name, name) && !class->delme) {
00676          break;
00677       }
00678       ao2_ref(class, -1);
00679    }
00680 
00681    if (!class)
00682       return NULL;
00683 
00684    ast_assert(ao2_ref(class, 0) > 1);
00685 
00686    if (class->haspool) {
00687       /* Recycle connections before building another */
00688       aoi = ao2_iterator_init(class->obj_container, 0);
00689       while ((obj = ao2_iterator_next(&aoi))) {
00690          if (! obj->used) {
00691             ast_mutex_lock(&obj->lock);
00692             obj->used = 1;
00693             ast_mutex_unlock(&obj->lock);
00694             break;
00695          }
00696          ao2_ref(obj, -1);
00697       }
00698 
00699       if (obj) {
00700          ast_assert(ao2_ref(obj, 0) > 1);
00701       }
00702 
00703       if (!obj && (class->count < class->limit)) {
00704          class->count++;
00705          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
00706          if (!obj) {
00707             ao2_ref(class, -1);
00708             return NULL;
00709          }
00710          ast_assert(ao2_ref(obj, 0) == 1);
00711          ast_mutex_init(&obj->lock);
00712          /* obj inherits the outstanding reference to class */
00713          obj->parent = class;
00714          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00715             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00716             ao2_ref(obj, -1);
00717             ast_assert(ao2_ref(class, 0) > 0);
00718             obj = NULL;
00719          } else {
00720             obj->used = 1;
00721             ao2_link(class->obj_container, obj);
00722          }
00723          class = NULL;
00724       } else {
00725          /* Object is not constructed, so delete outstanding reference to class. */
00726          ao2_ref(class, -1);
00727          class = NULL;
00728       }
00729    } else {
00730       /* Non-pooled connection: multiple modules can use the same connection. */
00731       aoi = ao2_iterator_init(class->obj_container, 0);
00732       while ((obj = ao2_iterator_next(&aoi))) {
00733          /* Non-pooled connection: if there is an entry, return it */
00734          break;
00735       }
00736 
00737       if (obj) {
00738          /* Object is not constructed, so delete outstanding reference to class. */
00739          ast_assert(ao2_ref(class, 0) > 1);
00740          ao2_ref(class, -1);
00741          class = NULL;
00742       } else {
00743          /* No entry: build one */
00744          obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
00745          if (!obj) {
00746             ast_assert(ao2_ref(class, 0) > 1);
00747             ao2_ref(class, -1);
00748             return NULL;
00749          }
00750          ast_mutex_init(&obj->lock);
00751          /* obj inherits the outstanding reference to class */
00752          obj->parent = class;
00753          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00754             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00755             ao2_ref(obj, -1);
00756             obj = NULL;
00757          } else {
00758             ao2_link(class->obj_container, obj);
00759             ast_assert(ao2_ref(obj, 0) > 1);
00760          }
00761          class = NULL;
00762       }
00763    }
00764 
00765    if (obj && check) {
00766       ast_odbc_sanity_check(obj);
00767    } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck)
00768       odbc_obj_connect(obj);
00769 
00770 #ifdef DEBUG_THREADS
00771    if (obj) {
00772       ast_copy_string(obj->file, file, sizeof(obj->file));
00773       ast_copy_string(obj->function, function, sizeof(obj->function));
00774       obj->lineno = lineno;
00775    }
00776 #endif
00777    ast_assert(class == NULL);
00778 
00779    if (obj) {
00780       ast_assert(ao2_ref(obj, 0) > 1);
00781    }
00782    return obj;
00783 }

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 372 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, and odbc_obj::up.

Referenced by ast_odbc_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), and handle_cli_odbc_show().

00373 {
00374    char *test_sql = "select 1";
00375    SQLHSTMT stmt;
00376    int res = 0;
00377 
00378    if (!ast_strlen_zero(obj->parent->sanitysql))
00379       test_sql = obj->parent->sanitysql;
00380 
00381    if (obj->up) {
00382       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00383       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00384          obj->up = 0;
00385       } else {
00386          res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
00387          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00388             obj->up = 0;
00389          } else {
00390             res = SQLExecute(stmt);
00391             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00392                obj->up = 0;
00393             }
00394          }
00395       }
00396       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00397    }
00398 
00399    if (!obj->up) { /* Try to reconnect! */
00400       ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
00401       odbc_obj_disconnect(obj);
00402       odbc_obj_connect(obj);
00403    }
00404    return obj->up;
00405 }

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

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

00346 {
00347    int res = 0, i;
00348    SQLINTEGER nativeerror=0, numfields=0;
00349    SQLSMALLINT diagbytes=0;
00350    unsigned char state[10], diagnostic[256];
00351 
00352    res = SQLExecute(stmt);
00353    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00354       if (res == SQL_ERROR) {
00355          SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00356          for (i = 0; i < numfields; i++) {
00357             SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00358             ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00359             if (i > 10) {
00360                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00361                break;
00362             }
00363          }
00364       }
00365    } else
00366       obj->last_used = ast_tvnow();
00367    
00368    return res;
00369 }


Generated on Wed Aug 18 22:34:32 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7