Asterisk - The Open Source Telephony Project GIT-master-0a46be9
res_config_odbc.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2010, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct@yahoo.com>
9 *
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
15 *
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
19 */
20
21/*! \file
22 *
23 * \brief odbc+odbc plugin for portable configuration engine
24 *
25 * \author Mark Spencer <markster@digium.com>
26 * \author Anthony Minessale II <anthmct@yahoo.com>
27 *
28 * \arg http://www.unixodbc.org
29 */
30
31/*** MODULEINFO
32 <depend>res_odbc</depend>
33 <depend>generic_odbc</depend>
34 <support_level>core</support_level>
35 ***/
36
37#include "asterisk.h"
38
39#include "asterisk/file.h"
40#include "asterisk/channel.h"
41#include "asterisk/pbx.h"
42#include "asterisk/config.h"
43#include "asterisk/module.h"
44#include "asterisk/lock.h"
45#include "asterisk/res_odbc.h"
46#include "asterisk/utils.h"
48
49/*! Initial SQL query buffer size to allocate. */
50#define SQL_BUF_SIZE 1024
51
52static const char *res_config_odbc_conf = "res_config_odbc.conf";
54
57
59 const char *sql;
60 const char *extra;
63 );
64 const struct ast_variable *fields;
65 unsigned long long skip;
66};
67
68#define ENCODE_CHUNK(buffer, s) \
69 do { \
70 char *eptr = buffer; \
71 const char *vptr = s; \
72 for (; *vptr && eptr < buffer + sizeof(buffer); vptr++) { \
73 if (strchr("^;", *vptr)) { \
74 /* We use ^XX, instead of %XX because '%' is a special character in SQL */ \
75 snprintf(eptr, buffer + sizeof(buffer) - eptr, "^%02hhX", *vptr); \
76 eptr += 3; \
77 } else { \
78 *eptr++ = *vptr; \
79 } \
80 } \
81 if (eptr < buffer + sizeof(buffer)) { \
82 *eptr = '\0'; \
83 } else { \
84 buffer[sizeof(buffer) - 1] = '\0'; \
85 } \
86 } while(0)
87
88static void decode_chunk(char *chunk)
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}
97
98static inline int is_text(const struct odbc_cache_columns *column)
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}
103
104static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
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}
159
160/*!
161 * \brief Execute an SQL query and return ast_variable list
162 * \param database
163 * \param table
164 * \param fields list containing one or more field/operator/value set.
165 *
166 * Select database and preform query on table, prepare the sql statement
167 * Sub-in the values to the prepared statement and execute it. Return results
168 * as a ast_variable list.
169 *
170 * \return var on success (data found)
171 * \return CONFIG_RT_NOT_FOUND on success but no record
172 * \retval NULL on failure
173 */
174static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
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}
335
336/*!
337 * \brief Execute an Select query and return ast_config list
338 * \param database
339 * \param table
340 * \param fields list containing one or more field/operator/value set.
341 *
342 * Select database and preform query on table, prepare the sql statement
343 * Sub-in the values to the prepared statement and execute it.
344 * Execute this prepared query against several ODBC connected databases.
345 * Return results as an ast_config variable.
346 *
347 * \return var on success
348 * \retval NULL on failure
349 */
350static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
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}
511
512/*!
513 * \brief Execute an UPDATE query
514 * \param database
515 * \param table
516 * \param keyfield where clause field
517 * \param lookup value of field for where clause
518 * \param fields list containing one or more field/value set(s).
519 *
520 * Update a database table, prepare the sql statement using keyfield and lookup
521 * control the number of records to change. All values to be changed are stored in ap list.
522 * Sub-in the values to the prepared statement and execute it.
523 *
524 * \return number of rows affected
525 * \retval -1 on failure
526 */
527static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
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}
606
608 const char *database;
609 const char *table;
613};
614
615static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
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}
671
672/*!
673 * \brief Execute an UPDATE query
674 * \param database, table, lookup_fields
675 * \param update_fields list containing one or more field/value set(s).
676 *
677 * Update a database table, preparing the sql statement from a list of
678 * key/value pairs specified in ap. The lookup pairs are specified first
679 * and are separated from the update pairs by a sentinel value.
680 * Sub-in the values to the prepared statement and execute it.
681 *
682 * \return number of rows affected
683 * \retval -1 on failure
684*/
685static int update2_odbc(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
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}
737
738/*!
739 * \brief Execute an INSERT query
740 * \param database
741 * \param table
742 * \param fields list containing one or more field/value set(s)
743 *
744 * Insert a new record into database table, prepare the sql statement.
745 * All values to be changed are stored in ap list.
746 * Sub-in the values to the prepared statement and execute it.
747 *
748 * \return number of rows affected
749 * \retval -1 on failure
750 */
751static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
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}
818
819/*!
820 * \brief Execute an DELETE query
821 * \param database
822 * \param table
823 * \param keyfield where clause field
824 * \param lookup value of field for where clause
825 * \param fields list containing one or more field/value set(s)
826 *
827 * Delete a row from a database table, prepare the sql statement using keyfield and lookup
828 * control the number of records to change. Additional params to match rows are stored in ap list.
829 * Sub-in the values to the prepared statement and execute it.
830 *
831 * \return number of rows affected
832 * \retval -1 on failure
833 */
834static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
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}
888
890 char *sql;
891 unsigned long cat_metric;
892 char category[128];
893 char var_name[128];
894 char *var_val;
895 unsigned long var_val_size;
896 SQLLEN err;
897};
898
899
900static SQLHSTMT length_determination_odbc_prepare(struct odbc_obj *obj, void *data)
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}
923
924static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
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}
950
951static 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)
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;
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) {
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}
1082
1083#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)
1084#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)
1085
1086static int require_odbc(const char *database, const char *table, va_list ap)
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}
1241#undef warn_length
1242#undef warn_type
1243
1244static int unload_odbc(const char *a, const char *b)
1245{
1246 return ast_odbc_clear_cache(a, b);
1247}
1248
1250 .name = "odbc",
1251 .load_func = config_odbc,
1252 .realtime_func = realtime_odbc,
1253 .realtime_multi_func = realtime_multi_odbc,
1254 .store_func = store_odbc,
1255 .destroy_func = destroy_odbc,
1256 .update_func = update_odbc,
1257 .update2_func = update2_odbc,
1258 .require_func = require_odbc,
1259 .unload_func = unload_odbc,
1260};
1261
1262static void load_config(const char *filename)
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}
1283
1284static int load_module(void)
1285{
1286 /* We'll either successfully load the configuration or fail with reasonable
1287 * defaults */
1290 return 0;
1291}
1292
1293static int reload_module(void)
1294{
1296 return 0;
1297}
1298
1299static int unload_module(void)
1300{
1302 return 0;
1303}
1304
1305AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime ODBC configuration",
1306 .support_level = AST_MODULE_SUPPORT_CORE,
1307 .load = load_module,
1308 .unload = unload_module,
1310 .load_pri = AST_MODPRI_REALTIME_DRIVER,
1311 .requires = "extconfig,res_odbc",
struct sla_ringing_trunk * first
Definition: app_sla.c:338
struct sla_ringing_trunk * last
Definition: app_sla.c:338
#define var
Definition: ast_expr2f.c:605
char * strsep(char **str, const char *delims)
char * strcasestr(const char *, const char *)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#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
static char * encoding
Definition: cdr_pgsql.c:70
static const char type[]
Definition: chan_ooh323.c:109
static const char config[]
Definition: chan_ooh323.c:111
General Asterisk PBX channel definitions.
Generic File Format Support. Should be included by clients of the file handling routines....
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
void ast_category_rename(struct ast_category *cat, const char *name)
Definition: main/config.c:1563
#define CONFIG_STATUS_FILEMISSING
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3274
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_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.
Definition: main/config.c:3393
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
Definition: extconf.c:2781
#define CONFIG_STATUS_FILEINVALID
void ast_category_destroy(struct ast_category *cat)
Definition: extconf.c:2845
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
int ast_rq_is_int(require_type type)
Check if require type is an integer type.
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:869
require_type
Types used in ast_realtime_require_field.
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
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define CONFIG_RT_NOT_FOUND
#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.
Definition: main/config.c:3377
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
#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
Asterisk locking-related definitions:
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_REALTIME_DRIVER
Definition: module.h:337
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Core PBX routines and definitions.
static int reload(void)
#define SQL_BUF_SIZE
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_config_engine odbc_engine
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.
#define warn_length(col, size)
#define CHECK_SIZE(n)
static SQLHSTMT length_determination_odbc_prepare(struct odbc_obj *obj, void *data)
static void decode_chunk(char *chunk)
static int require_odbc(const char *database, const char *table, va_list ap)
#define ENCODE_CHUNK(buffer, s)
static int order_multi_row_results_by_initial_column
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 void load_config(const char *filename)
static int load_module(void)
static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
static const char * res_config_odbc_conf
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_threadstorage sql_buf
static struct keys keys
ODBC resource manager.
@ RES_ODBC_CONNECTED
Definition: res_odbc.h:42
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
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
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
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
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
#define ast_odbc_release_table(ptr)
Release a table returned from ast_odbc_find_table.
Definition: res_odbc.h:219
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
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 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 ast_odbc_request_obj(name, check)
Get a ODBC connection object.
Definition: res_odbc.h:120
#define NULL
Definition: resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#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
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
#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
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:2235
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
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_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
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
#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
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
Configuration engine structure, used to define realtime drivers.
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.
struct ast_variable * next
unsigned long var_val_size
unsigned long cat_metric
const ast_string_field encoding[256]
unsigned long long skip
const struct ast_variable * fields
These structures are used for adaptive capabilities.
Definition: res_odbc.h:59
SQLSMALLINT type
Definition: res_odbc.h:61
SQLINTEGER size
Definition: res_odbc.h:62
SQLSMALLINT nullable
Definition: res_odbc.h:65
struct odbc_cache_tables::_columns columns
ODBC container.
Definition: res_odbc.h:46
SQLHDBC con
Definition: res_odbc.h:47
const struct ast_variable * lookup_fields
const struct ast_variable * update_fields
struct odbc_cache_tables * tableptr
static struct test_val b
static struct test_val a
static int indicator
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:86
Utility functions.
#define ast_assert(a)
Definition: utils.h:776