Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Enumerations | Functions | Variables
func_odbc.c File Reference

ODBC lookups. More...

#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/res_odbc.h"
#include "asterisk/res_odbc_transaction.h"
#include "asterisk/app.h"
#include "asterisk/cli.h"
#include "asterisk/strings.h"

Go to the source code of this file.

Data Structures

struct  acf_odbc_query
 
struct  dsn
 Data source name. More...
 
struct  odbc_datastore
 
struct  odbc_datastore_row
 
struct  queries
 

Macros

#define DEFAULT_SINGLE_DB_CONNECTION   0
 
#define DSN_BUCKETS   37
 

Enumerations

enum  odbc_option_flags { OPT_ESCAPECOMMAS = (1 << 0), OPT_MULTIROW = (1 << 1) }
 

Functions

static void __init_coldata_buf (void)
 
static void __init_colnames_buf (void)
 
static void __init_sql2_buf (void)
 
static void __init_sql_buf (void)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int acf_escape (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len, char character)
 
static int acf_escape_backslashes (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_escape_ticks (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_fetch (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_odbc_read (struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
 
static int acf_odbc_write (struct ast_channel *chan, const char *cmd, char *s, const char *value)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static char * cli_odbc_read (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * cli_odbc_write (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int connection_dead (struct odbc_obj *connection)
 Determine if the connection has died. More...
 
static struct dsncreate_dsn (const char *name)
 Create a DSN and connect to the database. More...
 
static int dsn_cmp (void *obj, void *arg, int flags)
 
static void dsn_destructor (void *obj)
 
static int dsn_hash (const void *obj, const int flags)
 
static int exec_odbcfinish (struct ast_channel *chan, const char *data)
 
static SQLHSTMT execute (struct odbc_obj *obj, void *data, int silent)
 Common execution function for SQL queries. More...
 
static int free_acf_query (struct acf_odbc_query *query)
 
static SQLHSTMT generic_execute (struct odbc_obj *obj, void *data)
 
static struct dsnget_dsn (const char *name)
 Retrieve a DSN, or create it if it does not exist. More...
 
static struct odbc_objget_odbc_obj (const char *dsn_name, struct dsn **dsn)
 Get a DB handle via a DSN or directly. More...
 
static int init_acf_query (struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
 
static int load_module (void)
 
static void odbc_datastore_free (void *data)
 
static void release_obj_or_dsn (struct odbc_obj **obj, struct dsn **dsn)
 Release an ODBC obj or a DSN. More...
 
static int reload (void)
 
static SQLHSTMT silent_execute (struct odbc_obj *obj, void *data)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ODBC lookups" , .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 = "da6642af068ee5e6490c5b1d2cc1d238" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .requires = "res_odbc", }
 
static char * app_odbcfinish = "ODBCFinish"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_func_odbc []
 
static struct ast_threadstorage coldata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_coldata_buf , .custom_init = NULL , }
 
static struct ast_threadstorage colnames_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_colnames_buf , .custom_init = NULL , }
 
static char * config = "func_odbc.conf"
 
struct ao2_containerdsns
 
static struct ast_custom_function escape_backslashes_function
 
static struct ast_custom_function escape_function
 
static struct ast_custom_function fetch_function
 
static const struct ast_datastore_info odbc_info
 
static struct queries queries = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static int resultcount = 0
 
static int single_db_connection
 
static ast_rwlock_t single_db_connection_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} }
 
static struct ast_threadstorage sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , }
 
static struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }
 

Detailed Description

ODBC lookups.

Author
Tilghman Lesher func_.nosp@m.odbc.nosp@m.__200.nosp@m.508@.nosp@m.the-t.nosp@m.ilgh.nosp@m.man.c.nosp@m.om

Definition in file func_odbc.c.

Function Documentation

static int acf_odbc_write ( struct ast_channel chan,
const char *  cmd,
char *  s,
const char *  value 
)
static
Note
Okay, this part is confusing. Transactions belong to a single database handle. Therefore, when working with transactions, we CANNOT failover to multiple DSNs. We MUST have a single handle all the way through the transaction, or else we CANNOT enforce atomicity.

Definition at line 526 of file func_odbc.c.

References AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_unref, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc, ast_odbc_direct_execute(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strdupa, get_odbc_obj(), pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), and release_obj_or_dsn().

527 {
528  struct odbc_obj *obj = NULL;
529  struct acf_odbc_query *query;
530  char *t, varname[15];
531  int i, dsn_num, bogus_chan = 0;
532  int transactional = 0;
534  AST_APP_ARG(field)[100];
535  );
537  AST_APP_ARG(field)[100];
538  );
539  SQLHSTMT stmt = NULL;
540  SQLLEN rows=0;
541  struct ast_str *buf = ast_str_thread_get(&sql_buf, 16);
542  struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16);
543  const char *status = "FAILURE";
544  struct dsn *dsn = NULL;
545 
546  if (!buf || !insertbuf) {
547  return -1;
548  }
549 
551  AST_RWLIST_TRAVERSE(&queries, query, list) {
552  if (!strcmp(query->acf->name, cmd)) {
553  break;
554  }
555  }
556 
557  if (!query) {
558  ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
560  if (chan) {
561  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
562  }
563  return -1;
564  }
565 
566  AST_STANDARD_APP_ARGS(args, s);
567  if (args.argc < query->minargs) {
568  ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
569  args.argc, cmd, query->minargs);
571  return -1;
572  }
573 
574  if (!chan) {
575  if (!(chan = ast_dummy_channel_alloc())) {
577  return -1;
578  }
579  bogus_chan = 1;
580  }
581 
582  if (!bogus_chan) {
583  ast_autoservice_start(chan);
584  }
585 
586  ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300);
587  /* We only get here if sql_write is set. sql_insert is optional however. */
588  if (query->sql_insert) {
589  ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300);
590  }
591 
592  /* Parse our arguments */
593  t = value ? ast_strdupa(value) : "";
594 
595  if (!s || !t) {
596  ast_log(LOG_ERROR, "Out of memory\n");
598  if (!bogus_chan) {
599  ast_autoservice_stop(chan);
600  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
601  } else {
602  ast_channel_unref(chan);
603  }
604  return -1;
605  }
606 
607  snprintf(varname, sizeof(varname), "%u", args.argc);
608  pbx_builtin_pushvar_helper(chan, "ARGC", varname);
609  for (i = 0; i < args.argc; i++) {
610  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
611  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
612  }
613 
614  /* Parse values, just like arguments */
616  for (i = 0; i < values.argc; i++) {
617  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
618  pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
619  }
620 
621  /* Additionally set the value as a whole (but push an empty string if value is NULL) */
622  pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
623 
624  ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
625  if (query->sql_insert) {
626  ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
627  }
628 
629  if (bogus_chan) {
630  chan = ast_channel_unref(chan);
631  } else {
632  /* Restore prior values */
633  pbx_builtin_setvar_helper(chan, "ARGC", NULL);
634 
635  for (i = 0; i < args.argc; i++) {
636  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
637  pbx_builtin_setvar_helper(chan, varname, NULL);
638  }
639 
640  for (i = 0; i < values.argc; i++) {
641  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
642  pbx_builtin_setvar_helper(chan, varname, NULL);
643  }
644  pbx_builtin_setvar_helper(chan, "VALUE", NULL);
645  }
646 
647  /*!\note
648  * Okay, this part is confusing. Transactions belong to a single database
649  * handle. Therefore, when working with transactions, we CANNOT failover
650  * to multiple DSNs. We MUST have a single handle all the way through the
651  * transaction, or else we CANNOT enforce atomicity.
652  */
653  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
654  if (!ast_strlen_zero(query->writehandle[dsn_num])) {
655  if (transactional) {
656  /* This can only happen second time through or greater. */
657  ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
658  }
659 
660  if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) {
661  transactional = 1;
662  } else {
663  obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
664  transactional = 0;
665  }
666 
667  if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
668  break;
669  }
670  if (!transactional) {
671  release_obj_or_dsn (&obj, &dsn);
672  }
673  }
674  }
675 
676  if (stmt) {
677  SQLRowCount(stmt, &rows);
678  SQLCloseCursor(stmt);
679  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
680 
681  if (rows != 0) {
682  status = "SUCCESS";
683 
684  } else if (query->sql_insert) {
685  if (!transactional) {
686  release_obj_or_dsn (&obj, &dsn);
687  }
688 
689  for (transactional = 0, dsn_num = 0; dsn_num < 5; dsn_num++) {
690  if (!ast_strlen_zero(query->writehandle[dsn_num])) {
691  if (transactional) {
692  /* This can only happen second time through or greater. */
693  ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
694  } else {
695  release_obj_or_dsn (&obj, &dsn);
696  }
697 
698  if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) {
699  transactional = 1;
700  } else {
701  obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
702  transactional = 0;
703  }
704  if (obj) {
705  stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf));
706  }
707  }
708  if (stmt) {
709  status = "FAILOVER";
710  SQLRowCount(stmt, &rows);
711  SQLCloseCursor(stmt);
712  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
713  break;
714  }
715  }
716  }
717  }
718 
720 
721  /* Output the affected rows, for all cases. In the event of failure, we
722  * flag this as -1 rows. Note that this is different from 0 affected rows
723  * which would be the case if we succeeded in our query, but the values did
724  * not change. */
725  if (!bogus_chan) {
726  snprintf(varname, sizeof(varname), "%d", (int)rows);
727  pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
728  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
729  }
730 
731  if (!transactional) {
732  release_obj_or_dsn (&obj, &dsn);
733  }
734 
735  if (!bogus_chan) {
736  ast_autoservice_stop(chan);
737  }
738 
739  return 0;
740 }
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
Data source name.
Definition: func_odbc.c:167
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value...
ODBC container.
Definition: res_odbc.h:46
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
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.
Definition: res_odbc.c:360
Support for dynamic strings.
Definition: strings.h:623
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...
static void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
Release an ODBC obj or a DSN.
Definition: func_odbc.c:405
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
static struct odbc_obj * get_odbc_obj(const char *dsn_name, struct dsn **dsn)
Get a DB handle via a DSN or directly.
Definition: func_odbc.c:376
#define AST_APP_ARG(name)
Define an application argument.
static int connection_dead ( struct odbc_obj connection)
static

