#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_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 |
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 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().
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.
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 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.
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_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 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 }