Asterisk - The Open Source Telephony Project GIT-master-c753fe4
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Functions | Variables
res_odbc.c File Reference

ODBC resource manager. More...

#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/res_odbc.h"
#include "asterisk/time.h"
#include "asterisk/astobj2.h"
#include "asterisk/app.h"
#include "asterisk/strings.h"
#include "asterisk/threadstorage.h"
Include dependency graph for res_odbc.c:

Go to the source code of this file.

Data Structures

struct  odbc_class
 
struct  odbc_tables
 
struct  odbc_txn_frame
 

Functions

static void __init_errors_buf (void)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
struct odbc_obj_ast_odbc_request_obj (const char *name, int check, const char *file, const char *function, int lineno)
 
struct odbc_obj_ast_odbc_request_obj2 (const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
 
static int aoro2_class_cb (void *obj, void *arg, int flags)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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. More...
 
int ast_odbc_backslash_is_escape (struct odbc_obj *obj)
 Checks if the database natively supports backslash as an escape character. More...
 
unsigned int ast_odbc_class_get_forcecommit (struct odbc_class *class)
 Get the transaction forcecommit setting for an ODBC class. More...
 
unsigned int ast_odbc_class_get_isolation (struct odbc_class *class)
 Get the transaction isolation setting for an ODBC class. More...
 
const char * ast_odbc_class_get_name (struct odbc_class *class)
 Get the name of an ODBC class. More...
 
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. More...
 
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. More...
 
SQLRETURN ast_odbc_execute_sql (struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
 Execute a unprepared SQL query. More...
 
struct odbc_cache_columnsast_odbc_find_column (struct odbc_cache_tables *table, const char *colname)
 Find a column entry within a cached table structure. More...
 
struct odbc_cache_tablesast_odbc_find_table (const char *database, const char *tablename)
 Find or create an entry describing the table specified. More...
 
unsigned int ast_odbc_get_max_connections (const char *name)
 Return the current configured maximum number of connections for a class. More...
 
const char * ast_odbc_isolation2text (int iso)
 Convert from numeric transaction isolation values to their textual counterparts. More...
 
int ast_odbc_prepare (struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
 Prepares a SQL query on a statement. More...
 
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. More...
 
struct ast_strast_odbc_print_errors (SQLSMALLINT handle_type, SQLHANDLE handle, const char *operation)
 Shortcut for printing errors to logs after a failed SQL operation. More...
 
void ast_odbc_release_obj (struct odbc_obj *obj)
 Releases an ODBC object previously allocated by ast_odbc_request_obj() More...
 
int ast_odbc_smart_execute (struct odbc_obj *obj, SQLHSTMT stmt)
 Executes a prepared statement handle. More...
 
int ast_odbc_text2isolation (const char *txt)
 Convert from textual transaction isolation values to their numeric constants. More...
 
static int connection_dead (struct odbc_obj *connection, struct odbc_class *class)
 Determine if the connection has died. More...
 
static void destroy_table_cache (struct odbc_cache_tables *table)
 
static char * handle_cli_odbc_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int load_module (void)
 
static int load_odbc_config (void)
 
static void odbc_class_destructor (void *data)
 
static odbc_status odbc_obj_connect (struct odbc_obj *obj)
 
static void odbc_obj_destructor (void *data)
 
static odbc_status odbc_obj_disconnect (struct odbc_obj *obj)
 
static void odbc_register_class (struct odbc_class *class, int connect)
 
static int reload (void)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "ODBC resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, .requires = "res_odbc_transaction", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ao2_containerclass_container
 
static struct ast_cli_entry cli_odbc []
 
static struct ast_threadstorage errors_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_errors_buf , .custom_init = NULL , }
 
static struct odbc_tables odbc_tables = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 

Detailed Description

ODBC resource manager.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Anthony Minessale II anthm.nosp@m.ct@y.nosp@m.ahoo..nosp@m.com
Tilghman Lesher tilgh.nosp@m.man@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file res_odbc.c.

Function Documentation

◆ __init_errors_buf()

static void __init_errors_buf ( void  )
static

Definition at line 118 of file res_odbc.c.

120{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1219 of file res_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1219 of file res_odbc.c.

◆ _ast_odbc_request_obj()

struct odbc_obj * _ast_odbc_request_obj ( const char *  name,
int  check,
const char *  file,
const char *  function,
int  lineno 
)

Definition at line 1054 of file res_odbc.c.

1055{
1056 struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
1057 /* XXX New flow means that the "check" parameter doesn't do anything. We're requesting
1058 * a connection from ODBC. We'll either get a new one, which obviously is already connected, or
1059 * we'll get one from the ODBC connection pool. In that case, it will ensure to only give us a
1060 * live connection
1061 */
1062 return _ast_odbc_request_obj2(name, flags, file, function, lineno);
1063}
static const char name[]
Definition: format_mp3.c:68
struct odbc_obj * _ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
Definition: res_odbc.c:959
@ RES_ODBC_SANITY_CHECK
Definition: res_odbc.h:40
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200

References _ast_odbc_request_obj2(), make_ari_stubs::file, ast_flags::flags, name, and RES_ODBC_SANITY_CHECK.

◆ _ast_odbc_request_obj2()

struct odbc_obj * _ast_odbc_request_obj2 ( const char *  name,
struct ast_flags  flags,
const char *  file,
const char *  function,
int  lineno 
)

Definition at line 959 of file res_odbc.c.

960{
961 struct odbc_obj *obj = NULL;
962 struct odbc_class *class;
963
964 if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
965 ast_debug(1, "Class '%s' not found!\n", name);
966 return NULL;
967 }
968
969 while (!obj) {
970 ast_mutex_lock(&class->lock);
971
972 obj = AST_LIST_REMOVE_HEAD(&class->connections, list);
973 if (obj) {
974 --class->cur_cache;
975 }
976
977 ast_mutex_unlock(&class->lock);
978
979 if (!obj) {
980 ast_mutex_lock(&class->lock);
981
982 if (class->connection_cnt < class->maxconnections) {
983 /* If no connection is immediately available establish a new
984 * one if allowed. If we try and fail we give up completely as
985 * we could go into an infinite loop otherwise.
986 */
987 obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
988 if (!obj) {
989 ast_mutex_unlock(&class->lock);
990 break;
991 }
992
993 obj->parent = ao2_bump(class);
994
995 class->connection_cnt++;
996
997 ast_mutex_unlock(&class->lock);
998
999 if (odbc_obj_connect(obj) == ODBC_FAIL) {
1000 ast_mutex_lock(&class->lock);
1001 class->connection_cnt--;
1002 ast_cond_signal(&class->cond);
1003 ast_mutex_unlock(&class->lock);
1004 ao2_ref(obj->parent, -1);
1005 ao2_ref(obj, -1);
1006 obj = NULL;
1007 break;
1008 }
1009
1010 ast_mutex_lock(&class->lock);
1011
1012 ast_debug(2, "Created ODBC handle %p on class '%s', new count is %zd\n", obj,
1013 name, class->connection_cnt);
1014
1015 } else {
1016 /* Otherwise if we're not allowed to create a new one we
1017 * wait for another thread to give up the connection they
1018 * own.
1019 */
1020 ast_cond_wait(&class->cond, &class->lock);
1021 }
1022
1023 ast_mutex_unlock(&class->lock);
1024
1025 } else if (connection_dead(obj, class)) {
1026 /* If the connection is dead try to grab another functional one from the
1027 * pool instead of trying to resurrect this one.
1028 */
1029 ast_mutex_lock(&class->lock);
1030
1031 class->connection_cnt--;
1032 /* this thread will re-acquire, and if that fails will signal,
1033 * thus no need to signal class->cond here */
1034 ast_debug(2, "ODBC handle %p dead - removing from class '%s', new count is %zd\n",
1035 obj, name, class->connection_cnt);
1036
1037 ast_mutex_unlock(&class->lock);
1038
1039 ao2_ref(obj, -1);
1040 obj = NULL;
1041 } else {
1042 /* We successfully grabbed a connection from the pool and all is well!
1043 */
1044 obj->parent = ao2_bump(class);
1045 ast_debug(2, "Reusing ODBC handle %p from class '%s'\n", obj, name);
1046 }
1047 }
1048
1049 ao2_ref(class, -1);
1050
1051 return obj;
1052}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define ast_cond_wait(cond, mutex)
Definition: lock.h:212
#define ast_mutex_unlock(a)
Definition: lock.h:197
#define ast_mutex_lock(a)
Definition: lock.h:196
#define ast_cond_signal(cond)
Definition: lock.h:210
static int aoro2_class_cb(void *obj, void *arg, int flags)
Definition: res_odbc.c:889
static void odbc_obj_destructor(void *data)
Definition: res_odbc.c:199
static odbc_status odbc_obj_connect(struct odbc_obj *obj)
Definition: res_odbc.c:1092
static struct ao2_container * class_container
Definition: res_odbc.c:110
static int connection_dead(struct odbc_obj *connection, struct odbc_class *class)
Determine if the connection has died.
Definition: res_odbc.c:923
@ ODBC_FAIL
Definition: res_odbc.h:36
#define NULL
Definition: resample.c:96
struct odbc_class::@444 list
ODBC container.
Definition: res_odbc.h:46
struct odbc_class * parent
Definition: res_odbc.h:48

References ao2_alloc, ao2_bump, ao2_callback, ao2_ref, aoro2_class_cb(), ast_cond_signal, ast_cond_wait, ast_debug, AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, class_container, connection_dead(), odbc_class::list, name, NULL, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), and odbc_obj::parent.

Referenced by _ast_odbc_request_obj().

◆ aoro2_class_cb()

static int aoro2_class_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 889 of file res_odbc.c.

890{
891 struct odbc_class *class = obj;
892 char *name = arg;
893 if (!strcmp(class->name, name) && !class->delme) {
894 return CMP_MATCH | CMP_STOP;
895 }
896 return 0;
897}
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028

References CMP_MATCH, CMP_STOP, and name.

Referenced by _ast_odbc_request_obj2(), and ast_odbc_get_max_connections().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1219 of file res_odbc.c.

◆ ast_odbc_ast_str_SQLGetData()

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.

Parameters
bufAddress of the pointer to the ast_str structure.
pmaxlenThe maximum size of the resulting string, or 0 for no limit.
StatementHandleThe statement handle from which to retrieve data.
ColumnNumberColumn number (1-based offset) for which to retrieve data.
TargetTypeThe SQL constant indicating what kind of data is to be retrieved (usually SQL_CHAR)
StrLen_or_IndA pointer to a length indicator, specifying the total length of data.

Definition at line 503 of file res_odbc.c.

504{
505 SQLRETURN res;
506
507 if (pmaxlen == 0) {
508 if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
509 ast_str_make_space(buf, *StrLen_or_Ind + 1);
510 }
511 } else if (pmaxlen > 0) {
512 ast_str_make_space(buf, pmaxlen);
513 }
514 res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
516
517 return res;
518}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ast_str_make_space(buf, new_len)
Definition: strings.h:828
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:703
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:742

