Wed Jan 8 2020 09:50:13

Asterisk developer's documentation


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/app.h"
#include "asterisk/cli.h"
#include "asterisk/strings.h"

Go to the source code of this file.

Data Structures

struct  acf_odbc_query
 
struct  odbc_datastore
 
struct  odbc_datastore_row
 
struct  queries
 

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)
 
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 exec_odbcfinish (struct ast_channel *chan, const char *data)
 
static int free_acf_query (struct acf_odbc_query *query)
 
static SQLHSTMT generic_execute (struct odbc_obj *obj, void *data)
 
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 int reload (void)
 
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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, }
 
static char * app_odbcfinish = "ODBCFinish"
 
static 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"
 
static struct ast_custom_function escape_function
 
static struct ast_custom_function fetch_function
 
static struct ast_datastore_info odbc_info
 
static struct queries queries = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 } , }
 
static int resultcount = 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

Enumeration Type Documentation

Enumerator
OPT_ESCAPECOMMAS 
OPT_MULTIROW 

Definition at line 103 of file func_odbc.c.

103  {
104  OPT_ESCAPECOMMAS = (1 << 0),
105  OPT_MULTIROW = (1 << 1),
106 };

Function Documentation

static void __init_coldata_buf ( void  )
static

Definition at line 145 of file func_odbc.c.

