2 * Asterisk -- A telephony toolkit for Linux.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * res_config_odbc.c <odbc+odbc plugin for portable configuration engine >
9 * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct@yahoo.com>
12 #include "asterisk/file.h"
13 #include "asterisk/logger.h"
14 #include "asterisk/channel.h"
15 #include "asterisk/pbx.h"
16 #include "asterisk/config.h"
17 #include "asterisk/module.h"
18 #include "asterisk/lock.h"
19 #include "asterisk/options.h"
23 #include "asterisk/res_odbc.h"
24 #include "asterisk/utils.h"
26 static char *tdesc = "ODBC Configuration";
31 static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
39 const char *newparam, *newval;
45 struct ast_variable *var=NULL, *prev=NULL;
48 SQLSMALLINT colcount=0;
50 SQLSMALLINT decimaldigits;
61 obj = fetch_odbc_obj(database, 0);
65 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
66 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
67 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
71 newparam = va_arg(aq, const char *);
73 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
76 newval = va_arg(aq, const char *);
77 if (!strchr(newparam, ' ')) op = " ="; else op = "";
78 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?", table, newparam, op);
79 while((newparam = va_arg(aq, const char *))) {
80 if (!strchr(newparam, ' ')) op = " ="; else op = "";
81 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?", newparam, op);
82 newval = va_arg(aq, const char *);
85 res = SQLPrepare(stmt, sql, SQL_NTS);
86 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
87 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
88 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
92 /* Now bind the parameters */
95 while((newparam = va_arg(ap, const char *))) {
96 newval = va_arg(ap, const char *);
97 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
100 res = odbc_smart_execute(obj, stmt);
102 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
103 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
104 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
108 res = SQLRowCount(stmt, &rowcount);
109 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
110 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
111 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
115 res = SQLNumResultCols(stmt, &colcount);
116 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
117 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
118 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
123 res = SQLFetch(stmt);
124 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
125 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
126 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
129 for (x=0;x<colcount;x++) {
131 collen = sizeof(coltitle);
132 res = SQLDescribeCol(stmt, x + 1, coltitle, sizeof(coltitle), &collen,
133 &datatype, &colsize, &decimaldigits, &nullable);
134 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
135 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
137 ast_variables_destroy(var);
142 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
143 if (indicator == SQL_NULL_DATA)
146 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
147 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
149 ast_variables_destroy(var);
154 chunk = strsep(&stringp, ";");
155 if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
157 prev->next = ast_variable_new(coltitle, chunk);
161 prev = var = ast_variable_new(coltitle, chunk);
169 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
173 static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap)
180 const char *initfield=NULL;
182 const char *newparam, *newval;
188 struct ast_variable *var=NULL;
189 struct ast_config *cfg=NULL;
190 struct ast_category *cat=NULL;
191 struct ast_realloca ra;
194 SQLSMALLINT colcount=0;
195 SQLSMALLINT datatype;
196 SQLSMALLINT decimaldigits;
197 SQLSMALLINT nullable;
198 SQLINTEGER indicator;
206 memset(&ra, 0, sizeof(ra));
208 obj = fetch_odbc_obj(database, 0);
212 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
213 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
214 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
218 newparam = va_arg(aq, const char *);
220 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
223 initfield = ast_strdupa(newparam);
224 if (initfield && (op = strchr(initfield, ' ')))
226 newval = va_arg(aq, const char *);
227 if (!strchr(newparam, ' ')) op = " ="; else op = "";
228 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?", table, newparam, op);
229 while((newparam = va_arg(aq, const char *))) {
230 if (!strchr(newparam, ' ')) op = " ="; else op = "";
231 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?", newparam, op);
232 newval = va_arg(aq, const char *);
235 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
237 res = SQLPrepare(stmt, sql, SQL_NTS);
238 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
239 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
240 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
244 /* Now bind the parameters */
247 while((newparam = va_arg(ap, const char *))) {
248 newval = va_arg(ap, const char *);
249 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
252 res = odbc_smart_execute(obj, stmt);
254 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
255 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
256 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
260 res = SQLRowCount(stmt, &rowcount);
261 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
262 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
263 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
267 res = SQLNumResultCols(stmt, &colcount);
268 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
269 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
270 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
274 cfg = ast_config_new();
276 ast_log(LOG_WARNING, "Out of memory!\n");
277 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
283 res = SQLFetch(stmt);
284 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
285 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
288 cat = ast_category_new("");
290 ast_log(LOG_WARNING, "Out of memory!\n");
293 for (x=0;x<colcount;x++) {
295 collen = sizeof(coltitle);
296 res = SQLDescribeCol(stmt, x + 1, coltitle, sizeof(coltitle), &collen,
297 &datatype, &colsize, &decimaldigits, &nullable);
298 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
299 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
300 ast_category_destroy(cat);
305 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
306 if (indicator == SQL_NULL_DATA)
309 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
310 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
311 ast_category_destroy(cat);
316 chunk = strsep(&stringp, ";");
317 if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
318 if (initfield && !strcmp(initfield, coltitle))
319 ast_category_rename(cat, chunk);
320 var = ast_variable_new(coltitle, chunk);
321 ast_variable_append(cat, var);
325 ast_category_append(cfg, cat);
328 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
332 static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
338 const char *newparam, *newval;
348 obj = fetch_odbc_obj (database, 0);
352 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
353 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
354 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
358 newparam = va_arg(aq, const char *);
360 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
363 newval = va_arg(aq, const char *);
364 snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
365 while((newparam = va_arg(aq, const char *))) {
366 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
367 newval = va_arg(aq, const char *);
370 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
372 res = SQLPrepare(stmt, sql, SQL_NTS);
373 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
374 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
375 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
379 /* Now bind the parameters */
382 while((newparam = va_arg(ap, const char *))) {
383 newval = va_arg(ap, const char *);
384 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
387 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL);
389 res = odbc_smart_execute(obj, stmt);
391 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
392 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
393 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
397 res = SQLRowCount(stmt, &rowcount);
398 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
400 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
401 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
406 return (int)rowcount;
411 static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg)
413 struct ast_variable *new_v;
414 struct ast_category *cur_cat;
417 SQLINTEGER err=0, commented=0, cat_metric=0, var_metric=0, last_cat_metric=0;
419 char sql[255] = "", filename[128], category[128], var_name[128], var_val[512];
420 SQLSMALLINT rowcount=0;
424 if (!file || !strcmp (file, "res_config_odbc.conf"))
425 return NULL; /* cant configure myself with myself ! */
427 obj = fetch_odbc_obj(database, 0);
431 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
433 SQLBindCol (stmt, 1, SQL_C_ULONG, &id, sizeof (id), &err);
434 SQLBindCol (stmt, 2, SQL_C_ULONG, &cat_metric, sizeof (cat_metric), &err);
435 SQLBindCol (stmt, 3, SQL_C_ULONG, &var_metric, sizeof (var_metric), &err);
436 SQLBindCol (stmt, 4, SQL_C_ULONG, &commented, sizeof (commented), &err);
437 SQLBindCol (stmt, 5, SQL_C_CHAR, &filename, sizeof (filename), &err);
438 SQLBindCol (stmt, 6, SQL_C_CHAR, &category, sizeof (category), &err);
439 SQLBindCol (stmt, 7, SQL_C_CHAR, &var_name, sizeof (var_name), &err);
440 SQLBindCol (stmt, 8, SQL_C_CHAR, &var_val, sizeof (var_val), &err);
442 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE filename='%s' and commented=0 ORDER BY filename,cat_metric desc,var_metric asc,category,var_name,var_val,id", table, file);
444 res = odbc_smart_direct_execute(obj, stmt, sql);
446 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
447 ast_log (LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
448 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
452 res = SQLNumResultCols (stmt, &rowcount);
454 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
455 ast_log (LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
456 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
461 ast_log (LOG_NOTICE, "found nothing\n");
465 cur_cat = ast_config_get_current_category(cfg);
467 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
468 if (!strcmp (var_name, "#include")) {
469 if (!ast_config_internal_load(var_val, cfg)) {
470 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
475 if (strcmp(last, category) || last_cat_metric != cat_metric) {
476 cur_cat = ast_category_new(category);
478 ast_log(LOG_WARNING, "Out of memory!\n");
481 strcpy(last, category);
482 last_cat_metric = cat_metric;
483 ast_category_append(cfg, cur_cat);
486 new_v = ast_variable_new(var_name, var_val);
487 ast_variable_append(cur_cat, new_v);
490 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
494 static struct ast_config_engine odbc_engine = {
496 .load_func = config_odbc,
497 .realtime_func = realtime_odbc,
498 .realtime_multi_func = realtime_multi_odbc,
499 .update_func = update_odbc
502 int unload_module (void)
504 ast_config_engine_deregister(&odbc_engine);
506 ast_verbose("res_config_odbc unloaded.\n");
507 STANDARD_HANGUP_LOCALUSERS;
511 int load_module (void)
513 ast_config_engine_register(&odbc_engine);
515 ast_verbose("res_config_odbc loaded.\n");
519 char *description (void)
526 /* never unload a config module */
532 return ASTERISK_GPL_KEY;