Asterisk - The Open Source Telephony Project  18.5.0
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)
 Get a ODBC connection object. More...
 
struct odbc_obj_ast_odbc_request_obj2 (const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
 Retrieves a connected ODBC object. More...
 
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 nonprepared 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)
 
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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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 113 of file res_odbc.c.

115 {

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1147 of file res_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1147 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 
)

Get a ODBC connection object.

The "check" parameter is leftover from an earlier implementation where database connections were cached by res_odbc. Since connections are managed by unixODBC now, this parameter is only kept around for API compatibility.

Parameters
nameThe name of the res_odbc.conf section describing the database to connect to
checkunused
Returns
A connection to the database. Call ast_odbc_release_obj() when finished.

Definition at line 984 of file res_odbc.c.

References _ast_odbc_request_obj2(), and RES_ODBC_SANITY_CHECK.

985 {
986  struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
987  /* XXX New flow means that the "check" parameter doesn't do anything. We're requesting
988  * a connection from ODBC. We'll either get a new one, which obviously is already connected, or
989  * we'll get one from the ODBC connection pool. In that case, it will ensure to only give us a
990  * live connection
991  */
992  return _ast_odbc_request_obj2(name, flags, file, function, lineno);
993 }
unsigned int flags
Definition: utils.h:200
struct odbc_obj * _ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
Retrieves a connected ODBC object.
Definition: res_odbc.c:917
static const char name[]
Definition: cdr_mysql.c:74
Structure used to handle boolean flags.
Definition: utils.h:199

◆ _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 
)

Retrieves a connected ODBC object.

Deprecated:

This is only around for backwards-compatibility with older versions of Asterisk.

Definition at line 917 of file res_odbc.c.

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

Referenced by _ast_odbc_request_obj().

918 {
919  struct odbc_obj *obj = NULL;
920  struct odbc_class *class;
921 
922  if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
923  ast_debug(1, "Class '%s' not found!\n", name);
924  return NULL;
925  }
926 
927  ast_mutex_lock(&class->lock);
928 
929  while (!obj) {
930  obj = AST_LIST_REMOVE_HEAD(&class->connections, list);
931 
932  if (!obj) {
933  if (class->connection_cnt < class->maxconnections) {
934  /* If no connection is immediately available establish a new
935  * one if allowed. If we try and fail we give up completely as
936  * we could go into an infinite loop otherwise.
937  */
938  obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
939  if (!obj) {
940  break;
941  }
942 
943  obj->parent = ao2_bump(class);
944  if (odbc_obj_connect(obj) == ODBC_FAIL) {
945  ao2_ref(obj->parent, -1);
946  ao2_ref(obj, -1);
947  obj = NULL;
948  break;
949  }
950 
951  class->connection_cnt++;
952  ast_debug(2, "Created ODBC handle %p on class '%s', new count is %zd\n", obj,
953  name, class->connection_cnt);
954  } else {
955  /* Otherwise if we're not allowed to create a new one we
956  * wait for another thread to give up the connection they
957  * own.
958  */
959  ast_cond_wait(&class->cond, &class->lock);
960  }
961  } else if (connection_dead(obj, class)) {
962  /* If the connection is dead try to grab another functional one from the
963  * pool instead of trying to resurrect this one.
964  */
965  ao2_ref(obj, -1);
966  obj = NULL;
967  class->connection_cnt--;
968  ast_debug(2, "ODBC handle %p dead - removing from class '%s', new count is %zd\n",
969  obj, name, class->connection_cnt);
970  } else {
971  /* We successfully grabbed a connection from the pool and all is well!
972  */
973  obj->parent = ao2_bump(class);
974  ast_debug(2, "Reusing ODBC handle %p from class '%s'\n", obj, name);
975  }
976  }
977 
978  ast_mutex_unlock(&class->lock);
979  ao2_ref(class, -1);
980 
981  return obj;
982 }
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
static int aoro2_class_cb(void *obj, void *arg, int flags)
Definition: res_odbc.c:847
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491
static void odbc_obj_destructor(void *data)
Definition: res_odbc.c:194
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
ODBC container.
Definition: res_odbc.h:46
static int connection_dead(struct odbc_obj *connection, struct odbc_class *class)
Definition: res_odbc.c:881
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
struct odbc_class * parent
Definition: res_odbc.h:48
static odbc_status odbc_obj_connect(struct odbc_obj *obj)
Definition: res_odbc.c:1022
struct odbc_class::@468 list
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static const char name[]
Definition: cdr_mysql.c:74
static struct ao2_container * class_container
Definition: res_odbc.c:105
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ aoro2_class_cb()

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

Definition at line 847 of file res_odbc.c.

References CMP_MATCH, CMP_STOP, and odbc_class::name.

Referenced by _ast_odbc_request_obj2().

848 {
849  struct odbc_class *class = obj;
850  char *name = arg;
851  if (!strcmp(class->name, name) && !class->delme) {
852  return CMP_MATCH | CMP_STOP;
853  }
854  return 0;
855 }
static const char name[]
Definition: cdr_mysql.c:74

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1147 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 507 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().

