Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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
 Data source name. More...
 
struct  odbc_datastore
 
struct  odbc_datastore_row
 
struct  queries
 

Macros

#define DEFAULT_SINGLE_DB_CONNECTION   0
 
#define DSN_BUCKETS   37
 

Enumerations

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

Functions

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "ODBC lookups" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .requires = "res_odbc", }
 
static char * app_odbcfinish = "ODBCFinish"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_func_odbc []
 
static struct ast_threadstorage coldata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_coldata_buf , .custom_init = NULL , }
 
static struct ast_threadstorage colnames_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_colnames_buf , .custom_init = NULL , }
 
static char * config = "func_odbc.conf"
 
struct ao2_containerdsns
 
static struct ast_custom_function escape_backslashes_function
 
static struct ast_custom_function escape_function
 
static struct ast_custom_function fetch_function
 
static const struct ast_datastore_info odbc_info
 
static struct queries queries = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static int resultcount = 0
 
static int single_db_connection
 
static ast_rwlock_t single_db_connection_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} }
 
static struct ast_threadstorage sql2_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql2_buf , .custom_init = NULL , }
 
static struct ast_threadstorage sql_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_sql_buf , .custom_init = NULL , }
 

Detailed Description

ODBC lookups.

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

Definition in file func_odbc.c.

Macro Definition Documentation

◆ DEFAULT_SINGLE_DB_CONNECTION

#define DEFAULT_SINGLE_DB_CONNECTION   0

Definition at line 120 of file func_odbc.c.

◆ DSN_BUCKETS

#define DSN_BUCKETS   37

Definition at line 174 of file func_odbc.c.

Enumeration Type Documentation

◆ odbc_option_flags

Enumerator
OPT_ESCAPECOMMAS 
OPT_MULTIROW 

Definition at line 126 of file func_odbc.c.

126 {
127 OPT_ESCAPECOMMAS = (1 << 0),
128 OPT_MULTIROW = (1 << 1),
129};
@ OPT_ESCAPECOMMAS
Definition: func_odbc.c:127
@ OPT_MULTIROW
Definition: func_odbc.c:128

Function Documentation

◆ __init_coldata_buf()

static void __init_coldata_buf ( void  )
static

Definition at line 439 of file func_odbc.c.