151 {
static void __init_colnames_buf ( void  )
static

Definition at line 146 of file func_odbc.c.

151 {
static void __init_sql2_buf ( void  )
static

Definition at line 144 of file func_odbc.c.

151 {
static void __init_sql_buf ( void  )
static

Definition at line 143 of file func_odbc.c.

151 {
static void __reg_module ( void  )
static

Definition at line 1586 of file func_odbc.c.

static void __unreg_module ( void  )
static

Definition at line 1586 of file func_odbc.c.

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

Definition at line 780 of file func_odbc.c.

References odbc_datastore_row::data, and len().

781 {
782  char *out = buf;
783 
784  for (; *data && out - buf < len; data++) {
785  if (*data == '\'') {
786  *out = '\'';
787  out++;
788  }
789  *out++ = *data;
790  }
791  *out = '\0';
792 
793  return 0;
794 }
const char * data
Definition: channel.h:755
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static int acf_fetch ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

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

803 {
804  struct ast_datastore *store;
805  struct odbc_datastore *resultset;
806  struct odbc_datastore_row *row;
807 
808  if (!chan) {
809  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
810  return -1;
811  }
812 
813  ast_channel_lock(chan);
814  store = ast_channel_datastore_find(chan, &odbc_info, data);
815  if (!store) {
816  ast_channel_unlock(chan);
817  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
818  return -1;
819  }
820  resultset = store->data;
821  AST_LIST_LOCK(resultset);
822  row = AST_LIST_REMOVE_HEAD(resultset, list);
823  AST_LIST_UNLOCK(resultset);
824  if (!row) {
825  /* Cleanup datastore */
826  ast_channel_datastore_remove(chan, store);
827  ast_datastore_free(store);
828  ast_channel_unlock(chan);
829  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
830  return -1;
831  }
832  pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
833  ast_channel_unlock(chan);
834  ast_copy_string(buf, row->data, len);
835  ast_free(row);
836  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
837  return 0;
838 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define LOG_WARNING
Definition: logger.h:144
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
struct odbc_datastore_row::@136 list
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
static struct ast_datastore_info odbc_info
Definition: func_odbc.c:122
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_channel_unlock(chan)
Definition: channel.h:2467
#define ast_free(a)
Definition: astmm.h:97
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
void * data
Definition: datastore.h:56
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
char names[0]
Definition: func_odbc.c:136
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2599
static int acf_odbc_read ( struct ast_channel chan,
const char *  cmd,
char *  s,
char *  buf,
size_t  len 
)
static

Definition at line 420 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_odbc_release_obj(), ast_odbc_request_obj, 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, dsn, generic_execute(), odbc_datastore_row::list, LOG_ERROR, LOG_WARNING, odbc_datastore_free(), OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), resultcount, sql_buf, and status.

Referenced by init_acf_query().

421 {
422  struct odbc_obj *obj = NULL;
423  struct acf_odbc_query *query;
424  char varname[15], rowcount[12] = "-1";
425  struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
426  int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn, bogus_chan = 0;
428  AST_APP_ARG(field)[100];
429  );
430  SQLHSTMT stmt = NULL;
431  SQLSMALLINT colcount=0;
432  SQLLEN indicator;
433  SQLSMALLINT collength;
434  struct odbc_datastore *resultset = NULL;
435  struct odbc_datastore_row *row = NULL;
436  struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
437  const char *status = "FAILURE";
438 
439  if (!sql || !colnames) {
440  if (chan) {
441  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
442  }
443  return -1;
444  }
445 
446  ast_str_reset(colnames);
447 
449  AST_RWLIST_TRAVERSE(&queries, query, list) {
450  if (!strcmp(query->acf->name, cmd)) {
451  break;
452  }
453  }
454 
455  if (!query) {
456  ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
458  if (chan) {
459  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
460  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
461  }
462  return -1;
463  }
464 
465  if (!chan) {
466  if (!(chan = ast_dummy_channel_alloc())) {
468  return -1;
469  }
470  bogus_chan = 1;
471  }
472 
473  if (!bogus_chan) {
474  ast_autoservice_start(chan);
475  }
476 
478  for (x = 0; x < args.argc; x++) {
479  snprintf(varname, sizeof(varname), "ARG%d", x + 1);
480  pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
481  }
482 
483  ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
484 
485  if (bogus_chan) {
486  chan = ast_channel_unref(chan);
487  } else {
488  /* Restore prior values */
489  for (x = 0; x < args.argc; x++) {
490  snprintf(varname, sizeof(varname), "ARG%d", x + 1);
491  pbx_builtin_setvar_helper(chan, varname, NULL);
492  }
493  }
494 
495  /* Save these flags, so we can release the lock */
496  escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
497  if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) {
498  if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
499  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
500  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
501  ast_autoservice_stop(chan);
502  return -1;
503  }
504  AST_LIST_HEAD_INIT(resultset);
505  if (query->rowlimit) {
506  rowlimit = query->rowlimit;
507  } else {
508  rowlimit = INT_MAX;
509  }
510  multirow = 1;
511  } else if (!bogus_chan) {
512  if (query->rowlimit > 1) {
513  rowlimit = query->rowlimit;
514  if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
515  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
516  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
517  ast_autoservice_stop(chan);
518  return -1;
519  }
520  AST_LIST_HEAD_INIT(resultset);
521  }
522  }
524 
525  for (dsn = 0; dsn < 5; dsn++) {
526  if (!ast_strlen_zero(query->readhandle[dsn])) {
527  obj = ast_odbc_request_obj(query->readhandle[dsn], 0);
528  if (obj) {
530  }
531  }
532  if (stmt) {
533  break;
534  }
535  if (obj) {
537  obj = NULL;
538  }
539  }
540 
541  if (!stmt) {
542  ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
543  if (obj) {
545  obj = NULL;
546  }
547  if (!bogus_chan) {
548  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
549  ast_autoservice_stop(chan);
550  }
551  odbc_datastore_free(resultset);
552  return -1;
553  }
554 
555  res = SQLNumResultCols(stmt, &colcount);
556  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
557  ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
558  SQLCloseCursor(stmt);
559  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
561  obj = NULL;
562  if (!bogus_chan) {
563  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
564  ast_autoservice_stop(chan);
565  }
566  odbc_datastore_free(resultset);
567  return -1;
568  }
569 
570  res = SQLFetch(stmt);
571  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
572  int res1 = -1;
573  if (res == SQL_NO_DATA) {
574  ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
575  res1 = 0;
576  buf[0] = '\0';
577  ast_copy_string(rowcount, "0", sizeof(rowcount));
578  status = "NODATA";
579  } else {
580  ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
581  status = "FETCHERROR";
582  }
583  SQLCloseCursor(stmt);
584  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
586  obj = NULL;
587  if (!bogus_chan) {
588  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
589  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
590  ast_autoservice_stop(chan);
591  }
592  odbc_datastore_free(resultset);
593  return res1;
594  }
595 
596  status = "SUCCESS";
597 
598  for (y = 0; y < rowlimit; y++) {
599  buf[0] = '\0';
600  for (x = 0; x < colcount; x++) {
601  int i;
602  struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
603  char *ptrcoldata;
604 
605  if (!coldata) {
606  odbc_datastore_free(resultset);
607  SQLCloseCursor(stmt);
608  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
610  obj = NULL;
611  if (!bogus_chan) {
612  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
613  ast_autoservice_stop(chan);
614  }
615  return -1;
616  }
617 
618  if (y == 0) {
619  char colname[256];
620  SQLULEN maxcol = 0;
621 
622  res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
623  ast_debug(3, "Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (int)collength, (int)maxcol, colname, x);
624  if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
625  snprintf(colname, sizeof(colname), "field%d", x);
626  }
627 
628  ast_str_make_space(&coldata, maxcol + 1);
629 
630  if (ast_str_strlen(colnames)) {
631  ast_str_append(&colnames, 0, ",");
632  }
633  ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
634 
635  if (resultset) {
636  void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
637  if (!tmp) {
638  ast_log(LOG_ERROR, "No space for a new resultset?\n");
639  odbc_datastore_free(resultset);
640  SQLCloseCursor(stmt);
641  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
643  obj = NULL;
644  if (!bogus_chan) {
645  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
646  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
647  ast_autoservice_stop(chan);
648  }
649  return -1;
650  }
651  resultset = tmp;
652  strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
653  }
654  }
655 
656  buflen = strlen(buf);
657  res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
658  if (indicator == SQL_NULL_DATA) {
659  ast_debug(3, "Got NULL data\n");
660  ast_str_reset(coldata);
661  res = SQL_SUCCESS;
662  }
663 
664  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
665  ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
666  y = -1;
667  buf[0] = '\0';
668  goto end_acf_read;
669  }
670 
671  ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
672 
673  if (x) {
674  buf[buflen++] = ',';
675  }
676 
677  /* Copy data, encoding '\' and ',' for the argument parser */
678  ptrcoldata = ast_str_buffer(coldata);
679  for (i = 0; i < ast_str_strlen(coldata); i++) {
680  if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
681  buf[buflen++] = '\\';
682  }
683  buf[buflen++] = ptrcoldata[i];
684 
685  if (buflen >= len - 2) {
686  break;
687  }
688 
689  if (ptrcoldata[i] == '\0') {
690  break;
691  }
692  }
693 
694  buf[buflen] = '\0';
695  ast_debug(2, "buf is now set to '%s'\n", buf);
696  }
697  ast_debug(2, "buf is now set to '%s'\n", buf);
698 
699  if (resultset) {
700  row = ast_calloc(1, sizeof(*row) + buflen + 1);
701  if (!row) {
702  ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
703  status = "MEMERROR";
704  goto end_acf_read;
705  }
706  strcpy((char *)row + sizeof(*row), buf);
707  AST_LIST_INSERT_TAIL(resultset, row, list);
708 
709  /* Get next row */
710  res = SQLFetch(stmt);
711  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
712  if (res != SQL_NO_DATA) {
713  ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
714  }
715  /* Number of rows in the resultset */
716  y++;
717  break;
718  }
719  }
720  }
721 
722 end_acf_read:
723  if (!bogus_chan) {
724  snprintf(rowcount, sizeof(rowcount), "%d", y);
725  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
726  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
727  pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
728  if (resultset) {
729  int uid;
730  struct ast_datastore *odbc_store;
731  if (multirow) {
732  uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
733  snprintf(buf, len, "%d", uid);
734  } else {
735  /* Name of the query is name of the resultset */
736  ast_copy_string(buf, cmd, len);
737 
738  /* If there's one with the same name already, free it */
739  ast_channel_lock(chan);
740  if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) {
741  ast_channel_datastore_remove(chan, odbc_store);
742  ast_datastore_free(odbc_store);
743  }
744  ast_channel_unlock(chan);
745  }
746  odbc_store = ast_datastore_alloc(&odbc_info, buf);
747  if (!odbc_store) {
748  ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n");
749  odbc_datastore_free(resultset);
750  SQLCloseCursor(stmt);
751  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
753  obj = NULL;
754  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
755  ast_autoservice_stop(chan);
756  return -1;
757  }
758  odbc_store->data = resultset;
759  ast_channel_lock(chan);
760  ast_channel_datastore_add(chan, odbc_store);
761  ast_channel_unlock(chan);
762  }
763  }
764  SQLCloseCursor(stmt);
765  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
767  obj = NULL;
768  if (resultset && !multirow) {
769  /* Fetch the first resultset */
770  if (!acf_fetch(chan, "", buf, buf, len)) {
771  buf[0] = '\0';
772  }
773  }
774  if (!bogus_chan) {
775  ast_autoservice_stop(chan);
776  }
777  return 0;
778 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
#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:143
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: pbx.c:4468
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:837
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
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...
Definition: pbx.c:10513
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:168
#define ast_verb(level,...)
Definition: logger.h:243
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static struct ast_datastore_info odbc_info
Definition: func_odbc.c:122
ODBC container.
Definition: res_odbc.h:46
int ast_str_make_space(struct ast_str **buf, size_t new_len)
Definition: strings.h:588
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
static int resultcount
Definition: func_odbc.c:141
static struct ast_threadstorage coldata_buf
Definition: func_odbc.c:145
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:238
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:802
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:594
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static struct @350 args
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Definition: datastore.c:98
static void odbc_datastore_free(void *data)
Definition: func_odbc.c:150
#define ast_channel_unlock(chan)
Definition: channel.h:2467
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:611
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:123
static char * dsn
Definition: cdr_odbc.c:50
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:436
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
void * data
Definition: datastore.h:56
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define ast_realloc(a, b)
Definition: astmm.h:103
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:718
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
struct ast_channel * ast_dummy_channel_alloc(void)
Create a fake channel structure.
Definition: channel.c:1391
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:1112
static struct ast_threadstorage colnames_buf
Definition: func_odbc.c:146
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2590
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2599
jack_status_t status
Definition: app_jack.c:143
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 211 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_release_obj(), ast_odbc_request_obj, 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(), dsn, generic_execute(), odbc_datastore_row::list, LOG_ERROR, LOG_WARNING, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), sql2_buf, sql_buf, and status.