References ast_str_buffer(), ast_str_make_space, ast_str_size(), ast_str_update(), and buf.

Referenced by acf_odbc_read(), and cli_odbc_read().

◆ ast_odbc_backslash_is_escape()

int ast_odbc_backslash_is_escape ( struct odbc_obj obj)

Checks if the database natively supports backslash as an escape character.

Parameters
objThe ODBC object
Return values
1if backslash is a native escape character
0if an ESCAPE clause is needed to support '\'

Definition at line 884 of file res_odbc.c.

885{
886 return obj->parent->backslash_is_escape;
887}
unsigned int backslash_is_escape
Definition: res_odbc.c:74

References odbc_class::backslash_is_escape, and odbc_obj::parent.

Referenced by odbc_log(), realtime_multi_odbc(), and realtime_odbc().

◆ ast_odbc_class_get_forcecommit()

unsigned int ast_odbc_class_get_forcecommit ( struct odbc_class class)

Get the transaction forcecommit setting for an ODBC class.

Definition at line 550 of file res_odbc.c.

551{
552 return class->forcecommit;
553}

Referenced by create_transaction().

◆ ast_odbc_class_get_isolation()

unsigned int ast_odbc_class_get_isolation ( struct odbc_class class)

Get the transaction isolation setting for an ODBC class.

Definition at line 545 of file res_odbc.c.

546{
547 return class->isolation;
548}

Referenced by create_transaction().

◆ ast_odbc_class_get_name()

const char * ast_odbc_class_get_name ( struct odbc_class class)

Get the name of an ODBC class.

Definition at line 555 of file res_odbc.c.

556{
557 return class->name;
558}

Referenced by ast_odbc_retrieve_transaction_obj().

◆ ast_odbc_clear_cache()

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.

Parameters
databaseName of an ODBC class (used to ensure like-named tables in different databases are not confused)
tablenameTablename for which a cached record should be removed
Return values
0if the cache entry was removed.
-1if no matching entry was found.
Since
1.6.1

Definition at line 348 of file res_odbc.c.

349{
350 struct odbc_cache_tables *tableptr;
351
354 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
356 destroy_table_cache(tableptr);
357 break;
358 }
359 }
362 return tableptr ? 0 : -1;
363}
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
static void destroy_table_cache(struct odbc_cache_tables *table)
Definition: res_odbc.c:206
char * connection
Definition: res_odbc.h:71

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(), and odbc_cache_tables::table.

Referenced by unload_odbc().

◆ ast_odbc_direct_execute()

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.

Parameters
objThe ODBC object
exec_cbA function callback, which, when called, should return a statement handle with result columns bound.
dataA parameter to be passed to the exec_cb parameter function, indicating which statement handle is to be prepared.
Returns
a statement handle
Return values
NULLon error

Definition at line 365 of file res_odbc.c.

