Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 134 of file func_odbc.c.

◆ DSN_BUCKETS

#define DSN_BUCKETS   37

Definition at line 188 of file func_odbc.c.

Enumeration Type Documentation

◆ odbc_option_flags

Enumerator
OPT_ESCAPECOMMAS 
OPT_MULTIROW 

Definition at line 140 of file func_odbc.c.

140 {
141 OPT_ESCAPECOMMAS = (1 << 0),
142 OPT_MULTIROW = (1 << 1),
143};
@ OPT_ESCAPECOMMAS
Definition: func_odbc.c:141
@ OPT_MULTIROW
Definition: func_odbc.c:142

Function Documentation

◆ __init_coldata_buf()

static void __init_coldata_buf ( void  )
static

Definition at line 453 of file func_odbc.c.

459{

◆ __init_colnames_buf()

static void __init_colnames_buf ( void  )
static

Definition at line 454 of file func_odbc.c.

459{

◆ __init_sql2_buf()

static void __init_sql2_buf ( void  )
static

Definition at line 452 of file func_odbc.c.

459{

◆ __init_sql_buf()

static void __init_sql_buf ( void  )
static

Definition at line 451 of file func_odbc.c.

459{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2027 of file func_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

1137{
1138 char *out = buf;
1139
1140 for (; *data && out - buf < len; data++) {
1141 if (*data == character) {
1142 *out = character;
1143 out++;
1144 }
1145 *out++ = *data;
1146 }
1147 *out = '\0';
1148
1149 return 0;
1150}
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 1163 of file func_odbc.c.

1164{
1165 return acf_escape(chan, cmd, data, buf, len, '\\');
1166}
static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len, char character)
Definition: func_odbc.c:1136

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

1153{
1154 return acf_escape(chan, cmd, data, buf, len, '\'');
1155}

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

1175{
1176 struct ast_datastore *store;
1177 struct odbc_datastore *resultset;
1178 struct odbc_datastore_row *row;
1179
1180 if (!chan) {
1181 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1182 return -1;
1183 }
1184
1185 ast_channel_lock(chan);
1186 store = ast_channel_datastore_find(chan, &odbc_info, data);
1187 if (!store) {
1188 ast_channel_unlock(chan);
1189 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
1190 return -1;
1191 }
1192 resultset = store->data;
1193 AST_LIST_LOCK(resultset);
1194 row = AST_LIST_REMOVE_HEAD(resultset, list);
1195 AST_LIST_UNLOCK(resultset);
1196 if (!row) {
1197 /* Cleanup datastore */
1198 ast_channel_datastore_remove(chan, store);
1199 ast_datastore_free(store);
1200 ast_channel_unlock(chan);
1201 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
1202 return -1;
1203 }
1204 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
1205 ast_channel_unlock(chan);
1206 ast_copy_string(buf, row->data, len);
1207 ast_free(row);
1208 pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
1209 return 0;
1210}
#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:2423
#define ast_channel_lock(chan)
Definition: channel.h:2970
#define ast_channel_unlock(chan)
Definition: channel.h:2971
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:2428
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:160
#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:174

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

757{
758 struct odbc_obj *obj = NULL;
759 struct acf_odbc_query *query;
760 char varname[15], rowcount[12] = "-1";
761 struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
762 int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn_num, bogus_chan = 0;
764 AST_APP_ARG(field)[100];
765 );
766 SQLHSTMT stmt = NULL;
767 SQLSMALLINT colcount=0;
768 SQLLEN indicator;
769 SQLSMALLINT collength;
770 struct odbc_datastore *resultset = NULL;
771 struct odbc_datastore_row *row = NULL;
772 struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
773 const char *status = "FAILURE";
774 struct dsn *dsn = NULL;
775
776 if (!sql || !colnames) {
777 if (chan) {
778 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
779 }
780 return -1;
781 }
782
783 ast_str_reset(colnames);
784
786 AST_RWLIST_TRAVERSE(&queries, query, list) {
787 if (!strcmp(query->acf->name, cmd)) {
788 break;
789 }
790 }
791
792 if (!query) {
793 ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
795 if (chan) {
796 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
797 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
798 }
799 return -1;
800 }
801
803 if (args.argc < query->minargs) {
804 ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
805 args.argc, cmd, query->minargs);
807 return -1;
808 }
809
810 if (!chan) {
811 if (!(chan = ast_dummy_channel_alloc())) {
813 return -1;
814 }
815 bogus_chan = 1;
816 }
817
818 if (!bogus_chan) {
820 }
821
822 snprintf(varname, sizeof(varname), "%u", args.argc);
823 pbx_builtin_pushvar_helper(chan, "ARGC", varname);
824 for (x = 0; x < args.argc; x++) {
825 snprintf(varname, sizeof(varname), "ARG%d", x + 1);
826 pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
827 }
828
829 ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
830
831 if (bogus_chan) {
832 chan = ast_channel_unref(chan);
833 } else {
834 /* Restore prior values */
835 pbx_builtin_setvar_helper(chan, "ARGC", NULL);
836
837 for (x = 0; x < args.argc; x++) {
838 snprintf(varname, sizeof(varname), "ARG%d", x + 1);
839 pbx_builtin_setvar_helper(chan, varname, NULL);
840 }
841 }
842
843 /* Save these flags, so we can release the lock */
844 escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
845 if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) {
846 if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
847 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
848 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
851 return -1;
852 }
853 AST_LIST_HEAD_INIT(resultset);
854 if (query->rowlimit) {
855 rowlimit = query->rowlimit;
856 } else {
857 rowlimit = INT_MAX;
858 }
859 multirow = 1;
860 } else if (!bogus_chan) {
861 if (query->rowlimit > 1) {
862 rowlimit = query->rowlimit;
863 if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
864 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
865 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
868 return -1;
869 }
870 AST_LIST_HEAD_INIT(resultset);
871 }
872 }
874
875 for (dsn_num = 0; dsn_num < 5; dsn_num++) {
876 if (!ast_strlen_zero(query->readhandle[dsn_num])) {
877 obj = get_odbc_obj(query->readhandle[dsn_num], &dsn);
878 if (!obj) {
879 continue;
880 }
882 }
883 if (stmt) {
884 break;
885 }
886 release_obj_or_dsn (&obj, &dsn);
887 }
888
889 if (!stmt) {
890 ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
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 res = SQLNumResultCols(stmt, &colcount);
901 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
902 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
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", rowcount);
909 }
910 odbc_datastore_free(resultset);
911 return -1;
912 }
913
914 if (colcount <= 0) {
915 ast_verb(4, "Returned %d columns [%s]\n", colcount, ast_str_buffer(sql));
916 buf[0] = '\0';
917 SQLCloseCursor(stmt);
918 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
919 release_obj_or_dsn (&obj, &dsn);
920 if (!bogus_chan) {
921 pbx_builtin_setvar_helper(chan, "ODBCROWS", "0");
922 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "NODATA");
924 }
925 odbc_datastore_free(resultset);
926 return 0;
927 }
928
929 res = SQLFetch(stmt);
930 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
931 int res1 = -1;
932 if (res == SQL_NO_DATA) {
933 ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
934 res1 = 0;
935 buf[0] = '\0';
936 ast_copy_string(rowcount, "0", sizeof(rowcount));
937 status = "NODATA";
938 } else {
939 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
940 status = "FETCHERROR";
941 }
942 SQLCloseCursor(stmt);
943 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
944 release_obj_or_dsn (&obj, &dsn);
945 if (!bogus_chan) {
946 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
947 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
949 }
950 odbc_datastore_free(resultset);
951 return res1;
952 }
953
954 status = "SUCCESS";
955
956 for (y = 0; y < rowlimit; y++) {
957 buf[0] = '\0';
958 for (x = 0; x < colcount; x++) {
959 int i;
960 struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
961 char *ptrcoldata;
962
963 if (!coldata) {
964 odbc_datastore_free(resultset);
965 SQLCloseCursor(stmt);
966 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
967 release_obj_or_dsn (&obj, &dsn);
968 if (!bogus_chan) {
969 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
971 }
972 return -1;
973 }
974
975 if (y == 0) {
976 char colname[256];
977 SQLLEN octetlength = 0;
978
979 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL);
980 ast_debug(3, "Got collength of %d for column '%s' (offset %d)\n", (int)collength, colname, x);
981 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
982 snprintf(colname, sizeof(colname), "field%d", x);
983 }
984
985 SQLColAttribute(stmt, x + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &octetlength);
986
987 ast_str_make_space(&coldata, octetlength + 1);
988
989 if (ast_str_strlen(colnames)) {
990 ast_str_append(&colnames, 0, ",");
991 }
992 ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
993
994 if (resultset) {
995 void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
996 if (!tmp) {
997 ast_log(LOG_ERROR, "No space for a new resultset?\n");
998 odbc_datastore_free(resultset);
999 SQLCloseCursor(stmt);
1000 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1001 release_obj_or_dsn (&obj, &dsn);
1002 if (!bogus_chan) {
1003 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
1004 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
1006 }
1007 return -1;
1008 }
1009 resultset = tmp;
1010 strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
1011 }
1012 }
1013
1014 buflen = strlen(buf);
1015 res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
1016 if (indicator == SQL_NULL_DATA) {
1017 ast_debug(3, "Got NULL data\n");
1018 ast_str_reset(coldata);
1019 res = SQL_SUCCESS;
1020 }
1021
1022 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1023 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
1024 y = -1;
1025 buf[0] = '\0';
1026 goto end_acf_read;
1027 }
1028
1029 ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
1030
1031 if (x) {
1032 buf[buflen++] = ',';
1033 }
1034
1035 /* Copy data, encoding '\' and ',' for the argument parser */
1036 ptrcoldata = ast_str_buffer(coldata);
1037 for (i = 0; i < ast_str_strlen(coldata); i++) {
1038 if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
1039 buf[buflen++] = '\\';
1040 }
1041 buf[buflen++] = ptrcoldata[i];
1042
1043 if (buflen >= len - 2) {
1044 break;
1045 }
1046
1047 if (ptrcoldata[i] == '\0') {
1048 break;
1049 }
1050 }
1051
1052 buf[buflen] = '\0';
1053 ast_debug(2, "buf is now set to '%s'\n", buf);
1054 }
1055 ast_debug(2, "buf is now set to '%s'\n", buf);
1056
1057 if (resultset) {
1058 row = ast_calloc(1, sizeof(*row) + buflen + 1);
1059 if (!row) {
1060 ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
1061 status = "MEMERROR";
1062 goto end_acf_read;
1063 }
1064 strcpy((char *)row + sizeof(*row), buf);
1065 AST_LIST_INSERT_TAIL(resultset, row, list);
1066
1067 /* Get next row */
1068 res = SQLFetch(stmt);
1069 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1070 if (res != SQL_NO_DATA) {
1071 ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1072 }
1073 /* Number of rows in the resultset */
1074 y++;
1075 break;
1076 }
1077 }
1078 }
1079
1080end_acf_read:
1081 if (!bogus_chan) {
1082 snprintf(rowcount, sizeof(rowcount), "%d", y);
1083 pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
1084 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
1085 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
1086 if (resultset) {
1087 struct ast_datastore *odbc_store;
1088 if (multirow) {
1089 int uid;
1091 snprintf(buf, len, "%d", uid);
1092 } else {
1093 /* Name of the query is name of the resultset */
1094 ast_copy_string(buf, cmd, len);
1095
1096 /* If there's one with the same name already, free it */
1097 ast_channel_lock(chan);
1098 if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) {
1099 ast_channel_datastore_remove(chan, odbc_store);
1100 ast_datastore_free(odbc_store);
1101 }
1102 ast_channel_unlock(chan);
1103 }
1104 odbc_store = ast_datastore_alloc(&odbc_info, buf);
1105 if (!odbc_store) {
1106 ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n");
1107 odbc_datastore_free(resultset);
1108 SQLCloseCursor(stmt);
1109 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1110 release_obj_or_dsn (&obj, &dsn);
1111 pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
1113 return -1;
1114 }
1115 odbc_store->data = resultset;
1116 ast_channel_lock(chan);
1117 ast_channel_datastore_add(chan, odbc_store);
1118 ast_channel_unlock(chan);
1119 }
1120 }
1121 SQLCloseCursor(stmt);
1122 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1123 release_obj_or_dsn (&obj, &dsn);
1124 if (resultset && !multirow) {
1125 /* Fetch the first resultset */
1126 if (!acf_fetch(chan, "", buf, buf, len)) {
1127 buf[0] = '\0';
1128 }
1129 }
1130 if (!bogus_chan) {
1132 }
1133 return 0;
1134}
jack_status_t status
Definition: app_jack.c:149
#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
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:2414
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:3006
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1328
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:527
static struct ast_threadstorage colnames_buf
Definition: func_odbc.c:454
static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1174
static void odbc_datastore_free(void *data)
Definition: func_odbc.c:458
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:390
static struct ast_threadstorage coldata_buf
Definition: func_odbc.c:453
static int resultcount
Definition: func_odbc.c:449
static void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
Release an ODBC obj or a DSN.
Definition: func_odbc.c:419
static struct ast_threadstorage sql_buf
Definition: func_odbc.c:451
#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:761
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:181
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, 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 540 of file func_odbc.c.

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

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

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

