Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
res_config_odbc.c File Reference

odbc+odbc plugin for portable configuration engine More...

#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/res_odbc.h"
#include "asterisk/utils.h"
#include "asterisk/stringfields.h"
Include dependency graph for res_config_odbc.c:

Go to the source code of this file.

Data Structures

struct  config_odbc_obj
 
struct  custom_prepare_struct
 
struct  update2_prepare_struct
 

Macros

#define CHECK_SIZE(n)
 
#define ENCODE_CHUNK(buffer, s)
 
#define SQL_BUF_SIZE   1024
 
#define warn_length(col, size)   ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is not long enough to contain realtime data (needs %d)\n", table, database, col->name, size)
 
#define warn_type(col, type)   ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is of the incorrect type (%d) to contain the required realtime data\n", table, database, col->name, col->type)
 
#define WARN_TYPE_OR_LENGTH(n)
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_THREADSTORAGE_CUSTOM_SCOPE (rowdata_buf, NULL, ast_free_ptr, static)
 
 AST_THREADSTORAGE_CUSTOM_SCOPE (sql_buf, NULL, ast_free_ptr, static)
 
static struct ast_configconfig_odbc (const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
 
static SQLHSTMT config_odbc_prepare (struct odbc_obj *obj, void *data)
 
static SQLHSTMT custom_prepare (struct odbc_obj *obj, void *data)
 
static void decode_chunk (char *chunk)
 
static int destroy_odbc (const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
 Execute an DELETE query.
 
static int is_text (const struct odbc_cache_columns *column)
 
static SQLHSTMT length_determination_odbc_prepare (struct odbc_obj *obj, void *data)
 
static void load_config (const char *filename)
 
static int load_module (void)
 
static struct ast_configrealtime_multi_odbc (const char *database, const char *table, const struct ast_variable *fields)
 Execute an Select query and return ast_config list.
 
static struct ast_variablerealtime_odbc (const char *database, const char *table, const struct ast_variable *fields)
 Execute an SQL query and return ast_variable list.
 
static int reload_module (void)
 
static int require_odbc (const char *database, const char *table, va_list ap)
 
static int store_odbc (const char *database, const char *table, const struct ast_variable *fields)
 Execute an INSERT query.
 
static int unload_module (void)
 
static int unload_odbc (const char *a, const char *b)
 
static int update2_odbc (const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
 Execute an UPDATE query.
 
static SQLHSTMT update2_prepare (struct odbc_obj *obj, void *data)
 
static int update_odbc (const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
 Execute an UPDATE query.
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime ODBC configuration" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, .requires = "extconfig,res_odbc", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_config_engine odbc_engine
 
static int order_multi_row_results_by_initial_column = 1
 
static const char * res_config_odbc_conf = "res_config_odbc.conf"
 

Detailed Description

odbc+odbc plugin for portable configuration engine

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Anthony Minessale II anthm.nosp@m.ct@y.nosp@m.ahoo..nosp@m.com

Definition in file res_config_odbc.c.

Macro Definition Documentation

◆ CHECK_SIZE

#define CHECK_SIZE (   n)
Value:
if (col->size < n) { \
warn_length(col, n); \
} \
break;

◆ ENCODE_CHUNK

#define ENCODE_CHUNK (   buffer,
 
)

Definition at line 68 of file res_config_odbc.c.

69 { \
70 char *eptr = buffer; \
71 const char *vptr = s; \
72 for (; *vptr && eptr < buffer + sizeof(buffer); vptr++) { \
73 if (strchr("^;", *vptr)) { \
74 /* We use ^XX, instead of %XX because '%' is a special character in SQL */ \
75 snprintf(eptr, buffer + sizeof(buffer) - eptr, "^%02hhX", *vptr); \
76 eptr += 3; \
77 } else { \
78 *eptr++ = *vptr; \
79 } \
80 } \
81 if (eptr < buffer + sizeof(buffer)) { \
82 *eptr = '\0'; \
83 } else { \
84 buffer[sizeof(buffer) - 1] = '\0'; \
85 } \
86 } while(0)

◆ SQL_BUF_SIZE

#define SQL_BUF_SIZE   1024

Initial SQL query buffer size to allocate.

Definition at line 50 of file res_config_odbc.c.

◆ warn_length

#define warn_length (   col,
  size 
)    ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is not long enough to contain realtime data (needs %d)\n", table, database, col->name, size)

Definition at line 1088 of file res_config_odbc.c.

◆ warn_type

#define warn_type (   col,
  type 
)    ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is of the incorrect type (%d) to contain the required realtime data\n", table, database, col->name, col->type)

Definition at line 1089 of file res_config_odbc.c.

◆ WARN_TYPE_OR_LENGTH

#define WARN_TYPE_OR_LENGTH (   n)
Value:
if (!ast_rq_is_int(type)) { \
warn_type(col, type); \
} else { \
warn_length(col, n); \
}
static const char type[]
int ast_rq_is_int(require_type type)
Check if require type is an integer type.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1317 of file res_config_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1317 of file res_config_odbc.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1317 of file res_config_odbc.c.

◆ AST_THREADSTORAGE_CUSTOM_SCOPE() [1/2]

AST_THREADSTORAGE_CUSTOM_SCOPE ( rowdata_buf  ,
NULL  ,
ast_free_ptr  ,
static   
)

◆ AST_THREADSTORAGE_CUSTOM_SCOPE() [2/2]

AST_THREADSTORAGE_CUSTOM_SCOPE ( sql_buf  ,
NULL  ,
ast_free_ptr  ,
static   
)

◆ config_odbc()

static struct ast_config * config_odbc ( const char *  database,
const char *  table,
const char *  file,
struct ast_config cfg,
struct ast_flags  flags,
const char *  sugg_incl,
const char *  who_asked 
)
static

Definition at line 953 of file res_config_odbc.c.

954{
955 struct ast_variable *new_v;
956 struct ast_category *cur_cat;
957 int res = 0;
958 struct odbc_obj *obj;
959 struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
960 unsigned int last_cat_metric = 0;
961 SQLSMALLINT rowcount = 0;
962 SQLHSTMT stmt;
963 char last[128] = "";
964 struct config_odbc_obj q;
965 struct ast_flags loader_flags = { 0 };
966 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
967
968 memset(&q, 0, sizeof(q));
969
970 if (!file || !strcmp (file, res_config_odbc_conf) || !sql) {
971 return NULL; /* cant configure myself with myself ! */
972 }
973
974 obj = ast_odbc_request_obj2(database, connected_flag);
975 if (!obj)
976 return NULL;
977
978 ast_str_set(&sql, 0, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'",
979 table, file);
980 q.sql = ast_str_buffer(sql);
981
983 if (!stmt) {
984 ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
986 return NULL;
987 }
988
989 res = SQLNumResultCols(stmt, &rowcount);
990
991 if (!SQL_SUCCEEDED(res)) {
992 ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
993 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
995 return NULL;
996 }
997
998 if (!rowcount) {
999 ast_log(LOG_NOTICE, "found nothing\n");
1000 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1002 return cfg;
1003 }
1004
1005 /* There will be only one result for this, the maximum length of a variable value */
1006 if (SQLFetch(stmt) == SQL_NO_DATA) {
1007 ast_log(LOG_NOTICE, "Failed to determine maximum length of a configuration value\n");
1008 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1010 return NULL;
1011 }
1012
1013 /* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
1014 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1015
1016 ast_str_set(&sql, 0, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
1017 ast_str_append(&sql, 0, "WHERE filename='%s' AND commented=0 ", file);
1018 ast_str_append(&sql, 0, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
1019 q.sql = ast_str_buffer(sql);
1020
1021 q.var_val_size += 1;
1022 q.var_val = ast_malloc(q.var_val_size);
1023 if (!q.var_val) {
1024 ast_log(LOG_WARNING, "Could not create buffer for reading in configuration values for '%s'\n", file);
1025 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1027 return NULL;
1028 }
1029
1031 if (!stmt) {
1032 ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
1034 ast_free(q.var_val);
1035 return NULL;
1036 }
1037
1038 res = SQLNumResultCols(stmt, &rowcount);
1039
1040 if (!SQL_SUCCEEDED(res)) {
1041 ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
1042 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1044 ast_free(q.var_val);
1045 return NULL;
1046 }
1047
1048 if (!rowcount) {
1049 ast_log(LOG_NOTICE, "found nothing\n");
1050 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1052 ast_free(q.var_val);
1053 return cfg;
1054 }
1055
1056 cur_cat = ast_config_get_current_category(cfg);
1057
1058 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
1059 if (!strcmp (q.var_name, "#include")) {
1060 if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
1061 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1063 ast_free(q.var_val);
1064 return NULL;
1065 }
1066 continue;
1067 }
1068 if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
1069 cur_cat = ast_category_new_dynamic(q.category);
1070 if (!cur_cat) {
1071 break;
1072 }
1073 strcpy(last, q.category);
1074 last_cat_metric = q.cat_metric;
1075 ast_category_append(cfg, cur_cat);
1076 }
1077
1078 new_v = ast_variable_new(q.var_name, q.var_val, "");
1079 ast_variable_append(cur_cat, new_v);
1080 }
1081
1082 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1084 ast_free(q.var_val);
1085 return cfg;
1086}
struct sla_ringing_trunk * last
Definition app_sla.c:338
#define ast_free(a)
Definition astmm.h:180
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition extconf.c:2831
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition extconf.c:1175
#define ast_variable_new(name, value, filename)
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
Definition extconf.c:2779
struct ast_config * ast_config_internal_load(const char *configfile, struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl_file, const char *who_asked)
#define ast_category_new_dynamic(name)
Create a category that is not backed by a file.
#define LOG_NOTICE
#define LOG_WARNING
#define SQL_BUF_SIZE
static SQLHSTMT length_determination_odbc_prepare(struct odbc_obj *obj, void *data)
static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
static const char * res_config_odbc_conf
@ RES_ODBC_CONNECTED
Definition res_odbc.h:42
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition res_odbc.c:828
#define ast_odbc_request_obj2(name, check)
Retrieves a connected ODBC object.
Definition res_odbc.h:106
SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
Prepares, executes, and returns the resulting statement handle.
Definition res_odbc.c:403
#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
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
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
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
Structure used to handle boolean flags.
Definition utils.h:220
Support for dynamic strings.
Definition strings.h:623
Structure for variables, used for configurations and for channel variables.
ODBC container.
Definition res_odbc.h:46

References ast_category_append(), ast_category_new_dynamic, ast_config_get_current_category(), ast_config_internal_load(), ast_free, ast_log, ast_malloc, ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_variable_append(), ast_variable_new, config_odbc_obj::cat_metric, config_odbc_obj::category, config_odbc_prepare(), last, length_determination_odbc_prepare(), LOG_NOTICE, LOG_WARNING, NULL, res_config_odbc_conf, RES_ODBC_CONNECTED, config_odbc_obj::sql, SQL_BUF_SIZE, config_odbc_obj::var_name, config_odbc_obj::var_val, and config_odbc_obj::var_val_size.

◆ config_odbc_prepare()

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

Definition at line 926 of file res_config_odbc.c.

927{
928 struct config_odbc_obj *q = data;
929 SQLHSTMT sth;
930 int res;
931
932 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
933 if (!SQL_SUCCEEDED(res)) {
934 ast_verb(4, "Failure in AllocStatement %d\n", res);
935 return NULL;
936 }
937
938 res = ast_odbc_prepare(obj, sth, q->sql);
939 if (!SQL_SUCCEEDED(res)) {
940 ast_verb(4, "Error in PREPARE %d\n", res);
941 SQLFreeHandle(SQL_HANDLE_STMT, sth);
942 return NULL;
943 }
944
945 SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
946 SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
947 SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
948 SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, q->var_val_size, &q->err);
949
950 return sth;
951}
#define ast_verb(level,...)
int ast_odbc_prepare(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Prepares a SQL query on a statement.
Definition res_odbc.c:459
unsigned long var_val_size
unsigned long cat_metric
SQLHDBC con
Definition res_odbc.h:47

References ast_odbc_prepare(), ast_verb, config_odbc_obj::cat_metric, config_odbc_obj::category, odbc_obj::con, config_odbc_obj::err, NULL, config_odbc_obj::sql, config_odbc_obj::var_name, config_odbc_obj::var_val, and config_odbc_obj::var_val_size.

Referenced by config_odbc().

◆ custom_prepare()

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

Definition at line 104 of file res_config_odbc.c.

105{
106 int res, x = 1, count = 0;
107 struct custom_prepare_struct *cps = data;
108 const struct ast_variable *field;
109 char encodebuf[1024];
110 SQLHSTMT stmt;
111
112 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
113 if (!SQL_SUCCEEDED(res)) {
114 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
115 return NULL;
116 }
117
118 ast_debug(1, "Skip: %llu; SQL: %s\n", cps->skip, cps->sql);
119
120 res = ast_odbc_prepare(obj, stmt, cps->sql);
121 if (!SQL_SUCCEEDED(res)) {
122 if (res == SQL_ERROR) {
123 ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Prepare");
124 }
125 ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", cps->sql);
126 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
127 return NULL;
128 }
129
130 for (field = cps->fields; field; field = field->next) {
131 const char *newval = field->value;
132
133 if ((1LL << count++) & cps->skip) {
134 ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", field->name, newval, 1ULL << (count - 1), cps->skip);
135 continue;
136 }
137 ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, field->name, newval);
138 if (strchr(newval, ';') || strchr(newval, '^')) {
139 ENCODE_CHUNK(encodebuf, newval);
140 ast_string_field_set(cps, encoding[x], encodebuf);
141 newval = cps->encoding[x];
142 }
143 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
144 }
145
146 if (!ast_strlen_zero(cps->extra)) {
147 const char *newval = cps->extra;
148 ast_debug(1, "Parameter %d = '%s'\n", x, newval);
149 if (strchr(newval, ';') || strchr(newval, '^')) {
150 ENCODE_CHUNK(encodebuf, newval);
151 ast_string_field_set(cps, encoding[x], encodebuf);
152 newval = cps->encoding[x];
153 }
154 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
155 }
156
157 return stmt;
158}
static char * encoding
Definition cdr_pgsql.c:70
#define ast_debug(level,...)
Log a DEBUG message.
#define ENCODE_CHUNK(buffer, s)
struct ast_str * ast_odbc_print_errors(SQLSMALLINT handle_type, SQLHANDLE handle, const char *operation)
Shortcut for printing errors to logs after a failed SQL operation.
Definition res_odbc.c:520
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
struct ast_variable * next
const ast_string_field encoding[256]
unsigned long long skip
const struct ast_variable * fields

References ast_debug, ast_log, ast_odbc_prepare(), ast_odbc_print_errors(), ast_string_field_set, ast_strlen_zero(), odbc_obj::con, ENCODE_CHUNK, encoding, custom_prepare_struct::encoding, custom_prepare_struct::extra, custom_prepare_struct::fields, LOG_WARNING, ast_variable::name, ast_variable::next, NULL, custom_prepare_struct::skip, custom_prepare_struct::sql, and ast_variable::value.

Referenced by destroy_odbc(), realtime_multi_odbc(), realtime_odbc(), store_odbc(), and update_odbc().

◆ decode_chunk()

static void decode_chunk ( char *  chunk)
static

Definition at line 88 of file res_config_odbc.c.

89{
90 for (; *chunk; chunk++) {
91 if (*chunk == '^' && strchr("0123456789ABCDEF", chunk[1]) && strchr("0123456789ABCDEF", chunk[2])) {
92 sscanf(chunk + 1, "%02hhX", (unsigned char *)chunk);
93 memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
94 }
95 }
96}

Referenced by realtime_multi_odbc(), and realtime_odbc().

◆ destroy_odbc()

static int destroy_odbc ( const char *  database,
const char *  table,
const char *  keyfield,
const char *  lookup,
const struct ast_variable fields 
)
static

Execute an DELETE query.

Parameters
database
table
keyfieldwhere clause field
lookupvalue of field for where clause
fieldslist containing one or more field/value set(s)

Delete a row from a database table, prepare the sql statement using keyfield and lookup control the number of records to change. Additional params to match rows are stored in ap list. Sub-in the values to the prepared statement and execute it.

Returns
number of rows affected
Return values
-1on failure

Definition at line 836 of file res_config_odbc.c.

837{
838 struct odbc_obj *obj;
839 SQLHSTMT stmt;
840 SQLLEN rowcount=0;
841 struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
842 const struct ast_variable *field;
843 int res;
844 struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
845 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
846
847 if (!table || !sql) {
848 return -1;
849 }
850
851 obj = ast_odbc_request_obj2(database, connected_flag);
852 if (!obj) {
853 return -1;
854 }
855
856 ast_str_set(&sql, 0, "DELETE FROM %s WHERE ", table);
857 for (field = fields; field; field = field->next) {
858 ast_str_append(&sql, 0, "%s=? AND ", field->name);
859 }
860 ast_str_append(&sql, 0, "%s=?", keyfield);
861
862 cps.sql = ast_str_buffer(sql);
863
864 if (ast_string_field_init(&cps, 256)) {
866 return -1;
867 }
870
871 if (!stmt) {
873 return -1;
874 }
875
876 res = SQLRowCount(stmt, &rowcount);
877 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
879
880 if (!SQL_SUCCEEDED(res)) {
881 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
882 return -1;
883 }
884
885 if (rowcount >= 0)
886 return (int)rowcount;
887
888 return -1;
889}
static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object

References ast_log, ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_string_field_free_memory, ast_string_field_init, custom_prepare(), custom_prepare_struct::extra, custom_prepare_struct::fields, LOG_WARNING, ast_variable::name, ast_variable::next, RES_ODBC_CONNECTED, custom_prepare_struct::sql, and SQL_BUF_SIZE.

◆ is_text()

static int is_text ( const struct odbc_cache_columns column)
inlinestatic

Definition at line 98 of file res_config_odbc.c.

99{
100 return column->type == SQL_CHAR || column->type == SQL_VARCHAR || column->type == SQL_LONGVARCHAR
101 || column->type == SQL_WCHAR || column->type == SQL_WVARCHAR || column->type == SQL_WLONGVARCHAR;
102}
SQLSMALLINT type
Definition res_odbc.h:61

References odbc_cache_columns::type.

Referenced by update_odbc().

◆ length_determination_odbc_prepare()

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

Definition at line 902 of file res_config_odbc.c.

903{
904 struct config_odbc_obj *q = data;
905 SQLHSTMT sth;
906 int res;
907
908 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
909 if (!SQL_SUCCEEDED(res)) {
910 ast_verb(4, "Failure in AllocStatement %d\n", res);
911 return NULL;
912 }
913
914 res = ast_odbc_prepare(obj, sth, q->sql);
915 if (!SQL_SUCCEEDED(res)) {
916 ast_verb(4, "Error in PREPARE %d\n", res);
917 SQLFreeHandle(SQL_HANDLE_STMT, sth);
918 return NULL;
919 }
920
921 SQLBindCol(sth, 1, SQL_C_ULONG, &q->var_val_size, sizeof(q->var_val_size), &q->err);
922
923 return sth;
924}

References ast_odbc_prepare(), ast_verb, odbc_obj::con, config_odbc_obj::err, NULL, config_odbc_obj::sql, and config_odbc_obj::var_val_size.

Referenced by config_odbc().

◆ load_config()

static void load_config ( const char *  filename)
static

Definition at line 1267 of file res_config_odbc.c.

1268{
1269 struct ast_config *config;
1270 struct ast_flags config_flags = { 0 };
1271 const char *s;
1272
1273 config = ast_config_load(filename, config_flags);
1276 ast_log(LOG_WARNING, "Unable to load config '%s'. Using defaults.\n", filename);
1277 }
1279 return;
1280 }
1281
1282 /* Result set ordering is enabled by default */
1283 s = ast_variable_retrieve(config, "general", "order_multi_row_results_by_initial_column");
1285
1287}
static const char config[]
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEMISSING
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
static int order_multi_row_results_by_initial_column
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:2233

References ast_config_destroy(), ast_config_load, ast_log, ast_true(), ast_variable_retrieve(), config, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, LOG_WARNING, and order_multi_row_results_by_initial_column.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1289 of file res_config_odbc.c.

1290{
1291 /* We'll either successfully load the configuration or fail with reasonable
1292 * defaults */
1295 return 0;
1296}
static int load_config(void)
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
static struct ast_config_engine odbc_engine

References ast_config_engine_register(), load_config(), odbc_engine, and res_config_odbc_conf.

◆ realtime_multi_odbc()

static struct ast_config * realtime_multi_odbc ( const char *  database,
const char *  table,
const struct ast_variable fields 
)
static

Execute an Select query and return ast_config list.

Parameters
database
table
fieldslist containing one or more field/operator/value set.

Select database and preform query on table, prepare the sql statement Sub-in the values to the prepared statement and execute it. Execute this prepared query against several ODBC connected databases. Return results as an ast_config variable.

Returns
var on success
Return values
NULLon failure

Definition at line 352 of file res_config_odbc.c.

353{
354 struct odbc_obj *obj;
355 SQLHSTMT stmt;
356 char coltitle[256];
357 struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
358 struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
359 char *initfield;
360 char *op;
361 const struct ast_variable *field = fields;
362 char *stringp;
363 char *chunk;
364 SQLSMALLINT collen;
365 int res;
366 int x;
367 struct ast_variable *var=NULL;
368 struct ast_config *cfg=NULL;
369 struct ast_category *cat=NULL;
370 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
371 SQLULEN colsize;
372 SQLSMALLINT colcount=0;
373 SQLSMALLINT datatype;
374 SQLSMALLINT decimaldigits;
375 SQLSMALLINT nullable;
376 SQLLEN indicator;
377 struct custom_prepare_struct cps = { .fields = fields, };
378
379 if (!table || !field || !sql || !rowdata) {
380 return NULL;
381 }
382
383 obj = ast_odbc_request_obj2(database, connected_flag);
384 if (!obj) {
385 return NULL;
386 }
387
388 initfield = ast_strdupa(field->name);
389 if ((op = strchr(initfield, ' '))) {
390 *op = '\0';
391 }
392
393 op = !strchr(field->name, ' ') ? " =" : "";
394 ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
395 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
396 while ((field = field->next)) {
397 op = !strchr(field->name, ' ') ? " =" : "";
398 ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
399 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
400 }
401
403 ast_str_append(&sql, 0, " ORDER BY %s", initfield);
404 }
405
406 cps.sql = ast_str_buffer(sql);
407
408 if (ast_string_field_init(&cps, 256)) {
410 return NULL;
411 }
414
415 if (!stmt) {
417 return NULL;
418 }
419
420 res = SQLNumResultCols(stmt, &colcount);
421 if (!SQL_SUCCEEDED(res)) {
422 ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
423 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
425 return NULL;
426 }
427
428 cfg = ast_config_new();
429 if (!cfg) {
430 ast_log(LOG_WARNING, "Out of memory!\n");
431 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
433 return NULL;
434 }
435
436 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
437 var = NULL;
438 if (!SQL_SUCCEEDED(res)) {
439 ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
440 continue;
441 }
443 if (!cat) {
444 continue;
445 }
446 for (x=0;x<colcount;x++) {
447 colsize = 0;
448 collen = sizeof(coltitle);
449 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
450 &datatype, &colsize, &decimaldigits, &nullable);
451 if (!SQL_SUCCEEDED(res)) {
452 ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
454 goto next_sql_fetch;
455 }
456
457 ast_str_reset(rowdata);
458 indicator = 0;
459
460 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
461 ast_str_update(rowdata);
462 if (indicator == SQL_NULL_DATA) {
463 continue;
464 }
465
466 if (SQL_SUCCEEDED(res)) {
467 if (indicator != ast_str_strlen(rowdata)) {
468 /* If the available space was not enough to contain the row data enlarge and read in the rest */
469 ast_str_make_space(&rowdata, indicator + 1);
470 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
471 ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
472 ast_str_update(rowdata);
473 }
474 }
475
476 if (!SQL_SUCCEEDED(res)) {
477 ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
479 goto next_sql_fetch;
480 }
481 stringp = ast_str_buffer(rowdata);
482 if (!strncmp(coltitle, "@", 1)) {
483 /* The '@' prefix indicates it's a sorcery extended field.
484 * Because ast_load_realtime_fields eliminates empty entries and makes blank (single whitespace)
485 * entries empty and keeps them, the empty or NULL values are encoded
486 * as a string containing a single whitespace. */
487 var = ast_variable_new(coltitle, S_OR(stringp," "), "");
489 } else {
490 while (stringp) {
491 chunk = strsep(&stringp, ";");
492 if (!ast_strlen_zero(ast_strip(chunk))) {
493 if (strchr(chunk, '^')) {
494 decode_chunk(chunk);
495 }
496 if (!strcmp(initfield, coltitle)) {
497 ast_category_rename(cat, chunk);
498 }
499 var = ast_variable_new(coltitle, chunk, "");
501 }
502 }
503 }
504 }
505 ast_category_append(cfg, cat);
506next_sql_fetch:;
507 }
508
509 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
511 return cfg;
512}
#define var
Definition ast_expr2f.c:605
char * strsep(char **str, const char *delims)
char * strcasestr(const char *, const char *)
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
void ast_category_rename(struct ast_category *cat, const char *name)
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition extconf.c:3272
#define ast_category_new_anonymous()
Create a nameless category that is not backed by a file.
void ast_category_destroy(struct ast_category *cat)
Definition extconf.c:2843
static void decode_chunk(char *chunk)
int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
Checks if the database natively supports backslash as an escape character.
Definition res_odbc.c:884
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition strings.h:730
#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
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
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition strings.h:703
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
size_t attribute_pure ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition strings.h:742
static int indicator

