Asterisk - The Open Source Telephony Project  18.5.0
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"
Include dependency graph for func_odbc.c:

Go to the source code of this file.

Data Structures

struct  acf_odbc_query
 
struct  dsn
 
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)
 
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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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_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.

Macro Definition Documentation

◆ DEFAULT_SINGLE_DB_CONNECTION

#define DEFAULT_SINGLE_DB_CONNECTION   0

Definition at line 103 of file func_odbc.c.

Referenced by load_module(), and reload().

◆ DSN_BUCKETS

#define DSN_BUCKETS   37

Definition at line 157 of file func_odbc.c.

Referenced by load_module(), and reload().

Enumeration Type Documentation

◆ odbc_option_flags

Enumerator
OPT_ESCAPECOMMAS 
OPT_MULTIROW 

Definition at line 109 of file func_odbc.c.

109  {
110  OPT_ESCAPECOMMAS = (1 << 0),
111  OPT_MULTIROW = (1 << 1),
112 };

Function Documentation

◆ __init_coldata_buf()

static void __init_coldata_buf ( void  )
static

Definition at line 422 of file func_odbc.c.

428 {

◆ __init_colnames_buf()

static void __init_colnames_buf ( void  )
static

Definition at line 423 of file func_odbc.c.

428 {

◆ __init_sql2_buf()

static void __init_sql2_buf ( void  )
static

Definition at line 421 of file func_odbc.c.

428 {

◆ __init_sql_buf()

static void __init_sql_buf ( void  )
static

Definition at line 420 of file func_odbc.c.

428 {

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1978 of file func_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1978 of file func_odbc.c.

◆ acf_escape()

static int acf_escape ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 1105 of file func_odbc.c.

References buf, ast_datastore::data, len(), and out.

1106 {
1107  char *out = buf;
1108 
1109  for (; *data && out - buf < len; data++) {
1110  if (*data == '\'') {
1111  *out = '\'';
1112  out++;
1113  }
1114  *out++ = *data;
1115  }
1116  *out = '\0';
1117 
1118  return 0;
1119 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
FILE * out
Definition: utils/frame.c:33

◆ acf_fetch()

static int acf_fetch ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 1127 of file func_odbc.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_datastore_free(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_datastore::data, odbc_datastore_row::data, odbc_datastore_row::list, LOG_WARNING, odbc_datastore::names, and pbx_builtin_setvar_helper().

Referenced by acf_odbc_read().

1128 {
1129  struct ast_datastore *store;
1130  struct odbc_datastore *resultset;
1131  struct odbc_datastore_row *row;
1132 
1133  if (!chan) {
1134  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1135  return -1;
1136  }
1137 
1138  ast_channel_lock(chan);
1139  store = ast_channel_datastore_find(chan, &odbc_info, data);
1140  if (!store) {
1141  ast_channel_unlock(chan);
1142  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
1143  return -1;
1144  }
1145  resultset = store->data;
1146  AST_LIST_LOCK(resultset);
1147  row = AST_LIST_REMOVE_HEAD(resultset, list);
1148  AST_LIST_UNLOCK(resultset);
1149  if (!row) {
1150  /* Cleanup datastore */
1151  ast_channel_datastore_remove(chan, store);
1152  ast_datastore_free(store);
1153  ast_channel_unlock(chan);
1154  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
1155  return -1;
1156  }
1157  pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
1158  ast_channel_unlock(chan);
1159  ast_copy_string(buf, row->data, len);
1160  ast_free(row);
1161  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
1162  return 0;
1163 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct odbc_datastore_row::@212 list
Structure for a data store object.
Definition: datastore.h:68
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:2404
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_log
Definition: astobj2.c:42
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_free(a)
Definition: astmm.h:182
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...
void * data
Definition: datastore.h:70
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char names[0]
Definition: func_odbc.c:143
static const struct ast_datastore_info odbc_info
Definition: func_odbc.c:129
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399

◆ acf_odbc_read()

static int acf_odbc_read ( struct ast_channel chan,
const char *  cmd,
char *  s,
char *  buf,
size_t  len 
)
static

Definition at line 725 of file func_odbc.c.

References acf_fetch(), args, AST_APP_ARG, ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, ast_log, ast_odbc_ast_str_SQLGetData(), ast_odbc_direct_execute(), ast_realloc, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_append(), ast_str_append_escapecommas(), ast_str_buffer(), ast_str_make_space, ast_str_reset(), ast_str_strlen(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strlen_zero, ast_test_flag, ast_verb, coldata_buf, colnames_buf, ast_datastore::data, generic_execute(), get_odbc_obj(), indicator, LOG_ERROR, LOG_WARNING, NULL, odbc_datastore_free(), OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), release_obj_or_dsn(), sql_buf, status, tmp(), and ast_datastore::uid.

Referenced by init_acf_query().

726 {
727  struct odbc_obj *obj = NULL;
728  struct acf_odbc_query *query;
729  char varname[15], rowcount[12] = "-1";
730  struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
731  int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn_num, bogus_chan = 0;
733  AST_APP_ARG(field)[100];
734  );
735  SQLHSTMT stmt = NULL;
736  SQLSMALLINT colcount=0;
737  SQLLEN indicator;
738  SQLSMALLINT collength;
739  struct odbc_datastore *resultset = NULL;
740  struct odbc_datastore_row *row = NULL;
741  struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
742  const char *status = "FAILURE";
743  struct dsn *dsn = NULL;
744 
745  if (!sql || !colnames) {
746  if (chan) {
747  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
748  }
749  return -1;
750  }
751 
752  ast_str_reset(colnames);
753 
755  AST_RWLIST_TRAVERSE(&queries, query, list) {
756  if (!strcmp(query->acf->name, cmd)) {
757  break;
758  }
759  }
760 
761  if (!query) {
762  ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
764  if (chan) {
765  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
766  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
767  }
768  return -1;
769  }
770 
772  if (args.argc < query->minargs) {
773  ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
774  args.argc, cmd, query->minargs);
776  return -1;
777  }
778 
779  if (!chan) {
780  if (!(chan = ast_dummy_channel_alloc())) {
782  return -1;
783  }
784  bogus_chan = 1;
785  }
786 
787  if (!bogus_chan) {
788  ast_autoservice_start(chan);
789  }
790 
791  snprintf(varname, sizeof(varname), "%u", args.argc);
792  pbx_builtin_pushvar_helper(chan, "ARGC", varname);
793  for (x = 0; x < args.argc; x++) {
794  snprintf(varname, sizeof(varname), "ARG%d", x + 1);
795  pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
796  }
797 
798  ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
799 
800  if (bogus_chan) {
801  chan = ast_channel_unref(chan);
802  } else {
803  /* Restore prior values */
804  pbx_builtin_setvar_helper(chan, "ARGC", NULL);
805 
806  for (x = 0; x < args.argc; x++) {
807  snprintf(varname, sizeof(varname), "ARG%d", x + 1);
808  pbx_builtin_setvar_helper(chan, varname, NULL);
809  }
810  }
811 
812  /* Save these flags, so we can release the lock */
813  escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
814  if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) {
815  if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
816  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
817  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
819  ast_autoservice_stop(chan);
820  return -1;
821  }
822  AST_LIST_HEAD_INIT(resultset);
823  if (query->rowlimit) {
824  rowlimit = query->rowlimit;
825  } else {
826  rowlimit = INT_MAX;
827  }
828  multirow = 1;
829  } else if (!bogus_chan) {
830  if (query->rowlimit > 1) {
831  rowlimit = query->rowlimit;
832  if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
833  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
834  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
836  ast_autoservice_stop(chan);
837  return -1;
838  }
839  AST_LIST_HEAD_INIT(resultset);
840  }
841  }
843 
844  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
845  if (!ast_strlen_zero(query->readhandle[dsn_num])) {
846  obj = get_odbc_obj(query->readhandle[dsn_num], &dsn);
847  if (!obj) {
848  continue;
849  }
851  }
852  if (stmt) {
853  break;
854  }
855  release_obj_or_dsn (&obj, &dsn);
856  }
857 
858  if (!stmt) {
859  ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
860  release_obj_or_dsn (&obj, &dsn);
861  if (!bogus_chan) {
862  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
863  ast_autoservice_stop(chan);
864  }
865  odbc_datastore_free(resultset);
866  return -1;
867  }
868 
869  res = SQLNumResultCols(stmt, &colcount);
870  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
871  ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
872  SQLCloseCursor(stmt);
873  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
874  release_obj_or_dsn (&obj, &dsn);
875  if (!bogus_chan) {
876  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
877  ast_autoservice_stop(chan);
878  }
879  odbc_datastore_free(resultset);
880  return -1;
881  }
882 
883  if (colcount <= 0) {
884  ast_verb(4, "Returned %d columns [%s]\n", colcount, ast_str_buffer(sql));
885  buf[0] = '\0';
886  SQLCloseCursor(stmt);
887  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
888  release_obj_or_dsn (&obj, &dsn);
889  if (!bogus_chan) {
890  pbx_builtin_setvar_helper(chan, "ODBCROWS", "0");
891  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "NODATA");
892  ast_autoservice_stop(chan);
893  }
894  odbc_datastore_free(resultset);
895  return 0;
896  }
897 
898  res = SQLFetch(stmt);
899  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
900  int res1 = -1;
901  if (res == SQL_NO_DATA) {
902  ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
903  res1 = 0;
904  buf[0] = '\0';
905  ast_copy_string(rowcount, "0", sizeof(rowcount));
906  status = "NODATA";
907  } else {
908  ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
909  status = "FETCHERROR";
910  }
911  SQLCloseCursor(stmt);
912  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
913  release_obj_or_dsn (&obj, &dsn);
914  if (!bogus_chan) {
915  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
916  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
917  ast_autoservice_stop(chan);
918  }
919  odbc_datastore_free(resultset);
920  return res1;
921  }
922 
923  status = "SUCCESS";
924 
925  for (y = 0; y < rowlimit; y++) {
926  buf[0] = '\0';
927  for (x = 0; x < colcount; x++) {
928  int i;
929  struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
930  char *ptrcoldata;
931 
932  if (!coldata) {
933  odbc_datastore_free(resultset);
934  SQLCloseCursor(stmt);
935  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
936  release_obj_or_dsn (&obj, &dsn);
937  if (!bogus_chan) {
938  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
939  ast_autoservice_stop(chan);
940  }
941  return -1;
942  }
943 
944  if (y == 0) {
945  char colname[256];
946  SQLLEN octetlength = 0;
947 
948  res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL);
949  ast_debug(3, "Got collength of %d for column '%s' (offset %d)\n", (int)collength, colname, x);
950  if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
951  snprintf(colname, sizeof(colname), "field%d", x);
952  }
953 
954  SQLColAttribute(stmt, x + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &octetlength);
955 
956  ast_str_make_space(&coldata, octetlength + 1);
957 
958  if (ast_str_strlen(colnames)) {
959  ast_str_append(&colnames, 0, ",");
960  }
961  ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
962 
963  if (resultset) {
964  void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
965  if (!tmp) {
966  ast_log(LOG_ERROR, "No space for a new resultset?\n");
967  odbc_datastore_free(resultset);
968  SQLCloseCursor(stmt);
969  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
970  release_obj_or_dsn (&obj, &dsn);
971  if (!bogus_chan) {
972  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
973  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
974  ast_autoservice_stop(chan);
975  }
976  return -1;
977  }
978  resultset = tmp;
979  strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
980  }
981  }
982 
983  buflen = strlen(buf);
984  res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
985  if (indicator == SQL_NULL_DATA) {
986  ast_debug(3, "Got NULL data\n");
987  ast_str_reset(coldata);
988  res = SQL_SUCCESS;
989  }
990 
991  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
992  ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
993  y = -1;
994  buf[0] = '\0';
995  goto end_acf_read;
996  }
997 
998  ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
999 
1000  if (x) {
1001  buf[buflen++] = ',';
1002  }
1003 
1004  /* Copy data, encoding '\' and ',' for the argument parser */
1005  ptrcoldata = ast_str_buffer(coldata);
1006  for (i = 0; i < ast_str_strlen(coldata); i++) {
1007  if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
1008  buf[buflen++] = '\\';
1009  }
1010  buf[buflen++] = ptrcoldata[i];
1011 
1012  if (buflen >= len - 2) {
1013  break;
1014  }
1015 
1016  if (ptrcoldata[i] == '\0') {
1017  break;
1018  }
1019  }
1020 
1021  buf[buflen] = '\0';
1022  ast_debug(2, "buf is now set to '%s'\n", buf);
1023  }
1024  ast_debug(2, "buf is now set to '%s'\n", buf);
1025 
1026  if (resultset) {
1027  row = ast_calloc(1, sizeof(*row) + buflen + 1);
1028  if (!row) {
1029  ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
1030  status = "MEMERROR";
1031  goto end_acf_read;
1032  }
1033  strcpy((char *)row + sizeof(*row), buf);
1034  AST_LIST_INSERT_TAIL(resultset, row, list);
1035 
1036  /* Get next row */
1037  res = SQLFetch(stmt);
1038  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1039  if (res != SQL_NO_DATA) {
1040  ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1041  }
1042  /* Number of rows in the resultset */
1043  y++;
1044  break;
1045  }
1046  }
1047  }
1048 
1049 end_acf_read:
1050  if (!bogus_chan) {
1051  snprintf(rowcount, sizeof(rowcount), "%d", y);
1052  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
1053  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
1054  pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
1055  if (resultset) {
1056  struct ast_datastore *odbc_store;
1057  if (multirow) {
1058  int uid;
1059  uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
1060  snprintf(buf, len, "%d", uid);
1061  } else {
1062  /* Name of the query is name of the resultset */
1063  ast_copy_string(buf, cmd, len);
1064 
1065  /* If there's one with the same name already, free it */
1066  ast_channel_lock(chan);
1067  if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) {
1068  ast_channel_datastore_remove(chan, odbc_store);
1069  ast_datastore_free(odbc_store);
1070  }
1071  ast_channel_unlock(chan);
1072  }
1073  odbc_store = ast_datastore_alloc(&odbc_info, buf);
1074  if (!odbc_store) {
1075  ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n");
1076  odbc_datastore_free(resultset);
1077  SQLCloseCursor(stmt);
1078  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1079  release_obj_or_dsn (&obj, &dsn);
1080  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
1081  ast_autoservice_stop(chan);
1082  return -1;
1083  }
1084  odbc_store->data = resultset;
1085  ast_channel_lock(chan);
1086  ast_channel_datastore_add(chan, odbc_store);
1087  ast_channel_unlock(chan);
1088  }
1089  }
1090  SQLCloseCursor(stmt);
1091  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1092  release_obj_or_dsn (&obj, &dsn);
1093  if (resultset && !multirow) {
1094  /* Fetch the first resultset */
1095  if (!acf_fetch(chan, "", buf, buf, len)) {
1096  buf[0] = '\0';
1097  }
1098  }
1099  if (!bogus_chan) {
1100  ast_autoservice_stop(chan);
1101  }
1102  return 0;
1103 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define ast_realloc(p, len)
A wrapper for realloc()
Definition: astmm.h:228
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:2981
#define ast_test_flag(p, flag)
Definition: utils.h:63
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static int indicator
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static int tmp()
Definition: bt_open.c:389
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static struct ast_threadstorage sql_buf
Definition: func_odbc.c:420
Definition: func_odbc.c:150
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
char * ast_str_append_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string, with escaping of commas...
Definition: strings.h:1028
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
Structure for a data store object.
Definition: datastore.h:68
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:2404
const char * args
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...
#define NULL
Definition: resample.c:96
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:496
#define ast_verb(level,...)
Definition: logger.h:463
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
const char * uid
Definition: datastore.h:69
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
ODBC container.
Definition: res_odbc.h:46
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
static int resultcount
Definition: func_odbc.c:418
static struct ast_threadstorage coldata_buf
Definition: func_odbc.c:422
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1127
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:369
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static void odbc_datastore_free(void *data)
Definition: func_odbc.c:427
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:625
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
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...
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:653
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
void * data
Definition: datastore.h:70
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
Release an ODBC obj or a DSN.
Definition: func_odbc.c:388
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.
Definition: res_odbc.c:507
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:861
static struct ast_threadstorage colnames_buf
Definition: func_odbc.c:423
static const struct ast_datastore_info odbc_info
Definition: func_odbc.c:129
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399
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:359
jack_status_t status
Definition: app_jack.c:146
#define AST_APP_ARG(name)
Define an application argument.