Referenced by init_acf_query().

212 {
213  struct odbc_obj *obj = NULL;
214  struct acf_odbc_query *query;
215  char *t, varname[15];
216  int i, dsn, bogus_chan = 0;
217  int transactional = 0;
219  AST_APP_ARG(field)[100];
220  );
222  AST_APP_ARG(field)[100];
223  );
224  SQLHSTMT stmt = NULL;
225  SQLLEN rows=0;
226  struct ast_str *buf = ast_str_thread_get(&sql_buf, 16);
227  struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16);
228  const char *status = "FAILURE";
229 
230  if (!buf || !insertbuf) {
231  return -1;
232  }
233 
235  AST_RWLIST_TRAVERSE(&queries, query, list) {
236  if (!strcmp(query->acf->name, cmd)) {
237  break;
238  }
239  }
240 
241  if (!query) {
242  ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
244  if (chan) {
245  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
246  }
247  return -1;
248  }
249 
250  if (!chan) {
251  if (!(chan = ast_dummy_channel_alloc())) {
253  return -1;
254  }
255  bogus_chan = 1;
256  }
257 
258  if (!bogus_chan) {
259  ast_autoservice_start(chan);
260  }
261 
262  ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300);
263  /* We only get here if sql_write is set. sql_insert is optional however. */
264  if (query->sql_insert) {
265  ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300);
266  }
267 
268  /* Parse our arguments */
269  t = value ? ast_strdupa(value) : "";
270 
271  if (!s || !t) {
272  ast_log(LOG_ERROR, "Out of memory\n");
274  if (!bogus_chan) {
275  ast_autoservice_stop(chan);
276  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
277  } else {
278  ast_channel_unref(chan);
279  }
280  return -1;
281  }
282 
284  for (i = 0; i < args.argc; i++) {
285  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
286  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
287  }
288 
289  /* Parse values, just like arguments */
291  for (i = 0; i < values.argc; i++) {
292  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
293  pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
294  }
295 
296  /* Additionally set the value as a whole (but push an empty string if value is NULL) */
297  pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
298 
299  ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
300  if (query->sql_insert) {
301  ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
302  }
303 
304  if (bogus_chan) {
305  chan = ast_channel_unref(chan);
306  } else {
307  /* Restore prior values */
308  for (i = 0; i < args.argc; i++) {
309  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
310  pbx_builtin_setvar_helper(chan, varname, NULL);
311  }
312 
313  for (i = 0; i < values.argc; i++) {
314  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
315  pbx_builtin_setvar_helper(chan, varname, NULL);
316  }
317  pbx_builtin_setvar_helper(chan, "VALUE", NULL);
318  }
319 
320  /*!\note
321  * Okay, this part is confusing. Transactions belong to a single database
322  * handle. Therefore, when working with transactions, we CANNOT failover
323  * to multiple DSNs. We MUST have a single handle all the way through the
324  * transaction, or else we CANNOT enforce atomicity.
325  */
326  for (dsn = 0; dsn < 5; dsn++) {
327  if (!ast_strlen_zero(query->writehandle[dsn])) {
328  if (transactional) {
329  /* This can only happen second time through or greater. */
330  ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
331  }
332 
333  if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) {
334  transactional = 1;
335  } else {
336  obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
337  transactional = 0;
338  }
339 
340  if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
341  break;
342  }
343 
344  if (obj && !transactional) {
346  obj = NULL;
347  }
348  }
349  }
350 
351  if (stmt) {
352  SQLRowCount(stmt, &rows);
353  SQLCloseCursor(stmt);
354  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
355 
356  if (rows != 0) {
357  status = "SUCCESS";
358 
359  } else if (query->sql_insert) {
360  if (obj && !transactional) {
362  obj = NULL;
363  }
364 
365  for (transactional = 0, dsn = 0; dsn < 5; dsn++) {
366  if (!ast_strlen_zero(query->writehandle[dsn])) {
367  if (transactional) {
368  /* This can only happen second time through or greater. */
369  ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
370  } else if (obj) {
372  obj = NULL;
373  }
374 
375  if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) {
376  transactional = 1;
377  } else {
378  obj = ast_odbc_request_obj(query->writehandle[dsn], 0);
379  transactional = 0;
380  }
381  if (obj) {
382  stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf));
383  }
384  }
385  if (stmt) {
386  status = "FAILOVER";
387  SQLRowCount(stmt, &rows);
388  SQLCloseCursor(stmt);
389  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
390  break;
391  }
392  }
393  }
394  }
395 
397 
398  /* Output the affected rows, for all cases. In the event of failure, we
399  * flag this as -1 rows. Note that this is different from 0 affected rows
400  * which would be the case if we succeeded in our query, but the values did
401  * not change. */
402  if (!bogus_chan) {
403  snprintf(varname, sizeof(varname), "%d", (int)rows);
404  pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
405  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
406  }
407 
408  if (obj && !transactional) {
410  obj = NULL;
411  }
412 
413  if (!bogus_chan) {
414  ast_autoservice_stop(chan);
415  }
416 
417  return 0;
418 }
struct odbc_obj * ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname)
Retrieve a stored ODBC object, if a transaction has been started.
Definition: res_odbc.c:1456
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
#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:143
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: pbx.c:4468
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...
Definition: pbx.c:10513
int value
Definition: syslog.c:39
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:168
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
ODBC container.
Definition: res_odbc.h:46
int ast_str_make_space(struct ast_str **buf, size_t new_len)
Definition: strings.h:588
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:238
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
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:594
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static struct @350 args
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static struct ast_threadstorage sql2_buf
Definition: func_odbc.c:144
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:123
static char * dsn
Definition: cdr_odbc.c:50
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
struct ast_channel * ast_dummy_channel_alloc(void)
Create a fake channel structure.
Definition: channel.c:1391
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:1112
jack_status_t status
Definition: app_jack.c:143
static char* cli_odbc_read ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1101 of file func_odbc.c.