References ast_category_append(), ast_category_destroy(), ast_category_new_anonymous, ast_category_rename(), ast_config_new(), ast_log, ast_odbc_backslash_is_escape(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_str_append(), ast_str_buffer(), ast_str_make_space, ast_str_reset(), ast_str_set(), ast_str_size(), ast_str_strlen(), ast_str_thread_get(), ast_str_update(), ast_strdupa, ast_string_field_free_memory, ast_string_field_init, ast_strip(), ast_strlen_zero(), ast_variable_append(), ast_variable_new, custom_prepare(), decode_chunk(), custom_prepare_struct::fields, indicator, LOG_WARNING, ast_variable::name, ast_variable::next, NULL, order_multi_row_results_by_initial_column, RES_ODBC_CONNECTED, S_OR, custom_prepare_struct::sql, SQL_BUF_SIZE, strcasestr(), strsep(), and var.

◆ realtime_odbc()

static struct ast_variable * realtime_odbc ( const char *  database,
const char *  table,
const struct ast_variable fields 
)
static

Execute an SQL query and return ast_variable list.

Parameters
database
table
fieldslist containing one or more field/operator/value set.

Select database and preform query on table, prepare the sql statement Sub-in the values to the prepared statement and execute it. Return results as a ast_variable list.

Returns
var on success (data found)
CONFIG_RT_NOT_FOUND on success but no record
Return values
NULLon failure

Definition at line 174 of file res_config_odbc.c.

175{
176 struct odbc_obj *obj;
177 SQLHSTMT stmt;
178 char coltitle[256];
179 struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
180 struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
181 char *op;
182 const struct ast_variable *field = fields;
183 char *stringp;
184 char *chunk;
185 SQLSMALLINT collen;
186 int res;
187 int x;
188 struct ast_variable *var=NULL, *prev=NULL;
189 SQLULEN colsize;
190 SQLSMALLINT colcount=0;
191 SQLSMALLINT datatype;
192 SQLSMALLINT decimaldigits;
193 SQLSMALLINT nullable;
194 SQLLEN indicator;
195 struct custom_prepare_struct cps = { .fields = fields, };
196 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
197
198 if (!table || !field || !sql || !rowdata) {
199 return NULL;
200 }
201
202 obj = ast_odbc_request_obj2(database, connected_flag);
203 if (!obj) {
204 ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
205 return NULL;
206 }
207
208 op = !strchr(field->name, ' ') ? " =" : "";
209 ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
210 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
211 while ((field = field->next)) {
212 op = !strchr(field->name, ' ') ? " =" : "";
213 ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
214 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
215 }
216
217 cps.sql = ast_str_buffer(sql);
218
219 if (ast_string_field_init(&cps, 256)) {
221 return NULL;
222 }
225
226 if (!stmt) {
228 return NULL;
229 }
230
231 res = SQLNumResultCols(stmt, &colcount);
232 if (!SQL_SUCCEEDED(res)) {
233 ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
234 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
236 return NULL;
237 }
238
239 res = SQLFetch(stmt);
240 if (res == SQL_NO_DATA) {
241 /* SQL_NO_DATA indicates that the query was valid but no record was found.
242 * Instead of returning NULL (which signals a backend error to the core),
243 * return CONFIG_RT_NOT_FOUND to prevent incorrect failover.
244 */
245 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
247 return CONFIG_RT_NOT_FOUND;
248 }
249 if (!SQL_SUCCEEDED(res)) {
250 ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
251 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
253 return NULL;
254 }
255 for (x = 0; x < colcount; x++) {
256 colsize = 0;
257 collen = sizeof(coltitle);
258 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
259 &datatype, &colsize, &decimaldigits, &nullable);
260 if (!SQL_SUCCEEDED(res)) {
261 ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
262 if (var)
264 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
266 return NULL;
267 }
268
269 ast_str_reset(rowdata);
270 indicator = 0;
271
272 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
273 ast_str_update(rowdata);
274 if (indicator == SQL_NULL_DATA) {
275 ast_str_reset(rowdata);
276 } else if (!ast_str_strlen(rowdata)) {
277 /* Because we encode the empty string for a NULL, we will encode
278 * actual empty strings as a string containing a single whitespace. */
279 ast_str_set(&rowdata, -1, "%s", " ");
280 } else if (SQL_SUCCEEDED(res)) {
281 if (indicator != ast_str_strlen(rowdata)) {
282 /* If the available space was not enough to contain the row data enlarge and read in the rest */
283 ast_str_make_space(&rowdata, indicator + 1);
284 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
285 ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
286 ast_str_update(rowdata);
287 }
288 }
289
290 if (!SQL_SUCCEEDED(res)) {
291 ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
292 if (var)
294 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
296 return NULL;
297 }
298
299 stringp = ast_str_buffer(rowdata);
300 if (!strncmp(coltitle, "@", 1)) {
301 /* The '@' prefix indicates it's a sorcery extended field.
302 * Because ast_load_realtime_fields eliminates empty entries and makes blank (single whitespace)
303 * entries empty and keeps them, the empty or NULL values are encoded
304 * as a string containing a single whitespace. */
305 if (prev) {
306 prev->next = ast_variable_new(coltitle, S_OR(stringp," "), "");
307 if (prev->next) {
308 prev = prev->next;
309 }
310 } else {
311 prev = var = ast_variable_new(coltitle, S_OR(stringp," "), "");
312 }
313 } else {
314 while (stringp) {
315 chunk = strsep(&stringp, ";");
316 if (!ast_strlen_zero(ast_strip(chunk))) {
317 if (strchr(chunk, '^')) {
318 decode_chunk(chunk);
319 }
320 if (prev) {
321 prev->next = ast_variable_new(coltitle, chunk, "");
322 if (prev->next) {
323 prev = prev->next;
324 }
325 } else {
326 prev = var = ast_variable_new(coltitle, chunk, "");
327 }
328 }
329 }
330 }
331 }
332
333 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
335 return var;
336}
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
#define CONFIG_RT_NOT_FOUND
#define LOG_ERROR