◆ acf_odbc_write()

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 509 of file func_odbc.c.

References args, AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_unref, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc, ast_log, ast_odbc_direct_execute(), ast_odbc_retrieve_transaction_obj(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_make_space, ast_str_substitute_variables(), ast_str_thread_get(), ast_strdupa, ast_strlen_zero, buf, generic_execute(), get_odbc_obj(), LOG_ERROR, LOG_WARNING, NULL, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), release_obj_or_dsn(), sql2_buf, sql_buf, and status.

Referenced by init_acf_query().

510 {
511  struct odbc_obj *obj = NULL;
512  struct acf_odbc_query *query;
513  char *t, varname[15];
514  int i, dsn_num, bogus_chan = 0;
515  int transactional = 0;
517  AST_APP_ARG(field)[100];
518  );
520  AST_APP_ARG(field)[100];
521  );
522  SQLHSTMT stmt = NULL;
523  SQLLEN rows=0;
524  struct ast_str *buf = ast_str_thread_get(&sql_buf, 16);
525  struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16);
526  const char *status = "FAILURE";
527  struct dsn *dsn = NULL;
528 
529  if (!buf || !insertbuf) {
530  return -1;
531  }
532 
534  AST_RWLIST_TRAVERSE(&queries, query, list) {
535  if (!strcmp(query->acf->name, cmd)) {
536  break;
537  }
538  }
539 
540  if (!query) {
541  ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
543  if (chan) {
544  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
545  }
546  return -1;
547  }
548 
550  if (args.argc < query->minargs) {
551  ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
552  args.argc, cmd, query->minargs);
554  return -1;
555  }
556 
557  if (!chan) {
558  if (!(chan = ast_dummy_channel_alloc())) {
560  return -1;
561  }
562  bogus_chan = 1;
563  }
564 
565  if (!bogus_chan) {
566  ast_autoservice_start(chan);
567  }
568 
569  ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300);
570  /* We only get here if sql_write is set. sql_insert is optional however. */
571  if (query->sql_insert) {
572  ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300);
573  }
574 
575  /* Parse our arguments */
576  t = value ? ast_strdupa(value) : "";
577 
578  if (!s || !t) {
579  ast_log(LOG_ERROR, "Out of memory\n");
581  if (!bogus_chan) {
582  ast_autoservice_stop(chan);
583  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
584  } else {
585  ast_channel_unref(chan);
586  }
587  return -1;
588  }
589 
590  snprintf(varname, sizeof(varname), "%u", args.argc);
591  pbx_builtin_pushvar_helper(chan, "ARGC", varname);
592  for (i = 0; i < args.argc; i++) {
593  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
594  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
595  }
596 
597  /* Parse values, just like arguments */
599  for (i = 0; i < values.argc; i++) {
600  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
601  pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
602  }
603 
604  /* Additionally set the value as a whole (but push an empty string if value is NULL) */
605  pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
606 
607  ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
608  if (query->sql_insert) {
609  ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
610  }
611 
612  if (bogus_chan) {
613  chan = ast_channel_unref(chan);
614  } else {
615  /* Restore prior values */
616  pbx_builtin_setvar_helper(chan, "ARGC", NULL);
617 
618  for (i = 0; i < args.argc; i++) {
619  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
620  pbx_builtin_setvar_helper(chan, varname, NULL);
621  }
622 
623  for (i = 0; i < values.argc; i++) {
624  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
625  pbx_builtin_setvar_helper(chan, varname, NULL);
626  }
627  pbx_builtin_setvar_helper(chan, "VALUE", NULL);
628  }
629 
630  /*!\note
631  * Okay, this part is confusing. Transactions belong to a single database
632  * handle. Therefore, when working with transactions, we CANNOT failover
633  * to multiple DSNs. We MUST have a single handle all the way through the
634  * transaction, or else we CANNOT enforce atomicity.
635  */
636  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
637  if (!ast_strlen_zero(query->writehandle[dsn_num])) {
638  if (transactional) {
639  /* This can only happen second time through or greater. */
640  ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
641  }
642 
643  if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) {
644  transactional = 1;
645  } else {
646  obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
647  transactional = 0;
648  }
649 
650  if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
651  break;
652  }
653  if (!transactional) {
654  release_obj_or_dsn (&obj, &dsn);
655  }
656  }
657  }
658 
659  if (stmt) {
660  SQLRowCount(stmt, &rows);
661  SQLCloseCursor(stmt);
662  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
663 
664  if (rows != 0) {
665  status = "SUCCESS";
666 
667  } else if (query->sql_insert) {
668  if (!transactional) {
669  release_obj_or_dsn (&obj, &dsn);
670  }
671 
672  for (transactional = 0, dsn_num = 0; dsn_num < 5; dsn_num++) {
673  if (!ast_strlen_zero(query->writehandle[dsn_num])) {
674  if (transactional) {
675  /* This can only happen second time through or greater. */
676  ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
677  } else {
678  release_obj_or_dsn (&obj, &dsn);
679  }
680 
681  if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) {
682  transactional = 1;
683  } else {
684  obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
685  transactional = 0;
686  }
687  if (obj) {
688  stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf));
689  }
690  }
691  if (stmt) {
692  status = "FAILOVER";
693  SQLRowCount(stmt, &rows);
694  SQLCloseCursor(stmt);
695  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
696  break;
697  }
698  }
699  }
700  }
701 
703 
704  /* Output the affected rows, for all cases. In the event of failure, we
705  * flag this as -1 rows. Note that this is different from 0 affected rows
706  * which would be the case if we succeeded in our query, but the values did
707  * not change. */
708  if (!bogus_chan) {
709  snprintf(varname, sizeof(varname), "%d", (int)rows);
710  pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
711  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
712  }
713 
714  if (!transactional) {
715  release_obj_or_dsn (&obj, &dsn);
716  }
717 
718  if (!bogus_chan) {
719  ast_autoservice_stop(chan);
720  }
721 
722  return 0;
723 }
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:2981
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static struct ast_threadstorage sql_buf
Definition: func_odbc.c:420
Definition: func_odbc.c:150
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
const char * args
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...
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:496
struct odbc_obj * ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname)
Retrieve an ODBC transaction connection with the given ODBC class name.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_log
Definition: astobj2.c:42
ODBC container.
Definition: res_odbc.h:46
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
#define LOG_ERROR
Definition: logger.h:285
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:369
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static struct ast_threadstorage sql2_buf
Definition: func_odbc.c:421
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:388
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:861
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;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:359
jack_status_t status
Definition: app_jack.c:146
#define AST_APP_ARG(name)
Define an application argument.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1978 of file func_odbc.c.