297{
298 SQLINTEGER dead;
299 SQLRETURN res;
300 SQLHSTMT stmt;
301
302 if (!connection) {
303 return 1;
304 }
305
306 res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0);
307 if (SQL_SUCCEEDED(res)) {
308 return dead == SQL_CD_TRUE ? 1 : 0;
309 }
310
311 /* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a direct
312 * execute of a probing statement and see if that succeeds instead
313 */
314 stmt = ast_odbc_direct_execute(connection, silent_execute, "SELECT 1");
315 if (!stmt) {
316 return 1;
317 }
318
319 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
320 return 0;
321}
static SQLHSTMT silent_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:532
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 257 of file func_odbc.c.

258{
259 struct dsn *dsn;
260
261 if (!dsns) {
262 return NULL;
263 }
264
265 dsn = ao2_alloc(sizeof(*dsn) + strlen(name) + 1, dsn_destructor);
266 if (!dsn) {
267 return NULL;
268 }
269
270 /* Safe */
271 strcpy(dsn->name, name);
272
274 if (!dsn->connection) {
275 ao2_ref(dsn, -1);
276 return NULL;
277 }
278
280 ao2_ref(dsn, -1);
281 return NULL;
282 }
283
284 return dsn;
285}
#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:190
static void dsn_destructor(void *obj)
Definition: func_odbc.c:241
#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:183
char name[0]
Definition: func_odbc.c:185

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