References ast_log, ast_odbc_backslash_is_escape(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_str_append(), ast_str_buffer(), ast_str_make_space, ast_str_reset(), ast_str_set(), ast_str_size(), ast_str_strlen(), ast_str_thread_get(), ast_str_update(), ast_string_field_free_memory, ast_string_field_init, ast_strip(), ast_strlen_zero(), ast_variable_new, ast_variables_destroy(), CONFIG_RT_NOT_FOUND, custom_prepare(), decode_chunk(), custom_prepare_struct::fields, indicator, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, NULL, RES_ODBC_CONNECTED, S_OR, custom_prepare_struct::sql, SQL_BUF_SIZE, strcasestr(), strsep(), and var.

◆ reload_module()

static int reload_module ( void  )
static

Definition at line 1298 of file res_config_odbc.c.

1299{
1301 return 0;
1302}

References load_config(), and res_config_odbc_conf.

◆ require_odbc()

static int require_odbc ( const char *  database,
const char *  table,
va_list  ap 
)
static

Definition at line 1091 of file res_config_odbc.c.

1092{
1093 struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table);
1094 struct odbc_cache_columns *col;
1095 char *elm;
1096 int type, size;
1097
1098 if (!tableptr) {
1099 return -1;
1100 }
1101
1102 while ((elm = va_arg(ap, char *))) {
1103 type = va_arg(ap, require_type);
1104 size = va_arg(ap, int);
1105 /* Check if the field matches the criteria */
1106 AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) {
1107 if (strcmp(col->name, elm) == 0) {
1108 /* Type check, first. Some fields are more particular than others */
1109 switch (col->type) {
1110 case SQL_CHAR:
1111 case SQL_VARCHAR:
1112 case SQL_LONGVARCHAR:
1113#ifdef HAVE_ODBC_WCHAR
1114 case SQL_WCHAR:
1115 case SQL_WVARCHAR:
1116 case SQL_WLONGVARCHAR:
1117#endif
1118 case SQL_BINARY:
1119 case SQL_VARBINARY:
1120 case SQL_LONGVARBINARY:
1121 case SQL_GUID:
1122#define CHECK_SIZE(n) \
1123 if (col->size < n) { \
1124 warn_length(col, n); \
1125 } \
1126 break;
1127 switch (type) {
1128 case RQ_UINTEGER1: CHECK_SIZE(3) /* 255 */
1129 case RQ_INTEGER1: CHECK_SIZE(4) /* -128 */
1130 case RQ_UINTEGER2: CHECK_SIZE(5) /* 65535 */
1131 case RQ_INTEGER2: CHECK_SIZE(6) /* -32768 */
1132 case RQ_UINTEGER3: /* 16777215 */
1133 case RQ_INTEGER3: CHECK_SIZE(8) /* -8388608 */
1134 case RQ_DATE: /* 2008-06-09 */
1135 case RQ_UINTEGER4: CHECK_SIZE(10) /* 4200000000 */
1136 case RQ_INTEGER4: CHECK_SIZE(11) /* -2100000000 */
1137 case RQ_DATETIME: /* 2008-06-09 16:03:47 */
1138 case RQ_UINTEGER8: CHECK_SIZE(19) /* trust me */
1139 case RQ_INTEGER8: CHECK_SIZE(20) /* ditto */
1140 case RQ_FLOAT:
1141 case RQ_CHAR: CHECK_SIZE(size)
1142 }
1143#undef CHECK_SIZE
1144 break;
1145 case SQL_TYPE_DATE:
1146 if (type != RQ_DATE) {
1147 warn_type(col, type);
1148 }
1149 break;
1150 case SQL_TYPE_TIMESTAMP:
1151 case SQL_TIMESTAMP:
1152 case SQL_DATETIME:
1153 if (type != RQ_DATE && type != RQ_DATETIME) {
1154 warn_type(col, type);
1155 }
1156 break;
1157 case SQL_BIT:
1158 warn_length(col, size);
1159 break;
1160#define WARN_TYPE_OR_LENGTH(n) \
1161 if (!ast_rq_is_int(type)) { \
1162 warn_type(col, type); \
1163 } else { \
1164 warn_length(col, n); \
1165 }
1166 case SQL_TINYINT:
1167 if (type != RQ_UINTEGER1) {
1169 }
1170 break;
1171 case SQL_C_STINYINT:
1172 if (type != RQ_INTEGER1) {
1174 }
1175 break;
1176 case SQL_C_USHORT:
1177 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) {
1179 }
1180 break;
1181 case SQL_SMALLINT:
1182 case SQL_C_SSHORT:
1183 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) {
1185 }
1186 break;
1187 case SQL_C_ULONG:
1188 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1189 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1190 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1191 type != RQ_INTEGER4) {
1193 }
1194 break;
1195 case SQL_INTEGER:
1196 case SQL_C_SLONG:
1197 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1198 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1199 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1200 type != RQ_INTEGER4) {
1202 }
1203 break;
1204 case SQL_C_UBIGINT:
1205 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1206 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1207 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1208 type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
1209 type != RQ_INTEGER8) {
1211 }
1212 break;
1213 case SQL_BIGINT:
1214 case SQL_C_SBIGINT:
1215 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1216 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1217 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1218 type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
1219 type != RQ_INTEGER8) {
1221 }
1222 break;
1223#undef WARN_TYPE_OR_LENGTH
1224 case SQL_NUMERIC:
1225 case SQL_DECIMAL:
1226 case SQL_FLOAT:
1227 case SQL_REAL:
1228 case SQL_DOUBLE:
1229 if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
1230 warn_type(col, type);
1231 }
1232 break;
1233 default:
1234 ast_log(LOG_WARNING, "Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->type, elm);
1235 }
1236 break;
1237 }
1238 }
1239 if (!col) {
1240 ast_log(LOG_WARNING, "Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm);
1241 }
1242 }
1243 AST_RWLIST_UNLOCK(&tableptr->columns);
1244 return 0;
1245}
require_type
Types used in ast_realtime_require_field.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_RWLIST_TRAVERSE
#define warn_length(col, size)
#define CHECK_SIZE(n)
#define warn_type(col, type)
#define WARN_TYPE_OR_LENGTH(n)
struct odbc_cache_tables * ast_odbc_find_table(const char *database, const char *tablename)
Find or create an entry describing the table specified.
Definition res_odbc.c:237
These structures are used for adaptive capabilities.
Definition res_odbc.h:59
struct odbc_cache_columns::@270 list
SQLINTEGER size
Definition res_odbc.h:62
struct odbc_cache_tables::_columns columns