508 {
509  SQLRETURN res;
510 
511  if (pmaxlen == 0) {
512  if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
513  ast_str_make_space(buf, *StrLen_or_Ind + 1);
514  }
515  } else if (pmaxlen > 0) {
516  ast_str_make_space(buf, pmaxlen);
517  }
518  res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
519  ast_str_update(*buf);
520 
521  return res;
522 }
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:699
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
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:663

◆ 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
Returns
Returns 1 if backslash is a native escape character, 0 if an ESCAPE clause is needed to support '\'

Definition at line 842 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().

843 {
844  return obj->parent->backslash_is_escape;
845 }
struct odbc_class * parent
Definition: res_odbc.h:48
unsigned int backslash_is_escape
Definition: res_odbc.c:74

◆ 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 554 of file res_odbc.c.

Referenced by create_transaction().

555 {
556  return class->forcecommit;
557 }

◆ 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 549 of file res_odbc.c.

Referenced by create_transaction().

550 {
551  return class->isolation;
552 }

◆ 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 559 of file res_odbc.c.

Referenced by ast_odbc_retrieve_transaction_obj().

560 {
561  return class->name;
562 }

◆ 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, or -1 if no matching entry was found.
Since
1.6.1

Definition at line 352 of file res_odbc.c.

References AST_LIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, odbc_cache_tables::connection, destroy_table_cache(), odbc_class::list, and odbc_cache_tables::table.

Referenced by unload_odbc().

353 {
354  struct odbc_cache_tables *tableptr;
355 
357  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
358  if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
360  destroy_table_cache(tableptr);
361  break;
362  }
363  }
366  return tableptr ? 0 : -1;
367 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
char * connection
Definition: res_odbc.h:71
static void destroy_table_cache(struct odbc_cache_tables *table)
Definition: res_odbc.c:201
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616

◆ 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.
Return values
astatement handle
NULLon error

Definition at line 369 of file res_odbc.c.

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().

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

◆ ast_odbc_execute_sql()

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

Execute a nonprepared SQL query.

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

Definition at line 478 of file res_odbc.c.

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().

479 {
480  if (obj->parent->logging) {
481  ast_free(obj->sql_text);
482  obj->sql_text = ast_strdup(sql);
484  }
485 
486  return SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS);
487 }
unsigned int logging
Definition: res_odbc.c:92
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
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:755
struct odbc_class * parent
Definition: res_odbc.h:48
#define ast_free(a)
Definition: astmm.h:182
char * sql_text
Definition: res_odbc.h:54
int queries_executed
Definition: res_odbc.c:96

◆ 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
Return values
Astructure describing the column type, or NULL, if the column is not found.
Since
1.6.1

Definition at line 341 of file res_odbc.c.

References AST_RWLIST_TRAVERSE, odbc_cache_tables::columns, odbc_class::list, odbc_cache_columns::name, and NULL.

Referenced by update2_prepare(), and update_odbc().

342 {
343  struct odbc_cache_columns *col;
344  AST_RWLIST_TRAVERSE(&table->columns, col, list) {
345  if (strcasecmp(col->name, colname) == 0) {
346  return col;
347  }
348  }
349  return NULL;
350 }
#define NULL
Definition: resample.c:96
These structures are used for adaptive capabilities.
Definition: res_odbc.h:59
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct odbc_cache_tables::_columns columns

◆ 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.

Parameters
databaseName of an ODBC class on which to query the table
tablenameTablename to describe
Return values
Astructure 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.

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.
Since
1.6.1

Definition at line 241 of file res_odbc.c.

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_class::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().

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

◆ 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 857 of file res_odbc.c.

References ao2_callback, and ao2_ref.

Referenced by release_obj_or_dsn().

858 {
859  struct odbc_class *class;
860  unsigned int max_connections;
861 
862  class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name);
863  if (!class) {
864  return 0;
865  }
866 
867  max_connections = class->maxconnections;
868  ao2_ref(class, -1);
869 
870  return max_connections;
871 }
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
static int aoro2_class_cb(void *obj, void *arg, int flags)
Definition: res_odbc.c:847
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static const char name[]
Definition: cdr_mysql.c:74
static struct ao2_container * class_container
Definition: res_odbc.c:105

◆ ast_odbc_isolation2text()

const char* ast_odbc_isolation2text ( int  iso)

Convert from numeric transaction isolation values to their textual counterparts.

Definition at line 132 of file res_odbc.c.

Referenced by acf_transaction_read().

133 {
134  if (iso == SQL_TXN_READ_COMMITTED) {
135  return "read_committed";
136  } else if (iso == SQL_TXN_READ_UNCOMMITTED) {
137  return "read_uncommitted";
138  } else if (iso == SQL_TXN_SERIALIZABLE) {
139  return "serializable";
140  } else if (iso == SQL_TXN_REPEATABLE_READ) {
141  return "repeatable_read";
142  } else {
143  return "unknown";
144  }
145 }