366{
367 struct timeval start;
368 SQLHSTMT stmt;
369
370 if (obj->parent->logging) {
371 start = ast_tvnow();
372 }
373
374 stmt = exec_cb(obj, data);
375
376 if (obj->parent->logging) {
377 long execution_time = ast_tvdiff_ms(ast_tvnow(), start);
378
379 if (obj->parent->slowquerylimit && execution_time > obj->parent->slowquerylimit) {
380 ast_log(LOG_WARNING, "SQL query '%s' took %ld milliseconds to execute on class '%s', this may indicate a database problem\n",
381 obj->sql_text, execution_time, obj->parent->name);
382 }
383
384 ast_mutex_lock(&obj->parent->lock);
385 if (execution_time > obj->parent->longest_query_execution_time || !obj->parent->sql_text) {
386 obj->parent->longest_query_execution_time = execution_time;
387 /* Due to the callback nature of the res_odbc API it's not possible to ensure that
388 * the SQL text is removed from the connection in all cases, so only if it becomes the
389 * new longest executing query do we steal the SQL text. In other cases what will happen
390 * is that the SQL text will be freed if the connection is released back to the class or
391 * if a new query is done on the connection.
392 */
393 ast_free(obj->parent->sql_text);
394 obj->parent->sql_text = obj->sql_text;
395 obj->sql_text = NULL;
396 }
398 }
399
400 return stmt;
401}
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
#define LOG_WARNING
unsigned int slowquerylimit
Definition: res_odbc.c:103
char * sql_text
Definition: res_odbc.c:101
char name[80]
Definition: res_odbc.c:67
unsigned int logging
Definition: res_odbc.c:93
long longest_query_execution_time
Definition: res_odbc.c:99
ast_mutex_t lock
Definition: res_odbc.c:87
char * sql_text
Definition: res_odbc.h:54
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ast_free, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_tvdiff_ms(), ast_tvnow(), odbc_class::lock, LOG_WARNING, odbc_class::logging, odbc_class::longest_query_execution_time, odbc_class::name, NULL, odbc_obj::parent, odbc_class::slowquerylimit, odbc_obj::sql_text, and odbc_class::sql_text.

Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), cli_odbc_write(), connection_dead(), and odbc_log().

◆ ast_odbc_execute_sql()

SQLRETURN ast_odbc_execute_sql ( struct odbc_obj obj,
SQLHSTMT *  stmt,
const char *  sql 
)

Execute a unprepared SQL query.

Parameters
objThe ODBC object
stmtThe statement
sqlThe SQL query
Note
This should be used in place of SQLExecDirect

Definition at line 474 of file res_odbc.c.

475{
476 if (obj->parent->logging) {
477 ast_free(obj->sql_text);
478 obj->sql_text = ast_strdup(sql);
480 }
481
482 return SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS);
483}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:764
int queries_executed
Definition: res_odbc.c:97

References ast_atomic_fetchadd_int(), ast_free, ast_strdup, odbc_class::logging, odbc_obj::parent, odbc_class::queries_executed, and odbc_obj::sql_text.

Referenced by execute(), and execute_cb().

◆ ast_odbc_find_column()

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.

Parameters
tableCached table structure, as returned from ast_odbc_find_table()
colnameThe column name requested
Returns
A structure describing the column type, or NULL, if the column is not found.
Since
1.6.1

Definition at line 337 of file res_odbc.c.

338{
339 struct odbc_cache_columns *col;
340 AST_RWLIST_TRAVERSE(&table->columns, col, list) {
341 if (strcasecmp(col->name, colname) == 0) {
342 return col;
343 }
344 }
345 return NULL;
346}
static char * table
Definition: cdr_odbc.c:55
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
These structures are used for adaptive capabilities.
Definition: res_odbc.h:59

References AST_RWLIST_TRAVERSE, odbc_cache_columns::name, NULL, and table.

Referenced by update2_prepare(), and update_odbc().

◆ ast_odbc_find_table()

struct odbc_cache_tables * ast_odbc_find_table ( const char *  database,
const char *  tablename 
)

Find or create an entry describing the table specified.

XXX This creates a connection and disconnects it. In some situations, the caller of this function has its own connection and could donate it to this function instead of needing to create another one.

XXX The automatic readlock of the columns is awkward. It's done because it's possible for multiple threads to have references to the table, and the table is not refcounted. Possible changes here would be

  • Eliminate the table cache entirely. The use of ast_odbc_find_table() is generally questionable. The only real good use right now is from ast_realtime_require_field() in order to make sure the DB has the expected columns in it. Since that is only used sparingly, the need to cache tables is questionable. Instead, the table structure can be fetched from the DB directly each time, resulting in a single owner of the data.
  • Make odbc_cache_tables a refcounted object.

Definition at line 237 of file res_odbc.c.

238{
239 struct odbc_cache_tables *tableptr;
240 struct odbc_cache_columns *entry;
241 char columnname[80];
242 SQLLEN sqlptr;
243 SQLHSTMT stmt = NULL;
244 int res = 0, error = 0;
245 struct odbc_obj *obj;
246
249 if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
250 break;
251 }
252 }
253 if (tableptr) {
254 AST_RWLIST_RDLOCK(&tableptr->columns);
256 return tableptr;
257 }
258
259 if (!(obj = ast_odbc_request_obj(database, 0))) {
260 ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
262 return NULL;
263 }
264
265 /* Table structure not already cached; build it now. */
266 do {
267 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
268 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
269 ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
270 break;
271 }
272
273 res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS);
274 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
275 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
276 ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
277 break;
278 }
279
280 if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
281 ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
282 break;
283 }
284
285 tableptr->connection = (char *)tableptr + sizeof(*tableptr);
286 tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1;
287 strcpy(tableptr->connection, database); /* SAFE */
288 strcpy(tableptr->table, tablename); /* SAFE */
289 AST_RWLIST_HEAD_INIT(&(tableptr->columns));
290
291 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
292 SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
293
294 if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) {
295 ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
296 error = 1;
297 break;
298 }
299 entry->name = (char *)entry + sizeof(*entry);
300 strcpy(entry->name, columnname);
301
302 SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
303 SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
304 SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
305 SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
306 SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
307 SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
308
309 /* Specification states that the octenlen should be the maximum number of bytes
310 * returned in a char or binary column, but it seems that some drivers just set
311 * it to NULL. (Bad Postgres! No biscuit!) */
312 if (entry->octetlen == 0) {
313 entry->octetlen = entry->size;
314 }
315
316 ast_debug(3, "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);
317 /* Insert column info into column list */
318 AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
319 }
320 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
321
323 AST_RWLIST_RDLOCK(&(tableptr->columns));
324 break;
325 } while (1);
326
328
329 if (error) {
330 destroy_table_cache(tableptr);
331 tableptr = NULL;
332 }
334 return tableptr;
335}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define LOG_ERROR
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_HEAD_INIT(head)
Initializes an rwlist head structure.
Definition: linkedlists.h:639
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:741
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:828
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
Definition: res_odbc.h:120
SQLSMALLINT decimals
Definition: res_odbc.h:63
SQLSMALLINT radix
Definition: res_odbc.h:64
SQLSMALLINT type
Definition: res_odbc.h:61
SQLINTEGER octetlen
Definition: res_odbc.h:66
SQLINTEGER size
Definition: res_odbc.h:62
SQLSMALLINT nullable
Definition: res_odbc.h:65
struct odbc_cache_tables::_columns columns
struct odbc_obj::@257 list
SQLHDBC con
Definition: res_odbc.h:47
int error(const char *format,...)
Definition: utils/frame.c:999