References ast_log, ast_odbc_find_table(), ast_rq_is_int(), AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CHECK_SIZE, odbc_cache_tables::columns, odbc_cache_columns::list, LOG_WARNING, odbc_cache_columns::name, RQ_CHAR, RQ_DATE, RQ_DATETIME, RQ_FLOAT, RQ_INTEGER1, RQ_INTEGER2, RQ_INTEGER3, RQ_INTEGER4, RQ_INTEGER8, RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, RQ_UINTEGER8, odbc_cache_columns::size, odbc_cache_tables::table, type, odbc_cache_columns::type, warn_length, warn_type, and WARN_TYPE_OR_LENGTH.

◆ store_odbc()

static int store_odbc ( const char *  database,
const char *  table,
const struct ast_variable fields 
)
static

Execute an INSERT query.

Parameters
database
table
fieldslist containing one or more field/value set(s)

Insert a new record into database table, prepare the sql statement. All values to be changed are stored in ap list. Sub-in the values to the prepared statement and execute it.

Returns
number of rows affected
Return values
-1on failure

Definition at line 753 of file res_config_odbc.c.

754{
755 struct odbc_obj *obj;
756 SQLHSTMT stmt;
757 SQLLEN rowcount=0;
758 const struct ast_variable *field = fields;
759 struct ast_str *keys;
760 struct ast_str *vals;
761 struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
762 int res;
763 struct custom_prepare_struct cps = { .fields = fields, };
764 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
765
767 vals = ast_str_create(SQL_BUF_SIZE / 4);
768 if (!table || !field || !keys || !vals || !sql) {
769 ast_free(vals);
770 ast_free(keys);
771 return -1;
772 }
773
774 obj = ast_odbc_request_obj2(database, connected_flag);
775 if (!obj) {
776 ast_free(vals);
777 ast_free(keys);
778 return -1;
779 }
780
781 ast_str_set(&keys, 0, "%s", field->name);
782 ast_str_set(&vals, 0, "?");
783 while ((field = field->next)) {
784 ast_str_append(&keys, 0, ", %s", field->name);
785 ast_str_append(&vals, 0, ", ?");
786 }
787 ast_str_set(&sql, 0, "INSERT INTO %s (%s) VALUES (%s)",
788 table, ast_str_buffer(keys), ast_str_buffer(vals));
789
790 ast_free(vals);
791 ast_free(keys);
792 cps.sql = ast_str_buffer(sql);
793
794 if (ast_string_field_init(&cps, 256)) {
796 return -1;
797 }
800
801 if (!stmt) {
803 return -1;
804 }
805
806 res = SQLRowCount(stmt, &rowcount);
807 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
809
810 if (!SQL_SUCCEEDED(res)) {
811 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
812 return -1;
813 }
814
815 if (rowcount >= 0)
816 return (int)rowcount;
817
818 return -1;
819}
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659