References ast_cli_args::argc, args, ast_cli_args::argv, AST_APP_ARG, ast_channel_unref, ast_cli(), ast_debug, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc(), ast_odbc_ast_str_SQLGetData(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_obj, 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, dsn, ast_cli_args::fd, generic_execute(), odbc_datastore_row::list, ast_cli_args::n, pbx_builtin_pushvar_helper(), ast_cli_args::pos, sql_buf, ast_cli_entry::usage, and ast_cli_args::word.

1102 {
1104  AST_APP_ARG(field)[100];
1105  );
1106  struct ast_str *sql;
1107  char *char_args, varname[10];
1108  struct acf_odbc_query *query;
1109  struct ast_channel *chan;
1110  int i;
1111 
1112  switch (cmd) {
1113  case CLI_INIT:
1114  e->command = "odbc read";
1115  e->usage =
1116  "Usage: odbc read <name> <args> [exec]\n"
1117  " Evaluates the SQL provided in the ODBC function <name>, and\n"
1118  " optionally executes the function. This function is intended for\n"
1119  " testing purposes. Remember to quote arguments containing spaces.\n";
1120  return NULL;
1121  case CLI_GENERATE:
1122  if (a->pos == 2) {
1123  int wordlen = strlen(a->word), which = 0;
1124  /* Complete function name */
1126  AST_RWLIST_TRAVERSE(&queries, query, list) {
1127  if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1128  if (++which > a->n) {
1129  char *res = ast_strdup(query->acf->name);
1131  return res;
1132  }
1133  }
1134  }
1136  return NULL;
1137  } else if (a->pos == 4) {
1138  return a->n == 0 ? ast_strdup("exec") : NULL;
1139  } else {
1140  return NULL;
1141  }
1142  }
1143 
1144  if (a->argc < 4 || a->argc > 5) {
1145  return CLI_SHOWUSAGE;
1146  }
1147 
1148  sql = ast_str_thread_get(&sql_buf, 16);
1149  if (!sql) {
1150  return CLI_FAILURE;
1151  }
1152 
1154  AST_RWLIST_TRAVERSE(&queries, query, list) {
1155  if (!strcmp(query->acf->name, a->argv[2])) {
1156  break;
1157  }
1158  }
1159 
1160  if (!query) {
1161  ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1163  return CLI_SHOWUSAGE;
1164  }
1165 
1166  if (!query->sql_read) {
1167  ast_cli(a->fd, "The function %s has no readsql parameter.\n", a->argv[2]);
1169  return CLI_SUCCESS;
1170  }
1171 
1172  ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
1173 
1174  /* Evaluate function */
1175  char_args = ast_strdupa(a->argv[3]);
1176 
1177  chan = ast_dummy_channel_alloc();
1178  if (!chan) {
1180  return CLI_FAILURE;
1181  }
1182 
1183  AST_STANDARD_APP_ARGS(args, char_args);
1184  for (i = 0; i < args.argc; i++) {
1185  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1186  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1187  }
1188 
1189  ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
1190  chan = ast_channel_unref(chan);
1191 
1192  if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
1193  /* Execute the query */
1194  struct odbc_obj *obj = NULL;
1195  int dsn, executed = 0;
1196  SQLHSTMT stmt;
1197  int rows = 0, res, x;
1198  SQLSMALLINT colcount = 0, collength;
1199  SQLLEN indicator;
1200  struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
1201  char colname[256];
1202  SQLULEN maxcol;
1203 
1204  if (!coldata) {
1206  return CLI_SUCCESS;
1207  }
1208 
1209  for (dsn = 0; dsn < 5; dsn++) {
1210  if (ast_strlen_zero(query->readhandle[dsn])) {
1211  continue;
1212  }
1213  ast_debug(1, "Found handle %s\n", query->readhandle[dsn]);
1214  if (!(obj = ast_odbc_request_obj(query->readhandle[dsn], 0))) {
1215  continue;
1216  }
1217 
1218  ast_debug(1, "Got obj\n");
1219  if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
1220  ast_odbc_release_obj(obj);
1221  obj = NULL;
1222  continue;
1223  }
1224 
1225  executed = 1;
1226 
1227  res = SQLNumResultCols(stmt, &colcount);
1228  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1229  ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
1230  SQLCloseCursor(stmt);
1231  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1232  ast_odbc_release_obj(obj);
1233  obj = NULL;
1235  return CLI_SUCCESS;
1236  }
1237 
1238  res = SQLFetch(stmt);
1239  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1240  SQLCloseCursor(stmt);
1241  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1242  ast_odbc_release_obj(obj);
1243  obj = NULL;
1244  if (res == SQL_NO_DATA) {
1245  ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], ast_str_buffer(sql));
1246  break;
1247  } else {
1248  ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1249  }
1251  return CLI_SUCCESS;
1252  }
1253  for (;;) {
1254  for (x = 0; x < colcount; x++) {
1255  maxcol = 0;
1256 
1257  res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
1258  if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
1259  snprintf(colname, sizeof(colname), "field%d", x);
1260  }
1261 
1262  res = ast_odbc_ast_str_SQLGetData(&coldata, maxcol, stmt, x + 1, SQL_CHAR, &indicator);
1263  if (indicator == SQL_NULL_DATA) {
1264  ast_str_set(&coldata, 0, "(nil)");
1265  res = SQL_SUCCESS;
1266  }
1267 
1268  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1269  ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
1270  SQLCloseCursor(stmt);
1271  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1272  ast_odbc_release_obj(obj);
1273  obj = NULL;
1275  return CLI_SUCCESS;
1276  }
1277 
1278  ast_cli(a->fd, "%-20.20s %s\n", colname, ast_str_buffer(coldata));
1279  }
1280  rows++;
1281 
1282  /* Get next row */
1283  res = SQLFetch(stmt);
1284  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1285  break;
1286  }
1287  ast_cli(a->fd, "%-20.20s %s\n", "----------", "----------");
1288  }
1289  SQLCloseCursor(stmt);
1290  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1291  ast_odbc_release_obj(obj);
1292  obj = NULL;
1293  ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn, query->readhandle[dsn]);
1294  break;
1295  }
1296  if (obj) {
1297  ast_odbc_release_obj(obj);
1298  obj = NULL;
1299  }
1300 
1301  if (!executed) {
1302  ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
1303  }
1304  } else { /* No execution, just print out the resulting SQL */
1305  ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1306  }
1308  return CLI_SUCCESS;
1309 }
Main Channel structure associated with a channel.
Definition: channel.h:742
#define ast_strdup(a)
Definition: astmm.h:109
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
const int argc
Definition: cli.h:154
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
#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:143
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: pbx.c:4468
Definition: cli.h:146
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...
Definition: pbx.c:10513
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:168
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:874
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
ODBC container.
Definition: res_odbc.h:46
int ast_str_make_space(struct ast_str **buf, size_t new_len)
Definition: strings.h:588
const int fd
Definition: cli.h:153
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
const int n
Definition: cli.h:159
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
static struct ast_threadstorage coldata_buf
Definition: func_odbc.c:145
const char *const * argv
Definition: cli.h:155
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
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:594
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static struct @350 args
#define CLI_SHOWUSAGE
Definition: cli.h:44
#define CLI_FAILURE
Definition: cli.h:45
char * command
Definition: cli.h:180
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:123
const char * word
Definition: cli.h:157
static char * dsn
Definition: cdr_odbc.c:50
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
const int pos
Definition: cli.h:158
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:718
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
struct ast_channel * ast_dummy_channel_alloc(void)
Create a fake channel structure.
Definition: channel.c:1391
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:1112
static char* cli_odbc_write ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1311 of file func_odbc.c.