213{
214 const struct dsn *object_left = obj;
215 const struct dsn *object_right = arg;
216 const char *right_key = arg;
217 int cmp;
218
219 switch (flags & OBJ_SEARCH_MASK) {
221 right_key = object_right->name;
222 /* Fall through */
223 case OBJ_SEARCH_KEY:
224 cmp = strcmp(object_left->name, right_key);
225 break;
227 cmp = strncmp(object_left->name, right_key, strlen(right_key));
228 break;
229 default:
230 cmp = 0;
231 break;
232 }
233
234 if (cmp) {
235 return 0;
236 }
237
238 return CMP_MATCH;
239}
@ 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 241 of file func_odbc.c.

242{
243 struct dsn *dsn = obj;
244
245 if (dsn->connection) {
247 }
248}
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 192 of file func_odbc.c.

193{
194 const struct dsn *object;
195 const char *key;
196
197 switch (flags & OBJ_SEARCH_MASK) {
198 case OBJ_SEARCH_KEY:
199 key = obj;
200 break;
202 object = obj;
203 key = object->name;
204 break;
205 default:
206 ast_assert(0);
207 return 0;
208 }
209 return ast_str_hash(key);
210}
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 1220 of file func_odbc.c.

1221{
1222 struct ast_datastore *store;
1223
1224 ast_channel_lock(chan);
1225 store = ast_channel_datastore_find(chan, &odbc_info, data);
1226 if (store) {
1227 ast_channel_datastore_remove(chan, store);
1228 ast_datastore_free(store);
1229 }
1230 ast_channel_unlock(chan);
1231 return 0;
1232}

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

