Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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 __init_rowdata_buf (void)
 
static void __init_sql_buf (void)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Realtime ODBC configuration" , .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_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"
 
static struct ast_threadstorage rowdata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_rowdata_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+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.

◆ 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 1078 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 1079 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[]
Definition: chan_ooh323.c:109
int ast_rq_is_int(require_type type)
Check if require type is an integer type.

Function Documentation

◆ __init_rowdata_buf()

static void __init_rowdata_buf ( void  )
static

Definition at line 56 of file res_config_odbc.c.

58{

◆ __init_sql_buf()

static void __init_sql_buf ( void  )
static

Definition at line 55 of file res_config_odbc.c.

58{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1307 of file res_config_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1307 of file res_config_odbc.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1307 of file res_config_odbc.c.

◆ 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 946 of file res_config_odbc.c.

947{
948 struct ast_variable *new_v;
949 struct ast_category *cur_cat;
950 int res = 0;
951 struct odbc_obj *obj;
953 unsigned int last_cat_metric = 0;
954 SQLSMALLINT rowcount = 0;
955 SQLHSTMT stmt;
956 char last[128] = "";
957 struct config_odbc_obj q;
958 struct ast_flags loader_flags = { 0 };
959 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
960
961 memset(&q, 0, sizeof(q));
962
963 if (!file || !strcmp (file, res_config_odbc_conf) || !sql) {
964 return NULL; /* cant configure myself with myself ! */
965 }
966
967 obj = ast_odbc_request_obj2(database, connected_flag);
968 if (!obj)
969 return NULL;
970
971 ast_str_set(&sql, 0, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'",
972 table, file);
973 q.sql = ast_str_buffer(sql);
974
976 if (!stmt) {
977 ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
979 return NULL;
980 }
981
982 res = SQLNumResultCols(stmt, &rowcount);
983
984 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
985 ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
986 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
988 return NULL;
989 }
990
991 if (!rowcount) {
992 ast_log(LOG_NOTICE, "found nothing\n");
994 return cfg;
995 }
996
997 /* There will be only one result for this, the maximum length of a variable value */
998 if (SQLFetch(stmt) == SQL_NO_DATA) {
999 ast_log(LOG_NOTICE, "Failed to determine maximum length of a configuration value\n");
1000 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1002 return NULL;
1003 }
1004
1005 /* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
1006 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1007
1008 ast_str_set(&sql, 0, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
1009 ast_str_append(&sql, 0, "WHERE filename='%s' AND commented=0 ", file);
1010 ast_str_append(&sql, 0, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
1011 q.sql = ast_str_buffer(sql);
1012
1013 q.var_val_size += 1;
1014 q.var_val = ast_malloc(q.var_val_size);
1015 if (!q.var_val) {
1016 ast_log(LOG_WARNING, "Could not create buffer for reading in configuration values for '%s'\n", file);
1018 return NULL;
1019 }
1020
1022 if (!stmt) {
1023 ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
1025 ast_free(q.var_val);
1026 return NULL;
1027 }
1028
1029 res = SQLNumResultCols(stmt, &rowcount);
1030
1031 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1032 ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
1033 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1035 ast_free(q.var_val);
1036 return NULL;
1037 }
1038
1039 if (!rowcount) {
1040 ast_log(LOG_NOTICE, "found nothing\n");
1042 ast_free(q.var_val);
1043 return cfg;
1044 }
1045
1046 cur_cat = ast_config_get_current_category(cfg);
1047
1048 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
1049 if (!strcmp (q.var_name, "#include")) {
1050 if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
1051 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1053 ast_free(q.var_val);
1054 return NULL;
1055 }
1056 continue;
1057 }
1058 if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
1059 cur_cat = ast_category_new_dynamic(q.category);
1060 if (!cur_cat) {
1061 break;
1062 }
1063 strcpy(last, q.category);
1064 last_cat_metric = q.cat_metric;
1065 ast_category_append(cfg, cur_cat);
1066 }
1067
1068 new_v = ast_variable_new(q.var_name, q.var_val, "");
1069 ast_variable_append(cur_cat, new_v);
1070 }
1071
1072 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1074 ast_free(q.var_val);
1075 return cfg;
1076}
struct sla_ringing_trunk * last
Definition: app_sla.c:332
#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
static char * table
Definition: cdr_odbc.c:55
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition: extconf.c:2833
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: extconf.c:1177
#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:2781
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)
Definition: main/config.c:3279
#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
static struct ast_threadstorage sql_buf
@ 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:804
#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:398
#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
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
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:199
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(), make_ari_stubs::file, last, length_determination_odbc_prepare(), LOG_NOTICE, LOG_WARNING, NULL, res_config_odbc_conf, RES_ODBC_CONNECTED, config_odbc_obj::sql, sql_buf, SQL_BUF_SIZE, table, 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 919 of file res_config_odbc.c.

920{
921 struct config_odbc_obj *q = data;
922 SQLHSTMT sth;
923 int res;
924
925 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
926 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
927 ast_verb(4, "Failure in AllocStatement %d\n", res);
928 return NULL;
929 }
930
931 res = ast_odbc_prepare(obj, sth, q->sql);
932 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
933 ast_verb(4, "Error in PREPARE %d\n", res);
934 SQLFreeHandle(SQL_HANDLE_STMT, sth);
935 return NULL;
936 }
937
938 SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
939 SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
940 SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
941 SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, q->var_val_size, &q->err);
942
943 return sth;
944}
#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:454
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 ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
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 ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
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:515
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
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 829 of file res_config_odbc.c.

830{
831 struct odbc_obj *obj;
832 SQLHSTMT stmt;
833 SQLLEN rowcount=0;
835 const struct ast_variable *field;
836 int res;
837 struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
838 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
839
840 if (!table || !sql) {
841 return -1;
842 }
843
844 obj = ast_odbc_request_obj2(database, connected_flag);
845 if (!obj) {
846 return -1;
847 }
848
849 ast_str_set(&sql, 0, "DELETE FROM %s WHERE ", table);
850 for (field = fields; field; field = field->next) {
851 ast_str_append(&sql, 0, "%s=? AND ", field->name);
852 }
853 ast_str_append(&sql, 0, "%s=?", keyfield);
854
855 cps.sql = ast_str_buffer(sql);
856
857 if (ast_string_field_init(&cps, 256)) {
859 return -1;
860 }
863
864 if (!stmt) {
866 return -1;
867 }
868
869 res = SQLRowCount(stmt, &rowcount);
870 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
872
873 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
874 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
875 return -1;
876 }
877
878 if (rowcount >= 0)
879 return (int)rowcount;
880
881 return -1;
882}
static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374

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, sql_buf, SQL_BUF_SIZE, and table.

◆ 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 895 of file res_config_odbc.c.

896{
897 struct config_odbc_obj *q = data;
898 SQLHSTMT sth;
899 int res;
900
901 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
902 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
903 ast_verb(4, "Failure in AllocStatement %d\n", res);
904 return NULL;
905 }
906
907 res = ast_odbc_prepare(obj, sth, q->sql);
908 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
909 ast_verb(4, "Error in PREPARE %d\n", res);
910 SQLFreeHandle(SQL_HANDLE_STMT, sth);
911 return NULL;
912 }
913
914 SQLBindCol(sth, 1, SQL_C_ULONG, &q->var_val_size, sizeof(q->var_val_size), &q->err);
915
916 return sth;
917}

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 1257 of file res_config_odbc.c.

1258{
1259 struct ast_config *config;
1260 struct ast_flags config_flags = { 0 };
1261 const char *s;
1262
1263 config = ast_config_load(filename, config_flags);
1266 ast_log(LOG_WARNING, "Unable to load config '%s'. Using defaults.\n", filename);
1267 }
1269 return;
1270 }
1271
1272 /* Result set ordering is enabled by default */
1273 s = ast_variable_retrieve(config, "general", "order_multi_row_results_by_initial_column");
1275
1277}
static const char config[]
Definition: chan_ooh323.c:111
#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:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
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:2199

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.

Referenced by load_module(), and reload_module().

◆ load_module()

static int load_module ( void  )
static

Definition at line 1279 of file res_config_odbc.c.

1280{
1281 /* We'll either successfully load the configuration or fail with reasonable
1282 * defaults */
1285 return 0;
1286}
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
Definition: main/config.c:3157
static struct ast_config_engine odbc_engine
static void load_config(const char *filename)

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 345 of file res_config_odbc.c.

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

Definition at line 173 of file res_config_odbc.c.

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

◆ reload_module()

static int reload_module ( void  )
static

Definition at line 1288 of file res_config_odbc.c.

1289{
1291 return 0;
1292}

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 1081 of file res_config_odbc.c.

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

747{
748 struct odbc_obj *obj;
749 SQLHSTMT stmt;
750 SQLLEN rowcount=0;
751 const struct ast_variable *field = fields;
752 struct ast_str *keys;
753 struct ast_str *vals;
755 int res;
756 struct custom_prepare_struct cps = { .fields = fields, };
757 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
758
760 vals = ast_str_create(SQL_BUF_SIZE / 4);
761 if (!table || !field || !keys || !vals || !sql) {
762 ast_free(vals);
763 ast_free(keys);
764 return -1;
765 }
766
767 obj = ast_odbc_request_obj2(database, connected_flag);
768 if (!obj) {
769 ast_free(vals);
770 ast_free(keys);
771 return -1;
772 }
773
774 ast_str_set(&keys, 0, "%s", field->name);
775 ast_str_set(&vals, 0, "?");
776 while ((field = field->next)) {
777 ast_str_append(&keys, 0, ", %s", field->name);
778 ast_str_append(&vals, 0, ", ?");
779 }
780 ast_str_set(&sql, 0, "INSERT INTO %s (%s) VALUES (%s)",
782
783 ast_free(vals);
784 ast_free(keys);
785 cps.sql = ast_str_buffer(sql);
786
787 if (ast_string_field_init(&cps, 256)) {
789 return -1;
790 }
793
794 if (!stmt) {
796 return -1;
797 }
798
799 res = SQLRowCount(stmt, &rowcount);
800 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
802
803 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
804 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
805 return -1;
806 }
807
808 if (rowcount >= 0)
809 return (int)rowcount;
810
811 return -1;
812}
static struct keys keys
#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, keys, LOG_WARNING, ast_variable::name, ast_variable::next, RES_ODBC_CONNECTED, custom_prepare_struct::sql, sql_buf, SQL_BUF_SIZE, and table.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1294 of file res_config_odbc.c.

1295{
1297 return 0;
1298}
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
Definition: main/config.c:3173

References ast_config_engine_deregister(), and odbc_engine.

◆ unload_odbc()

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

Definition at line 1239 of file res_config_odbc.c.

1240{
1241 return ast_odbc_clear_cache(a, b);
1242}
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:343
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 680 of file res_config_odbc.c.

681{
682 struct odbc_obj *obj;
683 SQLHSTMT stmt;
684 struct update2_prepare_struct ups = {
686 .table = table,
687 .lookup_fields = lookup_fields,
688 .update_fields = update_fields,
689 };
690 struct ast_str *sql;
691 int res;
692 SQLLEN rowcount = 0;
693
694 ups.tableptr = ast_odbc_find_table(database, table);
695 if (!ups.tableptr) {
696 ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", table, database);
697 return -1;
698 }
699
700 if (!(obj = ast_odbc_request_obj(database, 0))) {
702 return -1;
703 }
704
705 if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
708 return -1;
709 }
710
711 /* We don't need the table anymore */
713
714 res = SQLRowCount(stmt, &rowcount);
715 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
717
718 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
719 /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
721 ast_assert(sql != NULL);
722 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
723 return -1;
724 }
725
726 if (rowcount >= 0) {
727 return (int) rowcount;
728 }
729
730 return -1;
731}
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:739

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, SQL_BUF_SIZE, 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 610 of file res_config_odbc.c.