◆ 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 sql The SQL query
Note
This should be used in place of SQLPrepare

Definition at line 463 of file res_odbc.c.

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().

464 {
465  if (obj->parent->logging) {
466  /* It is possible for this connection to be reused without being
467  * released back to the class, so we free what may already exist
468  * and place the new SQL in.
469  */
470  ast_free(obj->sql_text);
471  obj->sql_text = ast_strdup(sql);
473  }
474 
475  return SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
476 }
unsigned int logging
Definition: res_odbc.c:92
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
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:755
int prepares_executed
Definition: res_odbc.c:94
struct odbc_class * parent
Definition: res_odbc.h:48
#define ast_free(a)
Definition: astmm.h:182
char * sql_text
Definition: res_odbc.h:54

◆ 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.
Return values
astatement handle
NULLon error

Definition at line 407 of file res_odbc.c.

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(), free_zone(), odbc_log(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().

408 {
409  struct timeval start;
410  int res = 0;
411  SQLHSTMT stmt;
412 
413  if (obj->parent->logging) {
414  start = ast_tvnow();
415  }
416 
417  /* This prepare callback may do more than just prepare -- it may also
418  * bind parameters, bind results, etc. The real key, here, is that
419  * when we disconnect, all handles become invalid for most databases.
420  * We must therefore redo everything when we establish a new
421  * connection. */
422  stmt = prepare_cb(obj, data);
423  if (!stmt) {
424  return NULL;
425  }
426 
427  res = SQLExecute(stmt);
428  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
429  if (res == SQL_ERROR) {
430  ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute");
431  }
432 
433  ast_log(LOG_WARNING, "SQL Execute error %d!\n", res);
434  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
435  stmt = NULL;
436  } else if (obj->parent->logging) {
437  long execution_time = ast_tvdiff_ms(ast_tvnow(), start);
438 
439  if (obj->parent->slowquerylimit && execution_time > obj->parent->slowquerylimit) {
440  ast_log(LOG_WARNING, "SQL query '%s' took %ld milliseconds to execute on class '%s', this may indicate a database problem\n",
441  obj->sql_text, execution_time, obj->parent->name);
442  }
443 
444  ast_mutex_lock(&obj->parent->lock);
445 
446  /* If this takes the record on longest query execution time, update the parent class
447  * with the information.
448  */
449  if (execution_time > obj->parent->longest_query_execution_time || !obj->parent->sql_text) {
450  obj->parent->longest_query_execution_time = execution_time;
451  ast_free(obj->parent->sql_text);
452  obj->parent->sql_text = obj->sql_text;
453  obj->sql_text = NULL;
454  }
455  ast_mutex_unlock(&obj->parent->lock);
456 
458  }
459 
460  return stmt;
461 }
ast_mutex_t lock
Definition: res_odbc.c:86
char name[80]
Definition: res_odbc.c:67
char * sql_text
Definition: res_odbc.c:100
unsigned int logging
Definition: res_odbc.c:92
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:524
#define LOG_WARNING
Definition: logger.h:274
unsigned int slowquerylimit
Definition: res_odbc.c:102
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define NULL
Definition: resample.c:96
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:755
#define ast_log
Definition: astobj2.c:42
struct odbc_class * parent
Definition: res_odbc.h:48
#define ast_free(a)
Definition: astmm.h:182
char * sql_text
Definition: res_odbc.h:54
int queries_executed
Definition: res_odbc.c:96
long longest_query_execution_time
Definition: res_odbc.c:98
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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 524 of file res_odbc.c.

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().

525 {
526  struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
527  SQLINTEGER nativeerror = 0;
528  SQLSMALLINT diagbytes = 0;
529  SQLSMALLINT i;
530  unsigned char state[10];
531  unsigned char diagnostic[256];
532 
533  ast_str_reset(errors);
534  i = 0;
535  while (SQLGetDiagRec(handle_type, handle, ++i, state, &nativeerror,
536  diagnostic, sizeof(diagnostic), &diagbytes) == SQL_SUCCESS) {
537  ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
538  ast_log(LOG_WARNING, "%s returned an error: %s: %s\n", operation, state, diagnostic);
539  /* XXX Why is this here? */
540  if (i > 10) {
541  ast_log(LOG_WARNING, "There are more than 10 diagnostic records! Ignore the rest.\n");
542  break;
543  }
544  }
545 
546  return errors;
547 }
#define LOG_WARNING
Definition: logger.h:274
static struct ast_threadstorage errors_buf
Definition: res_odbc.c:113
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:1091
#define ast_log
Definition: astobj2.c:42
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
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:653
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
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:861

◆ 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 813 of file res_odbc.c.

References ao2_ref, ast_cond_signal, ast_debug, ast_free, AST_LIST_INSERT_HEAD, ast_mutex_lock, ast_mutex_unlock, odbc_class::list, NULL, odbc_obj::parent, and odbc_obj::sql_text.