445{

◆ __init_colnames_buf()

static void __init_colnames_buf ( void  )
static

Definition at line 440 of file func_odbc.c.

445{

◆ __init_sql2_buf()

static void __init_sql2_buf ( void  )
static

Definition at line 438 of file func_odbc.c.

445{

◆ __init_sql_buf()

static void __init_sql_buf ( void  )
static

Definition at line 437 of file func_odbc.c.

445{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2013 of file func_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2013 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,
char  character 
)
static

Definition at line 1122 of file func_odbc.c.

1123{
1124 char *out = buf;
1125
1126 for (; *data && out - buf < len; data++) {
1127 if (*data == character) {
1128 *out = character;
1129 out++;
1130 }
1131 *out++ = *data;
1132 }
1133 *out = '\0';
1134
1135 return 0;
1136}
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

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

Referenced by acf_escape_backslashes(), and acf_escape_ticks().

◆ acf_escape_backslashes()

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

Definition at line 1149 of file func_odbc.c.

1150{
1151 return acf_escape(chan, cmd, data, buf, len, '\\');
1152}
static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len, char character)
Definition: func_odbc.c:1122

References acf_escape(), buf, and len().

◆ acf_escape_ticks()

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

Definition at line 1138 of file func_odbc.c.

1139{
1140 return acf_escape(chan, cmd, data, buf, len, '\'');
1141}

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

◆ acf_fetch()

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

Definition at line 1160 of file func_odbc.c.

1161{
1162 struct ast_datastore *store;
1163 struct odbc_datastore *resultset;
1164 struct odbc_datastore_row *row;
1165
1166 if (!chan) {
1167 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1168 return -1;
1169 }
1170
1171 ast_channel_lock(chan);
1172 store = ast_channel_datastore_find(chan, &odbc_info, data);
1173 if (!store) {
1174 ast_channel_unlock(chan);
1175 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
1176 return -1;
1177 }
1178 resultset = store->data;
1179 AST_LIST_LOCK(resultset);
1180 row = AST_LIST_REMOVE_HEAD(resultset, list);
1181 AST_LIST_UNLOCK(resultset);
1182 if (!row) {
1183 /* Cleanup datastore */
1184 ast_channel_datastore_remove(chan, store);
1185 ast_datastore_free(store);
1186 ast_channel_unlock(chan);
1187 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
1188 return -1;
1189 }
1190 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
1191 ast_channel_unlock(chan);
1192 ast_copy_string(buf, row->data, len);
1193 ast_free(row);
1194 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
1195 return 0;
1196}
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
#define ast_channel_lock(chan)
Definition: channel.h:2922
#define ast_channel_unlock(chan)
Definition: channel.h:2923
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:2399
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
static const struct ast_datastore_info odbc_info
Definition: func_odbc.c:146
#define LOG_WARNING
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
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_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
struct odbc_datastore_row::@175 list
char names[0]
Definition: func_odbc.c:160

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, buf, odbc_datastore_row::data, ast_datastore::data, len(), odbc_datastore_row::list, LOG_WARNING, odbc_datastore::names, odbc_info, and pbx_builtin_setvar_helper().

Referenced by acf_odbc_read().

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

743{
744 struct odbc_obj *obj = NULL;
745 struct acf_odbc_query *query;
746 char varname[15], rowcount[12] = "-1";
747 struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
748 int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn_num, bogus_chan = 0;
750 AST_APP_ARG(field)[100];
751 );
752 SQLHSTMT stmt = NULL;
753 SQLSMALLINT colcount=0;
754 SQLLEN indicator;
755 SQLSMALLINT collength;
756 struct odbc_datastore *resultset = NULL;
757 struct odbc_datastore_row *row = NULL;
758 struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
759 const char *status = "FAILURE";
760 struct dsn *dsn = NULL;
761
762 if (!sql || !colnames) {
763 if (chan) {
764 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
765 }
766 return -1;
767 }
768
769 ast_str_reset(colnames);
770
772 AST_RWLIST_TRAVERSE(&queries, query, list) {
773 if (!strcmp(query->acf->name, cmd)) {
774 break;
775 }
776 }
777
778 if (!query) {
779 ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
781 if (chan) {
782 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
783 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
784 }
785 return -1;
786 }
787
789 if (args.argc < query->minargs) {
790 ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
791 args.argc, cmd, query->minargs);
793 return -1;
794 }
795
796 if (!chan) {
797 if (!(chan = ast_dummy_channel_alloc())) {
799 return -1;
800 }
801 bogus_chan = 1;
802 }
803
804 if (!bogus_chan) {
806 }
807
808 snprintf(varname, sizeof(varname), "%u", args.argc);
809 pbx_builtin_pushvar_helper(chan, "ARGC", varname);
810 for (x = 0; x < args.argc; x++) {
811 snprintf(varname, sizeof(varname), "ARG%d", x + 1);
812 pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
813 }
814
815 ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
816
817 if (bogus_chan) {
818 chan = ast_channel_unref(chan);
819 } else {
820 /* Restore prior values */
821 pbx_builtin_setvar_helper(chan, "ARGC", NULL);
822
823 for (x = 0; x < args.argc; x++) {
824 snprintf(varname, sizeof(varname), "ARG%d", x + 1);
825 pbx_builtin_setvar_helper(chan, varname, NULL);
826 }
827 }
828
829 /* Save these flags, so we can release the lock */
830 escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
831 if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) {
832 if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
833 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
834 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
837 return -1;
838 }
839 AST_LIST_HEAD_INIT(resultset);
840 if (query->rowlimit) {
841 rowlimit = query->rowlimit;
842 } else {
843 rowlimit = INT_MAX;
844 }
845 multirow = 1;
846 } else if (!bogus_chan) {
847 if (query->rowlimit > 1) {
848 rowlimit = query->rowlimit;
849 if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
850 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
851 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
854 return -1;
855 }
856 AST_LIST_HEAD_INIT(resultset);
857 }
858 }
860
861 for (dsn_num = 0; dsn_num < 5; dsn_num++) {
862 if (!ast_strlen_zero(query->readhandle[dsn_num])) {
863 obj = get_odbc_obj(query->readhandle[dsn_num], &dsn);
864 if (!obj) {
865 continue;
866 }
868 }
869 if (stmt) {
870 break;
871 }
872 release_obj_or_dsn (&obj, &dsn);
873 }
874
875 if (!stmt) {
876 ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
877 release_obj_or_dsn (&obj, &dsn);
878 if (!bogus_chan) {
879 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
881 }
882 odbc_datastore_free(resultset);
883 return -1;
884 }
885
886 res = SQLNumResultCols(stmt, &colcount);
887 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
888 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
889 SQLCloseCursor(stmt);
890 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
891 release_obj_or_dsn (&obj, &dsn);
892 if (!bogus_chan) {
893 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
895 }
896 odbc_datastore_free(resultset);
897 return -1;
898 }
899
900 if (colcount <= 0) {
901 ast_verb(4, "Returned %d columns [%s]\n", colcount, ast_str_buffer(sql));
902 buf[0] = '\0';
903 SQLCloseCursor(stmt);
904 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
905 release_obj_or_dsn (&obj, &dsn);
906 if (!bogus_chan) {
907 pbx_builtin_setvar_helper(chan, "ODBCROWS", "0");
908 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "NODATA");
910 }
911 odbc_datastore_free(resultset);
912 return 0;
913 }
914
915 res = SQLFetch(stmt);
916 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
917 int res1 = -1;
918 if (res == SQL_NO_DATA) {
919 ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
920 res1 = 0;
921 buf[0] = '\0';
922 ast_copy_string(rowcount, "0", sizeof(rowcount));
923 status = "NODATA";
924 } else {
925 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
926 status = "FETCHERROR";
927 }
928 SQLCloseCursor(stmt);
929 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
930 release_obj_or_dsn (&obj, &dsn);
931 if (!bogus_chan) {
932 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
933 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
935 }
936 odbc_datastore_free(resultset);
937 return res1;
938 }
939
940 status = "SUCCESS";
941
942 for (y = 0; y < rowlimit; y++) {
943 buf[0] = '\0';
944 for (x = 0; x < colcount; x++) {
945 int i;
946 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
947 char *ptrcoldata;
948
949 if (!coldata) {
950 odbc_datastore_free(resultset);
951 SQLCloseCursor(stmt);
952 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
953 release_obj_or_dsn (&obj, &dsn);
954 if (!bogus_chan) {
955 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
957 }
958 return -1;
959 }
960
961 if (y == 0) {
962 char colname[256];
963 SQLLEN octetlength = 0;
964
965 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL);
966 ast_debug(3, "Got collength of %d for column '%s' (offset %d)\n", (int)collength, colname, x);
967 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
968 snprintf(colname, sizeof(colname), "field%d", x);
969 }
970
971 SQLColAttribute(stmt, x + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &octetlength);
972
973 ast_str_make_space(&coldata, octetlength + 1);
974
975 if (ast_str_strlen(colnames)) {
976 ast_str_append(&colnames, 0, ",");
977 }
978 ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
979
980 if (resultset) {
981 void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
982 if (!tmp) {
983 ast_log(LOG_ERROR, "No space for a new resultset?\n");
984 odbc_datastore_free(resultset);
985 SQLCloseCursor(stmt);
986 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
987 release_obj_or_dsn (&obj, &dsn);
988 if (!bogus_chan) {
989 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
990 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
992 }
993 return -1;
994 }
995 resultset = tmp;
996 strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
997 }
998 }
999
1000 buflen = strlen(buf);
1001 res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
1002 if (indicator == SQL_NULL_DATA) {
1003 ast_debug(3, "Got NULL data\n");
1004 ast_str_reset(coldata);
1005 res = SQL_SUCCESS;
1006 }
1007
1008 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1009 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
1010 y = -1;
1011 buf[0] = '\0';
1012 goto end_acf_read;
1013 }
1014
1015 ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
1016
1017 if (x) {
1018 buf[buflen++] = ',';
1019 }
1020
1021 /* Copy data, encoding '\' and ',' for the argument parser */
1022 ptrcoldata = ast_str_buffer(coldata);
1023 for (i = 0; i < ast_str_strlen(coldata); i++) {
1024 if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
1025 buf[buflen++] = '\\';
1026 }
1027 buf[buflen++] = ptrcoldata[i];
1028
1029 if (buflen >= len - 2) {
1030 break;
1031 }
1032
1033 if (ptrcoldata[i] == '\0') {
1034 break;
1035 }
1036 }
1037
1038 buf[buflen] = '\0';
1039 ast_debug(2, "buf is now set to '%s'\n", buf);
1040 }
1041 ast_debug(2, "buf is now set to '%s'\n", buf);
1042
1043 if (resultset) {
1044 row = ast_calloc(1, sizeof(*row) + buflen + 1);
1045 if (!row) {
1046 ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
1047 status = "MEMERROR";
1048 goto end_acf_read;
1049 }
1050 strcpy((char *)row + sizeof(*row), buf);
1051 AST_LIST_INSERT_TAIL(resultset, row, list);
1052
1053 /* Get next row */
1054 res = SQLFetch(stmt);
1055 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1056 if (res != SQL_NO_DATA) {
1057 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1058 }
1059 /* Number of rows in the resultset */
1060 y++;
1061 break;
1062 }
1063 }
1064 }
1065
1066end_acf_read:
1067 if (!bogus_chan) {
1068 snprintf(rowcount, sizeof(rowcount), "%d", y);
1069 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
1070 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
1071 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
1072 if (resultset) {
1073 struct ast_datastore *odbc_store;
1074 if (multirow) {
1075 int uid;
1077 snprintf(buf, len, "%d", uid);
1078 } else {
1079 /* Name of the query is name of the resultset */
1080 ast_copy_string(buf, cmd, len);
1081
1082 /* If there's one with the same name already, free it */
1083 ast_channel_lock(chan);
1084 if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) {
1085 ast_channel_datastore_remove(chan, odbc_store);
1086 ast_datastore_free(odbc_store);
1087 }
1088 ast_channel_unlock(chan);
1089 }
1090 odbc_store = ast_datastore_alloc(&odbc_info, buf);
1091 if (!odbc_store) {
1092 ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n");
1093 odbc_datastore_free(resultset);
1094 SQLCloseCursor(stmt);
1095 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1096 release_obj_or_dsn (&obj, &dsn);
1097 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
1099 return -1;
1100 }
1101 odbc_store->data = resultset;
1102 ast_channel_lock(chan);
1103 ast_channel_datastore_add(chan, odbc_store);
1104 ast_channel_unlock(chan);
1105 }
1106 }
1107 SQLCloseCursor(stmt);
1108 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1109 release_obj_or_dsn (&obj, &dsn);
1110 if (resultset && !multirow) {
1111 /* Fetch the first resultset */
1112 if (!acf_fetch(chan, "", buf, buf, len)) {
1113 buf[0] = '\0';
1114 }
1115 }
1116 if (!bogus_chan) {
1118 }
1119 return 0;
1120}
jack_status_t status
Definition: app_jack.c:146
#define ast_realloc(p, len)
A wrapper for realloc()
Definition: astmm.h:226
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static int tmp()
Definition: bt_open.c:389
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:513
static struct ast_threadstorage colnames_buf
Definition: func_odbc.c:440
static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1160
static void odbc_datastore_free(void *data)
Definition: func_odbc.c:444
static struct odbc_obj * get_odbc_obj(const char *dsn_name, struct dsn **dsn)
Get a DB handle via a DSN or directly.
Definition: func_odbc.c:376
static struct ast_threadstorage coldata_buf
Definition: func_odbc.c:439
static int resultcount
Definition: func_odbc.c:435
static void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
Release an ODBC obj or a DSN.
Definition: func_odbc.c:405
static struct ast_threadstorage sql_buf
Definition: func_odbc.c:437
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
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:757
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value.
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:498
SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data)
Executes an non prepared statement and returns the resulting statement handle.
Definition: res_odbc.c:360
#define NULL
Definition: resample.c:96
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:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
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:1076
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:693
#define ast_str_make_space(buf, new_len)
Definition: strings.h:828
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
const char * uid
Definition: datastore.h:65
Support for dynamic strings.
Definition: strings.h:623
Data source name.
Definition: func_odbc.c:167
ODBC container.
Definition: res_odbc.h:46
const char * args
static int indicator
#define ast_test_flag(p, flag)
Definition: utils.h:63

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, buf, coldata_buf, colnames_buf, ast_datastore::data, generic_execute(), get_odbc_obj(), indicator, len(), LOG_ERROR, LOG_WARNING, NULL, odbc_datastore_free(), odbc_info, OPT_ESCAPECOMMAS, OPT_MULTIROW, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), release_obj_or_dsn(), resultcount, sql_buf, status, tmp(), and ast_datastore::uid.