References ast_cli_args::argc, args, ast_cli_args::argv, AST_APP_ARG, ast_channel_unref, ast_cli(), ast_debug, AST_DECLARE_APP_ARGS, ast_dummy_channel_alloc(), ast_odbc_direct_execute(), ast_odbc_release_obj(), ast_odbc_request_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_strdup, ast_strdupa, ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dsn, ast_cli_args::fd, generic_execute(), odbc_datastore_row::list, ast_cli_args::n, pbx_builtin_pushvar_helper(), ast_cli_args::pos, S_OR, sql_buf, ast_cli_entry::usage, and ast_cli_args::word.

1312 {
1314  AST_APP_ARG(field)[100];
1315  );
1317  AST_APP_ARG(field)[100];
1318  );
1319  struct ast_str *sql;
1320  char *char_args, *char_values, varname[10];
1321  struct acf_odbc_query *query;
1322  struct ast_channel *chan;
1323  int i;
1324 
1325  switch (cmd) {
1326  case CLI_INIT:
1327  e->command = "odbc write";
1328  e->usage =
1329  "Usage: odbc write <name> <args> <value> [exec]\n"
1330  " Evaluates the SQL provided in the ODBC function <name>, and\n"
1331  " optionally executes the function. This function is intended for\n"
1332  " testing purposes. Remember to quote arguments containing spaces.\n";
1333  return NULL;
1334  case CLI_GENERATE:
1335  if (a->pos == 2) {
1336  int wordlen = strlen(a->word), which = 0;
1337  /* Complete function name */
1339  AST_RWLIST_TRAVERSE(&queries, query, list) {
1340  if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1341  if (++which > a->n) {
1342  char *res = ast_strdup(query->acf->name);
1344  return res;
1345  }
1346  }
1347  }
1349  return NULL;
1350  } else if (a->pos == 5) {
1351  return a->n == 0 ? ast_strdup("exec") : NULL;
1352  } else {
1353  return NULL;
1354  }
1355  }
1356 
1357  if (a->argc < 5 || a->argc > 6) {
1358  return CLI_SHOWUSAGE;
1359  }
1360 
1361  sql = ast_str_thread_get(&sql_buf, 16);
1362  if (!sql) {
1363  return CLI_FAILURE;
1364  }
1365 
1367  AST_RWLIST_TRAVERSE(&queries, query, list) {
1368  if (!strcmp(query->acf->name, a->argv[2])) {
1369  break;
1370  }
1371  }
1372 
1373  if (!query) {
1374  ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1376  return CLI_SHOWUSAGE;
1377  }
1378 
1379  if (!query->sql_write) {
1380  ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
1382  return CLI_SUCCESS;
1383  }
1384 
1385  /* FIXME: The code below duplicates code found in acf_odbc_write but
1386  * lacks the newer sql_insert additions. */
1387 
1388  ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300);
1389 
1390  /* Evaluate function */
1391  char_args = ast_strdupa(a->argv[3]);
1392  char_values = ast_strdupa(a->argv[4]);
1393 
1394  chan = ast_dummy_channel_alloc();
1395  if (!chan) {
1397  return CLI_FAILURE;
1398  }
1399 
1400  AST_STANDARD_APP_ARGS(args, char_args);
1401  for (i = 0; i < args.argc; i++) {
1402  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1403  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1404  }
1405 
1406  /* Parse values, just like arguments */
1407  AST_STANDARD_APP_ARGS(values, char_values);
1408  for (i = 0; i < values.argc; i++) {
1409  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
1410  pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
1411  }
1412 
1413  /* Additionally set the value as a whole (but push an empty string if value is NULL) */
1414  pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
1415  ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
1416  ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
1417 
1418  chan = ast_channel_unref(chan);
1419 
1420  if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
1421  /* Execute the query */
1422  struct odbc_obj *obj = NULL;
1423  int dsn, executed = 0;
1424  SQLHSTMT stmt;
1425  SQLLEN rows = -1;
1426 
1427  for (dsn = 0; dsn < 5; dsn++) {
1428  if (ast_strlen_zero(query->writehandle[dsn])) {
1429  continue;
1430  }
1431  if (!(obj = ast_odbc_request_obj(query->writehandle[dsn], 0))) {
1432  continue;
1433  }
1434  if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
1435  ast_odbc_release_obj(obj);
1436  obj = NULL;
1437  continue;
1438  }
1439 
1440  SQLRowCount(stmt, &rows);
1441  SQLCloseCursor(stmt);
1442  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1443  ast_odbc_release_obj(obj);
1444  obj = NULL;
1445  ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn, query->writehandle[dsn]);
1446  executed = 1;
1447  break;
1448  }
1449 
1450  if (!executed) {
1451  ast_cli(a->fd, "Failed to execute query.\n");
1452  }
1453  } else { /* No execution, just print out the resulting SQL */
1454  ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1455  }
1457  return CLI_SUCCESS;
1458 }
Main Channel structure associated with a channel.
Definition: channel.h:742
#define ast_strdup(a)
Definition: astmm.h:109
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
const int argc
Definition: cli.h:154
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
#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:143
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: pbx.c:4468
Definition: cli.h:146
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...
Definition: pbx.c:10513
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:168
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
ODBC container.
Definition: res_odbc.h:46
int ast_str_make_space(struct ast_str **buf, size_t new_len)
Definition: strings.h:588
const int fd
Definition: cli.h:153
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
const int n
Definition: cli.h:159
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
const char *const * argv
Definition: cli.h:155
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
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:594
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static struct @350 args
#define CLI_SHOWUSAGE
Definition: cli.h:44
#define CLI_FAILURE
Definition: cli.h:45
char * command
Definition: cli.h:180
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:123
const char * word
Definition: cli.h:157
static char * dsn
Definition: cdr_odbc.c:50
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
const int pos
Definition: cli.h:158
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
struct ast_channel * ast_dummy_channel_alloc(void)
Create a fake channel structure.
Definition: channel.c:1391
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:1112
static int exec_odbcfinish ( struct ast_channel chan,
const char *  data 
)
static

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

