#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include "asterisk/linkedlists.h"
#include "asterisk/strings.h"
Go to the source code of this file.
Data Structures | |
struct | odbc_cache_columns |
These structures are used for adaptive capabilities. More... | |
struct | odbc_cache_tables |
struct | odbc_cache_tables::_columns |
struct | odbc_obj |
ODBC container. More... | |
Defines | |
#define | ast_odbc_release_table(ptr) if (ptr) { AST_RWLIST_UNLOCK(&(ptr)->columns); } |
Release a table returned from ast_odbc_find_table. | |
#define | ast_odbc_request_obj(a, b) _ast_odbc_request_obj(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__) |
#define | ast_odbc_request_obj2(a, b) _ast_odbc_request_obj2(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__) |
Enumerations | |
enum | { RES_ODBC_SANITY_CHECK = (1 << 0), RES_ODBC_INDEPENDENT_CONNECTION = (1 << 1), RES_ODBC_CONNECTED = (1 << 2) } |
Flags for use with. More... | |
enum | odbc_status { ODBC_SUCCESS = 0, ODBC_FAIL = -1 } |
Functions | |
odbc_obj * | _ast_odbc_request_obj (const char *name, int check, const char *file, const char *function, int lineno) |
odbc_obj * | _ast_odbc_request_obj2 (const char *name, struct ast_flags flags, const char *file, const char *function, int lineno) |
Retrieves a connected ODBC object. | |
SQLRETURN | ast_odbc_ast_str_SQLGetData (struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind) |
Wrapper for SQLGetData to use with dynamic strings. | |
int | ast_odbc_backslash_is_escape (struct odbc_obj *obj) |
Checks if the database natively supports backslash as an escape character. | |
int | ast_odbc_clear_cache (const char *database, const char *tablename) |
Remove a cache entry from memory This function may be called to clear entries created and cached by the ast_odbc_find_table() API call. | |
SQLHSTMT | ast_odbc_direct_execute (struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data) |
Executes an non prepared statement and returns the resulting statement handle. | |
odbc_cache_columns * | ast_odbc_find_column (struct odbc_cache_tables *table, const char *colname) |
Find a column entry within a cached table structure. | |
odbc_cache_tables * | ast_odbc_find_table (const char *database, const char *tablename) |
Find or create an entry describing the table specified. | |
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 ast_odbc_request_obj(). | |
odbc_obj * | ast_odbc_retrieve_transaction_obj (struct ast_channel *chan, const char *objname) |
Retrieve a stored ODBC object, if a transaction has been started. | |
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.
#define ast_odbc_release_table | ( | ptr | ) | if (ptr) { AST_RWLIST_UNLOCK(&(ptr)->columns); } |
Release a table returned from ast_odbc_find_table.
Definition at line 213 of file res_odbc.h.
Referenced by update2_prepare(), and update_odbc().
#define ast_odbc_request_obj | ( | a, | |||
b | ) | _ast_odbc_request_obj(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__) |
Definition at line 123 of file res_odbc.h.
Referenced by acf_odbc_read(), acf_odbc_write(), ast_odbc_find_table(), load_config(), odbc_log(), odbc_register_class(), and update2_odbc().
#define ast_odbc_request_obj2 | ( | a, | |||
b | ) | _ast_odbc_request_obj2(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__) |
Definition at line 122 of file res_odbc.h.
Referenced by acf_transaction_write(), config_odbc(), destroy_odbc(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().
anonymous enum |
Flags for use with.
Definition at line 39 of file res_odbc.h.
00039 { 00040 RES_ODBC_SANITY_CHECK = (1 << 0), 00041 RES_ODBC_INDEPENDENT_CONNECTION = (1 << 1), 00042 RES_ODBC_CONNECTED = (1 << 2), 00043 };
enum odbc_status |
struct odbc_obj* _ast_odbc_request_obj | ( | const char * | name, | |
int | check, | |||
const char * | file, | |||
const char * | function, | |||
int | lineno | |||
) |
Definition at line 1382 of file res_odbc.c.
References _ast_odbc_request_obj2(), ast_flags::flags, and RES_ODBC_SANITY_CHECK.
01383 { 01384 struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 }; 01385 return _ast_odbc_request_obj2(name, flags, file, function, lineno); 01386 }
struct odbc_obj* _ast_odbc_request_obj2 | ( | const char * | name, | |
struct ast_flags | flags, | |||
const char * | file, | |||
const char * | function, | |||
int | lineno | |||
) |
Retrieves a connected ODBC object.
name | The name of the ODBC class for which a connection is needed. | |
flags | One or more of the following flags:
|
NULL | if there is no connection available with the requested name. |
Definition at line 1199 of file res_odbc.c.
References ao2_alloc, ao2_callback, ao2_link, ao2_ref, aoro2_class_cb(), aoro2_obj_cb(), ast_assert, ast_atomic_fetchadd_int(), ast_debug, ast_log(), ast_mutex_init, ast_test_flag, class_container, odbc_obj::con, EOR_TX, LOG_WARNING, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), RES_ODBC_INDEPENDENT_CONNECTION, and USE_TX.
Referenced by _ast_odbc_request_obj().
01200 { 01201 struct odbc_obj *obj = NULL; 01202 struct odbc_class *class; 01203 SQLINTEGER nativeerror=0, numfields=0; 01204 SQLSMALLINT diagbytes=0, i; 01205 unsigned char state[10], diagnostic[256]; 01206 01207 if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) { 01208 ast_debug(1, "Class '%s' not found!\n", name); 01209 return NULL; 01210 } 01211 01212 ast_assert(ao2_ref(class, 0) > 1); 01213 01214 if (class->haspool) { 01215 /* Recycle connections before building another */ 01216 obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX); 01217 01218 if (obj) { 01219 ast_assert(ao2_ref(obj, 0) > 1); 01220 } 01221 if (!obj && (class->count < class->limit) && 01222 (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) { 01223 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 01224 if (!obj) { 01225 class->count--; 01226 ao2_ref(class, -1); 01227 ast_debug(3, "Unable to allocate object\n"); 01228 return NULL; 01229 } 01230 ast_assert(ao2_ref(obj, 0) == 1); 01231 ast_mutex_init(&obj->lock); 01232 /* obj inherits the outstanding reference to class */ 01233 obj->parent = class; 01234 class = NULL; 01235 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01236 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01237 ao2_ref(obj, -1); 01238 ast_assert(ao2_ref(class, 0) > 0); 01239 obj = NULL; 01240 } else { 01241 obj->used = 1; 01242 ao2_link(obj->parent->obj_container, obj); 01243 ast_atomic_fetchadd_int(&obj->parent->count, +1); 01244 } 01245 } else { 01246 /* Object is not constructed, so delete outstanding reference to class. */ 01247 ao2_ref(class, -1); 01248 class = NULL; 01249 } 01250 01251 if (obj && ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { 01252 /* Ensure this connection has autocommit turned off. */ 01253 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { 01254 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01255 for (i = 0; i < numfields; i++) { 01256 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01257 ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01258 if (i > 10) { 01259 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01260 break; 01261 } 01262 } 01263 } 01264 } 01265 } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { 01266 /* Non-pooled connections -- but must use a separate connection handle */ 01267 if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) { 01268 ast_debug(1, "Object not found\n"); 01269 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 01270 if (!obj) { 01271 ao2_ref(class, -1); 01272 ast_debug(3, "Unable to allocate object\n"); 01273 return NULL; 01274 } 01275 ast_mutex_init(&obj->lock); 01276 /* obj inherits the outstanding reference to class */ 01277 obj->parent = class; 01278 class = NULL; 01279 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01280 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01281 ao2_ref(obj, -1); 01282 obj = NULL; 01283 } else { 01284 obj->used = 1; 01285 ao2_link(obj->parent->obj_container, obj); 01286 ast_atomic_fetchadd_int(&obj->parent->count, +1); 01287 } 01288 } 01289 01290 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { 01291 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01292 for (i = 0; i < numfields; i++) { 01293 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01294 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01295 if (i > 10) { 01296 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01297 break; 01298 } 01299 } 01300 } 01301 } else { 01302 /* Non-pooled connection: multiple modules can use the same connection. */ 01303 if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, NO_TX))) { 01304 /* Object is not constructed, so delete outstanding reference to class. */ 01305 ast_assert(ao2_ref(class, 0) > 1); 01306 ao2_ref(class, -1); 01307 class = NULL; 01308 } else { 01309 /* No entry: build one */ 01310 if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) { 01311 ast_assert(ao2_ref(class, 0) > 1); 01312 ao2_ref(class, -1); 01313 ast_debug(3, "Unable to allocate object\n"); 01314 return NULL; 01315 } 01316 ast_mutex_init(&obj->lock); 01317 /* obj inherits the outstanding reference to class */ 01318 obj->parent = class; 01319 class = NULL; 01320 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01321 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01322 ao2_ref(obj, -1); 01323 obj = NULL; 01324 } else { 01325 ao2_link(obj->parent->obj_container, obj); 01326 ast_assert(ao2_ref(obj, 0) > 1); 01327 } 01328 } 01329 01330 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) { 01331 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01332 for (i = 0; i < numfields; i++) { 01333 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01334 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01335 if (i > 10) { 01336 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01337 break; 01338 } 01339 } 01340 } 01341 } 01342 01343 /* Set the isolation property */ 01344 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) { 01345 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01346 for (i = 0; i < numfields; i++) { 01347 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01348 ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic); 01349 if (i > 10) { 01350 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01351 break; 01352 } 01353 } 01354 } 01355 01356 if (obj && ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) { 01357 /* Check if this connection qualifies for reconnection, with negative connection cache time */ 01358 if (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec) { 01359 odbc_obj_connect(obj); 01360 } 01361 } else if (obj && ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) { 01362 ast_odbc_sanity_check(obj); 01363 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) { 01364 odbc_obj_connect(obj); 01365 } 01366 01367 #ifdef DEBUG_THREADS 01368 if (obj) { 01369 ast_copy_string(obj->file, file, sizeof(obj->file)); 01370 ast_copy_string(obj->function, function, sizeof(obj->function)); 01371 obj->lineno = lineno; 01372 } 01373 #endif 01374 ast_assert(class == NULL); 01375 01376 if (obj) { 01377 ast_assert(ao2_ref(obj, 0) > 1); 01378 } 01379 return obj; 01380 }
SQLRETURN ast_odbc_ast_str_SQLGetData | ( | struct ast_str ** | buf, | |
int | pmaxlen, | |||
SQLHSTMT | StatementHandle, | |||
SQLUSMALLINT | ColumnNumber, | |||
SQLSMALLINT | TargetType, | |||
SQLLEN * | StrLen_or_Ind | |||
) |
Wrapper for SQLGetData to use with dynamic strings.
buf | Address of the pointer to the ast_str structure. | |
pmaxlen | The maximum size of the resulting string, or 0 for no limit. | |
StatementHandle | The statement handle from which to retrieve data. | |
ColumnNumber | Column number (1-based offset) for which to retrieve data. | |
TargetType | The SQL constant indicating what kind of data is to be retrieved (usually SQL_CHAR) | |
StrLen_or_Ind | A pointer to a length indicator, specifying the total length of data. |
Definition at line 698 of file res_odbc.c.
References ast_str_buffer(), ast_str_make_space(), ast_str_size(), and ast_str_update().
00699 { 00700 SQLRETURN res; 00701 00702 if (pmaxlen == 0) { 00703 if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) { 00704 ast_str_make_space(buf, *StrLen_or_Ind + 1); 00705 } 00706 } else if (pmaxlen > 0) { 00707 ast_str_make_space(buf, pmaxlen); 00708 } 00709 res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind); 00710 ast_str_update(*buf); 00711 00712 return res; 00713 }
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 1093 of file res_odbc.c.
References odbc_class::backslash_is_escape, odbc_txn_frame::obj, and odbc_obj::parent.
Referenced by odbc_log(), realtime_multi_odbc(), and realtime_odbc().
01094 { 01095 return obj->parent->backslash_is_escape; 01096 }
int ast_odbc_clear_cache | ( | const char * | database, | |
const char * | tablename | |||
) |
Remove a cache entry from memory This function may be called to clear entries created and cached by the ast_odbc_find_table() API call.
database | Name of an ODBC class (used to ensure like-named tables in different databases are not confused) | |
tablename | Tablename for which a cached record should be removed |
0 | if the cache entry was removed, or -1 if no matching entry was found. |
Definition at line 569 of file res_odbc.c.
References AST_LIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, odbc_cache_tables::connection, destroy_table_cache(), odbc_class::list, and odbc_cache_tables::table.
00570 { 00571 struct odbc_cache_tables *tableptr; 00572 00573 AST_RWLIST_WRLOCK(&odbc_tables); 00574 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) { 00575 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00576 AST_LIST_REMOVE_CURRENT(list); 00577 destroy_table_cache(tableptr); 00578 break; 00579 } 00580 } 00581 AST_RWLIST_TRAVERSE_SAFE_END 00582 AST_RWLIST_UNLOCK(&odbc_tables); 00583 return tableptr ? 0 : -1; 00584 }
SQLHSTMT ast_odbc_direct_execute | ( | struct odbc_obj * | obj, | |
SQLHSTMT(*)(struct odbc_obj *obj, void *data) | exec_cb, | |||
void * | data | |||
) |
Executes an non prepared statement and returns the resulting statement handle.
obj | The ODBC object | |
exec_cb | A function callback, which, when called, should return a statement handle with result columns bound. | |
data | A parameter to be passed to the exec_cb parameter function, indicating which statement handle is to be prepared. |
a | statement handle | |
NULL | on error |
Definition at line 586 of file res_odbc.c.
References ast_log(), ast_odbc_sanity_check(), and LOG_WARNING.
Referenced by acf_odbc_read(), acf_odbc_write(), and odbc_log().
00587 { 00588 int attempt; 00589 SQLHSTMT stmt; 00590 00591 for (attempt = 0; attempt < 2; attempt++) { 00592 stmt = exec_cb(obj, data); 00593 00594 if (stmt) { 00595 break; 00596 } else if (obj->tx) { 00597 ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n"); 00598 break; 00599 } else if (attempt == 0) { 00600 ast_log(LOG_WARNING, "SQL Execute error! Verifying connection to %s [%s]...\n", obj->parent->name, obj->parent->dsn); 00601 } 00602 if (!ast_odbc_sanity_check(obj)) { 00603 break; 00604 } 00605 } 00606 00607 return stmt; 00608 }
struct odbc_cache_columns* ast_odbc_find_column | ( | struct odbc_cache_tables * | table, | |
const char * | colname | |||
) |
Find a column entry within a cached table structure.
table | Cached table structure, as returned from ast_odbc_find_table() | |
colname | The column name requested |
A | structure describing the column type, or NULL, if the column is not found. |
Definition at line 558 of file res_odbc.c.
References AST_RWLIST_TRAVERSE, odbc_class::list, odbc_cache_columns::name, and table.
Referenced by update2_prepare(), and update_odbc().
00559 { 00560 struct odbc_cache_columns *col; 00561 AST_RWLIST_TRAVERSE(&table->columns, col, list) { 00562 if (strcasecmp(col->name, colname) == 0) { 00563 return col; 00564 } 00565 } 00566 return NULL; 00567 }
struct odbc_cache_tables* ast_odbc_find_table | ( | const char * | database, | |
const char * | tablename | |||
) |
Find or create an entry describing the table specified.
database | Name of an ODBC class on which to query the table | |
tablename | Tablename to describe |
A | structure describing the table layout, or NULL, if the table is not found or another error occurs. When a structure is returned, the contained columns list will be rdlock'ed, to ensure that it will be retained in memory. |
Definition at line 443 of file res_odbc.c.
References ast_calloc, AST_LIST_INSERT_TAIL, ast_log(), ast_odbc_release_obj(), ast_odbc_request_obj, ast_odbc_sanity_check(), AST_RWLIST_HEAD_INIT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_verb, odbc_cache_tables::columns, odbc_obj::con, odbc_cache_tables::connection, destroy_table_cache(), odbc_class::list, LOG_ERROR, LOG_WARNING, and odbc_cache_tables::table.
Referenced by require_odbc(), update2_prepare(), and update_odbc().
00444 { 00445 struct odbc_cache_tables *tableptr; 00446 struct odbc_cache_columns *entry; 00447 char columnname[80]; 00448 SQLLEN sqlptr; 00449 SQLHSTMT stmt = NULL; 00450 int res = 0, error = 0, try = 0; 00451 struct odbc_obj *obj = ast_odbc_request_obj(database, 0); 00452 00453 AST_RWLIST_RDLOCK(&odbc_tables); 00454 AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) { 00455 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00456 break; 00457 } 00458 } 00459 if (tableptr) { 00460 AST_RWLIST_RDLOCK(&tableptr->columns); 00461 AST_RWLIST_UNLOCK(&odbc_tables); 00462 if (obj) { 00463 ast_odbc_release_obj(obj); 00464 } 00465 return tableptr; 00466 } 00467 00468 if (!obj) { 00469 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database); 00470 AST_RWLIST_UNLOCK(&odbc_tables); 00471 return NULL; 00472 } 00473 00474 /* Table structure not already cached; build it now. */ 00475 do { 00476 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00477 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00478 if (try == 0) { 00479 try = 1; 00480 ast_odbc_sanity_check(obj); 00481 continue; 00482 } 00483 ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database); 00484 break; 00485 } 00486 00487 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS); 00488 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00489 if (try == 0) { 00490 try = 1; 00491 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00492 ast_odbc_sanity_check(obj); 00493 continue; 00494 } 00495 ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database); 00496 break; 00497 } 00498 00499 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) { 00500 ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database); 00501 break; 00502 } 00503 00504 tableptr->connection = (char *)tableptr + sizeof(*tableptr); 00505 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1; 00506 strcpy(tableptr->connection, database); /* SAFE */ 00507 strcpy(tableptr->table, tablename); /* SAFE */ 00508 AST_RWLIST_HEAD_INIT(&(tableptr->columns)); 00509 00510 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) { 00511 SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr); 00512 00513 if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) { 00514 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database); 00515 error = 1; 00516 break; 00517 } 00518 entry->name = (char *)entry + sizeof(*entry); 00519 strcpy(entry->name, columnname); 00520 00521 SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL); 00522 SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL); 00523 SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL); 00524 SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL); 00525 SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL); 00526 SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL); 00527 00528 /* Specification states that the octenlen should be the maximum number of bytes 00529 * returned in a char or binary column, but it seems that some drivers just set 00530 * it to NULL. (Bad Postgres! No biscuit!) */ 00531 if (entry->octetlen == 0) { 00532 entry->octetlen = entry->size; 00533 } 00534 00535 ast_verb(10, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix); 00536 /* Insert column info into column list */ 00537 AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list); 00538 } 00539 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00540 00541 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list); 00542 AST_RWLIST_RDLOCK(&(tableptr->columns)); 00543 break; 00544 } while (1); 00545 00546 AST_RWLIST_UNLOCK(&odbc_tables); 00547 00548 if (error) { 00549 destroy_table_cache(tableptr); 00550 tableptr = NULL; 00551 } 00552 if (obj) { 00553 ast_odbc_release_obj(obj); 00554 } 00555 return tableptr; 00556 }
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. |
a | statement handle | |
NULL | on error |
Definition at line 610 of file res_odbc.c.
References ast_log(), ast_odbc_sanity_check(), ast_tvnow(), and LOG_WARNING.
Referenced by config_odbc(), destroy_odbc(), odbc_log(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().
00611 { 00612 int res = 0, i, attempt; 00613 SQLINTEGER nativeerror=0, numfields=0; 00614 SQLSMALLINT diagbytes=0; 00615 unsigned char state[10], diagnostic[256]; 00616 SQLHSTMT stmt; 00617 00618 for (attempt = 0; attempt < 2; attempt++) { 00619 /* This prepare callback may do more than just prepare -- it may also 00620 * bind parameters, bind results, etc. The real key, here, is that 00621 * when we disconnect, all handles become invalid for most databases. 00622 * We must therefore redo everything when we establish a new 00623 * connection. */ 00624 stmt = prepare_cb(obj, data); 00625 00626 if (stmt) { 00627 res = SQLExecute(stmt); 00628 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00629 if (res == SQL_ERROR) { 00630 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00631 for (i = 0; i < numfields; i++) { 00632 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00633 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00634 if (i > 10) { 00635 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00636 break; 00637 } 00638 } 00639 } 00640 00641 if (obj->tx) { 00642 ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n"); 00643 break; 00644 } else { 00645 ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn); 00646 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00647 stmt = NULL; 00648 00649 obj->up = 0; 00650 /* 00651 * While this isn't the best way to try to correct an error, this won't automatically 00652 * fail when the statement handle invalidates. 00653 */ 00654 if (!ast_odbc_sanity_check(obj)) { 00655 break; 00656 } 00657 continue; 00658 } 00659 } else { 00660 obj->last_used = ast_tvnow(); 00661 } 00662 break; 00663 } else if (attempt == 0) { 00664 ast_odbc_sanity_check(obj); 00665 } 00666 } 00667 00668 return stmt; 00669 }
void ast_odbc_release_obj | ( | struct odbc_obj * | obj | ) |
Releases an ODBC object previously allocated by ast_odbc_request_obj().
obj | The ODBC object |
Definition at line 1087 of file res_odbc.c.
References find_transaction(), odbc_txn_frame::obj, and odbc_release_obj2().
Referenced by acf_odbc_read(), acf_odbc_write(), ast_odbc_find_table(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().
01088 { 01089 struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0); 01090 odbc_release_obj2(obj, tx); 01091 }
struct odbc_obj* ast_odbc_retrieve_transaction_obj | ( | struct ast_channel * | chan, | |
const char * | objname | |||
) |
Retrieve a stored ODBC object, if a transaction has been started.
chan | Channel associated with the transaction. | |
objname | Name of the database handle. This name corresponds to the name passed to |
A | stored ODBC object, if a transaction was already started. | |
NULL,if | no transaction yet exists. |
Definition at line 1388 of file res_odbc.c.
References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_txn_frame::list, odbc_class::name, odbc_txn_frame::obj, odbc_obj::parent, and txn_info.
Referenced by acf_odbc_write().
01389 { 01390 struct ast_datastore *txn_store; 01391 AST_LIST_HEAD(, odbc_txn_frame) *oldlist; 01392 struct odbc_txn_frame *txn = NULL; 01393 01394 if (!chan) { 01395 /* No channel == no transaction */ 01396 return NULL; 01397 } 01398 01399 ast_channel_lock(chan); 01400 if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { 01401 oldlist = txn_store->data; 01402 } else { 01403 ast_channel_unlock(chan); 01404 return NULL; 01405 } 01406 01407 AST_LIST_LOCK(oldlist); 01408 ast_channel_unlock(chan); 01409 01410 AST_LIST_TRAVERSE(oldlist, txn, list) { 01411 if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) { 01412 AST_LIST_UNLOCK(oldlist); 01413 return txn->obj; 01414 } 01415 } 01416 AST_LIST_UNLOCK(oldlist); 01417 return NULL; 01418 }
int ast_odbc_sanity_check | ( | struct odbc_obj * | obj | ) |
Checks an ODBC object to ensure it is still connected.
obj | The ODBC object |
0 | if connected | |
-1 | otherwise. |
Definition at line 715 of file res_odbc.c.
References ast_log(), ast_strlen_zero(), odbc_obj::con, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), odbc_obj::parent, odbc_class::sanitysql, odbc_obj::tx, and odbc_obj::up.
Referenced by ast_odbc_direct_execute(), ast_odbc_find_table(), ast_odbc_prepare_and_execute(), data_odbc_provider_handler(), and handle_cli_odbc_show().
00716 { 00717 char *test_sql = "select 1"; 00718 SQLHSTMT stmt; 00719 int res = 0; 00720 00721 if (!ast_strlen_zero(obj->parent->sanitysql)) 00722 test_sql = obj->parent->sanitysql; 00723 00724 if (obj->up) { 00725 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00726 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00727 obj->up = 0; 00728 } else { 00729 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00730 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00731 obj->up = 0; 00732 } else { 00733 res = SQLExecute(stmt); 00734 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00735 obj->up = 0; 00736 } 00737 } 00738 } 00739 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00740 } 00741 00742 if (!obj->up && !obj->tx) { /* Try to reconnect! */ 00743 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00744 odbc_obj_disconnect(obj); 00745 odbc_obj_connect(obj); 00746 } 00747 return obj->up; 00748 }
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 |
0 | on success | |
-1 | on failure |
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 671 of file res_odbc.c.
References ast_log(), ast_tvnow(), odbc_obj::last_used, and LOG_WARNING.
00672 { 00673 int res = 0, i; 00674 SQLINTEGER nativeerror=0, numfields=0; 00675 SQLSMALLINT diagbytes=0; 00676 unsigned char state[10], diagnostic[256]; 00677 00678 res = SQLExecute(stmt); 00679 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00680 if (res == SQL_ERROR) { 00681 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00682 for (i = 0; i < numfields; i++) { 00683 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00684 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00685 if (i > 10) { 00686 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00687 break; 00688 } 00689 } 00690 } 00691 } else { 00692 obj->last_used = ast_tvnow(); 00693 } 00694 00695 return res; 00696 }