References ast_calloc, ast_debug, AST_LIST_INSERT_TAIL, ast_log, ast_odbc_release_obj(), ast_odbc_request_obj, AST_RWLIST_HEAD_INIT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, odbc_cache_tables::columns, odbc_obj::con, odbc_cache_tables::connection, odbc_cache_columns::decimals, destroy_table_cache(), error(), odbc_obj::list, LOG_ERROR, LOG_WARNING, odbc_cache_columns::name, NULL, 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_odbc(), and update_odbc().

◆ ast_odbc_get_max_connections()

unsigned int ast_odbc_get_max_connections ( const char *  name)

Return the current configured maximum number of connections for a class.

Definition at line 899 of file res_odbc.c.

900{
901 struct odbc_class *class;
902 unsigned int max_connections;
903
904 class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name);
905 if (!class) {
906 return 0;
907 }
908
909 max_connections = class->maxconnections;
910 ao2_ref(class, -1);
911
912 return max_connections;
913}

References ao2_callback, ao2_ref, aoro2_class_cb(), class_container, and name.

Referenced by release_obj_or_dsn().

◆ ast_odbc_isolation2text()

const char * ast_odbc_isolation2text ( int  iso)

Convert from numeric transaction isolation values to their textual counterparts.

Definition at line 137 of file res_odbc.c.

138{
139 if (iso == SQL_TXN_READ_COMMITTED) {
140 return "read_committed";
141 } else if (iso == SQL_TXN_READ_UNCOMMITTED) {
142 return "read_uncommitted";
143 } else if (iso == SQL_TXN_SERIALIZABLE) {
144 return "serializable";
145 } else if (iso == SQL_TXN_REPEATABLE_READ) {
146 return "repeatable_read";
147 } else {
148 return "unknown";
149 }
150}

Referenced by acf_transaction_read().

◆ ast_odbc_prepare()

int ast_odbc_prepare ( struct odbc_obj obj,
SQLHSTMT *  stmt,
const char *  sql 
)

Prepares a SQL query on a statement.

Parameters
objThe ODBC object
stmtThe statement
sqlThe SQL query
Note
This should be used in place of SQLPrepare

Definition at line 459 of file res_odbc.c.

460{
461 if (obj->parent->logging) {
462 /* It is possible for this connection to be reused without being
463 * released back to the class, so we free what may already exist
464 * and place the new SQL in.
465 */
466 ast_free(obj->sql_text);
467 obj->sql_text = ast_strdup(sql);
469 }
470
471 return SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
472}
int prepares_executed
Definition: res_odbc.c:95

References ast_atomic_fetchadd_int(), ast_free, ast_strdup, odbc_class::logging, odbc_obj::parent, odbc_class::prepares_executed, and odbc_obj::sql_text.

Referenced by config_odbc_prepare(), custom_prepare(), generic_prepare(), length_determination_odbc_prepare(), and update2_prepare().

◆ ast_odbc_prepare_and_execute()

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.

Parameters
objThe ODBC object
prepare_cbA function callback, which, when called, should return a statement handle prepared, with any necessary parameters or result columns bound.
dataA parameter to be passed to the prepare_cb parameter function, indicating which statement handle is to be prepared.
Returns
a statement handle
Return values
NULLon error

Definition at line 403 of file res_odbc.c.

404{
405 struct timeval start;
406 int res = 0;
407 SQLHSTMT stmt;
408
409 if (obj->parent->logging) {
410 start = ast_tvnow();
411 }
412
413 /* This prepare callback may do more than just prepare -- it may also
414 * bind parameters, bind results, etc. The real key, here, is that
415 * when we disconnect, all handles become invalid for most databases.
416 * We must therefore redo everything when we establish a new
417 * connection. */
418 stmt = prepare_cb(obj, data);
419 if (!stmt) {
420 return NULL;
421 }
422
423 res = SQLExecute(stmt);
424 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
425 if (res == SQL_ERROR) {
426 ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute");
427 }
428
429 ast_log(LOG_WARNING, "SQL Execute error %d!\n", res);
430 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
431 stmt = NULL;
432 } else if (obj->parent->logging) {
433 long execution_time = ast_tvdiff_ms(ast_tvnow(), start);
434
435 if (obj->parent->slowquerylimit && execution_time > obj->parent->slowquerylimit) {
436 ast_log(LOG_WARNING, "SQL query '%s' took %ld milliseconds to execute on class '%s', this may indicate a database problem\n",
437 obj->sql_text, execution_time, obj->parent->name);
438 }
439
440 ast_mutex_lock(&obj->parent->lock);
441
442 /* If this takes the record on longest query execution time, update the parent class
443 * with the information.
444 */
445 if (execution_time > obj->parent->longest_query_execution_time || !obj->parent->sql_text) {
446 obj->parent->longest_query_execution_time = execution_time;
447 ast_free(obj->parent->sql_text);
448 obj->parent->sql_text = obj->sql_text;
449 obj->sql_text = NULL;
450 }
452
454 }
455
456 return stmt;
457}
struct ast_str * ast_odbc_print_errors(SQLSMALLINT handle_type, SQLHANDLE handle, const char *operation)
Shortcut for printing errors to logs after a failed SQL operation.
Definition: res_odbc.c:520

References ast_atomic_fetchadd_int(), ast_free, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_odbc_print_errors(), ast_tvdiff_ms(), ast_tvnow(), odbc_class::lock, LOG_WARNING, odbc_class::logging, odbc_class::longest_query_execution_time, odbc_class::name, NULL, odbc_obj::parent, odbc_class::queries_executed, odbc_class::slowquerylimit, odbc_obj::sql_text, and odbc_class::sql_text.