Referenced by init_acf_query().

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

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

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, status, and value.

Referenced by init_acf_query().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 2013 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 1463 of file func_odbc.c.

1464{
1466 AST_APP_ARG(field)[100];
1467 );
1468 struct ast_str *sql;
1469 char *char_args, varname[15];
1470 struct acf_odbc_query *query;
1471 struct ast_channel *chan;
1472 int i;
1473
1474 switch (cmd) {
1475 case CLI_INIT:
1476 e->command = "odbc read";
1477 e->usage =
1478 "Usage: odbc read <name> <args> [exec]\n"
1479 " Evaluates the SQL provided in the ODBC function <name>, and\n"
1480 " optionally executes the function. This function is intended for\n"
1481 " testing purposes. Remember to quote arguments containing spaces.\n";
1482 return NULL;
1483 case CLI_GENERATE:
1484 if (a->pos == 2) {
1485 int wordlen = strlen(a->word), which = 0;
1486 /* Complete function name */
1488 AST_RWLIST_TRAVERSE(&queries, query, list) {
1489 if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1490 if (++which > a->n) {
1491 char *res = ast_strdup(query->acf->name);
1493 return res;
1494 }
1495 }
1496 }
1498 return NULL;
1499 } else if (a->pos == 4) {
1500 static const char * const completions[] = { "exec", NULL };
1501 return ast_cli_complete(a->word, completions, a->n);
1502 } else {
1503 return NULL;
1504 }
1505 }
1506
1507 if (a->argc < 4 || a->argc > 5) {
1508 return CLI_SHOWUSAGE;
1509 }
1510
1511 sql = ast_str_thread_get(&sql_buf, 16);
1512 if (!sql) {
1513 return CLI_FAILURE;
1514 }
1515
1517 AST_RWLIST_TRAVERSE(&queries, query, list) {
1518 if (!strcmp(query->acf->name, a->argv[2])) {
1519 break;
1520 }
1521 }
1522
1523 if (!query) {
1524 ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1526 return CLI_SHOWUSAGE;
1527 }
1528
1529 if (!query->sql_read) {
1530 ast_cli(a->fd, "The function %s has no readsql parameter.\n", a->argv[2]);
1532 return CLI_SUCCESS;
1533 }
1534
1535 ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
1536
1537 /* Evaluate function */
1538 char_args = ast_strdupa(a->argv[3]);
1539
1540 chan = ast_dummy_channel_alloc();
1541 if (!chan) {
1543 return CLI_FAILURE;
1544 }
1545
1546 AST_STANDARD_APP_ARGS(args, char_args);
1547 for (i = 0; i < args.argc; i++) {
1548 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1549 pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1550 }
1551
1552 ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
1553 chan = ast_channel_unref(chan);
1554
1555 if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
1556 /* Execute the query */
1557 struct odbc_obj *obj = NULL;
1558 struct dsn *dsn = NULL;
1559 int dsn_num, executed = 0;
1560 SQLHSTMT stmt;
1561 int rows = 0, res, x;
1562 SQLSMALLINT colcount = 0, collength;
1563 SQLLEN indicator, octetlength;
1564 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
1565 char colname[256];
1566
1567 if (!coldata) {
1569 return CLI_SUCCESS;
1570 }
1571
1572 for (dsn_num = 0; dsn_num < 5; dsn_num++) {
1573 if (ast_strlen_zero(query->readhandle[dsn_num])) {
1574 continue;
1575 }
1576 obj = get_odbc_obj(query->readhandle[dsn_num], &dsn);
1577 if (!obj) {
1578 continue;
1579 }
1580 ast_debug(1, "Found handle %s\n", query->readhandle[dsn_num]);
1581
1582 if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
1583 release_obj_or_dsn (&obj, &dsn);
1584 continue;
1585 }
1586
1587 executed = 1;
1588
1589 res = SQLNumResultCols(stmt, &colcount);
1590 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1591 ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
1592 SQLCloseCursor(stmt);
1593 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1594 release_obj_or_dsn (&obj, &dsn);
1596 return CLI_SUCCESS;
1597 }
1598
1599 if (colcount <= 0) {
1600 SQLCloseCursor(stmt);
1601 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1602 release_obj_or_dsn (&obj, &dsn);
1603 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));
1605 return CLI_SUCCESS;
1606 }
1607
1608 res = SQLFetch(stmt);
1609 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1610 SQLCloseCursor(stmt);
1611 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1612 release_obj_or_dsn (&obj, &dsn);
1613 if (res == SQL_NO_DATA) {
1614 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));
1615 break;
1616 } else {
1617 ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1618 }
1620 return CLI_SUCCESS;
1621 }
1622 for (;;) {
1623 for (x = 0; x < colcount; x++) {
1624 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL);
1625 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
1626 snprintf(colname, sizeof(colname), "field%d", x);
1627 }
1628
1629 octetlength = 0;
1630 SQLColAttribute(stmt, x + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &octetlength);
1631
1632 res = ast_odbc_ast_str_SQLGetData(&coldata, octetlength + 1, stmt, x + 1, SQL_CHAR, &indicator);
1633 if (indicator == SQL_NULL_DATA) {
1634 ast_str_set(&coldata, 0, "(nil)");
1635 res = SQL_SUCCESS;
1636 }
1637
1638 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1639 ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
1640 SQLCloseCursor(stmt);
1641 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1642 release_obj_or_dsn (&obj, &dsn);
1644 return CLI_SUCCESS;
1645 }
1646
1647 ast_cli(a->fd, "%-20.20s %s\n", colname, ast_str_buffer(coldata));
1648 }
1649 rows++;
1650
1651 /* Get next row */
1652 res = SQLFetch(stmt);
1653 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1654 break;
1655 }
1656 ast_cli(a->fd, "%-20.20s %s\n", "----------", "----------");
1657 }
1658 SQLCloseCursor(stmt);
1659 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1660 release_obj_or_dsn (&obj, &dsn);
1661 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]);
1662 break;
1663 }
1664 release_obj_or_dsn (&obj, &dsn);
1665
1666 if (!executed) {
1667 ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
1668 }
1669 } else { /* No execution, just print out the resulting SQL */
1670 ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1671 }
1673 return CLI_SUCCESS;
1674}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition: main/cli.c:1841
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
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:1113
Main Channel structure associated with a channel.
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
static struct test_val a