Referenced by ast_odbc_find_table(), config_odbc(), create_transaction(), destroy_odbc(), dsn_destructor(), free_zone(), 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().

814 {
815  struct odbc_class *class = obj->parent;
816 
817  ast_debug(2, "Releasing ODBC handle %p into pool\n", obj);
818 
819  /* The odbc_obj only holds a reference to the class when it is
820  * actively being used. This guarantees no circular reference
821  * between odbc_class and odbc_obj. Since it is being released
822  * we also release our class reference. If a reload occurred before
823  * the class will go away automatically once all odbc_obj are
824  * released back.
825  */
826  obj->parent = NULL;
827 
828  /* Free the SQL text so that the next user of this connection has
829  * a fresh start.
830  */
831  ast_free(obj->sql_text);
832  obj->sql_text = NULL;
833 
834  ast_mutex_lock(&class->lock);
835  AST_LIST_INSERT_HEAD(&class->connections, obj, list);
836  ast_cond_signal(&class->cond);
837  ast_mutex_unlock(&class->lock);
838 
839  ao2_ref(class, -1);
840 }
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
#define ast_cond_signal(cond)
Definition: lock.h:201
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct odbc_class * parent
Definition: res_odbc.h:48
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_free(a)
Definition: astmm.h:182
char * sql_text
Definition: res_odbc.h:54
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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 489 of file res_odbc.c.

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

490 {
491  int res = 0;
492 
493  res = SQLExecute(stmt);
494  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
495  if (res == SQL_ERROR) {
496  ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Execute");
497  }
498  }
499 
500  if (obj->parent->logging) {
502  }
503 
504  return res;
505 }
unsigned int logging
Definition: res_odbc.c:92
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:524
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:755
struct odbc_class * parent
Definition: res_odbc.h:48
int queries_executed
Definition: res_odbc.c:96

◆ ast_odbc_text2isolation()

int ast_odbc_text2isolation ( const char *  txt)

Convert from textual transaction isolation values to their numeric constants.

Definition at line 147 of file res_odbc.c.

Referenced by acf_transaction_write(), and load_odbc_config().

148 {
149  if (strncasecmp(txt, "read_", 5) == 0) {
150  if (strncasecmp(txt + 5, "c", 1) == 0) {
151  return SQL_TXN_READ_COMMITTED;
152  } else if (strncasecmp(txt + 5, "u", 1) == 0) {
153  return SQL_TXN_READ_UNCOMMITTED;
154  } else {
155  return 0;
156  }
157  } else if (strncasecmp(txt, "ser", 3) == 0) {
158  return SQL_TXN_SERIALIZABLE;
159  } else if (strncasecmp(txt, "rep", 3) == 0) {
160  return SQL_TXN_REPEATABLE_READ;
161  } else {
162  return 0;
163  }
164 }

◆ connection_dead()

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

Definition at line 881 of file res_odbc.c.

References ast_strlen_zero, and odbc_obj::con.

Referenced by _ast_odbc_request_obj2().

882 {
883  char *test_sql = "select 1";
884  SQLINTEGER dead;
885  SQLRETURN res;
886  SQLHSTMT stmt;
887 
888  res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0);
889  if (SQL_SUCCEEDED(res)) {
890  return dead == SQL_CD_TRUE ? 1 : 0;
891  }
892 
893  /* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a
894  * probing query instead
895  */
896  res = SQLAllocHandle(SQL_HANDLE_STMT, connection->con, &stmt);
897  if (!SQL_SUCCEEDED(res)) {
898  return 1;
899  }
900 
901  if (!ast_strlen_zero(class->sanitysql)) {
902  test_sql = class->sanitysql;
903  }
904 
905  res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
906  if (!SQL_SUCCEEDED(res)) {
907  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
908  return 1;
909  }
910 
911  res = SQLExecute(stmt);
912  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
913 
914  return SQL_SUCCEEDED(res) ? 0 : 1;
915 }
SQLHDBC con
Definition: res_odbc.h:47
#define ast_strlen_zero(foo)
Definition: strings.h:52
char * sanitysql
Definition: res_odbc.c:71

◆ destroy_table_cache()

static void destroy_table_cache ( struct odbc_cache_tables table)
static

Definition at line 201 of file res_odbc.c.

References ast_debug, ast_free, AST_RWLIST_HEAD_DESTROY, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, odbc_cache_tables::columns, odbc_class::list, and odbc_cache_tables::table.

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

202 {
203  struct odbc_cache_columns *col;
204 
205  ast_debug(1, "Destroying table cache for %s\n", table->table);
206 
207  AST_RWLIST_WRLOCK(&table->columns);
208  while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
209  ast_free(col);
210  }
211  AST_RWLIST_UNLOCK(&table->columns);
213 
214  ast_free(table);
215 }
#define AST_RWLIST_HEAD_DESTROY(head)
Destroys an rwlist head structure.
Definition: linkedlists.h:666
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
These structures are used for adaptive capabilities.
Definition: res_odbc.h:59
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_free(a)
Definition: astmm.h:182
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
struct odbc_cache_tables::_columns columns