Referenced by config_odbc(), destroy_odbc(), odbc_log(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().

◆ ast_odbc_print_errors()

struct ast_str * ast_odbc_print_errors ( SQLSMALLINT  handle_type,
SQLHANDLE  handle,
const char *  operation 
)

Shortcut for printing errors to logs after a failed SQL operation.

Parameters
handle_typeThe type of SQL handle on which to gather diagnostics
handleThe SQL handle to gather diagnostics from
operationThe name of the failed operation.
Returns
The error string that was printed to the logs

Definition at line 520 of file res_odbc.c.

521{
522 struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
523 SQLINTEGER nativeerror = 0;
524 SQLSMALLINT diagbytes = 0;
525 SQLSMALLINT i;
526 unsigned char state[10];
527 unsigned char diagnostic[256];
528
529 ast_str_reset(errors);
530 i = 0;
531 while (SQLGetDiagRec(handle_type, handle, ++i, state, &nativeerror,
532 diagnostic, sizeof(diagnostic), &diagbytes) == SQL_SUCCESS) {
533 ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
534 ast_log(LOG_WARNING, "%s returned an error: %s: %s\n", operation, state, diagnostic);
535 /* XXX Why is this here? */
536 if (i > 10) {
537 ast_log(LOG_WARNING, "There are more than 10 diagnostic records! Ignore the rest.\n");
538 break;
539 }
540 }
541
542 return errors;
543}
static struct ast_threadstorage errors_buf
Definition: res_odbc.c:118
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
Support for dynamic strings.
Definition: strings.h:623

References ast_log, ast_str_append(), ast_str_reset(), ast_str_strlen(), ast_str_thread_get(), errors_buf, and LOG_WARNING.

Referenced by acf_transaction_write(), ast_odbc_prepare_and_execute(), ast_odbc_smart_execute(), commit_exec(), create_transaction(), custom_prepare(), release_transaction(), rollback_exec(), and update2_prepare().

◆ ast_odbc_release_obj()

void ast_odbc_release_obj ( struct odbc_obj obj)

Releases an ODBC object previously allocated by ast_odbc_request_obj()

Parameters
objThe ODBC object

Definition at line 828 of file res_odbc.c.

829{
830 struct odbc_class *class = obj->parent;
831
832 ast_debug(2, "Releasing ODBC handle %p into pool\n", obj);
833
834 /* The odbc_obj only holds a reference to the class when it is
835 * actively being used. This guarantees no circular reference
836 * between odbc_class and odbc_obj. Since it is being released
837 * we also release our class reference. If a reload occurred before
838 * the class will go away automatically once all odbc_obj are
839 * released back.
840 */
841 obj->parent = NULL;
842
843 /* Free the SQL text so that the next user of this connection has
844 * a fresh start.
845 */
846 ast_free(obj->sql_text);
847 obj->sql_text = NULL;
848
849 ast_mutex_lock(&class->lock);
850 if (class->cache_is_queue) {
851 AST_LIST_INSERT_TAIL(&class->connections, obj, list);
852 } else {
853 AST_LIST_INSERT_HEAD(&class->connections, obj, list);
854 }
855
856 if (class->cur_cache >= class->max_cache_size) {
857 /* cache is full */
858 if (class->cache_is_queue) {
859 /* HEAD will be oldest */
860 obj = AST_LIST_REMOVE_HEAD(&class->connections, list);
861 } else {
862 /* TAIL will be oldest */
863 obj = AST_LIST_LAST(&class->connections);
864 AST_LIST_REMOVE(&class->connections, obj, list);
865 }
866 --class->connection_cnt;
867 ast_mutex_unlock(&class->lock);
868
869 ast_debug(2, "ODBC Pool '%s' exceeded cache size, dropping '%p', connection count is %zd (%u cached)\n",
870 class->name, obj, class->connection_cnt, class->cur_cache);
871
872 ao2_ref(obj, -1);
873
874 ast_mutex_lock(&class->lock);
875 } else {
876 ++class->cur_cache;
877 }
878 ast_cond_signal(&class->cond);
879 ast_mutex_unlock(&class->lock);
880
881 ao2_ref(class, -1);
882}
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:429
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856

References ao2_ref, ast_cond_signal, ast_debug, ast_free, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LAST, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, NULL, odbc_obj::parent, and odbc_obj::sql_text.

Referenced by ast_odbc_find_table(), config_odbc(), create_transaction(), destroy_odbc(), dsn_destructor(), get_dsn(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), release_obj_or_dsn(), release_transaction(), store_odbc(), update2_odbc(), and update_odbc().

◆ ast_odbc_smart_execute()

int ast_odbc_smart_execute ( struct odbc_obj obj,
SQLHSTMT  stmt 
)

Executes a prepared statement handle.

Parameters
objThe non-NULL result of odbc_request_obj()
stmtThe prepared statement handle
Return values
0on success
-1on 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 485 of file res_odbc.c.

486{
487 int res = 0;
488
489 res = SQLExecute(stmt);
490 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
491 if (res == SQL_ERROR) {
492 ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute");
493 }
494 }
495
496 if (obj->parent->logging) {
498 }
499
500 return res;
501}

References ast_atomic_fetchadd_int(), ast_odbc_print_errors(), odbc_class::logging, odbc_obj::parent, and odbc_class::queries_executed.

◆ ast_odbc_text2isolation()

int ast_odbc_text2isolation ( const char *  txt)

Convert from textual transaction isolation values to their numeric constants.

Definition at line 152 of file res_odbc.c.

153{
154 if (strncasecmp(txt, "read_", 5) == 0) {
155 if (strncasecmp(txt + 5, "c", 1) == 0) {
156 return SQL_TXN_READ_COMMITTED;
157 } else if (strncasecmp(txt + 5, "u", 1) == 0) {
158 return SQL_TXN_READ_UNCOMMITTED;
159 } else {
160 return 0;
161 }
162 } else if (strncasecmp(txt, "ser", 3) == 0) {
163 return SQL_TXN_SERIALIZABLE;
164 } else if (strncasecmp(txt, "rep", 3) == 0) {
165 return SQL_TXN_REPEATABLE_READ;
166 } else {
167 return 0;
168 }
169}

Referenced by acf_transaction_write(), and load_odbc_config().

◆ connection_dead()

static int connection_dead ( struct odbc_obj connection,
struct odbc_class class 
)
static

Determine if the connection has died.

Parameters
connectionThe connection to check
classThe ODBC class
Return values
1Yep, it's dead
0It's alive and well

Definition at line 923 of file res_odbc.c.

924{
925 char *test_sql = "select 1";
926 SQLINTEGER dead;
927 SQLRETURN res;
928 SQLHSTMT stmt;
929
930 res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0);
931 if (SQL_SUCCEEDED(res)) {
932 return dead == SQL_CD_TRUE ? 1 : 0;
933 }
934
935 /* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a
936 * probing query instead
937 */
938 res = SQLAllocHandle(SQL_HANDLE_STMT, connection->con, &stmt);
939 if (!SQL_SUCCEEDED(res)) {
940 return 1;
941 }
942
943 if (!ast_strlen_zero(class->sanitysql)) {
944 test_sql = class->sanitysql;
945 }
946
947 res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
948 if (!SQL_SUCCEEDED(res)) {
949 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
950 return 1;
951 }
952
953 res = SQLExecute(stmt);
954 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
955
956 return SQL_SUCCEEDED(res) ? 0 : 1;
957}
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
char * sanitysql
Definition: res_odbc.c:71

References ast_strlen_zero(), and odbc_obj::con.

Referenced by _ast_odbc_request_obj2().

◆ destroy_table_cache()

static void destroy_table_cache ( struct odbc_cache_tables table)
static

Definition at line 206 of file res_odbc.c.

