ODBC resource manager. More...
#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 | _columns |
| struct | odbc_cache_columns |
| struct | odbc_cache_tables |
| 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. | |
Enumerations | |
| enum | { RES_ODBC_SANITY_CHECK = (1 << 0), RES_ODBC_INDEPENDENT_CONNECTION = (1 << 1) } |
Flags for use with. More... | |
| enum | odbc_status { ODBC_SUCCESS = 0, ODBC_FAIL = -1 } |
Functions | |
| 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. | |
| 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. | |
| 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. | |
| struct 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 odbc_request_obj(). | |
| struct odbc_obj * | ast_odbc_request_obj (const char *name, int check) |
| struct odbc_obj * | ast_odbc_request_obj2 (const char *name, struct ast_flags flags) |
| Retrieves a connected ODBC object. | |
| 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. | |
| 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. | |
ODBC resource manager.
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 212 of file res_odbc.h.
Referenced by update2_prepare(), 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 };
| enum odbc_status |
Definition at line 36 of file res_odbc.h.
00036 { ODBC_SUCCESS=0, ODBC_FAIL=-1} odbc_status;
| 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 678 of file res_odbc.c.
References ast_str_buffer(), ast_str_make_space(), ast_str_size(), and ast_str_update().
Referenced by acf_odbc_read(), and cli_odbc_read().
00679 { 00680 SQLRETURN res; 00681 00682 if (pmaxlen == 0) { 00683 if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) { 00684 ast_str_make_space(buf, *StrLen_or_Ind + 1); 00685 } 00686 } else if (pmaxlen > 0) { 00687 ast_str_make_space(buf, pmaxlen); 00688 } 00689 res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind); 00690 ast_str_update(*buf); 00691 00692 return res; 00693 }
| 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 1047 of file res_odbc.c.
References odbc_class::backslash_is_escape, and odbc_obj::parent.
Referenced by odbc_log(), realtime_multi_odbc(), and realtime_odbc().
01048 { 01049 return obj->parent->backslash_is_escape; 01050 }
| int ast_odbc_clear_cache | ( | const char * | database, | |
| const char * | tablename | |||
| ) |
Remove a cache entry from memory.
| 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 551 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.
00552 { 00553 struct odbc_cache_tables *tableptr; 00554 00555 AST_RWLIST_WRLOCK(&odbc_tables); 00556 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) { 00557 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00558 AST_LIST_REMOVE_CURRENT(list); 00559 destroy_table_cache(tableptr); 00560 break; 00561 } 00562 } 00563 AST_RWLIST_TRAVERSE_SAFE_END 00564 AST_RWLIST_UNLOCK(&odbc_tables); 00565 return tableptr ? 0 : -1; 00566 }
| 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 568 of file res_odbc.c.
References ast_log(), LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), odbc_obj::tx, and odbc_obj::up.
Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), cli_odbc_write(), and odbc_log().
00569 { 00570 int attempt; 00571 SQLHSTMT stmt; 00572 00573 for (attempt = 0; attempt < 2; attempt++) { 00574 stmt = exec_cb(obj, data); 00575 00576 if (stmt) { 00577 break; 00578 } else if (obj->tx) { 00579 ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n"); 00580 break; 00581 } else { 00582 obj->up = 0; 00583 ast_log(LOG_WARNING, "SQL Exec Direct failed. Attempting a reconnect...\n"); 00584 00585 odbc_obj_disconnect(obj); 00586 odbc_obj_connect(obj); 00587 } 00588 } 00589 00590 return stmt; 00591 }
| struct odbc_cache_columns* ast_odbc_find_column | ( | struct odbc_cache_tables * | table, | |
| const char * | colname | |||
| ) | [read] |
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 540 of file res_odbc.c.
References AST_RWLIST_TRAVERSE, odbc_cache_tables::columns, odbc_class::list, and odbc_cache_columns::name.
Referenced by update2_prepare(), and update_odbc().
00541 { 00542 struct odbc_cache_columns *col; 00543 AST_RWLIST_TRAVERSE(&table->columns, col, list) { 00544 if (strcasecmp(col->name, colname) == 0) { 00545 return col; 00546 } 00547 } 00548 return NULL; 00549 }
| struct odbc_cache_tables* ast_odbc_find_table | ( | const char * | database, | |
| const char * | tablename | |||
| ) | [read] |
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 425 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, odbc_cache_columns::decimals, destroy_table_cache(), odbc_class::list, LOG_ERROR, LOG_WARNING, odbc_cache_columns::name, odbc_cache_columns::nullable, odbc_cache_columns::octetlen, odbc_cache_columns::radix, odbc_cache_columns::size, odbc_cache_tables::table, and odbc_cache_columns::type.
Referenced by require_odbc(), update2_prepare(), and update_odbc().
00426 { 00427 struct odbc_cache_tables *tableptr; 00428 struct odbc_cache_columns *entry; 00429 char columnname[80]; 00430 SQLLEN sqlptr; 00431 SQLHSTMT stmt = NULL; 00432 int res = 0, error = 0, try = 0; 00433 struct odbc_obj *obj = ast_odbc_request_obj(database, 0); 00434 00435 AST_RWLIST_RDLOCK(&odbc_tables); 00436 AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) { 00437 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00438 break; 00439 } 00440 } 00441 if (tableptr) { 00442 AST_RWLIST_RDLOCK(&tableptr->columns); 00443 AST_RWLIST_UNLOCK(&odbc_tables); 00444 if (obj) { 00445 ast_odbc_release_obj(obj); 00446 } 00447 return tableptr; 00448 } 00449 00450 if (!obj) { 00451 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database); 00452 AST_RWLIST_UNLOCK(&odbc_tables); 00453 return NULL; 00454 } 00455 00456 /* Table structure not already cached; build it now. */ 00457 do { 00458 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00459 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00460 if (try == 0) { 00461 try = 1; 00462 ast_odbc_sanity_check(obj); 00463 continue; 00464 } 00465 ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database); 00466 break; 00467 } 00468 00469 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS); 00470 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00471 if (try == 0) { 00472 try = 1; 00473 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00474 ast_odbc_sanity_check(obj); 00475 continue; 00476 } 00477 ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database); 00478 break; 00479 } 00480 00481 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) { 00482 ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database); 00483 break; 00484 } 00485 00486 tableptr->connection = (char *)tableptr + sizeof(*tableptr); 00487 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1; 00488 strcpy(tableptr->connection, database); /* SAFE */ 00489 strcpy(tableptr->table, tablename); /* SAFE */ 00490 AST_RWLIST_HEAD_INIT(&(tableptr->columns)); 00491 00492 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) { 00493 SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr); 00494 00495 if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) { 00496 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database); 00497 error = 1; 00498 break; 00499 } 00500 entry->name = (char *)entry + sizeof(*entry); 00501 strcpy(entry->name, columnname); 00502 00503 SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL); 00504 SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL); 00505 SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL); 00506 SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL); 00507 SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL); 00508 SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL); 00509 00510 /* Specification states that the octenlen should be the maximum number of bytes 00511 * returned in a char or binary column, but it seems that some drivers just set 00512 * it to NULL. (Bad Postgres! No biscuit!) */ 00513 if (entry->octetlen == 0) { 00514 entry->octetlen = entry->size; 00515 } 00516 00517 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); 00518 /* Insert column info into column list */ 00519 AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list); 00520 } 00521 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00522 00523 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list); 00524 AST_RWLIST_RDLOCK(&(tableptr->columns)); 00525 break; 00526 } while (1); 00527 00528 AST_RWLIST_UNLOCK(&odbc_tables); 00529 00530 if (error) { 00531 destroy_table_cache(tableptr); 00532 tableptr = NULL; 00533 } 00534 if (obj) { 00535 ast_odbc_release_obj(obj); 00536 } 00537 return tableptr; 00538 }
| 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 593 of file res_odbc.c.
References ast_log(), ast_odbc_sanity_check(), ast_tvnow(), odbc_obj::last_used, LOG_WARNING, odbc_obj::tx, and odbc_obj::up.
Referenced by config_odbc(), destroy_odbc(), odbc_log(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().
00594 { 00595 int res = 0, i, attempt; 00596 SQLINTEGER nativeerror=0, numfields=0; 00597 SQLSMALLINT diagbytes=0; 00598 unsigned char state[10], diagnostic[256]; 00599 SQLHSTMT stmt; 00600 00601 for (attempt = 0; attempt < 2; attempt++) { 00602 /* This prepare callback may do more than just prepare -- it may also 00603 * bind parameters, bind results, etc. The real key, here, is that 00604 * when we disconnect, all handles become invalid for most databases. 00605 * We must therefore redo everything when we establish a new 00606 * connection. */ 00607 stmt = prepare_cb(obj, data); 00608 00609 if (stmt) { 00610 res = SQLExecute(stmt); 00611 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00612 if (res == SQL_ERROR) { 00613 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00614 for (i = 0; i < numfields; i++) { 00615 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00616 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00617 if (i > 10) { 00618 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00619 break; 00620 } 00621 } 00622 } 00623 00624 if (obj->tx) { 00625 ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n"); 00626 break; 00627 } else { 00628 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00629 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00630 stmt = NULL; 00631 00632 obj->up = 0; 00633 /* 00634 * While this isn't the best way to try to correct an error, this won't automatically 00635 * fail when the statement handle invalidates. 00636 */ 00637 ast_odbc_sanity_check(obj); 00638 continue; 00639 } 00640 } else { 00641 obj->last_used = ast_tvnow(); 00642 } 00643 break; 00644 } else if (attempt == 0) { 00645 ast_odbc_sanity_check(obj); 00646 } 00647 } 00648 00649 return stmt; 00650 }
| 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 1041 of file res_odbc.c.
References find_transaction(), and odbc_release_obj2().
Referenced by acf_odbc_read(), acf_odbc_write(), ast_odbc_find_table(), cli_odbc_read(), cli_odbc_write(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().
01042 { 01043 struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0); 01044 odbc_release_obj2(obj, tx); 01045 }
| struct odbc_obj* ast_odbc_request_obj | ( | const char * | name, | |
| int | check | |||
| ) | [read] |
Definition at line 1331 of file res_odbc.c.
References ast_odbc_request_obj2(), and RES_ODBC_SANITY_CHECK.
Referenced by acf_odbc_read(), acf_odbc_write(), ast_odbc_find_table(), cli_odbc_read(), cli_odbc_write(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().
01333 { 01334 struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 }; 01335 #ifdef DEBUG_THREADS 01336 return _ast_odbc_request_obj2(name, flags, file, function, lineno); 01337 #else 01338 return ast_odbc_request_obj2(name, flags); 01339 #endif 01340 }
Retrieves a connected ODBC object.
| name | The name of the ODBC class for which a connection is needed. | |
| flags | Set of flags used to control which connection is returned. |
| ODBC | object | |
| NULL | if there is no connection available with the requested name. |
Connection classes may, in fact, contain multiple connection handles. If the connection is pooled, then each connection will be dedicated to the thread which requests it. Note that all connections should be released when the thread is done by calling odbc_release_obj(), below.
Definition at line 1156 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_copy_string(), ast_log(), ast_mutex_init(), ast_odbc_sanity_check(), ast_test_flag, ast_tvdiff_sec(), ast_tvnow(), class_container, odbc_obj::con, odbc_class::count, EOR_TX, odbc_class::idlecheck, odbc_class::isolation, odbc_obj::last_used, odbc_obj::lock, LOG_WARNING, NO_TX, odbc_class::obj_container, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), odbc_obj::parent, RES_ODBC_INDEPENDENT_CONNECTION, RES_ODBC_SANITY_CHECK, USE_TX, and odbc_obj::used.
Referenced by acf_transaction_write(), and ast_odbc_request_obj().
01158 { 01159 struct odbc_obj *obj = NULL; 01160 struct odbc_class *class; 01161 SQLINTEGER nativeerror=0, numfields=0; 01162 SQLSMALLINT diagbytes=0, i; 01163 unsigned char state[10], diagnostic[256]; 01164 01165 if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) { 01166 return NULL; 01167 } 01168 01169 ast_assert(ao2_ref(class, 0) > 1); 01170 01171 if (class->haspool) { 01172 /* Recycle connections before building another */ 01173 obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX); 01174 01175 if (obj) { 01176 ast_assert(ao2_ref(obj, 0) > 1); 01177 } 01178 01179 if (!obj && (class->count < class->limit)) { 01180 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 01181 if (!obj) { 01182 ao2_ref(class, -1); 01183 return NULL; 01184 } 01185 ast_assert(ao2_ref(obj, 0) == 1); 01186 ast_mutex_init(&obj->lock); 01187 /* obj inherits the outstanding reference to class */ 01188 obj->parent = class; 01189 class = NULL; 01190 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01191 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01192 ao2_ref(obj, -1); 01193 ast_assert(ao2_ref(class, 0) > 0); 01194 obj = NULL; 01195 } else { 01196 obj->used = 1; 01197 ao2_link(obj->parent->obj_container, obj); 01198 ast_atomic_fetchadd_int(&obj->parent->count, +1); 01199 } 01200 } else { 01201 /* Object is not constructed, so delete outstanding reference to class. */ 01202 ao2_ref(class, -1); 01203 class = NULL; 01204 } 01205 01206 if (obj && ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { 01207 /* Ensure this connection has autocommit turned off. */ 01208 if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { 01209 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01210 for (i = 0; i < numfields; i++) { 01211 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01212 ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01213 if (i > 10) { 01214 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01215 break; 01216 } 01217 } 01218 } 01219 } 01220 } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) { 01221 /* Non-pooled connections -- but must use a separate connection handle */ 01222 if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) { 01223 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 01224 if (!obj) { 01225 ao2_ref(class, -1); 01226 return NULL; 01227 } 01228 ast_mutex_init(&obj->lock); 01229 /* obj inherits the outstanding reference to class */ 01230 obj->parent = class; 01231 class = NULL; 01232 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01233 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01234 ao2_ref(obj, -1); 01235 obj = NULL; 01236 } else { 01237 obj->used = 1; 01238 ao2_link(obj->parent->obj_container, obj); 01239 ast_atomic_fetchadd_int(&obj->parent->count, +1); 01240 } 01241 } 01242 01243 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) { 01244 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01245 for (i = 0; i < numfields; i++) { 01246 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01247 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01248 if (i > 10) { 01249 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01250 break; 01251 } 01252 } 01253 } 01254 } else { 01255 /* Non-pooled connection: multiple modules can use the same connection. */ 01256 if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, NO_TX))) { 01257 /* Object is not constructed, so delete outstanding reference to class. */ 01258 ast_assert(ao2_ref(class, 0) > 1); 01259 ao2_ref(class, -1); 01260 class = NULL; 01261 } else { 01262 /* No entry: build one */ 01263 if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) { 01264 ast_assert(ao2_ref(class, 0) > 1); 01265 ao2_ref(class, -1); 01266 return NULL; 01267 } 01268 ast_mutex_init(&obj->lock); 01269 /* obj inherits the outstanding reference to class */ 01270 obj->parent = class; 01271 class = NULL; 01272 if (odbc_obj_connect(obj) == ODBC_FAIL) { 01273 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 01274 ao2_ref(obj, -1); 01275 obj = NULL; 01276 } else { 01277 ao2_link(obj->parent->obj_container, obj); 01278 ast_assert(ao2_ref(obj, 0) > 1); 01279 } 01280 } 01281 01282 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) { 01283 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01284 for (i = 0; i < numfields; i++) { 01285 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01286 ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic); 01287 if (i > 10) { 01288 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01289 break; 01290 } 01291 } 01292 } 01293 } 01294 01295 /* Set the isolation property */ 01296 if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) { 01297 SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 01298 for (i = 0; i < numfields; i++) { 01299 SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 01300 ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic); 01301 if (i > 10) { 01302 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 01303 break; 01304 } 01305 } 01306 } 01307 01308 if (obj && ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) { 01309 ast_odbc_sanity_check(obj); 01310 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) 01311 odbc_obj_connect(obj); 01312 01313 #ifdef DEBUG_THREADS 01314 if (obj) { 01315 ast_copy_string(obj->file, file, sizeof(obj->file)); 01316 ast_copy_string(obj->function, function, sizeof(obj->function)); 01317 obj->lineno = lineno; 01318 } 01319 #endif 01320 ast_assert(class == NULL); 01321 01322 if (obj) { 01323 ast_assert(ao2_ref(obj, 0) > 1); 01324 } 01325 return obj; 01326 }
| struct odbc_obj* ast_odbc_retrieve_transaction_obj | ( | struct ast_channel * | chan, | |
| const char * | objname | |||
| ) | [read] |
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 1342 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_class::list, odbc_class::name, odbc_txn_frame::obj, odbc_obj::parent, and txn_info.
Referenced by acf_odbc_write().
01343 { 01344 struct ast_datastore *txn_store; 01345 AST_LIST_HEAD(, odbc_txn_frame) *oldlist; 01346 struct odbc_txn_frame *txn = NULL; 01347 01348 if (!chan) { 01349 /* No channel == no transaction */ 01350 return NULL; 01351 } 01352 01353 ast_channel_lock(chan); 01354 if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) { 01355 oldlist = txn_store->data; 01356 } else { 01357 ast_channel_unlock(chan); 01358 return NULL; 01359 } 01360 01361 AST_LIST_LOCK(oldlist); 01362 ast_channel_unlock(chan); 01363 01364 AST_LIST_TRAVERSE(oldlist, txn, list) { 01365 if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) { 01366 AST_LIST_UNLOCK(oldlist); 01367 return txn->obj; 01368 } 01369 } 01370 AST_LIST_UNLOCK(oldlist); 01371 return NULL; 01372 }
| 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 695 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_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_request_obj2(), and handle_cli_odbc_show().
00696 { 00697 char *test_sql = "select 1"; 00698 SQLHSTMT stmt; 00699 int res = 0; 00700 00701 if (!ast_strlen_zero(obj->parent->sanitysql)) 00702 test_sql = obj->parent->sanitysql; 00703 00704 if (obj->up) { 00705 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00706 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00707 obj->up = 0; 00708 } else { 00709 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00710 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00711 obj->up = 0; 00712 } else { 00713 res = SQLExecute(stmt); 00714 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00715 obj->up = 0; 00716 } 00717 } 00718 } 00719 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00720 } 00721 00722 if (!obj->up && !obj->tx) { /* Try to reconnect! */ 00723 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00724 odbc_obj_disconnect(obj); 00725 odbc_obj_connect(obj); 00726 } 00727 return obj->up; 00728 }
| 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 was originally designed simply to execute a prepared statement handle and to retry if the initial execution failed. Unfortunately, it did this by disconnecting and reconnecting the database handle which on most databases causes the statement handle to become invalid. Therefore, this method has been deprecated in favor of odbc_prepare_and_execute() which allows the statement to be prepared multiple times, if necessary, in case of a loss of connection.
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 652 of file res_odbc.c.
References ast_log(), ast_tvnow(), odbc_obj::last_used, and LOG_WARNING.
00653 { 00654 int res = 0, i; 00655 SQLINTEGER nativeerror=0, numfields=0; 00656 SQLSMALLINT diagbytes=0; 00657 unsigned char state[10], diagnostic[256]; 00658 00659 res = SQLExecute(stmt); 00660 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00661 if (res == SQL_ERROR) { 00662 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00663 for (i = 0; i < numfields; i++) { 00664 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00665 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00666 if (i > 10) { 00667 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00668 break; 00669 } 00670 } 00671 } 00672 } else 00673 obj->last_used = ast_tvnow(); 00674 00675 return res; 00676 }
1.6.2