Determine if the connection has died.

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

Definition at line 282 of file func_odbc.c.

References ast_odbc_direct_execute(), and odbc_obj::con.

Referenced by get_dsn().

283 {
284  SQLINTEGER dead;
285  SQLRETURN res;
286  SQLHSTMT stmt;
287 
288  if (!connection) {
289  return 1;
290  }
291 
292  res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0);
293  if (SQL_SUCCEEDED(res)) {
294  return dead == SQL_CD_TRUE ? 1 : 0;
295  }
296 
297  /* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a direct
298  * execute of a probing statement and see if that succeeds instead
299  */
300  stmt = ast_odbc_direct_execute(connection, silent_execute, "SELECT 1");
301  if (!stmt) {
302  return 1;
303  }
304 
305  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
306  return 0;
307 }
SQLHDBC con
Definition: res_odbc.h:47
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.
Definition: res_odbc.c:360
static struct dsn* create_dsn ( const char *  name)
static

Create a DSN and connect to the database.

Parameters
nameThe name of the DSN as found in res_odbc.conf
Return values
NULLFail
non-NULLThe newly-created structure

Definition at line 243 of file func_odbc.c.

References ao2_link_flags, ao2_ref, ast_odbc_request_obj, dsn::connection, dsn::name, and OBJ_NOLOCK.