849 {
850  struct ast_datastore *store;
851 
852  ast_channel_lock(chan);
853  store = ast_channel_datastore_find(chan, &odbc_info, data);
854  if (store) {
855  ast_channel_datastore_remove(chan, store);
856  ast_datastore_free(store);
857  }
858  ast_channel_unlock(chan);
859  return 0;
860 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
Structure for a data store object.
Definition: datastore.h:54
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
static struct ast_datastore_info odbc_info
Definition: func_odbc.c:122
#define ast_channel_unlock(chan)
Definition: channel.h:2467
void * data
Definition: datastore.h:56
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2599
static int free_acf_query ( struct acf_odbc_query query)
static

Definition at line 862 of file func_odbc.c.

References ast_free, and ast_string_field_free_memory.

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

863 {
864  if (query) {
865  if (query->acf) {
866  if (query->acf->name)
867  ast_free((char *)query->acf->name);
868  ast_string_field_free_memory(query->acf);
869  ast_free(query->acf);
870  }
871  ast_free(query->sql_read);
872  ast_free(query->sql_write);
873  ast_free(query->sql_insert);
874  ast_free(query);
875  }
876  return 0;
877 }
#define ast_free(a)
Definition: astmm.h:97
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:253
static SQLHSTMT generic_execute ( struct odbc_obj obj,
void *  data 
)
static

Definition at line 168 of file func_odbc.c.

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

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

169 {
170  int res;
171  char *sql = data;
172  SQLHSTMT stmt;
173 
174  res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
175  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
176  ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res);
177  return NULL;
178  }
179 
180  res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS);
181  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
182  if (res == SQL_ERROR) {
183  int i;
184  SQLINTEGER nativeerror=0, numfields=0;
185  SQLSMALLINT diagbytes=0;
186  unsigned char state[10], diagnostic[256];
187 
188  SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
189  for (i = 0; i < numfields; i++) {
190  SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
191  ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
192  if (i > 10) {
193  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
194  break;
195  }
196  }
197  }
198 
199  ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql);
200  SQLCloseCursor(stmt);
201  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
202  return NULL;
203  }
204 
205  return stmt;
206 }
SQLHDBC con
Definition: res_odbc.h:48
#define LOG_WARNING
Definition: logger.h:144
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
void * data
Definition: datastore.h:56
static int init_acf_query ( struct ast_config cfg,
char *  catg,
struct acf_odbc_query **  query 
)
static

Definition at line 879 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, dsn, free_acf_query(), LOG_ERROR, LOG_WARNING, OPT_ESCAPECOMMAS, OPT_MULTIROW, and synopsis.

Referenced by load_module(), and reload().