References a, args, 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, generic_execute(), get_odbc_obj(), indicator, NULL, pbx_builtin_pushvar_helper(), release_obj_or_dsn(), sql_buf, and ast_cli_entry::usage.

◆ cli_odbc_write()

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

Definition at line 1676 of file func_odbc.c.

1677{
1679 AST_APP_ARG(field)[100];
1680 );
1682 AST_APP_ARG(field)[100];
1683 );
1684 struct ast_str *sql;
1685 char *char_args, *char_values, varname[15];
1686 struct acf_odbc_query *query;
1687 struct ast_channel *chan;
1688 int i;
1689
1690 switch (cmd) {
1691 case CLI_INIT:
1692 e->command = "odbc write";
1693 e->usage =
1694 "Usage: odbc write <name> <args> <value> [exec]\n"
1695 " Evaluates the SQL provided in the ODBC function <name>, and\n"
1696 " optionally executes the function. This function is intended for\n"
1697 " testing purposes. Remember to quote arguments containing spaces.\n";
1698 return NULL;
1699 case CLI_GENERATE:
1700 if (a->pos == 2) {
1701 int wordlen = strlen(a->word), which = 0;
1702 /* Complete function name */
1704 AST_RWLIST_TRAVERSE(&queries, query, list) {
1705 if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1706 if (++which > a->n) {
1707 char *res = ast_strdup(query->acf->name);
1709 return res;
1710 }
1711 }
1712 }
1714 return NULL;
1715 } else if (a->pos == 5) {
1716 static const char * const completions[] = { "exec", NULL };
1717 return ast_cli_complete(a->word, completions, a->n);
1718 } else {
1719 return NULL;
1720 }
1721 }
1722
1723 if (a->argc < 5 || a->argc > 6) {
1724 return CLI_SHOWUSAGE;
1725 }
1726
1727 sql = ast_str_thread_get(&sql_buf, 16);
1728 if (!sql) {
1729 return CLI_FAILURE;
1730 }
1731
1733 AST_RWLIST_TRAVERSE(&queries, query, list) {
1734 if (!strcmp(query->acf->name, a->argv[2])) {
1735 break;
1736 }
1737 }
1738
1739 if (!query) {
1740 ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1742 return CLI_SHOWUSAGE;
1743 }
1744
1745 if (!query->sql_write) {
1746 ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
1748 return CLI_SUCCESS;
1749 }
1750
1751 /* FIXME: The code below duplicates code found in acf_odbc_write but
1752 * lacks the newer sql_insert additions. */
1753
1754 ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300);
1755
1756 /* Evaluate function */
1757 char_args = ast_strdupa(a->argv[3]);
1758 char_values = ast_strdupa(a->argv[4]);
1759
1760 chan = ast_dummy_channel_alloc();
1761 if (!chan) {
1763 return CLI_FAILURE;
1764 }
1765
1766 AST_STANDARD_APP_ARGS(args, char_args);
1767 for (i = 0; i < args.argc; i++) {
1768 snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1769 pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1770 }
1771
1772 /* Parse values, just like arguments */
1773 AST_STANDARD_APP_ARGS(values, char_values);
1774 for (i = 0; i < values.argc; i++) {
1775 snprintf(varname, sizeof(varname), "VAL%d", i + 1);
1776 pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
1777 }
1778
1779 /* Additionally set the value as a whole (but push an empty string if value is NULL) */
1780 pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
1781 ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
1782 ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
1783
1784 chan = ast_channel_unref(chan);
1785
1786 if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
1787 /* Execute the query */
1788 struct odbc_obj *obj = NULL;
1789 struct dsn *dsn = NULL;
1790 int dsn_num, executed = 0;
1791 SQLHSTMT stmt;
1792 SQLLEN rows = -1;
1793
1794 for (dsn_num = 0; dsn_num < 5; dsn_num++) {
1795 if (ast_strlen_zero(query->writehandle[dsn_num])) {
1796 continue;
1797 }
1798 obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
1799 if (!obj) {
1800 continue;
1801 }
1802 if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
1803 release_obj_or_dsn (&obj, &dsn);
1804 continue;
1805 }
1806
1807 SQLRowCount(stmt, &rows);
1808 SQLCloseCursor(stmt);
1809 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1810 release_obj_or_dsn (&obj, &dsn);
1811 ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn_num, query->writehandle[dsn_num]);
1812 executed = 1;
1813 break;
1814 }
1815
1816 if (!executed) {
1817 ast_cli(a->fd, "Failed to execute query.\n");
1818 }
1819 } else { /* No execution, just print out the resulting SQL */
1820 ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1821 }
1823 return CLI_SUCCESS;
1824}
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80