Referenced by get_dsn().

244 {
245  struct dsn *dsn;
246 
247  if (!dsns) {
248  return NULL;
249  }
250 
251  dsn = ao2_alloc(sizeof(*dsn) + strlen(name) + 1, dsn_destructor);
252  if (!dsn) {
253  return NULL;
254  }
255 
256  /* Safe */
257  strcpy(dsn->name, name);
258 
260  if (!dsn->connection) {
261  ao2_ref(dsn, -1);
262  return NULL;
263  }
264 
265  if (!ao2_link_flags(dsns, dsn, OBJ_NOLOCK)) {
266  ao2_ref(dsn, -1);
267  return NULL;
268  }
269 
270  return dsn;
271 }
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
Definition: res_odbc.h:120
Data source name.
Definition: func_odbc.c:167
struct odbc_obj * connection
Definition: func_odbc.c:169
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
char name[0]
Definition: func_odbc.c:171
static SQLHSTMT execute ( struct odbc_obj obj,
void *  data,
int  silent 
)
static

Common execution function for SQL queries.

Parameters
objDB connection
dataThe query to execute
silentIf true, do not print warnings on failure
Return values
NULLFailed to execute query
non-NULLThe executed statement

Definition at line 471 of file func_odbc.c.

References ast_odbc_execute_sql(), and odbc_obj::con.

