Wed Jan 8 2020 09:50:19

Asterisk developer's documentation


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 "asterisk/data.h"

Go to the source code of this file.

Data Structures

struct  odbc_class
 
struct  odbc_tables
 
struct  odbc_txn_frame
 

Macros

#define DATA_EXPORT_ODBC_CLASS(MEMBER)
 
#define EOR_TX   (void *)(long)3
 
#define NO_TX   (void *)(long)2
 
#define USE_TX   (void *)(long)1
 

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)
 Retrieves a connected ODBC object. More...
 
static int acf_transaction_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_transaction_write (struct ast_channel *chan, const char *cmd, char *s, const char *value)
 
static int aoro2_class_cb (void *obj, void *arg, int flags)
 
static int aoro2_obj_cb (void *vobj, void *arg, int flags)
 
static int aoro2_obj_notx_cb (void *vobj, void *arg, int flags)
 
 AST_DATA_STRUCTURE (odbc_class, DATA_EXPORT_ODBC_CLASS)
 
int ast_odbc_allow_empty_string_in_nontext (struct odbc_obj *obj)
 Checks if the database natively supports implicit conversion from an empty string to a number (0). More...
 
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...
 
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...
 
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...
 
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...
 
void ast_odbc_release_obj (struct odbc_obj *obj)
 Releases an ODBC object previously allocated by ast_odbc_request_obj() More...
 
struct odbc_objast_odbc_retrieve_transaction_obj (struct ast_channel *chan, const char *objname)
 Retrieve a stored ODBC object, if a transaction has been started. More...
 
int ast_odbc_sanity_check (struct odbc_obj *obj)
 Checks an ODBC object to ensure it is still connected. More...
 
int ast_odbc_smart_execute (struct odbc_obj *obj, SQLHSTMT stmt)
 Executes a prepared statement handle. More...
 
static int commit_exec (struct ast_channel *chan, const char *data)
 
static int data_odbc_provider_handler (const struct ast_data_search *search, struct ast_data *root)
 
static void destroy_table_cache (struct odbc_cache_tables *table)
 
static struct odbc_txn_framefind_transaction (struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
 
static char * handle_cli_odbc_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static const char * isolation2text (int iso)
 
static int load_module (void)
 
static int load_odbc_config (void)
 
static int mark_transaction_active (struct ast_channel *chan, struct odbc_txn_frame *tx)
 
static int null_hash_fn (const void *obj, const int flags)
 
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 int odbc_register_class (struct odbc_class *class, int connect)
 
static void odbc_release_obj2 (struct odbc_obj *obj, struct odbc_txn_frame *tx)
 
static void odbc_txn_free (void *data)
 
static struct odbc_txn_framerelease_transaction (struct odbc_txn_frame *tx)
 
static int reload (void)
 
static int rollback_exec (struct ast_channel *chan, const char *data)
 
static int text2isolation (const char *txt)
 
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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, }
 
static const char *const app_commit = "ODBC_Commit"
 
static const char *const app_rollback = "ODBC_Rollback"
 
static 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 ast_custom_function odbc_function
 
static struct ast_data_handler odbc_provider
 
static struct ast_data_entry odbc_providers []
 
static struct odbc_tables odbc_tables = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } , }
 
static struct ast_datastore_info txn_info
 

Detailed Description

Macro Definition Documentation

#define DATA_EXPORT_ODBC_CLASS (   MEMBER)

Definition at line 179 of file res_odbc.c.

#define EOR_TX   (void *)(long)3

Definition at line 1214 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().

#define NO_TX   (void *)(long)2

Definition at line 1213 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().

#define USE_TX   (void *)(long)1

Definition at line 1212 of file res_odbc.c.

Referenced by _ast_odbc_request_obj2(), and aoro2_obj_cb().

Function Documentation

static void __init_errors_buf ( void  )
static

Definition at line 155 of file res_odbc.c.

157 {
static void __reg_module ( void  )
static

Definition at line 1912 of file res_odbc.c.

static void __unreg_module ( void  )
static

Definition at line 1912 of file res_odbc.c.

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

Definition at line 1450 of file res_odbc.c.

References _ast_odbc_request_obj2(), and RES_ODBC_SANITY_CHECK.

1451 {
1452  struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
1453  return _ast_odbc_request_obj2(name, flags, file, function, lineno);
1454 }
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:1241
unsigned int flags
Definition: utils.h:201
static const char name[]
Structure used to handle boolean 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.

Parameters
nameThe name of the ODBC class for which a connection is needed.
flagsOne or more of the following flags:
  • RES_ODBC_SANITY_CHECK Whether to ensure that a connection is valid before returning the handle. Usually unnecessary.
  • RES_ODBC_INDEPENDENT_CONNECTION Return a handle which is independent from all others. Usually used when starting a transaction.
  • RES_ODBC_CONNECTED Only return a connected handle. Intended for use with peers which use idlecheck, which are checked periodically for reachability.
Returns
ODBC object
Return values
NULLif there is no connection available with the requested name.

Connection classes may, in fact, contain multiple connection handles. If the connection is pooled, then each connection will be dedicated to the thread which requests it. Note that all connections should be released when the thread is done by calling ast_odbc_release_obj(), below.

Definition at line 1241 of file res_odbc.c.

References ao2_alloc, ao2_callback, ao2_link, ao2_ref, aoro2_class_cb(), aoro2_obj_cb(), aoro2_obj_notx_cb(), ast_assert, ast_atomic_fetchadd_int(), ast_copy_string(), ast_debug, ast_log(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_odbc_sanity_check(), ast_test_flag, ast_tvdiff_sec(), ast_tvnow(), class_container, odbc_obj::con, odbc_class::count, EOR_TX, odbc_class::idlecheck, odbc_class::isolation, odbc_class::last_negative_connect, odbc_obj::last_used, odbc_obj::lock, LOG_WARNING, odbc_class::negative_connection_cache, NO_TX, odbc_class::obj_container, ODBC_FAIL, odbc_obj_connect(), odbc_obj_destructor(), odbc_obj::parent, RES_ODBC_CONNECTED, RES_ODBC_INDEPENDENT_CONNECTION, RES_ODBC_SANITY_CHECK, odbc_obj::up, USE_TX, and odbc_obj::used.

Referenced by _ast_odbc_request_obj().

1242 {
1243  struct odbc_obj *obj = NULL;
1244  struct odbc_class *class;
1245  SQLINTEGER nativeerror=0, numfields=0;
1246  SQLSMALLINT diagbytes=0, i;
1247  unsigned char state[10], diagnostic[256];
1248 
1249  if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
1250  ast_debug(1, "Class '%s' not found!\n", name);
1251  return NULL;
1252  }
1253 
1254  ast_assert(ao2_ref(class, 0) > 1);
1255 
1256  if (class->haspool) {
1257  /* Recycle connections before building another */
1258  obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX);
1259 
1260  if (obj) {
1261  ast_assert(ao2_ref(obj, 0) > 1);
1262  }
1263  if (!obj && (ast_atomic_fetchadd_int(&class->count, +1) < class->limit) &&
1264  (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) {
1265  obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
1266  if (!obj) {
1267  class->count--;
1268  ao2_ref(class, -1);
1269  ast_debug(3, "Unable to allocate object\n");
1270  ast_atomic_fetchadd_int(&class->count, -1);
1271  return NULL;
1272  }
1273  ast_assert(ao2_ref(obj, 0) == 1);
1274  ast_mutex_init(&obj->lock);
1275  /* obj inherits the outstanding reference to class */
1276  obj->parent = class;
1277  class = NULL;
1278  if (odbc_obj_connect(obj) == ODBC_FAIL) {
1279  ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1280  ast_assert(ao2_ref(obj->parent, 0) > 0);
1281  /* Because it was never within the container, we have to manually decrement the count here */
1282  ast_atomic_fetchadd_int(&obj->parent->count, -1);
1283  ao2_ref(obj, -1);
1284  obj = NULL;
1285  } else {
1286  obj->used = 1;
1287  ao2_link(obj->parent->obj_container, obj);
1288  }
1289  } else {
1290  /* If construction fails due to the limit (or negative timecache), reverse our increment. */
1291  if (!obj) {
1292  ast_atomic_fetchadd_int(&class->count, -1);
1293  }
1294  /* Object is not constructed, so delete outstanding reference to class. */
1295  ao2_ref(class, -1);
1296  class = NULL;
1297  }
1298 
1299  if (!obj) {
1300  return NULL;
1301  }
1302 
1303  ast_mutex_lock(&obj->lock);
1304 
1306  /* Ensure this connection has autocommit turned off. */
1307  if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
1308  SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1309  for (i = 0; i < numfields; i++) {
1310  SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1311  ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1312  if (i > 10) {
1313  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1314  break;
1315  }
1316  }
1317  }
1318  }
1319  } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
1320  /* Non-pooled connections -- but must use a separate connection handle */
1321  if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) {
1322  ast_debug(1, "Object not found\n");
1323  obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
1324  if (!obj) {
1325  ao2_ref(class, -1);
1326  ast_debug(3, "Unable to allocate object\n");
1327  return NULL;
1328  }
1329  ast_mutex_init(&obj->lock);
1330  /* obj inherits the outstanding reference to class */
1331  obj->parent = class;
1332  class = NULL;
1333  if (odbc_obj_connect(obj) == ODBC_FAIL) {
1334  ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1335  ao2_ref(obj, -1);
1336  obj = NULL;
1337  } else {
1338  obj->used = 1;
1339  ao2_link(obj->parent->obj_container, obj);
1340  ast_atomic_fetchadd_int(&obj->parent->count, +1);
1341  }
1342  }
1343 
1344  if (!obj) {
1345  return NULL;
1346  }
1347 
1348  ast_mutex_lock(&obj->lock);
1349 
1350  if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
1351  SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1352  for (i = 0; i < numfields; i++) {
1353  SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1354  ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1355  if (i > 10) {
1356  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1357  break;
1358  }
1359  }
1360  }
1361  } else {
1362  /* Non-pooled connection: multiple modules can use the same connection. */
1363  if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_notx_cb, NO_TX))) {
1364  /* Object is not constructed, so delete outstanding reference to class. */
1365  ast_assert(ao2_ref(class, 0) > 1);
1366  ao2_ref(class, -1);
1367  class = NULL;
1368  } else {
1369  /* No entry: build one */
1370  if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) {
1371  ast_assert(ao2_ref(class, 0) > 1);
1372  ao2_ref(class, -1);
1373  ast_debug(3, "Unable to allocate object\n");
1374  return NULL;
1375  }
1376  ast_mutex_init(&obj->lock);
1377  /* obj inherits the outstanding reference to class */
1378  obj->parent = class;
1379  class = NULL;
1380  if (odbc_obj_connect(obj) == ODBC_FAIL) {
1381  ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
1382  ao2_ref(obj, -1);
1383  obj = NULL;
1384  } else {
1385  ao2_link(obj->parent->obj_container, obj);
1386  ast_assert(ao2_ref(obj, 0) > 1);
1387  }
1388  }
1389 
1390  if (!obj) {
1391  return NULL;
1392  }
1393 
1394  ast_mutex_lock(&obj->lock);
1395 
1396  if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
1397  SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1398  for (i = 0; i < numfields; i++) {
1399  SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1400  ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1401  if (i > 10) {
1402  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1403  break;
1404  }
1405  }
1406  }
1407  }
1408 
1409  ast_assert(obj != NULL);
1410 
1411  /* Set the isolation property */
1412  if (SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
1413  SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1414  for (i = 0; i < numfields; i++) {
1415  SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1416  ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
1417  if (i > 10) {
1418  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1419  break;
1420  }
1421  }
1422  }
1423 
1424  if (ast_test_flag(&flags, RES_ODBC_CONNECTED) && !obj->up) {
1425  /* Check if this connection qualifies for reconnection, with negative connection cache time */
1426  if (time(NULL) > obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec) {
1427  odbc_obj_connect(obj);
1428  }
1429  } else if (ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
1430  ast_odbc_sanity_check(obj);
1431  } else if (obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck) {
1432  odbc_obj_connect(obj);
1433  }
1434 
1435 #ifdef DEBUG_THREADS
1436  ast_copy_string(obj->file, file, sizeof(obj->file));
1437  ast_copy_string(obj->function, function, sizeof(obj->function));
1438  obj->lineno = lineno;
1439 #endif
1440 
1441  /* We had it locked because of the obj_connects we see here. */
1442  ast_mutex_unlock(&obj->lock);
1443 
1444  ast_assert(class == NULL);
1445 
1446  ast_assert(ao2_ref(obj, 0) > 1);
1447  return obj;
1448 }
SQLHDBC con
Definition: res_odbc.h:48
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
struct ao2_container * obj_container
Definition: res_odbc.c:142
#define ast_test_flag(p, flag)
Definition: utils.h:63
static int aoro2_obj_cb(void *vobj, void *arg, int flags)
Definition: res_odbc.c:1216
int count
Definition: res_odbc.c:134
#define LOG_WARNING
Definition: logger.h:144
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
Definition: time.h:56
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:910
static int aoro2_class_cb(void *obj, void *arg, int flags)
Definition: res_odbc.c:1202
unsigned int idlecheck
Definition: res_odbc.c:135
#define USE_TX
Definition: res_odbc.c:1212
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define ast_assert(a)
Definition: utils.h:738
#define ast_mutex_lock(a)
Definition: lock.h:155
struct timeval negative_connection_cache
Definition: res_odbc.c:138
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
unsigned int isolation
Definition: res_odbc.c:132
static void odbc_obj_destructor(void *data)
Definition: res_odbc.c:418
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define EOR_TX
Definition: res_odbc.c:1214
ODBC container.
Definition: res_odbc.h:46
#define ao2_ref(o, delta)
Definition: astobj2.h:472
unsigned int used
Definition: res_odbc.h:56
unsigned int up
Definition: res_odbc.h:57
struct odbc_class * parent
Definition: res_odbc.h:49
static odbc_status odbc_obj_connect(struct odbc_obj *obj)
Definition: res_odbc.c:1524
#define NO_TX
Definition: res_odbc.c:1213
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
static const char name[]
int ast_odbc_sanity_check(struct odbc_obj *obj)
Checks an ODBC object to ensure it is still connected.
Definition: res_odbc.c:735
ast_mutex_t lock
Definition: res_odbc.h:47
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
struct timeval last_used
Definition: res_odbc.h:50
#define ast_mutex_init(pmutex)
Definition: lock.h:152
struct timeval last_negative_connect
Definition: res_odbc.c:140
static struct ao2_container * class_container
Definition: res_odbc.c:145
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int aoro2_obj_notx_cb(void *vobj, void *arg, int flags)
Definition: res_odbc.c:1232
static int acf_transaction_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 1582 of file res_odbc.c.