◆ cli_odbc_read()

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

Definition at line 1430 of file func_odbc.c.

References ast_cli_args::argc, args, ast_cli_args::argv, AST_APP_ARG, ast_channel_unref, ast_cli(), ast_cli_complete(), ast_debug, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc, ast_odbc_ast_str_SQLGetData(), ast_odbc_direct_execute(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_make_space, ast_str_set(), ast_str_substitute_variables(), ast_str_thread_get(), ast_strdup, ast_strdupa, ast_strlen_zero, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, coldata_buf, ast_cli_entry::command, ast_cli_args::fd, generic_execute(), get_odbc_obj(), indicator, ast_cli_args::n, NULL, pbx_builtin_pushvar_helper(), ast_cli_args::pos, release_obj_or_dsn(), sql_buf, ast_cli_entry::usage, and ast_cli_args::word.

1431 {
1433  AST_APP_ARG(field)[100];
1434  );
1435  struct ast_str *sql;
1436  char *char_args, varname[15];
1437  struct acf_odbc_query *query;
1438  struct ast_channel *chan;
1439  int i;
1440 
1441  switch (cmd) {
1442  case CLI_INIT:
1443  e->command = "odbc read";
1444  e->usage =
1445  "Usage: odbc read <name> <args> [exec]\n"
1446  " Evaluates the SQL provided in the ODBC function <name>, and\n"
1447  " optionally executes the function. This function is intended for\n"
1448  " testing purposes. Remember to quote arguments containing spaces.\n";
1449  return NULL;
1450  case CLI_GENERATE:
1451  if (a->pos == 2) {
1452  int wordlen = strlen(a->word), which = 0;
1453  /* Complete function name */
1455  AST_RWLIST_TRAVERSE(&queries, query, list) {
1456  if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1457  if (++which > a->n) {
1458  char *res = ast_strdup(query->acf->name);
1460  return res;
1461  }
1462  }
1463  }
1465  return NULL;
1466  } else if (a->pos == 4) {
1467  static const char * const completions[] = { "exec", NULL };
1468  return ast_cli_complete(a->word, completions, a->n);
1469  } else {
1470  return NULL;
1471  }
1472  }
1473 
1474  if (a->argc < 4 || a->argc > 5) {
1475  return CLI_SHOWUSAGE;
1476  }
1477 
1478  sql = ast_str_thread_get(&sql_buf, 16);
1479  if (!sql) {
1480  return CLI_FAILURE;
1481  }
1482 
1484  AST_RWLIST_TRAVERSE(&queries, query, list) {
1485  if (!strcmp(query->acf->name, a->argv[2])) {
1486  break;
1487  }
1488  }
1489 
1490  if (!query) {
1491  ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1493  return CLI_SHOWUSAGE;
1494  }
1495 
1496  if (!query->sql_read) {
1497  ast_cli(a->fd, "The function %s has no readsql parameter.\n", a->argv[2]);
1499  return CLI_SUCCESS;
1500  }
1501 
1502  ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
1503 
1504  /* Evaluate function */
1505  char_args = ast_strdupa(a->argv[3]);
1506 
1507  chan = ast_dummy_channel_alloc();
1508  if (!chan) {
1510  return CLI_FAILURE;
1511  }
1512 
1513  AST_STANDARD_APP_ARGS(args, char_args);
1514  for (i = 0; i < args.argc; i++) {
1515  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1516  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1517  }
1518 
1519  ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
1520  chan = ast_channel_unref(chan);
1521 
1522  if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
1523  /* Execute the query */
1524  struct odbc_obj *obj = NULL;
1525  struct dsn *dsn = NULL;
1526  int dsn_num, executed = 0;
1527  SQLHSTMT stmt;
1528  int rows = 0, res, x;
1529  SQLSMALLINT colcount = 0, collength;
1530  SQLLEN indicator, octetlength;
1531  struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
1532  char colname[256];
1533 
1534  if (!coldata) {
1536  return CLI_SUCCESS;
1537  }
1538 
1539  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
1540  if (ast_strlen_zero(query->readhandle[dsn_num])) {
1541  continue;
1542  }
1543  obj = get_odbc_obj(query->readhandle[dsn_num], &dsn);
1544  if (!obj) {
1545  continue;
1546  }
1547  ast_debug(1, "Found handle %s\n", query->readhandle[dsn_num]);
1548 
1549  if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
1550  release_obj_or_dsn (&obj, &dsn);
1551  continue;
1552  }
1553 
1554  executed = 1;
1555 
1556  res = SQLNumResultCols(stmt, &colcount);
1557  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1558  ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
1559  SQLCloseCursor(stmt);
1560  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1561  release_obj_or_dsn (&obj, &dsn);
1563  return CLI_SUCCESS;
1564  }
1565 
1566  if (colcount <= 0) {
1567  SQLCloseCursor(stmt);
1568  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1569  release_obj_or_dsn (&obj, &dsn);
1570  ast_cli(a->fd, "Returned %d columns. Query executed on handle %d:%s [%s]\n", colcount, dsn_num, query->readhandle[dsn_num], ast_str_buffer(sql));
1572  return CLI_SUCCESS;
1573  }
1574 
1575  res = SQLFetch(stmt);
1576  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1577  SQLCloseCursor(stmt);
1578  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1579  release_obj_or_dsn (&obj, &dsn);
1580  if (res == SQL_NO_DATA) {
1581  ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn_num, query->readhandle[dsn_num], ast_str_buffer(sql));
1582  break;
1583  } else {
1584  ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1585  }
1587  return CLI_SUCCESS;
1588  }
1589  for (;;) {
1590  for (x = 0; x < colcount; x++) {
1591  res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL);
1592  if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
1593  snprintf(colname, sizeof(colname), "field%d", x);
1594  }
1595 
1596  octetlength = 0;
1597  SQLColAttribute(stmt, x + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &octetlength);
1598 
1599  res = ast_odbc_ast_str_SQLGetData(&coldata, octetlength + 1, stmt, x + 1, SQL_CHAR, &indicator);
1600  if (indicator == SQL_NULL_DATA) {
1601  ast_str_set(&coldata, 0, "(nil)");
1602  res = SQL_SUCCESS;
1603  }
1604 
1605  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1606  ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
1607  SQLCloseCursor(stmt);
1608  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1609  release_obj_or_dsn (&obj, &dsn);
1611  return CLI_SUCCESS;
1612  }
1613 
1614  ast_cli(a->fd, "%-20.20s %s\n", colname, ast_str_buffer(coldata));
1615  }
1616  rows++;
1617 
1618  /* Get next row */
1619  res = SQLFetch(stmt);
1620  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1621  break;
1622  }
1623  ast_cli(a->fd, "%-20.20s %s\n", "----------", "----------");
1624  }
1625  SQLCloseCursor(stmt);
1626  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1627  release_obj_or_dsn (&obj, &dsn);
1628  ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn_num, query->readhandle[dsn_num]);
1629  break;
1630  }
1631  release_obj_or_dsn (&obj, &dsn);
1632 
1633  if (!executed) {
1634  ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
1635  }
1636  } else { /* No execution, just print out the resulting SQL */
1637  ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1638  }
1640  return CLI_SUCCESS;
1641 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
const int argc
Definition: cli.h:160
static int indicator
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static struct ast_threadstorage sql_buf
Definition: func_odbc.c:420
Definition: func_odbc.c:150
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: cli.h:152
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * args
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...
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:496
#define ast_strlen_zero(foo)
Definition: strings.h:52
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition: main/cli.c:1811
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
ODBC container.
Definition: res_odbc.h:46
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static struct ast_threadstorage coldata_buf
Definition: func_odbc.c:422
const char *const * argv
Definition: cli.h:161
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:369
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
static void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
Release an ODBC obj or a DSN.
Definition: func_odbc.c:388
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.
Definition: res_odbc.c:507
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:861
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;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:359
#define AST_APP_ARG(name)
Define an application argument.