Referenced by load_pbx_builtins().

472 {
473  int res;
474  char *sql = data;
475  SQLHSTMT stmt;
476 
477  res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
478  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
479  ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res);
480  return NULL;
481  }
482 
483  res = ast_odbc_execute_sql(obj, stmt, sql);
484  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
485  if (res == SQL_ERROR && !silent) {
486  int i;
487  SQLINTEGER nativeerror=0, numfields=0;
488  SQLSMALLINT diagbytes=0;
489  unsigned char state[10], diagnostic[256];
490 
491  SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
492  for (i = 0; i < numfields; i++) {
493  SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
494  ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
495  if (i > 10) {
496  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
497  break;
498  }
499  }
500  }
501 
502  if (!silent) {
503  ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql);
504  }
505  SQLCloseCursor(stmt);
506  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
507  return NULL;
508  }
509 
510  return stmt;
511 }
SQLHDBC con
Definition: res_odbc.h:47
SQLRETURN ast_odbc_execute_sql(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Execute a unprepared SQL query.
Definition: res_odbc.c:469
static struct dsn* get_dsn ( const char *  name)
static

Retrieve a DSN, or create it if it does not exist.

The created DSN is returned locked. This should be inconsequential to callers in most cases.

When finished with the returned structure, the caller must call release_obj_or_dsn

Parameters
nameName of the DSN as found in res_odbc.conf
Return values
NULLUnable to retrieve or create the DSN
non-NULLThe retrieved/created locked DSN

Definition at line 322 of file func_odbc.c.

References ao2_ref, ast_odbc_release_obj(), ast_odbc_request_obj, dsn::connection, connection_dead(), create_dsn(), OBJ_NOLOCK, and OBJ_SEARCH_KEY.

Referenced by get_odbc_obj().

323 {
324  struct dsn *dsn;
325 
326  if (!dsns) {
327  return NULL;
328  }
329 
330  ao2_lock(dsns);
331  dsn = ao2_find(dsns, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
332  if (!dsn) {
333  dsn = create_dsn(name);
334  }
335  ao2_unlock(dsns);
336 
337  if (!dsn) {
338  return NULL;
339  }
340 
341  ao2_lock(dsn);
342  if (!dsn->connection) {
344  if (!dsn->connection) {
345  ao2_unlock(dsn);
346  ao2_ref(dsn, -1);
347  return NULL;
348  }
349  return dsn;
350  }
351 
352  if (connection_dead(dsn->connection)) {
355  if (!dsn->connection) {
356  ao2_unlock(dsn);
357  ao2_ref(dsn, -1);
358  return NULL;
359  }
360  }
361 
362  return dsn;
363 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
Definition: res_odbc.h:120
Data source name.
Definition: func_odbc.c:167
struct odbc_obj * connection
Definition: func_odbc.c:169
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
char name[0]
Definition: func_odbc.c:171
static int connection_dead(struct odbc_obj *connection)
Determine if the connection has died.
Definition: func_odbc.c:282
static struct dsn * create_dsn(const char *name)
Create a DSN and connect to the database.
Definition: func_odbc.c:243
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:804
static struct odbc_obj* get_odbc_obj ( const char *  dsn_name,
struct dsn **  dsn 
)
static

Get a DB handle via a DSN or directly.

If single db connection then get the DB handle via DSN else by requesting a connection directly

Parameters
dsn_nameName of the DSN as found in res_odbc.conf
dsnThe pointer to the DSN
Return values
NULLUnable to retrieve the DB handle
non-NULLThe retrieved DB handle

Definition at line 376 of file func_odbc.c.

References ast_odbc_request_obj, and get_dsn().

Referenced by acf_odbc_write().

377 {
378  struct odbc_obj *obj = NULL;
379 
380  ast_rwlock_rdlock(&single_db_connection_lock);
381  if (single_db_connection) {
382  if (dsn) {
383  *dsn = get_dsn(dsn_name);
384  if (*dsn) {
385  obj = (*dsn)->connection;
386  }
387  }
388  } else {
389  obj = ast_odbc_request_obj(dsn_name, 0);
390  }
391  ast_rwlock_unlock(&single_db_connection_lock);
392 
393  return obj;
394 }
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
Definition: res_odbc.h:120
ODBC container.
Definition: res_odbc.h:46
static struct dsn * get_dsn(const char *name)
Retrieve a DSN, or create it if it does not exist.
Definition: func_odbc.c:322
static void release_obj_or_dsn ( struct odbc_obj **  obj,
struct dsn **  dsn 
)
inlinestatic

Release an ODBC obj or a DSN.

If single db connection then unlock and unreference the DSN else release the ODBC obj

Parameters
objThe pointer to the ODBC obj to release
dsnThe pointer to the dsn to unlock and unreference

Definition at line 405 of file func_odbc.c.

References ao2_ref, ast_odbc_get_max_connections(), and ast_odbc_release_obj().

Referenced by acf_odbc_write().

406 {
407  if (dsn && *dsn) {
408  /* If multiple connections are not enabled then the guarantee
409  * of a single connection already exists and holding on to the
410  * connection would prevent any other user from acquiring it
411  * indefinitely.
412  */
413  if (ast_odbc_get_max_connections((*dsn)->name) < 2) {
414  ast_odbc_release_obj((*dsn)->connection);
415  (*dsn)->connection = NULL;
416  }
417  ao2_unlock(*dsn);
418  ao2_ref(*dsn, -1);
419  *dsn = NULL;
420  /* Some callers may provide both an obj and dsn. To ensure that
421  * the connection is not released twice we set it to NULL here if
422  * present.
423  */
424  if (obj) {
425  *obj = NULL;
426  }
427  } else if (obj && *obj) {
428  ast_odbc_release_obj(*obj);
429  *obj = NULL;
430  }
431 }
unsigned int ast_odbc_get_max_connections(const char *name)
Return the current configured maximum number of connections for a class.
Definition: res_odbc.c:848
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:804

Variable Documentation

struct ast_cli_entry cli_func_odbc[]
static
Initial value:
= {
{ .handler = cli_odbc_write , .summary = "Test setting a func_odbc function" ,},
{ .handler = cli_odbc_read , .summary = "Test reading a func_odbc function" ,},
}

Definition at line 1826 of file func_odbc.c.

struct ast_custom_function escape_backslashes_function
static
Initial value:
= {
.name = "SQL_ESC_BACKSLASHES",
.read = acf_escape_backslashes,
.write = NULL,
}

Definition at line 1154 of file func_odbc.c.

struct ast_custom_function escape_function
static
Initial value:
= {
.name = "SQL_ESC",
.read = acf_escape_ticks,
.write = NULL,
}

Definition at line 1143 of file func_odbc.c.

struct ast_custom_function fetch_function
static
Initial value:
= {
.name = "ODBC_FETCH",
.read = acf_fetch,
.write = NULL,
}

Definition at line 1198 of file func_odbc.c.

const struct ast_datastore_info odbc_info
static
Initial value:
= {
.type = "FUNC_ODBC",
.destroy = odbc_datastore_free,
}

Definition at line 146 of file func_odbc.c.