References ast_free, ast_log, ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_request_obj2, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_str_thread_get(), ast_string_field_free_memory, ast_string_field_init, custom_prepare(), custom_prepare_struct::fields, LOG_WARNING, ast_variable::name, ast_variable::next, RES_ODBC_CONNECTED, custom_prepare_struct::sql, and SQL_BUF_SIZE.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1304 of file res_config_odbc.c.

1305{
1307 return 0;
1308}
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.

References ast_config_engine_deregister(), and odbc_engine.

◆ unload_odbc()

static int unload_odbc ( const char *  a,
const char *  b 
)
static

Definition at line 1249 of file res_config_odbc.c.

1250{
1251 return ast_odbc_clear_cache(a, b);
1252}
int ast_odbc_clear_cache(const char *database, const char *tablename)
Remove a cache entry from memory This function may be called to clear entries created and cached by t...
Definition res_odbc.c:348
static struct test_val b
static struct test_val a

References a, ast_odbc_clear_cache(), and b.

◆ update2_odbc()

static int update2_odbc ( const char *  database,
const char *  table,
const struct ast_variable lookup_fields,
const struct ast_variable update_fields 
)
static

Execute an UPDATE query.

Parameters
database,table,lookup_fields
update_fieldslist containing one or more field/value set(s).