207{
208 struct odbc_cache_columns *col;
209
210 ast_debug(1, "Destroying table cache for %s\n", table->table);
211
212 AST_RWLIST_WRLOCK(&table->columns);
213 while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
214 ast_free(col);
215 }
216 AST_RWLIST_UNLOCK(&table->columns);
218
220}
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:844
#define AST_RWLIST_HEAD_DESTROY(head)
Destroys an rwlist head structure.
Definition: linkedlists.h:667

References ast_debug, ast_free, AST_RWLIST_HEAD_DESTROY, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and table.

Referenced by ast_odbc_clear_cache(), ast_odbc_find_table(), and reload().

◆ handle_cli_odbc_show()

static char * handle_cli_odbc_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 728 of file res_odbc.c.

729{
730 struct ao2_iterator aoi;
731 struct odbc_class *class;
732 int length = 0;
733 int which = 0;
734 char *ret = NULL;
735
736 switch (cmd) {
737 case CLI_INIT:
738 e->command = "odbc show";
739 e->usage =
740 "Usage: odbc show [class]\n"
741 " List settings of a particular ODBC class or,\n"
742 " if not specified, all classes.\n";
743 return NULL;
744 case CLI_GENERATE:
745 if (a->pos != 2)
746 return NULL;
747 length = strlen(a->word);
749 while ((class = ao2_iterator_next(&aoi))) {
750 if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
751 ret = ast_strdup(class->name);
752 }
753 ao2_ref(class, -1);
754 if (ret) {
755 break;
756 }
757 }
759 if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
760 ret = ast_strdup("all");
761 }
762 return ret;
763 }
764
765 ast_cli(a->fd, "\nODBC DSN Settings\n");
766 ast_cli(a->fd, "-----------------\n\n");
768 while ((class = ao2_iterator_next(&aoi))) {
769 if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
770 char timestr[80];
771 struct ast_tm tm;
772
773 ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn);
774
775 if (class->last_negative_connect.tv_sec > 0) {
776 ast_localtime(&class->last_negative_connect, &tm, NULL);
777 ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm);
778 ast_cli(a->fd, " Last fail connection attempt: %s\n", timestr);
779 }
780
781 ast_cli(a->fd, " Number of active connections: %zd (out of %d)\n", class->connection_cnt, class->maxconnections);
782 ast_cli(a->fd, " Cache Type: %s\n", class->cache_is_queue ? "round-robin queue" : "stack (last release, first re-use)");
783 ast_cli(a->fd, " Cache Usage: %u cached out of %u\n", class->cur_cache,
784 class->max_cache_size < class->maxconnections ? class->max_cache_size : class->maxconnections);
785 ast_cli(a->fd, " Logging: %s\n", class->logging ? "Enabled" : "Disabled");
786 if (class->logging) {
787 ast_cli(a->fd, " Number of prepares executed: %d\n", class->prepares_executed);
788 ast_cli(a->fd, " Number of queries executed: %d\n", class->queries_executed);
789 ast_mutex_lock(&class->lock);
790 if (class->sql_text) {
791 ast_cli(a->fd, " Longest running SQL query: %s (%ld milliseconds)\n", class->sql_text, class->longest_query_execution_time);
792 }
793 ast_mutex_unlock(&class->lock);
794 }
795 ast_cli(a->fd, "\n");
796 }
797 ao2_ref(class, -1);
798 }
800
801 return CLI_SUCCESS;
802}
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
const char * name
static struct test_val a

References a, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), ast_localtime(), ast_mutex_lock, ast_mutex_unlock, ast_strdup, ast_strftime(), class_container, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, test_val::name, NULL, and ast_cli_entry::usage.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1195 of file res_odbc.c.

1196{
1198 if (!class_container) {
1200 }
1201
1202 if (load_odbc_config() == -1) {
1204 }
1205
1208
1210}
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
int ao2_match_by_addr(void *obj, void *arg, int flags)
A common ao2_callback is one that matches by address.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:478
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct ast_cli_entry cli_odbc[]
Definition: res_odbc.c:804
static int load_odbc_config(void)
Definition: res_odbc.c:560
struct ast_module * self
Definition: module.h:356
#define ARRAY_LEN(a)
Definition: utils.h:666

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_list, ao2_match_by_addr(), ARRAY_LEN, ast_cli_register_multiple, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_module_shutdown_ref, class_container, cli_odbc, load_odbc_config(), NULL, and ast_module_info::self.

◆ load_odbc_config()

static int load_odbc_config ( void  )
static

Definition at line 560 of file res_odbc.c.

