Thu Oct 11 06:44:16 2012

Asterisk developer's documentation


res_odbc.h File Reference

ODBC resource manager. More...

#include <sql.h>
#include <sqlext.h>
#include <sqltypes.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  odbc_obj

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


Enumeration Type Documentation

Enumerator:
ODBC_SUCCESS 
ODBC_FAIL 

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

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

Referenced by realtime_multi_odbc(), and realtime_odbc().

00395 {
00396    return obj->parent->backslash_is_escape;
00397 }

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.
Returns:
Returns a statement handle or NULL on error.

Definition at line 82 of file res_odbc.c.

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

Referenced by acf_odbc_read(), acf_odbc_write(), config_odbc(), realtime_multi_odbc(), realtime_odbc(), and update_odbc().

00083 {
00084    int res = 0, i, attempt;
00085    SQLINTEGER nativeerror=0, numfields=0;
00086    SQLSMALLINT diagbytes=0;
00087    unsigned char state[10], diagnostic[256];
00088    SQLHSTMT stmt;
00089 
00090    for (attempt = 0; attempt < 2; attempt++) {
00091       /* This prepare callback may do more than just prepare -- it may also
00092        * bind parameters, bind results, etc.  The real key, here, is that
00093        * when we disconnect, all handles become invalid for most databases.
00094        * We must therefore redo everything when we establish a new
00095        * connection. */
00096       stmt = prepare_cb(obj, data);
00097 
00098       if (stmt) {
00099          res = SQLExecute(stmt);
00100          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00101             if (res == SQL_ERROR) {
00102                SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00103                for (i = 0; i < numfields; i++) {
00104                   SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00105                   ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00106                   if (i > 10) {
00107                      ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00108                      break;
00109                   }
00110                }
00111             }
00112 
00113             ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn);
00114             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00115             stmt = NULL;
00116 
00117             if (!ast_odbc_sanity_check(obj)) {
00118                break;
00119             }
00120             continue;
00121          } else
00122             obj->last_used = ast_tvnow();
00123          break;
00124       } else {
00125          ast_log(LOG_WARNING, "SQL Prepare failed.  Verifying connection to %s [%s]\n", obj->parent->name, obj->parent->dsn);
00126          ast_odbc_sanity_check(obj);
00127       }
00128    }
00129 
00130    return stmt;
00131 }

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

References odbc_obj::used.

Referenced by acf_odbc_read(), acf_odbc_write(), config_odbc(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), and update_odbc().

00388 {
00389    /* For pooled connections, this frees the connection to be
00390     * reused.  For non-pooled connections, it does nothing. */
00391    obj->used = 0;
00392 }

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

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.
Returns:
Returns an ODBC object or 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 399 of file res_odbc.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_odbc_sanity_check(), ast_tvdiff_ms(), ast_tvnow(), free, odbc_class::idlecheck, odbc_obj::last_used, odbc_class::list, odbc_obj::lock, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), odbc_obj::parent, and odbc_obj::used.

Referenced by acf_odbc_read(), acf_odbc_write(), config_odbc(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), and update_odbc().