Update a database table, preparing the sql statement from a list of key/value pairs specified in ap. The lookup pairs are specified first and are separated from the update pairs by a sentinel value. Sub-in the values to the prepared statement and execute it.

Returns
number of rows affected
Return values
-1on failure

Definition at line 687 of file res_config_odbc.c.

688{
689 struct odbc_obj *obj;
690 SQLHSTMT stmt;
691 struct update2_prepare_struct ups = {
693 .table = table,
694 .lookup_fields = lookup_fields,
695 .update_fields = update_fields,
696 };
697 struct ast_str *sql;
698 int res;
699 SQLLEN rowcount = 0;
700
701 ups.tableptr = ast_odbc_find_table(database, table);
702 if (!ups.tableptr) {
703 ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", table, database);
704 return -1;
705 }
706
707 if (!(obj = ast_odbc_request_obj(database, 0))) {
709 return -1;
710 }
711
712 if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
715 return -1;
716 }
717
718 /* We don't need the table anymore */
720
721 res = SQLRowCount(stmt, &rowcount);
722 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
724
725 if (!SQL_SUCCEEDED(res)) {
726 /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
727 sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
728 ast_assert(sql != NULL);
729 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
730 return -1;
731 }
732
733 if (rowcount >= 0) {
734 return (int) rowcount;
735 }
736
737 return -1;
738}
static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
#define ast_odbc_release_table(ptr)
Release a table returned from ast_odbc_find_table.
Definition res_odbc.h:219
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
Definition res_odbc.h:120
const struct ast_variable * lookup_fields
const struct ast_variable * update_fields
struct odbc_cache_tables * tableptr
#define ast_assert(a)
Definition utils.h:779