561{
562 static char *cfg = "res_odbc.conf";
563 struct ast_config *config;
564 struct ast_variable *v;
565 char *cat;
566 const char *dsn, *username, *password, *sanitysql;
567 int enabled, bse, conntimeout, forcecommit, isolation, maxconnections, logging, slowquerylimit;
568 struct timeval ncache = { 0, 0 };
569 int preconnect = 0, res = 0, cache_is_queue = 0;
570 struct ast_flags config_flags = { 0 };
571 unsigned int max_cache_size;
572
573 struct odbc_class *new;
574
575 config = ast_config_load(cfg, config_flags);
577 ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
578 return -1;
579 }
580 for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
581 if (!strcasecmp(cat, "ENV")) {
582 for (v = ast_variable_browse(config, cat); v; v = v->next) {
583 setenv(v->name, v->value, 1);
584 ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
585 }
586 } else {
587 /* Reset all to defaults for each class of odbc connections */
589 enabled = 1;
590 preconnect = 0;
591 bse = 1;
592 conntimeout = 10;
593 forcecommit = 0;
594 isolation = SQL_TXN_READ_COMMITTED;
595 maxconnections = 1;
596 logging = 0;
597 slowquerylimit = 5000;
598 cache_is_queue = 0;
599 max_cache_size = UINT_MAX;
600 for (v = ast_variable_browse(config, cat); v; v = v->next) {
601 if (!strcasecmp(v->name, "pooling") ||
602 !strncasecmp(v->name, "share", 5) ||
603 !strcasecmp(v->name, "limit") ||
604 !strcasecmp(v->name, "idlecheck")) {
605 ast_log(LOG_WARNING, "The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options were replaced by 'max_connections'. See res_odbc.conf.sample.\n");
606 } else if (!strcasecmp(v->name, "enabled")) {
607 enabled = ast_true(v->value);
608 } else if (!strcasecmp(v->name, "pre-connect")) {
609 preconnect = ast_true(v->value);
610 } else if (!strcasecmp(v->name, "dsn")) {
611 dsn = v->value;
612 } else if (!strcasecmp(v->name, "username")) {
613 username = v->value;
614 } else if (!strcasecmp(v->name, "password")) {
615 password = v->value;
616 } else if (!strcasecmp(v->name, "sanitysql")) {
617 sanitysql = v->value;
618 } else if (!strcasecmp(v->name, "backslash_is_escape")) {
619 bse = ast_true(v->value);
620 } else if (!strcasecmp(v->name, "connect_timeout")) {
621 if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
622 ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
623 conntimeout = 10;
624 }
625 } else if (!strcasecmp(v->name, "negative_connection_cache")) {
626 double dncache;
627 if (sscanf(v->value, "%lf", &dncache) != 1 || dncache < 0) {
628 ast_log(LOG_WARNING, "negative_connection_cache must be a non-negative integer\n");
629 /* 5 minutes sounds like a reasonable default */
630 ncache.tv_sec = 300;
631 ncache.tv_usec = 0;
632 } else {
633 ncache.tv_sec = (int)dncache;
634 ncache.tv_usec = (dncache - ncache.tv_sec) * 1000000;
635 }
636 } else if (!strcasecmp(v->name, "forcecommit")) {
638 } else if (!strcasecmp(v->name, "isolation")) {
639 if ((isolation = ast_odbc_text2isolation(v->value)) == 0) {
640 ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat);
641 isolation = SQL_TXN_READ_COMMITTED;
642 }
643 } else if (!strcasecmp(v->name, "max_connections")) {
644 if (sscanf(v->value, "%30d", &maxconnections) != 1 || maxconnections < 1) {
645 ast_log(LOG_WARNING, "max_connections must be a positive integer\n");
646 maxconnections = 1;
647 }
648 } else if (!strcasecmp(v->name, "logging")) {
649 logging = ast_true(v->value);
650 } else if (!strcasecmp(v->name, "slow_query_limit")) {
651 if (sscanf(v->value, "%30d", &slowquerylimit) != 1) {
652 ast_log(LOG_WARNING, "slow_query_limit must be a positive integer\n");
653 slowquerylimit = 5000;
654 }
655 } else if (!strcasecmp(v->name, "cache_type")) {
656 cache_is_queue = !strcasecmp(v->value, "rr") ||
657 !strcasecmp(v->value, "roundrobin") ||
658 !strcasecmp(v->value, "queue");
659 } else if (!strcasecmp(v->name, "cache_size")) {
660 if (!strcasecmp(v->value, "-1")) {
661 max_cache_size = UINT_MAX;
662 } else if (sscanf(v->value, "%u", &max_cache_size) != 1) {
663 ast_log(LOG_WARNING, "cache_size must be a non-negative integer or -1 (infinite)\n");
664 }
665 }
666 }
667
668 if (enabled && !ast_strlen_zero(dsn)) {
669 new = ao2_alloc(sizeof(*new), odbc_class_destructor);
670
671 if (!new) {
672 res = -1;
673 break;
674 }
675
676 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
677 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
678
679 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
680 ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
681 ao2_ref(new, -1);
682 return res;
683 }
684
685 new->backslash_is_escape = bse ? 1 : 0;
686 new->forcecommit = forcecommit ? 1 : 0;
687 new->isolation = isolation;
688 new->conntimeout = conntimeout;
689 new->negative_connection_cache = ncache;
690 new->maxconnections = maxconnections;
691 new->logging = logging;
692 new->slowquerylimit = slowquerylimit;
693 new->cache_is_queue = cache_is_queue;
694 new->max_cache_size = max_cache_size;
695 new->cur_cache = 0;
696
697 if (cat)
698 ast_copy_string(new->name, cat, sizeof(new->name));
699 if (dsn)
700 ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
701 if (username && !(new->username = ast_strdup(username))) {
702 ao2_ref(new, -1);
703 break;
704 }
705 if (password && !(new->password = ast_strdup(password))) {
706 ao2_ref(new, -1);
707 break;
708 }
709 if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) {
710 ao2_ref(new, -1);
711 break;
712 }
713
714 ast_mutex_init(&new->lock);
715 ast_cond_init(&new->cond, NULL);
716
717 odbc_register_class(new, preconnect);
718 ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
719 ao2_ref(new, -1);
720 new = NULL;
721 }
722 }
723 }
725 return res;
726}
int setenv(const char *name, const char *value, int overwrite)
static char * dsn
Definition: cdr_odbc.c:55
static const char config[]
Definition: chan_ooh323.c:111
static int enabled
Definition: dnsmgr.c:91
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
#define CONFIG_STATUS_FILEMISSING
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
#define LOG_NOTICE
#define ast_cond_init(cond, attr)
Definition: lock.h:208
#define ast_mutex_init(pmutex)
Definition: lock.h:193
static void odbc_register_class(struct odbc_class *class, int connect)
Definition: res_odbc.c:808
static void odbc_class_destructor(void *data)
Definition: res_odbc.c:171
int ast_odbc_text2isolation(const char *txt)
Convert from textual transaction isolation values to their numeric constants.
Definition: res_odbc.c:152
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Data source name.
Definition: func_odbc.c:181
unsigned int max_cache_size
Definition: res_odbc.c:105
char * password
Definition: res_odbc.c:70
unsigned int maxconnections
Definition: res_odbc.c:79
unsigned int isolation
Definition: res_odbc.c:77
unsigned int cache_is_queue
Definition: res_odbc.c:76
char * username
Definition: res_odbc.c:69
unsigned int conntimeout
Definition: res_odbc.c:78
unsigned int forcecommit
Definition: res_odbc.c:75

References ao2_alloc, ao2_ref, ast_category_browse(), ast_cond_init, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_log, ast_mutex_init, ast_odbc_text2isolation(), ast_strdup, ast_strlen_zero(), ast_true(), ast_variable_browse(), odbc_class::cache_is_queue, config, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, odbc_class::conntimeout, dsn, enabled, odbc_class::forcecommit, odbc_class::isolation, LOG_ERROR, LOG_NOTICE, LOG_WARNING, odbc_class::logging, odbc_class::max_cache_size, odbc_class::maxconnections, ast_variable::name, ast_variable::next, NULL, odbc_class_destructor(), odbc_register_class(), odbc_class::password, odbc_class::sanitysql, setenv(), odbc_class::slowquerylimit, odbc_class::username, and ast_variable::value.

Referenced by load_module(), and reload().

◆ odbc_class_destructor()

static void odbc_class_destructor ( void *  data)
static

Definition at line 171 of file res_odbc.c.

172{
173 struct odbc_class *class = data;
174 struct odbc_obj *obj;
175
176 /* Due to refcounts, we can safely assume that any objects with a reference
177 * to us will prevent our destruction, so we don't need to worry about them.
178 */
179 if (class->username) {
180 ast_free(class->username);
181 }
182 if (class->password) {
183 ast_free(class->password);
184 }
185 if (class->sanitysql) {
186 ast_free(class->sanitysql);
187 }
188
189 while ((obj = AST_LIST_REMOVE_HEAD(&class->connections, list))) {
190 ao2_ref(obj, -1);
191 }
192
193 SQLFreeHandle(SQL_HANDLE_ENV, class->env);
194 ast_mutex_destroy(&class->lock);
195 ast_cond_destroy(&class->cond);
196 ast_free(class->sql_text);
197}
#define ast_cond_destroy(cond)
Definition: lock.h:209
#define ast_mutex_destroy(a)
Definition: lock.h:195