◆ 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 716 of file res_odbc.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_localtime(), ast_mutex_lock, ast_mutex_unlock, ast_strdup, ast_strftime(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::n, NULL, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

717 {
718  struct ao2_iterator aoi;
719  struct odbc_class *class;
720  int length = 0;
721  int which = 0;
722  char *ret = NULL;
723 
724  switch (cmd) {
725  case CLI_INIT:
726  e->command = "odbc show";
727  e->usage =
728  "Usage: odbc show [class]\n"
729  " List settings of a particular ODBC class or,\n"
730  " if not specified, all classes.\n";
731  return NULL;
732  case CLI_GENERATE:
733  if (a->pos != 2)
734  return NULL;
735  length = strlen(a->word);
737  while ((class = ao2_iterator_next(&aoi))) {
738  if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
739  ret = ast_strdup(class->name);
740  }
741  ao2_ref(class, -1);
742  if (ret) {
743  break;
744  }
745  }
746  ao2_iterator_destroy(&aoi);
747  if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
748  ret = ast_strdup("all");
749  }
750  return ret;
751  }
752 
753  ast_cli(a->fd, "\nODBC DSN Settings\n");
754  ast_cli(a->fd, "-----------------\n\n");
756  while ((class = ao2_iterator_next(&aoi))) {
757  if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
758  char timestr[80];
759  struct ast_tm tm;
760 
761  ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn);
762 
763  if (class->last_negative_connect.tv_sec > 0) {
764  ast_localtime(&class->last_negative_connect, &tm, NULL);
765  ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm);
766  ast_cli(a->fd, " Last fail connection attempt: %s\n", timestr);
767  }
768 
769  ast_cli(a->fd, " Number of active connections: %zd (out of %d)\n", class->connection_cnt, class->maxconnections);
770  ast_cli(a->fd, " Logging: %s\n", class->logging ? "Enabled" : "Disabled");
771  if (class->logging) {
772  ast_cli(a->fd, " Number of prepares executed: %d\n", class->prepares_executed);
773  ast_cli(a->fd, " Number of queries executed: %d\n", class->queries_executed);
774  ast_mutex_lock(&class->lock);
775  if (class->sql_text) {
776  ast_cli(a->fd, " Longest running SQL query: %s (%ld milliseconds)\n", class->sql_text, class->longest_query_execution_time);
777  }
778  ast_mutex_unlock(&class->lock);
779  }
780  ast_cli(a->fd, "\n");
781  }
782  ao2_ref(class, -1);
783  }
784  ao2_iterator_destroy(&aoi);
785 
786  return CLI_SUCCESS;
787 }
const int argc
Definition: cli.h:160
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
Definition: cli.h:152
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_mutex_lock(a)
Definition: lock.h:187
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char *const * argv
Definition: cli.h:161
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
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
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
const int pos
Definition: cli.h:164
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static struct ao2_container * class_container
Definition: res_odbc.c:105
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ load_module()

static int load_module ( void  )
static