◆ cli_odbc_write()

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

Definition at line 1643 of file func_odbc.c.

References ast_cli_args::argc, args, ast_cli_args::argv, AST_APP_ARG, ast_channel_unref, ast_cli(), ast_cli_complete(), ast_debug, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc, ast_odbc_direct_execute(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_make_space, ast_str_substitute_variables(), ast_str_thread_get(), ast_strdup, ast_strdupa, ast_strlen_zero, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, generic_execute(), get_odbc_obj(), ast_cli_args::n, NULL, pbx_builtin_pushvar_helper(), ast_cli_args::pos, release_obj_or_dsn(), S_OR, sql_buf, ast_cli_entry::usage, and ast_cli_args::word.

1644 {
1646  AST_APP_ARG(field)[100];
1647  );
1649  AST_APP_ARG(field)[100];
1650  );
1651  struct ast_str *sql;
1652  char *char_args, *char_values, varname[15];
1653  struct acf_odbc_query *query;
1654  struct ast_channel *chan;
1655  int i;
1656 
1657  switch (cmd) {
1658  case CLI_INIT:
1659  e->command = "odbc write";
1660  e->usage =
1661  "Usage: odbc write <name> <args> <value> [exec]\n"
1662  " Evaluates the SQL provided in the ODBC function <name>, and\n"
1663  " optionally executes the function. This function is intended for\n"
1664  " testing purposes. Remember to quote arguments containing spaces.\n";
1665  return NULL;
1666  case CLI_GENERATE:
1667  if (a->pos == 2) {
1668  int wordlen = strlen(a->word), which = 0;
1669  /* Complete function name */
1671  AST_RWLIST_TRAVERSE(&queries, query, list) {
1672  if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1673  if (++which > a->n) {
1674  char *res = ast_strdup(query->acf->name);
1676  return res;
1677  }
1678  }
1679  }
1681  return NULL;
1682  } else if (a->pos == 5) {
1683  static const char * const completions[] = { "exec", NULL };
1684  return ast_cli_complete(a->word, completions, a->n);
1685  } else {
1686  return NULL;
1687  }
1688  }
1689 
1690  if (a->argc < 5 || a->argc > 6) {
1691  return CLI_SHOWUSAGE;
1692  }
1693 
1694  sql = ast_str_thread_get(&sql_buf, 16);
1695  if (!sql) {
1696  return CLI_FAILURE;
1697  }
1698 
1700  AST_RWLIST_TRAVERSE(&queries, query, list) {
1701  if (!strcmp(query->acf->name, a->argv[2])) {
1702  break;
1703  }
1704  }
1705 
1706  if (!query) {
1707  ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1709  return CLI_SHOWUSAGE;
1710  }
1711 
1712  if (!query->sql_write) {
1713  ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
1715  return CLI_SUCCESS;
1716  }
1717 
1718  /* FIXME: The code below duplicates code found in acf_odbc_write but
1719  * lacks the newer sql_insert additions. */
1720 
1721  ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300);
1722 
1723  /* Evaluate function */
1724  char_args = ast_strdupa(a->argv[3]);
1725  char_values = ast_strdupa(a->argv[4]);
1726 
1727  chan = ast_dummy_channel_alloc();
1728  if (!chan) {
1730  return CLI_FAILURE;
1731  }
1732 
1733  AST_STANDARD_APP_ARGS(args, char_args);
1734  for (i = 0; i < args.argc; i++) {
1735  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1736  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1737  }
1738 
1739  /* Parse values, just like arguments */
1740  AST_STANDARD_APP_ARGS(values, char_values);
1741  for (i = 0; i < values.argc; i++) {
1742  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
1743  pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
1744  }
1745 
1746  /* Additionally set the value as a whole (but push an empty string if value is NULL) */
1747  pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
1748  ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
1749  ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
1750 
1751  chan = ast_channel_unref(chan);
1752 
1753  if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
1754  /* Execute the query */
1755  struct odbc_obj *obj = NULL;
1756  struct dsn *dsn = NULL;
1757  int dsn_num, executed = 0;
1758  SQLHSTMT stmt;
1759  SQLLEN rows = -1;
1760 
1761  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
1762  if (ast_strlen_zero(query->writehandle[dsn_num])) {
1763  continue;
1764  }
1765  obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
1766  if (!obj) {
1767  continue;
1768  }
1769  if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
1770  release_obj_or_dsn (&obj, &dsn);
1771  continue;
1772  }
1773 
1774  SQLRowCount(stmt, &rows);
1775  SQLCloseCursor(stmt);
1776  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1777  release_obj_or_dsn (&obj, &dsn);
1778  ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn_num, query->writehandle[dsn_num]);
1779  executed = 1;
1780  break;
1781  }
1782 
1783  if (!executed) {
1784  ast_cli(a->fd, "Failed to execute query.\n");
1785  }
1786  } else { /* No execution, just print out the resulting SQL */
1787  ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1788  }
1790  return CLI_SUCCESS;
1791 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
const int argc
Definition: cli.h:160
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static struct ast_threadstorage sql_buf
Definition: func_odbc.c:420
Definition: func_odbc.c:150
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: cli.h:152
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * args
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...
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:496
#define ast_strlen_zero(foo)
Definition: strings.h:52
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition: main/cli.c:1811
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
ODBC container.
Definition: res_odbc.h:46
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char *const * argv
Definition: cli.h:161
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:369
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const int pos
Definition: cli.h:164
static void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
Release an ODBC obj or a DSN.
Definition: func_odbc.c:388
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:861
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;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:359
#define AST_APP_ARG(name)
Define an application argument.