880 {
881  const char *tmp;
882  const char *tmp2;
883  int i;
884 
885  if (!cfg || !catg) {
886  return EINVAL;
887  }
888 
889  if (!(*query = ast_calloc(1, sizeof(**query)))) {
890  return ENOMEM;
891  }
892 
893  if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
894  char *tmp2 = ast_strdupa(tmp);
895  AST_DECLARE_APP_ARGS(writeconf,
896  AST_APP_ARG(dsn)[5];
897  );
898  AST_STANDARD_APP_ARGS(writeconf, tmp2);
899  for (i = 0; i < 5; i++) {
900  if (!ast_strlen_zero(writeconf.dsn[i]))
901  ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
902  }
903  }
904 
905  if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
906  char *tmp2 = ast_strdupa(tmp);
907  AST_DECLARE_APP_ARGS(readconf,
908  AST_APP_ARG(dsn)[5];
909  );
910  AST_STANDARD_APP_ARGS(readconf, tmp2);
911  for (i = 0; i < 5; i++) {
912  if (!ast_strlen_zero(readconf.dsn[i]))
913  ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
914  }
915  } else {
916  /* If no separate readhandle, then use the writehandle for reading */
917  for (i = 0; i < 5; i++) {
918  if (!ast_strlen_zero((*query)->writehandle[i]))
919  ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
920  }
921  }
922 
923  if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")) ||
924  (tmp2 = ast_variable_retrieve(cfg, catg, "read"))) {
925  if (!tmp) {
926  ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg);
927  tmp = tmp2;
928  }
929  if (*tmp != '\0') { /* non-empty string */
930  if (!((*query)->sql_read = ast_strdup(tmp))) {
931  free_acf_query(*query);
932  *query = NULL;
933  return ENOMEM;
934  }
935  }
936  }
937 
938  if ((*query)->sql_read && ast_strlen_zero((*query)->readhandle[0])) {
939  free_acf_query(*query);
940  *query = NULL;
941  ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
942  return EINVAL;
943  }
944 
945  if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")) ||
946  (tmp2 = ast_variable_retrieve(cfg, catg, "write"))) {
947  if (!tmp) {
948  ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg);
949  tmp = tmp2;
950  }
951  if (*tmp != '\0') { /* non-empty string */
952  if (!((*query)->sql_write = ast_strdup(tmp))) {
953  free_acf_query(*query);
954  *query = NULL;
955  return ENOMEM;
956  }
957  }
958  }
959 
960  if ((*query)->sql_write && ast_strlen_zero((*query)->writehandle[0])) {
961  free_acf_query(*query);
962  *query = NULL;
963  ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
964  return EINVAL;
965  }
966 
967  if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
968  if (*tmp != '\0') { /* non-empty string */
969  if (!((*query)->sql_insert = ast_strdup(tmp))) {
970  free_acf_query(*query);
971  *query = NULL;
972  return ENOMEM;
973  }
974  }
975  }
976 
977  /* Allow escaping of embedded commas in fields to be turned off */
978  ast_set_flag((*query), OPT_ESCAPECOMMAS);
979  if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
980  if (ast_false(tmp))
981  ast_clear_flag((*query), OPT_ESCAPECOMMAS);
982  }
983 
984  if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
985  if (strcasecmp(tmp, "multirow") == 0)
986  ast_set_flag((*query), OPT_MULTIROW);
987  if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
988  sscanf(tmp, "%30d", &((*query)->rowlimit));
989  }
990 
991  (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
992  if (!(*query)->acf) {
993  free_acf_query(*query);
994  *query = NULL;
995  return ENOMEM;
996  }
997  if (ast_string_field_init((*query)->acf, 128)) {
998  free_acf_query(*query);
999  *query = NULL;
1000  return ENOMEM;
1001  }
1002 
1003  if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
1004  if (ast_asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
1005  (*query)->acf->name = NULL;
1006  }
1007  } else {
1008  if (ast_asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
1009  (*query)->acf->name = NULL;
1010  }
1011  }
1012 
1013  if (!(*query)->acf->name) {
1014  free_acf_query(*query);
1015  *query = NULL;
1016  return ENOMEM;
1017  }
1018 
1019  if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) {
1020  ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp);
1021  } else {
1022  ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name);
1023  }
1024 
1025  if (ast_strlen_zero((*query)->acf->syntax)) {
1026  free_acf_query(*query);
1027  *query = NULL;
1028  return ENOMEM;
1029  }
1030 
1031  if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) {
1032  ast_string_field_set((*query)->acf, synopsis, tmp);
1033  } else {
1034  ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments");
1035  }
1036 
1037  if (ast_strlen_zero((*query)->acf->synopsis)) {
1038  free_acf_query(*query);
1039  *query = NULL;
1040  return ENOMEM;
1041  }
1042 
1043  if ((*query)->sql_read && (*query)->sql_write) {
1044  ast_string_field_build((*query)->acf, desc,
1045  "Runs the following query, as defined in func_odbc.conf, performing\n"
1046  "substitution of the arguments into the query as specified by ${ARG1},\n"
1047  "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n"
1048  "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1049  "%s"
1050  "\nRead:\n%s\n\nWrite:\n%s%s%s",
1051  (*query)->sql_insert ?
1052  "If the write query affects no rows, the insert query will be\n"
1053  "performed.\n" : "",
1054  (*query)->sql_read,
1055  (*query)->sql_write,
1056  (*query)->sql_insert ? "\n\nInsert:\n" : "",
1057  (*query)->sql_insert ? (*query)->sql_insert : "");
1058  } else if ((*query)->sql_read) {
1059  ast_string_field_build((*query)->acf, desc,
1060  "Runs the following query, as defined in func_odbc.conf, performing\n"
1061  "substitution of the arguments into the query as specified by ${ARG1},\n"
1062  "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s",
1063  (*query)->sql_read);
1064  } else if ((*query)->sql_write) {
1065  ast_string_field_build((*query)->acf, desc,
1066  "Runs the following query, as defined in func_odbc.conf, performing\n"
1067  "substitution of the arguments into the query as specified by ${ARG1},\n"
1068  "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n"
1069  "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1070  "This function may only be set.\n%s\nSQL:\n%s%s%s",
1071  (*query)->sql_insert ?
1072  "If the write query affects no rows, the insert query will be\n"
1073  "performed.\n" : "",
1074  (*query)->sql_write,
1075  (*query)->sql_insert ? "\n\nInsert:\n" : "",
1076  (*query)->sql_insert ? (*query)->sql_insert : "");
1077  } else {
1078  free_acf_query(*query);
1079  *query = NULL;
1080  ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute. Ignoring.\n", catg);
1081  return EINVAL;
1082  }
1083 
1084  if (ast_strlen_zero((*query)->acf->desc)) {
1085  free_acf_query(*query);
1086  *query = NULL;
1087  return ENOMEM;
1088  }
1089 
1090  if ((*query)->sql_read) {
1091  (*query)->acf->read = acf_odbc_read;
1092  }
1093 
1094  if ((*query)->sql_write) {
1095  (*query)->acf->write = acf_odbc_write;
1096  }
1097 
1098  return 0;
1099 }
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
#define ast_strdup(a)
Definition: astmm.h:109
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define ast_asprintf(a, b, c...)
Definition: astmm.h:121
static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
Definition: func_odbc.c:211
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:249
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Data structure associated with a custom dialplan function.
Definition: pbx.h:95
static const char desc[]
Definition: cdr_radius.c:85
static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
Definition: func_odbc.c:420
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static char * synopsis
Definition: func_enum.c:156
static char * dsn
Definition: cdr_odbc.c:50
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:367
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is &quot;false&quot;...
Definition: utils.c:1550
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
static int free_acf_query(struct acf_odbc_query *query)
Definition: func_odbc.c:862
static int load_module ( void  )
static

Definition at line 1465 of file func_odbc.c.

References app_odbcfinish, 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, cli_func_odbc, CONFIG_STATUS_FILEINVALID, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), odbc_datastore_row::list, LOG_ERROR, and LOG_NOTICE.