References args, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strlen_zero(), find_transaction(), odbc_txn_frame::forcecommit, odbc_txn_frame::isolation, isolation2text(), and odbc_txn_frame::name.

1583 {
1585  AST_APP_ARG(property);
1586  AST_APP_ARG(opt);
1587  );
1588  struct odbc_txn_frame *tx;
1589 
1590  AST_STANDARD_APP_ARGS(args, data);
1591  if (strcasecmp(args.property, "transaction") == 0) {
1592  if ((tx = find_transaction(chan, NULL, NULL, 1))) {
1593  ast_copy_string(buf, tx->name, len);
1594  return 0;
1595  }
1596  } else if (strcasecmp(args.property, "isolation") == 0) {
1597  if (!ast_strlen_zero(args.opt)) {
1598  tx = find_transaction(chan, NULL, args.opt, 0);
1599  } else {
1600  tx = find_transaction(chan, NULL, NULL, 1);
1601  }
1602  if (tx) {
1604  return 0;
1605  }
1606  } else if (strcasecmp(args.property, "forcecommit") == 0) {
1607  if (!ast_strlen_zero(args.opt)) {
1608  tx = find_transaction(chan, NULL, args.opt, 0);
1609  } else {
1610  tx = find_transaction(chan, NULL, NULL, 1);
1611  }
1612  if (tx) {
1613  ast_copy_string(buf, tx->forcecommit ? "1" : "0", len);
1614  return 0;
1615  }
1616  }
1617  return -1;
1618 }
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
char name[0]
Definition: res_odbc.c:176
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static struct @350 args
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static const char * isolation2text(int iso)
Definition: res_odbc.c:190
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
Definition: res_odbc.c:224
unsigned int forcecommit
Definition: res_odbc.c:174
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
unsigned int isolation
Definition: res_odbc.c:175
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static int acf_transaction_write ( struct ast_channel chan,
const char *  cmd,
char *  s,
const char *  value 
)
static

Definition at line 1620 of file res_odbc.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_false(), ast_log(), ast_odbc_request_obj2, AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_true(), odbc_obj::con, find_transaction(), odbc_txn_frame::forcecommit, odbc_class::isolation, odbc_txn_frame::isolation, LOG_ERROR, LOG_WARNING, mark_transaction_active(), odbc_txn_frame::obj, pbx_builtin_setvar_helper(), RES_ODBC_INDEPENDENT_CONNECTION, S_OR, text2isolation(), and odbc_obj::tx.

1621 {
1623  AST_APP_ARG(property);
1624  AST_APP_ARG(opt);
1625  );
1626  struct odbc_txn_frame *tx;
1627  SQLINTEGER nativeerror=0, numfields=0;
1628  SQLSMALLINT diagbytes=0, i;
1629  unsigned char state[10], diagnostic[256];
1630 
1632  if (strcasecmp(args.property, "transaction") == 0) {
1633  /* Set active transaction */
1634  struct odbc_obj *obj;
1635  if ((tx = find_transaction(chan, NULL, value, 0))) {
1636  mark_transaction_active(chan, tx);
1637  } else {
1638  /* No such transaction, create one */
1640  if (ast_strlen_zero(args.opt) || !(obj = ast_odbc_request_obj2(args.opt, flags))) {
1641  ast_log(LOG_ERROR, "Could not create transaction: invalid database specification '%s'\n", S_OR(args.opt, ""));
1642  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_DB");
1643  return -1;
1644  }
1645  if (!find_transaction(chan, obj, value, 0)) {
1646  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1647  return -1;
1648  }
1649  obj->tx = 1;
1650  }
1651  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1652  return 0;
1653  } else if (strcasecmp(args.property, "forcecommit") == 0) {
1654  /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */
1655  if (ast_strlen_zero(args.opt)) {
1656  tx = find_transaction(chan, NULL, NULL, 1);
1657  } else {
1658  tx = find_transaction(chan, NULL, args.opt, 0);
1659  }
1660  if (!tx) {
1661  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1662  return -1;
1663  }
1664  if (ast_true(value)) {
1665  tx->forcecommit = 1;
1666  } else if (ast_false(value)) {
1667  tx->forcecommit = 0;
1668  } else {
1669  ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, ""));
1670  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
1671  return -1;
1672  }
1673 
1674  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1675  return 0;
1676  } else if (strcasecmp(args.property, "isolation") == 0) {
1677  /* How do uncommitted transactions affect reads? */
1678  int isolation = text2isolation(value);
1679  if (ast_strlen_zero(args.opt)) {
1680  tx = find_transaction(chan, NULL, NULL, 1);
1681  } else {
1682  tx = find_transaction(chan, NULL, args.opt, 0);
1683  }
1684  if (!tx) {
1685  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
1686  return -1;
1687  }
1688  if (isolation == 0) {
1689  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
1690  ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, ""));
1691  } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) {
1692  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR");
1693  SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1694  for (i = 0; i < numfields; i++) {
1695  SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1696  ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
1697  if (i > 10) {
1698  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1699  break;
1700  }
1701  }
1702  } else {
1703  pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
1704  tx->isolation = isolation;
1705  }
1706  return 0;
1707  } else {
1708  ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property);
1709  return -1;
1710  }
1711 }
SQLHDBC con
Definition: res_odbc.h:48
#define LOG_WARNING
Definition: logger.h:144
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
unsigned int flags
Definition: utils.h:201
#define ast_odbc_request_obj2(a, b)
Definition: res_odbc.h:122
unsigned int tx
Definition: res_odbc.h:58
int value
Definition: syslog.c:39
ODBC container.
Definition: res_odbc.h:46
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define LOG_ERROR
Definition: logger.h:155
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
static struct @350 args
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx)
Definition: res_odbc.c:359
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
Definition: res_odbc.c:224
static int text2isolation(const char *txt)
Definition: res_odbc.c:205
Structure used to handle boolean flags.
Definition: utils.h:200
unsigned int forcecommit
Definition: res_odbc.c:174
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is &quot;false&quot;...
Definition: utils.c:1550
unsigned int isolation
Definition: res_odbc.c:175
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
struct odbc_obj * obj
Definition: res_odbc.c:165
static int aoro2_class_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1202 of file res_odbc.c.

References CMP_MATCH, and CMP_STOP.

Referenced by _ast_odbc_request_obj2().

1203 {
1204  struct odbc_class *class = obj;
1205  char *name = arg;
1206  if (!strcmp(class->name, name) && !class->delme) {
1207  return CMP_MATCH | CMP_STOP;
1208  }
1209  return 0;
1210 }
static const char name[]
static int aoro2_obj_cb ( void *  vobj,
void *  arg,
int  flags 
)
static

Definition at line 1216 of file res_odbc.c.

References ast_mutex_lock, ast_mutex_unlock, CMP_MATCH, CMP_STOP, EOR_TX, odbc_obj::lock, NO_TX, odbc_obj::tx, USE_TX, and odbc_obj::used.

Referenced by _ast_odbc_request_obj2().

1217 {
1218  struct odbc_obj *obj = vobj;
1219  ast_mutex_lock(&obj->lock);
1220  if ((arg == NO_TX && !obj->tx) || (arg == EOR_TX && !obj->used) || (arg == USE_TX && obj->tx && !obj->used)) {
1221  obj->used = 1;
1222  ast_mutex_unlock(&obj->lock);
1223  return CMP_MATCH | CMP_STOP;
1224  }
1225  ast_mutex_unlock(&obj->lock);
1226  return 0;
1227 }
#define USE_TX
Definition: res_odbc.c:1212
#define ast_mutex_lock(a)
Definition: lock.h:155
unsigned int tx
Definition: res_odbc.h:58
#define EOR_TX
Definition: res_odbc.c:1214
ODBC container.
Definition: res_odbc.h:46
unsigned int used
Definition: res_odbc.h:56
#define NO_TX
Definition: res_odbc.c:1213
ast_mutex_t lock
Definition: res_odbc.h:47
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int aoro2_obj_notx_cb ( void *  vobj,
void *  arg,
int  flags 
)
static