◆ connection_dead()

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 265 of file func_odbc.c.

References ast_odbc_direct_execute(), and odbc_obj::con.

Referenced by get_dsn().

266 {
267  SQLINTEGER dead;
268  SQLRETURN res;
269  SQLHSTMT stmt;
270 
271  if (!connection) {
272  return 1;
273  }
274 
275  res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0);
276  if (SQL_SUCCEEDED(res)) {
277  return dead == SQL_CD_TRUE ? 1 : 0;
278  }
279 
280  /* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a direct
281  * execute of a probing statement and see if that succeeds instead
282  */
283  stmt = ast_odbc_direct_execute(connection, silent_execute, "SELECT 1");
284  if (!stmt) {
285  return 1;
286  }
287 
288  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
289  return 0;
290 }
SQLHDBC con
Definition: res_odbc.h:47
static SQLHSTMT silent_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:501
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:369

◆ create_dsn()

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 226 of file func_odbc.c.

References ao2_alloc, ao2_link_flags, ao2_ref, ast_odbc_request_obj, dsn::connection, dsn, dsn_destructor(), dsn::name, NULL, OBJ_NOLOCK, and silent_execute().

Referenced by get_dsn().

227 {
228  struct dsn *dsn;
229 
230  if (!dsns) {
231  return NULL;
232  }
233 
234  dsn = ao2_alloc(sizeof(*dsn) + strlen(name) + 1, dsn_destructor);
235  if (!dsn) {
236  return NULL;
237  }
238 
239  /* Safe */
240  strcpy(dsn->name, name);
241 
243  if (!dsn->connection) {
244  ao2_ref(dsn, -1);
245  return NULL;
246  }
247 
248  if (!ao2_link_flags(dsns, dsn, OBJ_NOLOCK)) {
249  ao2_ref(dsn, -1);
250  return NULL;
251  }
252 
253  return dsn;
254 }
Definition: func_odbc.c:150
struct odbc_obj * connection
Definition: func_odbc.c:152
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_link_flags(container, obj, flags)
Definition: astobj2.h:1572
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static void dsn_destructor(void *obj)
Definition: func_odbc.c:210
char name[0]
Definition: func_odbc.c:154
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static const char name[]
Definition: cdr_mysql.c:74
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:122
static char * dsn
Definition: cdr_odbc.c:58
struct ao2_container * dsns
Definition: func_odbc.c:159

◆ dsn_cmp()

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

Definition at line 181 of file func_odbc.c.

References CMP_MATCH, dsn::name, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_SEARCH_PARTIAL_KEY.

Referenced by load_module(), and reload().