Definition at line 1123 of file res_odbc.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_list, ao2_match_by_addr(), ARRAY_LEN, ast_cli_register_multiple, AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_REALTIME_DEPEND, AST_MODULE_INFO(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_module_shutdown_ref, AST_MODULE_SUPPORT_CORE, ASTERISK_GPL_KEY, load_odbc_config(), NULL, reload(), ast_module_info::self, and unload_module().

1124 {
1126  if (!class_container) {
1127  return AST_MODULE_LOAD_DECLINE;
1128  }
1129 
1130  if (load_odbc_config() == -1) {
1131  return AST_MODULE_LOAD_DECLINE;
1132  }
1133 
1136 
1137  return AST_MODULE_LOAD_SUCCESS;
1138 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int load_odbc_config(void)
Definition: res_odbc.c:564
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define NULL
Definition: resample.c:96
static struct ast_cli_entry cli_odbc[]
Definition: res_odbc.c:789
struct ast_module * self
Definition: module.h:342
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
int ao2_match_by_addr(void *obj, void *arg, int flags)
A common ao2_callback is one that matches by address.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct ao2_container * class_container
Definition: res_odbc.c:105

◆ load_odbc_config()

static int load_odbc_config ( void  )
static

Definition at line 564 of file res_odbc.c.

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(), config, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, odbc_class::conntimeout, odbc_class::dsn, enabled, odbc_class::forcecommit, odbc_class::isolation, LOG_ERROR, LOG_NOTICE, LOG_WARNING, odbc_class::logging, 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().

565 {
566  static char *cfg = "res_odbc.conf";
567  struct ast_config *config;
568  struct ast_variable *v;
569  char *cat;
570  const char *dsn, *username, *password, *sanitysql;
571  int enabled, bse, conntimeout, forcecommit, isolation, maxconnections, logging, slowquerylimit;
572  struct timeval ncache = { 0, 0 };
573  int preconnect = 0, res = 0;
574  struct ast_flags config_flags = { 0 };
575 
576  struct odbc_class *new;
577 
578  config = ast_config_load(cfg, config_flags);
579  if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
580  ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
581  return -1;
582  }
583  for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
584  if (!strcasecmp(cat, "ENV")) {
585  for (v = ast_variable_browse(config, cat); v; v = v->next) {
586  setenv(v->name, v->value, 1);
587  ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
588  }
589  } else {
590  /* Reset all to defaults for each class of odbc connections */
591  dsn = username = password = sanitysql = NULL;
592  enabled = 1;
593  preconnect = 0;
594  bse = 1;
595  conntimeout = 10;
596  forcecommit = 0;
597  isolation = SQL_TXN_READ_COMMITTED;
598  maxconnections = 1;
599  logging = 0;
600  slowquerylimit = 5000;
601  for (v = ast_variable_browse(config, cat); v; v = v->next) {
602  if (!strcasecmp(v->name, "pooling") ||
603  !strncasecmp(v->name, "share", 5) ||
604  !strcasecmp(v->name, "limit") ||
605  !strcasecmp(v->name, "idlecheck")) {
606  ast_log(LOG_WARNING, "The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options were replaced by 'max_connections'. See res_odbc.conf.sample.\n");
607  } else if (!strcasecmp(v->name, "enabled")) {
608  enabled = ast_true(v->value);
609  } else if (!strcasecmp(v->name, "pre-connect")) {
610  preconnect = ast_true(v->value);
611  } else if (!strcasecmp(v->name, "dsn")) {
612  dsn = v->value;
613  } else if (!strcasecmp(v->name, "username")) {
614  username = v->value;
615  } else if (!strcasecmp(v->name, "password")) {
616  password = v->value;
617  } else if (!strcasecmp(v->name, "sanitysql")) {
618  sanitysql = v->value;
619  } else if (!strcasecmp(v->name, "backslash_is_escape")) {
620  bse = ast_true(v->value);
621  } else if (!strcasecmp(v->name, "connect_timeout")) {
622  if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
623  ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
624  conntimeout = 10;
625  }
626  } else if (!strcasecmp(v->name, "negative_connection_cache")) {
627  double dncache;
628  if (sscanf(v->value, "%lf", &dncache) != 1 || dncache < 0) {
629  ast_log(LOG_WARNING, "negative_connection_cache must be a non-negative integer\n");
630  /* 5 minutes sounds like a reasonable default */
631  ncache.tv_sec = 300;
632  ncache.tv_usec = 0;
633  } else {
634  ncache.tv_sec = (int)dncache;
635  ncache.tv_usec = (dncache - ncache.tv_sec) * 1000000;
636  }
637  } else if (!strcasecmp(v->name, "forcecommit")) {
638  forcecommit = ast_true(v->value);
639  } else if (!strcasecmp(v->name, "isolation")) {
640  if ((isolation = ast_odbc_text2isolation(v->value)) == 0) {
641  ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat);
642  isolation = SQL_TXN_READ_COMMITTED;
643  }
644  } else if (!strcasecmp(v->name, "max_connections")) {
645  if (sscanf(v->value, "%30d", &maxconnections) != 1 || maxconnections < 1) {
646  ast_log(LOG_WARNING, "max_connections must be a positive integer\n");
647  maxconnections = 1;
648  }
649  } else if (!strcasecmp(v->name, "logging")) {
650  logging = ast_true(v->value);
651  } else if (!strcasecmp(v->name, "slow_query_limit")) {
652  if (sscanf(v->value, "%30d", &slowquerylimit) != 1) {
653  ast_log(LOG_WARNING, "slow_query_limit must be a positive integer\n");
654  slowquerylimit = 5000;
655  }
656  }
657  }
658 
659  if (enabled && !ast_strlen_zero(dsn)) {
660  new = ao2_alloc(sizeof(*new), odbc_class_destructor);
661 
662  if (!new) {
663  res = -1;
664  break;
665  }
666 
667  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
668  res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
669 
670  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
671  ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
672  ao2_ref(new, -1);
673  return res;
674  }
675 
676  new->backslash_is_escape = bse ? 1 : 0;
677  new->forcecommit = forcecommit ? 1 : 0;
678  new->isolation = isolation;
679  new->conntimeout = conntimeout;
680  new->negative_connection_cache = ncache;
681  new->maxconnections = maxconnections;
682  new->logging = logging;
683  new->slowquerylimit = slowquerylimit;
684 
685  if (cat)
686  ast_copy_string(new->name, cat, sizeof(new->name));
687  if (dsn)
688  ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
689  if (username && !(new->username = ast_strdup(username))) {
690  ao2_ref(new, -1);
691  break;
692  }
693  if (password && !(new->password = ast_strdup(password))) {
694  ao2_ref(new, -1);
695  break;
696  }
697  if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) {
698  ao2_ref(new, -1);
699  break;
700  }
701 
702  ast_mutex_init(&new->lock);
703  ast_cond_init(&new->cond, NULL);
704 
705  odbc_register_class(new, preconnect);
706  ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
707  ao2_ref(new, -1);
708  new = NULL;
709  }
710  }
711  }
712  ast_config_destroy(config);
713  return res;
714 }
struct ast_variable * next
static void odbc_class_destructor(void *data)
Definition: res_odbc.c:166
unsigned int maxconnections
Definition: res_odbc.c:78
char * config
Definition: conf2ael.c:66
unsigned int logging
Definition: res_odbc.c:92
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
#define LOG_WARNING
Definition: logger.h:274
#define CONFIG_STATUS_FILEINVALID
unsigned int slowquerylimit
Definition: res_odbc.c:102
Structure for variables, used for configurations and for channel variables.
#define ast_cond_init(cond, attr)
Definition: lock.h:199
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
static struct ast_str * password
Definition: cdr_mysql.c:77
#define ast_strlen_zero(foo)
Definition: strings.h:52
unsigned int isolation
Definition: res_odbc.c:76
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
unsigned int conntimeout
Definition: res_odbc.c:77
int ast_odbc_text2isolation(const char *txt)
Convert from textual transaction isolation values to their numeric constants.
Definition: res_odbc.c:147
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define LOG_NOTICE
Definition: logger.h:263
static char * dsn
Definition: cdr_odbc.c:58
Structure used to handle boolean flags.
Definition: utils.h:199
#define CONFIG_STATUS_FILEMISSING
static void odbc_register_class(struct odbc_class *class, int connect)
Definition: res_odbc.c:793
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
int setenv(const char *name, const char *value, int overwrite)
#define ast_mutex_init(pmutex)
Definition: lock.h:184
static int enabled
Definition: dnsmgr.c:91