Definition at line 1232 of file res_odbc.c.

References CMP_MATCH, CMP_STOP, and odbc_obj::tx.

Referenced by _ast_odbc_request_obj2().

1233 {
1234  struct odbc_obj *obj = vobj;
1235  if (!obj->tx) {
1236  return CMP_MATCH | CMP_STOP;
1237  }
1238  return 0;
1239 }
unsigned int tx
Definition: res_odbc.h:58
ODBC container.
Definition: res_odbc.h:46
AST_DATA_STRUCTURE ( odbc_class  ,
DATA_EXPORT_ODBC_CLASS   
)
int ast_odbc_allow_empty_string_in_nontext ( struct odbc_obj obj)

Checks if the database natively supports implicit conversion from an empty string to a number (0).

Parameters
objThe ODBC object
Returns
Returns 1 if the implicit conversion is valid and non-text columns can take empty strings, 0 if the conversion is not valid and NULLs should be used instead '\'

Definition at line 1123 of file res_odbc.c.

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

Referenced by update_odbc().

1124 {
1125  return obj->parent->allow_empty_strings;
1126 }
struct odbc_class * parent
Definition: res_odbc.h:49
unsigned int allow_empty_strings
Definition: res_odbc.c:131
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 718 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().

719 {
720  SQLRETURN res;
721 
722  if (pmaxlen == 0) {
723  if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
724  ast_str_make_space(buf, *StrLen_or_Ind + 1);
725  }
726  } else if (pmaxlen > 0) {
727  ast_str_make_space(buf, pmaxlen);
728  }
729  res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
730  ast_str_update(*buf);
731 
732  return res;
733 }
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:482
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
int ast_str_make_space(struct ast_str **buf, size_t new_len)
Definition: strings.h:588
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:446
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 1118 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().

1119 {
1120  return obj->parent->backslash_is_escape;
1121 }
struct odbc_class * parent
Definition: res_odbc.h:49
unsigned int backslash_is_escape
Definition: res_odbc.c:129
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 577 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(), and odbc_cache_tables::table.

Referenced by unload_odbc().

578 {
579  struct odbc_cache_tables *tableptr;
580 
582  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&odbc_tables, tableptr, list) {
583  if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
585  destroy_table_cache(tableptr);
586  break;
587  }
588  }
591  return tableptr ? 0 : -1;
592 }
#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:76
static void destroy_table_cache(struct odbc_cache_tables *table)
Definition: res_odbc.c:428
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:542
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:602
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 594 of file res_odbc.c.

References ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_odbc_sanity_check(), odbc_class::dsn, odbc_obj::lock, LOG_WARNING, odbc_class::name, odbc_obj::parent, and odbc_obj::tx.

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

595 {
596  int attempt;
597  SQLHSTMT stmt;
598 
599  ast_mutex_lock(&obj->lock);
600 
601  for (attempt = 0; attempt < 2; attempt++) {
602  stmt = exec_cb(obj, data);
603 
604  if (stmt) {
605  break;
606  } else if (obj->tx) {
607  ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n");
608  break;
609  } else if (attempt == 0) {
610  ast_log(LOG_WARNING, "SQL Execute error! Verifying connection to %s [%s]...\n", obj->parent->name, obj->parent->dsn);
611  }
612  if (!ast_odbc_sanity_check(obj)) {
613  break;
614  }
615  }
616 
617  ast_mutex_unlock(&obj->lock);
618 
619  return stmt;
620 }
char name[80]
Definition: res_odbc.c:121
#define LOG_WARNING
Definition: logger.h:144
#define ast_mutex_lock(a)
Definition: lock.h:155
unsigned int tx
Definition: res_odbc.h:58
struct odbc_class * parent
Definition: res_odbc.h:49
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int ast_odbc_sanity_check(struct odbc_obj *obj)
Checks an ODBC object to ensure it is still connected.
Definition: res_odbc.c:735
ast_mutex_t lock
Definition: res_odbc.h:47
char dsn[80]
Definition: res_odbc.c:122
#define ast_mutex_unlock(a)
Definition: lock.h:156
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 566 of file res_odbc.c.

References AST_RWLIST_TRAVERSE, odbc_cache_tables::columns, and odbc_cache_columns::name.

Referenced by update2_prepare(), and update_odbc().

567 {
568  struct odbc_cache_columns *col;
569  AST_RWLIST_TRAVERSE(&table->columns, col, list) {
570  if (strcasecmp(col->name, colname) == 0) {
571  return col;
572  }
573  }
574  return NULL;
575 }
These structures are used for adaptive capabilities.
Definition: res_odbc.h:64
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct odbc_cache_tables::_columns columns
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.
Since
1.6.1

Definition at line 449 of file res_odbc.c.

References ast_calloc, AST_LIST_INSERT_TAIL, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_odbc_release_obj(), ast_odbc_request_obj, ast_odbc_sanity_check(), AST_RWLIST_HEAD_INIT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_verb, odbc_cache_tables::columns, odbc_obj::con, odbc_cache_tables::connection, odbc_cache_columns::decimals, destroy_table_cache(), odbc_obj::lock, LOG_ERROR, LOG_WARNING, odbc_cache_columns::name, odbc_cache_columns::nullable, odbc_cache_columns::octetlen, odbc_cache_columns::radix, odbc_cache_columns::size, odbc_cache_tables::table, and odbc_cache_columns::type.

Referenced by require_odbc(), update2_prepare(), and update_odbc().

450 {
451  struct odbc_cache_tables *tableptr;
452  struct odbc_cache_columns *entry;
453  char columnname[80];
454  SQLLEN sqlptr;
455  SQLHSTMT stmt = NULL;
456  int res = 0, error = 0, try = 0;
457  struct odbc_obj *obj = ast_odbc_request_obj(database, 0);
458 
460  AST_RWLIST_TRAVERSE(&odbc_tables, tableptr, list) {
461  if (strcmp(tableptr->connection, database) == 0 && strcmp(tableptr->table, tablename) == 0) {
462  break;
463  }
464  }
465  if (tableptr) {
466  AST_RWLIST_RDLOCK(&tableptr->columns);
468  if (obj) {
470  }
471  return tableptr;
472  }
473 
474  if (!obj) {
475  ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
477  return NULL;
478  }
479 
480  /* Table structure not already cached; build it now. */
481  ast_mutex_lock(&obj->lock);
482  do {
483  res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
484  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
485  if (try == 0) {
486  try = 1;
488  continue;
489  }
490  ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
491  break;
492  }
493 
494  res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)tablename, SQL_NTS, (unsigned char *)"%", SQL_NTS);
495  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
496  if (try == 0) {
497  try = 1;
498  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
500  continue;
501  }
502  ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
503  break;
504  }
505 
506  if (!(tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
507  ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
508  break;
509  }
510 
511  tableptr->connection = (char *)tableptr + sizeof(*tableptr);
512  tableptr->table = (char *)tableptr + sizeof(*tableptr) + strlen(database) + 1;
513  strcpy(tableptr->connection, database); /* SAFE */
514  strcpy(tableptr->table, tablename); /* SAFE */
515  AST_RWLIST_HEAD_INIT(&(tableptr->columns));
516 
517  while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
518  SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
519 
520  if (!(entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1))) {
521  ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
522  error = 1;
523  break;
524  }
525  entry->name = (char *)entry + sizeof(*entry);
526  strcpy(entry->name, columnname);
527 
528  SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
529  SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
530  SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
531  SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
532  SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
533  SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
534 
535  /* Specification states that the octenlen should be the maximum number of bytes
536  * returned in a char or binary column, but it seems that some drivers just set
537  * it to NULL. (Bad Postgres! No biscuit!) */
538  if (entry->octetlen == 0) {
539  entry->octetlen = entry->size;
540  }
541 
542  ast_verb(10, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
543  /* Insert column info into column list */
544  AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
545  }
546  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
547 
549  AST_RWLIST_RDLOCK(&(tableptr->columns));
550  break;
551  } while (1);
552  ast_mutex_unlock(&obj->lock);
553 
555 
556  if (error) {
557  destroy_table_cache(tableptr);
558  tableptr = NULL;
559  }
560  if (obj) {
562  }
563  return tableptr;
564 }
SQLHDBC con
Definition: res_odbc.h:48
#define LOG_WARNING
Definition: logger.h:144
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
SQLSMALLINT nullable
Definition: res_odbc.h:70
char * connection
Definition: res_odbc.h:76
#define ast_mutex_lock(a)
Definition: lock.h:155
#define AST_RWLIST_HEAD_INIT(head)
Initializes an rwlist head structure.
Definition: linkedlists.h:624
static void destroy_table_cache(struct odbc_cache_tables *table)
Definition: res_odbc.c:428
These structures are used for adaptive capabilities.
Definition: res_odbc.h:64
#define ast_verb(level,...)
Definition: logger.h:243
SQLINTEGER octetlen
Definition: res_odbc.h:71
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
ODBC container.
Definition: res_odbc.h:46
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct odbc_obj::@207 list
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
SQLINTEGER size
Definition: res_odbc.h:67
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:123
int ast_odbc_sanity_check(struct odbc_obj *obj)
Checks an ODBC object to ensure it is still connected.
Definition: res_odbc.c:735
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:726
ast_mutex_t lock
Definition: res_odbc.h:47
#define ast_calloc(a, b)
Definition: astmm.h:82
SQLSMALLINT decimals
Definition: res_odbc.h:68
SQLSMALLINT radix
Definition: res_odbc.h:69
SQLSMALLINT type
Definition: res_odbc.h:66
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:1112
#define ast_mutex_unlock(a)
Definition: lock.h:156
struct odbc_cache_tables::_columns columns
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 622 of file res_odbc.c.

References ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_odbc_sanity_check(), ast_tvnow(), odbc_class::dsn, odbc_obj::last_used, odbc_obj::lock, LOG_WARNING, odbc_class::name, odbc_obj::parent, odbc_obj::tx, and odbc_obj::up.

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

