50 #define SQL_BUF_SIZE 1024
65 #define ENCODE_CHUNK(buffer, s) \
67 char *eptr = buffer; \
68 const char *vptr = s; \
69 for (; *vptr && eptr < buffer + sizeof(buffer); vptr++) { \
70 if (strchr("^;", *vptr)) { \
72 snprintf(eptr, buffer + sizeof(buffer) - eptr, "^%02hhX", *vptr); \
78 if (eptr < buffer + sizeof(buffer)) { \
81 buffer[sizeof(buffer) - 1] = '\0'; \
87 for (; *chunk; chunk++) {
88 if (*chunk ==
'^' && strchr(
"0123456789ABCDEF", chunk[1]) && strchr(
"0123456789ABCDEF", chunk[2])) {
89 sscanf(chunk + 1,
"%02hhX", (
unsigned char *)chunk);
90 memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
97 return column->
type == SQL_CHAR || column->
type == SQL_VARCHAR || column->
type == SQL_LONGVARCHAR
98 || column->
type == SQL_WCHAR || column->
type == SQL_WVARCHAR || column->
type == SQL_WLONGVARCHAR;
103 int res, x = 1, count = 0;
106 char encodebuf[1024];
109 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
110 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
118 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
119 if (res == SQL_ERROR) {
123 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
127 for (field = cps->
fields; field; field = field->
next) {
128 const char *newval = field->
value;
130 if ((1LL << count++) & cps->
skip) {
131 ast_debug(1,
"Skipping field '%s'='%s' (%llo/%llo)\n", field->
name, newval, 1ULL << (count - 1), cps->
skip);
134 ast_debug(1,
"Parameter %d ('%s') = '%s'\n", x, field->
name, newval);
135 if (strchr(newval,
';') || strchr(newval,
'^')) {
140 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (
void *)newval, 0,
NULL);
144 const char *newval = cps->
extra;
145 ast_debug(1,
"Parameter %d = '%s'\n", x, newval);
146 if (strchr(newval,
';') || strchr(newval,
'^')) {
151 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (
void *)newval, 0,
NULL);
186 SQLSMALLINT colcount=0;
187 SQLSMALLINT datatype;
188 SQLSMALLINT decimaldigits;
189 SQLSMALLINT nullable;
194 if (!
table || !field || !sql || !rowdata) {
200 ast_log(
LOG_ERROR,
"No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
204 op = !strchr(field->
name,
' ') ?
" =" :
"";
207 while ((field = field->
next)) {
208 op = !strchr(field->
name,
' ') ?
" =" :
"";
227 res = SQLNumResultCols(stmt, &colcount);
228 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
230 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
235 res = SQLFetch(stmt);
236 if (res == SQL_NO_DATA) {
237 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
241 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
243 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
247 for (x = 0; x < colcount; x++) {
249 collen =
sizeof(coltitle);
250 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *)coltitle,
sizeof(coltitle), &collen,
251 &datatype, &colsize, &decimaldigits, &nullable);
252 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
271 }
else if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
281 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
290 if (!strncmp(coltitle,
"@", 1)) {
305 chunk =
strsep(&stringp,
";");
307 if (strchr(chunk,
'^')) {
323 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
349 const char *initfield;
362 SQLSMALLINT colcount=0;
363 SQLSMALLINT datatype;
364 SQLSMALLINT decimaldigits;
365 SQLSMALLINT nullable;
369 if (!
table || !field || !
sql || !rowdata) {
379 if ((op = strchr(initfield,
' '))) {
383 op = !strchr(field->
name,
' ') ?
" =" :
"";
386 while ((field = field->
next)) {
387 op = !strchr(field->
name,
' ') ?
" =" :
"";
407 res = SQLNumResultCols(stmt, &colcount);
408 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
410 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
418 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
423 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
425 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
433 for (x=0;x<colcount;x++) {
435 collen =
sizeof(coltitle);
436 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *)coltitle,
sizeof(coltitle), &collen,
437 &datatype, &colsize, &decimaldigits, &nullable);
438 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
453 if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
463 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
469 if (!strncmp(coltitle,
"@", 1)) {
478 chunk =
strsep(&stringp,
";");
480 if (strchr(chunk,
'^')) {
483 if (!strcmp(initfield, coltitle)) {
496 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
523 int res, count = 0, paramcount = 0;
529 if (!
table || !field || !keyfield || !sql) {
540 ast_log(
LOG_WARNING,
"Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield,
table, database);
552 cps.
skip |= (1LL << count);
558 cps.
skip |= (1LL << count);
580 res = SQLRowCount(stmt, &rowcount);
581 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
584 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
590 return (
int) rowcount;
606 int res, x = 1,
first = 1;
616 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
617 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
627 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->
name), 0, (
void *)field->
value, 0,
NULL);
640 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
644 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->
value), 0, (
void *)field->
value, 0,
NULL);
649 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
650 if (res == SQL_ERROR) {
654 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
690 ast_log(
LOG_ERROR,
"Could not retrieve metadata for table '%s@%s'. Update will fail!\n",
table, database);
708 res = SQLRowCount(stmt, &rowcount);
709 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
712 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
721 return (
int) rowcount;
755 if (!
table || !field || !
keys || !vals || !sql) {
770 while ((field = field->
next)) {
774 ast_str_set(&sql, 0,
"INSERT INTO %s (%s) VALUES (%s)",
793 res = SQLRowCount(stmt, &rowcount);
794 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
797 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
803 return (
int)rowcount;
834 if (!
table || !sql) {
844 for (field = fields; field; field = field->
next) {
863 res = SQLRowCount(stmt, &rowcount);
864 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
867 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
873 return (
int)rowcount;
895 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &sth);
896 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
897 ast_verb(4,
"Failure in AllocStatement %d\n", res);
902 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
903 ast_verb(4,
"Error in PREPARE %d\n", res);
904 SQLFreeHandle(SQL_HANDLE_STMT, sth);
919 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &sth);
920 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
921 ast_verb(4,
"Failure in AllocStatement %d\n", res);
926 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
927 ast_verb(4,
"Error in PREPARE %d\n", res);
928 SQLFreeHandle(SQL_HANDLE_STMT, sth);
947 unsigned int last_cat_metric = 0;
948 SQLSMALLINT rowcount = 0;
955 memset(&q, 0,
sizeof(q));
957 if (!
file || !strcmp (
file,
"res_config_odbc.conf") || !sql) {
965 ast_str_set(&sql, 0,
"SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'",
976 res = SQLNumResultCols(stmt, &rowcount);
978 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
980 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
992 if (SQLFetch(stmt) == SQL_NO_DATA) {
993 ast_log(
LOG_NOTICE,
"Failed to determine maximum length of a configuration value\n");
994 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1000 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1002 ast_str_set(&sql, 0,
"SELECT cat_metric, category, var_name, var_val FROM %s ",
table);
1004 ast_str_append(&sql, 0,
"ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
1023 res = SQLNumResultCols(stmt, &rowcount);
1025 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1027 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1042 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
1043 if (!strcmp (q.
var_name,
"#include")) {
1045 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1066 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1072 #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)
1073 #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)
1086 while ((elm = va_arg(ap,
char *))) {
1088 size = va_arg(ap,
int);
1091 if (strcmp(col->
name, elm) == 0) {
1093 switch (col->
type) {
1096 case SQL_LONGVARCHAR:
1097 #ifdef HAVE_ODBC_WCHAR
1100 case SQL_WLONGVARCHAR:
1104 case SQL_LONGVARBINARY:
1106 #define CHECK_SIZE(n) \
1107 if (col->size < n) { \
1108 warn_length(col, n); \
1134 case SQL_TYPE_TIMESTAMP:
1143 #define WARN_TYPE_OR_LENGTH(n) \
1144 if (!ast_rq_is_int(type)) { \
1145 warn_type(col, type); \
1147 warn_length(col, n); \
1154 case SQL_C_STINYINT:
1206 #undef WARN_TYPE_OR_LENGTH
1223 ast_log(
LOG_WARNING,
"Realtime table %s@%s requires column '%s', but that column does not exist!\n",
table, database, elm);
1275 .requires =
"extconfig,res_odbc",
struct sla_ringing_trunk * first
struct sla_ringing_trunk * last
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_malloc(len)
A wrapper for malloc()
General Asterisk PBX channel definitions.
Generic File Format Support. Should be included by clients of the file handling routines....
char * strcasestr(const char *, const char *)
char * strsep(char **str, const char *delims)
Configuration File Parser.
void ast_category_rename(struct ast_category *cat, const char *name)
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
#define ast_category_new_anonymous()
Create a nameless category that is not backed by a file.
#define ast_variable_new(name, value, filename)
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
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)
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
void ast_category_destroy(struct ast_category *cat)
int ast_rq_is_int(require_type type)
Check if require type is an integer type.
require_type
Types used in ast_realtime_require_field.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
#define ast_category_new_dynamic(name)
Create a category that is not backed by a file.
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_RWLIST_TRAVERSE
Asterisk locking-related definitions:
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODPRI_REALTIME_DRIVER
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
Core PBX routines and definitions.
static struct ast_config_engine odbc_engine
#define warn_length(col, size)
static SQLHSTMT length_determination_odbc_prepare(struct odbc_obj *obj, void *data)
static void decode_chunk(char *chunk)
static struct ast_variable * realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an SQL query and return ast_variable list.
static int require_odbc(const char *database, const char *table, va_list ap)
#define ENCODE_CHUNK(buffer, s)
static struct ast_threadstorage rowdata_buf
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.
static int is_text(const struct odbc_cache_columns *column)
static int reload_module(void)
static struct ast_config * realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an Select query and return ast_config list.
static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
static int update2_odbc(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
Execute an UPDATE query.
static int unload_odbc(const char *a, const char *b)
#define warn_type(col, type)
static int load_module(void)
static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
static int unload_module(void)
static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an INSERT query.
static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Execute an DELETE query.
#define WARN_TYPE_OR_LENGTH(n)
static struct ast_config * config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
static struct ast_threadstorage sql_buf
int ast_odbc_prepare(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Prepares a SQL query on a statement.
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
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...
#define ast_odbc_release_table(ptr)
Release a table returned from ast_odbc_find_table.
int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
Checks if the database natively supports backslash as an escape character.
struct odbc_cache_tables * ast_odbc_find_table(const char *database, const char *tablename)
Find or create an entry describing the table specified.
#define ast_odbc_request_obj2(name, check)
Retrieves a connected ODBC object.
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.
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.
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
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_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
#define ast_str_make_space(buf, new_len)
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Configuration engine structure, used to define realtime drivers.
Structure used to handle boolean flags.
Support for dynamic strings.
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
unsigned long var_val_size
const ast_string_field encoding[256]
const struct ast_variable * fields
These structures are used for adaptive capabilities.
struct odbc_cache_tables::_columns columns
const struct ast_variable * lookup_fields
const struct ast_variable * update_fields
struct odbc_cache_tables * tableptr
#define AST_THREADSTORAGE(name)
Define a thread storage variable.