486{
487 int res;
488 char *sql = data;
489 SQLHSTMT stmt;
490
491 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
492 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
493 ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res);
494 return NULL;
495 }
496
497 res = ast_odbc_execute_sql(obj, stmt, sql);
498 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
499 if (res == SQL_ERROR && !silent) {
500 int i;
501 SQLINTEGER nativeerror=0, numfields=0;
502 SQLSMALLINT diagbytes=0;
503 unsigned char state[10], diagnostic[256];
504
505 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
506 for (i = 0; i < numfields; i++) {
507 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
508 ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
509 if (i > 10) {
510 ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
511 break;
512 }
513 }
514 }
515
516 if (!silent) {
517 ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql);
518 }
519 SQLCloseCursor(stmt);
520 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
521 return NULL;
522 }
523
524 return stmt;
525}
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 1234 of file func_odbc.c.

1235{
1236 if (query) {
1237 if (query->acf) {
1238 if (query->acf->name)
1239 ast_free((char *)query->acf->name);
1240 ast_string_field_free_memory(query->acf);
1241 ast_free(query->acf);
1242 }
1243 ast_free(query->sql_read);
1244 ast_free(query->sql_write);
1245 ast_free(query->sql_insert);
1246 ast_free(query);
1247 }
1248 return 0;
1249}
#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 527 of file func_odbc.c.