623 {
624  int res = 0, i, attempt;
625  SQLINTEGER nativeerror=0, numfields=0;
626  SQLSMALLINT diagbytes=0;
627  unsigned char state[10], diagnostic[256];
628  SQLHSTMT stmt;
629 
630  ast_mutex_lock(&obj->lock);
631 
632  for (attempt = 0; attempt < 2; attempt++) {
633  /* This prepare callback may do more than just prepare -- it may also
634  * bind parameters, bind results, etc. The real key, here, is that
635  * when we disconnect, all handles become invalid for most databases.
636  * We must therefore redo everything when we establish a new
637  * connection. */
638  stmt = prepare_cb(obj, data);
639 
640  if (stmt) {
641  res = SQLExecute(stmt);
642  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
643  if (res == SQL_ERROR) {
644  SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
645  for (i = 0; i < numfields; i++) {
646  SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
647  ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
648  if (i > 10) {
649  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
650  break;
651  }
652  }
653  }
654 
655  if (obj->tx) {
656  ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n");
657  break;
658  } else {
659  ast_log(LOG_WARNING, "SQL Execute error %d! Verifying connection to %s [%s]...\n", res, obj->parent->name, obj->parent->dsn);
660  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
661  stmt = NULL;
662 
663  obj->up = 0;
664  /*
665  * While this isn't the best way to try to correct an error, this won't automatically
666  * fail when the statement handle invalidates.
667  */
668  if (!ast_odbc_sanity_check(obj)) {
669  break;
670  }
671  continue;
672  }
673  } else {
674  obj->last_used = ast_tvnow();
675  }
676  break;
677  } else if (attempt == 0) {
679  }
680  }
681 
682  ast_mutex_unlock(&obj->lock);
683 
684  return stmt;
685 }
char name[80]
Definition: res_odbc.c:121
#define LOG_WARNING
Definition: logger.h:144
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define ast_mutex_lock(a)
Definition: lock.h:155
unsigned int tx
Definition: res_odbc.h:58
unsigned int up
Definition: res_odbc.h:57
struct odbc_class * parent
Definition: res_odbc.h:49
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int ast_odbc_sanity_check(struct odbc_obj *obj)
Checks an ODBC object to ensure it is still connected.
Definition: res_odbc.c:735
ast_mutex_t lock
Definition: res_odbc.h:47
struct timeval last_used
Definition: res_odbc.h:50
char dsn[80]
Definition: res_odbc.c:122
#define ast_mutex_unlock(a)
Definition: lock.h:156
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 1112 of file res_odbc.c.

References find_transaction(), and odbc_release_obj2().

Referenced by acf_odbc_read(), acf_odbc_write(), ast_odbc_find_table(), cli_odbc_read(), cli_odbc_write(), config_odbc(), destroy_odbc(), load_config(), odbc_log(), odbc_register_class(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), update2_odbc(), and update_odbc().

1113 {
1114  struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
1115  odbc_release_obj2(obj, tx);
1116 }
static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx)
Definition: res_odbc.c:1053
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
Definition: res_odbc.c:224
struct odbc_obj* ast_odbc_retrieve_transaction_obj ( struct ast_channel chan,
const char *  objname 
)

Retrieve a stored ODBC object, if a transaction has been started.

Parameters
chanChannel associated with the transaction.
objnameName of the database handle. This name corresponds to the name passed to
See Also
ast_odbc_request_obj2 (or formerly, to ast_odbc_request_obj). Note that the existence of this parameter name explicitly allows for multiple transactions to be open at once, albeit to different databases.
Return values
Astored ODBC object, if a transaction was already started.
NULL,ifno transaction yet exists.

Definition at line 1456 of file res_odbc.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_class::name, odbc_txn_frame::obj, odbc_obj::parent, and txn_info.

Referenced by acf_odbc_write().

1457 {
1458  struct ast_datastore *txn_store;
1459  AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
1460  struct odbc_txn_frame *txn = NULL;
1461 
1462  if (!chan) {
1463  /* No channel == no transaction */
1464  return NULL;
1465  }
1466 
1467  ast_channel_lock(chan);
1468  if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
1469  oldlist = txn_store->data;
1470  } else {
1471  ast_channel_unlock(chan);
1472  return NULL;
1473  }
1474 
1475  AST_LIST_LOCK(oldlist);
1476  ast_channel_unlock(chan);
1477 
1478  AST_LIST_TRAVERSE(oldlist, txn, list) {
1479  if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) {
1480  AST_LIST_UNLOCK(oldlist);
1481  return txn->obj;
1482  }
1483  }
1484  AST_LIST_UNLOCK(oldlist);
1485  return NULL;
1486 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
char name[80]
Definition: res_odbc.c:121
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static struct ast_datastore_info txn_info
Definition: res_odbc.c:157
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
struct odbc_txn_frame::@338 list
struct odbc_class * parent
Definition: res_odbc.h:49
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2467
void * data
Definition: datastore.h:56
struct odbc_obj * obj
Definition: res_odbc.c:165
int ast_odbc_sanity_check ( struct odbc_obj obj)

Checks an ODBC object to ensure it is still connected.

Parameters
objThe ODBC object
Return values
0if connected
-1otherwise.

Definition at line 735 of file res_odbc.c.

References ast_log(), ast_strlen_zero(), odbc_obj::con, LOG_WARNING, odbc_obj_connect(), odbc_obj_disconnect(), odbc_obj::parent, odbc_class::sanitysql, odbc_obj::tx, and odbc_obj::up.

Referenced by _ast_odbc_request_obj2(), ast_odbc_direct_execute(), ast_odbc_find_table(), ast_odbc_prepare_and_execute(), data_odbc_provider_handler(), and handle_cli_odbc_show().

736 {
737  char *test_sql = "select 1";
738  SQLHSTMT stmt;
739  int res = 0;
740 
741  if (!ast_strlen_zero(obj->parent->sanitysql))
742  test_sql = obj->parent->sanitysql;
743 
744  if (obj->up) {
745  res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
746  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
747  obj->up = 0;
748  } else {
749  res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
750  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
751  obj->up = 0;
752  } else {
753  res = SQLExecute(stmt);
754  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
755  obj->up = 0;
756  }
757  }
758  }
759  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
760  }
761 
762  if (!obj->up && !obj->tx) { /* Try to reconnect! */
763  ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
764  odbc_obj_disconnect(obj);
765  odbc_obj_connect(obj);
766  }
767  return obj->up;
768 }
SQLHDBC con
Definition: res_odbc.h:48
#define LOG_WARNING
Definition: logger.h:144
unsigned int tx
Definition: res_odbc.h:58
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
unsigned int up
Definition: res_odbc.h:57
struct odbc_class * parent
Definition: res_odbc.h:49
static odbc_status odbc_obj_connect(struct odbc_obj *obj)
Definition: res_odbc.c:1524
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
Definition: res_odbc.c:1488
char * sanitysql
Definition: res_odbc.c:125
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 687 of file res_odbc.c.

References ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_tvnow(), odbc_obj::last_used, odbc_obj::lock, and LOG_WARNING.

688 {
689  int res = 0, i;
690  SQLINTEGER nativeerror=0, numfields=0;
691  SQLSMALLINT diagbytes=0;
692  unsigned char state[10], diagnostic[256];
693 
694  ast_mutex_lock(&obj->lock);
695 
696  res = SQLExecute(stmt);
697  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
698  if (res == SQL_ERROR) {
699  SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
700  for (i = 0; i < numfields; i++) {
701  SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
702  ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
703  if (i > 10) {
704  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
705  break;
706  }
707  }
708  }
709  } else {
710  obj->last_used = ast_tvnow();
711  }
712 
713  ast_mutex_unlock(&obj->lock);
714 
715  return res;
716 }
#define LOG_WARNING
Definition: logger.h:144
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define ast_mutex_lock(a)
Definition: lock.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
ast_mutex_t lock
Definition: res_odbc.h:47
struct timeval last_used
Definition: res_odbc.h:50
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int commit_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 1128 of file res_odbc.c.

References ast_log(), ast_str_append(), ast_str_buffer(), ast_str_reset(), ast_str_strlen(), ast_str_thread_get(), ast_strlen_zero(), odbc_obj::con, errors_buf, find_transaction(), LOG_WARNING, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().

Referenced by load_module().

1129 {
1130  struct odbc_txn_frame *tx;
1131  SQLINTEGER nativeerror=0, numfields=0;
1132  SQLSMALLINT diagbytes=0, i;
1133  unsigned char state[10], diagnostic[256];
1134 
1135  if (ast_strlen_zero(data)) {
1136  tx = find_transaction(chan, NULL, NULL, 1);
1137  } else {
1138  tx = find_transaction(chan, NULL, data, 0);
1139  }
1140 
1141  pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK");
1142 
1143  if (tx) {
1144  if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) {
1145  struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
1146  ast_str_reset(errors);
1147 
1148  /* Handle possible transaction commit failure */
1149  SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1150  for (i = 0; i < numfields; i++) {
1151  SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1152  ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
1153  ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
1154  if (i > 10) {
1155  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1156  break;
1157  }
1158  }
1159  pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
1160  }
1161  }
1162  return 0;
1163 }
SQLHDBC con
Definition: res_odbc.h:48
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
static struct ast_threadstorage errors_buf
Definition: res_odbc.c:155
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:900
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
Definition: res_odbc.c:224
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
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:436
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
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:669
struct odbc_obj * obj
Definition: res_odbc.c:165
static int data_odbc_provider_handler ( const struct ast_data_search search,
struct ast_data root 
)
static

Definition at line 1726 of file res_odbc.c.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_data_add_bool(), ast_data_add_int(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), ast_mutex_lock, ast_mutex_unlock, ast_odbc_sanity_check(), class_container, odbc_class::count, isolation2text(), odbc_obj::lock, odbc_obj::tx, odbc_obj::up, and odbc_obj::used.