00400 {
00401    struct odbc_obj *obj = NULL;
00402    struct odbc_class *class;
00403 
00404    AST_LIST_LOCK(&odbc_list);
00405    AST_LIST_TRAVERSE(&odbc_list, class, list) {
00406       if (!strcmp(class->name, name))
00407          break;
00408    }
00409    AST_LIST_UNLOCK(&odbc_list);
00410 
00411    if (!class)
00412       return NULL;
00413 
00414    AST_LIST_LOCK(&class->odbc_obj);
00415    if (class->haspool) {
00416       /* Recycle connections before building another */
00417       AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) {
00418          if (! obj->used) {
00419             obj->used = 1;
00420             break;
00421          }
00422       }
00423 
00424       if (!obj && (class->count < class->limit)) {
00425          class->count++;
00426          obj = ast_calloc(1, sizeof(*obj));
00427          if (!obj) {
00428             AST_LIST_UNLOCK(&class->odbc_obj);
00429             return NULL;
00430          }
00431          ast_mutex_init(&obj->lock);
00432          obj->parent = class;
00433          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00434             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00435             ast_mutex_destroy(&obj->lock);
00436             free(obj);
00437             obj = NULL;
00438             class->count--;
00439          } else {
00440             obj->used = 1;
00441             AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list);
00442          }
00443       }
00444    } else {
00445       /* Non-pooled connection: multiple modules can use the same connection. */
00446       AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) {
00447          /* Non-pooled connection: if there is an entry, return it */
00448          break;
00449       }
00450 
00451       if (!obj) {
00452          /* No entry: build one */
00453          obj = ast_calloc(1, sizeof(*obj));
00454          if (!obj) {
00455             AST_LIST_UNLOCK(&class->odbc_obj);
00456             return NULL;
00457          }
00458          ast_mutex_init(&obj->lock);
00459          obj->parent = class;
00460          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00461             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00462             ast_mutex_destroy(&obj->lock);
00463             free(obj);
00464             obj = NULL;
00465          } else {
00466             AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list);
00467          }
00468       }
00469    }
00470    AST_LIST_UNLOCK(&class->odbc_obj);
00471 
00472    if (obj && check) {
00473       ast_odbc_sanity_check(obj);
00474    } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_ms(ast_tvnow(), obj->last_used) / 1000 > obj->parent->idlecheck)
00475       odbc_obj_connect(obj);
00476 
00477    return obj;
00478 }

int ast_odbc_sanity_check ( struct odbc_obj obj  ) 

Checks an ODBC object to ensure it is still connected.

Parameters:
obj The ODBC object
Returns:
Returns 0 if connected, -1 otherwise.

Definition at line 176 of file res_odbc.c.

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

Referenced by ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), and odbc_show_command().

00177 {
00178    char *test_sql = "select 1";
00179    SQLHSTMT stmt;
00180    int res = 0;
00181 
00182    if (obj->up) {
00183       res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00184       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00185          obj->up = 0;
00186       } else {
00187          res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
00188          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00189             obj->up = 0;
00190          } else {
00191             res = SQLExecute(stmt);
00192             if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00193                obj->up = 0;
00194             }
00195          }
00196       }
00197       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00198    }
00199 
00200    if (!obj->up) { /* Try to reconnect! */
00201       ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
00202       odbc_obj_disconnect(obj);
00203       odbc_obj_connect(obj);
00204    }
00205    return obj->up;
00206 }

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
Returns:
Returns 0 on success or -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 133 of file res_odbc.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvnow(), odbc_obj::last_used, odbc_obj::lock, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), and odbc_obj::up.

00134 {
00135    int res = 0, i;
00136    SQLINTEGER nativeerror=0, numfields=0;
00137    SQLSMALLINT diagbytes=0;
00138    unsigned char state[10], diagnostic[256];
00139 
00140    res = SQLExecute(stmt);
00141    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
00142       if (res == SQL_ERROR) {
00143          SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
00144          for (i = 0; i < numfields; i++) {
00145             SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
00146             ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
00147             if (i > 10) {
00148                ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
00149                break;
00150             }
00151          }
00152       }
00153 #if 0
00154       /* This is a really bad method of trying to correct a dead connection.  It
00155        * only ever really worked with MySQL.  It will not work with any other
00156        * database, since most databases prepare their statements on the server,
00157        * and if you disconnect, you invalidate the statement handle.  Hence, if
00158        * you disconnect, you're going to fail anyway, whether you try to execute
00159        * a second time or not.
00160        */
00161       ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
00162       ast_mutex_lock(&obj->lock);
00163       obj->up = 0;
00164       ast_mutex_unlock(&obj->lock);
00165       odbc_obj_disconnect(obj);
00166       odbc_obj_connect(obj);
00167       res = SQLExecute(stmt);
00168 #endif
00169    } else
00170       obj->last_used = ast_tvnow();
00171    
00172    return res;
00173 }


Generated on Thu Oct 11 06:44:16 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6