528{
529 return execute(obj, data, 0);
530}
static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
Common execution function for SQL queries.
Definition: func_odbc.c:485

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

337{
338 struct dsn *dsn;
339
340 if (!dsns) {
341 return NULL;
342 }
343
344 ao2_lock(dsns);
346 if (!dsn) {
348 }
350
351 if (!dsn) {
352 return NULL;
353 }
354
355 ao2_lock(dsn);
356 if (!dsn->connection) {
358 if (!dsn->connection) {
360 ao2_ref(dsn, -1);
361 return NULL;
362 }
363 return dsn;
364 }
365
369 if (!dsn->connection) {
371 ao2_ref(dsn, -1);
372 return NULL;
373 }
374 }
375
376 return dsn;
377}
#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:296
static struct dsn * create_dsn(const char *name)
Create a DSN and connect to the database.
Definition: func_odbc.c:257

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

391{
392 struct odbc_obj *obj = NULL;
393
396 if (dsn) {
397 *dsn = get_dsn(dsn_name);
398 if (*dsn) {
399 obj = (*dsn)->connection;
400 }
401 }
402 } else {
403 obj = ast_odbc_request_obj(dsn_name, 0);
404 }
406
407 return obj;
408}
static ast_rwlock_t single_db_connection_lock
Definition: func_odbc.c:138
static struct dsn * get_dsn(const char *name)
Retrieve a DSN, or create it if it does not exist.
Definition: func_odbc.c:336
static int single_db_connection
Definition: func_odbc.c:136
#define ast_rwlock_rdlock(a)
Definition: lock.h:239
#define ast_rwlock_unlock(a)
Definition: lock.h:238

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

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

Referenced by load_module(), and reload().

◆ load_module()

static int load_module ( void  )
static

Definition at line 1845 of file func_odbc.c.

1846{
1847 int res = 0;
1848 struct ast_config *cfg;
1849 char *catg;
1850 const char *s;
1851 struct ast_flags config_flags = { 0 };
1852
1855
1856 cfg = ast_config_load(config, config_flags);
1857 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1858 ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
1860 }
1861
1863 if ((s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) {
1865 } else {
1867 }
1868
1869 dsns = NULL;
1870
1874 if (!dsns) {
1875 ast_log(LOG_ERROR, "Could not initialize DSN container\n");
1878 }
1879 }
1881
1883 for (catg = ast_category_browse(cfg, NULL);
1884 catg;
1885 catg = ast_category_browse(cfg, catg)) {
1886 struct acf_odbc_query *query = NULL;
1887 int err;
1888
1889 if (!strcasecmp(catg, "general")) {
1890 continue;
1891 }
1892
1893 if ((err = init_acf_query(cfg, catg, &query))) {
1894 if (err == ENOMEM)
1895 ast_log(LOG_ERROR, "Out of memory\n");
1896 else if (err == EINVAL)
1897 ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
1898 else
1899 ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
1900 } else {
1901 AST_RWLIST_INSERT_HEAD(&queries, query, list);
1902 ast_custom_function_register(query->acf);
1903 }
1904 }
1905
1906 ast_config_destroy(cfg);
1910
1912 return res;
1913}
@ 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:1157
static int exec_odbcfinish(struct ast_channel *chan, const char *data)
Definition: func_odbc.c:1220
static struct ast_custom_function escape_backslashes_function
Definition: func_odbc.c:1168
static struct ast_custom_function fetch_function
Definition: func_odbc.c:1212
static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
Definition: func_odbc.c:1251
static int dsn_cmp(void *obj, void *arg, int flags)
Definition: func_odbc.c:212
static char * config
Definition: func_odbc.c:132
#define DEFAULT_SINGLE_DB_CONNECTION
Definition: func_odbc.c:134
static int dsn_hash(const void *obj, const int flags)
Definition: func_odbc.c:192
static char * app_odbcfinish
Definition: func_odbc.c:1218
#define DSN_BUCKETS
Definition: func_odbc.c:188
static struct ast_cli_entry cli_func_odbc[]
Definition: func_odbc.c:1840
#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:240
@ 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:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1559
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 458 of file func_odbc.c.