1466 {
1467  int res = 0;
1468  struct ast_config *cfg;
1469  char *catg;
1470  struct ast_flags config_flags = { 0 };
1471 
1475 
1476  cfg = ast_config_load(config, config_flags);
1477  if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1478  ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
1480  return AST_MODULE_LOAD_DECLINE;
1481  }
1482 
1483  for (catg = ast_category_browse(cfg, NULL);
1484  catg;
1485  catg = ast_category_browse(cfg, catg)) {
1486  struct acf_odbc_query *query = NULL;
1487  int err;
1488 
1489  if ((err = init_acf_query(cfg, catg, &query))) {
1490  if (err == ENOMEM)
1491  ast_log(LOG_ERROR, "Out of memory\n");
1492  else if (err == EINVAL)
1493  ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
1494  else
1495  ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
1496  } else {
1497  AST_RWLIST_INSERT_HEAD(&queries, query, list);
1498  ast_custom_function_register(query->acf);
1499  }
1500  }
1501 
1502  ast_config_destroy(cfg);
1505 
1507  return res;
1508 }
static char * app_odbcfinish
Definition: func_odbc.c:846
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static struct ast_custom_function fetch_function
Definition: func_odbc.c:840
#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
static int exec_odbcfinish(struct ast_channel *chan, const char *data)
Definition: func_odbc.c:848
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
static struct ast_custom_function escape_function
Definition: func_odbc.c:796
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:703
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
Structure used to handle boolean flags.
Definition: utils.h:200
static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
Definition: func_odbc.c:879
static struct ast_cli_entry cli_func_odbc[]
Definition: func_odbc.c:1460
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static char * config
Definition: func_odbc.c:101
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static void odbc_datastore_free ( void *  data)
static

Definition at line 150 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::data, and odbc_datastore_row::list.

Referenced by acf_odbc_read().

151 {
152  struct odbc_datastore *result = data;
153  struct odbc_datastore_row *row;
154 
155  if (!result) {
156  return;
157  }
158 
159  AST_LIST_LOCK(result);
160  while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
161  ast_free(row);
162  }
163  AST_LIST_UNLOCK(result);
164  AST_LIST_HEAD_DESTROY(result);
165  ast_free(result);
166 }
#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::@136 list
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:638
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
#define ast_free(a)
Definition: astmm.h:97
static int reload ( void  )
static

Definition at line 1536 of file func_odbc.c.

References ast_category_browse(), ast_config_destroy(), ast_config_load, ast_custom_function_register, ast_custom_function_unregister(), ast_log(), AST_RWLIST_EMPTY, AST_RWLIST_INSERT_HEAD, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, free_acf_query(), init_acf_query(), odbc_datastore_row::list, LOG_ERROR, and LOG_WARNING.

1537 {
1538  int res = 0;
1539  struct ast_config *cfg;
1540  struct acf_odbc_query *oldquery;
1541  char *catg;
1542  struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
1543 
1544  cfg = ast_config_load(config, config_flags);
1546  return 0;
1547 
1549 
1550  while (!AST_RWLIST_EMPTY(&queries)) {
1551  oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
1552  ast_custom_function_unregister(oldquery->acf);
1553  free_acf_query(oldquery);
1554  }
1555 
1556  if (!cfg) {
1557  ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
1558  goto reload_out;
1559  }
1560 
1561  for (catg = ast_category_browse(cfg, NULL);
1562  catg;
1563  catg = ast_category_browse(cfg, catg)) {
1564  struct acf_odbc_query *query = NULL;
1565 
1566  if (init_acf_query(cfg, catg, &query)) {
1567  ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
1568  } else {
1569  AST_RWLIST_INSERT_HEAD(&queries, query, list);
1570  ast_custom_function_register(query->acf);
1571  }
1572  }
1573 
1574  ast_config_destroy(cfg);
1575 reload_out:
1577  return res;
1578 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define LOG_WARNING
Definition: logger.h:144
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Definition: pbx.c:3814
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:703
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:829
Structure used to handle boolean flags.
Definition: utils.h:200
static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
Definition: func_odbc.c:879
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static char * config
Definition: func_odbc.c:101
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
static int free_acf_query(struct acf_odbc_query *query)
Definition: func_odbc.c:862
static int unload_module ( void  )
static

Definition at line 1510 of file func_odbc.c.

References app_odbcfinish, 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(), cli_func_odbc, escape_function, fetch_function, free_acf_query(), and odbc_datastore_row::list.

1511 {
1512  struct acf_odbc_query *query;
1513  int res = 0;
1514 
1516  while (!AST_RWLIST_EMPTY(&queries)) {
1517  query = AST_RWLIST_REMOVE_HEAD(&queries, list);
1518  ast_custom_function_unregister(query->acf);
1519  free_acf_query(query);
1520  }
1521 
1526 
1527  /* Allow any threads waiting for this lock to pass (avoids a race) */
1529  usleep(1);
1531 
1533  return 0;
1534 }
static char * app_odbcfinish
Definition: func_odbc.c:846
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static struct ast_custom_function fetch_function
Definition: func_odbc.c:840
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
#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.c:7705
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Definition: pbx.c:3814
static struct ast_custom_function escape_function
Definition: func_odbc.c:796
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:829
static struct ast_cli_entry cli_func_odbc[]
Definition: func_odbc.c:1460
static int free_acf_query(struct acf_odbc_query *query)
Definition: func_odbc.c:862

Variable Documentation

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

Definition at line 1586 of file func_odbc.c.

char* app_odbcfinish = "ODBCFinish"
static

Definition at line 846 of file func_odbc.c.

Referenced by load_module(), and unload_module().

Definition at line 1586 of file func_odbc.c.

struct ast_cli_entry cli_func_odbc[]
static
Initial value:
= {
AST_CLI_DEFINE(cli_odbc_write, "Test setting a func_odbc function"),
AST_CLI_DEFINE(cli_odbc_read, "Test reading a func_odbc function"),
}
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static char * cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1101
static char * cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1311

Definition at line 1460 of file func_odbc.c.

Referenced by load_module(), and unload_module().

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

Definition at line 145 of file func_odbc.c.

Referenced by acf_odbc_read(), and cli_odbc_read().

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

Definition at line 146 of file func_odbc.c.

Referenced by acf_odbc_read().

char* config = "func_odbc.conf"
static

Definition at line 101 of file func_odbc.c.

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:780

Definition at line 796 of file func_odbc.c.

Referenced by load_module(), and unload_module().

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

Definition at line 840 of file func_odbc.c.

Referenced by load_module(), and unload_module().

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:150

Definition at line 122 of file func_odbc.c.

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

Definition at line 141 of file func_odbc.c.

Referenced by acf_odbc_read().

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

Definition at line 144 of file func_odbc.c.

Referenced by acf_odbc_write().

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

Definition at line 143 of file func_odbc.c.

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