Asterisk - The Open Source Telephony Project  18.5.0
func_odbc.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (c) 2005, 2006 Tilghman Lesher
5  * Copyright (c) 2008, 2009 Digium, Inc.
6  *
7  * Tilghman Lesher <[email protected]>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19 
20 /*!
21  * \file
22  *
23  * \brief ODBC lookups
24  *
25  * \author Tilghman Lesher <[email protected]>
26  *
27  * \ingroup functions
28  */
29 
30 /*** MODULEINFO
31  <depend>res_odbc</depend>
32  <depend>generic_odbc</depend>
33  <support_level>core</support_level>
34  ***/
35 
36 #include "asterisk.h"
37 
38 #include "asterisk/module.h"
39 #include "asterisk/file.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/config.h"
43 #include "asterisk/res_odbc.h"
45 #include "asterisk/app.h"
46 #include "asterisk/cli.h"
47 #include "asterisk/strings.h"
48 
49 /*** DOCUMENTATION
50  <function name="ODBC_FETCH" language="en_US">
51  <synopsis>
52  Fetch a row from a multirow query.
53  </synopsis>
54  <syntax>
55  <parameter name="result-id" required="true" />
56  </syntax>
57  <description>
58  <para>For queries which are marked as mode=multirow, the original
59  query returns a <replaceable>result-id</replaceable> from which results
60  may be fetched. This function implements the actual fetch of the results.</para>
61  <para>This also sets <variable>ODBC_FETCH_STATUS</variable>.</para>
62  <variablelist>
63  <variable name="ODBC_FETCH_STATUS">
64  <value name="SUCESS">
65  If rows are available.
66  </value>
67  <value name="FAILURE">
68  If no rows are available.
69  </value>
70  </variable>
71  </variablelist>
72  </description>
73  </function>
74  <application name="ODBCFinish" language="en_US">
75  <synopsis>
76  Clear the resultset of a sucessful multirow query.
77  </synopsis>
78  <syntax>
79  <parameter name="result-id" required="true" />
80  </syntax>
81  <description>
82  <para>For queries which are marked as mode=multirow, this will clear
83  any remaining rows of the specified resultset.</para>
84  </description>
85  </application>
86  <function name="SQL_ESC" language="en_US">
87  <synopsis>
88  Escapes single ticks for use in SQL statements.
89  </synopsis>
90  <syntax>
91  <parameter name="string" required="true" />
92  </syntax>
93  <description>
94  <para>Used in SQL templates to escape data which may contain single ticks
95  <literal>'</literal> which are otherwise used to delimit data.</para>
96  <para>Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'</para>
97  </description>
98  </function>
99  ***/
100 
101 static char *config = "func_odbc.conf";
102 
103 #define DEFAULT_SINGLE_DB_CONNECTION 0
104 
106 
108 
110  OPT_ESCAPECOMMAS = (1 << 0),
111  OPT_MULTIROW = (1 << 1),
112 };
113 
116  char readhandle[5][30];
117  char writehandle[5][30];
118  char *sql_read;
119  char *sql_write;
120  char *sql_insert;
121  unsigned int flags;
122  int rowlimit;
123  int minargs;
124  struct ast_custom_function *acf;
125 };
126 
127 static void odbc_datastore_free(void *data);
128 
129 static const struct ast_datastore_info odbc_info = {
130  .type = "FUNC_ODBC",
131  .destroy = odbc_datastore_free,
132 };
133 
134 /* For storing each result row */
137  char data[0];
138 };
139 
140 /* For storing each result set */
143  char names[0];
144 };
145 
146 /* \brief Data source name
147  *
148  * This holds data that pertains to a DSN
149  */
150 struct dsn {
151  /*! A connection to the database */
153  /*! The name of the DSN as defined in res_odbc.conf */
154  char name[0];
155 };
156 
157 #define DSN_BUCKETS 37
158 
160 
161 static int dsn_hash(const void *obj, const int flags)
162 {
163  const struct dsn *object;
164  const char *key;
165 
166  switch (flags & OBJ_SEARCH_MASK) {
167  case OBJ_SEARCH_KEY:
168  key = obj;
169  break;
170  case OBJ_SEARCH_OBJECT:
171  object = obj;
172  key = object->name;
173  break;
174  default:
175  ast_assert(0);
176  return 0;
177  }
178  return ast_str_hash(key);
179 }
180 
181 static int dsn_cmp(void *obj, void *arg, int flags)
182 {
183  const struct dsn *object_left = obj;
184  const struct dsn *object_right = arg;
185  const char *right_key = arg;
186  int cmp;
187 
188  switch (flags & OBJ_SEARCH_MASK) {
189  case OBJ_SEARCH_OBJECT:
190  right_key = object_right->name;
191  /* Fall through */
192  case OBJ_SEARCH_KEY:
193  cmp = strcmp(object_left->name, right_key);
194  break;
196  cmp = strncmp(object_left->name, right_key, strlen(right_key));
197  break;
198  default:
199  cmp = 0;
200  break;
201  }
202 
203  if (cmp) {
204  return 0;
205  }
206 
207  return CMP_MATCH;
208 }
209 
210 static void dsn_destructor(void *obj)
211 {
212  struct dsn *dsn = obj;
213 
214  if (dsn->connection) {
216  }
217 }
218 
219 /*!
220  * \brief Create a DSN and connect to the database
221  *
222  * \param name The name of the DSN as found in res_odbc.conf
223  * \retval NULL Fail
224  * \retval non-NULL The newly-created structure
225  */
226 static struct dsn *create_dsn(const char *name)
227 {
228  struct dsn *dsn;
229 
230  if (!dsns) {
231  return NULL;
232  }
233 
234  dsn = ao2_alloc(sizeof(*dsn) + strlen(name) + 1, dsn_destructor);
235  if (!dsn) {
236  return NULL;
237  }
238 
239  /* Safe */
240  strcpy(dsn->name, name);
241 
242  dsn->connection = ast_odbc_request_obj(name, 0);
243  if (!dsn->connection) {
244  ao2_ref(dsn, -1);
245  return NULL;
246  }
247 
248  if (!ao2_link_flags(dsns, dsn, OBJ_NOLOCK)) {
249  ao2_ref(dsn, -1);
250  return NULL;
251  }
252 
253  return dsn;
254 }
255 
256 static SQLHSTMT silent_execute(struct odbc_obj *obj, void *data);
257 
258 /*!
259  * \brief Determine if the connection has died.
260  *
261  * \param connection The connection to check
262  * \retval 1 Yep, it's dead
263  * \retval 0 It's alive and well
264  */
266 {
267  SQLINTEGER dead;
268  SQLRETURN res;
269  SQLHSTMT stmt;
270 
271  if (!connection) {
272  return 1;
273  }
274 
275  res = SQLGetConnectAttr(connection->con, SQL_ATTR_CONNECTION_DEAD, &dead, 0, 0);
276  if (SQL_SUCCEEDED(res)) {
277  return dead == SQL_CD_TRUE ? 1 : 0;
278  }
279 
280  /* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a direct
281  * execute of a probing statement and see if that succeeds instead
282  */
283  stmt = ast_odbc_direct_execute(connection, silent_execute, "SELECT 1");
284  if (!stmt) {
285  return 1;
286  }
287 
288  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
289  return 0;
290 }
291 
292 /*!
293  * \brief Retrieve a DSN, or create it if it does not exist.
294  *
295  * The created DSN is returned locked. This should be inconsequential
296  * to callers in most cases.
297  *
298  * When finished with the returned structure, the caller must call
299  * \ref release_dsn
300  *
301  * \param name Name of the DSN as found in res_odbc.conf
302  * \retval NULL Unable to retrieve or create the DSN
303  * \retval non-NULL The retrieved/created locked DSN
304  */
305 static struct dsn *get_dsn(const char *name)
306 {
307  struct dsn *dsn;
308 
309  if (!dsns) {
310  return NULL;
311  }
312 
313  ao2_lock(dsns);
314  dsn = ao2_find(dsns, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
315  if (!dsn) {
316  dsn = create_dsn(name);
317  }
318  ao2_unlock(dsns);
319 
320  if (!dsn) {
321  return NULL;
322  }
323 
324  ao2_lock(dsn);
325  if (!dsn->connection) {
326  dsn->connection = ast_odbc_request_obj(name, 0);
327  if (!dsn->connection) {
328  ao2_unlock(dsn);
329  ao2_ref(dsn, -1);
330  return NULL;
331  }
332  return dsn;
333  }
334 
335  if (connection_dead(dsn->connection)) {
337  dsn->connection = ast_odbc_request_obj(name, 0);
338  if (!dsn->connection) {
339  ao2_unlock(dsn);
340  ao2_ref(dsn, -1);
341  return NULL;
342  }
343  }
344 
345  return dsn;
346 }
347 
348 /*!
349  * \brief Get a DB handle via a DSN or directly
350  *
351  * If single db connection then get the DB handle via DSN
352  * else by requesting a connection directly
353  *
354  * \param dsn_name Name of the DSN as found in res_odbc.conf
355  * \param dsn The pointer to the DSN
356  * \retval NULL Unable to retrieve the DB handle
357  * \retval non-NULL The retrieved DB handle
358  */
359 static struct odbc_obj *get_odbc_obj(const char *dsn_name, struct dsn **dsn)
360 {
361  struct odbc_obj *obj = NULL;
362 
364  if (single_db_connection) {
365  if (dsn) {
366  *dsn = get_dsn(dsn_name);
367  if (*dsn) {
368  obj = (*dsn)->connection;
369  }
370  }
371  } else {
372  obj = ast_odbc_request_obj(dsn_name, 0);
373  }
375 
376  return obj;
377 }
378 
379 /*!
380  * \brief Release an ODBC obj or a DSN
381  *
382  * If single db connection then unlock and unreference the DSN
383  * else release the ODBC obj
384  *
385  * \param obj The pointer to the ODBC obj to release
386  * \param dsn The pointer to the dsn to unlock and unreference
387  */
388 static inline void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
389 {
390  if (dsn && *dsn) {
391  /* If multiple connections are not enabled then the guarantee
392  * of a single connection already exists and holding on to the
393  * connection would prevent any other user from acquiring it
394  * indefinitely.
395  */
396  if (ast_odbc_get_max_connections((*dsn)->name) < 2) {
397  ast_odbc_release_obj((*dsn)->connection);
398  (*dsn)->connection = NULL;
399  }
400  ao2_unlock(*dsn);
401  ao2_ref(*dsn, -1);
402  *dsn = NULL;
403  /* Some callers may provide both an obj and dsn. To ensure that
404  * the connection is not released twice we set it to NULL here if
405  * present.
406  */
407  if (obj) {
408  *obj = NULL;
409  }
410  } else if (obj && *obj) {
411  ast_odbc_release_obj(*obj);
412  *obj = NULL;
413  }
414 }
415 
417 
418 static int resultcount = 0;
419 
424 
425 static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
426 
427 static void odbc_datastore_free(void *data)
428 {
429  struct odbc_datastore *result = data;
430  struct odbc_datastore_row *row;
431 
432  if (!result) {
433  return;
434  }
435 
436  AST_LIST_LOCK(result);
437  while ((row = AST_LIST_REMOVE_HEAD(result, list))) {
438  ast_free(row);
439  }
440  AST_LIST_UNLOCK(result);
441  AST_LIST_HEAD_DESTROY(result);
442  ast_free(result);
443 }
444 
445 /*!
446  * \brief Common execution function for SQL queries.
447  *
448  * \param obj DB connection
449  * \param data The query to execute
450  * \param silent If true, do not print warnings on failure
451  * \retval NULL Failed to execute query
452  * \retval non-NULL The executed statement
453  */
454 static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
455 {
456  int res;
457  char *sql = data;
458  SQLHSTMT stmt;
459 
460  res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
461  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
462  ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res);
463  return NULL;
464  }
465 
466  res = ast_odbc_execute_sql(obj, stmt, sql);
467  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
468  if (res == SQL_ERROR && !silent) {
469  int i;
470  SQLINTEGER nativeerror=0, numfields=0;
471  SQLSMALLINT diagbytes=0;
472  unsigned char state[10], diagnostic[256];
473 
474  SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
475  for (i = 0; i < numfields; i++) {
476  SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
477  ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
478  if (i > 10) {
479  ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
480  break;
481  }
482  }
483  }
484 
485  if (!silent) {
486  ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql);
487  }
488  SQLCloseCursor(stmt);
489  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
490  return NULL;
491  }
492 
493  return stmt;
494 }
495 
496 static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
497 {
498  return execute(obj, data, 0);
499 }
500 
501 static SQLHSTMT silent_execute(struct odbc_obj *obj, void *data)
502 {
503  return execute(obj, data, 1);
504 }
505 
506 /*
507  * Master control routine
508  */
509 static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
510 {
511  struct odbc_obj *obj = NULL;
512  struct acf_odbc_query *query;
513  char *t, varname[15];
514  int i, dsn_num, bogus_chan = 0;
515  int transactional = 0;
517  AST_APP_ARG(field)[100];
518  );
520  AST_APP_ARG(field)[100];
521  );
522  SQLHSTMT stmt = NULL;
523  SQLLEN rows=0;
524  struct ast_str *buf = ast_str_thread_get(&sql_buf, 16);
525  struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16);
526  const char *status = "FAILURE";
527  struct dsn *dsn = NULL;
528 
529  if (!buf || !insertbuf) {
530  return -1;
531  }
532 
534  AST_RWLIST_TRAVERSE(&queries, query, list) {
535  if (!strcmp(query->acf->name, cmd)) {
536  break;
537  }
538  }
539 
540  if (!query) {
541  ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
543  if (chan) {
544  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
545  }
546  return -1;
547  }
548 
550  if (args.argc < query->minargs) {
551  ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
552  args.argc, cmd, query->minargs);
554  return -1;
555  }
556 
557  if (!chan) {
558  if (!(chan = ast_dummy_channel_alloc())) {
560  return -1;
561  }
562  bogus_chan = 1;
563  }
564 
565  if (!bogus_chan) {
566  ast_autoservice_start(chan);
567  }
568 
569  ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300);
570  /* We only get here if sql_write is set. sql_insert is optional however. */
571  if (query->sql_insert) {
572  ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300);
573  }
574 
575  /* Parse our arguments */
576  t = value ? ast_strdupa(value) : "";
577 
578  if (!s || !t) {
579  ast_log(LOG_ERROR, "Out of memory\n");
581  if (!bogus_chan) {
582  ast_autoservice_stop(chan);
583  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
584  } else {
585  ast_channel_unref(chan);
586  }
587  return -1;
588  }
589 
590  snprintf(varname, sizeof(varname), "%u", args.argc);
591  pbx_builtin_pushvar_helper(chan, "ARGC", varname);
592  for (i = 0; i < args.argc; i++) {
593  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
594  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
595  }
596 
597  /* Parse values, just like arguments */
599  for (i = 0; i < values.argc; i++) {
600  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
601  pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
602  }
603 
604  /* Additionally set the value as a whole (but push an empty string if value is NULL) */
605  pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
606 
607  ast_str_substitute_variables(&buf, 0, chan, query->sql_write);
608  if (query->sql_insert) {
609  ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert);
610  }
611 
612  if (bogus_chan) {
613  chan = ast_channel_unref(chan);
614  } else {
615  /* Restore prior values */
616  pbx_builtin_setvar_helper(chan, "ARGC", NULL);
617 
618  for (i = 0; i < args.argc; i++) {
619  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
620  pbx_builtin_setvar_helper(chan, varname, NULL);
621  }
622 
623  for (i = 0; i < values.argc; i++) {
624  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
625  pbx_builtin_setvar_helper(chan, varname, NULL);
626  }
627  pbx_builtin_setvar_helper(chan, "VALUE", NULL);
628  }
629 
630  /*!\note
631  * Okay, this part is confusing. Transactions belong to a single database
632  * handle. Therefore, when working with transactions, we CANNOT failover
633  * to multiple DSNs. We MUST have a single handle all the way through the
634  * transaction, or else we CANNOT enforce atomicity.
635  */
636  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
637  if (!ast_strlen_zero(query->writehandle[dsn_num])) {
638  if (transactional) {
639  /* This can only happen second time through or greater. */
640  ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
641  }
642 
643  if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) {
644  transactional = 1;
645  } else {
646  obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
647  transactional = 0;
648  }
649 
650  if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) {
651  break;
652  }
653  if (!transactional) {
654  release_obj_or_dsn (&obj, &dsn);
655  }
656  }
657  }
658 
659  if (stmt) {
660  SQLRowCount(stmt, &rows);
661  SQLCloseCursor(stmt);
662  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
663 
664  if (rows != 0) {
665  status = "SUCCESS";
666 
667  } else if (query->sql_insert) {
668  if (!transactional) {
669  release_obj_or_dsn (&obj, &dsn);
670  }
671 
672  for (transactional = 0, dsn_num = 0; dsn_num < 5; dsn_num++) {
673  if (!ast_strlen_zero(query->writehandle[dsn_num])) {
674  if (transactional) {
675  /* This can only happen second time through or greater. */
676  ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n");
677  } else {
678  release_obj_or_dsn (&obj, &dsn);
679  }
680 
681  if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn_num]))) {
682  transactional = 1;
683  } else {
684  obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
685  transactional = 0;
686  }
687  if (obj) {
688  stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf));
689  }
690  }
691  if (stmt) {
692  status = "FAILOVER";
693  SQLRowCount(stmt, &rows);
694  SQLCloseCursor(stmt);
695  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
696  break;
697  }
698  }
699  }
700  }
701 
703 
704  /* Output the affected rows, for all cases. In the event of failure, we
705  * flag this as -1 rows. Note that this is different from 0 affected rows
706  * which would be the case if we succeeded in our query, but the values did
707  * not change. */
708  if (!bogus_chan) {
709  snprintf(varname, sizeof(varname), "%d", (int)rows);
710  pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
711  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
712  }
713 
714  if (!transactional) {
715  release_obj_or_dsn (&obj, &dsn);
716  }
717 
718  if (!bogus_chan) {
719  ast_autoservice_stop(chan);
720  }
721 
722  return 0;
723 }
724 
725 static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
726 {
727  struct odbc_obj *obj = NULL;
728  struct acf_odbc_query *query;
729  char varname[15], rowcount[12] = "-1";
730  struct ast_str *colnames = ast_str_thread_get(&colnames_buf, 16);
731  int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0, dsn_num, bogus_chan = 0;
733  AST_APP_ARG(field)[100];
734  );
735  SQLHSTMT stmt = NULL;
736  SQLSMALLINT colcount=0;
737  SQLLEN indicator;
738  SQLSMALLINT collength;
739  struct odbc_datastore *resultset = NULL;
740  struct odbc_datastore_row *row = NULL;
741  struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
742  const char *status = "FAILURE";
743  struct dsn *dsn = NULL;
744 
745  if (!sql || !colnames) {
746  if (chan) {
747  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
748  }
749  return -1;
750  }
751 
752  ast_str_reset(colnames);
753 
755  AST_RWLIST_TRAVERSE(&queries, query, list) {
756  if (!strcmp(query->acf->name, cmd)) {
757  break;
758  }
759  }
760 
761  if (!query) {
762  ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
764  if (chan) {
765  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
766  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
767  }
768  return -1;
769  }
770 
772  if (args.argc < query->minargs) {
773  ast_log(LOG_ERROR, "%d arguments supplied to '%s' requiring minimum %d\n",
774  args.argc, cmd, query->minargs);
776  return -1;
777  }
778 
779  if (!chan) {
780  if (!(chan = ast_dummy_channel_alloc())) {
782  return -1;
783  }
784  bogus_chan = 1;
785  }
786 
787  if (!bogus_chan) {
788  ast_autoservice_start(chan);
789  }
790 
791  snprintf(varname, sizeof(varname), "%u", args.argc);
792  pbx_builtin_pushvar_helper(chan, "ARGC", varname);
793  for (x = 0; x < args.argc; x++) {
794  snprintf(varname, sizeof(varname), "ARG%d", x + 1);
795  pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
796  }
797 
798  ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
799 
800  if (bogus_chan) {
801  chan = ast_channel_unref(chan);
802  } else {
803  /* Restore prior values */
804  pbx_builtin_setvar_helper(chan, "ARGC", NULL);
805 
806  for (x = 0; x < args.argc; x++) {
807  snprintf(varname, sizeof(varname), "ARG%d", x + 1);
808  pbx_builtin_setvar_helper(chan, varname, NULL);
809  }
810  }
811 
812  /* Save these flags, so we can release the lock */
813  escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
814  if (!bogus_chan && ast_test_flag(query, OPT_MULTIROW)) {
815  if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
816  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
817  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
819  ast_autoservice_stop(chan);
820  return -1;
821  }
822  AST_LIST_HEAD_INIT(resultset);
823  if (query->rowlimit) {
824  rowlimit = query->rowlimit;
825  } else {
826  rowlimit = INT_MAX;
827  }
828  multirow = 1;
829  } else if (!bogus_chan) {
830  if (query->rowlimit > 1) {
831  rowlimit = query->rowlimit;
832  if (!(resultset = ast_calloc(1, sizeof(*resultset)))) {
833  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
834  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
836  ast_autoservice_stop(chan);
837  return -1;
838  }
839  AST_LIST_HEAD_INIT(resultset);
840  }
841  }
843 
844  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
845  if (!ast_strlen_zero(query->readhandle[dsn_num])) {
846  obj = get_odbc_obj(query->readhandle[dsn_num], &dsn);
847  if (!obj) {
848  continue;
849  }
851  }
852  if (stmt) {
853  break;
854  }
855  release_obj_or_dsn (&obj, &dsn);
856  }
857 
858  if (!stmt) {
859  ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql));
860  release_obj_or_dsn (&obj, &dsn);
861  if (!bogus_chan) {
862  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
863  ast_autoservice_stop(chan);
864  }
865  odbc_datastore_free(resultset);
866  return -1;
867  }
868 
869  res = SQLNumResultCols(stmt, &colcount);
870  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
871  ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
872  SQLCloseCursor(stmt);
873  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
874  release_obj_or_dsn (&obj, &dsn);
875  if (!bogus_chan) {
876  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
877  ast_autoservice_stop(chan);
878  }
879  odbc_datastore_free(resultset);
880  return -1;
881  }
882 
883  if (colcount <= 0) {
884  ast_verb(4, "Returned %d columns [%s]\n", colcount, ast_str_buffer(sql));
885  buf[0] = '\0';
886  SQLCloseCursor(stmt);
887  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
888  release_obj_or_dsn (&obj, &dsn);
889  if (!bogus_chan) {
890  pbx_builtin_setvar_helper(chan, "ODBCROWS", "0");
891  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "NODATA");
892  ast_autoservice_stop(chan);
893  }
894  odbc_datastore_free(resultset);
895  return 0;
896  }
897 
898  res = SQLFetch(stmt);
899  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
900  int res1 = -1;
901  if (res == SQL_NO_DATA) {
902  ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql));
903  res1 = 0;
904  buf[0] = '\0';
905  ast_copy_string(rowcount, "0", sizeof(rowcount));
906  status = "NODATA";
907  } else {
908  ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
909  status = "FETCHERROR";
910  }
911  SQLCloseCursor(stmt);
912  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
913  release_obj_or_dsn (&obj, &dsn);
914  if (!bogus_chan) {
915  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
916  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
917  ast_autoservice_stop(chan);
918  }
919  odbc_datastore_free(resultset);
920  return res1;
921  }
922 
923  status = "SUCCESS";
924 
925  for (y = 0; y < rowlimit; y++) {
926  buf[0] = '\0';
927  for (x = 0; x < colcount; x++) {
928  int i;
929  struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
930  char *ptrcoldata;
931 
932  if (!coldata) {
933  odbc_datastore_free(resultset);
934  SQLCloseCursor(stmt);
935  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
936  release_obj_or_dsn (&obj, &dsn);
937  if (!bogus_chan) {
938  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
939  ast_autoservice_stop(chan);
940  }
941  return -1;
942  }
943 
944  if (y == 0) {
945  char colname[256];
946  SQLLEN octetlength = 0;
947 
948  res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL);
949  ast_debug(3, "Got collength of %d for column '%s' (offset %d)\n", (int)collength, colname, x);
950  if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
951  snprintf(colname, sizeof(colname), "field%d", x);
952  }
953 
954  SQLColAttribute(stmt, x + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &octetlength);
955 
956  ast_str_make_space(&coldata, octetlength + 1);
957 
958  if (ast_str_strlen(colnames)) {
959  ast_str_append(&colnames, 0, ",");
960  }
961  ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname));
962 
963  if (resultset) {
964  void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1);
965  if (!tmp) {
966  ast_log(LOG_ERROR, "No space for a new resultset?\n");
967  odbc_datastore_free(resultset);
968  SQLCloseCursor(stmt);
969  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
970  release_obj_or_dsn (&obj, &dsn);
971  if (!bogus_chan) {
972  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
973  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
974  ast_autoservice_stop(chan);
975  }
976  return -1;
977  }
978  resultset = tmp;
979  strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames));
980  }
981  }
982 
983  buflen = strlen(buf);
984  res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator);
985  if (indicator == SQL_NULL_DATA) {
986  ast_debug(3, "Got NULL data\n");
987  ast_str_reset(coldata);
988  res = SQL_SUCCESS;
989  }
990 
991  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
992  ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql));
993  y = -1;
994  buf[0] = '\0';
995  goto end_acf_read;
996  }
997 
998  ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata));
999 
1000  if (x) {
1001  buf[buflen++] = ',';
1002  }
1003 
1004  /* Copy data, encoding '\' and ',' for the argument parser */
1005  ptrcoldata = ast_str_buffer(coldata);
1006  for (i = 0; i < ast_str_strlen(coldata); i++) {
1007  if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) {
1008  buf[buflen++] = '\\';
1009  }
1010  buf[buflen++] = ptrcoldata[i];
1011 
1012  if (buflen >= len - 2) {
1013  break;
1014  }
1015 
1016  if (ptrcoldata[i] == '\0') {
1017  break;
1018  }
1019  }
1020 
1021  buf[buflen] = '\0';
1022  ast_debug(2, "buf is now set to '%s'\n", buf);
1023  }
1024  ast_debug(2, "buf is now set to '%s'\n", buf);
1025 
1026  if (resultset) {
1027  row = ast_calloc(1, sizeof(*row) + buflen + 1);
1028  if (!row) {
1029  ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n");
1030  status = "MEMERROR";
1031  goto end_acf_read;
1032  }
1033  strcpy((char *)row + sizeof(*row), buf);
1034  AST_LIST_INSERT_TAIL(resultset, row, list);
1035 
1036  /* Get next row */
1037  res = SQLFetch(stmt);
1038  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1039  if (res != SQL_NO_DATA) {
1040  ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1041  }
1042  /* Number of rows in the resultset */
1043  y++;
1044  break;
1045  }
1046  }
1047  }
1048 
1049 end_acf_read:
1050  if (!bogus_chan) {
1051  snprintf(rowcount, sizeof(rowcount), "%d", y);
1052  pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount);
1053  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
1054  pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames));
1055  if (resultset) {
1056  struct ast_datastore *odbc_store;
1057  if (multirow) {
1058  int uid;
1059  uid = ast_atomic_fetchadd_int(&resultcount, +1) + 1;
1060  snprintf(buf, len, "%d", uid);
1061  } else {
1062  /* Name of the query is name of the resultset */
1063  ast_copy_string(buf, cmd, len);
1064 
1065  /* If there's one with the same name already, free it */
1066  ast_channel_lock(chan);
1067  if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) {
1068  ast_channel_datastore_remove(chan, odbc_store);
1069  ast_datastore_free(odbc_store);
1070  }
1071  ast_channel_unlock(chan);
1072  }
1073  odbc_store = ast_datastore_alloc(&odbc_info, buf);
1074  if (!odbc_store) {
1075  ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n");
1076  odbc_datastore_free(resultset);
1077  SQLCloseCursor(stmt);
1078  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1079  release_obj_or_dsn (&obj, &dsn);
1080  pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR");
1081  ast_autoservice_stop(chan);
1082  return -1;
1083  }
1084  odbc_store->data = resultset;
1085  ast_channel_lock(chan);
1086  ast_channel_datastore_add(chan, odbc_store);
1087  ast_channel_unlock(chan);
1088  }
1089  }
1090  SQLCloseCursor(stmt);
1091  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1092  release_obj_or_dsn (&obj, &dsn);
1093  if (resultset && !multirow) {
1094  /* Fetch the first resultset */
1095  if (!acf_fetch(chan, "", buf, buf, len)) {
1096  buf[0] = '\0';
1097  }
1098  }
1099  if (!bogus_chan) {
1100  ast_autoservice_stop(chan);
1101  }
1102  return 0;
1103 }
1104 
1105 static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1106 {
1107  char *out = buf;
1108 
1109  for (; *data && out - buf < len; data++) {
1110  if (*data == '\'') {
1111  *out = '\'';
1112  out++;
1113  }
1114  *out++ = *data;
1115  }
1116  *out = '\0';
1117 
1118  return 0;
1119 }
1120 
1122  .name = "SQL_ESC",
1123  .read = acf_escape,
1124  .write = NULL,
1125 };
1126 
1127 static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1128 {
1129  struct ast_datastore *store;
1130  struct odbc_datastore *resultset;
1131  struct odbc_datastore_row *row;
1132 
1133  if (!chan) {
1134  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1135  return -1;
1136  }
1137 
1138  ast_channel_lock(chan);
1139  store = ast_channel_datastore_find(chan, &odbc_info, data);
1140  if (!store) {
1141  ast_channel_unlock(chan);
1142  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
1143  return -1;
1144  }
1145  resultset = store->data;
1146  AST_LIST_LOCK(resultset);
1147  row = AST_LIST_REMOVE_HEAD(resultset, list);
1148  AST_LIST_UNLOCK(resultset);
1149  if (!row) {
1150  /* Cleanup datastore */
1151  ast_channel_datastore_remove(chan, store);
1152  ast_datastore_free(store);
1153  ast_channel_unlock(chan);
1154  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
1155  return -1;
1156  }
1157  pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
1158  ast_channel_unlock(chan);
1159  ast_copy_string(buf, row->data, len);
1160  ast_free(row);
1161  pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
1162  return 0;
1163 }
1164 
1166  .name = "ODBC_FETCH",
1167  .read = acf_fetch,
1168  .write = NULL,
1169 };
1170 
1171 static char *app_odbcfinish = "ODBCFinish";
1172 
1173 static int exec_odbcfinish(struct ast_channel *chan, const char *data)
1174 {
1175  struct ast_datastore *store;
1176 
1177  ast_channel_lock(chan);
1178  store = ast_channel_datastore_find(chan, &odbc_info, data);
1179  if (store) {
1180  ast_channel_datastore_remove(chan, store);
1181  ast_datastore_free(store);
1182  }
1183  ast_channel_unlock(chan);
1184  return 0;
1185 }
1186 
1187 static int free_acf_query(struct acf_odbc_query *query)
1188 {
1189  if (query) {
1190  if (query->acf) {
1191  if (query->acf->name)
1192  ast_free((char *)query->acf->name);
1193  ast_string_field_free_memory(query->acf);
1194  ast_free(query->acf);
1195  }
1196  ast_free(query->sql_read);
1197  ast_free(query->sql_write);
1198  ast_free(query->sql_insert);
1199  ast_free(query);
1200  }
1201  return 0;
1202 }
1203 
1204 static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
1205 {
1206  const char *tmp;
1207  const char *tmp2 = NULL;
1208  int i;
1209 
1210  if (!cfg || !catg) {
1211  return EINVAL;
1212  }
1213 
1214  if (!(*query = ast_calloc(1, sizeof(**query)))) {
1215  return ENOMEM;
1216  }
1217 
1218  if (((tmp = ast_variable_retrieve(cfg, catg, "writehandle"))) || ((tmp = ast_variable_retrieve(cfg, catg, "dsn")))) {
1219  char *tmp2 = ast_strdupa(tmp);
1220  AST_DECLARE_APP_ARGS(writeconf,
1221  AST_APP_ARG(dsn)[5];
1222  );
1223  AST_STANDARD_APP_ARGS(writeconf, tmp2);
1224  for (i = 0; i < 5; i++) {
1225  if (!ast_strlen_zero(writeconf.dsn[i]))
1226  ast_copy_string((*query)->writehandle[i], writeconf.dsn[i], sizeof((*query)->writehandle[i]));
1227  }
1228  }
1229 
1230  if ((tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
1231  char *tmp2 = ast_strdupa(tmp);
1232  AST_DECLARE_APP_ARGS(readconf,
1233  AST_APP_ARG(dsn)[5];
1234  );
1235  AST_STANDARD_APP_ARGS(readconf, tmp2);
1236  for (i = 0; i < 5; i++) {
1237  if (!ast_strlen_zero(readconf.dsn[i]))
1238  ast_copy_string((*query)->readhandle[i], readconf.dsn[i], sizeof((*query)->readhandle[i]));
1239  }
1240  } else {
1241  /* If no separate readhandle, then use the writehandle for reading */
1242  for (i = 0; i < 5; i++) {
1243  if (!ast_strlen_zero((*query)->writehandle[i]))
1244  ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i], sizeof((*query)->readhandle[i]));
1245  }
1246  }
1247 
1248  if ((tmp = ast_variable_retrieve(cfg, catg, "readsql")) ||
1249  (tmp2 = ast_variable_retrieve(cfg, catg, "read"))) {
1250  if (!tmp) {
1251  ast_log(LOG_WARNING, "Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg);
1252  tmp = tmp2;
1253  }
1254  if (*tmp != '\0') { /* non-empty string */
1255  if (!((*query)->sql_read = ast_strdup(tmp))) {
1256  free_acf_query(*query);
1257  *query = NULL;
1258  return ENOMEM;
1259  }
1260  }
1261  }
1262 
1263  if ((*query)->sql_read && ast_strlen_zero((*query)->readhandle[0])) {
1264  free_acf_query(*query);
1265  *query = NULL;
1266  ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for reading: %s\n", catg);
1267  return EINVAL;
1268  }
1269 
1270  if ((tmp = ast_variable_retrieve(cfg, catg, "writesql")) ||
1271  (tmp2 = ast_variable_retrieve(cfg, catg, "write"))) {
1272  if (!tmp) {
1273  ast_log(LOG_WARNING, "Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg);
1274  tmp = tmp2;
1275  }
1276  if (*tmp != '\0') { /* non-empty string */
1277  if (!((*query)->sql_write = ast_strdup(tmp))) {
1278  free_acf_query(*query);
1279  *query = NULL;
1280  return ENOMEM;
1281  }
1282  }
1283  }
1284 
1285  if ((*query)->sql_write && ast_strlen_zero((*query)->writehandle[0])) {
1286  free_acf_query(*query);
1287  *query = NULL;
1288  ast_log(LOG_ERROR, "There is SQL, but no ODBC class to be used for writing: %s\n", catg);
1289  return EINVAL;
1290  }
1291 
1292  if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) {
1293  if (*tmp != '\0') { /* non-empty string */
1294  if (!((*query)->sql_insert = ast_strdup(tmp))) {
1295  free_acf_query(*query);
1296  *query = NULL;
1297  return ENOMEM;
1298  }
1299  }
1300  }
1301 
1302  /* Allow escaping of embedded commas in fields to be turned off */
1303  ast_set_flag((*query), OPT_ESCAPECOMMAS);
1304  if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
1305  if (ast_false(tmp))
1306  ast_clear_flag((*query), OPT_ESCAPECOMMAS);
1307  }
1308 
1309  if ((tmp = ast_variable_retrieve(cfg, catg, "mode"))) {
1310  if (strcasecmp(tmp, "multirow") == 0)
1311  ast_set_flag((*query), OPT_MULTIROW);
1312  if ((tmp = ast_variable_retrieve(cfg, catg, "rowlimit")))
1313  sscanf(tmp, "%30d", &((*query)->rowlimit));
1314  }
1315 
1316  if ((tmp = ast_variable_retrieve(cfg, catg, "minargs"))) {
1317  sscanf(tmp, "%30d", &((*query)->minargs));
1318  }
1319 
1320  (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
1321  if (!(*query)->acf) {
1322  free_acf_query(*query);
1323  *query = NULL;
1324  return ENOMEM;
1325  }
1326  if (ast_string_field_init((*query)->acf, 128)) {
1327  free_acf_query(*query);
1328  *query = NULL;
1329  return ENOMEM;
1330  }
1331 
1332  if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
1333  if (ast_asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
1334  (*query)->acf->name = NULL;
1335  }
1336  } else {
1337  if (ast_asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
1338  (*query)->acf->name = NULL;
1339  }
1340  }
1341 
1342  if (!(*query)->acf->name) {
1343  free_acf_query(*query);
1344  *query = NULL;
1345  return ENOMEM;
1346  }
1347 
1348  if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) {
1349  ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp);
1350  } else {
1351  ast_string_field_build((*query)->acf, syntax, "%s(<arg1>[...[,<argN>]])", (*query)->acf->name);
1352  }
1353 
1354  if (ast_strlen_zero((*query)->acf->syntax)) {
1355  free_acf_query(*query);
1356  *query = NULL;
1357  return ENOMEM;
1358  }
1359 
1360  if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) {
1361  ast_string_field_set((*query)->acf, synopsis, tmp);
1362  } else {
1363  ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments");
1364  }
1365 
1366  if (ast_strlen_zero((*query)->acf->synopsis)) {
1367  free_acf_query(*query);
1368  *query = NULL;
1369  return ENOMEM;
1370  }
1371 
1372  if ((*query)->sql_read && (*query)->sql_write) {
1373  ast_string_field_build((*query)->acf, desc,
1374  "Runs the following query, as defined in func_odbc.conf, performing\n"
1375  "substitution of the arguments into the query as specified by ${ARG1},\n"
1376  "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n"
1377  "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1378  "%s"
1379  "\nRead:\n%s\n\nWrite:\n%s%s%s",
1380  (*query)->sql_insert ?
1381  "If the write query affects no rows, the insert query will be\n"
1382  "performed.\n" : "",
1383  (*query)->sql_read,
1384  (*query)->sql_write,
1385  (*query)->sql_insert ? "\n\nInsert:\n" : "",
1386  (*query)->sql_insert ? (*query)->sql_insert : "");
1387  } else if ((*query)->sql_read) {
1388  ast_string_field_build((*query)->acf, desc,
1389  "Runs the following query, as defined in func_odbc.conf, performing\n"
1390  "substitution of the arguments into the query as specified by ${ARG1},\n"
1391  "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s",
1392  (*query)->sql_read);
1393  } else if ((*query)->sql_write) {
1394  ast_string_field_build((*query)->acf, desc,
1395  "Runs the following query, as defined in func_odbc.conf, performing\n"
1396  "substitution of the arguments into the query as specified by ${ARG1},\n"
1397  "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n"
1398  "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1399  "This function may only be set.\n%s\nSQL:\n%s%s%s",
1400  (*query)->sql_insert ?
1401  "If the write query affects no rows, the insert query will be\n"
1402  "performed.\n" : "",
1403  (*query)->sql_write,
1404  (*query)->sql_insert ? "\n\nInsert:\n" : "",
1405  (*query)->sql_insert ? (*query)->sql_insert : "");
1406  } else {
1407  free_acf_query(*query);
1408  *query = NULL;
1409  ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute. Ignoring.\n", catg);
1410  return EINVAL;
1411  }
1412 
1413  if (ast_strlen_zero((*query)->acf->desc)) {
1414  free_acf_query(*query);
1415  *query = NULL;
1416  return ENOMEM;
1417  }
1418 
1419  if ((*query)->sql_read) {
1420  (*query)->acf->read = acf_odbc_read;
1421  }
1422 
1423  if ((*query)->sql_write) {
1424  (*query)->acf->write = acf_odbc_write;
1425  }
1426 
1427  return 0;
1428 }
1429 
1430 static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1431 {
1433  AST_APP_ARG(field)[100];
1434  );
1435  struct ast_str *sql;
1436  char *char_args, varname[15];
1437  struct acf_odbc_query *query;
1438  struct ast_channel *chan;
1439  int i;
1440 
1441  switch (cmd) {
1442  case CLI_INIT:
1443  e->command = "odbc read";
1444  e->usage =
1445  "Usage: odbc read <name> <args> [exec]\n"
1446  " Evaluates the SQL provided in the ODBC function <name>, and\n"
1447  " optionally executes the function. This function is intended for\n"
1448  " testing purposes. Remember to quote arguments containing spaces.\n";
1449  return NULL;
1450  case CLI_GENERATE:
1451  if (a->pos == 2) {
1452  int wordlen = strlen(a->word), which = 0;
1453  /* Complete function name */
1455  AST_RWLIST_TRAVERSE(&queries, query, list) {
1456  if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1457  if (++which > a->n) {
1458  char *res = ast_strdup(query->acf->name);
1460  return res;
1461  }
1462  }
1463  }
1465  return NULL;
1466  } else if (a->pos == 4) {
1467  static const char * const completions[] = { "exec", NULL };
1468  return ast_cli_complete(a->word, completions, a->n);
1469  } else {
1470  return NULL;
1471  }
1472  }
1473 
1474  if (a->argc < 4 || a->argc > 5) {
1475  return CLI_SHOWUSAGE;
1476  }
1477 
1478  sql = ast_str_thread_get(&sql_buf, 16);
1479  if (!sql) {
1480  return CLI_FAILURE;
1481  }
1482 
1484  AST_RWLIST_TRAVERSE(&queries, query, list) {
1485  if (!strcmp(query->acf->name, a->argv[2])) {
1486  break;
1487  }
1488  }
1489 
1490  if (!query) {
1491  ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1493  return CLI_SHOWUSAGE;
1494  }
1495 
1496  if (!query->sql_read) {
1497  ast_cli(a->fd, "The function %s has no readsql parameter.\n", a->argv[2]);
1499  return CLI_SUCCESS;
1500  }
1501 
1502  ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300);
1503 
1504  /* Evaluate function */
1505  char_args = ast_strdupa(a->argv[3]);
1506 
1507  chan = ast_dummy_channel_alloc();
1508  if (!chan) {
1510  return CLI_FAILURE;
1511  }
1512 
1513  AST_STANDARD_APP_ARGS(args, char_args);
1514  for (i = 0; i < args.argc; i++) {
1515  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1516  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1517  }
1518 
1519  ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
1520  chan = ast_channel_unref(chan);
1521 
1522  if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
1523  /* Execute the query */
1524  struct odbc_obj *obj = NULL;
1525  struct dsn *dsn = NULL;
1526  int dsn_num, executed = 0;
1527  SQLHSTMT stmt;
1528  int rows = 0, res, x;
1529  SQLSMALLINT colcount = 0, collength;
1530  SQLLEN indicator, octetlength;
1531  struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16);
1532  char colname[256];
1533 
1534  if (!coldata) {
1536  return CLI_SUCCESS;
1537  }
1538 
1539  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
1540  if (ast_strlen_zero(query->readhandle[dsn_num])) {
1541  continue;
1542  }
1543  obj = get_odbc_obj(query->readhandle[dsn_num], &dsn);
1544  if (!obj) {
1545  continue;
1546  }
1547  ast_debug(1, "Found handle %s\n", query->readhandle[dsn_num]);
1548 
1549  if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
1550  release_obj_or_dsn (&obj, &dsn);
1551  continue;
1552  }
1553 
1554  executed = 1;
1555 
1556  res = SQLNumResultCols(stmt, &colcount);
1557  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1558  ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql));
1559  SQLCloseCursor(stmt);
1560  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1561  release_obj_or_dsn (&obj, &dsn);
1563  return CLI_SUCCESS;
1564  }
1565 
1566  if (colcount <= 0) {
1567  SQLCloseCursor(stmt);
1568  SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1569  release_obj_or_dsn (&obj, &dsn);
1570  ast_cli(a->fd, "Returned %d columns. Query executed on handle %d:%s [%s]\n", colcount, dsn_num, query->readhandle[dsn_num], ast_str_buffer(sql));
1572  return CLI_SUCCESS;
1573  }
1574 
1575  res = SQLFetch(stmt);
1576  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1577  SQLCloseCursor(stmt);
1578  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1579  release_obj_or_dsn (&obj, &dsn);
1580  if (res == SQL_NO_DATA) {
1581  ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn_num, query->readhandle[dsn_num], ast_str_buffer(sql));
1582  break;
1583  } else {
1584  ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql));
1585  }
1587  return CLI_SUCCESS;
1588  }
1589  for (;;) {
1590  for (x = 0; x < colcount; x++) {
1591  res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, NULL, NULL, NULL);
1592  if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
1593  snprintf(colname, sizeof(colname), "field%d", x);
1594  }
1595 
1596  octetlength = 0;
1597  SQLColAttribute(stmt, x + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &octetlength);
1598 
1599  res = ast_odbc_ast_str_SQLGetData(&coldata, octetlength + 1, stmt, x + 1, SQL_CHAR, &indicator);
1600  if (indicator == SQL_NULL_DATA) {
1601  ast_str_set(&coldata, 0, "(nil)");
1602  res = SQL_SUCCESS;
1603  }
1604 
1605  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1606  ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql));
1607  SQLCloseCursor(stmt);
1608  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1609  release_obj_or_dsn (&obj, &dsn);
1611  return CLI_SUCCESS;
1612  }
1613 
1614  ast_cli(a->fd, "%-20.20s %s\n", colname, ast_str_buffer(coldata));
1615  }
1616  rows++;
1617 
1618  /* Get next row */
1619  res = SQLFetch(stmt);
1620  if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1621  break;
1622  }
1623  ast_cli(a->fd, "%-20.20s %s\n", "----------", "----------");
1624  }
1625  SQLCloseCursor(stmt);
1626  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1627  release_obj_or_dsn (&obj, &dsn);
1628  ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn_num, query->readhandle[dsn_num]);
1629  break;
1630  }
1631  release_obj_or_dsn (&obj, &dsn);
1632 
1633  if (!executed) {
1634  ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql));
1635  }
1636  } else { /* No execution, just print out the resulting SQL */
1637  ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1638  }
1640  return CLI_SUCCESS;
1641 }
1642 
1643 static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1644 {
1646  AST_APP_ARG(field)[100];
1647  );
1649  AST_APP_ARG(field)[100];
1650  );
1651  struct ast_str *sql;
1652  char *char_args, *char_values, varname[15];
1653  struct acf_odbc_query *query;
1654  struct ast_channel *chan;
1655  int i;
1656 
1657  switch (cmd) {
1658  case CLI_INIT:
1659  e->command = "odbc write";
1660  e->usage =
1661  "Usage: odbc write <name> <args> <value> [exec]\n"
1662  " Evaluates the SQL provided in the ODBC function <name>, and\n"
1663  " optionally executes the function. This function is intended for\n"
1664  " testing purposes. Remember to quote arguments containing spaces.\n";
1665  return NULL;
1666  case CLI_GENERATE:
1667  if (a->pos == 2) {
1668  int wordlen = strlen(a->word), which = 0;
1669  /* Complete function name */
1671  AST_RWLIST_TRAVERSE(&queries, query, list) {
1672  if (!strncasecmp(query->acf->name, a->word, wordlen)) {
1673  if (++which > a->n) {
1674  char *res = ast_strdup(query->acf->name);
1676  return res;
1677  }
1678  }
1679  }
1681  return NULL;
1682  } else if (a->pos == 5) {
1683  static const char * const completions[] = { "exec", NULL };
1684  return ast_cli_complete(a->word, completions, a->n);
1685  } else {
1686  return NULL;
1687  }
1688  }
1689 
1690  if (a->argc < 5 || a->argc > 6) {
1691  return CLI_SHOWUSAGE;
1692  }
1693 
1694  sql = ast_str_thread_get(&sql_buf, 16);
1695  if (!sql) {
1696  return CLI_FAILURE;
1697  }
1698 
1700  AST_RWLIST_TRAVERSE(&queries, query, list) {
1701  if (!strcmp(query->acf->name, a->argv[2])) {
1702  break;
1703  }
1704  }
1705 
1706  if (!query) {
1707  ast_cli(a->fd, "No such query '%s'\n", a->argv[2]);
1709  return CLI_SHOWUSAGE;
1710  }
1711 
1712  if (!query->sql_write) {
1713  ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]);
1715  return CLI_SUCCESS;
1716  }
1717 
1718  /* FIXME: The code below duplicates code found in acf_odbc_write but
1719  * lacks the newer sql_insert additions. */
1720 
1721  ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300);
1722 
1723  /* Evaluate function */
1724  char_args = ast_strdupa(a->argv[3]);
1725  char_values = ast_strdupa(a->argv[4]);
1726 
1727  chan = ast_dummy_channel_alloc();
1728  if (!chan) {
1730  return CLI_FAILURE;
1731  }
1732 
1733  AST_STANDARD_APP_ARGS(args, char_args);
1734  for (i = 0; i < args.argc; i++) {
1735  snprintf(varname, sizeof(varname), "ARG%d", i + 1);
1736  pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
1737  }
1738 
1739  /* Parse values, just like arguments */
1740  AST_STANDARD_APP_ARGS(values, char_values);
1741  for (i = 0; i < values.argc; i++) {
1742  snprintf(varname, sizeof(varname), "VAL%d", i + 1);
1743  pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
1744  }
1745 
1746  /* Additionally set the value as a whole (but push an empty string if value is NULL) */
1747  pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], ""));
1748  ast_str_substitute_variables(&sql, 0, chan, query->sql_write);
1749  ast_debug(1, "SQL is %s\n", ast_str_buffer(sql));
1750 
1751  chan = ast_channel_unref(chan);
1752 
1753  if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
1754  /* Execute the query */
1755  struct odbc_obj *obj = NULL;
1756  struct dsn *dsn = NULL;
1757  int dsn_num, executed = 0;
1758  SQLHSTMT stmt;
1759  SQLLEN rows = -1;
1760 
1761  for (dsn_num = 0; dsn_num < 5; dsn_num++) {
1762  if (ast_strlen_zero(query->writehandle[dsn_num])) {
1763  continue;
1764  }
1765  obj = get_odbc_obj(query->writehandle[dsn_num], &dsn);
1766  if (!obj) {
1767  continue;
1768  }
1769  if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) {
1770  release_obj_or_dsn (&obj, &dsn);
1771  continue;
1772  }
1773 
1774  SQLRowCount(stmt, &rows);
1775  SQLCloseCursor(stmt);
1776  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1777  release_obj_or_dsn (&obj, &dsn);
1778  ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn_num, query->writehandle[dsn_num]);
1779  executed = 1;
1780  break;
1781  }
1782 
1783  if (!executed) {
1784  ast_cli(a->fd, "Failed to execute query.\n");
1785  }
1786  } else { /* No execution, just print out the resulting SQL */
1787  ast_cli(a->fd, "%s\n", ast_str_buffer(sql));
1788  }
1790  return CLI_SUCCESS;
1791 }
1792 
1793 static struct ast_cli_entry cli_func_odbc[] = {
1794  AST_CLI_DEFINE(cli_odbc_write, "Test setting a func_odbc function"),
1795  AST_CLI_DEFINE(cli_odbc_read, "Test reading a func_odbc function"),
1796 };
1797 
1798 static int load_module(void)
1799 {
1800  int res = 0;
1801  struct ast_config *cfg;
1802  char *catg;
1803  const char *s;
1804  struct ast_flags config_flags = { 0 };
1805 
1806  res |= ast_custom_function_register(&fetch_function);
1807  res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish);
1808 
1809  cfg = ast_config_load(config, config_flags);
1810  if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1811  ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
1812  return AST_MODULE_LOAD_DECLINE;
1813  }
1814 
1816  if ((s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) {
1818  } else {
1820  }
1821 
1822  dsns = NULL;
1823 
1824  if (single_db_connection) {
1826  dsn_hash, NULL, dsn_cmp);
1827  if (!dsns) {
1828  ast_log(LOG_ERROR, "Could not initialize DSN container\n");
1830  return AST_MODULE_LOAD_DECLINE;
1831  }
1832  }
1834 
1836  for (catg = ast_category_browse(cfg, NULL);
1837  catg;
1838  catg = ast_category_browse(cfg, catg)) {
1839  struct acf_odbc_query *query = NULL;
1840  int err;
1841 
1842  if (!strcasecmp(catg, "general")) {
1843  continue;
1844  }
1845 
1846  if ((err = init_acf_query(cfg, catg, &query))) {
1847  if (err == ENOMEM)
1848  ast_log(LOG_ERROR, "Out of memory\n");
1849  else if (err == EINVAL)
1850  ast_log(LOG_ERROR, "Invalid parameters for category %s\n", catg);
1851  else
1852  ast_log(LOG_ERROR, "%s (%d)\n", strerror(err), err);
1853  } else {
1854  AST_RWLIST_INSERT_HEAD(&queries, query, list);
1855  ast_custom_function_register(query->acf);
1856  }
1857  }
1858 
1859  ast_config_destroy(cfg);
1860  res |= ast_custom_function_register(&escape_function);
1861  ast_cli_register_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
1862 
1864  return res;
1865 }
1866 
1867 static int unload_module(void)
1868 {
1869  struct acf_odbc_query *query;
1870  int res = 0;
1871 
1873  while (!AST_RWLIST_EMPTY(&queries)) {
1874  query = AST_RWLIST_REMOVE_HEAD(&queries, list);
1875  ast_custom_function_unregister(query->acf);
1876  free_acf_query(query);
1877  }
1878 
1879  res |= ast_custom_function_unregister(&escape_function);
1880  res |= ast_custom_function_unregister(&fetch_function);
1881  res |= ast_unregister_application(app_odbcfinish);
1882  ast_cli_unregister_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc));
1883 
1884  /* Allow any threads waiting for this lock to pass (avoids a race) */
1886  usleep(1);
1888 
1890 
1891  if (dsns) {
1892  ao2_ref(dsns, -1);
1893  }
1894  return res;
1895 }
1896 
1897 static int reload(void)
1898 {
1899  int res = 0;
1900  struct ast_config *cfg;
1901  struct acf_odbc_query *oldquery;
1902  char *catg;
1903  const char *s;
1904  struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
1905 
1906  cfg = ast_config_load(config, config_flags);
1908  return 0;
1909 
1911 
1912  if (dsns) {
1913  ao2_ref(dsns, -1);
1914  dsns = NULL;
1915  }
1916 
1917  if (cfg && (s = ast_variable_retrieve(cfg, "general", "single_db_connection"))) {
1919  } else {
1921  }
1922 
1923  if (single_db_connection) {
1925  dsn_hash, NULL, dsn_cmp);
1926  if (!dsns) {
1927  ast_log(LOG_ERROR, "Could not initialize DSN container\n");
1929  return 0;
1930  }
1931  }
1933 
1935 
1936  while (!AST_RWLIST_EMPTY(&queries)) {
1937  oldquery = AST_RWLIST_REMOVE_HEAD(&queries, list);
1938  ast_custom_function_unregister(oldquery->acf);
1939  free_acf_query(oldquery);
1940  }
1941 
1942  if (!cfg) {
1943  ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
1944  goto reload_out;
1945  }
1946 
1947  for (catg = ast_category_browse(cfg, NULL);
1948  catg;
1949  catg = ast_category_browse(cfg, catg)) {
1950  struct acf_odbc_query *query = NULL;
1951 
1952  if (!strcasecmp(catg, "general")) {
1953  continue;
1954  }
1955 
1956  if (init_acf_query(cfg, catg, &query)) {
1957  ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
1958  } else {
1959  AST_RWLIST_INSERT_HEAD(&queries, query, list);
1960  ast_custom_function_register(query->acf);
1961  }
1962  }
1963 
1964  ast_config_destroy(cfg);
1965 reload_out:
1967  return res;
1968 }
1969 
1970 /* XXX need to revise usecount - set if query_lock is set */
1971 
1973  .support_level = AST_MODULE_SUPPORT_CORE,
1974  .load = load_module,
1975  .unload = unload_module,
1976  .reload = reload,
1977  .requires = "res_odbc",
1978 );
const char * name
Definition: pbx.h:119
const char * type
Definition: datastore.h:32
SQLHDBC con
Definition: res_odbc.h:47
static const char synopsis[]
Definition: app_mysql.c:64
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:84
#define ast_rwlock_rdlock(a)
Definition: lock.h:233
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
Asterisk main include file. File version handling, generic pbx functions.
#define ast_realloc(p, len)
A wrapper for realloc()
Definition: astmm.h:228
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:541
static char * app_odbcfinish
Definition: func_odbc.c:1171
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
Common execution function for SQL queries.
Definition: func_odbc.c:454
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
String manipulation functions.
static struct ast_custom_function fetch_function
Definition: func_odbc.c:1165
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
#define ast_test_flag(p, flag)
Definition: utils.h:63
static SQLHSTMT silent_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:501
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static int indicator
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static int unload_module(void)
Definition: func_odbc.c:1867
#define DSN_BUCKETS
Definition: func_odbc.c:157
#define CONFIG_STATUS_FILEINVALID
static int tmp()
Definition: bt_open.c:389
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
static struct ast_threadstorage sql_buf
Definition: func_odbc.c:420
static int exec_odbcfinish(struct ast_channel *chan, const char *data)
Definition: func_odbc.c:1173
Definition: func_odbc.c:150
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
struct odbc_obj * connection
Definition: func_odbc.c:152
Definition: cli.h:152
static const char desc[]
Definition: cdr_mysql.c:73
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
Structure for a data store type.
Definition: datastore.h:31
char * ast_str_append_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string, with escaping of commas...
Definition: strings.h:1028
static int reload(void)
Definition: func_odbc.c:1897
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:1091
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1105
#define ast_assert(a)
Definition: utils.h:695
#define ao2_link_flags(container, obj, flags)
Definition: astobj2.h:1572
#define ao2_unlock(a)
Definition: astobj2.h:730
struct odbc_datastore_row::@212 list
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Structure for a data store object.
Definition: datastore.h:68
#define DEFAULT_SINGLE_DB_CONNECTION
Definition: func_odbc.c:103
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2404
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
const char * args
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value...
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define ast_rwlock_unlock(a)
Definition: lock.h:232
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
Definition: func_odbc.c:496
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_verb(level,...)
Definition: logger.h:463
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
static struct ast_custom_function escape_function
Definition: func_odbc.c:1121
const char * uid
Definition: datastore.h:69
struct odbc_obj * ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname)
Retrieve an ODBC transaction connection with the given ODBC class name.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:652
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition: main/cli.c:1811
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:1065
Configuration File Parser.
unsigned int ast_odbc_get_max_connections(const char *name)
Return the current configured maximum number of connections for a class.
Definition: res_odbc.c:857
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
static int dsn_hash(const void *obj, const int flags)
Definition: func_odbc.c:161
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:717
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
#define ast_config_load(filename, flags)
Load a config file.
static int single_db_connection
Definition: func_odbc.c:105
General Asterisk PBX channel definitions.
ODBC container.
Definition: res_odbc.h:46
static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
Definition: func_odbc.c:509
const int fd
Definition: cli.h:159
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
const int n
Definition: cli.h:165
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
static int load_module(void)
Definition: func_odbc.c:1798
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int resultcount
Definition: func_odbc.c:418
static struct ast_threadstorage coldata_buf
Definition: func_odbc.c:422
static void dsn_destructor(void *obj)
Definition: func_odbc.c:210
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
ODBC resource manager.
static char * cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1430
Core PBX routines and definitions.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
#define CONFIG_STATUS_FILEUNCHANGED
char name[0]
Definition: func_odbc.c:154
const char *const * argv
Definition: cli.h:161
static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
Definition: func_odbc.c:725
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static int connection_dead(struct odbc_obj *connection)
Determine if the connection has died.
Definition: func_odbc.c:265
static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_odbc.c:1127
SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data)
Executes an non prepared statement and returns the resulting statement handle.
Definition: res_odbc.c:369
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define CLI_SHOWUSAGE
Definition: cli.h:45
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
odbc_option_flags
Definition: func_odbc.c:109
static struct ast_threadstorage sql2_buf
Definition: func_odbc.c:421
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define LOG_NOTICE
Definition: logger.h:263
static char * cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: func_odbc.c:1643
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
static void odbc_datastore_free(void *data)
Definition: func_odbc.c:427
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define CLI_FAILURE
Definition: cli.h:46
static const char name[]
Definition: cdr_mysql.c:74
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:625
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define ast_odbc_request_obj(a, b)
Definition: res_odbc.h:122
const char * word
Definition: cli.h:163
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:843
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
static char * dsn
Definition: cdr_odbc.c:58
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:550
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static struct dsn * create_dsn(const char *name)
Create a DSN and connect to the database.
Definition: func_odbc.c:226
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:414
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
const char * usage
Definition: cli.h:177
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
#define ast_rwlock_wrlock(a)
Definition: lock.h:234
static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
Definition: func_odbc.c:1204
SQLRETURN ast_odbc_execute_sql(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Execute a nonprepared SQL query.
Definition: res_odbc.c:478
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:653
#define CLI_SUCCESS
Definition: cli.h:44
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
void * data
Definition: datastore.h:70
static struct ast_cli_entry cli_func_odbc[]
Definition: func_odbc.c:1793
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
FILE * out
Definition: utils/frame.c:33
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char names[0]
Definition: func_odbc.c:143
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
const int pos
Definition: cli.h:164
static struct dsn * get_dsn(const char *name)
Retrieve a DSN, or create it if it does not exist.
Definition: func_odbc.c:305
static PGresult * result
Definition: cel_pgsql.c:88
static int dsn_cmp(void *obj, void *arg, int flags)
Definition: func_odbc.c:181
static void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
Release an ODBC obj or a DSN.
Definition: func_odbc.c:388
SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind)
Wrapper for SQLGetData to use with dynamic strings.
Definition: res_odbc.c:507
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
Generic container type.
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:861
Search option field mask.
Definition: astobj2.h:1076
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
Definition: res_odbc.c:813
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
static char * config
Definition: func_odbc.c:101
Asterisk module definitions.
static struct ast_threadstorage colnames_buf
Definition: func_odbc.c:423
static const struct ast_datastore_info odbc_info
Definition: func_odbc.c:129
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ao2_container * dsns
Definition: func_odbc.c:159
static ast_rwlock_t single_db_connection_lock
Definition: func_odbc.c:107
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
static struct odbc_obj * get_odbc_obj(const char *dsn_name, struct dsn **dsn)
Get a DB handle via a DSN or directly.
Definition: func_odbc.c:359
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
jack_status_t status
Definition: app_jack.c:146
#define AST_APP_ARG(name)
Define an application argument.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
static struct test_val a
static int free_acf_query(struct acf_odbc_query *query)
Definition: func_odbc.c:1187