References a, args, 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, generic_execute(), get_odbc_obj(), NULL, pbx_builtin_pushvar_helper(), release_obj_or_dsn(), S_OR, sql_buf, and ast_cli_entry::usage.

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

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

References ast_odbc_direct_execute(), odbc_obj::con, dsn::connection, and silent_execute().

Referenced by get_dsn().

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

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

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

Referenced by get_dsn().

◆ dsn_cmp()

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

Definition at line 198 of file func_odbc.c.

199{
200 const struct dsn *object_left = obj;
201 const struct dsn *object_right = arg;
202 const char *right_key = arg;
203 int cmp;
204
205 switch (flags & OBJ_SEARCH_MASK) {
207 right_key = object_right->name;
208 /* Fall through */
209 case OBJ_SEARCH_KEY:
210 cmp = strcmp(object_left->name, right_key);
211 break;
213 cmp = strncmp(object_left->name, right_key, strlen(right_key));
214 break;
215 default:
216 cmp = 0;
217 break;
218 }
219
220 if (cmp) {
221 return 0;
222 }
223
224 return CMP_MATCH;
225}
@ CMP_MATCH
Definition: astobj2.h:1027
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101

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

◆ dsn_destructor()

static void dsn_destructor ( void *  obj)
static

Definition at line 227 of file func_odbc.c.

228{
229 struct dsn *dsn = obj;
230
231 if (dsn->connection) {
233 }
234}
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:804

References ast_odbc_release_obj(), and dsn::connection.

Referenced by create_dsn().

◆ dsn_hash()

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

Definition at line 178 of file func_odbc.c.

179{
180 const struct dsn *object;
181 const char *key;
182
183 switch (flags & OBJ_SEARCH_MASK) {
184 case OBJ_SEARCH_KEY:
185 key = obj;
186 break;
188 object = obj;
189 key = object->name;
190 break;
191 default:
192 ast_assert(0);
193 return 0;
194 }
195 return ast_str_hash(key);
196}
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
#define ast_assert(a)
Definition: utils.h:739

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

Referenced by load_module(), and reload().

◆ exec_odbcfinish()

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

Definition at line 1206 of file func_odbc.c.

1207{
1208 struct ast_datastore *store;
1209
1210 ast_channel_lock(chan);
1211 store = ast_channel_datastore_find(chan, &odbc_info, data);
1212 if (store) {
1213 ast_channel_datastore_remove(chan, store);
1214 ast_datastore_free(store);
1215 }
1216 ast_channel_unlock(chan);
1217 return 0;
1218}

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_free(), ast_datastore::data, and odbc_info.

Referenced by load_module().

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

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

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

Referenced by ast_register_application2(), generic_execute(), load_pbx_builtins(), and silent_execute().

◆ free_acf_query()

static int free_acf_query ( struct acf_odbc_query query)
static

Definition at line 1220 of file func_odbc.c.