182 {
183  const struct dsn *object_left = obj;
184  const struct dsn *object_right = arg;
185  const char *right_key = arg;
186  int cmp;
187 
188  switch (flags & OBJ_SEARCH_MASK) {
189  case OBJ_SEARCH_OBJECT:
190  right_key = object_right->name;
191  /* Fall through */
192  case OBJ_SEARCH_KEY:
193  cmp = strcmp(object_left->name, right_key);
194  break;
196  cmp = strncmp(object_left->name, right_key, strlen(right_key));
197  break;
198  default:
199  cmp = 0;
200  break;
201  }
202 
203  if (cmp) {
204  return 0;
205  }
206 
207  return CMP_MATCH;
208 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
Definition: func_odbc.c:150
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
char name[0]
Definition: func_odbc.c:154
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Search option field mask.
Definition: astobj2.h:1076

◆ dsn_destructor()

static void dsn_destructor ( void *  obj)
static

Definition at line 210 of file func_odbc.c.

References ast_odbc_release_obj(), and dsn::connection.

Referenced by create_dsn().

211 {
212  struct dsn *dsn = obj;
213 
214  if (dsn->connection) {
216  }
217 }
Definition: func_odbc.c:150
struct odbc_obj * connection
Definition: func_odbc.c:152
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:813

◆ dsn_hash()

static int dsn_hash ( const void *  obj,
const int  flags 
)
static

Definition at line 161 of file func_odbc.c.

References ast_assert, ast_str_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, and OBJ_SEARCH_OBJECT.

Referenced by load_module(), and reload().

162 {
163  const struct dsn *object;
164  const char *key;
165 
166  switch (flags & OBJ_SEARCH_MASK) {
167  case OBJ_SEARCH_KEY:
168  key = obj;
169  break;
170  case OBJ_SEARCH_OBJECT:
171  object = obj;
172  key = object->name;
173  break;
174  default:
175  ast_assert(0);
176  return 0;
177  }
178  return ast_str_hash(key);
179 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
Definition: func_odbc.c:150
#define ast_assert(a)
Definition: utils.h:695
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Search option field mask.
Definition: astobj2.h:1076
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206

◆ exec_odbcfinish()

static int exec_odbcfinish ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 1173 of file func_odbc.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, and ast_datastore_free().

Referenced by load_module().

1174 {
1175  struct ast_datastore *store;
1176 
1177  ast_channel_lock(chan);
1178  store = ast_channel_datastore_find(chan, &odbc_info, data);
1179  if (store) {
1180  ast_channel_datastore_remove(chan, store);
1181  ast_datastore_free(store);
1182  }
1183  ast_channel_unlock(chan);
1184  return 0;
1185 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
Structure for a data store object.
Definition: datastore.h:68
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:2404
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70
static const struct ast_datastore_info odbc_info
Definition: func_odbc.c:129
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399

◆ execute()

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 454 of file func_odbc.c.

References ast_log, ast_odbc_execute_sql(), odbc_obj::con, odbc_datastore_row::data, LOG_WARNING, and NULL.

Referenced by ast_monitor_stop(), generic_execute(), silent_execute(), and test_execute_multiple().

455 {
456  int res;
457  char *sql = data;
458  SQLHSTMT stmt;
459 
460  res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
461  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
462  ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res);
463  return NULL;
464  }
465 
466  res = ast_odbc_execute_sql(obj, stmt, sql);
467  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
468  if (res == SQL_ERROR && !silent) {
469  int i;
470  SQLINTEGER nativeerror=0, numfields=0;
471  SQLSMALLINT diagbytes=0;
472  unsigned char state[10], diagnostic[256];
473 
474  SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
475  for (i = 0; i < numfields; i++) {
476  SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
477  ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
478  if (i > 10) {
479  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
480  break;
481  }
482  }
483  }
484 
485  if (!silent) {
486  ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql);
487  }
488  SQLCloseCursor(stmt);
489  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
490  return NULL;
491  }
492 
493  return stmt;
494 }
SQLHDBC con
Definition: res_odbc.h:47
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
SQLRETURN ast_odbc_execute_sql(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Execute a nonprepared SQL query.
Definition: res_odbc.c:478
void * data
Definition: datastore.h:70

◆ free_acf_query()

static int free_acf_query ( struct acf_odbc_query query)
static

Definition at line 1187 of file func_odbc.c.

References ast_free, and ast_string_field_free_memory.

Referenced by init_acf_query(), reload(), and unload_module().

1188 {
1189  if (query) {
1190  if (query->acf) {
1191  if (query->acf->name)
1192  ast_free((char *)query->acf->name);
1193  ast_string_field_free_memory(query->acf);
1194  ast_free(query->acf);
1195  }
1196  ast_free(query->sql_read);
1197  ast_free(query->sql_write);
1198  ast_free(query->sql_insert);
1199  ast_free(query);
1200  }
1201  return 0;
1202 }
#define ast_free(a)
Definition: astmm.h:182
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368

◆ generic_execute()

static SQLHSTMT generic_execute ( struct odbc_obj obj,
void *  data 
)
static

Definition at line 496 of file func_odbc.c.

References execute().

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

497 {
498  return execute(obj, data, 0);
499 }
static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
Common execution function for SQL queries.
Definition: func_odbc.c:454
void * data
Definition: datastore.h:70

◆ get_dsn()

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_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 305 of file func_odbc.c.

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

Referenced by get_odbc_obj().

306 {
307  struct dsn *dsn;
308 
309  if (!dsns) {
310  return NULL;
311  }
312 
313  ao2_lock(dsns);
315  if (!dsn) {
316  dsn = create_dsn(name);
317  }
318  ao2_unlock(dsns);
319 
320  if (!dsn) {
321  return NULL;
322  }
323 
324  ao2_lock(dsn);
325  if (!dsn->connection) {
327  if (!dsn->connection) {
328  ao2_unlock(dsn);
329  ao2_ref(dsn, -1);
330  return NULL;
331  }
332  return dsn;
333  }
334 
335  if (connection_dead(dsn->connection)) {
338  if (!dsn->connection) {
339  ao2_unlock(dsn);
340  ao2_ref(dsn, -1);
341  return NULL;
342  }
343  }
344 
345  return dsn;
346 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
Definition: func_odbc.c:150
struct odbc_obj * connection
Definition: func_odbc.c:152
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static int connection_dead(struct odbc_obj *connection)
Determine if the connection has died.
Definition: func_odbc.c:265
static const char name[]
Definition: cdr_mysql.c:74
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:122
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
static char * dsn
Definition: cdr_odbc.c:58
static struct dsn * create_dsn(const char *name)
Create a DSN and connect to the database.
Definition: func_odbc.c:226
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:813
struct ao2_container * dsns
Definition: func_odbc.c:159

◆ get_odbc_obj()

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 359 of file func_odbc.c.

References ast_odbc_request_obj, ast_rwlock_rdlock, ast_rwlock_unlock, get_dsn(), NULL, single_db_connection, and single_db_connection_lock.

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

360 {
361  struct odbc_obj *obj = NULL;
362 
364  if (single_db_connection) {
365  if (dsn) {
366  *dsn = get_dsn(dsn_name);
367  if (*dsn) {
368  obj = (*dsn)->connection;
369  }
370  }
371  } else {
372  obj = ast_odbc_request_obj(dsn_name, 0);
373  }
375 
376  return obj;
377 }
#define ast_rwlock_rdlock(a)
Definition: lock.h:233
#define NULL
Definition: resample.c:96
#define ast_rwlock_unlock(a)
Definition: lock.h:232
static int single_db_connection
Definition: func_odbc.c:105
ODBC container.
Definition: res_odbc.h:46
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:122
static struct dsn * get_dsn(const char *name)
Retrieve a DSN, or create it if it does not exist.
Definition: func_odbc.c:305
static ast_rwlock_t single_db_connection_lock
Definition: func_odbc.c:107

◆ init_acf_query()

static int init_acf_query ( struct ast_config cfg,
char *  catg,
struct acf_odbc_query **  query 
)
static

Definition at line 1204 of file func_odbc.c.

References acf_odbc_read(), acf_odbc_write(), AST_APP_ARG, ast_asprintf, ast_calloc, ast_clear_flag, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_false(), ast_log, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdup, ast_strdupa, ast_string_field_build, ast_string_field_init, ast_string_field_set, ast_strlen_zero, ast_variable_retrieve(), desc, free_acf_query(), LOG_ERROR, LOG_WARNING, NULL, OPT_ESCAPECOMMAS, OPT_MULTIROW, synopsis, and tmp().

Referenced by load_module(), and reload().

1205 {
1206  const char *tmp;
1207  const char *tmp2 = NULL;
1208  int i;
1209 
1210  if (!cfg || !catg) {
1211  return EINVAL;
1212  }
1213 
1214  if (!(*query = ast_calloc(1, sizeof(**query)))) {
1215  return ENOMEM;
1216  }
1217 
1218  if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
1219  char *tmp2 = ast_strdupa(tmp);
1220  AST_DECLARE_APP_ARGS(writeconf,
1221  AST_APP_ARG(dsn)[5];
1222  );
1223  AST_STANDARD_APP_ARGS(writeconf, tmp2);
1224  for (i = 0; i < 5; i++) {
1225  if (!ast_strlen_zero(writeconf.dsn[i]))
1226  ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
1227  }
1228  }
1229 
1230  if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
1231  char *tmp2 = ast_strdupa(tmp);
1232  AST_DECLARE_APP_ARGS(readconf,
1233  AST_APP_ARG(dsn)[5];
1234  );
1235  AST_STANDARD_APP_ARGS(readconf, tmp2);
1236  for (i = 0; i < 5; i++) {
1237  if (!ast_strlen_zero(readconf.dsn[i]))
1238  ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
1239  }
1240  } else {
1241  /* If no separate readhandle, then use the writehandle for reading */
1242  for (i = 0; i < 5; i++) {
1243  if (!ast_strlen_zero((*query)->writehandle[i]))
1244  ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
1245  }
1246  }
1247 
1248  if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")) ||
1249  (tmp2 = ast_variable_retrieve(cfg, catg, "read"))) {
1250  if (!tmp) {
1251  ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg);
1252  tmp = tmp2;
1253  }
1254  if (*tmp != '\0') { /* non-empty string */
1255  if (!((*query)->sql_read = ast_strdup(tmp))) {
1256  free_acf_query(*query);
1257  *query = NULL;
1258  return ENOMEM;
1259  }
1260  }
1261  }
1262 
1263  if ((*query)->sql_read && ast_strlen_zero((*query)->readhandle[0])) {
1264  free_acf_query(*query);
1265  *query = NULL;
1266  ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
1267  return EINVAL;
1268  }
1269 
1270  if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")) ||
1271  (tmp2 = ast_variable_retrieve(cfg, catg, "write"))) {
1272  if (!tmp) {
1273  ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg);
1274  tmp = tmp2;
1275  }
1276  if (*tmp != '\0') { /* non-empty string */
1277  if (!((*query)->sql_write = ast_strdup(tmp))) {
1278  free_acf_query(*query);
1279  *query = NULL;
1280  return ENOMEM;
1281  }
1282  }
1283  }
1284 
1285  if ((*query)->sql_write && ast_strlen_zero((*query)->writehandle[0])) {
1286  free_acf_query(*query);
1287  *query = NULL;
1288  ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
1289  return EINVAL;
1290  }
1291 
1292  if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
1293  if (*tmp != '\0') { /* non-empty string */
1294  if (!((*query)->sql_insert = ast_strdup(tmp))) {
1295  free_acf_query(*query);
1296  *query = NULL;
1297  return ENOMEM;
1298  }
1299  }
1300  }
1301 
1302  /* Allow escaping of embedded commas in fields to be turned off */
1303  ast_set_flag((*query), OPT_ESCAPECOMMAS);
1304  if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
1305  if (ast_false(tmp))
1306  ast_clear_flag((*query), OPT_ESCAPECOMMAS);
1307  }
1308 
1309  if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
1310  if (strcasecmp(tmp, "multirow") == 0)
1311  ast_set_flag((*query), OPT_MULTIROW);
1312  if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
1313  sscanf(tmp, "%30d", &((*query)->rowlimit));
1314  }
1315 
1316  if ((tmp = ast_variable_retrieve(cfg, catg, "minargs"))) {
1317  sscanf(tmp, "%30d", &((*query)->minargs));
1318  }
1319 
1320  (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
1321  if (!(*query)->acf) {
1322  free_acf_query(*query);
1323  *query = NULL;
1324  return ENOMEM;
1325  }
1326  if (ast_string_field_init((*query)->acf, 128)) {
1327  free_acf_query(*query);
1328  *query = NULL;
1329  return ENOMEM;
1330  }
1331 
1332  if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
1333  if (ast_asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
1334  (*query)->acf->name = NULL;
1335  }
1336  } else {
1337  if (ast_asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
1338  (*query)->acf->name = NULL;
1339  }
1340  }
1341 
1342  if (!(*query)->acf->name) {
1343  free_acf_query(*query);
1344  *query = NULL;
1345  return ENOMEM;
1346  }
1347 
1348  if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) {
1349  ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp);
1350  } else {
1351  ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name);
1352  }
1353 
1354  if (ast_strlen_zero((*query)->acf->syntax)) {
1355  free_acf_query(*query);
1356  *query = NULL;
1357  return ENOMEM;
1358  }
1359 
1360  if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) {
1361  ast_string_field_set((*query)->acf, synopsis, tmp);
1362  } else {
1363  ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments");
1364  }
1365 
1366  if (ast_strlen_zero((*query)->acf->synopsis)) {
1367  free_acf_query(*query);
1368  *query = NULL;
1369  return ENOMEM;
1370  }
1371 
1372  if ((*query)->sql_read && (*query)->sql_write) {
1373  ast_string_field_build((*query)->acf, desc,
1374  "Runs the following query, as defined in func_odbc.conf, performing\n"
1375  "substitution of the arguments into the query as specified by ${ARG1},\n"
1376  "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n"
1377  "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1378  "%s"
1379  "\nRead:\n%s\n\nWrite:\n%s%s%s",
1380  (*query)->sql_insert ?
1381  "If the write query affects no rows, the insert query will be\n"
1382  "performed.\n" : "",
1383  (*query)->sql_read,
1384  (*query)->sql_write,
1385  (*query)->sql_insert ? "\n\nInsert:\n" : "",
1386  (*query)->sql_insert ? (*query)->sql_insert : "");
1387  } else if ((*query)->sql_read) {
1388  ast_string_field_build((*query)->acf, desc,
1389  "Runs the following query, as defined in func_odbc.conf, performing\n"
1390  "substitution of the arguments into the query as specified by ${ARG1},\n"
1391  "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s",
1392  (*query)->sql_read);
1393  } else if ((*query)->sql_write) {
1394  ast_string_field_build((*query)->acf, desc,
1395  "Runs the following query, as defined in func_odbc.conf, performing\n"
1396  "substitution of the arguments into the query as specified by ${ARG1},\n"
1397  "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n"
1398  "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1399  "This function may only be set.\n%s\nSQL:\n%s%s%s",
1400  (*query)->sql_insert ?
1401  "If the write query affects no rows, the insert query will be\n"
1402  "performed.\n" : "",
1403  (*query)->sql_write,
1404  (*query)->sql_insert ? "\n\nInsert:\n" : "",
1405  (*query)->sql_insert ? (*query)->sql_insert : "");
1406  } else {
1407  free_acf_query(*query);
1408  *query = NULL;
1409  ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute. Ignoring.\n", catg);
1410  return EINVAL;
1411  }
1412 
1413  if (ast_strlen_zero((*query)->acf->desc)) {
1414  free_acf_query(*query);
1415  *query = NULL;
1416  return ENOMEM;
1417  }
1418 
1419  if ((*query)->sql_read) {
1420  (*query)->acf->read = acf_odbc_read;
1421  }
1422 
1423  if ((*query)->sql_write) {
1424  (*query)->acf->write = acf_odbc_write;
1425  }
1426 
1427  return 0;
1428 }
static const char synopsis[]
Definition: app_mysql.c:64
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
Definition: func_odbc.c:150
static const char desc[]
Definition: cdr_mysql.c:73
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
Definition: func_odbc.c:509
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
Definition: func_odbc.c:725
#define LOG_ERROR
Definition: logger.h:285
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:550
#define ast_clear_flag(p, flag)
Definition: utils.h:77
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
static int free_acf_query(struct acf_odbc_query *query)
Definition: func_odbc.c:1187