1728 {
1729  struct ao2_iterator aoi, aoi2;
1730  struct odbc_class *class;
1731  struct odbc_obj *current;
1732  struct ast_data *data_odbc_class, *data_odbc_connections, *data_odbc_connection;
1733  struct ast_data *enum_node;
1734  int count;
1735 
1737  while ((class = ao2_iterator_next(&aoi))) {
1738  data_odbc_class = ast_data_add_node(root, "class");
1739  if (!data_odbc_class) {
1740  ao2_ref(class, -1);
1741  continue;
1742  }
1743 
1744  ast_data_add_structure(odbc_class, data_odbc_class, class);
1745 
1746  if (!ao2_container_count(class->obj_container)) {
1747  ao2_ref(class, -1);
1748  continue;
1749  }
1750 
1751  data_odbc_connections = ast_data_add_node(data_odbc_class, "connections");
1752  if (!data_odbc_connections) {
1753  ao2_ref(class, -1);
1754  continue;
1755  }
1756 
1757  ast_data_add_bool(data_odbc_class, "shared", !class->haspool);
1758  /* isolation */
1759  enum_node = ast_data_add_node(data_odbc_class, "isolation");
1760  if (!enum_node) {
1761  ao2_ref(class, -1);
1762  continue;
1763  }
1764  ast_data_add_int(enum_node, "value", class->isolation);
1765  ast_data_add_str(enum_node, "text", isolation2text(class->isolation));
1766 
1767  count = 0;
1768  aoi2 = ao2_iterator_init(class->obj_container, 0);
1769  while ((current = ao2_iterator_next(&aoi2))) {
1770  data_odbc_connection = ast_data_add_node(data_odbc_connections, "connection");
1771  if (!data_odbc_connection) {
1772  ao2_ref(current, -1);
1773  continue;
1774  }
1775 
1776  ast_mutex_lock(&current->lock);
1777  ast_data_add_str(data_odbc_connection, "status", current->used ? "in use" :
1778  current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
1779  ast_data_add_bool(data_odbc_connection, "transactional", current->tx);
1780  ast_mutex_unlock(&current->lock);
1781 
1782  if (class->haspool) {
1783  ast_data_add_int(data_odbc_connection, "number", ++count);
1784  }
1785 
1786  ao2_ref(current, -1);
1787  }
1788  ao2_iterator_destroy(&aoi2);
1789  ao2_ref(class, -1);
1790 
1791  if (!ast_data_search_match(search, data_odbc_class)) {
1792  ast_data_remove_node(root, data_odbc_class);
1793  }
1794  }
1795  ao2_iterator_destroy(&aoi);
1796  return 0;
1797 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Definition: astobj2.c:470
The data tree to be returned by the callbacks and managed by functions local to this file...
Definition: data.c:85
#define ao2_iterator_next(arg1)
Definition: astobj2.h:1126
struct ast_data * ast_data_add_bool(struct ast_data *root, const char *childname, unsigned int boolean)
Add a boolean node type.
Definition: data.c:2344
#define ast_mutex_lock(a)
Definition: lock.h:155
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
unsigned int tx
Definition: res_odbc.h:58
ODBC container.
Definition: res_odbc.h:46
struct ast_data * ast_data_add_node(struct ast_data *root, const char *childname)
Add a container child.
Definition: data.c:2317
#define ao2_ref(o, delta)
Definition: astobj2.h:472
unsigned int used
Definition: res_odbc.h:56
unsigned int up
Definition: res_odbc.h:57
#define ast_data_add_structure(structure_name, root, structure)
Definition: data.h:620
void ast_data_remove_node(struct ast_data *root, struct ast_data *child)
Remove a node that was added using ast_data_add_.
Definition: data.c:2486
static const char * isolation2text(int iso)
Definition: res_odbc.c:190
int ast_odbc_sanity_check(struct odbc_obj *obj)
Checks an ODBC object to ensure it is still connected.
Definition: res_odbc.c:735
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
ast_mutex_t lock
Definition: res_odbc.h:47
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
struct ast_data * ast_data_add_str(struct ast_data *root, const char *childname, const char *string)
Add a string node type.
Definition: data.c:2401
struct ast_data * ast_data_add_int(struct ast_data *root, const char *childname, int value)
Add an integer node type.
Definition: data.c:2322
int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data)
Check the current generated node to know if it matches the search condition.
Definition: data.c:1458
static struct ao2_container * class_container
Definition: res_odbc.c:145
#define ast_mutex_unlock(a)
Definition: lock.h:156
static void destroy_table_cache ( struct odbc_cache_tables table)
static

Definition at line 428 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, and odbc_cache_tables::table.

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

428  {
429  struct odbc_cache_columns *col;
430  ast_debug(1, "Destroying table cache for %s\n", table->table);
431  AST_RWLIST_WRLOCK(&table->columns);
432  while ((col = AST_RWLIST_REMOVE_HEAD(&table->columns, list))) {
433  ast_free(col);
434  }
435  AST_RWLIST_UNLOCK(&table->columns);
437  ast_free(table);
438 }
#define AST_RWLIST_HEAD_DESTROY(head)
Destroys an rwlist head structure.
Definition: linkedlists.h:652
#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:64
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ast_free(a)
Definition: astmm.h:97
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:829
struct odbc_cache_tables::_columns columns
static struct odbc_txn_frame* find_transaction ( struct ast_channel chan,
struct odbc_obj obj,
const char *  name,
int  active 
)
static

Definition at line 224 of file res_odbc.c.

References odbc_txn_frame::active, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc(), ast_datastore_free(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, odbc_class::forcecommit, odbc_txn_frame::forcecommit, odbc_class::isolation, odbc_txn_frame::isolation, LOG_ERROR, odbc_txn_frame::name, odbc_txn_frame::obj, odbc_txn_frame::owner, odbc_obj::parent, odbc_obj::tx, odbc_obj::txf, and txn_info.

Referenced by acf_transaction_read(), acf_transaction_write(), ast_odbc_release_obj(), commit_exec(), and rollback_exec().

225 {
226  struct ast_datastore *txn_store;
227  AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
228  struct odbc_txn_frame *txn = NULL;
229 
230  if (!chan && obj && obj->txf && obj->txf->owner) {
231  chan = obj->txf->owner;
232  } else if (!chan) {
233  /* No channel == no transaction */
234  return NULL;
235  }
236 
237  ast_channel_lock(chan);
238  if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
239  oldlist = txn_store->data;
240  } else {
241  /* Need to create a new datastore */
242  if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) {
243  ast_log(LOG_ERROR, "Unable to allocate a new datastore. Cannot create a new transaction.\n");
244  ast_channel_unlock(chan);
245  return NULL;
246  }
247 
248  if (!(oldlist = ast_calloc(1, sizeof(*oldlist)))) {
249  ast_log(LOG_ERROR, "Unable to allocate datastore list head. Cannot create a new transaction.\n");
250  ast_datastore_free(txn_store);
251  ast_channel_unlock(chan);
252  return NULL;
253  }
254 
255  txn_store->data = oldlist;
256  AST_LIST_HEAD_INIT(oldlist);
257  ast_channel_datastore_add(chan, txn_store);
258  }
259 
260  AST_LIST_LOCK(oldlist);
261  ast_channel_unlock(chan);
262 
263  /* Scanning for an object is *fast*. Scanning for a name is much slower. */
264  if (obj != NULL || active == 1) {
265  AST_LIST_TRAVERSE(oldlist, txn, list) {
266  if (txn->obj == obj || txn->active) {
267  AST_LIST_UNLOCK(oldlist);
268  return txn;
269  }
270  }
271  }
272 
273  if (name != NULL) {
274  AST_LIST_TRAVERSE(oldlist, txn, list) {
275  if (!strcasecmp(txn->name, name)) {
276  AST_LIST_UNLOCK(oldlist);
277  return txn;
278  }
279  }
280  }
281 
282  /* Nothing found, create one */
283  if (name && obj && (txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1))) {
284  struct odbc_txn_frame *otxn;
285 
286  strcpy(txn->name, name); /* SAFE */
287  txn->obj = obj;
288  txn->isolation = obj->parent->isolation;
289  txn->forcecommit = obj->parent->forcecommit;
290  txn->owner = chan;
291  txn->active = 1;
292 
293  /* On creation, the txn becomes active, and all others inactive */
294  AST_LIST_TRAVERSE(oldlist, otxn, list) {
295  otxn->active = 0;
296  }
297  AST_LIST_INSERT_TAIL(oldlist, txn, list);
298 
299  obj->txf = txn;
300  obj->tx = 1;
301  }
302  AST_LIST_UNLOCK(oldlist);
303 
304  return txn;
305 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
unsigned int forcecommit
Definition: res_odbc.c:130
unsigned int active
Is this record the current active transaction within the channel? Note that the active flag is really...
Definition: res_odbc.c:173
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
char name[0]
Definition: res_odbc.c:176
static struct ast_datastore_info txn_info
Definition: res_odbc.c:157
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
unsigned int tx
Definition: res_odbc.h:58
struct ast_channel * owner
Definition: res_odbc.c:164
struct odbc_txn_frame::@338 list
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
unsigned int isolation
Definition: res_odbc.c:132
struct odbc_class * parent
Definition: res_odbc.h:49
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
struct odbc_txn_frame * txf
Definition: res_odbc.h:59
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Definition: datastore.c:98
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2467
static const char name[]
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:611
unsigned int forcecommit
Definition: res_odbc.c:174
void * data
Definition: datastore.h:56
#define ast_calloc(a, b)
Definition: astmm.h:82
unsigned int isolation
Definition: res_odbc.c:175
struct odbc_obj * obj
Definition: res_odbc.c:165
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2590
static char* handle_cli_odbc_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 935 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_odbc_sanity_check(), ast_strdup, ast_strftime(), class_container, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, odbc_class::count, ast_cli_args::fd, odbc_obj::lock, ast_cli_args::n, ast_cli_args::pos, odbc_obj::up, ast_cli_entry::usage, odbc_obj::used, and ast_cli_args::word.

936 {
937  struct ao2_iterator aoi;
938  struct odbc_class *class;
939  struct odbc_obj *current;
940  int length = 0;
941  int which = 0;
942  char *ret = NULL;
943 
944  switch (cmd) {
945  case CLI_INIT:
946  e->command = "odbc show";
947  e->usage =
948  "Usage: odbc show [class]\n"
949  " List settings of a particular ODBC class or,\n"
950  " if not specified, all classes.\n";
951  return NULL;
952  case CLI_GENERATE:
953  if (a->pos != 2)
954  return NULL;
955  length = strlen(a->word);
957  while ((class = ao2_iterator_next(&aoi))) {
958  if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
959  ret = ast_strdup(class->name);
960  }
961  ao2_ref(class, -1);
962  if (ret) {
963  break;
964  }
965  }
966  ao2_iterator_destroy(&aoi);
967  if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
968  ret = ast_strdup("all");
969  }
970  return ret;
971  }
972 
973  ast_cli(a->fd, "\nODBC DSN Settings\n");
974  ast_cli(a->fd, "-----------------\n\n");
976  while ((class = ao2_iterator_next(&aoi))) {
977  if ((a->argc == 2) || (a->argc == 3 && !strcmp(a->argv[2], "all")) || (!strcmp(a->argv[2], class->name))) {
978  int count = 0;
979  char timestr[80];
980  struct ast_tm tm;
981 
982  ast_localtime(&class->last_negative_connect, &tm, NULL);
983  ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %T", &tm);
984  ast_cli(a->fd, " Name: %s\n DSN: %s\n", class->name, class->dsn);
985  ast_cli(a->fd, " Last connection attempt: %s\n", timestr);
986 
987  if (class->haspool) {
988  struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
989 
990  ast_cli(a->fd, " Pooled: Yes\n Limit: %u\n Connections in use: %d\n", class->limit, class->count);
991 
992  while ((current = ao2_iterator_next(&aoi2))) {
993  ast_mutex_lock(&current->lock);
994 #ifdef DEBUG_THREADS
995  ast_cli(a->fd, " - Connection %d: %s (%s:%d %s)\n", ++count,
996  current->used ? "in use" :
997  current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected",
998  current->file, current->lineno, current->function);
999 #else
1000  ast_cli(a->fd, " - Connection %d: %s\n", ++count,
1001  current->used ? "in use" :
1002  current->up && ast_odbc_sanity_check(current) ? "connected" : "disconnected");
1003 #endif
1004  ast_mutex_unlock(&current->lock);
1005  ao2_ref(current, -1);
1006  }
1007  ao2_iterator_destroy(&aoi2);
1008  } else {
1009  /* Should only ever be one of these (unless there are transactions) */
1010  struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
1011  while ((current = ao2_iterator_next(&aoi2))) {
1012  ast_cli(a->fd, " Pooled: No\n Connected: %s\n", current->used ? "In use" :
1013  current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
1014  ao2_ref(current, -1);
1015  }
1016  ao2_iterator_destroy(&aoi2);
1017  }
1018  ast_cli(a->fd, "\n");
1019  }
1020  ao2_ref(class, -1);
1021  }
1022  ao2_iterator_destroy(&aoi);
1023 
1024  return CLI_SUCCESS;
1025 }
#define ast_strdup(a)
Definition: astmm.h:109
#define ao2_iterator_next(arg1)
Definition: astobj2.h:1126
const int argc
Definition: cli.h:154
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:1570
Definition: cli.h:146
#define ast_mutex_lock(a)
Definition: lock.h:155
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
ODBC container.
Definition: res_odbc.h:46
const int fd
Definition: cli.h:153
const int n
Definition: cli.h:159
#define ao2_ref(o, delta)
Definition: astobj2.h:472
unsigned int used
Definition: res_odbc.h:56
unsigned int up
Definition: res_odbc.h:57
const char *const * argv
Definition: cli.h:155
char * command
Definition: cli.h:180
const char * word
Definition: cli.h:157
int ast_odbc_sanity_check(struct odbc_obj *obj)
Checks an ODBC object to ensure it is still connected.
Definition: res_odbc.c:735
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:2351
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
ast_mutex_t lock
Definition: res_odbc.h:47
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
const int pos
Definition: cli.h:158
static struct ao2_container * class_container
Definition: res_odbc.c:145
#define ast_mutex_unlock(a)
Definition: lock.h:156
static const char* isolation2text ( int  iso)
static

