40 #include "asterisk/file.h"
63 #define ENCODE_CHUNK(buffer, s) \
65 char *eptr = buffer; \
66 const char *vptr = s; \
67 for (; *vptr && eptr < buffer + sizeof(buffer); vptr++) { \
68 if (strchr("^;", *vptr)) { \
70 snprintf(eptr, buffer + sizeof(buffer) - eptr, "^%02hhX", *vptr); \
76 if (eptr < buffer + sizeof(buffer)) { \
79 buffer[sizeof(buffer) - 1] = '\0'; \
85 for (; *chunk; chunk++) {
86 if (*chunk ==
'^' && strchr(
"0123456789ABCDEF", chunk[1]) && strchr(
"0123456789ABCDEF", chunk[2])) {
87 sscanf(chunk + 1,
"%02hhX", (
unsigned char *)chunk);
88 memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
95 return column->
type == SQL_CHAR || column->
type == SQL_VARCHAR || column->
type == SQL_LONGVARCHAR
96 || column->
type == SQL_WCHAR || column->
type == SQL_WVARCHAR || column->
type == SQL_WLONGVARCHAR;
101 int res, x = 1, count = 0;
103 const char *newparam, *newval;
104 char encodebuf[1024];
108 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
109 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
116 res = SQLPrepare(stmt, (
unsigned char *)cps->
sql, SQL_NTS);
117 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
119 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
123 va_copy(ap, cps->
ap);
124 while ((newparam = va_arg(ap,
const char *))) {
125 newval = va_arg(ap,
const char *);
126 if ((1LL << count++) & cps->
skip) {
127 ast_debug(1,
"Skipping field '%s'='%s' (%llo/%llo)\n", newparam, newval, 1ULL << (count - 1), cps->
skip);
130 ast_debug(1,
"Parameter %d ('%s') = '%s'\n", x, newparam, newval);
131 if (strchr(newval,
';') || strchr(newval,
'^')) {
136 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (
void *)newval, 0, NULL);
141 const char *newval = cps->
extra;
142 if (strchr(newval,
';') || strchr(newval,
'^')) {
147 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (
void *)newval, 0, NULL);
174 const char *newparam;
182 SQLSMALLINT colcount=0;
183 SQLSMALLINT datatype;
184 SQLSMALLINT decimaldigits;
185 SQLSMALLINT nullable;
198 ast_log(
LOG_ERROR,
"No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
203 newparam = va_arg(aq,
const char *);
209 va_arg(aq,
const char *);
210 op = !strchr(newparam,
' ') ?
" =" :
"";
211 snprintf(sql,
sizeof(sql),
"SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
213 while((newparam = va_arg(aq,
const char *))) {
214 op = !strchr(newparam,
' ') ?
" =" :
"";
215 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
" AND %s%s ?%s", newparam, op,
217 va_arg(aq,
const char *);
235 res = SQLNumResultCols(stmt, &colcount);
236 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
238 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
243 res = SQLFetch(stmt);
244 if (res == SQL_NO_DATA) {
245 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
249 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
251 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
255 for (x = 0; x < colcount; x++) {
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)) {
273 if (indicator == SQL_NULL_DATA) {
279 }
else if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
289 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
299 chunk =
strsep(&stringp,
";");
301 if (strchr(chunk,
'^')) {
316 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
342 const char *initfield;
344 const char *newparam;
355 SQLSMALLINT colcount=0;
356 SQLSMALLINT datatype;
357 SQLSMALLINT decimaldigits;
358 SQLSMALLINT nullable;
373 newparam = va_arg(aq,
const char *);
381 if ((op = strchr(initfield,
' '))) {
385 va_arg(aq,
const char *);
386 op = !strchr(newparam,
' ') ?
" =" :
"";
387 snprintf(sql,
sizeof(sql),
"SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
389 while((newparam = va_arg(aq,
const char *))) {
390 op = !strchr(newparam,
' ') ?
" =" :
"";
391 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
" AND %s%s ?%s", newparam, op,
393 va_arg(aq,
const char *);
397 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
" ORDER BY %s", initfield);
413 res = SQLNumResultCols(stmt, &colcount);
414 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
416 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
424 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
429 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
431 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
440 for (x=0;x<colcount;x++) {
442 collen =
sizeof(coltitle);
443 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *)coltitle,
sizeof(coltitle), &collen,
444 &datatype, &colsize, &decimaldigits, &nullable);
445 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
456 if (indicator == SQL_NULL_DATA) {
460 if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
470 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
477 chunk =
strsep(&stringp,
";");
479 if (strchr(chunk,
'^')) {
482 if (!strcmp(initfield, coltitle)) {
494 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
514 static int update_odbc(
const char *database,
const char *
table,
const char *keyfield,
const char *lookup, va_list
ap)
520 const char *newparam, *newval;
521 int res, count = 0, paramcount = 0;
528 if (!table || !keyfield) {
539 ast_log(
LOG_WARNING,
"Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield, table, database);
544 snprintf(sql,
sizeof(sql),
"UPDATE %s SET ", table);
545 while((newparam = va_arg(aq,
const char *))) {
546 newval = va_arg(aq,
const char *);
549 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
", ");
553 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
"%s=NULL", newparam);
554 cps.
skip |= (1LL << count);
557 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
"%s=?", newparam);
560 cps.
skip |= (1LL << count);
565 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
" WHERE %s=?", keyfield);
582 res = SQLRowCount(stmt, &rowcount);
583 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
586 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
592 return (
int) rowcount;
606 int res, x = 1,
first = 1;
608 const char *newparam, *newval;
626 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
627 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
636 va_copy(ap, ups->
ap);
638 while ((newparam = va_arg(ap,
const char *))) {
639 newval = va_arg(ap,
const char *);
642 while ((newparam = va_arg(ap,
const char *))) {
643 newval = va_arg(ap,
const char *);
646 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (
void *)newval, 0, NULL);
658 va_copy(ap, ups->
ap);
660 while ((newparam = va_arg(ap,
const char *))) {
661 newval = va_arg(ap,
const char *);
664 ast_log(
LOG_ERROR,
"One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", newparam, ups->
table, ups->
database);
666 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
670 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (
void *)newval, 0, NULL);
678 res = SQLPrepare(stmt, (
unsigned char *)
ast_str_buffer(sql), SQL_NTS);
679 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
681 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
723 res = SQLRowCount(stmt, &rowcount);
724 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
727 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
735 return (
int)rowcount;
762 const char *newparam;
779 newparam = va_arg(aq,
const char *);
785 va_arg(aq,
const char *);
786 snprintf(keys,
sizeof(keys),
"%s", newparam);
788 while ((newparam = va_arg(aq,
const char *))) {
789 snprintf(keys + strlen(keys),
sizeof(keys) - strlen(keys),
", %s", newparam);
790 snprintf(vals + strlen(vals),
sizeof(vals) - strlen(vals),
", ?");
791 va_arg(aq,
const char *);
794 snprintf(sql,
sizeof(sql),
"INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
810 res = SQLRowCount(stmt, &rowcount);
811 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
814 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
820 return (
int)rowcount;
840 static int destroy_odbc(
const char *database,
const char *
table,
const char *keyfield,
const char *lookup, va_list ap)
846 const char *newparam;
861 snprintf(sql,
sizeof(sql),
"DELETE FROM %s WHERE ", table);
864 while((newparam = va_arg(aq,
const char *))) {
865 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
"%s=? AND ", newparam);
866 va_arg(aq,
const char *);
869 snprintf(sql + strlen(sql),
sizeof(sql) - strlen(sql),
"%s=?", keyfield);
885 res = SQLRowCount(stmt, &rowcount);
886 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
889 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
895 return (
int)rowcount;
917 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &sth);
918 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
919 ast_verb(4,
"Failure in AllocStatement %d\n", res);
923 res = SQLPrepare(sth, (
unsigned char *)q->
sql, SQL_NTS);
924 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
925 ast_verb(4,
"Error in PREPARE %d\n", res);
926 SQLFreeHandle(SQL_HANDLE_STMT, sth);
941 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &sth);
942 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
943 ast_verb(4,
"Failure in AllocStatement %d\n", res);
947 res = SQLPrepare(sth, (
unsigned char *)q->
sql, SQL_NTS);
948 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
949 ast_verb(4,
"Error in PREPARE %d\n", res);
950 SQLFreeHandle(SQL_HANDLE_STMT, sth);
968 char sqlbuf[1024] =
"";
970 size_t sqlleft =
sizeof(sqlbuf);
971 unsigned int last_cat_metric = 0;
972 SQLSMALLINT rowcount = 0;
979 memset(&q, 0,
sizeof(q));
981 if (!file || !strcmp (file,
"res_config_odbc.conf"))
990 ast_build_string(&sql, &sqlleft,
"SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'", table, file);
1000 res = SQLNumResultCols(stmt, &rowcount);
1002 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1004 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1016 if (SQLFetch(stmt) == SQL_NO_DATA) {
1017 ast_log(
LOG_NOTICE,
"Failed to determine maximum length of a configuration value\n");
1018 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1024 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1026 sqlleft =
sizeof(sqlbuf);
1028 ast_build_string(&sql, &sqlleft,
"SELECT cat_metric, category, var_name, var_val FROM %s ", table);
1029 ast_build_string(&sql, &sqlleft,
"WHERE filename='%s' AND commented=0 ", file);
1030 ast_build_string(&sql, &sqlleft,
"ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
1035 ast_log(
LOG_WARNING,
"Could not create buffer for reading in configuration values for '%s'\n", file);
1049 res = SQLNumResultCols(stmt, &rowcount);
1051 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1053 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1068 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
1069 if (!strcmp (q.
var_name,
"#include")) {
1071 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1093 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1099 #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)
1100 #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)
1113 while ((elm = va_arg(ap,
char *))) {
1115 size = va_arg(ap,
int);
1118 if (strcmp(col->
name, elm) == 0) {
1120 switch (col->
type) {
1123 case SQL_LONGVARCHAR:
1124 #ifdef HAVE_ODBC_WCHAR
1127 case SQL_WLONGVARCHAR:
1131 case SQL_LONGVARBINARY:
1133 #define CHECK_SIZE(n) \
1134 if (col->size < n) { \
1135 warn_length(col, n); \
1161 case SQL_TYPE_TIMESTAMP:
1170 #define WARN_TYPE_OR_LENGTH(n) \
1171 if (!ast_rq_is_int(type)) { \
1172 warn_type(col, type); \
1174 warn_length(col, n); \
1181 case SQL_C_STINYINT:
1233 #undef WARN_TYPE_OR_LENGTH
1244 ast_log(
LOG_WARNING,
"Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->
type, elm);
1250 ast_log(
LOG_WARNING,
"Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm);
1281 ast_verb(1,
"res_config_odbc unloaded.\n");
1288 ast_verb(1,
"res_config_odbc loaded.\n");
static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
Excute an DELETE query.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
Checks if the database natively supports backslash as an escape character.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
char * strsep(char **str, const char *delims)
#define ast_odbc_release_table(ptr)
Release a table returned from ast_odbc_find_table.
static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
Excute an UPDATE query.
static int store_odbc(const char *database, const char *table, va_list ap)
Excute an INSERT query.
static int unload_odbc(const char *a, const char *b)
static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
static SQLHSTMT length_determination_odbc_prepare(struct odbc_obj *obj, void *data)
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
Structure for variables, used for configurations and for channel variables.
static int load_module(void)
Configuration File Parser.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ast_odbc_request_obj2(a, b)
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
These structures are used for adaptive capabilities.
#define ast_verb(level,...)
static int unload_module(void)
Configuration engine structure, used to define realtime drivers.
String fields in structures.
static struct ast_variable * realtime_odbc(const char *database, const char *table, va_list ap)
Excute an SQL query and return ast_variable list.
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category structure.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
#define ast_debug(level,...)
Log a DEBUG message.
void ast_category_destroy(struct ast_category *cat)
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
General Asterisk PBX channel definitions.
int ast_str_make_space(struct ast_str **buf, size_t new_len)
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.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
static int update2_odbc(const char *database, const char *table, va_list ap)
Execute an UPDATE query.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
struct sla_ringing_trunk * last
#define AST_RWLIST_TRAVERSE
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
#define AST_STRING_FIELD(name)
Declare a string field.
static struct ast_threadstorage rowdata_buf
static struct ast_config_engine odbc_engine
Core PBX routines and definitions.
unsigned long var_val_size
#define ast_strdupa(s)
duplicate a string in memory from the stack
struct odbc_cache_tables * ast_odbc_find_table(const char *database, const char *tablename)
Find or create an entry describing the table specified.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
int ast_odbc_allow_empty_string_in_nontext(struct odbc_obj *obj)
Checks if the database natively supports implicit conversion from an empty string to a number (0)...
static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
#define warn_length(col, size)
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
struct sla_ringing_trunk * first
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
static int require_odbc(const char *database, const char *table, va_list ap)
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
#define ast_odbc_request_obj(a, b)
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...
static struct ast_threadstorage sql_buf
Structure used to handle boolean flags.
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
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.
#define WARN_TYPE_OR_LENGTH(n)
const ast_string_field encoding[256]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
int ast_rq_is_int(require_type type)
Check if require type is an integer type.
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
static void decode_chunk(char *chunk)
static int reload_module(void)
static struct ast_config * realtime_multi_odbc(const char *database, const char *table, va_list ap)
Excute an Select query and return ast_config list.
#define warn_type(col, type)
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
void ast_category_append(struct ast_config *config, struct ast_category *cat)
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)
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)
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
void ast_category_rename(struct ast_category *cat, const char *name)
#define ASTERISK_GPL_KEY
The text the key() function should return.
static int is_text(const struct odbc_cache_columns *column)
Asterisk module definitions.
char * strcasestr(const char *, const char *)
require_type
Types used in ast_realtime_require_field.
#define ENCODE_CHUNK(buffer, s)
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
struct odbc_cache_tables::_columns columns