1221{
1222 if (query) {
1223 if (query->acf) {
1224 if (query->acf->name)
1225 ast_free((char *)query->acf->name);
1226 ast_string_field_free_memory(query->acf);
1227 ast_free(query->acf);
1228 }
1229 ast_free(query->sql_read);
1230 ast_free(query->sql_write);
1231 ast_free(query->sql_insert);
1232 ast_free(query);
1233 }
1234 return 0;
1235}
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374

References ast_free, and ast_string_field_free_memory.

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

◆ generic_execute()

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

Definition at line 513 of file func_odbc.c.

514{
515 return execute(obj, data, 0);
516}
static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
Common execution function for SQL queries.
Definition: func_odbc.c:471

References odbc_datastore_row::data, and execute().

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

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

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

Definition at line 322 of file func_odbc.c.

323{
324 struct dsn *dsn;
325
326 if (!dsns) {
327 return NULL;
328 }
329
330 ao2_lock(dsns);
332 if (!dsn) {
334 }
336
337 if (!dsn) {
338 return NULL;
339 }
340
341 ao2_lock(dsn);
342 if (!dsn->connection) {
344 if (!dsn->connection) {
346 ao2_ref(dsn, -1);
347 return NULL;
348 }
349 return dsn;
350 }
351
355 if (!dsn->connection) {
357 ao2_ref(dsn, -1);
358 return NULL;
359 }
360 }
361
362 return dsn;
363}
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
static int connection_dead(struct odbc_obj *connection)
Determine if the connection has died.
Definition: func_odbc.c:282
static struct dsn * create_dsn(const char *name)
Create a DSN and connect to the database.
Definition: func_odbc.c:243

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

Referenced by get_odbc_obj().

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

377{
378 struct odbc_obj *obj = NULL;
379
382 if (dsn) {
383 *dsn = get_dsn(dsn_name);
384 if (*dsn) {
385 obj = (*dsn)->connection;
386 }
387 }
388 } else {
389 obj = ast_odbc_request_obj(dsn_name, 0);
390 }
392
393 return obj;
394}
static ast_rwlock_t single_db_connection_lock
Definition: func_odbc.c:124
static struct dsn * get_dsn(const char *name)
Retrieve a DSN, or create it if it does not exist.
Definition: func_odbc.c:322
static int single_db_connection
Definition: func_odbc.c:122
#define ast_rwlock_rdlock(a)
Definition: lock.h:235
#define ast_rwlock_unlock(a)
Definition: lock.h:234

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

◆ init_acf_query()

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

Definition at line 1237 of file func_odbc.c.

