#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 1390 of file res_odbc.c.
References _ast_odbc_request_obj2(), ast_flags::flags, and RES_ODBC_SANITY_CHECK.
01391 { 01392 struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 }; 01393 return _ast_odbc_request_obj2(name, flags, file, function, lineno); 01394 }
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 1201 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().
01202 { 01203 struct odbc_obj *obj = NULL; 01204 struct odbc_class *class; 01205 SQLINTEGER nativeerror=0, numfields=0; 01206 SQLSMALLINT diagbytes=0, i; 01207 unsigned char state[10], diagnostic[256]; 01208 01209 if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) { 01210 ast_debug(1, "Class '%s' not found!\n", name); 01211 return NULL; 01212 } 01213 01214 ast_assert(ao2_ref(class, 0) > 1); 01215 01216 if (class->haspool) { 01217 /* Recycle connections before building another */ 01218 obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX); 01219 01220 if (obj) { 01221 ast_assert(ao2_ref(obj, 0) > 1); 01222 } 01223 if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit) && 01224 (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) { 01225 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 01226 if (!obj) { 01227 class->count--; 01228 ao2_ref(class, -1); 01229 ast_debug(3, "Unable to allocate object\n"); 01230 ast_atomic_fetchadd_int(&class->count, -1); 01231 return NULL; 01232 } 01233 ast_assert(ao2_ref(obj, 0) == 1); 01234 ast_mutex_init(&obj->lock); 01235 /* obj inherits the outstanding reference to class */ 01236 obj->parent = class; 01237 class = NULL; 01238 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01239 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01240 ast_assert(ao2_ref(obj->parent, 0) > 0); 01241 /* Because it was never within the container, we have to manually decrement the count here */ 01242 ast_atomic_fetchadd_int(&obj->parent->count, -1); 01243 ao2_ref(obj, -1); 01244 obj = NULL; 01245 } else { 01246 obj->used = 1; 01247 ao2_link(obj->parent->obj_container, obj); 01248 } 01249 } else { 01250 /* If construction fails due to the limit (or negative timecache), reverse our increment. */ 01251 if (!obj) { 01252 ast_atomic_fetchadd_int(&class->count, -1); 01253 } 01254 /* Object is not constructed, so delete outstanding reference to class. */ 01255 ao2_ref(class, -1); 01256 class = NULL; 01257 } 01258 01259 if (obj && ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { 01260 /* Ensure this connection has autocommit turned off. */ 01261 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { 01262 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01263 for (i = 0; i < numfields; i++) { 01264 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01265 ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01266 if (i > 10) { 01267 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01268 break; 01269 } 01270 } 01271 } 01272 } 01273 } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { 01274 /* Non-pooled connections -- but must use a separate connection handle */ 01275 if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) { 01276 ast_debug(1, "Object not found\n"); 01277 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 01278 if (!obj) { 01279 ao2_ref(class, -1); 01280 ast_debug(3, "Unable to allocate object\n"); 01281 return NULL; 01282 } 01283 ast_mutex_init(&obj->lock); 01284 /* obj inherits the outstanding reference to class */ 01285 obj->parent = class; 01286 class = NULL; 01287 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01288 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01289 ao2_ref(obj, -1); 01290 obj = NULL; 01291 } else { 01292 obj->used = 1; 01293 ao2_link(obj->parent->obj_container, obj); 01294 ast_atomic_fetchadd_int(&obj->parent->count, +1); 01295 } 01296 } 01297 01298 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { 01299 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01300 for (i = 0; i < numfields; i++) { 01301 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01302 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01303 if (i > 10) { 01304 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01305 break; 01306 } 01307 } 01308 } 01309 } else { 01310 /* Non-pooled connection: multiple modules can use the same connection. */ 01311 if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, NO_TX))) { 01312 /* Object is not constructed, so delete outstanding reference to class. */ 01313 ast_assert(ao2_ref(class, 0) > 1); 01314 ao2_ref(class, -1); 01315 class = NULL; 01316 } else { 01317 /* No entry: build one */ 01318 if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) { 01319 ast_assert(ao2_ref(class, 0) > 1); 01320 ao2_ref(class, -1); 01321 ast_debug(3, "Unable to allocate object\n"); 01322 return NULL; 01323 } 01324 ast_mutex_init(&obj->lock); 01325 /* obj inherits the outstanding reference to class */ 01326 obj->parent = class; 01327 class = NULL; 01328 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01329 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01330 ao2_ref(obj, -1); 01331 obj = NULL; 01332 } else { 01333 ao2_link(obj->parent->obj_container, obj); 01334 ast_assert(ao2_ref(obj, 0) > 1); 01335 } 01336 } 01337 01338 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) { 01339 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01340 for (i = 0; i < numfields; i++) { 01341 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01342 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01343 if (i > 10) { 01344 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01345 break; 01346 } 01347 } 01348 } 01349 } 01350 01351 /* Set the isolation property */ 01352 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) { 01353 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01354 for (i = 0; i < numfields; i++) { 01355 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01356 ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic); 01357 if (i > 10) { 01358 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01359 break; 01360 } 01361 } 01362 } 01363 01364 if (obj && ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) { 01365 /* Check if this connection qualifies for reconnection, with negative connection cache time */ 01366 if (time(NULL) > obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec) { 01367 odbc_obj_connect(obj); 01368 } 01369 } else if (obj && ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) { 01370 ast_odbc_sanity_check(obj); 01371 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) { 01372 odbc_obj_connect(obj); 01373 } 01374 01375 #ifdef DEBUG_THREADS 01376 if (obj) { 01377 ast_copy_string(obj->file, file, sizeof(obj->file)); 01378 ast_copy_string(obj->function, function, sizeof(obj->function)); 01379 obj->lineno = lineno; 01380 } 01381 #endif 01382 ast_assert(class == NULL); 01383 01384 if (obj) { 01385 ast_assert(ao2_ref(obj, 0) > 1); 01386 } 01387 return obj; 01388 }
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 699 of file res_odbc.c.
References ast_str_buffer(), ast_str_make_space(), ast_str_size(), and ast_str_update().
00700 { 00701 SQLRETURN res; 00702 00703 if (pmaxlen == 0) { 00704 if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) { 00705 ast_str_make_space(buf, *StrLen_or_Ind + 1); 00706 } 00707 } else if (pmaxlen > 0) { 00708 ast_str_make_space(buf, pmaxlen); 00709 } 00710 res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind); 00711 ast_str_update(*buf); 00712 00713 return res; 00714 }
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 1095 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().
01096 { 01097 return obj->parent->backslash_is_escape; 01098 }
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 570 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.
Referenced by unload_odbc().
00571 { 00572 struct odbc_cache_tables *tableptr; 00573 00574 AST_RWLIST_WRLOCK(&odbc_tables); 00575 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) { 00576 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00577 AST_LIST_REMOVE_CURRENT(list); 00578 destroy_table_cache(tableptr); 00579 break; 00580 } 00581 } 00582 AST_RWLIST_TRAVERSE_SAFE_END 00583 AST_RWLIST_UNLOCK(&odbc_tables); 00584 return tableptr ? 0 : -1; 00585 }
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 587 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().
00588 { 00589 int attempt; 00590 SQLHSTMT stmt; 00591 00592 for (attempt = 0; attempt < 2; attempt++) { 00593 stmt = exec_cb(obj, data); 00594 00595 if (stmt) { 00596 break; 00597 } else if (obj->tx) { 00598 ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n"); 00599 break; 00600 } else if (attempt == 0) { 00601 ast_log(LOG_WARNING, "SQL Execute error! Verifying connection to %s [%s]...\n", obj->parent->name, obj->parent->dsn); 00602 } 00603 if (!ast_odbc_sanity_check(obj)) { 00604 break; 00605 } 00606 } 00607 00608 return stmt; 00609 }
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 559 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().
00560 { 00561 struct odbc_cache_columns *col; 00562 AST_RWLIST_TRAVERSE(&table->columns, col, list) { 00563 if (strcasecmp(col->name, colname) == 0) { 00564 return col; 00565 } 00566 } 00567 return NULL; 00568 }
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 444 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().
00445 { 00446 struct odbc_cache_tables *tableptr; 00447 struct odbc_cache_columns *entry; 00448 char columnname[80]; 00449 SQLLEN sqlptr; 00450 SQLHSTMT stmt = NULL; 00451 int res = 0, error = 0, try = 0; 00452 struct odbc_obj *obj = ast_odbc_request_obj(database, 0); 00453 00454 AST_RWLIST_RDLOCK(&odbc_tables); 00455 AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) { 00456 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00457 break; 00458 } 00459 } 00460 if (tableptr) { 00461 AST_RWLIST_RDLOCK(&tableptr->columns); 00462 AST_RWLIST_UNLOCK(&odbc_tables); 00463 if (obj) { 00464 ast_odbc_release_obj(obj); 00465 } 00466 return tableptr; 00467 } 00468 00469 if (!obj) { 00470 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database); 00471 AST_RWLIST_UNLOCK(&odbc_tables); 00472 return NULL; 00473 } 00474 00475 /* Table structure not already cached; build it now. */ 00476 do { 00477 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00478 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00479 if (try == 0) { 00480 try = 1; 00481 ast_odbc_sanity_check(obj); 00482 continue; 00483 } 00484 ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database); 00485 break; 00486 } 00487 00488 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS); 00489 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00490 if (try == 0) { 00491 try = 1; 00492 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00493 ast_odbc_sanity_check(obj); 00494 continue; 00495 } 00496 ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database); 00497 break; 00498 } 00499 00500 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) { 00501 ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database); 00502 break; 00503 } 00504 00505 tableptr->connection = (char *)tableptr + sizeof(*tableptr); 00506 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1; 00507 strcpy(tableptr->connection, database); /* SAFE */ 00508 strcpy(tableptr->table, tablename); /* SAFE */ 00509 AST_RWLIST_HEAD_INIT(&(tableptr->columns)); 00510 00511 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) { 00512 SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr); 00513 00514 if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) { 00515 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database); 00516 error = 1; 00517 break; 00518 } 00519 entry->name = (char *)entry + sizeof(*entry); 00520 strcpy(entry->name, columnname); 00521 00522 SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL); 00523 SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL); 00524 SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL); 00525 SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL); 00526 SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL); 00527 SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL); 00528 00529 /* Specification states that the octenlen should be the maximum number of bytes 00530 * returned in a char or binary column, but it seems that some drivers just set 00531 * it to NULL. (Bad Postgres! No biscuit!) */ 00532 if (entry->octetlen == 0) { 00533 entry->octetlen = entry->size; 00534 } 00535 00536 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); 00537 /* Insert column info into column list */ 00538 AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list); 00539 } 00540 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00541 00542 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list); 00543 AST_RWLIST_RDLOCK(&(tableptr->columns)); 00544 break; 00545 } while (1); 00546 00547 AST_RWLIST_UNLOCK(&odbc_tables); 00548 00549 if (error) { 00550 destroy_table_cache(tableptr); 00551 tableptr = NULL; 00552 } 00553 if (obj) { 00554 ast_odbc_release_obj(obj); 00555 } 00556 return tableptr; 00557 }
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 611 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().
00612 { 00613 int res = 0, i, attempt; 00614 SQLINTEGER nativeerror=0, numfields=0; 00615 SQLSMALLINT diagbytes=0; 00616 unsigned char state[10], diagnostic[256]; 00617 SQLHSTMT stmt; 00618 00619 for (attempt = 0; attempt < 2; attempt++) { 00620 /* This prepare callback may do more than just prepare -- it may also 00621 * bind parameters, bind results, etc. The real key, here, is that 00622 * when we disconnect, all handles become invalid for most databases. 00623 * We must therefore redo everything when we establish a new 00624 * connection. */ 00625 stmt = prepare_cb(obj, data); 00626 00627 if (stmt) { 00628 res = SQLExecute(stmt); 00629 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00630 if (res == SQL_ERROR) { 00631 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00632 for (i = 0; i < numfields; i++) { 00633 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00634 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00635 if (i > 10) { 00636 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00637 break; 00638 } 00639 } 00640 } 00641 00642 if (obj->tx) { 00643 ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n"); 00644 break; 00645 } else { 00646 ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn); 00647 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00648 stmt = NULL; 00649 00650 obj->up = 0; 00651 /* 00652 * While this isn't the best way to try to correct an error, this won't automatically 00653 * fail when the statement handle invalidates. 00654 */ 00655 if (!ast_odbc_sanity_check(obj)) { 00656 break; 00657 } 00658 continue; 00659 } 00660 } else { 00661 obj->last_used = ast_tvnow(); 00662 } 00663 break; 00664 } else if (attempt == 0) { 00665 ast_odbc_sanity_check(obj); 00666 } 00667 } 00668 00669 return stmt; 00670 }
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 1089 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().
01090 { 01091 struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0); 01092 odbc_release_obj2(obj, tx); 01093 }
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 1396 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().
01397 { 01398 struct ast_datastore *txn_store; 01399 AST_LIST_HEAD(, odbc_txn_frame) *oldlist; 01400 struct odbc_txn_frame *txn = NULL; 01401 01402 if (!chan) { 01403 /* No channel == no transaction */ 01404 return NULL; 01405 } 01406 01407 ast_channel_lock(chan); 01408 if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { 01409 oldlist = txn_store->data; 01410 } else { 01411 ast_channel_unlock(chan); 01412 return NULL; 01413 } 01414 01415 AST_LIST_LOCK(oldlist); 01416 ast_channel_unlock(chan); 01417 01418 AST_LIST_TRAVERSE(oldlist, txn, list) { 01419 if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) { 01420 AST_LIST_UNLOCK(oldlist); 01421 return txn->obj; 01422 } 01423 } 01424 AST_LIST_UNLOCK(oldlist); 01425 return NULL; 01426 }
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 716 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().
00717 { 00718 char *test_sql = "select 1"; 00719 SQLHSTMT stmt; 00720 int res = 0; 00721 00722 if (!ast_strlen_zero(obj->parent->sanitysql)) 00723 test_sql = obj->parent->sanitysql; 00724 00725 if (obj->up) { 00726 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00727 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00728 obj->up = 0; 00729 } else { 00730 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00731 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00732 obj->up = 0; 00733 } else { 00734 res = SQLExecute(stmt); 00735 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00736 obj->up = 0; 00737 } 00738 } 00739 } 00740 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00741 } 00742 00743 if (!obj->up && !obj->tx) { /* Try to reconnect! */ 00744 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00745 odbc_obj_disconnect(obj); 00746 odbc_obj_connect(obj); 00747 } 00748 return obj->up; 00749 }
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 672 of file res_odbc.c.
References ast_log(), ast_tvnow(), odbc_obj::last_used, and LOG_WARNING.
00673 { 00674 int res = 0, i; 00675 SQLINTEGER nativeerror=0, numfields=0; 00676 SQLSMALLINT diagbytes=0; 00677 unsigned char state[10], diagnostic[256]; 00678 00679 res = SQLExecute(stmt); 00680 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00681 if (res == SQL_ERROR) { 00682 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00683 for (i = 0; i < numfields; i++) { 00684 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00685 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00686 if (i > 10) { 00687 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00688 break; 00689 } 00690 } 00691 } 00692 } else { 00693 obj->last_used = ast_tvnow(); 00694 } 00695 00696 return res; 00697 }