Asterisk - The Open Source Telephony Project GIT-master-43bf8a4
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 1083 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 1084 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 1312 of file res_config_odbc.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1312 of file res_config_odbc.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1312 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 951 of file res_config_odbc.c.

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

925{
926 struct config_odbc_obj *q = data;
927 SQLHSTMT sth;
928 int res;
929
930 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
931 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
932 ast_verb(4, "Failure in AllocStatement %d\n", res);
933 return NULL;
934 }
935
936 res = ast_odbc_prepare(obj, sth, q->sql);
937 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
938 ast_verb(4, "Error in PREPARE %d\n", res);
939 SQLFreeHandle(SQL_HANDLE_STMT, sth);
940 return NULL;
941 }
942
943 SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
944 SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
945 SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
946 SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, q->var_val_size, &q->err);
947
948 return sth;
949}
#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 ((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:520
#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 834 of file res_config_odbc.c.

835{
836 struct odbc_obj *obj;
837 SQLHSTMT stmt;
838 SQLLEN rowcount=0;
840 const struct ast_variable *field;
841 int res;
842 struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
843 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
844
845 if (!table || !sql) {
846 return -1;
847 }
848
849 obj = ast_odbc_request_obj2(database, connected_flag);
850 if (!obj) {
851 return -1;
852 }
853
854 ast_str_set(&sql, 0, "DELETE FROM %s WHERE ", table);
855 for (field = fields; field; field = field->next) {
856 ast_str_append(&sql, 0, "%s=? AND ", field->name);
857 }
858 ast_str_append(&sql, 0, "%s=?", keyfield);
859
860 cps.sql = ast_str_buffer(sql);
861
862 if (ast_string_field_init(&cps, 256)) {
864 return -1;
865 }
868
869 if (!stmt) {
871 return -1;
872 }
873
874 res = SQLRowCount(stmt, &rowcount);
875 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
877
878 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
879 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
880 return -1;
881 }
882
883 if (rowcount >= 0)
884 return (int)rowcount;
885
886 return -1;
887}
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 900 of file res_config_odbc.c.

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

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

1263{
1264 struct ast_config *config;
1265 struct ast_flags config_flags = { 0 };
1266 const char *s;
1267
1268 config = ast_config_load(filename, config_flags);
1271 ast_log(LOG_WARNING, "Unable to load config '%s'. Using defaults.\n", filename);
1272 }
1274 return;
1275 }
1276
1277 /* Result set ordering is enabled by default */
1278 s = ast_variable_retrieve(config, "general", "order_multi_row_results_by_initial_column");
1280
1282}
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:869
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 1284 of file res_config_odbc.c.

1285{
1286 /* We'll either successfully load the configuration or fail with reasonable
1287 * defaults */
1290 return 0;
1291}
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
Definition: main/config.c:3377
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 350 of file res_config_odbc.c.