1238{
1239 const char *tmp;
1240 const char *tmp2 = NULL;
1241 int i;
1242
1243 if (!cfg || !catg) {
1244 return EINVAL;
1245 }
1246
1247 if (!(*query = ast_calloc(1, sizeof(**query)))) {
1248 return ENOMEM;
1249 }
1250
1251 if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
1252 char *tmp2 = ast_strdupa(tmp);
1253 AST_DECLARE_APP_ARGS(writeconf,
1254 AST_APP_ARG(dsn)[5];
1255 );
1256 AST_STANDARD_APP_ARGS(writeconf, tmp2);
1257 for (i = 0; i < 5; i++) {
1258 if (!ast_strlen_zero(writeconf.dsn[i]))
1259 ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
1260 }
1261 }
1262
1263 if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
1264 char *tmp2 = ast_strdupa(tmp);
1265 AST_DECLARE_APP_ARGS(readconf,
1266 AST_APP_ARG(dsn)[5];
1267 );
1268 AST_STANDARD_APP_ARGS(readconf, tmp2);
1269 for (i = 0; i < 5; i++) {
1270 if (!ast_strlen_zero(readconf.dsn[i]))
1271 ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
1272 }
1273 } else {
1274 /* If no separate readhandle, then use the writehandle for reading */
1275 for (i = 0; i < 5; i++) {
1276 if (!ast_strlen_zero((*query)->writehandle[i]))
1277 ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
1278 }
1279 }
1280
1281 if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")) ||
1282 (tmp2 = ast_variable_retrieve(cfg, catg, "read"))) {
1283 if (!tmp) {
1284 ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg);
1285 tmp = tmp2;
1286 }
1287 if (*tmp != '\0') { /* non-empty string */
1288 if (!((*query)->sql_read = ast_strdup(tmp))) {
1289 free_acf_query(*query);
1290 *query = NULL;
1291 return ENOMEM;
1292 }
1293 }
1294 }
1295
1296 if ((*query)->sql_read && ast_strlen_zero((*query)->readhandle[0])) {
1297 free_acf_query(*query);
1298 *query = NULL;
1299 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
1300 return EINVAL;
1301 }
1302
1303 if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")) ||
1304 (tmp2 = ast_variable_retrieve(cfg, catg, "write"))) {
1305 if (!tmp) {
1306 ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg);
1307 tmp = tmp2;
1308 }
1309 if (*tmp != '\0') { /* non-empty string */
1310 if (!((*query)->sql_write = ast_strdup(tmp))) {
1311 free_acf_query(*query);
1312 *query = NULL;
1313 return ENOMEM;
1314 }
1315 }
1316 }
1317
1318 if ((*query)->sql_write && ast_strlen_zero((*query)->writehandle[0])) {
1319 free_acf_query(*query);
1320 *query = NULL;
1321 ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
1322 return EINVAL;
1323 }
1324
1325 if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
1326 if (*tmp != '\0') { /* non-empty string */
1327 if (!((*query)->sql_insert = ast_strdup(tmp))) {
1328 free_acf_query(*query);
1329 *query = NULL;
1330 return ENOMEM;
1331 }
1332 }
1333 }
1334
1335 /* Allow escaping of embedded commas in fields to be turned off */
1336 ast_set_flag((*query), OPT_ESCAPECOMMAS);
1337 if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
1338 if (ast_false(tmp))
1340 }
1341
1342 if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
1343 if (strcasecmp(tmp, "multirow") == 0)
1344 ast_set_flag((*query), OPT_MULTIROW);
1345 if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
1346 sscanf(tmp, "%30d", &((*query)->rowlimit));
1347 }
1348
1349 if ((tmp = ast_variable_retrieve(cfg, catg, "minargs"))) {
1350 sscanf(tmp, "%30d", &((*query)->minargs));
1351 }
1352
1353 (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
1354 if (!(*query)->acf) {
1355 free_acf_query(*query);
1356 *query = NULL;
1357 return ENOMEM;
1358 }
1359 if (ast_string_field_init((*query)->acf, 128)) {
1360 free_acf_query(*query);
1361 *query = NULL;
1362 return ENOMEM;
1363 }
1364
1365 if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
1366 if (ast_asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
1367 (*query)->acf->name = NULL;
1368 }
1369 } else {
1370 if (ast_asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
1371 (*query)->acf->name = NULL;
1372 }
1373 }
1374
1375 if (!(*query)->acf->name) {
1376 free_acf_query(*query);
1377 *query = NULL;
1378 return ENOMEM;
1379 }
1380
1381 if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) {
1382 ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp);
1383 } else {
1384 ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name);
1385 }
1386
1387 if (ast_strlen_zero((*query)->acf->syntax)) {
1388 free_acf_query(*query);
1389 *query = NULL;
1390 return ENOMEM;
1391 }
1392
1393 if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) {
1394 ast_string_field_set((*query)->acf, synopsis, tmp);
1395 } else {
1396 ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments");
1397 }
1398
1399 if (ast_strlen_zero((*query)->acf->synopsis)) {
1400 free_acf_query(*query);
1401 *query = NULL;
1402 return ENOMEM;
1403 }
1404
1405 if ((*query)->sql_read && (*query)->sql_write) {
1406 ast_string_field_build((*query)->acf, desc,
1407 "Runs the following query, as defined in func_odbc.conf, performing\n"
1408 "substitution of the arguments into the query as specified by ${ARG1},\n"
1409 "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n"
1410 "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1411 "%s"
1412 "\nRead:\n%s\n\nWrite:\n%s%s%s",
1413 (*query)->sql_insert ?
1414 "If the write query affects no rows, the insert query will be\n"
1415 "performed.\n" : "",
1416 (*query)->sql_read,
1417 (*query)->sql_write,
1418 (*query)->sql_insert ? "\n\nInsert:\n" : "",
1419 (*query)->sql_insert ? (*query)->sql_insert : "");
1420 } else if ((*query)->sql_read) {
1421 ast_string_field_build((*query)->acf, desc,
1422 "Runs the following query, as defined in func_odbc.conf, performing\n"
1423 "substitution of the arguments into the query as specified by ${ARG1},\n"
1424 "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s",
1425 (*query)->sql_read);
1426 } else if ((*query)->sql_write) {
1427 ast_string_field_build((*query)->acf, desc,
1428 "Runs the following query, as defined in func_odbc.conf, performing\n"
1429 "substitution of the arguments into the query as specified by ${ARG1},\n"
1430 "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n"
1431 "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1432 "This function may only be set.\n%s\nSQL:\n%s%s%s",
1433 (*query)->sql_insert ?
1434 "If the write query affects no rows, the insert query will be\n"
1435 "performed.\n" : "",
1436 (*query)->sql_write,
1437 (*query)->sql_insert ? "\n\nInsert:\n" : "",
1438 (*query)->sql_insert ? (*query)->sql_insert : "");
1439 } else {
1440 free_acf_query(*query);
1441 *query = NULL;
1442 ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute. Ignoring.\n", catg);
1443 return EINVAL;
1444 }
1445
1446 if (ast_strlen_zero((*query)->acf->desc)) {
1447 free_acf_query(*query);
1448 *query = NULL;
1449 return ENOMEM;
1450 }
1451
1452 if ((*query)->sql_read) {
1453 (*query)->acf->read = acf_odbc_read;
1454 }
1455
1456 if ((*query)->sql_write) {
1457 (*query)->acf->write = acf_odbc_write;
1458 }
1459
1460 return 0;
1461}
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
static const char desc[]
Definition: cdr_radius.c:84
static char * synopsis
Definition: func_enum.c:154
static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
Definition: func_odbc.c:526
static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
Definition: func_odbc.c:742
static int free_acf_query(struct acf_odbc_query *query)
Definition: func_odbc.c:1220
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70

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

◆ load_module()

static int load_module ( void  )
static

Definition at line 1831 of file func_odbc.c.

1832{
1833 int res = 0;
1834 struct ast_config *cfg;
1835 char *catg;
1836 const char *s;
1837 struct ast_flags config_flags = { 0 };
1838
1841
1842 cfg = ast_config_load(config, config_flags);
1843 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1844 ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
1846 }
1847
1849 if ((s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) {
1851 } else {
1853 }
1854
1855 dsns = NULL;
1856
1860 if (!dsns) {
1861 ast_log(LOG_ERROR, "Could not initialize DSN container\n");
1864 }
1865 }
1867
1869 for (catg = ast_category_browse(cfg, NULL);
1870 catg;
1871 catg = ast_category_browse(cfg, catg)) {
1872 struct acf_odbc_query *query = NULL;
1873 int err;
1874
1875 if (!strcasecmp(catg, "general")) {
1876 continue;
1877 }
1878
1879 if ((err = init_acf_query(cfg, catg, &query))) {
1880 if (err == ENOMEM)
1881 ast_log(LOG_ERROR, "Out of memory\n");
1882 else if (err == EINVAL)
1883 ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
1884 else
1885 ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
1886 } else {
1887 AST_RWLIST_INSERT_HEAD(&queries, query, list);
1888 ast_custom_function_register(query->acf);
1889 }
1890 }
1891
1892 ast_config_destroy(cfg);
1896
1898 return res;
1899}
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static struct ast_custom_function escape_function
Definition: func_odbc.c:1143
static int exec_odbcfinish(struct ast_channel *chan, const char *data)
Definition: func_odbc.c:1206
static struct ast_custom_function escape_backslashes_function
Definition: func_odbc.c:1154
static struct ast_custom_function fetch_function
Definition: func_odbc.c:1198
static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
Definition: func_odbc.c:1237
static int dsn_cmp(void *obj, void *arg, int flags)
Definition: func_odbc.c:198
static char * config
Definition: func_odbc.c:118
#define DEFAULT_SINGLE_DB_CONNECTION
Definition: func_odbc.c:120
static int dsn_hash(const void *obj, const int flags)
Definition: func_odbc.c:178
static char * app_odbcfinish
Definition: func_odbc.c:1204
#define DSN_BUCKETS
Definition: func_odbc.c:174
static struct ast_cli_entry cli_func_odbc[]
Definition: func_odbc.c:1826
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
#define LOG_NOTICE
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
#define ast_rwlock_wrlock(a)
Definition: lock.h:236
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
Structure used to handle boolean flags.
Definition: utils.h:199
#define ARRAY_LEN(a)
Definition: utils.h:666

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, 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, ast_rwlock_unlock, ast_rwlock_wrlock, ast_true(), ast_variable_retrieve(), cli_func_odbc, config, CONFIG_STATUS_FILEINVALID, DEFAULT_SINGLE_DB_CONNECTION, DSN_BUCKETS, dsn_cmp(), dsn_hash(), dsns, escape_backslashes_function, escape_function, exec_odbcfinish(), fetch_function, init_acf_query(), LOG_ERROR, LOG_NOTICE, NULL, single_db_connection, and single_db_connection_lock.