◆ odbc_class_destructor()

static void odbc_class_destructor ( void *  data)
static

Definition at line 166 of file res_odbc.c.

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

Referenced by load_odbc_config().

167 {
168  struct odbc_class *class = data;
169  struct odbc_obj *obj;
170 
171  /* Due to refcounts, we can safely assume that any objects with a reference
172  * to us will prevent our destruction, so we don't need to worry about them.
173  */
174  if (class->username) {
175  ast_free(class->username);
176  }
177  if (class->password) {
178  ast_free(class->password);
179  }
180  if (class->sanitysql) {
181  ast_free(class->sanitysql);
182  }
183 
184  while ((obj = AST_LIST_REMOVE_HEAD(&class->connections, list))) {
185  ao2_ref(obj, -1);
186  }
187 
188  SQLFreeHandle(SQL_HANDLE_ENV, class->env);
189  ast_mutex_destroy(&class->lock);
190  ast_cond_destroy(&class->cond);
191  ast_free(class->sql_text);
192 }
struct odbc_obj::@294 list
ODBC container.
Definition: res_odbc.h:46
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define ast_cond_destroy(cond)
Definition: lock.h:200
#define ast_free(a)
Definition: astmm.h:182
#define ast_mutex_destroy(a)
Definition: lock.h:186

◆ odbc_obj_connect()

static odbc_status odbc_obj_connect ( struct odbc_obj obj)
static

Definition at line 1022 of file res_odbc.c.

References ast_assert, ast_debug, ast_log, 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().

1023 {
1024  int res;
1025  SQLINTEGER err;
1026  short int mlen;
1027  unsigned char msg[200], state[10];
1028 #ifdef NEEDTRACE
1029  SQLINTEGER enable = 1;
1030  char *tracefile = "/tmp/odbc.trace";
1031 #endif
1032  SQLHDBC con;
1033  long int negative_cache_expiration;
1034 
1035  ast_assert(obj->con == NULL);
1036  ast_debug(3, "Connecting %s(%p)\n", obj->parent->name, obj);
1037 
1038  /* Dont connect while server is marked as unreachable via negative_connection_cache */
1039  negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec;
1040  if (time(NULL) < negative_cache_expiration) {
1041  ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %ld seconds\n", obj->parent->name, negative_cache_expiration - time(NULL));
1042  return ODBC_FAIL;
1043  }
1044 
1045  res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &con);
1046 
1047  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1048  ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
1050  return ODBC_FAIL;
1051  }
1052  SQLSetConnectAttr(con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
1053  SQLSetConnectAttr(con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
1054 #ifdef NEEDTRACE
1055  SQLSetConnectAttr(con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
1056  SQLSetConnectAttr(con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
1057 #endif
1058 
1059  res = SQLConnect(con,
1060  (SQLCHAR *) obj->parent->dsn, SQL_NTS,
1061  (SQLCHAR *) obj->parent->username, SQL_NTS,
1062  (SQLCHAR *) obj->parent->password, SQL_NTS);
1063 
1064  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1065  SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1067  ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
1068  if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) != SQL_SUCCESS) {
1069  SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1070  ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
1071  }
1072  return ODBC_FAIL;
1073  } else {
1074  ast_debug(3, "res_odbc: Connected to %s [%s (%p)]\n", obj->parent->name, obj->parent->dsn, obj);
1075  }
1076 
1077  obj->con = con;
1078  return ODBC_SUCCESS;
1079 }
SQLHDBC con
Definition: res_odbc.h:47
char name[80]
Definition: res_odbc.c:67
#define LOG_WARNING
Definition: logger.h:274
char * password
Definition: res_odbc.c:70
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
struct timeval negative_connection_cache
Definition: res_odbc.c:80
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
unsigned int conntimeout
Definition: res_odbc.c:77
struct odbc_class * parent
Definition: res_odbc.h:48
SQLHENV env
Definition: res_odbc.c:72
struct timeval last_negative_connect
Definition: res_odbc.c:82
char * username
Definition: res_odbc.c:69
char dsn[80]
Definition: res_odbc.c:68

