#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 400 of file res_odbc.c.
References odbc_class::backslash_is_escape, and odbc_obj::parent.
Referenced by realtime_multi_odbc(), and realtime_odbc().
00401 { 00402 return obj->parent->backslash_is_escape; 00403 }
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_tvnow(), LOG_WARNING, odbc_obj_connect(), and odbc_obj_disconnect().
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! Attempting a reconnect...\n", res); 00114 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00115 stmt = NULL; 00116 00117 obj->up = 0; 00118 /* 00119 * While this isn't the best way to try to correct an error, this won't automatically 00120 * fail when the statement handle invalidates. 00121 */ 00122 /* XXX Actually, it might, if we're using a non-pooled connection. Possible race here. XXX */ 00123 odbc_obj_disconnect(obj); 00124 odbc_obj_connect(obj); 00125 continue; 00126 } else 00127 obj->last_used = ast_tvnow(); 00128 break; 00129 } else { 00130 ast_log(LOG_WARNING, "SQL Prepare failed. Attempting a reconnect...\n"); 00131 odbc_obj_disconnect(obj); 00132 odbc_obj_connect(obj); 00133 } 00134 } 00135 00136 return stmt; 00137 }
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 393 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().
00394 { 00395 /* For pooled connections, this frees the connection to be 00396 * reused. For non-pooled connections, it does nothing. */ 00397 obj->used = 0; 00398 }
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 405 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().
00406 { 00407 struct odbc_obj *obj = NULL; 00408 struct odbc_class *class; 00409 00410 AST_LIST_LOCK(&odbc_list); 00411 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00412 if (!strcmp(class->name, name)) 00413 break; 00414 } 00415 AST_LIST_UNLOCK(&odbc_list); 00416 00417 if (!class) 00418 return NULL; 00419 00420 AST_LIST_LOCK(&class->odbc_obj); 00421 if (class->haspool) { 00422 /* Recycle connections before building another */ 00423 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00424 if (! obj->used) { 00425 obj->used = 1; 00426 break; 00427 } 00428 } 00429 00430 if (!obj && (class->count < class->limit)) { 00431 class->count++; 00432 obj = ast_calloc(1, sizeof(*obj)); 00433 if (!obj) { 00434 AST_LIST_UNLOCK(&class->odbc_obj); 00435 return NULL; 00436 } 00437 ast_mutex_init(&obj->lock); 00438 obj->parent = class; 00439 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00440 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00441 ast_mutex_destroy(&obj->lock); 00442 free(obj); 00443 obj = NULL; 00444 class->count--; 00445 } else { 00446 obj->used = 1; 00447 AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list); 00448 } 00449 } 00450 } else { 00451 /* Non-pooled connection: multiple modules can use the same connection. */ 00452 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00453 /* Non-pooled connection: if there is an entry, return it */ 00454 break; 00455 } 00456 00457 if (!obj) { 00458 /* No entry: build one */ 00459 obj = ast_calloc(1, sizeof(*obj)); 00460 if (!obj) { 00461 AST_LIST_UNLOCK(&class->odbc_obj); 00462 return NULL; 00463 } 00464 ast_mutex_init(&obj->lock); 00465 obj->parent = class; 00466 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00467 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00468 ast_mutex_destroy(&obj->lock); 00469 free(obj); 00470 obj = NULL; 00471 } else { 00472 AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list); 00473 } 00474 } 00475 } 00476 AST_LIST_UNLOCK(&class->odbc_obj); 00477 00478 if (obj && check) { 00479 ast_odbc_sanity_check(obj); 00480 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_ms(ast_tvnow(), obj->last_used) / 1000 > obj->parent->idlecheck) 00481 odbc_obj_connect(obj); 00482 00483 return obj; 00484 }
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 182 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().
00183 { 00184 char *test_sql = "select 1"; 00185 SQLHSTMT stmt; 00186 int res = 0; 00187 00188 if (obj->up) { 00189 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00190 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00191 obj->up = 0; 00192 } else { 00193 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00194 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00195 obj->up = 0; 00196 } else { 00197 res = SQLExecute(stmt); 00198 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00199 obj->up = 0; 00200 } 00201 } 00202 } 00203 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00204 } 00205 00206 if (!obj->up) { /* Try to reconnect! */ 00207 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00208 odbc_obj_disconnect(obj); 00209 odbc_obj_connect(obj); 00210 } 00211 return obj->up; 00212 }
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 139 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.
00140 { 00141 int res = 0, i; 00142 SQLINTEGER nativeerror=0, numfields=0; 00143 SQLSMALLINT diagbytes=0; 00144 unsigned char state[10], diagnostic[256]; 00145 00146 res = SQLExecute(stmt); 00147 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00148 if (res == SQL_ERROR) { 00149 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00150 for (i = 0; i < numfields; i++) { 00151 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00152 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00153 if (i > 10) { 00154 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00155 break; 00156 } 00157 } 00158 } 00159 #if 0 00160 /* This is a really bad method of trying to correct a dead connection. It 00161 * only ever really worked with MySQL. It will not work with any other 00162 * database, since most databases prepare their statements on the server, 00163 * and if you disconnect, you invalidate the statement handle. Hence, if 00164 * you disconnect, you're going to fail anyway, whether you try to execute 00165 * a second time or not. 00166 */ 00167 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00168 ast_mutex_lock(&obj->lock); 00169 obj->up = 0; 00170 ast_mutex_unlock(&obj->lock); 00171 odbc_obj_disconnect(obj); 00172 odbc_obj_connect(obj); 00173 res = SQLExecute(stmt); 00174 #endif 00175 } else 00176 obj->last_used = ast_tvnow(); 00177 00178 return res; 00179 }