References ast_assert, ast_log, ast_odbc_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_release_table, ast_odbc_request_obj, ast_str_buffer(), ast_str_thread_get(), update2_prepare_struct::database, LOG_ERROR, LOG_WARNING, update2_prepare_struct::lookup_fields, NULL, SQL_BUF_SIZE, update2_prepare_struct::table, update2_prepare_struct::tableptr, update2_prepare(), and update2_prepare_struct::update_fields.

◆ update2_prepare()

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

Definition at line 617 of file res_config_odbc.c.

618{
619 int res, x = 1, first = 1;
620 struct update2_prepare_struct *ups = data;
621 const struct ast_variable *field;
622 struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
623 SQLHSTMT stmt;
624
625 if (!sql) {
626 return NULL;
627 }
628
629 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
630 if (!SQL_SUCCEEDED(res)) {
631 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
632 return NULL;
633 }
634
635 ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
636
637 for (field = ups->update_fields; field; field = field->next) {
638 if (ast_odbc_find_column(ups->tableptr, field->name)) {
639 ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", field->name);
640 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->name), 0, (void *)field->value, 0, NULL);
641 first = 0;
642 } else {
643 ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", field->name, ups->table, ups->database);
644 }
645 }
646
647 ast_str_append(&sql, 0, "WHERE");
648 first = 1;
649
650 for (field = ups->lookup_fields; field; field = field->next) {
651 if (!ast_odbc_find_column(ups->tableptr, field->name)) {
652 ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", field->name, ups->table, ups->database);
653 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
654 return NULL;
655 }
656 ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", field->name);
657 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->value), 0, (void *)field->value, 0, NULL);
658 first = 0;
659 }
660
661 res = ast_odbc_prepare(obj, stmt, ast_str_buffer(sql));
662 if (!SQL_SUCCEEDED(res)) {
663 if (res == SQL_ERROR) {
664 ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Prepare");
665 }
666 ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", ast_str_buffer(sql));
667 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
668 return NULL;
669 }
670
671 return stmt;
672}
struct sla_ringing_trunk * first
Definition app_sla.c:338
static const char name[]
Definition format_mp3.c:68
struct odbc_cache_columns * ast_odbc_find_column(struct odbc_cache_tables *table, const char *colname)
Find a column entry within a cached table structure.
Definition res_odbc.c:337