Definition at line 190 of file res_odbc.c.

Referenced by acf_transaction_read(), and data_odbc_provider_handler().

191 {
192  if (iso == SQL_TXN_READ_COMMITTED) {
193  return "read_committed";
194  } else if (iso == SQL_TXN_READ_UNCOMMITTED) {
195  return "read_uncommitted";
196  } else if (iso == SQL_TXN_SERIALIZABLE) {
197  return "serializable";
198  } else if (iso == SQL_TXN_REPEATABLE_READ) {
199  return "repeatable_read";
200  } else {
201  return "unknown";
202  }
203 }
static int load_module ( void  )
static

Definition at line 1892 of file res_odbc.c.

References ao2_container_alloc, ao2_match_by_addr, app_commit, app_rollback, ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_data_register_multiple, ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_application_xml, class_container, cli_odbc, commit_exec(), load_odbc_config(), LOG_NOTICE, null_hash_fn(), odbc_function, odbc_providers, and rollback_exec().

1893 {
1895  return AST_MODULE_LOAD_DECLINE;
1896  if (load_odbc_config() == -1)
1897  return AST_MODULE_LOAD_DECLINE;
1903  ast_log(LOG_NOTICE, "res_odbc loaded.\n");
1904  return 0;
1905 }
static int null_hash_fn(const void *obj, const int flags)
Definition: res_odbc.c:413
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int load_odbc_config(void)
Definition: res_odbc.c:770
static struct ast_custom_function odbc_function
Definition: res_odbc.c:1713
static const char *const app_rollback
Definition: res_odbc.c:1720
static const char *const app_commit
Definition: res_odbc.c:1719
static struct ast_cli_entry cli_odbc[]
Definition: res_odbc.c:1027
#define ast_data_register_multiple(data_entries, entries)
Definition: data.h:377
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
static int rollback_exec(struct ast_channel *chan, const char *data)
Definition: res_odbc.c:1165
ao2_callback_fn ao2_match_by_addr
a very common callback is one that matches by address.
Definition: astobj2.h:646
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
static struct ast_data_entry odbc_providers[]
Definition: res_odbc.c:1808
static int commit_exec(struct ast_channel *chan, const char *data)
Definition: res_odbc.c:1128
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
static struct ao2_container * class_container
Definition: res_odbc.c:145
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static int load_odbc_config ( void  )
static

Definition at line 770 of file res_odbc.c.

References odbc_class::allow_empty_strings, ao2_alloc, ao2_container_alloc, ao2_match_by_addr, ao2_ref, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_false(), ast_log(), 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::idlecheck, odbc_class::isolation, odbc_class::limit, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, null_hash_fn(), odbc_class_destructor(), odbc_register_class(), odbc_class::password, odbc_class::sanitysql, setenv(), text2isolation(), odbc_class::username, and ast_variable::value.

Referenced by load_module(), and reload().

771 {
772  static char *cfg = "res_odbc.conf";
773  struct ast_config *config;
774  struct ast_variable *v;
775  char *cat;
776  const char *dsn, *username, *password, *sanitysql;
777  int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation, allow_empty_strings;
778  struct timeval ncache = { 0, 0 };
779  unsigned int idlecheck;
780  int preconnect = 0, res = 0;
781  struct ast_flags config_flags = { 0 };
782 
783  struct odbc_class *new;
784 
785  config = ast_config_load(cfg, config_flags);
786  if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
787  ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
788  return -1;
789  }
790  for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) {
791  if (!strcasecmp(cat, "ENV")) {
792  for (v = ast_variable_browse(config, cat); v; v = v->next) {
793  setenv(v->name, v->value, 1);
794  ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value);
795  }
796  } else {
797  /* Reset all to defaults for each class of odbc connections */
798  dsn = username = password = sanitysql = NULL;
799  enabled = 1;
800  preconnect = idlecheck = 0;
801  pooling = 0;
802  limit = 0;
803  bse = 1;
804  conntimeout = 10;
805  forcecommit = 0;
806  allow_empty_strings = 1;
807  isolation = SQL_TXN_READ_COMMITTED;
808  for (v = ast_variable_browse(config, cat); v; v = v->next) {
809  if (!strcasecmp(v->name, "pooling")) {
810  if (ast_true(v->value))
811  pooling = 1;
812  } else if (!strncasecmp(v->name, "share", 5)) {
813  /* "shareconnections" is a little clearer in meaning than "pooling" */
814  if (ast_false(v->value))
815  pooling = 1;
816  } else if (!strcasecmp(v->name, "limit")) {
817  sscanf(v->value, "%30d", &limit);
818  if (ast_true(v->value) && !limit) {
819  ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Setting limit to 1023 for ODBC class '%s'.\n", v->value, cat);
820  limit = 1023;
821  } else if (ast_false(v->value)) {
822  ast_log(LOG_WARNING, "Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->value, cat);
823  enabled = 0;
824  break;
825  }
826  } else if (!strcasecmp(v->name, "idlecheck")) {
827  sscanf(v->value, "%30u", &idlecheck);
828  } else if (!strcasecmp(v->name, "enabled")) {
829  enabled = ast_true(v->value);
830  } else if (!strcasecmp(v->name, "pre-connect")) {
831  preconnect = ast_true(v->value);
832  } else if (!strcasecmp(v->name, "dsn")) {
833  dsn = v->value;
834  } else if (!strcasecmp(v->name, "username")) {
835  username = v->value;
836  } else if (!strcasecmp(v->name, "password")) {
837  password = v->value;
838  } else if (!strcasecmp(v->name, "sanitysql")) {
839  sanitysql = v->value;
840  } else if (!strcasecmp(v->name, "backslash_is_escape")) {
841  bse = ast_true(v->value);
842  } else if (!strcasecmp(v->name, "allow_empty_string_in_nontext")) {
843  allow_empty_strings = ast_true(v->value);
844  } else if (!strcasecmp(v->name, "connect_timeout")) {
845  if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
846  ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
847  conntimeout = 10;
848  }
849  } else if (!strcasecmp(v->name, "negative_connection_cache")) {
850  double dncache;
851  if (sscanf(v->value, "%lf", &dncache) != 1 || dncache < 0) {
852  ast_log(LOG_WARNING, "negative_connection_cache must be a non-negative integer\n");
853  /* 5 minutes sounds like a reasonable default */
854  ncache.tv_sec = 300;
855  ncache.tv_usec = 0;
856  } else {
857  ncache.tv_sec = (int)dncache;
858  ncache.tv_usec = (dncache - ncache.tv_sec) * 1000000;
859  }
860  } else if (!strcasecmp(v->name, "forcecommit")) {
861  forcecommit = ast_true(v->value);
862  } else if (!strcasecmp(v->name, "isolation")) {
863  if ((isolation = text2isolation(v->value)) == 0) {
864  ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat);
865  isolation = SQL_TXN_READ_COMMITTED;
866  }
867  }
868  }
869 
870  if (enabled && !ast_strlen_zero(dsn)) {
871  new = ao2_alloc(sizeof(*new), odbc_class_destructor);
872 
873  if (!new) {
874  res = -1;
875  break;
876  }
877 
878  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
879  res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
880 
881  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
882  ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
883  ao2_ref(new, -1);
884  return res;
885  }
886 
887  new->obj_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr);
888 
889  if (pooling) {
890  new->haspool = pooling;
891  if (limit) {
892  new->limit = limit;
893  } else {
894  ast_log(LOG_WARNING, "Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n");
895  new->limit = 5;
896  }
897  }
898 
899  new->backslash_is_escape = bse ? 1 : 0;
900  new->forcecommit = forcecommit ? 1 : 0;
901  new->isolation = isolation;
902  new->idlecheck = idlecheck;
903  new->conntimeout = conntimeout;
904  new->negative_connection_cache = ncache;
905  new->allow_empty_strings = allow_empty_strings ? 1 : 0;
906 
907  if (cat)
908  ast_copy_string(new->name, cat, sizeof(new->name));
909  if (dsn)
910  ast_copy_string(new->dsn, dsn, sizeof(new->dsn));
911  if (username && !(new->username = ast_strdup(username))) {
912  ao2_ref(new, -1);
913  break;
914  }
915  if (password && !(new->password = ast_strdup(password))) {
916  ao2_ref(new, -1);
917  break;
918  }
919  if (sanitysql && !(new->sanitysql = ast_strdup(sanitysql))) {
920  ao2_ref(new, -1);
921  break;
922  }
923 
924  odbc_register_class(new, preconnect);
925  ast_log(LOG_NOTICE, "Registered ODBC class '%s' dsn->[%s]\n", cat, dsn);
926  ao2_ref(new, -1);
927  new = NULL;
928  }
929  }
930  }
931  ast_config_destroy(config);
932  return res;
933 }
static void odbc_class_destructor(void *data)
Definition: res_odbc.c:394
static int null_hash_fn(const void *obj, const int flags)
Definition: res_odbc.c:413
static const char config[]
Definition: cdr_csv.c:57
#define ast_strdup(a)
Definition: astmm.h:109
#define LOG_WARNING
Definition: logger.h:144
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
unsigned int idlecheck
Definition: res_odbc.c:135
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
#define CONFIG_STATUS_FILEMISSING
Definition: config.h:50
unsigned int isolation
Definition: res_odbc.c:132
const char * value
Definition: config.h:79
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
unsigned int enabled
Definition: devicestate.c:205
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define ao2_ref(o, delta)
Definition: astobj2.h:472
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
unsigned int conntimeout
Definition: res_odbc.c:136
const char * name
Definition: config.h:77
#define LOG_ERROR
Definition: logger.h:155
unsigned int limit
Definition: res_odbc.c:133
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
int setenv(const char *name, const char *value, int overwrite)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
#define LOG_NOTICE
Definition: logger.h:133
static int text2isolation(const char *txt)
Definition: res_odbc.c:205
static char * dsn
Definition: cdr_odbc.c:50
static int odbc_register_class(struct odbc_class *class, int connect)
Definition: res_odbc.c:1031
Structure used to handle boolean flags.
Definition: utils.h:200
ao2_callback_fn ao2_match_by_addr
a very common callback is one that matches by address.
Definition: astobj2.h:646
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is &quot;false&quot;...
Definition: utils.c:1550
struct ast_variable * next
Definition: config.h:82
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static int mark_transaction_active ( struct ast_channel chan,
struct odbc_txn_frame tx 
)
static

Definition at line 359 of file res_odbc.c.

References odbc_txn_frame::active, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, odbc_txn_frame::owner, and txn_info.

Referenced by acf_transaction_write().