◆ load_module()

static int load_module ( void  )
static

Definition at line 1798 of file func_odbc.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ARRAY_LEN, ast_category_browse(), ast_cli_register_multiple, ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_log, AST_MODULE_LOAD_DECLINE, ast_register_application_xml, AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_rwlock_unlock, ast_rwlock_wrlock, ast_true(), ast_variable_retrieve(), config, CONFIG_STATUS_FILEINVALID, DEFAULT_SINGLE_DB_CONNECTION, DSN_BUCKETS, dsn_cmp(), dsn_hash(), exec_odbcfinish(), init_acf_query(), LOG_ERROR, LOG_NOTICE, NULL, single_db_connection, and single_db_connection_lock.

Referenced by reload().

1799 {
1800  int res = 0;
1801  struct ast_config *cfg;
1802  char *catg;
1803  const char *s;
1804  struct ast_flags config_flags = { 0 };
1805 
1808 
1809  cfg = ast_config_load(config, config_flags);
1810  if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1811  ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
1812  return AST_MODULE_LOAD_DECLINE;
1813  }
1814 
1816  if ((s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) {
1818  } else {
1820  }
1821 
1822  dsns = NULL;
1823 
1824  if (single_db_connection) {
1826  dsn_hash, NULL, dsn_cmp);
1827  if (!dsns) {
1828  ast_log(LOG_ERROR, "Could not initialize DSN container\n");
1830  return AST_MODULE_LOAD_DECLINE;
1831  }
1832  }
1834 
1836  for (catg = ast_category_browse(cfg, NULL);
1837  catg;
1838  catg = ast_category_browse(cfg, catg)) {
1839  struct acf_odbc_query *query = NULL;
1840  int err;
1841 
1842  if (!strcasecmp(catg, "general")) {
1843  continue;
1844  }
1845 
1846  if ((err = init_acf_query(cfg, catg, &query))) {
1847  if (err == ENOMEM)
1848  ast_log(LOG_ERROR, "Out of memory\n");
1849  else if (err == EINVAL)
1850  ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
1851  else
1852  ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
1853  } else {
1854  AST_RWLIST_INSERT_HEAD(&queries, query, list);
1855  ast_custom_function_register(query->acf);
1856  }
1857  }
1858 
1859  ast_config_destroy(cfg);
1862 
1864  return res;
1865 }
static char * app_odbcfinish
Definition: func_odbc.c:1171
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static struct ast_custom_function fetch_function
Definition: func_odbc.c:1165
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define DSN_BUCKETS
Definition: func_odbc.c:157
#define CONFIG_STATUS_FILEINVALID
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static int exec_odbcfinish(struct ast_channel *chan, const char *data)
Definition: func_odbc.c:1173
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define DEFAULT_SINGLE_DB_CONNECTION
Definition: func_odbc.c:103
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
#define ast_rwlock_unlock(a)
Definition: lock.h:232
static struct ast_custom_function escape_function
Definition: func_odbc.c:1121
static int dsn_hash(const void *obj, const int flags)
Definition: func_odbc.c:161
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:717
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
static int single_db_connection
Definition: func_odbc.c:105
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define LOG_NOTICE
Definition: logger.h:263
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_rwlock_wrlock(a)
Definition: lock.h:234
static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
Definition: func_odbc.c:1204
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static struct ast_cli_entry cli_func_odbc[]
Definition: func_odbc.c:1793
static int dsn_cmp(void *obj, void *arg, int flags)
Definition: func_odbc.c:181
static char * config
Definition: func_odbc.c:101
struct ao2_container * dsns
Definition: func_odbc.c:159
static ast_rwlock_t single_db_connection_lock
Definition: func_odbc.c:107
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ odbc_datastore_free()

static void odbc_datastore_free ( void *  data)
static

Definition at line 427 of file func_odbc.c.

References ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, odbc_datastore_row::list, and result.

Referenced by acf_odbc_read().

428 {
429  struct odbc_datastore *result = data;
430  struct odbc_datastore_row *row;
431 
432  if (!result) {
433  return;
434  }
435 
436  AST_LIST_LOCK(result);
437  while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
438  ast_free(row);
439  }
440  AST_LIST_UNLOCK(result);
441  AST_LIST_HEAD_DESTROY(result);
442  ast_free(result);
443 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct odbc_datastore_row::@212 list
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:652
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define ast_free(a)
Definition: astmm.h:182
static PGresult * result
Definition: cel_pgsql.c:88

◆ release_obj_or_dsn()

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 388 of file func_odbc.c.

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

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

