Asterisk - The Open Source Telephony Project GIT-master-0bf3178
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
171 * \retval NULL on failure
172 */
173static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
174{
175 struct odbc_obj *obj;
176 SQLHSTMT stmt;
177 char coltitle[256];
179 struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
180 char *op;
181 const struct ast_variable *field = fields;
182 char *stringp;
183 char *chunk;
184 SQLSMALLINT collen;
185 int res;
186 int x;
187 struct ast_variable *var=NULL, *prev=NULL;
188 SQLULEN colsize;
189 SQLSMALLINT colcount=0;
190 SQLSMALLINT datatype;
191 SQLSMALLINT decimaldigits;
192 SQLSMALLINT nullable;
193 SQLLEN indicator;
194 struct custom_prepare_struct cps = { .fields = fields, };
195 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
196
197 if (!table || !field || !sql || !rowdata) {
198 return NULL;
199 }
200
201 obj = ast_odbc_request_obj2(database, connected_flag);
202 if (!obj) {
203 ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
204 return NULL;
205 }
206
207 op = !strchr(field->name, ' ') ? " =" : "";
208 ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
209 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
210 while ((field = field->next)) {
211 op = !strchr(field->name, ' ') ? " =" : "";
212 ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
213 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
214 }
215
216 cps.sql = ast_str_buffer(sql);
217
218 if (ast_string_field_init(&cps, 256)) {
220 return NULL;
221 }
224
225 if (!stmt) {
227 return NULL;
228 }
229
230 res = SQLNumResultCols(stmt, &colcount);
231 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
232 ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
233 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
235 return NULL;
236 }
237
238 res = SQLFetch(stmt);
239 if (res == SQL_NO_DATA) {
240 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
242 return NULL;
243 }
244 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
245 ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
246 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
248 return NULL;
249 }
250 for (x = 0; x < colcount; x++) {
251 colsize = 0;
252 collen = sizeof(coltitle);
253 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
254 &datatype, &colsize, &decimaldigits, &nullable);
255 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
256 ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
257 if (var)
260 return NULL;
261 }
262
263 ast_str_reset(rowdata);
264 indicator = 0;
265
266 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
267 ast_str_update(rowdata);
268 if (indicator == SQL_NULL_DATA) {
269 ast_str_reset(rowdata);
270 } else if (!ast_str_strlen(rowdata)) {
271 /* Because we encode the empty string for a NULL, we will encode
272 * actual empty strings as a string containing a single whitespace. */
273 ast_str_set(&rowdata, -1, "%s", " ");
274 } else if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
275 if (indicator != ast_str_strlen(rowdata)) {
276 /* If the available space was not enough to contain the row data enlarge and read in the rest */
277 ast_str_make_space(&rowdata, indicator + 1);
278 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
279 ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
280 ast_str_update(rowdata);
281 }
282 }
283
284 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
285 ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
286 if (var)
289 return NULL;
290 }
291
292 stringp = ast_str_buffer(rowdata);
293 if (!strncmp(coltitle, "@", 1)) {
294 /* The '@' prefix indicates it's a sorcery extended field.
295 * Because ast_load_realtime_fields eliminates empty entries and makes blank (single whitespace)
296 * entries empty and keeps them, the empty or NULL values are encoded
297 * as a string containing a single whitespace. */
298 if (prev) {
299 prev->next = ast_variable_new(coltitle, S_OR(stringp," "), "");
300 if (prev->next) {
301 prev = prev->next;
302 }
303 } else {
304 prev = var = ast_variable_new(coltitle, S_OR(stringp," "), "");
305 }
306 } else {
307 while (stringp) {
308 chunk = strsep(&stringp, ";");
309 if (!ast_strlen_zero(ast_strip(chunk))) {
310 if (strchr(chunk, '^')) {
311 decode_chunk(chunk);
312 }
313 if (prev) {
314 prev->next = ast_variable_new(coltitle, chunk, "");
315 if (prev->next) {
316 prev = prev->next;
317 }
318 } else {
319 prev = var = ast_variable_new(coltitle, chunk, "");
320 }
321 }
322 }
323 }
324 }
325
326 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
328 return var;
329}
330
331/*!
332 * \brief Execute an Select query and return ast_config list
333 * \param database
334 * \param table
335 * \param fields list containing one or more field/operator/value set.
336 *
337 * Select database and preform query on table, prepare the sql statement
338 * Sub-in the values to the prepared statement and execute it.
339 * Execute this prepared query against several ODBC connected databases.
340 * Return results as an ast_config variable.
341 *
342 * \return var on success
343 * \retval NULL on failure
344 */
345static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
346{
347 struct odbc_obj *obj;
348 SQLHSTMT stmt;
349 char coltitle[256];
351 struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
352 const char *initfield;
353 char *op;
354 const struct ast_variable *field = fields;
355 char *stringp;
356 char *chunk;
357 SQLSMALLINT collen;
358 int res;
359 int x;
360 struct ast_variable *var=NULL;
361 struct ast_config *cfg=NULL;
362 struct ast_category *cat=NULL;
363 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
364 SQLULEN colsize;
365 SQLSMALLINT colcount=0;
366 SQLSMALLINT datatype;
367 SQLSMALLINT decimaldigits;
368 SQLSMALLINT nullable;
369 SQLLEN indicator;
370 struct custom_prepare_struct cps = { .fields = fields, };
371
372 if (!table || !field || !sql || !rowdata) {
373 return NULL;
374 }
375
376 obj = ast_odbc_request_obj2(database, connected_flag);
377 if (!obj) {
378 return NULL;
379 }
380
381 initfield = ast_strdupa(field->name);
382 if ((op = strchr(initfield, ' '))) {
383 *op = '\0';
384 }
385
386 op = !strchr(field->name, ' ') ? " =" : "";
387 ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
388 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
389 while ((field = field->next)) {
390 op = !strchr(field->name, ' ') ? " =" : "";
391 ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
392 strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
393 }
394
396 ast_str_append(&sql, 0, " ORDER BY %s", initfield);
397 }
398
399 cps.sql = ast_str_buffer(sql);
400
401 if (ast_string_field_init(&cps, 256)) {
403 return NULL;
404 }
407
408 if (!stmt) {
410 return NULL;
411 }
412
413 res = SQLNumResultCols(stmt, &colcount);
414 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
415 ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
416 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
418 return NULL;
419 }
420
421 cfg = ast_config_new();
422 if (!cfg) {
423 ast_log(LOG_WARNING, "Out of memory!\n");
424 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
426 return NULL;
427 }
428
429 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
430 var = NULL;
431 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
432 ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
433 continue;
434 }
436 if (!cat) {
437 continue;
438 }
439 for (x=0;x<colcount;x++) {
440 colsize = 0;
441 collen = sizeof(coltitle);
442 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
443 &datatype, &colsize, &decimaldigits, &nullable);
444 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
445 ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
447 goto next_sql_fetch;
448 }
449
450 ast_str_reset(rowdata);
451 indicator = 0;
452
453 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
454 ast_str_update(rowdata);
455 if (indicator == SQL_NULL_DATA) {
456 continue;
457 }
458
459 if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
460 if (indicator != ast_str_strlen(rowdata)) {
461 /* If the available space was not enough to contain the row data enlarge and read in the rest */
462 ast_str_make_space(&rowdata, indicator + 1);
463 res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
464 ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
465 ast_str_update(rowdata);
466 }
467 }
468
469 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
470 ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
472 goto next_sql_fetch;
473 }
474 stringp = ast_str_buffer(rowdata);
475 if (!strncmp(coltitle, "@", 1)) {
476 /* The '@' prefix indicates it's a sorcery extended field.
477 * Because ast_load_realtime_fields eliminates empty entries and makes blank (single whitespace)
478 * entries empty and keeps them, the empty or NULL values are encoded
479 * as a string containing a single whitespace. */
480 var = ast_variable_new(coltitle, S_OR(stringp," "), "");
482 } else {
483 while (stringp) {
484 chunk = strsep(&stringp, ";");
485 if (!ast_strlen_zero(ast_strip(chunk))) {
486 if (strchr(chunk, '^')) {
487 decode_chunk(chunk);
488 }
489 if (!strcmp(initfield, coltitle)) {
490 ast_category_rename(cat, chunk);
491 }
492 var = ast_variable_new(coltitle, chunk, "");
494 }
495 }
496 }
497 }
498 ast_category_append(cfg, cat);
499next_sql_fetch:;
500 }
501
502 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
504 return cfg;
505}
506
507/*!
508 * \brief Execute an UPDATE query
509 * \param database
510 * \param table
511 * \param keyfield where clause field
512 * \param lookup value of field for where clause
513 * \param fields list containing one or more field/value set(s).
514 *
515 * Update a database table, prepare the sql statement using keyfield and lookup
516 * control the number of records to change. All values to be changed are stored in ap list.
517 * Sub-in the values to the prepared statement and execute it.
518 *
519 * \return number of rows affected
520 * \retval -1 on failure
521 */
522static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
523{
524 struct odbc_obj *obj;
525 SQLHSTMT stmt;
526 SQLLEN rowcount=0;
528 const struct ast_variable *field = fields;
529 int res, count = 0, paramcount = 0;
530 struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
531 struct odbc_cache_tables *tableptr;
532 struct odbc_cache_columns *column = NULL;
533 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
534
535 if (!table || !field || !keyfield || !sql) {
536 return -1;
537 }
538
539 tableptr = ast_odbc_find_table(database, table);
540 if (!(obj = ast_odbc_request_obj2(database, connected_flag))) {
541 ast_odbc_release_table(tableptr);
542 return -1;
543 }
544
545 if (tableptr && !ast_odbc_find_column(tableptr, keyfield)) {
546 ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield, table, database);
547 }
548
549 ast_str_set(&sql, 0, "UPDATE %s SET ", table);
550 while (field) {
551 if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) {
552 if (paramcount++) {
553 ast_str_append(&sql, 0, ", ");
554 }
555 /* NULL test for non-text columns */
556 if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column)) {
557 ast_str_append(&sql, 0, "%s=NULL", field->name);
558 cps.skip |= (1LL << count);
559 } else {
560 /* Value is not an empty string, or column is of text type, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
561 ast_str_append(&sql, 0, "%s=?", field->name);
562 }
563 } else { /* the column does not exist in the table */
564 cps.skip |= (1LL << count);
565 }
566 ++count;
567 field = field->next;
568 }
569 ast_str_append(&sql, 0, " WHERE %s=?", keyfield);
570 ast_odbc_release_table(tableptr);
571
572 cps.sql = ast_str_buffer(sql);
573
574 if (ast_string_field_init(&cps, 256)) {
576 return -1;
577 }
580
581 if (!stmt) {
583 return -1;
584 }
585
586 res = SQLRowCount(stmt, &rowcount);
587 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
589
590 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
591 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
592 return -1;
593 }
594
595 if (rowcount >= 0) {
596 return (int) rowcount;
597 }
598
599 return -1;
600}
601
603 const char *database;
604 const char *table;
608};
609
610static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
611{
612 int res, x = 1, first = 1;
613 struct update2_prepare_struct *ups = data;
614 const struct ast_variable *field;
616 SQLHSTMT stmt;
617
618 if (!sql) {
619 return NULL;
620 }
621
622 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
623 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
624 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
625 return NULL;
626 }
627
628 ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
629
630 for (field = ups->update_fields; field; field = field->next) {
631 if (ast_odbc_find_column(ups->tableptr, field->name)) {
632 ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", field->name);
633 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->name), 0, (void *)field->value, 0, NULL);
634 first = 0;
635 } else {
636 ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", field->name, ups->table, ups->database);
637 }
638 }
639
640 ast_str_append(&sql, 0, "WHERE");
641 first = 1;
642
643 for (field = ups->lookup_fields; field; field = field->next) {
644 if (!ast_odbc_find_column(ups->tableptr, field->name)) {
645 ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", field->name, ups->table, ups->database);
646 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
647 return NULL;
648 }
649 ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", field->name);
650 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->value), 0, (void *)field->value, 0, NULL);
651 first = 0;
652 }
653
654 res = ast_odbc_prepare(obj, stmt, ast_str_buffer(sql));
655 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
656 if (res == SQL_ERROR) {
657 ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Prepare");
658 }
659 ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", ast_str_buffer(sql));
660 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
661 return NULL;
662 }
663
664 return stmt;
665}
666
667/*!
668 * \brief Execute an UPDATE query
669 * \param database, table, lookup_fields
670 * \param update_fields list containing one or more field/value set(s).
671 *
672 * Update a database table, preparing the sql statement from a list of
673 * key/value pairs specified in ap. The lookup pairs are specified first
674 * and are separated from the update pairs by a sentinel value.
675 * Sub-in the values to the prepared statement and execute it.
676 *
677 * \return number of rows affected
678 * \retval -1 on failure
679*/
680static int update2_odbc(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
681{
682 struct odbc_obj *obj;
683 SQLHSTMT stmt;
684 struct update2_prepare_struct ups = {
686 .table = table,
687 .lookup_fields = lookup_fields,
688 .update_fields = update_fields,
689 };
690 struct ast_str *sql;
691 int res;
692 SQLLEN rowcount = 0;
693
694 ups.tableptr = ast_odbc_find_table(database, table);
695 if (!ups.tableptr) {
696 ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", table, database);
697 return -1;
698 }
699
700 if (!(obj = ast_odbc_request_obj(database, 0))) {
702 return -1;
703 }
704
705 if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
708 return -1;
709 }
710
711 /* We don't need the table anymore */
713
714 res = SQLRowCount(stmt, &rowcount);
715 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
717
718 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
719 /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
721 ast_assert(sql != NULL);
722 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
723 return -1;
724 }
725
726 if (rowcount >= 0) {
727 return (int) rowcount;
728 }
729
730 return -1;
731}
732
733/*!
734 * \brief Execute an INSERT query
735 * \param database
736 * \param table
737 * \param fields list containing one or more field/value set(s)
738 *
739 * Insert a new record into database table, prepare the sql statement.
740 * All values to be changed are stored in ap list.
741 * Sub-in the values to the prepared statement and execute it.
742 *
743 * \return number of rows affected
744 * \retval -1 on failure
745 */
746static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
747{
748 struct odbc_obj *obj;
749 SQLHSTMT stmt;
750 SQLLEN rowcount=0;
751 const struct ast_variable *field = fields;
752 struct ast_str *keys;
753 struct ast_str *vals;
755 int res;
756 struct custom_prepare_struct cps = { .fields = fields, };
757 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
758
760 vals = ast_str_create(SQL_BUF_SIZE / 4);
761 if (!table || !field || !keys || !vals || !sql) {
762 ast_free(vals);
763 ast_free(keys);
764 return -1;
765 }
766
767 obj = ast_odbc_request_obj2(database, connected_flag);
768 if (!obj) {
769 ast_free(vals);
770 ast_free(keys);
771 return -1;
772 }
773
774 ast_str_set(&keys, 0, "%s", field->name);
775 ast_str_set(&vals, 0, "?");
776 while ((field = field->next)) {
777 ast_str_append(&keys, 0, ", %s", field->name);
778 ast_str_append(&vals, 0, ", ?");
779 }
780 ast_str_set(&sql, 0, "INSERT INTO %s (%s) VALUES (%s)",
782
783 ast_free(vals);
784 ast_free(keys);
785 cps.sql = ast_str_buffer(sql);
786
787 if (ast_string_field_init(&cps, 256)) {
789 return -1;
790 }
793
794 if (!stmt) {
796 return -1;
797 }
798
799 res = SQLRowCount(stmt, &rowcount);
800 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
802
803 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
804 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
805 return -1;
806 }
807
808 if (rowcount >= 0)
809 return (int)rowcount;
810
811 return -1;
812}
813
814/*!
815 * \brief Execute an DELETE query
816 * \param database
817 * \param table
818 * \param keyfield where clause field
819 * \param lookup value of field for where clause
820 * \param fields list containing one or more field/value set(s)
821 *
822 * Delete a row from a database table, prepare the sql statement using keyfield and lookup
823 * control the number of records to change. Additional params to match rows are stored in ap list.
824 * Sub-in the values to the prepared statement and execute it.
825 *
826 * \return number of rows affected
827 * \retval -1 on failure
828 */
829static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
830{
831 struct odbc_obj *obj;
832 SQLHSTMT stmt;
833 SQLLEN rowcount=0;
835 const struct ast_variable *field;
836 int res;
837 struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
838 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
839
840 if (!table || !sql) {
841 return -1;
842 }
843
844 obj = ast_odbc_request_obj2(database, connected_flag);
845 if (!obj) {
846 return -1;
847 }
848
849 ast_str_set(&sql, 0, "DELETE FROM %s WHERE ", table);
850 for (field = fields; field; field = field->next) {
851 ast_str_append(&sql, 0, "%s=? AND ", field->name);
852 }
853 ast_str_append(&sql, 0, "%s=?", keyfield);
854
855 cps.sql = ast_str_buffer(sql);
856
857 if (ast_string_field_init(&cps, 256)) {
859 return -1;
860 }
863
864 if (!stmt) {
866 return -1;
867 }
868
869 res = SQLRowCount(stmt, &rowcount);
870 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
872
873 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
874 ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
875 return -1;
876 }
877
878 if (rowcount >= 0)
879 return (int)rowcount;
880
881 return -1;
882}
883
885 char *sql;
886 unsigned long cat_metric;
887 char category[128];
888 char var_name[128];
889 char *var_val;
890 unsigned long var_val_size;
891 SQLLEN err;
892};
893
894
895static SQLHSTMT length_determination_odbc_prepare(struct odbc_obj *obj, void *data)
896{
897 struct config_odbc_obj *q = data;
898 SQLHSTMT sth;
899 int res;
900
901 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
902 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
903 ast_verb(4, "Failure in AllocStatement %d\n", res);
904 return NULL;
905 }
906
907 res = ast_odbc_prepare(obj, sth, q->sql);
908 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
909 ast_verb(4, "Error in PREPARE %d\n", res);
910 SQLFreeHandle(SQL_HANDLE_STMT, sth);
911 return NULL;
912 }
913
914 SQLBindCol(sth, 1, SQL_C_ULONG, &q->var_val_size, sizeof(q->var_val_size), &q->err);
915
916 return sth;
917}
918
919static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
920{
921 struct config_odbc_obj *q = data;
922 SQLHSTMT sth;
923 int res;
924
925 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
926 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
927 ast_verb(4, "Failure in AllocStatement %d\n", res);
928 return NULL;
929 }
930
931 res = ast_odbc_prepare(obj, sth, q->sql);
932 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
933 ast_verb(4, "Error in PREPARE %d\n", res);
934 SQLFreeHandle(SQL_HANDLE_STMT, sth);
935 return NULL;
936 }
937
938 SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
939 SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
940 SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
941 SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, q->var_val_size, &q->err);
942
943 return sth;
944}
945
946static 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)
947{
948 struct ast_variable *new_v;
949 struct ast_category *cur_cat;
950 int res = 0;
951 struct odbc_obj *obj;
953 unsigned int last_cat_metric = 0;
954 SQLSMALLINT rowcount = 0;
955 SQLHSTMT stmt;
956 char last[128] = "";
957 struct config_odbc_obj q;
958 struct ast_flags loader_flags = { 0 };
959 struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
960
961 memset(&q, 0, sizeof(q));
962
963 if (!file || !strcmp (file, res_config_odbc_conf) || !sql) {
964 return NULL; /* cant configure myself with myself ! */
965 }
966
967 obj = ast_odbc_request_obj2(database, connected_flag);
968 if (!obj)
969 return NULL;
970
971 ast_str_set(&sql, 0, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'",
972 table, file);
973 q.sql = ast_str_buffer(sql);
974
976 if (!stmt) {
977 ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
979 return NULL;
980 }
981
982 res = SQLNumResultCols(stmt, &rowcount);
983
984 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
985 ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
986 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
988 return NULL;
989 }
990
991 if (!rowcount) {
992 ast_log(LOG_NOTICE, "found nothing\n");
994 return cfg;
995 }
996
997 /* There will be only one result for this, the maximum length of a variable value */
998 if (SQLFetch(stmt) == SQL_NO_DATA) {
999 ast_log(LOG_NOTICE, "Failed to determine maximum length of a configuration value\n");
1000 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1002 return NULL;
1003 }
1004
1005 /* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
1006 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1007
1008 ast_str_set(&sql, 0, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
1009 ast_str_append(&sql, 0, "WHERE filename='%s' AND commented=0 ", file);
1010 ast_str_append(&sql, 0, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
1011 q.sql = ast_str_buffer(sql);
1012
1013 q.var_val_size += 1;
1015 if (!q.var_val) {
1016 ast_log(LOG_WARNING, "Could not create buffer for reading in configuration values for '%s'\n", file);
1018 return NULL;
1019 }
1020
1022 if (!stmt) {
1023 ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
1025 ast_free(q.var_val);
1026 return NULL;
1027 }
1028
1029 res = SQLNumResultCols(stmt, &rowcount);
1030
1031 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1032 ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
1033 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1035 ast_free(q.var_val);
1036 return NULL;
1037 }
1038
1039 if (!rowcount) {
1040 ast_log(LOG_NOTICE, "found nothing\n");
1042 ast_free(q.var_val);
1043 return cfg;
1044 }
1045
1046 cur_cat = ast_config_get_current_category(cfg);
1047
1048 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
1049 if (!strcmp (q.var_name, "#include")) {
1050 if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
1051 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1053 ast_free(q.var_val);
1054 return NULL;
1055 }
1056 continue;
1057 }
1058 if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
1060 if (!cur_cat) {
1061 break;
1062 }
1063 strcpy(last, q.category);
1064 last_cat_metric = q.cat_metric;
1065 ast_category_append(cfg, cur_cat);
1066 }
1067
1068 new_v = ast_variable_new(q.var_name, q.var_val, "");
1069 ast_variable_append(cur_cat, new_v);
1070 }
1071
1072 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1074 ast_free(q.var_val);
1075 return cfg;
1076}
1077
1078#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)
1079#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)
1080
1081static int require_odbc(const char *database, const char *table, va_list ap)
1082{
1083 struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table);
1084 struct odbc_cache_columns *col;
1085 char *elm;
1086 int type, size;
1087
1088 if (!tableptr) {
1089 return -1;
1090 }
1091
1092 while ((elm = va_arg(ap, char *))) {
1093 type = va_arg(ap, require_type);
1094 size = va_arg(ap, int);
1095 /* Check if the field matches the criteria */
1096 AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) {
1097 if (strcmp(col->name, elm) == 0) {
1098 /* Type check, first. Some fields are more particular than others */
1099 switch (col->type) {
1100 case SQL_CHAR:
1101 case SQL_VARCHAR:
1102 case SQL_LONGVARCHAR:
1103#ifdef HAVE_ODBC_WCHAR
1104 case SQL_WCHAR:
1105 case SQL_WVARCHAR:
1106 case SQL_WLONGVARCHAR:
1107#endif
1108 case SQL_BINARY:
1109 case SQL_VARBINARY:
1110 case SQL_LONGVARBINARY:
1111 case SQL_GUID:
1112#define CHECK_SIZE(n) \
1113 if (col->size < n) { \
1114 warn_length(col, n); \
1115 } \
1116 break;
1117 switch (type) {
1118 case RQ_UINTEGER1: CHECK_SIZE(3) /* 255 */
1119 case RQ_INTEGER1: CHECK_SIZE(4) /* -128 */
1120 case RQ_UINTEGER2: CHECK_SIZE(5) /* 65535 */
1121 case RQ_INTEGER2: CHECK_SIZE(6) /* -32768 */
1122 case RQ_UINTEGER3: /* 16777215 */
1123 case RQ_INTEGER3: CHECK_SIZE(8) /* -8388608 */
1124 case RQ_DATE: /* 2008-06-09 */
1125 case RQ_UINTEGER4: CHECK_SIZE(10) /* 4200000000 */
1126 case RQ_INTEGER4: CHECK_SIZE(11) /* -2100000000 */
1127 case RQ_DATETIME: /* 2008-06-09 16:03:47 */
1128 case RQ_UINTEGER8: CHECK_SIZE(19) /* trust me */
1129 case RQ_INTEGER8: CHECK_SIZE(20) /* ditto */
1130 case RQ_FLOAT:
1131 case RQ_CHAR: CHECK_SIZE(size)
1132 }
1133#undef CHECK_SIZE
1134 break;
1135 case SQL_TYPE_DATE:
1136 if (type != RQ_DATE) {
1137 warn_type(col, type);
1138 }
1139 break;
1140 case SQL_TYPE_TIMESTAMP:
1141 case SQL_TIMESTAMP:
1142 case SQL_DATETIME:
1143 if (type != RQ_DATE && type != RQ_DATETIME) {
1144 warn_type(col, type);
1145 }
1146 break;
1147 case SQL_BIT:
1148 warn_length(col, size);
1149 break;
1150#define WARN_TYPE_OR_LENGTH(n) \
1151 if (!ast_rq_is_int(type)) { \
1152 warn_type(col, type); \
1153 } else { \
1154 warn_length(col, n); \
1155 }
1156 case SQL_TINYINT:
1157 if (type != RQ_UINTEGER1) {
1159 }
1160 break;
1161 case SQL_C_STINYINT:
1162 if (type != RQ_INTEGER1) {
1164 }
1165 break;
1166 case SQL_C_USHORT:
1167 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) {
1169 }
1170 break;
1171 case SQL_SMALLINT:
1172 case SQL_C_SSHORT:
1173 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) {
1175 }
1176 break;
1177 case SQL_C_ULONG:
1178 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1179 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1180 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1181 type != RQ_INTEGER4) {
1183 }
1184 break;
1185 case SQL_INTEGER:
1186 case SQL_C_SLONG:
1187 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1188 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1189 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1190 type != RQ_INTEGER4) {
1192 }
1193 break;
1194 case SQL_C_UBIGINT:
1195 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1196 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1197 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1198 type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
1199 type != RQ_INTEGER8) {
1201 }
1202 break;
1203 case SQL_BIGINT:
1204 case SQL_C_SBIGINT:
1205 if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1206 type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1207 type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1208 type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
1209 type != RQ_INTEGER8) {
1211 }
1212 break;
1213#undef WARN_TYPE_OR_LENGTH
1214 case SQL_NUMERIC:
1215 case SQL_DECIMAL:
1216 case SQL_FLOAT:
1217 case SQL_REAL:
1218 case SQL_DOUBLE:
1219 if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
1220 warn_type(col, type);
1221 }
1222 break;
1223 default:
1224 ast_log(LOG_WARNING, "Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->type, elm);
1225 }
1226 break;
1227 }
1228 }
1229 if (!col) {
1230 ast_log(LOG_WARNING, "Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm);
1231 }
1232 }
1233 AST_RWLIST_UNLOCK(&tableptr->columns);
1234 return 0;
1235}
1236#undef warn_length
1237#undef warn_type
1238
1239static int unload_odbc(const char *a, const char *b)
1240{
1241 return ast_odbc_clear_cache(a, b);
1242}
1243
1245 .name = "odbc",
1246 .load_func = config_odbc,
1247 .realtime_func = realtime_odbc,
1248 .realtime_multi_func = realtime_multi_odbc,
1249 .store_func = store_odbc,
1250 .destroy_func = destroy_odbc,
1251 .update_func = update_odbc,
1252 .update2_func = update2_odbc,
1253 .require_func = require_odbc,
1254 .unload_func = unload_odbc,
1255};
1256
1257static void load_config(const char *filename)
1258{
1259 struct ast_config *config;
1260 struct ast_flags config_flags = { 0 };
1261 const char *s;
1262
1263 config = ast_config_load(filename, config_flags);
1266 ast_log(LOG_WARNING, "Unable to load config '%s'. Using defaults.\n", filename);
1267 }
1269 return;
1270 }
1271
1272 /* Result set ordering is enabled by default */
1273 s = ast_variable_retrieve(config, "general", "order_multi_row_results_by_initial_column");
1275
1277}
1278
1279static int load_module(void)
1280{
1281 /* We'll either successfully load the configuration or fail with reasonable
1282 * defaults */
1285 return 0;
1286}
1287
1288static int reload_module(void)
1289{
1291 return 0;
1292}
1293
1294static int unload_module(void)
1295{
1297 return 0;
1298}
1299
1300AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime ODBC configuration",
1301 .support_level = AST_MODULE_SUPPORT_CORE,
1302 .load = load_module,
1303 .unload = unload_module,
1305 .load_pri = AST_MODPRI_REALTIME_DRIVER,
1306 .requires = "extconfig,res_odbc",
struct sla_ringing_trunk * first
Definition: app_sla.c:332
struct sla_ringing_trunk * last
Definition: app_sla.c:332
#define var
Definition: ast_expr2f.c:605
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....
char * strsep(char **str, const char *delims)
char * strcasestr(const char *, const char *)
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:1460
#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:3188
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:784
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:3294
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#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:3172
#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:454
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:804
struct odbc_cache_tables * ast_odbc_find_table(const char *database, const char *tablename)
Find or create an entry describing the table specified.
Definition: res_odbc.c:232
int ast_odbc_clear_cache(const char *database, const char *tablename)
Remove a cache entry from memory This function may be called to clear entries created and cached by t...
Definition: res_odbc.c:343
struct odbc_cache_columns * ast_odbc_find_column(struct odbc_cache_tables *table, const char *colname)
Find a column entry within a cached table structure.
Definition: res_odbc.c:332
#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:515
int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
Checks if the database natively supports backslash as an escape character.
Definition: res_odbc.c:833
#define ast_odbc_request_obj2(name, check)
Retrieves a connected ODBC object.
Definition: res_odbc.h:106
SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
Prepares, executes, and returns the resulting statement handle.
Definition: res_odbc.c:398
#define 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:2199
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:199
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:739