#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(). | |
struct 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) __attribute__((deprecated)) |
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 396 of file res_odbc.c.
References odbc_obj::parent.
Referenced by realtime_multi_odbc(), and realtime_odbc().
00397 { 00398 return obj->parent->backslash_is_escape; 00399 }
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(), odbc_obj::last_used, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), and odbc_obj::up.
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 389 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().
00390 { 00391 /* For pooled connections, this frees the connection to be 00392 * reused. For non-pooled connections, it does nothing. */ 00393 obj->used = 0; 00394 }
struct odbc_obj* ast_odbc_request_obj | ( | const char * | name, | |
int | check | |||
) | [read] |
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 401 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, odbc_obj::last_used, 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().
00402 { 00403 struct odbc_obj *obj = NULL; 00404 struct odbc_class *class; 00405 00406 AST_LIST_LOCK(&odbc_list); 00407 AST_LIST_TRAVERSE(&odbc_list, class, list) { 00408 if (!strcmp(class->name, name)) 00409 break; 00410 } 00411 AST_LIST_UNLOCK(&odbc_list); 00412 00413 if (!class) 00414 return NULL; 00415 00416 AST_LIST_LOCK(&class->odbc_obj); 00417 if (class->haspool) { 00418 /* Recycle connections before building another */ 00419 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00420 if (! obj->used) { 00421 obj->used = 1; 00422 break; 00423 } 00424 } 00425 00426 if (!obj && (class->count < class->limit)) { 00427 class->count++; 00428 obj = ast_calloc(1, sizeof(*obj)); 00429 if (!obj) { 00430 AST_LIST_UNLOCK(&class->odbc_obj); 00431 return NULL; 00432 } 00433 ast_mutex_init(&obj->lock); 00434 obj->parent = class; 00435 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00436 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00437 ast_mutex_destroy(&obj->lock); 00438 free(obj); 00439 obj = NULL; 00440 class->count--; 00441 } else { 00442 obj->used = 1; 00443 AST_LIST_INSERT_TAIL(&class->odbc_obj, obj, list); 00444 } 00445 } 00446 } else { 00447 /* Non-pooled connection: multiple modules can use the same connection. */ 00448 AST_LIST_TRAVERSE(&class->odbc_obj, obj, list) { 00449 /* Non-pooled connection: if there is an entry, return it */ 00450 break; 00451 } 00452 00453 if (!obj) { 00454 /* No entry: build one */ 00455 obj = ast_calloc(1, sizeof(*obj)); 00456 if (!obj) { 00457 AST_LIST_UNLOCK(&class->odbc_obj); 00458 return NULL; 00459 } 00460 ast_mutex_init(&obj->lock); 00461 obj->parent = class; 00462 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00463 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00464 ast_mutex_destroy(&obj->lock); 00465 free(obj); 00466 obj = NULL; 00467 } else { 00468 AST_LIST_INSERT_HEAD(&class->odbc_obj, obj, list); 00469 } 00470 } 00471 } 00472 AST_LIST_UNLOCK(&class->odbc_obj); 00473 00474 if (obj && check) { 00475 ast_odbc_sanity_check(obj); 00476 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_ms(ast_tvnow(), obj->last_used) / 1000 > obj->parent->idlecheck) 00477 odbc_obj_connect(obj); 00478 00479 return obj; 00480 }
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(), 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 }