References ao2_ref, ast_cond_destroy, ast_free, AST_LIST_REMOVE_HEAD, ast_mutex_destroy, and odbc_obj::list.

Referenced by load_odbc_config().

◆ odbc_obj_connect()

static odbc_status odbc_obj_connect ( struct odbc_obj obj)
static

Definition at line 1092 of file res_odbc.c.

1093{
1094 int res;
1095 SQLINTEGER err;
1096 short int mlen;
1097 unsigned char msg[200], state[10];
1098#ifdef NEEDTRACE
1099 SQLINTEGER enable = 1;
1100 char *tracefile = "/tmp/odbc.trace";
1101#endif
1102 SQLHDBC con;
1103 long int negative_cache_expiration;
1104
1105 ast_assert(obj->con == NULL);
1106 ast_debug(3, "Connecting %s(%p)\n", obj->parent->name, obj);
1107
1108 /* Dont connect while server is marked as unreachable via negative_connection_cache */
1109 negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec;
1110 if (time(NULL) < negative_cache_expiration) {
1111 char secs[AST_TIME_T_LEN];
1112 ast_time_t_to_string(negative_cache_expiration - time(NULL), secs, sizeof(secs));
1113 ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %s seconds\n", obj->parent->name, secs);
1114 return ODBC_FAIL;
1115 }
1116
1117 res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &con);
1118
1119 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1120 ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
1122 return ODBC_FAIL;
1123 }
1124 SQLSetConnectAttr(con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
1125 SQLSetConnectAttr(con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
1126#ifdef NEEDTRACE
1127 SQLSetConnectAttr(con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
1128 SQLSetConnectAttr(con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
1129#endif
1130
1131 res = SQLConnect(con,
1132 (SQLCHAR *) obj->parent->dsn, SQL_NTS,
1133 (SQLCHAR *) obj->parent->username, SQL_NTS,
1134 (SQLCHAR *) obj->parent->password, SQL_NTS);
1135
1136 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1137 SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1139 ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
1140 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) != SQL_SUCCESS) {
1141 SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1142 ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
1143 }
1144 return ODBC_FAIL;
1145 } else {
1146 ast_debug(3, "res_odbc: Connected to %s [%s (%p)]\n", obj->parent->name, obj->parent->dsn, obj);
1147 }
1148
1149 obj->con = con;
1150 return ODBC_SUCCESS;
1151}
@ ODBC_SUCCESS
Definition: res_odbc.h:36
char dsn[80]
Definition: res_odbc.c:68
struct timeval negative_connection_cache
Definition: res_odbc.c:81
SQLHENV env
Definition: res_odbc.c:72
struct timeval last_negative_connect
Definition: res_odbc.c:83
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
Definition: time.c:152
#define AST_TIME_T_LEN
Definition: time.h:45
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, ast_debug, ast_log, AST_TIME_T_LEN, ast_time_t_to_string(), ast_tvnow(), odbc_obj::con, odbc_class::conntimeout, odbc_class::dsn, odbc_class::env, odbc_class::last_negative_connect, LOG_WARNING, odbc_class::name, odbc_class::negative_connection_cache, NULL, ODBC_FAIL, ODBC_SUCCESS, odbc_obj::parent, odbc_class::password, and odbc_class::username.

Referenced by _ast_odbc_request_obj2().

◆ odbc_obj_destructor()

static void odbc_obj_destructor ( void *  data)
static

Definition at line 199 of file res_odbc.c.

200{
201 struct odbc_obj *obj = data;
202
204}
static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
Definition: res_odbc.c:1065

References odbc_obj_disconnect().

Referenced by _ast_odbc_request_obj2().

◆ odbc_obj_disconnect()

static odbc_status odbc_obj_disconnect ( struct odbc_obj obj)
static

Definition at line 1065 of file res_odbc.c.

1066{
1067 int res;
1068 SQLINTEGER err;
1069 short int mlen;
1070 unsigned char msg[200], state[10];
1071 SQLHDBC con;
1072
1073 /* Nothing to disconnect */
1074 if (!obj->con) {
1075 return ODBC_SUCCESS;
1076 }
1077
1078 con = obj->con;
1079 obj->con = NULL;
1080 res = SQLDisconnect(con);
1081
1082 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) == SQL_SUCCESS) {
1083 ast_debug(3, "Database handle %p (connection %p) deallocated\n", obj, con);
1084 } else {
1085 SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1086 ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
1087 }
1088
1089 return ODBC_SUCCESS;
1090}

References ast_debug, ast_log, odbc_obj::con, LOG_WARNING, NULL, and ODBC_SUCCESS.

Referenced by odbc_obj_destructor().

◆ odbc_register_class()

static void odbc_register_class ( struct odbc_class class,
int  connect 
)
static

Definition at line 808 of file res_odbc.c.

809{
810 struct odbc_obj *obj;
811
813 /* I still have a reference in the caller, so a deref is NOT missing here. */
814
815 if (!preconnect) {
816 return;
817 }
818
819 /* Request and release builds a connection */
820 obj = ast_odbc_request_obj(class->name, 0);
821 if (obj) {
823 }
824
825 return;
826}
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532

References ao2_link, ast_odbc_release_obj(), ast_odbc_request_obj, and class_container.

Referenced by load_odbc_config().

◆ reload()

static int reload ( void  )
static

Definition at line 1153 of file res_odbc.c.

1154{
1155 struct odbc_cache_tables *table;
1156 struct odbc_class *class;
1158
1159 /* First, mark all to be purged */
1160 while ((class = ao2_iterator_next(&aoi))) {
1161 class->delme = 1;
1162 ao2_ref(class, -1);
1163 }
1165
1167
1169 while ((class = ao2_iterator_next(&aoi))) {
1170 if (class->delme) {
1172 }
1173 ao2_ref(class, -1);
1174 }
1176
1177 /* Empty the cache; it will get rebuilt the next time the tables are needed. */
1179 while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
1181 }
1183
1184 return 0;
1185}
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, class_container, destroy_table_cache(), load_odbc_config(), and table.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1187 of file res_odbc.c.

1188{
1191
1192 return 0;
1193}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30

References ao2_cleanup, ARRAY_LEN, ast_cli_unregister_multiple(), class_container, and cli_odbc.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "ODBC resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, .requires = "res_odbc_transaction", }
static

Definition at line 1219 of file res_odbc.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1219 of file res_odbc.c.

◆ class_container

struct ao2_container* class_container
static

◆ cli_odbc

struct ast_cli_entry cli_odbc[]
static
Initial value:
= {
{ .handler = handle_cli_odbc_show , .summary = "List ODBC DSN(s)" ,}
}
static char * handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_odbc.c:728

Definition at line 804 of file res_odbc.c.

Referenced by load_module(), and unload_module().

◆ errors_buf

struct ast_threadstorage errors_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_errors_buf , .custom_init = NULL , }
static

Definition at line 118 of file res_odbc.c.

Referenced by ast_odbc_print_errors().

◆ odbc_tables

struct odbc_tables odbc_tables = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static