611{
612 int res, x = 1, first = 1;
613 struct update2_prepare_struct *ups = data;
614 const struct ast_variable *field;
616 SQLHSTMT stmt;
617
618 if (!sql) {
619 return NULL;
620 }
621
622 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
623 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
624 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
625 return NULL;
626 }
627
628 ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
629
630 for (field = ups->update_fields; field; field = field->next) {
631 if (ast_odbc_find_column(ups->tableptr, field->name)) {
632 ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", field->name);
633 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->name), 0, (void *)field->value, 0, NULL);
634 first = 0;
635 } else {
636 ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", field->name, ups->table, ups->database);
637 }
638 }
639
640 ast_str_append(&sql, 0, "WHERE");
641 first = 1;
642
643 for (field = ups->lookup_fields; field; field = field->next) {
644 if (!ast_odbc_find_column(ups->tableptr, field->name)) {
645 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);
646 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
647 return NULL;
648 }
649 ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", field->name);
650 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->value), 0, (void *)field->value, 0, NULL);
651 first = 0;
652 }
653
654 res = ast_odbc_prepare(obj, stmt, ast_str_buffer(sql));
655 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
656 if (res == SQL_ERROR) {
657 ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Prepare");
658 }
659 ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", ast_str_buffer(sql));
660 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
661 return NULL;
662 }
663
664 return stmt;
665}
struct sla_ringing_trunk * first
Definition: app_sla.c:332
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:332

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, 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 522 of file res_config_odbc.c.

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

Definition at line 1307 of file res_config_odbc.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1307 of file res_config_odbc.c.

◆ odbc_engine

struct ast_config_engine odbc_engine
static

Definition at line 1244 of file res_config_odbc.c.

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

◆ rowdata_buf

struct ast_threadstorage rowdata_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_rowdata_buf , .custom_init = NULL , }
static

Definition at line 56 of file res_config_odbc.c.

Referenced by realtime_multi_odbc(), and realtime_odbc().

◆ sql_buf

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