351{
352 struct odbc_obj *obj;
353 SQLHSTMT stmt;
354 char coltitle[256];
356 struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
357 const char *initfield;
358 char *op;
359 const struct ast_variable *field = fields;
360 char *stringp;
361 char *chunk;
362 SQLSMALLINT collen;
363 int res;
364 int x;
365 struct ast_variable *var=NULL;
366 struct ast_config *cfg=NULL;
367 struct ast_category *cat=NULL;
368 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
369 SQLULEN colsize;
370 SQLSMALLINT colcount=0;
371 SQLSMALLINT datatype;
372 SQLSMALLINT decimaldigits;
373 SQLSMALLINT nullable;
374 SQLLEN indicator;
375 struct custom_prepare_struct cps = { .fields = fields, };
376
377 if (!table || !field || !sql || !rowdata) {
378 return NULL;
379 }
380
381 obj = ast_odbc_request_obj2(database, connected_flag);
382 if (!obj) {
383 return NULL;
384 }
385
386 initfield = ast_strdupa(field->name);
387 if ((op = strchr(initfield, ' '))) {
388 *op = '\0';
389 }
390
391 op = !strchr(field->name, ' ') ? " =" : "";
392 ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
393 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
394 while ((field = field->next)) {
395 op = !strchr(field->name, ' ') ? " =" : "";
396 ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
397 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
398 }
399
401 ast_str_append(&sql, 0, " ORDER BY %s", initfield);
402 }
403
404 cps.sql = ast_str_buffer(sql);
405
406 if (ast_string_field_init(&cps, 256)) {
408 return NULL;
409 }
412
413 if (!stmt) {
415 return NULL;
416 }
417
418 res = SQLNumResultCols(stmt, &colcount);
419 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
420 ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
421 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
423 return NULL;
424 }
425
426 cfg = ast_config_new();
427 if (!cfg) {
428 ast_log(LOG_WARNING, "Out of memory!\n");
429 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
431 return NULL;
432 }
433
434 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
435 var = NULL;
436 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
437 ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
438 continue;
439 }
441 if (!cat) {
442 continue;
443 }
444 for (x=0;x<colcount;x++) {
445 colsize = 0;
446 collen = sizeof(coltitle);
447 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
448 &datatype, &colsize, &decimaldigits, &nullable);
449 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
450 ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
452 goto next_sql_fetch;
453 }
454
455 ast_str_reset(rowdata);
456 indicator = 0;
457
458 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
459 ast_str_update(rowdata);
460 if (indicator == SQL_NULL_DATA) {
461 continue;
462 }
463
464 if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
465 if (indicator != ast_str_strlen(rowdata)) {
466 /* If the available space was not enough to contain the row data enlarge and read in the rest */
467 ast_str_make_space(&rowdata, indicator + 1);
468 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
469 ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
470 ast_str_update(rowdata);
471 }
472 }
473
474 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
475 ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
477 goto next_sql_fetch;
478 }
479 stringp = ast_str_buffer(rowdata);
480 if (!strncmp(coltitle, "@", 1)) {
481 /* The '@' prefix indicates it's a sorcery extended field.
482 * Because ast_load_realtime_fields eliminates empty entries and makes blank (single whitespace)
483 * entries empty and keeps them, the empty or NULL values are encoded
484 * as a string containing a single whitespace. */
485 var = ast_variable_new(coltitle, S_OR(stringp," "), "");
487 } else {
488 while (stringp) {
489 chunk = strsep(&stringp, ";");
490 if (!ast_strlen_zero(ast_strip(chunk))) {
491 if (strchr(chunk, '^')) {
492 decode_chunk(chunk);
493 }
494 if (!strcmp(initfield, coltitle)) {
495 ast_category_rename(cat, chunk);
496 }
497 var = ast_variable_new(coltitle, chunk, "");
499 }
500 }
501 }
502 }
503 ast_category_append(cfg, cat);
504next_sql_fetch:;
505 }
506
507 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
509 return cfg;
510}
#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)
Definition: main/config.c:1563
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:884
#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 (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];
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 ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
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 ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
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 ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
261 ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
262 if (var)
265 return NULL;
266 }
267
268 ast_str_reset(rowdata);
269 indicator = 0;
270
271 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
272 ast_str_update(rowdata);
273 if (indicator == SQL_NULL_DATA) {
274 ast_str_reset(rowdata);
275 } else if (!ast_str_strlen(rowdata)) {
276 /* Because we encode the empty string for a NULL, we will encode
277 * actual empty strings as a string containing a single whitespace. */
278 ast_str_set(&rowdata, -1, "%s", " ");
279 } else if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
280 if (indicator != ast_str_strlen(rowdata)) {
281 /* If the available space was not enough to contain the row data enlarge and read in the rest */
282 ast_str_make_space(&rowdata, indicator + 1);
283 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
284 ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
285 ast_str_update(rowdata);
286 }
287 }
288
289 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
290 ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
291 if (var)
294 return NULL;
295 }
296
297 stringp = ast_str_buffer(rowdata);
298 if (!strncmp(coltitle, "@", 1)) {
299 /* The '@' prefix indicates it's a sorcery extended field.
300 * Because ast_load_realtime_fields eliminates empty entries and makes blank (single whitespace)
301 * entries empty and keeps them, the empty or NULL values are encoded
302 * as a string containing a single whitespace. */
303 if (prev) {
304 prev->next = ast_variable_new(coltitle, S_OR(stringp," "), "");
305 if (prev->next) {
306 prev = prev->next;
307 }
308 } else {
309 prev = var = ast_variable_new(coltitle, S_OR(stringp," "), "");
310 }
311 } else {
312 while (stringp) {
313 chunk = strsep(&stringp, ";");
314 if (!ast_strlen_zero(ast_strip(chunk))) {
315 if (strchr(chunk, '^')) {
316 decode_chunk(chunk);
317 }
318 if (prev) {
319 prev->next = ast_variable_new(coltitle, chunk, "");
320 if (prev->next) {
321 prev = prev->next;
322 }
323 } else {
324 prev = var = ast_variable_new(coltitle, chunk, "");
325 }
326 }
327 }
328 }
329 }
330
331 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
333 return var;
334}
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#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, 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 1293 of file res_config_odbc.c.

1294{
1296 return 0;
1297}

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

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

752{
753 struct odbc_obj *obj;
754 SQLHSTMT stmt;
755 SQLLEN rowcount=0;
756 const struct ast_variable *field = fields;
757 struct ast_str *keys;
758 struct ast_str *vals;
760 int res;
761 struct custom_prepare_struct cps = { .fields = fields, };
762 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
763
765 vals = ast_str_create(SQL_BUF_SIZE / 4);
766 if (!table || !field || !keys || !vals || !sql) {
767 ast_free(vals);
768 ast_free(keys);
769 return -1;
770 }
771
772 obj = ast_odbc_request_obj2(database, connected_flag);
773 if (!obj) {
774 ast_free(vals);
775 ast_free(keys);
776 return -1;
777 }
778
779 ast_str_set(&keys, 0, "%s", field->name);
780 ast_str_set(&vals, 0, "?");
781 while ((field = field->next)) {
782 ast_str_append(&keys, 0, ", %s", field->name);
783 ast_str_append(&vals, 0, ", ?");
784 }
785 ast_str_set(&sql, 0, "INSERT INTO %s (%s) VALUES (%s)",
787
788 ast_free(vals);
789 ast_free(keys);
790 cps.sql = ast_str_buffer(sql);
791
792 if (ast_string_field_init(&cps, 256)) {
794 return -1;
795 }
798
799 if (!stmt) {
801 return -1;
802 }
803
804 res = SQLRowCount(stmt, &rowcount);
805 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
807
808 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
809 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
810 return -1;
811 }
812
813 if (rowcount >= 0)
814 return (int)rowcount;
815
816 return -1;
817}
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 1299 of file res_config_odbc.c.

1300{
1302 return 0;
1303}
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
Definition: main/config.c:3393

References ast_config_engine_deregister(), and odbc_engine.

◆ unload_odbc()

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

Definition at line 1244 of file res_config_odbc.c.

1245{
1246 return ast_odbc_clear_cache(a, b);
1247}
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 685 of file res_config_odbc.c.

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

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

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

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

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1312 of file res_config_odbc.c.

◆ odbc_engine

struct ast_config_engine odbc_engine
static

Definition at line 1249 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