References ast_log, ast_odbc_find_column(), ast_odbc_prepare(), ast_odbc_print_errors(), ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), odbc_obj::con, update2_prepare_struct::database, first, LOG_ERROR, LOG_NOTICE, LOG_WARNING, update2_prepare_struct::lookup_fields, ast_variable::name, ast_variable::next, NULL, SQL_BUF_SIZE, update2_prepare_struct::table, update2_prepare_struct::tableptr, update2_prepare_struct::update_fields, and ast_variable::value.

Referenced by update2_odbc().

◆ update_odbc()

static int update_odbc ( const char *  database,
const char *  table,
const char *  keyfield,
const char *  lookup,
const struct ast_variable fields 
)
static

Execute an UPDATE query.

Parameters
database
table
keyfieldwhere clause field
lookupvalue of field for where clause
fieldslist containing one or more field/value set(s).

Update a database table, prepare the sql statement using keyfield and lookup control the number of records to change. All values to be changed are stored in ap list. Sub-in the values to the prepared statement and execute it.

Returns
number of rows affected
Return values
-1on failure

Definition at line 529 of file res_config_odbc.c.

530{
531 struct odbc_obj *obj;
532 SQLHSTMT stmt;
533 SQLLEN rowcount=0;
534 struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
535 const struct ast_variable *field = fields;
536 int res, count = 0, paramcount = 0;
537 struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
538 struct odbc_cache_tables *tableptr;
539 struct odbc_cache_columns *column = NULL;
540 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
541
542 if (!table || !field || !keyfield || !sql) {
543 return -1;
544 }
545
546 tableptr = ast_odbc_find_table(database, table);
547 if (!(obj = ast_odbc_request_obj2(database, connected_flag))) {
548 ast_odbc_release_table(tableptr);
549 return -1;
550 }
551
552 if (tableptr && !ast_odbc_find_column(tableptr, keyfield)) {
553 ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield, table, database);
554 }
555
556 ast_str_set(&sql, 0, "UPDATE %s SET ", table);
557 while (field) {
558 if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) {
559 if (paramcount++) {
560 ast_str_append(&sql, 0, ", ");
561 }
562 /* NULL test for non-text columns */
563 if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column)) {
564 ast_str_append(&sql, 0, "%s=NULL", field->name);
565 cps.skip |= (1LL << count);
566 } else {
567 /* Value is not an empty string, or column is of text type, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
568 ast_str_append(&sql, 0, "%s=?", field->name);
569 }
570 } else { /* the column does not exist in the table */
571 cps.skip |= (1LL << count);
572 }
573 ++count;
574 field = field->next;
575 }
576 ast_str_append(&sql, 0, " WHERE %s=?", keyfield);
577 ast_odbc_release_table(tableptr);
578
579 cps.sql = ast_str_buffer(sql);
580
581 if (ast_string_field_init(&cps, 256)) {
583 return -1;
584 }
587
588 if (!stmt) {
590 return -1;
591 }
592
593 res = SQLRowCount(stmt, &rowcount);
594 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
596
597 if (!SQL_SUCCEEDED(res)) {
598 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
599 return -1;
600 }
601
602 if (rowcount >= 0) {
603 return (int) rowcount;
604 }
605
606 return -1;
607}
static int is_text(const struct odbc_cache_columns *column)
SQLSMALLINT nullable
Definition res_odbc.h:65

References ast_log, ast_odbc_find_column(), ast_odbc_find_table(), ast_odbc_prepare_and_execute(), ast_odbc_release_obj(), ast_odbc_release_table, ast_odbc_request_obj2, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_thread_get(), ast_string_field_free_memory, ast_string_field_init, ast_strlen_zero(), custom_prepare(), custom_prepare_struct::extra, custom_prepare_struct::fields, is_text(), LOG_WARNING, ast_variable::name, ast_variable::next, NULL, odbc_cache_columns::nullable, RES_ODBC_CONNECTED, custom_prepare_struct::skip, custom_prepare_struct::sql, SQL_BUF_SIZE, and ast_variable::value.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime ODBC configuration" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, .requires = "extconfig,res_odbc", }
static

Definition at line 1317 of file res_config_odbc.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1317 of file res_config_odbc.c.

◆ odbc_engine

struct ast_config_engine odbc_engine
static

Definition at line 1254 of file res_config_odbc.c.

1254 {
1255 .name = "odbc",
1256 .load_func = config_odbc,
1257 .realtime_func = realtime_odbc,
1258 .realtime_multi_func = realtime_multi_odbc,
1259 .store_func = store_odbc,
1260 .destroy_func = destroy_odbc,
1261 .update_func = update_odbc,
1262 .update2_func = update2_odbc,
1263 .require_func = require_odbc,
1264 .unload_func = unload_odbc,
1265};
static struct ast_config * config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
static struct ast_variable * realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an SQL query and return ast_variable list.
static int require_odbc(const char *database, const char *table, va_list ap)
static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Execute an UPDATE query.
static struct ast_config * realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an Select query and return ast_config list.
static int update2_odbc(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
Execute an UPDATE query.
static int unload_odbc(const char *a, const char *b)
static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an INSERT query.
static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Execute an DELETE query.

Referenced by load_module(), and unload_module().

◆ order_multi_row_results_by_initial_column

int order_multi_row_results_by_initial_column = 1
static

Definition at line 53 of file res_config_odbc.c.

Referenced by load_config(), and realtime_multi_odbc().

◆ res_config_odbc_conf

const char* res_config_odbc_conf = "res_config_odbc.conf"
static

Definition at line 52 of file res_config_odbc.c.

Referenced by config_odbc(), load_module(), and reload_module().