360 {
361  struct ast_datastore *txn_store;
362  AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
363  struct odbc_txn_frame *active = NULL, *txn;
364 
365  if (!chan && tx && tx->owner) {
366  chan = tx->owner;
367  }
368 
369  if (!chan) {
370  return -1;
371  }
372 
373  ast_channel_lock(chan);
374  if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
375  ast_channel_unlock(chan);
376  return -1;
377  }
378 
379  oldlist = txn_store->data;
380  AST_LIST_LOCK(oldlist);
381  AST_LIST_TRAVERSE(oldlist, txn, list) {
382  if (txn == tx) {
383  txn->active = 1;
384  active = txn;
385  } else {
386  txn->active = 0;
387  }
388  }
389  AST_LIST_UNLOCK(oldlist);
390  ast_channel_unlock(chan);
391  return active ? 0 : -1;
392 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
unsigned int active
Is this record the current active transaction within the channel? Note that the active flag is really...
Definition: res_odbc.c:173
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static struct ast_datastore_info txn_info
Definition: res_odbc.c:157
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
struct ast_channel * owner
Definition: res_odbc.c:164
struct odbc_txn_frame::@338 list
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2467
void * data
Definition: datastore.h:56
static int null_hash_fn ( const void *  obj,
const int  flags 
)
static

Definition at line 413 of file res_odbc.c.

Referenced by load_module(), and load_odbc_config().

414 {
415  return 0;
416 }
static void odbc_class_destructor ( void *  data)
static

Definition at line 394 of file res_odbc.c.

References ao2_ref, and ast_free.

Referenced by load_odbc_config().

395 {
396  struct odbc_class *class = data;
397  /* Due to refcounts, we can safely assume that any objects with a reference
398  * to us will prevent our destruction, so we don't need to worry about them.
399  */
400  if (class->username) {
401  ast_free(class->username);
402  }
403  if (class->password) {
404  ast_free(class->password);
405  }
406  if (class->sanitysql) {
407  ast_free(class->sanitysql);
408  }
409  ao2_ref(class->obj_container, -1);
410  SQLFreeHandle(SQL_HANDLE_ENV, class->env);
411 }
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ast_free(a)
Definition: astmm.h:97
static odbc_status odbc_obj_connect ( struct odbc_obj obj)
static

Definition at line 1524 of file res_odbc.c.

References ast_assert, ast_log(), ast_tvnow(), odbc_obj::con, odbc_class::conntimeout, odbc_class::dsn, odbc_class::env, odbc_class::last_negative_connect, odbc_obj::last_used, LOG_NOTICE, LOG_WARNING, odbc_class::name, ODBC_FAIL, odbc_obj_disconnect(), ODBC_SUCCESS, odbc_obj::parent, odbc_class::password, odbc_obj::up, and odbc_class::username.

Referenced by _ast_odbc_request_obj2(), and ast_odbc_sanity_check().

1525 {
1526  int res;
1527  SQLINTEGER err;
1528  short int mlen;
1529  unsigned char msg[200], state[10];
1530 #ifdef NEEDTRACE
1531  SQLINTEGER enable = 1;
1532  char *tracefile = "/tmp/odbc.trace";
1533 #endif
1534  SQLHDBC con;
1535 
1536  if (obj->up) {
1537  odbc_obj_disconnect(obj);
1538  ast_log(LOG_NOTICE, "Re-connecting %s\n", obj->parent->name);
1539  } else {
1540  ast_assert(obj->con == NULL);
1541  ast_log(LOG_NOTICE, "Connecting %s\n", obj->parent->name);
1542  }
1543 
1544  res = SQLAllocHandle(SQL_HANDLE_DBC, obj->parent->env, &con);
1545 
1546  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1547  ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
1549  return ODBC_FAIL;
1550  }
1551  SQLSetConnectAttr(con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
1552  SQLSetConnectAttr(con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *)(long) obj->parent->conntimeout, 0);
1553 #ifdef NEEDTRACE
1554  SQLSetConnectAttr(con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
1555  SQLSetConnectAttr(con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
1556 #endif
1557 
1558  res = SQLConnect(con,
1559  (SQLCHAR *) obj->parent->dsn, SQL_NTS,
1560  (SQLCHAR *) obj->parent->username, SQL_NTS,
1561  (SQLCHAR *) obj->parent->password, SQL_NTS);
1562 
1563  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1564  SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1566  ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
1567  if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con) != SQL_SUCCESS)) {
1568  SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1569  ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
1570  }
1571  return ODBC_FAIL;
1572  } else {
1573  ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->parent->name, obj->parent->dsn);
1574  obj->up = 1;
1575  obj->last_used = ast_tvnow();
1576  }
1577 
1578  obj->con = con;
1579  return ODBC_SUCCESS;
1580 }
SQLHDBC con
Definition: res_odbc.h:48
char name[80]
Definition: res_odbc.c:121
#define LOG_WARNING
Definition: logger.h:144
char * password
Definition: res_odbc.c:124
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define ast_assert(a)
Definition: utils.h:738
unsigned int conntimeout
Definition: res_odbc.c:136
unsigned int up
Definition: res_odbc.h:57
struct odbc_class * parent
Definition: res_odbc.h:49
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
Definition: res_odbc.c:1488
#define LOG_NOTICE
Definition: logger.h:133
struct timeval last_used
Definition: res_odbc.h:50
SQLHENV env
Definition: res_odbc.c:126
struct timeval last_negative_connect
Definition: res_odbc.c:140
char * username
Definition: res_odbc.c:123
char dsn[80]
Definition: res_odbc.c:122
static void odbc_obj_destructor ( void *  data)
static

Definition at line 418 of file res_odbc.c.

References ao2_ref, ast_mutex_destroy, odbc_obj::lock, odbc_obj_disconnect(), and odbc_obj::parent.

Referenced by _ast_odbc_request_obj2().

419 {
420  struct odbc_obj *obj = data;
421  struct odbc_class *class = obj->parent;
422  obj->parent = NULL;
423  odbc_obj_disconnect(obj);
424  ast_mutex_destroy(&obj->lock);
425  ao2_ref(class, -1);
426 }
ODBC container.
Definition: res_odbc.h:46
#define ao2_ref(o, delta)
Definition: astobj2.h:472
struct odbc_class * parent
Definition: res_odbc.h:49
static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
Definition: res_odbc.c:1488
ast_mutex_t lock
Definition: res_odbc.h:47
#define ast_mutex_destroy(a)
Definition: lock.h:154
static odbc_status odbc_obj_disconnect ( struct odbc_obj obj)
static

Definition at line 1488 of file res_odbc.c.

References ast_log(), odbc_obj::con, odbc_class::dsn, LOG_DEBUG, LOG_WARNING, odbc_class::name, ODBC_SUCCESS, odbc_obj::parent, and odbc_obj::up.

Referenced by ast_odbc_sanity_check(), odbc_obj_connect(), and odbc_obj_destructor().

1489 {
1490  int res;
1491  SQLINTEGER err;
1492  short int mlen;
1493  unsigned char msg[200], state[10];
1494  SQLHDBC con;
1495 
1496  /* Nothing to disconnect */
1497  if (!obj->con) {
1498  return ODBC_SUCCESS;
1499  }
1500 
1501  con = obj->con;
1502  obj->con = NULL;
1503  res = SQLDisconnect(con);
1504 
1505  if (obj->parent) {
1506  if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
1507  ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
1508  } else {
1509  ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
1510  }
1511  }
1512 
1513  if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con) == SQL_SUCCESS)) {
1514  ast_log(LOG_DEBUG, "Database handle %p deallocated\n", con);
1515  } else {
1516  SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1517  ast_log(LOG_WARNING, "Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (int)err, msg);
1518  }
1519 
1520  obj->up = 0;
1521  return ODBC_SUCCESS;
1522 }
SQLHDBC con
Definition: res_odbc.h:48
char name[80]
Definition: res_odbc.c:121
#define LOG_WARNING
Definition: logger.h:144
#define LOG_DEBUG
Definition: logger.h:122
unsigned int up
Definition: res_odbc.h:57
struct odbc_class * parent
Definition: res_odbc.h:49
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
char dsn[80]
Definition: res_odbc.c:122
static int odbc_register_class ( struct odbc_class class,
int  connect 
)
static

Definition at line 1031 of file res_odbc.c.

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

Referenced by load_odbc_config().

1032 {
1033  struct odbc_obj *obj;
1034  if (class) {
1035  ao2_link(class_container, class);
1036  /* I still have a reference in the caller, so a deref is NOT missing here. */
1037 
1038  if (preconnect) {
1039  /* Request and release builds a connection */
1040  obj = ast_odbc_request_obj(class->name, 0);
1041  if (obj) {
1042  ast_odbc_release_obj(obj);
1043  }
1044  }
1045 
1046  return 0;
1047  } else {
1048  ast_log(LOG_WARNING, "Attempted to register a NULL class?\n");
1049  return -1;
1050  }
1051 }
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
char name[80]
Definition: res_odbc.c:121
#define LOG_WARNING
Definition: logger.h:144
ODBC container.
Definition: res_odbc.h:46
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:123
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:1112
static struct ao2_container * class_container
Definition: res_odbc.c:145
static void odbc_release_obj2 ( struct odbc_obj obj,
struct odbc_txn_frame tx 
)
static

Definition at line 1053 of file res_odbc.c.

References ao2_ref, ast_debug, ast_log(), odbc_obj::con, odbc_txn_frame::forcecommit, LOG_WARNING, odbc_txn_frame::obj, release_transaction(), odbc_obj::txf, and odbc_obj::used.

Referenced by ast_odbc_release_obj(), and release_transaction().

