#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
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(). | |
odbc_obj * | ast_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. |
Definition in file res_odbc.h.
enum odbc_status |
int ast_odbc_backslash_is_escape | ( | struct odbc_obj * | obj | ) |
Checks if the database natively supports backslash as an escape character.
obj | The ODBC object |
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.
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. |
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().
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 | |||
) |
Retrieves a connected ODBC object.
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. |
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, 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.
obj | The ODBC object |
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.
obj | The non-NULL result of odbc_request_obj() | |
stmt | The prepared statement handle |
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 }