389 {
390  if (dsn && *dsn) {
391  /* If multiple connections are not enabled then the guarantee
392  * of a single connection already exists and holding on to the
393  * connection would prevent any other user from acquiring it
394  * indefinitely.
395  */
396  if (ast_odbc_get_max_connections((*dsn)->name) < 2) {
397  ast_odbc_release_obj((*dsn)->connection);
398  (*dsn)->connection = NULL;
399  }
400  ao2_unlock(*dsn);
401  ao2_ref(*dsn, -1);
402  *dsn = NULL;
403  /* Some callers may provide both an obj and dsn. To ensure that
404  * the connection is not released twice we set it to NULL here if
405  * present.
406  */
407  if (obj) {
408  *obj = NULL;
409  }
410  } else if (obj && *obj) {
411  ast_odbc_release_obj(*obj);
412  *obj = NULL;
413  }
414 }
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
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:857
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:813

◆ reload()

static int reload ( void  )
static

Definition at line 1897 of file func_odbc.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_ref, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_custom_function_unregister(), ast_log, AST_MODFLAG_DEFAULT, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, AST_RWLIST_EMPTY, AST_RWLIST_INSERT_HEAD, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_rwlock_unlock, ast_rwlock_wrlock, ast_true(), ast_variable_retrieve(), ASTERISK_GPL_KEY, config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_SINGLE_DB_CONNECTION, DSN_BUCKETS, dsn_cmp(), dsn_hash(), free_acf_query(), init_acf_query(), load_module(), LOG_ERROR, LOG_WARNING, NULL, single_db_connection, single_db_connection_lock, and unload_module().

1898 {
1899  int res = 0;
1900  struct ast_config *cfg;
1901  struct acf_odbc_query *oldquery;
1902  char *catg;
1903  const char *s;
1904  struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
1905 
1906  cfg = ast_config_load(config, config_flags);
1908  return 0;
1909 
1911 
1912  if (dsns) {
1913  ao2_ref(dsns, -1);
1914  dsns = NULL;
1915  }
1916 
1917  if (cfg && (s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) {
1919  } else {
1921  }
1922 
1923  if (single_db_connection) {
1925  dsn_hash, NULL, dsn_cmp);
1926  if (!dsns) {
1927  ast_log(LOG_ERROR, "Could not initialize DSN container\n");
1929  return 0;
1930  }
1931  }
1933 
1935 
1936  while (!AST_RWLIST_EMPTY(&queries)) {
1937  oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
1938  ast_custom_function_unregister(oldquery->acf);
1939  free_acf_query(oldquery);
1940  }
1941 
1942  if (!cfg) {
1943  ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
1944  goto reload_out;
1945  }
1946 
1947  for (catg = ast_category_browse(cfg, NULL);
1948  catg;
1949  catg = ast_category_browse(cfg, catg)) {
1950  struct acf_odbc_query *query = NULL;
1951 
1952  if (!strcasecmp(catg, "general")) {
1953  continue;
1954  }
1955 
1956  if (init_acf_query(cfg, catg, &query)) {
1957  ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
1958  } else {
1959  AST_RWLIST_INSERT_HEAD(&queries, query, list);
1960  ast_custom_function_register(query->acf);
1961  }
1962  }
1963 
1964  ast_config_destroy(cfg);
1965 reload_out:
1967  return res;
1968 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define LOG_WARNING
Definition: logger.h:274
#define DSN_BUCKETS
Definition: func_odbc.c:157
#define CONFIG_STATUS_FILEINVALID
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define DEFAULT_SINGLE_DB_CONNECTION
Definition: func_odbc.c:103
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
#define ast_rwlock_unlock(a)
Definition: lock.h:232
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static int dsn_hash(const void *obj, const int flags)
Definition: func_odbc.c:161
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:717
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
static int single_db_connection
Definition: func_odbc.c:105
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define CONFIG_STATUS_FILEUNCHANGED
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_rwlock_wrlock(a)
Definition: lock.h:234
static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
Definition: func_odbc.c:1204
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static int dsn_cmp(void *obj, void *arg, int flags)
Definition: func_odbc.c:181
static char * config
Definition: func_odbc.c:101
struct ao2_container * dsns
Definition: func_odbc.c:159
static ast_rwlock_t single_db_connection_lock
Definition: func_odbc.c:107
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
static int free_acf_query(struct acf_odbc_query *query)
Definition: func_odbc.c:1187

◆ silent_execute()

static SQLHSTMT silent_execute ( struct odbc_obj obj,
void *  data 
)
static

Definition at line 501 of file func_odbc.c.

References execute().

Referenced by create_dsn().

502 {
503  return execute(obj, data, 1);
504 }
static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
Common execution function for SQL queries.
Definition: func_odbc.c:454

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1867 of file func_odbc.c.

References ao2_ref, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), AST_RWLIST_EMPTY, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_unregister_application(), and free_acf_query().

Referenced by reload().

1868 {
1869  struct acf_odbc_query *query;
1870  int res = 0;
1871 
1873  while (!AST_RWLIST_EMPTY(&queries)) {
1874  query = AST_RWLIST_REMOVE_HEAD(&queries, list);
1875  ast_custom_function_unregister(query->acf);
1876  free_acf_query(query);
1877  }
1878 
1883 
1884  /* Allow any threads waiting for this lock to pass (avoids a race) */
1886  usleep(1);
1888 
1890 
1891  if (dsns) {
1892  ao2_ref(dsns, -1);
1893  }
1894  return res;
1895 }
static char * app_odbcfinish
Definition: func_odbc.c:1171
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static struct ast_custom_function fetch_function
Definition: func_odbc.c:1165
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#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
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static struct ast_custom_function escape_function
Definition: func_odbc.c:1121
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
static struct ast_cli_entry cli_func_odbc[]
Definition: func_odbc.c:1793
struct ao2_container * dsns
Definition: func_odbc.c:159
static int free_acf_query(struct acf_odbc_query *query)
Definition: func_odbc.c:1187

Variable Documentation

◆ __mod_info

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .requires = "res_odbc", }
static

Definition at line 1978 of file func_odbc.c.

◆ app_odbcfinish

char* app_odbcfinish = "ODBCFinish"
static

Definition at line 1171 of file func_odbc.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1978 of file func_odbc.c.

◆ cli_func_odbc

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" ,},
}
static char * cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1430
static char * cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1643

Definition at line 1793 of file func_odbc.c.

◆ coldata_buf

struct ast_threadstorage coldata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_coldata_buf , .custom_init = NULL , }
static

Definition at line 422 of file func_odbc.c.

Referenced by acf_odbc_read(), and cli_odbc_read().

◆ colnames_buf

struct ast_threadstorage colnames_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_colnames_buf , .custom_init = NULL , }
static

Definition at line 423 of file func_odbc.c.

Referenced by acf_odbc_read().

◆ config

char* config = "func_odbc.conf"
static

Definition at line 101 of file func_odbc.c.

Referenced by load_module(), and reload().

◆ dsns

struct ao2_container* dsns

Definition at line 159 of file func_odbc.c.

◆ escape_function

struct ast_custom_function escape_function
static
Initial value:
= {
.name = "SQL_ESC",
.read = acf_escape,
.write = NULL,
}
static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1105
#define NULL
Definition: resample.c:96

Definition at line 1121 of file func_odbc.c.

◆ fetch_function

struct ast_custom_function fetch_function
static
Initial value:
= {
.name = "ODBC_FETCH",
.read = acf_fetch,
.write = NULL,
}
#define NULL
Definition: resample.c:96
static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1127

Definition at line 1165 of file func_odbc.c.

◆ odbc_info

const struct ast_datastore_info odbc_info
static
Initial value:
= {
.type = "FUNC_ODBC",
.destroy = odbc_datastore_free,
}
static void odbc_datastore_free(void *data)
Definition: func_odbc.c:427

Definition at line 129 of file func_odbc.c.

◆ queries

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

◆ resultcount

int resultcount = 0
static

Definition at line 418 of file func_odbc.c.

◆ single_db_connection

int single_db_connection
static

Definition at line 105 of file func_odbc.c.

Referenced by get_odbc_obj(), load_module(), and reload().

◆ single_db_connection_lock

ast_rwlock_t single_db_connection_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} }
static

Definition at line 107 of file func_odbc.c.

Referenced by get_odbc_obj(), load_module(), and reload().

◆ sql2_buf

struct ast_threadstorage sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , }
static

Definition at line 421 of file func_odbc.c.

Referenced by acf_odbc_write().

◆ sql_buf

struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }
static

Definition at line 420 of file func_odbc.c.

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