◆ odbc_datastore_free()

static void odbc_datastore_free ( void *  data)
static

Definition at line 444 of file func_odbc.c.

445{
446 struct odbc_datastore *result = data;
447 struct odbc_datastore_row *row;
448
449 if (!result) {
450 return;
451 }
452
454 while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
455 ast_free(row);
456 }
460}
static PGresult * result
Definition: cel_pgsql.c:84
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653

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

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

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

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

◆ reload()

static int reload ( void  )
static

Definition at line 1932 of file func_odbc.c.

1933{
1934 int res = 0;
1935 struct ast_config *cfg;
1936 struct acf_odbc_query *oldquery;
1937 char *catg;
1938 const char *s;
1939 struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
1940
1941 cfg = ast_config_load(config, config_flags);
1943 return 0;
1944
1946
1947 if (dsns) {
1948 ao2_ref(dsns, -1);
1949 dsns = NULL;
1950 }
1951
1952 if (cfg && (s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) {
1954 } else {
1956 }
1957
1961 if (!dsns) {
1962 ast_log(LOG_ERROR, "Could not initialize DSN container\n");
1964 return 0;
1965 }
1966 }
1968
1970
1971 while (!AST_RWLIST_EMPTY(&queries)) {
1972 oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
1973 ast_custom_function_unregister(oldquery->acf);
1974 free_acf_query(oldquery);
1975 }
1976
1977 if (!cfg) {
1978 ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
1979 goto reload_out;
1980 }
1981
1982 for (catg = ast_category_browse(cfg, NULL);
1983 catg;
1984 catg = ast_category_browse(cfg, catg)) {
1985 struct acf_odbc_query *query = NULL;
1986
1987 if (!strcasecmp(catg, "general")) {
1988 continue;
1989 }
1990
1991 if (init_acf_query(cfg, catg, &query)) {
1992 ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
1993 } else {
1994 AST_RWLIST_INSERT_HEAD(&queries, query, list);
1995 ast_custom_function_register(query->acf);
1996 }
1997 }
1998
1999 ast_config_destroy(cfg);
2000reload_out:
2002 return res;
2003}
#define CONFIG_STATUS_FILEUNCHANGED
@ CONFIG_FLAG_FILEUNCHANGED
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:452
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:844
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

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_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(), config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_SINGLE_DB_CONNECTION, DSN_BUCKETS, dsn_cmp(), dsn_hash(), dsns, free_acf_query(), init_acf_query(), LOG_ERROR, LOG_WARNING, NULL, single_db_connection, and single_db_connection_lock.

◆ silent_execute()

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

Definition at line 518 of file func_odbc.c.

519{
520 return execute(obj, data, 1);
521}

References odbc_datastore_row::data, and execute().

Referenced by connection_dead().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1901 of file func_odbc.c.

1902{
1903 struct acf_odbc_query *query;
1904 int res = 0;
1905
1907 while (!AST_RWLIST_EMPTY(&queries)) {
1908 query = AST_RWLIST_REMOVE_HEAD(&queries, list);
1910 free_acf_query(query);
1911 }
1912
1918
1919 /* Allow any threads waiting for this lock to pass (avoids a race) */
1921 usleep(1);
1923
1925
1926 if (dsns) {
1927 ao2_ref(dsns, -1);
1928 }
1929 return res;
1930}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

References ao2_ref, 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, dsns, escape_backslashes_function, escape_function, fetch_function, and free_acf_query().

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

Definition at line 2013 of file func_odbc.c.

◆ app_odbcfinish

char* app_odbcfinish = "ODBCFinish"
static

Definition at line 1204 of file func_odbc.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2013 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_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1676
static char * cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1463

Definition at line 1826 of file func_odbc.c.

Referenced by load_module(), and unload_module().

◆ coldata_buf

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

Definition at line 439 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 440 of file func_odbc.c.

Referenced by acf_odbc_read().

◆ config

char* config = "func_odbc.conf"
static

Definition at line 118 of file func_odbc.c.

Referenced by load_module(), and reload().

◆ dsns

struct ao2_container* dsns

Definition at line 176 of file func_odbc.c.

Referenced by create_dsn(), get_dsn(), load_module(), reload(), and unload_module().

◆ escape_backslashes_function

struct ast_custom_function escape_backslashes_function
static
Initial value:
= {
.name = "SQL_ESC_BACKSLASHES",
.write = NULL,
}
static int acf_escape_backslashes(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1149

Definition at line 1154 of file func_odbc.c.

Referenced by load_module(), and unload_module().

◆ escape_function

struct ast_custom_function escape_function
static
Initial value:
= {
.name = "SQL_ESC",
.write = NULL,
}
static int acf_escape_ticks(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1138

Definition at line 1143 of file func_odbc.c.

Referenced by load_module(), and unload_module().

◆ fetch_function

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

Definition at line 1198 of file func_odbc.c.

Referenced by load_module(), and unload_module().

◆ odbc_info

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

Definition at line 146 of file func_odbc.c.

Referenced by acf_fetch(), acf_odbc_read(), and exec_odbcfinish().

◆ queries

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

◆ resultcount

int resultcount = 0
static

Definition at line 435 of file func_odbc.c.

Referenced by acf_odbc_read().

◆ single_db_connection

int single_db_connection
static

Definition at line 122 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 124 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 438 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 437 of file func_odbc.c.

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