◆ odbc_obj_destructor()

static void odbc_obj_destructor ( void *  data)
static

Definition at line 194 of file res_odbc.c.

References odbc_obj_disconnect().

Referenced by _ast_odbc_request_obj2().

195 {
196  struct odbc_obj *obj = data;
197 
198  odbc_obj_disconnect(obj);
199 }
ODBC container.
Definition: res_odbc.h:46
static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
Definition: res_odbc.c:995

◆ odbc_obj_disconnect()

static odbc_status odbc_obj_disconnect ( struct odbc_obj obj)
static

Definition at line 995 of file res_odbc.c.

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

Referenced by odbc_obj_destructor().

996 {
997  int res;
998  SQLINTEGER err;
999  short int mlen;
1000  unsigned char msg[200], state[10];
1001  SQLHDBC con;
1002 
1003  /* Nothing to disconnect */
1004  if (!obj->con) {
1005  return ODBC_SUCCESS;
1006  }
1007 
1008  con = obj->con;
1009  obj->con = NULL;
1010  res = SQLDisconnect(con);
1011 
1012  if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con)) == SQL_SUCCESS) {
1013  ast_debug(3, "Database handle %p (connection %p) deallocated\n", obj, con);
1014  } else {
1015  SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1016  ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
1017  }
1018 
1019  return ODBC_SUCCESS;
1020 }
SQLHDBC con
Definition: res_odbc.h:47
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42

◆ odbc_register_class()

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

Definition at line 793 of file res_odbc.c.

References ao2_link, ast_odbc_release_obj(), and ast_odbc_request_obj.

Referenced by load_odbc_config().

794 {
795  struct odbc_obj *obj;
796 
797  ao2_link(class_container, class);
798  /* I still have a reference in the caller, so a deref is NOT missing here. */
799 
800  if (!preconnect) {
801  return;
802  }
803 
804  /* Request and release builds a connection */
805  obj = ast_odbc_request_obj(class->name, 0);
806  if (obj) {
808  }
809 
810  return;
811 }
char name[80]
Definition: res_odbc.c:67
ODBC container.
Definition: res_odbc.h:46
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:813
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:122
static struct ao2_container * class_container
Definition: res_odbc.c:105
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ reload()

static int reload ( void  )
static

Definition at line 1081 of file res_odbc.c.

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

Referenced by load_module().

1082 {
1083  struct odbc_cache_tables *table;
1084  struct odbc_class *class;
1086 
1087  /* First, mark all to be purged */
1088  while ((class = ao2_iterator_next(&aoi))) {
1089  class->delme = 1;
1090  ao2_ref(class, -1);
1091  }
1092  ao2_iterator_destroy(&aoi);
1093 
1094  load_odbc_config();
1095 
1097  while ((class = ao2_iterator_next(&aoi))) {
1098  if (class->delme) {
1099  ao2_unlink(class_container, class);
1100  }
1101  ao2_ref(class, -1);
1102  }
1103  ao2_iterator_destroy(&aoi);
1104 
1105  /* Empty the cache; it will get rebuilt the next time the tables are needed. */
1107  while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
1108  destroy_table_cache(table);
1109  }
1111 
1112  return 0;
1113 }
static int load_odbc_config(void)
Definition: res_odbc.c:564
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static void destroy_table_cache(struct odbc_cache_tables *table)
Definition: res_odbc.c:201
static char * table
Definition: cdr_odbc.c:58
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static struct ao2_container * class_container
Definition: res_odbc.c:105

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1115 of file res_odbc.c.

References ao2_cleanup, ARRAY_LEN, and ast_cli_unregister_multiple().

Referenced by load_module().

1116 {
1119 
1120  return 0;
1121 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static struct ast_cli_entry cli_odbc[]
Definition: res_odbc.c:789
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ao2_container * class_container
Definition: res_odbc.c:105

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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 1147 of file res_odbc.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1147 of file res_odbc.c.

◆ class_container

struct ao2_container* class_container
static

Definition at line 105 of file res_odbc.c.

◆ 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:716

Definition at line 789 of file res_odbc.c.

◆ errors_buf

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

Definition at line 113 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