#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include "asterisk/linkedlists.h"
Go to the source code of this file.
Data Structures | |
struct | odbc_cache_columns |
These aren't used in any API calls, but they are kept in a common location, simply for convenience and to avoid duplication. 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. | |
Enumerations | |
enum | odbc_status { ODBC_SUCCESS = 0, ODBC_FAIL = -1 } |
Functions | |
int | ast_odbc_backslash_is_escape (struct odbc_obj *obj) |
Checks if the database natively supports backslash as an escape character. | |
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. | |
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 odbc_request_obj(). | |
odbc_obj * | ast_odbc_request_obj (const char *name, int check) |
Retrieves a connected ODBC object. | |
int | ast_odbc_sanity_check (struct odbc_obj *obj) |
Checks an ODBC object to ensure it is still connected. | |
int | ast_odbc_smart_execute (struct odbc_obj *obj, SQLHSTMT stmt) |
Executes a prepared statement handle. |
Definition in file res_odbc.h.
#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 187 of file res_odbc.h.
Referenced by update_odbc().
enum odbc_status |
int ast_odbc_backslash_is_escape | ( | struct odbc_obj * | obj | ) |
Checks if the database natively supports backslash as an escape character.
obj | The ODBC object |
Definition at line 655 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().
00656 { 00657 return obj->parent->backslash_is_escape; 00658 }
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) | |
table | 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 254 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.
00255 { 00256 struct odbc_cache_tables *tableptr; 00257 00258 AST_RWLIST_WRLOCK(&odbc_tables); 00259 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) { 00260 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00261 AST_LIST_REMOVE_CURRENT(list); 00262 destroy_table_cache(tableptr); 00263 break; 00264 } 00265 } 00266 AST_RWLIST_TRAVERSE_SAFE_END 00267 AST_RWLIST_UNLOCK(&odbc_tables); 00268 return tableptr ? 0 : -1; 00269 }
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 271 of file res_odbc.c.
References ast_log(), LOG_WARNING, odbc_obj_connect(), and odbc_obj_disconnect().
Referenced by acf_odbc_read(), acf_odbc_write(), and odbc_log().
00272 { 00273 int attempt; 00274 SQLHSTMT stmt; 00275 00276 for (attempt = 0; attempt < 2; attempt++) { 00277 stmt = exec_cb(obj, data); 00278 00279 if (stmt) { 00280 break; 00281 } else { 00282 obj->up = 0; 00283 ast_log(LOG_WARNING, "SQL Exec Direct failed. Attempting a reconnect...\n"); 00284 00285 odbc_obj_disconnect(obj); 00286 odbc_obj_connect(obj); 00287 } 00288 } 00289 00290 return stmt; 00291 }
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 243 of file res_odbc.c.
References AST_RWLIST_TRAVERSE, odbc_class::list, odbc_cache_columns::name, and table.
Referenced by update_odbc().
00244 { 00245 struct odbc_cache_columns *col; 00246 AST_RWLIST_TRAVERSE(&table->columns, col, list) { 00247 if (strcasecmp(col->name, colname) == 0) { 00248 return col; 00249 } 00250 } 00251 return NULL; 00252 }
struct odbc_cache_tables* ast_odbc_find_table | ( | const char * | database, | |
const char * | tablename | |||
) |
Find or create an entry describing the table specified.
obj | An active ODBC handle on which to query the table | |
table | 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 129 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(), and update_odbc().
00130 { 00131 struct odbc_cache_tables *tableptr; 00132 struct odbc_cache_columns *entry; 00133 char columnname[80]; 00134 SQLLEN sqlptr; 00135 SQLHSTMT stmt = NULL; 00136 int res = 0, error = 0, try = 0; 00137 struct odbc_obj *obj = ast_odbc_request_obj(database, 0); 00138 00139 AST_RWLIST_RDLOCK(&odbc_tables); 00140 AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) { 00141 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) { 00142 break; 00143 } 00144 } 00145 if (tableptr) { 00146 AST_RWLIST_RDLOCK(&tableptr->columns); 00147 AST_RWLIST_UNLOCK(&odbc_tables); 00148 if (obj) { 00149 ast_odbc_release_obj(obj); 00150 } 00151 return tableptr; 00152 } 00153 00154 if (!obj) { 00155 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database); 00156 return NULL; 00157 } 00158 00159 /* Table structure not already cached; build it now. */ 00160 do { 00161 retry: 00162 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00163 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00164 if (try == 0) { 00165 try = 1; 00166 ast_odbc_sanity_check(obj); 00167 goto retry; 00168 } 00169 ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database); 00170 break; 00171 } 00172 00173 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS); 00174 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00175 if (try == 0) { 00176 try = 1; 00177 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00178 ast_odbc_sanity_check(obj); 00179 goto retry; 00180 } 00181 ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database); 00182 break; 00183 } 00184 00185 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) { 00186 ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database); 00187 break; 00188 } 00189 00190 tableptr->connection = (char *)tableptr + sizeof(*tableptr); 00191 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1; 00192 strcpy(tableptr->connection, database); /* SAFE */ 00193 strcpy(tableptr->table, tablename); /* SAFE */ 00194 AST_RWLIST_HEAD_INIT(&(tableptr->columns)); 00195 00196 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) { 00197 SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr); 00198 00199 if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) { 00200 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database); 00201 error = 1; 00202 break; 00203 } 00204 entry->name = (char *)entry + sizeof(*entry); 00205 strcpy(entry->name, columnname); 00206 00207 SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL); 00208 SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL); 00209 SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL); 00210 SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL); 00211 SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL); 00212 SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL); 00213 00214 /* Specification states that the octenlen should be the maximum number of bytes 00215 * returned in a char or binary column, but it seems that some drivers just set 00216 * it to NULL. (Bad Postgres! No biscuit!) */ 00217 if (entry->octetlen == 0) { 00218 entry->octetlen = entry->size; 00219 } 00220 00221 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); 00222 /* Insert column info into column list */ 00223 AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list); 00224 } 00225 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00226 00227 AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list); 00228 AST_RWLIST_RDLOCK(&(tableptr->columns)); 00229 } while (0); 00230 00231 AST_RWLIST_UNLOCK(&odbc_tables); 00232 00233 if (error) { 00234 destroy_table_cache(tableptr); 00235 tableptr = NULL; 00236 } 00237 if (obj) { 00238 ast_odbc_release_obj(obj); 00239 } 00240 return tableptr; 00241 }
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 293 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(), and update_odbc().
00294 { 00295 int res = 0, i, attempt; 00296 SQLINTEGER nativeerror=0, numfields=0; 00297 SQLSMALLINT diagbytes=0; 00298 unsigned char state[10], diagnostic[256]; 00299 SQLHSTMT stmt; 00300 00301 for (attempt = 0; attempt < 2; attempt++) { 00302 /* This prepare callback may do more than just prepare -- it may also 00303 * bind parameters, bind results, etc. The real key, here, is that 00304 * when we disconnect, all handles become invalid for most databases. 00305 * We must therefore redo everything when we establish a new 00306 * connection. */ 00307 stmt = prepare_cb(obj, data); 00308 00309 if (stmt) { 00310 res = SQLExecute(stmt); 00311 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00312 if (res == SQL_ERROR) { 00313 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00314 for (i = 0; i < numfields; i++) { 00315 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00316 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00317 if (i > 10) { 00318 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00319 break; 00320 } 00321 } 00322 } 00323 00324 ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); 00325 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00326 stmt = NULL; 00327 00328 obj->up = 0; 00329 /* 00330 * While this isn't the best way to try to correct an error, this won't automatically 00331 * fail when the statement handle invalidates. 00332 */ 00333 ast_odbc_sanity_check(obj); 00334 continue; 00335 } else 00336 obj->last_used = ast_tvnow(); 00337 break; 00338 } else if (attempt == 0) 00339 ast_odbc_sanity_check(obj); 00340 } 00341 00342 return stmt; 00343 }
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 642 of file res_odbc.c.
References ao2_ref, and odbc_obj::used.
Referenced by ast_odbc_find_table(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().
00643 { 00644 /* For pooled connections, this frees the connection to be 00645 * reused. For non-pooled connections, it does nothing. */ 00646 obj->used = 0; 00647 #ifdef DEBUG_THREADS 00648 obj->file[0] = '\0'; 00649 obj->function[0] = '\0'; 00650 obj->lineno = 0; 00651 #endif 00652 ao2_ref(obj, -1); 00653 }
struct odbc_obj* ast_odbc_request_obj | ( | const char * | name, | |
int | check | |||
) |
Retrieves a connected ODBC object.
name | The name of the ODBC class for which a connection is needed. | |
check | Whether to ensure that a connection is valid before returning the handle. Usually unnecessary. |
ODBC | object | |
NULL | if there is no connection available with the requested name. |
Definition at line 663 of file res_odbc.c.
References ao2_alloc, ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_assert, ast_copy_string(), ast_log(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_odbc_sanity_check(), ast_tvdiff_sec(), ast_tvnow(), class_container, odbc_class::idlecheck, odbc_obj::last_used, LOG_WARNING, ao2_iterator::obj, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), and odbc_obj::parent.
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(), and update_odbc().
00665 { 00666 struct odbc_obj *obj = NULL; 00667 struct odbc_class *class; 00668 struct ao2_iterator aoi = ao2_iterator_init(class_container, 0); 00669 00670 while ((class = ao2_iterator_next(&aoi))) { 00671 if (!strcmp(class->name, name) && !class->delme) { 00672 break; 00673 } 00674 ao2_ref(class, -1); 00675 } 00676 00677 if (!class) 00678 return NULL; 00679 00680 ast_assert(ao2_ref(class, 0) > 1); 00681 00682 if (class->haspool) { 00683 /* Recycle connections before building another */ 00684 aoi = ao2_iterator_init(class->obj_container, 0); 00685 while ((obj = ao2_iterator_next(&aoi))) { 00686 if (! obj->used) { 00687 ast_mutex_lock(&obj->lock); 00688 obj->used = 1; 00689 ast_mutex_unlock(&obj->lock); 00690 break; 00691 } 00692 ao2_ref(obj, -1); 00693 } 00694 00695 if (obj) { 00696 ast_assert(ao2_ref(obj, 0) > 1); 00697 } 00698 00699 if (!obj && (class->count < class->limit)) { 00700 class->count++; 00701 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 00702 if (!obj) { 00703 ao2_ref(class, -1); 00704 return NULL; 00705 } 00706 ast_assert(ao2_ref(obj, 0) == 1); 00707 ast_mutex_init(&obj->lock); 00708 /* obj inherits the outstanding reference to class */ 00709 obj->parent = class; 00710 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00711 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00712 ao2_ref(obj, -1); 00713 ast_assert(ao2_ref(class, 0) > 0); 00714 obj = NULL; 00715 } else { 00716 obj->used = 1; 00717 ao2_link(class->obj_container, obj); 00718 } 00719 class = NULL; 00720 } else { 00721 /* Object is not constructed, so delete outstanding reference to class. */ 00722 ao2_ref(class, -1); 00723 class = NULL; 00724 } 00725 } else { 00726 /* Non-pooled connection: multiple modules can use the same connection. */ 00727 aoi = ao2_iterator_init(class->obj_container, 0); 00728 while ((obj = ao2_iterator_next(&aoi))) { 00729 /* Non-pooled connection: if there is an entry, return it */ 00730 break; 00731 } 00732 00733 if (obj) { 00734 /* Object is not constructed, so delete outstanding reference to class. */ 00735 ast_assert(ao2_ref(class, 0) > 1); 00736 ao2_ref(class, -1); 00737 class = NULL; 00738 } else { 00739 /* No entry: build one */ 00740 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor); 00741 if (!obj) { 00742 ast_assert(ao2_ref(class, 0) > 1); 00743 ao2_ref(class, -1); 00744 return NULL; 00745 } 00746 ast_mutex_init(&obj->lock); 00747 /* obj inherits the outstanding reference to class */ 00748 obj->parent = class; 00749 if (odbc_obj_connect(obj) == ODBC_FAIL) { 00750 ast_log(LOG_WARNING, "Failed to connect to %s\n", name); 00751 ao2_ref(obj, -1); 00752 obj = NULL; 00753 } else { 00754 ao2_link(class->obj_container, obj); 00755 ast_assert(ao2_ref(obj, 0) > 1); 00756 } 00757 class = NULL; 00758 } 00759 } 00760 00761 if (obj && check) { 00762 ast_odbc_sanity_check(obj); 00763 } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) 00764 odbc_obj_connect(obj); 00765 00766 #ifdef DEBUG_THREADS 00767 if (obj) { 00768 ast_copy_string(obj->file, file, sizeof(obj->file)); 00769 ast_copy_string(obj->function, function, sizeof(obj->function)); 00770 obj->lineno = lineno; 00771 } 00772 #endif 00773 ast_assert(class == NULL); 00774 00775 if (obj) { 00776 ast_assert(ao2_ref(obj, 0) > 1); 00777 } 00778 return obj; 00779 }
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 372 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, and odbc_obj::up.
Referenced by ast_odbc_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_request_obj(), and handle_cli_odbc_show().
00373 { 00374 char *test_sql = "select 1"; 00375 SQLHSTMT stmt; 00376 int res = 0; 00377 00378 if (!ast_strlen_zero(obj->parent->sanitysql)) 00379 test_sql = obj->parent->sanitysql; 00380 00381 if (obj->up) { 00382 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); 00383 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00384 obj->up = 0; 00385 } else { 00386 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); 00387 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00388 obj->up = 0; 00389 } else { 00390 res = SQLExecute(stmt); 00391 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00392 obj->up = 0; 00393 } 00394 } 00395 } 00396 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00397 } 00398 00399 if (!obj->up) { /* Try to reconnect! */ 00400 ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); 00401 odbc_obj_disconnect(obj); 00402 odbc_obj_connect(obj); 00403 } 00404 return obj->up; 00405 }
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 345 of file res_odbc.c.
References ast_log(), ast_tvnow(), odbc_obj::last_used, and LOG_WARNING.
00346 { 00347 int res = 0, i; 00348 SQLINTEGER nativeerror=0, numfields=0; 00349 SQLSMALLINT diagbytes=0; 00350 unsigned char state[10], diagnostic[256]; 00351 00352 res = SQLExecute(stmt); 00353 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { 00354 if (res == SQL_ERROR) { 00355 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); 00356 for (i = 0; i < numfields; i++) { 00357 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); 00358 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); 00359 if (i > 10) { 00360 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); 00361 break; 00362 } 00363 } 00364 } 00365 } else 00366 obj->last_used = ast_tvnow(); 00367 00368 return res; 00369 }