Mon May 14 04:52:38 2007

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

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.


Enumeration Type Documentation

enum odbc_status

Enumerator:
ODBC_SUCCESS 
ODBC_FAIL 

Definition at line 34 of file res_odbc.h.


Function Documentation

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 78 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 config_odbc().

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

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

References odbc_obj::used.

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

00375 {
00376    /* For pooled connections, this frees the connection to be
00377     * reused.  For non-pooled connections, it does nothing. */
00378    obj->used = 0;
00379 }

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.
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 381 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(), free, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), 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().

00382 {
00383    struct odbc_obj *obj = NULL;
00384    struct odbc_class *class;
00385 
00386    AST_LIST_LOCK(&odbc_list);
00387    AST_LIST_TRAVERSE(&odbc_list, class, list) {
00388       if (!strcmp(class->name, name))
00389          break;
00390    }
00391    AST_LIST_UNLOCK(&odbc_list);
00392 
00393    if (!class)
00394       return NULL;
00395 
00396    AST_LIST_LOCK(&class->odbc_obj);
00397    if (class->haspool) {
00398       /* Recycle connections before building another */
00399       AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) {
00400          if (! obj->used) {
00401             obj->used = 1;
00402             break;
00403          }
00404       }
00405 
00406       if (!obj && (class->count < class->limit)) {
00407          class->count++;
00408          obj = ast_calloc(1, sizeof(*obj));
00409          if (!obj) {
00410             AST_LIST_UNLOCK(&class->odbc_obj);
00411             return NULL;
00412          }
00413          ast_mutex_init(&obj->lock);
00414          obj->parent = class;
00415          odbc_obj_connect(obj);
00416          AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list);
00417       }
00418    } else {
00419       /* Non-pooled connection: multiple modules can use the same connection. */
00420       AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) {
00421          /* Non-pooled connection: if there is an entry, return it */
00422          break;
00423       }
00424 
00425       if (!obj) {
00426          /* No entry: build one */
00427          obj = ast_calloc(1, sizeof(*obj));
00428          if (!obj) {
00429             AST_LIST_UNLOCK(&class->odbc_obj);
00430             return NULL;
00431          }
00432          ast_mutex_init(&obj->lock);
00433          obj->parent = class;
00434          if (odbc_obj_connect(obj) == ODBC_FAIL) {
00435             ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
00436             ast_mutex_destroy(&obj->lock);
00437             free(obj);
00438             obj = NULL;
00439          } else {
00440             AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list);
00441          }
00442       }
00443    }
00444    AST_LIST_UNLOCK(&class->odbc_obj);
00445 
00446    if (obj && check) {
00447       ast_odbc_sanity_check(obj);
00448    }
00449    return obj;
00450 }

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

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

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

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


Generated on Mon May 14 04:52:39 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1