459{
460 struct odbc_datastore *result = data;
461 struct odbc_datastore_row *row;
462
463 if (!result) {
464 return;
465 }
466
468 while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
469 ast_free(row);
470 }
474}
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 419 of file func_odbc.c.

420{
421 if (dsn && *dsn) {
422 /* If multiple connections are not enabled then the guarantee
423 * of a single connection already exists and holding on to the
424 * connection would prevent any other user from acquiring it
425 * indefinitely.
426 */
427 if (ast_odbc_get_max_connections((*dsn)->name) < 2) {
428 ast_odbc_release_obj((*dsn)->connection);
429 (*dsn)->connection = NULL;
430 }
431 ao2_unlock(*dsn);
432 ao2_ref(*dsn, -1);
433 *dsn = NULL;
434 /* Some callers may provide both an obj and dsn. To ensure that
435 * the connection is not released twice we set it to NULL here if
436 * present.
437 */
438 if (obj) {
439 *obj = NULL;
440 }
441 } else if (obj && *obj) {
443 *obj = NULL;
444 }
445}
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 1946 of file func_odbc.c.

1947{
1948 int res = 0;
1949 struct ast_config *cfg;
1950 struct acf_odbc_query *oldquery;
1951 char *catg;
1952 const char *s;
1953 struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
1954
1955 cfg = ast_config_load(config, config_flags);
1957 return 0;
1958
1960
1961 if (dsns) {
1962 ao2_ref(dsns, -1);
1963 dsns = NULL;
1964 }
1965
1966 if (cfg && (s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) {
1968 } else {
1970 }
1971
1975 if (!dsns) {
1976 ast_log(LOG_ERROR, "Could not initialize DSN container\n");
1978 return 0;
1979 }
1980 }
1982
1984
1985 while (!AST_RWLIST_EMPTY(&queries)) {
1986 oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
1987 ast_custom_function_unregister(oldquery->acf);
1988 free_acf_query(oldquery);
1989 }
1990
1991 if (!cfg) {
1992 ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
1993 goto reload_out;
1994 }
1995
1996 for (catg = ast_category_browse(cfg, NULL);
1997 catg;
1998 catg = ast_category_browse(cfg, catg)) {
1999 struct acf_odbc_query *query = NULL;
2000
2001 if (!strcasecmp(catg, "general")) {
2002 continue;
2003 }
2004
2005 if (init_acf_query(cfg, catg, &query)) {
2006 ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
2007 } else {
2008 AST_RWLIST_INSERT_HEAD(&queries, query, list);
2009 ast_custom_function_register(query->acf);
2010 }
2011 }
2012
2013 ast_config_destroy(cfg);
2014reload_out:
2016 return res;
2017}
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_STATUS_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 532 of file func_odbc.c.

533{
534 return execute(obj, data, 1);
535}

References odbc_datastore_row::data, and execute().

Referenced by connection_dead().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1915 of file func_odbc.c.

1916{
1917 struct acf_odbc_query *query;
1918 int res = 0;
1919
1921 while (!AST_RWLIST_EMPTY(&queries)) {
1922 query = AST_RWLIST_REMOVE_HEAD(&queries, list);
1924 free_acf_query(query);
1925 }
1926
1932
1933 /* Allow any threads waiting for this lock to pass (avoids a race) */
1935 usleep(1);
1937
1939
1940 if (dsns) {
1941 ao2_ref(dsns, -1);
1942 }
1943 return res;
1944}
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 2027 of file func_odbc.c.

◆ app_odbcfinish

char* app_odbcfinish = "ODBCFinish"
static

Definition at line 1218 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 2027 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:1690
static char * cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1477

Definition at line 1840 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 453 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 454 of file func_odbc.c.

Referenced by acf_odbc_read().

◆ config

char* config = "func_odbc.conf"
static

Definition at line 132 of file func_odbc.c.

Referenced by load_module(), and reload().

◆ dsns

struct ao2_container* dsns

Definition at line 190 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:1163

Definition at line 1168 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:1152

Definition at line 1157 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 1212 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 160 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 449 of file func_odbc.c.

Referenced by acf_odbc_read().

◆ single_db_connection

int single_db_connection
static

Definition at line 136 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 138 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 452 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 451 of file func_odbc.c.

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