1054 {
1055  SQLINTEGER nativeerror=0, numfields=0;
1056  SQLSMALLINT diagbytes=0, i;
1057  unsigned char state[10], diagnostic[256];
1058 
1059  ast_debug(2, "odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->txf);
1060  if (tx) {
1061  ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK");
1062  if (SQLEndTran(SQL_HANDLE_DBC, obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
1063  /* Handle possible transaction commit failure */
1064  SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1065  for (i = 0; i < numfields; i++) {
1066  SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1067  ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
1068  if (!strcmp((char *)state, "25S02") || !strcmp((char *)state, "08007")) {
1069  /* These codes mean that a commit failed and a transaction
1070  * is still active. We must rollback, or things will get
1071  * very, very weird for anybody using the handle next. */
1072  SQLEndTran(SQL_HANDLE_DBC, obj->con, SQL_ROLLBACK);
1073  }
1074  if (i > 10) {
1075  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1076  break;
1077  }
1078  }
1079  }
1080 
1081  /* Transaction is done, reset autocommit */
1082  if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
1083  SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1084  for (i = 0; i < numfields; i++) {
1085  SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1086  ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1087  if (i > 10) {
1088  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1089  break;
1090  }
1091  }
1092  }
1093  }
1094 
1095 #ifdef DEBUG_THREADS
1096  obj->file[0] = '\0';
1097  obj->function[0] = '\0';
1098  obj->lineno = 0;
1099 #endif
1100 
1101  /* For pooled connections, this frees the connection to be
1102  * reused. For non-pooled connections, it does nothing. */
1103  obj->used = 0;
1104  if (obj->txf) {
1105  /* Prevent recursion -- transaction is already closed out. */
1106  obj->txf->obj = NULL;
1107  obj->txf = release_transaction(obj->txf);
1108  }
1109  ao2_ref(obj, -1);
1110 }
SQLHDBC con
Definition: res_odbc.h:48
static struct odbc_txn_frame * release_transaction(struct odbc_txn_frame *tx)
Definition: res_odbc.c:307
#define LOG_WARNING
Definition: logger.h:144
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ao2_ref(o, delta)
Definition: astobj2.h:472
unsigned int used
Definition: res_odbc.h:56
struct odbc_txn_frame * txf
Definition: res_odbc.h:59
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
unsigned int forcecommit
Definition: res_odbc.c:174
struct odbc_obj * obj
Definition: res_odbc.c:165
static void odbc_txn_free ( void *  data)
static

Definition at line 343 of file res_odbc.c.

References ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and release_transaction().

344 {
345  struct odbc_txn_frame *tx;
346  AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata;
347 
348  ast_debug(2, "odbc_txn_free(%p) called\n", vdata);
349 
350  AST_LIST_LOCK(oldlist);
351  while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) {
353  }
354  AST_LIST_UNLOCK(oldlist);
355  AST_LIST_HEAD_DESTROY(oldlist);
356  ast_free(oldlist);
357 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
static struct odbc_txn_frame * release_transaction(struct odbc_txn_frame *tx)
Definition: res_odbc.c:307
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct odbc_txn_frame::@338 list
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:638
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
#define ast_free(a)
Definition: astmm.h:97
static struct odbc_txn_frame* release_transaction ( struct odbc_txn_frame tx)
static

Definition at line 307 of file res_odbc.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_datastore::data, odbc_txn_frame::obj, odbc_release_obj2(), odbc_txn_frame::owner, odbc_obj::txf, and txn_info.

Referenced by odbc_release_obj2(), and odbc_txn_free().

308 {
309  if (!tx) {
310  return NULL;
311  }
312 
313  ast_debug(2, "release_transaction(%p) called (tx->obj = %p, tx->obj->txf = %p)\n", tx, tx->obj, tx->obj ? tx->obj->txf : NULL);
314 
315  /* If we have an owner, disassociate */
316  if (tx->owner) {
317  struct ast_datastore *txn_store;
318  AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
319 
320  ast_channel_lock(tx->owner);
321  if ((txn_store = ast_channel_datastore_find(tx->owner, &txn_info, NULL))) {
322  oldlist = txn_store->data;
323  AST_LIST_LOCK(oldlist);
324  AST_LIST_REMOVE(oldlist, tx, list);
325  AST_LIST_UNLOCK(oldlist);
326  }
328  tx->owner = NULL;
329  }
330 
331  if (tx->obj) {
332  /* If we have any uncommitted transactions, they are handled when we release the object */
333  struct odbc_obj *obj = tx->obj;
334  /* Prevent recursion during destruction */
335  tx->obj->txf = NULL;
336  tx->obj = NULL;
337  odbc_release_obj2(obj, tx);
338  }
339  ast_free(tx);
340  return NULL;
341 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static struct ast_datastore_info txn_info
Definition: res_odbc.c:157
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
struct ast_channel * owner
Definition: res_odbc.c:164
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
ODBC container.
Definition: res_odbc.h:46
static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx)
Definition: res_odbc.c:1053
struct odbc_txn_frame * txf
Definition: res_odbc.h:59
#define ast_channel_unlock(chan)
Definition: channel.h:2467
#define ast_free(a)
Definition: astmm.h:97
void * data
Definition: datastore.h:56
struct odbc_obj * obj
Definition: res_odbc.c:165
static int reload ( void  )
static

Definition at line 1812 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, class_container, destroy_table_cache(), load_odbc_config(), and table.

1813 {
1814  struct odbc_cache_tables *table;
1815  struct odbc_class *class;
1816  struct odbc_obj *current;
1818 
1819  /* First, mark all to be purged */
1820  while ((class = ao2_iterator_next(&aoi))) {
1821  class->delme = 1;
1822  ao2_ref(class, -1);
1823  }
1824  ao2_iterator_destroy(&aoi);
1825 
1826  load_odbc_config();
1827 
1828  /* Purge remaining classes */
1829 
1830  /* Note on how this works; this is a case of circular references, so we
1831  * explicitly do NOT want to use a callback here (or we wind up in
1832  * recursive hell).
1833  *
1834  * 1. Iterate through all the classes. Note that the classes will currently
1835  * contain two classes of the same name, one of which is marked delme and
1836  * will be purged when all remaining objects of the class are released, and
1837  * the other, which was created above when we re-parsed the config file.
1838  * 2. On each class, there is a reference held by the master container and
1839  * a reference held by each connection object. There are two cases for
1840  * destruction of the class, noted below. However, in all cases, all O-refs
1841  * (references to objects) will first be freed, which will cause the C-refs
1842  * (references to classes) to be decremented (but never to 0, because the
1843  * class container still has a reference).
1844  * a) If the class has outstanding objects, the C-ref by the class
1845  * container will then be freed, which leaves only C-refs by any
1846  * outstanding objects. When the final outstanding object is released
1847  * (O-refs held by applications and dialplan functions), it will in turn
1848  * free the final C-ref, causing class destruction.
1849  * b) If the class has no outstanding objects, when the class container
1850  * removes the final C-ref, the class will be destroyed.
1851  */
1853  while ((class = ao2_iterator_next(&aoi))) { /* C-ref++ (by iterator) */
1854  if (class->delme) {
1855  struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
1856  while ((current = ao2_iterator_next(&aoi2))) { /* O-ref++ (by iterator) */
1857  ao2_unlink(class->obj_container, current); /* unlink O-ref from class (reference handled implicitly) */
1858  ao2_ref(current, -1); /* O-ref-- (by iterator) */
1859  /* At this point, either
1860  * a) there's an outstanding O-ref, or
1861  * b) the object has already been destroyed.
1862  */
1863  }
1864  ao2_iterator_destroy(&aoi2);
1865  ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
1866  /* At this point, either
1867  * a) there's an outstanding O-ref, which holds an outstanding C-ref, or
1868  * b) the last remaining C-ref is held by the iterator, which will be
1869  * destroyed in the next step.
1870  */
1871  }
1872  ao2_ref(class, -1); /* C-ref-- (by iterator) */
1873  }
1874  ao2_iterator_destroy(&aoi);
1875 
1876  /* Empty the cache; it will get rebuilt the next time the tables are needed. */
1878  while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
1879  destroy_table_cache(table);
1880  }
1882 
1883  return 0;
1884 }
static int load_odbc_config(void)
Definition: res_odbc.c:770
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define ao2_iterator_next(arg1)
Definition: astobj2.h:1126
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
static void destroy_table_cache(struct odbc_cache_tables *table)
Definition: res_odbc.c:428
static char * table
Definition: cdr_odbc.c:50
ODBC container.
Definition: res_odbc.h:46
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:829
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
#define ao2_unlink(arg1, arg2)
Definition: astobj2.h:817
static struct ao2_container * class_container
Definition: res_odbc.c:145
static int rollback_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 1165 of file res_odbc.c.

References ast_log(), ast_str_append(), ast_str_buffer(), ast_str_reset(), ast_str_strlen(), ast_str_thread_get(), ast_strlen_zero(), odbc_obj::con, errors_buf, find_transaction(), LOG_WARNING, odbc_txn_frame::obj, and pbx_builtin_setvar_helper().

Referenced by load_module().

1166 {
1167  struct odbc_txn_frame *tx;
1168  SQLINTEGER nativeerror=0, numfields=0;
1169  SQLSMALLINT diagbytes=0, i;
1170  unsigned char state[10], diagnostic[256];
1171 
1172  if (ast_strlen_zero(data)) {
1173  tx = find_transaction(chan, NULL, NULL, 1);
1174  } else {
1175  tx = find_transaction(chan, NULL, data, 0);
1176  }
1177 
1178  pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK");
1179 
1180  if (tx) {
1181  if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) {
1182  struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
1183  ast_str_reset(errors);
1184 
1185  /* Handle possible transaction commit failure */
1186  SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1187  for (i = 0; i < numfields; i++) {
1188  SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
1189  ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
1190  ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
1191  if (i > 10) {
1192  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
1193  break;
1194  }
1195  }
1196  pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
1197  }
1198  }
1199  return 0;
1200 }
SQLHDBC con
Definition: res_odbc.h:48
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
static struct ast_threadstorage errors_buf
Definition: res_odbc.c:155
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:900
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
Definition: res_odbc.c:224
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
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:436
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
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:669
struct odbc_obj * obj
Definition: res_odbc.c:165
static int text2isolation ( const char *  txt)
static

Definition at line 205 of file res_odbc.c.

Referenced by acf_transaction_write(), and load_odbc_config().

206 {
207  if (strncasecmp(txt, "read_", 5) == 0) {
208  if (strncasecmp(txt + 5, "c", 1) == 0) {
209  return SQL_TXN_READ_COMMITTED;
210  } else if (strncasecmp(txt + 5, "u", 1) == 0) {
211  return SQL_TXN_READ_UNCOMMITTED;
212  } else {
213  return 0;
214  }
215  } else if (strncasecmp(txt, "ser", 3) == 0) {
216  return SQL_TXN_SERIALIZABLE;
217  } else if (strncasecmp(txt, "rep", 3) == 0) {
218  return SQL_TXN_REPEATABLE_READ;
219  } else {
220  return 0;
221  }
222 }
static int unload_module ( void  )
static

Definition at line 1886 of file res_odbc.c.

1887 {
1888  /* Prohibit unloading */
1889  return -1;
1890 }

Variable Documentation

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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DEPEND, }
static

Definition at line 1912 of file res_odbc.c.

const char* const app_commit = "ODBC_Commit"
static

Definition at line 1719 of file res_odbc.c.

Referenced by load_module().

const char* const app_rollback = "ODBC_Rollback"
static

Definition at line 1720 of file res_odbc.c.

Referenced by load_module().

Definition at line 1912 of file res_odbc.c.

struct ast_cli_entry cli_odbc[]
static
Initial value:
= {
AST_CLI_DEFINE(handle_cli_odbc_show, "List ODBC DSN(s)")
}
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static char * handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: res_odbc.c:935

Definition at line 1027 of file res_odbc.c.

Referenced by load_module().

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

Definition at line 155 of file res_odbc.c.

Referenced by commit_exec(), and rollback_exec().

struct ast_custom_function odbc_function
static
Initial value:
= {
.name = "ODBC",
}
static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: res_odbc.c:1582
static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
Definition: res_odbc.c:1620

Definition at line 1713 of file res_odbc.c.

Referenced by load_module().

struct ast_data_handler odbc_provider
static
Initial value:
= {
}
#define AST_DATA_HANDLER_VERSION
The Data API structures version.
Definition: data.h:204
static int data_odbc_provider_handler(const struct ast_data_search *search, struct ast_data *root)
Definition: res_odbc.c:1726

Definition at line 1803 of file res_odbc.c.

struct ast_data_entry odbc_providers[]
static
Initial value:
= {
AST_DATA_ENTRY("/asterisk/res/odbc", &odbc_provider),
}
static struct ast_data_handler odbc_provider
Definition: res_odbc.c:1803
#define AST_DATA_ENTRY(__path, __handler)
Definition: data.h:260

Definition at line 1808 of file res_odbc.c.

Referenced by load_module().

struct odbc_tables odbc_tables = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } , }
static
struct ast_datastore_info txn_info
static
Initial value:
= {
.type = "ODBC_Transaction",
.destroy = odbc_txn_free,
}
static void odbc_txn_free(void *data)
Definition: res_odbc.c:343

Definition at line 157 of file res_odbc.c.

Referenced by ast_odbc_retrieve_transaction_obj(), find_transaction(), mark_transaction_active(), and release_transaction().