Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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"
47 #include "asterisk/stringfields.h"
48 
49 /*! Initial SQL query buffer size to allocate. */
50 #define SQL_BUF_SIZE 1024
51 
54 
56  const char *sql;
57  const char *extra;
60  );
61  const struct ast_variable *fields;
62  unsigned long long skip;
63 };
64 
65 #define ENCODE_CHUNK(buffer, s) \
66  do { \
67  char *eptr = buffer; \
68  const char *vptr = s; \
69  for (; *vptr && eptr < buffer + sizeof(buffer); vptr++) { \
70  if (strchr("^;", *vptr)) { \
71  /* We use ^XX, instead of %XX because '%' is a special character in SQL */ \
72  snprintf(eptr, buffer + sizeof(buffer) - eptr, "^%02hhX", *vptr); \
73  eptr += 3; \
74  } else { \
75  *eptr++ = *vptr; \
76  } \
77  } \
78  if (eptr < buffer + sizeof(buffer)) { \
79  *eptr = '\0'; \
80  } else { \
81  buffer[sizeof(buffer) - 1] = '\0'; \
82  } \
83  } while(0)
84 
85 static void decode_chunk(char *chunk)
86 {
87  for (; *chunk; chunk++) {
88  if (*chunk == '^' && strchr("0123456789ABCDEF", chunk[1]) && strchr("0123456789ABCDEF", chunk[2])) {
89  sscanf(chunk + 1, "%02hhX", (unsigned char *)chunk);
90  memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
91  }
92  }
93 }
94 
95 static inline int is_text(const struct odbc_cache_columns *column)
96 {
97  return column->type == SQL_CHAR || column->type == SQL_VARCHAR || column->type == SQL_LONGVARCHAR
98  || column->type == SQL_WCHAR || column->type == SQL_WVARCHAR || column->type == SQL_WLONGVARCHAR;
99 }
100 
101 static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
102 {
103  int res, x = 1, count = 0;
104  struct custom_prepare_struct *cps = data;
105  const struct ast_variable *field;
106  char encodebuf[1024];
107  SQLHSTMT stmt;
108 
109  res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
110  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
111  ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
112  return NULL;
113  }
114 
115  ast_debug(1, "Skip: %llu; SQL: %s\n", cps->skip, cps->sql);
116 
117  res = ast_odbc_prepare(obj, stmt, cps->sql);
118  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
119  if (res == SQL_ERROR) {
120  ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Prepare");
121  }
122  ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", cps->sql);
123  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
124  return NULL;
125  }
126 
127  for (field = cps->fields; field; field = field->next) {
128  const char *newval = field->value;
129 
130  if ((1LL << count++) & cps->skip) {
131  ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", field->name, newval, 1ULL << (count - 1), cps->skip);
132  continue;
133  }
134  ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, field->name, newval);
135  if (strchr(newval, ';') || strchr(newval, '^')) {
136  ENCODE_CHUNK(encodebuf, newval);
137  ast_string_field_set(cps, encoding[x], encodebuf);
138  newval = cps->encoding[x];
139  }
140  SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
141  }
142 
143  if (!ast_strlen_zero(cps->extra)) {
144  const char *newval = cps->extra;
145  ast_debug(1, "Parameter %d = '%s'\n", x, newval);
146  if (strchr(newval, ';') || strchr(newval, '^')) {
147  ENCODE_CHUNK(encodebuf, newval);
148  ast_string_field_set(cps, encoding[x], encodebuf);
149  newval = cps->encoding[x];
150  }
151  SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
152  }
153 
154  return stmt;
155 }
156 
157 /*!
158  * \brief Execute an SQL query and return ast_variable list
159  * \param database
160  * \param table
161  * \param fields list containing one or more field/operator/value set.
162  *
163  * Select database and preform query on table, prepare the sql statement
164  * Sub-in the values to the prepared statement and execute it. Return results
165  * as a ast_variable list.
166  *
167  * \return var on success
168  * \retval NULL on failure
169  */
170 static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
171 {
172  struct odbc_obj *obj;
173  SQLHSTMT stmt;
174  char coltitle[256];
176  struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
177  char *op;
178  const struct ast_variable *field = fields;
179  char *stringp;
180  char *chunk;
181  SQLSMALLINT collen;
182  int res;
183  int x;
184  struct ast_variable *var=NULL, *prev=NULL;
185  SQLULEN colsize;
186  SQLSMALLINT colcount=0;
187  SQLSMALLINT datatype;
188  SQLSMALLINT decimaldigits;
189  SQLSMALLINT nullable;
190  SQLLEN indicator;
191  struct custom_prepare_struct cps = { .fields = fields, };
192  struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
193 
194  if (!table || !field || !sql || !rowdata) {
195  return NULL;
196  }
197 
198  obj = ast_odbc_request_obj2(database, connected_flag);
199  if (!obj) {
200  ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
201  return NULL;
202  }
203 
204  op = !strchr(field->name, ' ') ? " =" : "";
205  ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
206  strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
207  while ((field = field->next)) {
208  op = !strchr(field->name, ' ') ? " =" : "";
209  ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
210  strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
211  }
212 
213  cps.sql = ast_str_buffer(sql);
214 
215  if (ast_string_field_init(&cps, 256)) {
217  return NULL;
218  }
219  stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
221 
222  if (!stmt) {
224  return NULL;
225  }
226 
227  res = SQLNumResultCols(stmt, &colcount);
228  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
229  ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
230  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
232  return NULL;
233  }
234 
235  res = SQLFetch(stmt);
236  if (res == SQL_NO_DATA) {
237  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
239  return NULL;
240  }
241  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
242  ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
243  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
245  return NULL;
246  }
247  for (x = 0; x < colcount; x++) {
248  colsize = 0;
249  collen = sizeof(coltitle);
250  res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
251  &datatype, &colsize, &decimaldigits, &nullable);
252  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
253  ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
254  if (var)
257  return NULL;
258  }
259 
260  ast_str_reset(rowdata);
261  indicator = 0;
262 
263  res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
264  ast_str_update(rowdata);
265  if (indicator == SQL_NULL_DATA) {
266  ast_str_reset(rowdata);
267  } else if (!ast_str_strlen(rowdata)) {
268  /* Because we encode the empty string for a NULL, we will encode
269  * actual empty strings as a string containing a single whitespace. */
270  ast_str_set(&rowdata, -1, "%s", " ");
271  } else if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
272  if (indicator != ast_str_strlen(rowdata)) {
273  /* If the available space was not enough to contain the row data enlarge and read in the rest */
274  ast_str_make_space(&rowdata, indicator + 1);
275  res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
276  ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
277  ast_str_update(rowdata);
278  }
279  }
280 
281  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
282  ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
283  if (var)
286  return NULL;
287  }
288 
289  stringp = ast_str_buffer(rowdata);
290  if (!strncmp(coltitle, "@", 1)) {
291  /* The '@' prefix indicates it's a sorcery extended field.
292  * Because ast_load_realtime_fields eliminates empty entries and makes blank (single whitespace)
293  * entries empty and keeps them, the empty or NULL values are encoded
294  * as a string containing a single whitespace. */
295  if (prev) {
296  prev->next = ast_variable_new(coltitle, S_OR(stringp," "), "");
297  if (prev->next) {
298  prev = prev->next;
299  }
300  } else {
301  prev = var = ast_variable_new(coltitle, S_OR(stringp," "), "");
302  }
303  } else {
304  while (stringp) {
305  chunk = strsep(&stringp, ";");
306  if (!ast_strlen_zero(ast_strip(chunk))) {
307  if (strchr(chunk, '^')) {
308  decode_chunk(chunk);
309  }
310  if (prev) {
311  prev->next = ast_variable_new(coltitle, chunk, "");
312  if (prev->next) {
313  prev = prev->next;
314  }
315  } else {
316  prev = var = ast_variable_new(coltitle, chunk, "");
317  }
318  }
319  }
320  }
321  }
322 
323  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
325  return var;
326 }
327 
328 /*!
329  * \brief Execute an Select query and return ast_config list
330  * \param database
331  * \param table
332  * \param fields list containing one or more field/operator/value set.
333  *
334  * Select database and preform query on table, prepare the sql statement
335  * Sub-in the values to the prepared statement and execute it.
336  * Execute this prepared query against several ODBC connected databases.
337  * Return results as an ast_config variable.
338  *
339  * \return var on success
340  * \retval NULL on failure
341  */
342 static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
343 {
344  struct odbc_obj *obj;
345  SQLHSTMT stmt;
346  char coltitle[256];
348  struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
349  const char *initfield;
350  char *op;
351  const struct ast_variable *field = fields;
352  char *stringp;
353  char *chunk;
354  SQLSMALLINT collen;
355  int res;
356  int x;
357  struct ast_variable *var=NULL;
358  struct ast_config *cfg=NULL;
359  struct ast_category *cat=NULL;
360  struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
361  SQLULEN colsize;
362  SQLSMALLINT colcount=0;
363  SQLSMALLINT datatype;
364  SQLSMALLINT decimaldigits;
365  SQLSMALLINT nullable;
366  SQLLEN indicator;
367  struct custom_prepare_struct cps = { .fields = fields, };
368 
369  if (!table || !field || !sql || !rowdata) {
370  return NULL;
371  }
372 
373  obj = ast_odbc_request_obj2(database, connected_flag);
374  if (!obj) {
375  return NULL;
376  }
377 
378  initfield = ast_strdupa(field->name);
379  if ((op = strchr(initfield, ' '))) {
380  *op = '\0';
381  }
382 
383  op = !strchr(field->name, ' ') ? " =" : "";
384  ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
385  strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
386  while ((field = field->next)) {
387  op = !strchr(field->name, ' ') ? " =" : "";
388  ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
389  strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
390  }
391  ast_str_append(&sql, 0, " ORDER BY %s", initfield);
392 
393  cps.sql = ast_str_buffer(sql);
394 
395  if (ast_string_field_init(&cps, 256)) {
397  return NULL;
398  }
399  stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
401 
402  if (!stmt) {
404  return NULL;
405  }
406 
407  res = SQLNumResultCols(stmt, &colcount);
408  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
409  ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
410  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
412  return NULL;
413  }
414 
415  cfg = ast_config_new();
416  if (!cfg) {
417  ast_log(LOG_WARNING, "Out of memory!\n");
418  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
420  return NULL;
421  }
422 
423  while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
424  var = NULL;
425  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
426  ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
427  continue;
428  }
430  if (!cat) {
431  continue;
432  }
433  for (x=0;x<colcount;x++) {
434  colsize = 0;
435  collen = sizeof(coltitle);
436  res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
437  &datatype, &colsize, &decimaldigits, &nullable);
438  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
439  ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
441  goto next_sql_fetch;
442  }
443 
444  ast_str_reset(rowdata);
445  indicator = 0;
446 
447  res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata), ast_str_size(rowdata), &indicator);
448  ast_str_update(rowdata);
449  if (indicator == SQL_NULL_DATA) {
450  continue;
451  }
452 
453  if ((res == SQL_SUCCESS) || (res == SQL_SUCCESS_WITH_INFO)) {
454  if (indicator != ast_str_strlen(rowdata)) {
455  /* If the available space was not enough to contain the row data enlarge and read in the rest */
456  ast_str_make_space(&rowdata, indicator + 1);
457  res = SQLGetData(stmt, x + 1, SQL_CHAR, ast_str_buffer(rowdata) + ast_str_strlen(rowdata),
458  ast_str_size(rowdata) - ast_str_strlen(rowdata), &indicator);
459  ast_str_update(rowdata);
460  }
461  }
462 
463  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
464  ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
466  goto next_sql_fetch;
467  }
468  stringp = ast_str_buffer(rowdata);
469  if (!strncmp(coltitle, "@", 1)) {
470  /* The '@' prefix indicates it's a sorcery extended field.
471  * Because ast_load_realtime_fields eliminates empty entries and makes blank (single whitespace)
472  * entries empty and keeps them, the empty or NULL values are encoded
473  * as a string containing a single whitespace. */
474  var = ast_variable_new(coltitle, S_OR(stringp," "), "");
475  ast_variable_append(cat, var);
476  } else {
477  while (stringp) {
478  chunk = strsep(&stringp, ";");
479  if (!ast_strlen_zero(ast_strip(chunk))) {
480  if (strchr(chunk, '^')) {
481  decode_chunk(chunk);
482  }
483  if (!strcmp(initfield, coltitle)) {
484  ast_category_rename(cat, chunk);
485  }
486  var = ast_variable_new(coltitle, chunk, "");
487  ast_variable_append(cat, var);
488  }
489  }
490  }
491  }
492  ast_category_append(cfg, cat);
493 next_sql_fetch:;
494  }
495 
496  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
498  return cfg;
499 }
500 
501 /*!
502  * \brief Execute an UPDATE query
503  * \param database
504  * \param table
505  * \param keyfield where clause field
506  * \param lookup value of field for where clause
507  * \param fields list containing one or more field/value set(s).
508  *
509  * Update a database table, prepare the sql statement using keyfield and lookup
510  * control the number of records to change. All values to be changed are stored in ap list.
511  * Sub-in the values to the prepared statement and execute it.
512  *
513  * \return number of rows affected
514  * \retval -1 on failure
515  */
516 static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
517 {
518  struct odbc_obj *obj;
519  SQLHSTMT stmt;
520  SQLLEN rowcount=0;
522  const struct ast_variable *field = fields;
523  int res, count = 0, paramcount = 0;
524  struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
525  struct odbc_cache_tables *tableptr;
526  struct odbc_cache_columns *column = NULL;
527  struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
528 
529  if (!table || !field || !keyfield || !sql) {
530  return -1;
531  }
532 
533  tableptr = ast_odbc_find_table(database, table);
534  if (!(obj = ast_odbc_request_obj2(database, connected_flag))) {
535  ast_odbc_release_table(tableptr);
536  return -1;
537  }
538 
539  if (tableptr && !ast_odbc_find_column(tableptr, keyfield)) {
540  ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", keyfield, table, database);
541  }
542 
543  ast_str_set(&sql, 0, "UPDATE %s SET ", table);
544  while (field) {
545  if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) {
546  if (paramcount++) {
547  ast_str_append(&sql, 0, ", ");
548  }
549  /* NULL test for non-text columns */
550  if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column)) {
551  ast_str_append(&sql, 0, "%s=NULL", field->name);
552  cps.skip |= (1LL << count);
553  } else {
554  /* Value is not an empty string, or column is of text type, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
555  ast_str_append(&sql, 0, "%s=?", field->name);
556  }
557  } else { /* the column does not exist in the table */
558  cps.skip |= (1LL << count);
559  }
560  ++count;
561  field = field->next;
562  }
563  ast_str_append(&sql, 0, " WHERE %s=?", keyfield);
564  ast_odbc_release_table(tableptr);
565 
566  cps.sql = ast_str_buffer(sql);
567 
568  if (ast_string_field_init(&cps, 256)) {
570  return -1;
571  }
572  stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
574 
575  if (!stmt) {
577  return -1;
578  }
579 
580  res = SQLRowCount(stmt, &rowcount);
581  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
583 
584  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
585  ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
586  return -1;
587  }
588 
589  if (rowcount >= 0) {
590  return (int) rowcount;
591  }
592 
593  return -1;
594 }
595 
597  const char *database;
598  const char *table;
602 };
603 
604 static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
605 {
606  int res, x = 1, first = 1;
607  struct update2_prepare_struct *ups = data;
608  const struct ast_variable *field;
610  SQLHSTMT stmt;
611 
612  if (!sql) {
613  return NULL;
614  }
615 
616  res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
617  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
618  ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
619  return NULL;
620  }
621 
622  ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
623 
624  for (field = ups->update_fields; field; field = field->next) {
625  if (ast_odbc_find_column(ups->tableptr, field->name)) {
626  ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", field->name);
627  SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->name), 0, (void *)field->value, 0, NULL);
628  first = 0;
629  } else {
630  ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", field->name, ups->table, ups->database);
631  }
632  }
633 
634  ast_str_append(&sql, 0, "WHERE");
635  first = 1;
636 
637  for (field = ups->lookup_fields; field; field = field->next) {
638  if (!ast_odbc_find_column(ups->tableptr, field->name)) {
639  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);
640  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
641  return NULL;
642  }
643  ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", field->name);
644  SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->value), 0, (void *)field->value, 0, NULL);
645  first = 0;
646  }
647 
648  res = ast_odbc_prepare(obj, stmt, ast_str_buffer(sql));
649  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
650  if (res == SQL_ERROR) {
651  ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Prepare");
652  }
653  ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", ast_str_buffer(sql));
654  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
655  return NULL;
656  }
657 
658  return stmt;
659 }
660 
661 /*!
662  * \brief Execute an UPDATE query
663  * \param database, table, lookup_fields
664  * \param update_fields list containing one or more field/value set(s).
665  *
666  * Update a database table, preparing the sql statement from a list of
667  * key/value pairs specified in ap. The lookup pairs are specified first
668  * and are separated from the update pairs by a sentinel value.
669  * Sub-in the values to the prepared statement and execute it.
670  *
671  * \return number of rows affected
672  * \retval -1 on failure
673 */
674 static int update2_odbc(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
675 {
676  struct odbc_obj *obj;
677  SQLHSTMT stmt;
678  struct update2_prepare_struct ups = {
679  .database = database,
680  .table = table,
681  .lookup_fields = lookup_fields,
682  .update_fields = update_fields,
683  };
684  struct ast_str *sql;
685  int res;
686  SQLLEN rowcount = 0;
687 
688  ups.tableptr = ast_odbc_find_table(database, table);
689  if (!ups.tableptr) {
690  ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", table, database);
691  return -1;
692  }
693 
694  if (!(obj = ast_odbc_request_obj(database, 0))) {
696  return -1;
697  }
698 
699  if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
702  return -1;
703  }
704 
705  /* We don't need the table anymore */
707 
708  res = SQLRowCount(stmt, &rowcount);
709  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
711 
712  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
713  /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
715  ast_assert(sql != NULL);
716  ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
717  return -1;
718  }
719 
720  if (rowcount >= 0) {
721  return (int) rowcount;
722  }
723 
724  return -1;
725 }
726 
727 /*!
728  * \brief Execute an INSERT query
729  * \param database
730  * \param table
731  * \param fields list containing one or more field/value set(s)
732  *
733  * Insert a new record into database table, prepare the sql statement.
734  * All values to be changed are stored in ap list.
735  * Sub-in the values to the prepared statement and execute it.
736  *
737  * \return number of rows affected
738  * \retval -1 on failure
739  */
740 static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
741 {
742  struct odbc_obj *obj;
743  SQLHSTMT stmt;
744  SQLLEN rowcount=0;
745  const struct ast_variable *field = fields;
746  struct ast_str *keys;
747  struct ast_str *vals;
749  int res;
750  struct custom_prepare_struct cps = { .fields = fields, };
751  struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
752 
754  vals = ast_str_create(SQL_BUF_SIZE / 4);
755  if (!table || !field || !keys || !vals || !sql) {
756  ast_free(vals);
757  ast_free(keys);
758  return -1;
759  }
760 
761  obj = ast_odbc_request_obj2(database, connected_flag);
762  if (!obj) {
763  ast_free(vals);
764  ast_free(keys);
765  return -1;
766  }
767 
768  ast_str_set(&keys, 0, "%s", field->name);
769  ast_str_set(&vals, 0, "?");
770  while ((field = field->next)) {
771  ast_str_append(&keys, 0, ", %s", field->name);
772  ast_str_append(&vals, 0, ", ?");
773  }
774  ast_str_set(&sql, 0, "INSERT INTO %s (%s) VALUES (%s)",
776 
777  ast_free(vals);
778  ast_free(keys);
779  cps.sql = ast_str_buffer(sql);
780 
781  if (ast_string_field_init(&cps, 256)) {
783  return -1;
784  }
785  stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
787 
788  if (!stmt) {
790  return -1;
791  }
792 
793  res = SQLRowCount(stmt, &rowcount);
794  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
796 
797  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
798  ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
799  return -1;
800  }
801 
802  if (rowcount >= 0)
803  return (int)rowcount;
804 
805  return -1;
806 }
807 
808 /*!
809  * \brief Execute an DELETE query
810  * \param database
811  * \param table
812  * \param keyfield where clause field
813  * \param lookup value of field for where clause
814  * \param fields list containing one or more field/value set(s)
815  *
816  * Delete a row from a database table, prepare the sql statement using keyfield and lookup
817  * control the number of records to change. Additional params to match rows are stored in ap list.
818  * Sub-in the values to the prepared statement and execute it.
819  *
820  * \return number of rows affected
821  * \retval -1 on failure
822  */
823 static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
824 {
825  struct odbc_obj *obj;
826  SQLHSTMT stmt;
827  SQLLEN rowcount=0;
829  const struct ast_variable *field;
830  int res;
831  struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
832  struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
833 
834  if (!table || !sql) {
835  return -1;
836  }
837 
838  obj = ast_odbc_request_obj2(database, connected_flag);
839  if (!obj) {
840  return -1;
841  }
842 
843  ast_str_set(&sql, 0, "DELETE FROM %s WHERE ", table);
844  for (field = fields; field; field = field->next) {
845  ast_str_append(&sql, 0, "%s=? AND ", field->name);
846  }
847  ast_str_append(&sql, 0, "%s=?", keyfield);
848 
849  cps.sql = ast_str_buffer(sql);
850 
851  if (ast_string_field_init(&cps, 256)) {
853  return -1;
854  }
855  stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
857 
858  if (!stmt) {
860  return -1;
861  }
862 
863  res = SQLRowCount(stmt, &rowcount);
864  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
866 
867  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
868  ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
869  return -1;
870  }
871 
872  if (rowcount >= 0)
873  return (int)rowcount;
874 
875  return -1;
876 }
877 
879  char *sql;
880  unsigned long cat_metric;
881  char category[128];
882  char var_name[128];
883  char *var_val;
884  unsigned long var_val_size;
885  SQLLEN err;
886 };
887 
888 
889 static SQLHSTMT length_determination_odbc_prepare(struct odbc_obj *obj, void *data)
890 {
891  struct config_odbc_obj *q = data;
892  SQLHSTMT sth;
893  int res;
894 
895  res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
896  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
897  ast_verb(4, "Failure in AllocStatement %d\n", res);
898  return NULL;
899  }
900 
901  res = ast_odbc_prepare(obj, sth, q->sql);
902  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
903  ast_verb(4, "Error in PREPARE %d\n", res);
904  SQLFreeHandle(SQL_HANDLE_STMT, sth);
905  return NULL;
906  }
907 
908  SQLBindCol(sth, 1, SQL_C_ULONG, &q->var_val_size, sizeof(q->var_val_size), &q->err);
909 
910  return sth;
911 }
912 
913 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
914 {
915  struct config_odbc_obj *q = data;
916  SQLHSTMT sth;
917  int res;
918 
919  res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
920  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
921  ast_verb(4, "Failure in AllocStatement %d\n", res);
922  return NULL;
923  }
924 
925  res = ast_odbc_prepare(obj, sth, q->sql);
926  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
927  ast_verb(4, "Error in PREPARE %d\n", res);
928  SQLFreeHandle(SQL_HANDLE_STMT, sth);
929  return NULL;
930  }
931 
932  SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
933  SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
934  SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
935  SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, q->var_val_size, &q->err);
936 
937  return sth;
938 }
939 
940 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)
941 {
942  struct ast_variable *new_v;
943  struct ast_category *cur_cat;
944  int res = 0;
945  struct odbc_obj *obj;
947  unsigned int last_cat_metric = 0;
948  SQLSMALLINT rowcount = 0;
949  SQLHSTMT stmt;
950  char last[128] = "";
951  struct config_odbc_obj q;
952  struct ast_flags loader_flags = { 0 };
953  struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
954 
955  memset(&q, 0, sizeof(q));
956 
957  if (!file || !strcmp (file, "res_config_odbc.conf") || !sql) {
958  return NULL; /* cant configure myself with myself ! */
959  }
960 
961  obj = ast_odbc_request_obj2(database, connected_flag);
962  if (!obj)
963  return NULL;
964 
965  ast_str_set(&sql, 0, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'",
966  table, file);
967  q.sql = ast_str_buffer(sql);
968 
970  if (!stmt) {
971  ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
973  return NULL;
974  }
975 
976  res = SQLNumResultCols(stmt, &rowcount);
977 
978  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
979  ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
980  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
982  return NULL;
983  }
984 
985  if (!rowcount) {
986  ast_log(LOG_NOTICE, "found nothing\n");
988  return cfg;
989  }
990 
991  /* There will be only one result for this, the maximum length of a variable value */
992  if (SQLFetch(stmt) == SQL_NO_DATA) {
993  ast_log(LOG_NOTICE, "Failed to determine maximum length of a configuration value\n");
994  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
996  return NULL;
997  }
998 
999  /* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
1000  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1001 
1002  ast_str_set(&sql, 0, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
1003  ast_str_append(&sql, 0, "WHERE filename='%s' AND commented=0 ", file);
1004  ast_str_append(&sql, 0, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
1005  q.sql = ast_str_buffer(sql);
1006 
1007  q.var_val_size += 1;
1009  if (!q.var_val) {
1010  ast_log(LOG_WARNING, "Could not create buffer for reading in configuration values for '%s'\n", file);
1011  ast_odbc_release_obj(obj);
1012  return NULL;
1013  }
1014 
1016  if (!stmt) {
1017  ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
1018  ast_odbc_release_obj(obj);
1019  ast_free(q.var_val);
1020  return NULL;
1021  }
1022 
1023  res = SQLNumResultCols(stmt, &rowcount);
1024 
1025  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1026  ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
1027  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1028  ast_odbc_release_obj(obj);
1029  ast_free(q.var_val);
1030  return NULL;
1031  }
1032 
1033  if (!rowcount) {
1034  ast_log(LOG_NOTICE, "found nothing\n");
1035  ast_odbc_release_obj(obj);
1036  ast_free(q.var_val);
1037  return cfg;
1038  }
1039 
1040  cur_cat = ast_config_get_current_category(cfg);
1041 
1042  while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
1043  if (!strcmp (q.var_name, "#include")) {
1044  if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
1045  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1046  ast_odbc_release_obj(obj);
1047  ast_free(q.var_val);
1048  return NULL;
1049  }
1050  continue;
1051  }
1052  if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
1053  cur_cat = ast_category_new_dynamic(q.category);
1054  if (!cur_cat) {
1055  break;
1056  }
1057  strcpy(last, q.category);
1058  last_cat_metric = q.cat_metric;
1059  ast_category_append(cfg, cur_cat);
1060  }
1061 
1062  new_v = ast_variable_new(q.var_name, q.var_val, "");
1063  ast_variable_append(cur_cat, new_v);
1064  }
1065 
1066  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1067  ast_odbc_release_obj(obj);
1068  ast_free(q.var_val);
1069  return cfg;
1070 }
1071 
1072 #define warn_length(col, size) ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is not long enough to contain realtime data (needs %d)\n", table, database, col->name, size)
1073 #define warn_type(col, type) ast_log(LOG_WARNING, "Realtime table %s@%s: column '%s' is of the incorrect type (%d) to contain the required realtime data\n", table, database, col->name, col->type)
1074 
1075 static int require_odbc(const char *database, const char *table, va_list ap)
1076 {
1077  struct odbc_cache_tables *tableptr = ast_odbc_find_table(database, table);
1078  struct odbc_cache_columns *col;
1079  char *elm;
1080  int type, size;
1081 
1082  if (!tableptr) {
1083  return -1;
1084  }
1085 
1086  while ((elm = va_arg(ap, char *))) {
1087  type = va_arg(ap, require_type);
1088  size = va_arg(ap, int);
1089  /* Check if the field matches the criteria */
1090  AST_RWLIST_TRAVERSE(&tableptr->columns, col, list) {
1091  if (strcmp(col->name, elm) == 0) {
1092  /* Type check, first. Some fields are more particular than others */
1093  switch (col->type) {
1094  case SQL_CHAR:
1095  case SQL_VARCHAR:
1096  case SQL_LONGVARCHAR:
1097 #ifdef HAVE_ODBC_WCHAR
1098  case SQL_WCHAR:
1099  case SQL_WVARCHAR:
1100  case SQL_WLONGVARCHAR:
1101 #endif
1102  case SQL_BINARY:
1103  case SQL_VARBINARY:
1104  case SQL_LONGVARBINARY:
1105  case SQL_GUID:
1106 #define CHECK_SIZE(n) \
1107  if (col->size < n) { \
1108  warn_length(col, n); \
1109  } \
1110  break;
1111  switch (type) {
1112  case RQ_UINTEGER1: CHECK_SIZE(3) /* 255 */
1113  case RQ_INTEGER1: CHECK_SIZE(4) /* -128 */
1114  case RQ_UINTEGER2: CHECK_SIZE(5) /* 65535 */
1115  case RQ_INTEGER2: CHECK_SIZE(6) /* -32768 */
1116  case RQ_UINTEGER3: /* 16777215 */
1117  case RQ_INTEGER3: CHECK_SIZE(8) /* -8388608 */
1118  case RQ_DATE: /* 2008-06-09 */
1119  case RQ_UINTEGER4: CHECK_SIZE(10) /* 4200000000 */
1120  case RQ_INTEGER4: CHECK_SIZE(11) /* -2100000000 */
1121  case RQ_DATETIME: /* 2008-06-09 16:03:47 */
1122  case RQ_UINTEGER8: CHECK_SIZE(19) /* trust me */
1123  case RQ_INTEGER8: CHECK_SIZE(20) /* ditto */
1124  case RQ_FLOAT:
1125  case RQ_CHAR: CHECK_SIZE(size)
1126  }
1127 #undef CHECK_SIZE
1128  break;
1129  case SQL_TYPE_DATE:
1130  if (type != RQ_DATE) {
1131  warn_type(col, type);
1132  }
1133  break;
1134  case SQL_TYPE_TIMESTAMP:
1135  case SQL_TIMESTAMP:
1136  if (type != RQ_DATE && type != RQ_DATETIME) {
1137  warn_type(col, type);
1138  }
1139  break;
1140  case SQL_BIT:
1141  warn_length(col, size);
1142  break;
1143 #define WARN_TYPE_OR_LENGTH(n) \
1144  if (!ast_rq_is_int(type)) { \
1145  warn_type(col, type); \
1146  } else { \
1147  warn_length(col, n); \
1148  }
1149  case SQL_TINYINT:
1150  if (type != RQ_UINTEGER1) {
1152  }
1153  break;
1154  case SQL_C_STINYINT:
1155  if (type != RQ_INTEGER1) {
1157  }
1158  break;
1159  case SQL_C_USHORT:
1160  if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_UINTEGER2) {
1162  }
1163  break;
1164  case SQL_SMALLINT:
1165  case SQL_C_SSHORT:
1166  if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 && type != RQ_INTEGER2) {
1168  }
1169  break;
1170  case SQL_C_ULONG:
1171  if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1172  type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1173  type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1174  type != RQ_INTEGER4) {
1176  }
1177  break;
1178  case SQL_INTEGER:
1179  case SQL_C_SLONG:
1180  if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1181  type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1182  type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1183  type != RQ_INTEGER4) {
1185  }
1186  break;
1187  case SQL_C_UBIGINT:
1188  if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1189  type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1190  type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1191  type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
1192  type != RQ_INTEGER8) {
1194  }
1195  break;
1196  case SQL_BIGINT:
1197  case SQL_C_SBIGINT:
1198  if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
1199  type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
1200  type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
1201  type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
1202  type != RQ_INTEGER8) {
1204  }
1205  break;
1206 #undef WARN_TYPE_OR_LENGTH
1207  case SQL_NUMERIC:
1208  case SQL_DECIMAL:
1209  case SQL_FLOAT:
1210  case SQL_REAL:
1211  case SQL_DOUBLE:
1212  if (!ast_rq_is_int(type) && type != RQ_FLOAT) {
1213  warn_type(col, type);
1214  }
1215  break;
1216  default:
1217  ast_log(LOG_WARNING, "Realtime table %s@%s: column type (%d) unrecognized for column '%s'\n", table, database, col->type, elm);
1218  }
1219  break;
1220  }
1221  }
1222  if (!col) {
1223  ast_log(LOG_WARNING, "Realtime table %s@%s requires column '%s', but that column does not exist!\n", table, database, elm);
1224  }
1225  }
1226  AST_RWLIST_UNLOCK(&tableptr->columns);
1227  return 0;
1228 }
1229 #undef warn_length
1230 #undef warn_type
1231 
1232 static int unload_odbc(const char *a, const char *b)
1233 {
1234  return ast_odbc_clear_cache(a, b);
1235 }
1236 
1237 static struct ast_config_engine odbc_engine = {
1238  .name = "odbc",
1239  .load_func = config_odbc,
1240  .realtime_func = realtime_odbc,
1241  .realtime_multi_func = realtime_multi_odbc,
1242  .store_func = store_odbc,
1243  .destroy_func = destroy_odbc,
1244  .update_func = update_odbc,
1245  .update2_func = update2_odbc,
1246  .require_func = require_odbc,
1247  .unload_func = unload_odbc,
1248 };
1249 
1250 static int unload_module (void)
1251 {
1253 
1254  return 0;
1255 }
1256 
1257 static int load_module (void)
1258 {
1260 
1261  return 0;
1262 }
1263 
1264 static int reload_module(void)
1265 {
1266  return 0;
1267 }
1268 
1269 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime ODBC configuration",
1270  .support_level = AST_MODULE_SUPPORT_CORE,
1271  .load = load_module,
1272  .unload = unload_module,
1273  .reload = reload_module,
1274  .load_pri = AST_MODPRI_REALTIME_DRIVER,
1275  .requires = "extconfig,res_odbc",
1276 );
struct sla_ringing_trunk * first
Definition: app_meetme.c:1094
struct sla_ringing_trunk * last
Definition: app_meetme.c:1094
#define var
Definition: ast_expr2f.c:614
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
General Asterisk PBX channel definitions.
Generic File Format Support. Should be included by clients of the file handling routines....
char * strcasestr(const char *, const char *)
char * strsep(char **str, const char *delims)
Configuration File Parser.
void ast_category_rename(struct ast_category *cat, const char *name)
Definition: main/config.c:1436
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3275
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition: extconf.c:2834
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:3072
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:3178
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
Definition: extconf.c:2782
void ast_category_destroy(struct ast_category *cat)
Definition: extconf.c:2846
int ast_rq_is_int(require_type type)
Check if require type is an integer type.
require_type
Types used in ast_realtime_require_field.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
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:3056
#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:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_REALTIME_DRIVER
Definition: module.h:323
@ 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_engine odbc_engine
#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 struct ast_variable * realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an SQL query and return ast_variable list.
static int require_odbc(const char *database, const char *table, va_list ap)
#define ENCODE_CHUNK(buffer, s)
static struct ast_threadstorage rowdata_buf
static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Execute an UPDATE query.
static int is_text(const struct odbc_cache_columns *column)
static int reload_module(void)
static struct ast_config * realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an Select query and return ast_config list.
static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
static int update2_odbc(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
Execute an UPDATE query.
static int unload_odbc(const char *a, const char *b)
#define warn_type(col, type)
static int load_module(void)
static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
static int unload_module(void)
static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
Execute an INSERT query.
static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Execute an DELETE query.
#define WARN_TYPE_OR_LENGTH(n)
static struct ast_config * config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
static struct ast_threadstorage sql_buf
static struct keys keys
ODBC resource manager.
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
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
#define ast_odbc_release_table(ptr)
Release a table returned from ast_odbc_find_table.
Definition: res_odbc.h:219
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
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
#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
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
@ RES_ODBC_CONNECTED
Definition: res_odbc.h:42
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
Definition: res_odbc.h:120
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 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:1117
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
#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
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:674
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:640
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:1091
#define ast_str_make_space(buf, new_len)
Definition: strings.h:806
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:684
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:711
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:723
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:887
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:604
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:734