![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
res_config_odbc.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2005, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct@yahoo.com> 00009 * 00010 * See http://www.asterisk.org for more information about 00011 * the Asterisk project. Please do not directly contact 00012 * any of the maintainers of this project for assistance; 00013 * the project provides a web site, mailing lists and IRC 00014 * channels for your use. 00015 * 00016 * This program is free software, distributed under the terms of 00017 * the GNU General Public License Version 2. See the LICENSE file 00018 * at the top of the source tree. 00019 */ 00020 00021 /*! \file 00022 * 00023 * \brief odbc+odbc plugin for portable configuration engine 00024 * 00025 * \author Mark Spencer <markster@digium.com> 00026 * \author Anthony Minessale II <anthmct@yahoo.com> 00027 * 00028 * \arg http://www.unixodbc.org 00029 */ 00030 00031 /*** MODULEINFO 00032 <depend>unixodbc</depend> 00033 ***/ 00034 00035 #include "asterisk.h" 00036 00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 49808 $") 00038 00039 #include <stdio.h> 00040 #include <stdlib.h> 00041 #include <unistd.h> 00042 #include <string.h> 00043 00044 #include "asterisk/file.h" 00045 #include "asterisk/logger.h" 00046 #include "asterisk/channel.h" 00047 #include "asterisk/pbx.h" 00048 #include "asterisk/config.h" 00049 #include "asterisk/module.h" 00050 #include "asterisk/lock.h" 00051 #include "asterisk/options.h" 00052 #include "asterisk/res_odbc.h" 00053 #include "asterisk/utils.h" 00054 00055 static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap) 00056 { 00057 struct odbc_obj *obj; 00058 SQLHSTMT stmt; 00059 char sql[1024]; 00060 char coltitle[256]; 00061 char rowdata[2048]; 00062 char *op; 00063 const char *newparam, *newval; 00064 char *stringp; 00065 char *chunk; 00066 SQLSMALLINT collen; 00067 int res; 00068 int x; 00069 struct ast_variable *var=NULL, *prev=NULL; 00070 SQLULEN colsize; 00071 SQLSMALLINT colcount=0; 00072 SQLSMALLINT datatype; 00073 SQLSMALLINT decimaldigits; 00074 SQLSMALLINT nullable; 00075 SQLLEN indicator; 00076 va_list aq; 00077 00078 va_copy(aq, ap); 00079 00080 00081 if (!table) 00082 return NULL; 00083 00084 obj = ast_odbc_request_obj(database, 0); 00085 if (!obj) 00086 return NULL; 00087 00088 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); 00089 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00090 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); 00091 ast_odbc_release_obj(obj); 00092 return NULL; 00093 } 00094 00095 newparam = va_arg(aq, const char *); 00096 if (!newparam) { 00097 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00098 ast_odbc_release_obj(obj); 00099 return NULL; 00100 } 00101 newval = va_arg(aq, const char *); 00102 if (!strchr(newparam, ' ')) op = " ="; else op = ""; 00103 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?", table, newparam, op); 00104 while((newparam = va_arg(aq, const char *))) { 00105 if (!strchr(newparam, ' ')) op = " ="; else op = ""; 00106 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?", newparam, op); 00107 newval = va_arg(aq, const char *); 00108 } 00109 va_end(aq); 00110 res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); 00111 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00112 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); 00113 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00114 ast_odbc_release_obj(obj); 00115 return NULL; 00116 } 00117 00118 /* Now bind the parameters */ 00119 x = 1; 00120 00121 while((newparam = va_arg(ap, const char *))) { 00122 newval = va_arg(ap, const char *); 00123 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); 00124 } 00125 00126 res = ast_odbc_smart_execute(obj, stmt); 00127 00128 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00129 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); 00130 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00131 ast_odbc_release_obj(obj); 00132 return NULL; 00133 } 00134 00135 res = SQLNumResultCols(stmt, &colcount); 00136 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00137 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); 00138 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00139 ast_odbc_release_obj(obj); 00140 return NULL; 00141 } 00142 00143 res = SQLFetch(stmt); 00144 if (res == SQL_NO_DATA) { 00145 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00146 ast_odbc_release_obj(obj); 00147 return NULL; 00148 } 00149 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00150 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); 00151 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00152 ast_odbc_release_obj(obj); 00153 return NULL; 00154 } 00155 for (x = 0; x < colcount; x++) { 00156 rowdata[0] = '\0'; 00157 collen = sizeof(coltitle); 00158 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 00159 &datatype, &colsize, &decimaldigits, &nullable); 00160 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00161 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); 00162 if (var) 00163 ast_variables_destroy(var); 00164 ast_odbc_release_obj(obj); 00165 return NULL; 00166 } 00167 00168 indicator = 0; 00169 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator); 00170 if (indicator == SQL_NULL_DATA) 00171 rowdata[0] = '\0'; 00172 else if (ast_strlen_zero(rowdata)) { 00173 /* Because we encode the empty string for a NULL, we will encode 00174 * actual empty strings as a string containing a single whitespace. */ 00175 ast_copy_string(rowdata, " ", sizeof(rowdata)); 00176 } 00177 00178 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00179 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); 00180 if (var) 00181 ast_variables_destroy(var); 00182 ast_odbc_release_obj(obj); 00183 return NULL; 00184 } 00185 stringp = rowdata; 00186 while(stringp) { 00187 chunk = strsep(&stringp, ";"); 00188 if (prev) { 00189 prev->next = ast_variable_new(coltitle, chunk); 00190 if (prev->next) 00191 prev = prev->next; 00192 } else 00193 prev = var = ast_variable_new(coltitle, chunk); 00194 } 00195 } 00196 00197 00198 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00199 ast_odbc_release_obj(obj); 00200 return var; 00201 } 00202 00203 static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap) 00204 { 00205 struct odbc_obj *obj; 00206 SQLHSTMT stmt; 00207 char sql[1024]; 00208 char coltitle[256]; 00209 char rowdata[2048]; 00210 const char *initfield=NULL; 00211 char *op; 00212 const char *newparam, *newval; 00213 char *stringp; 00214 char *chunk; 00215 SQLSMALLINT collen; 00216 int res; 00217 int x; 00218 struct ast_variable *var=NULL; 00219 struct ast_config *cfg=NULL; 00220 struct ast_category *cat=NULL; 00221 struct ast_realloca ra; 00222 SQLULEN colsize; 00223 SQLSMALLINT colcount=0; 00224 SQLSMALLINT datatype; 00225 SQLSMALLINT decimaldigits; 00226 SQLSMALLINT nullable; 00227 SQLLEN indicator; 00228 00229 va_list aq; 00230 va_copy(aq, ap); 00231 00232 00233 if (!table) 00234 return NULL; 00235 memset(&ra, 0, sizeof(ra)); 00236 00237 obj = ast_odbc_request_obj(database, 0); 00238 if (!obj) 00239 return NULL; 00240 00241 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); 00242 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00243 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); 00244 ast_odbc_release_obj(obj); 00245 return NULL; 00246 } 00247 00248 newparam = va_arg(aq, const char *); 00249 if (!newparam) { 00250 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00251 ast_odbc_release_obj(obj); 00252 return NULL; 00253 } 00254 initfield = ast_strdupa(newparam); 00255 if ((op = strchr(initfield, ' '))) 00256 *op = '\0'; 00257 newval = va_arg(aq, const char *); 00258 if (!strchr(newparam, ' ')) op = " ="; else op = ""; 00259 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?", table, newparam, op); 00260 while((newparam = va_arg(aq, const char *))) { 00261 if (!strchr(newparam, ' ')) op = " ="; else op = ""; 00262 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?", newparam, op); 00263 newval = va_arg(aq, const char *); 00264 } 00265 if (initfield) 00266 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield); 00267 va_end(aq); 00268 res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); 00269 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00270 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); 00271 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00272 ast_odbc_release_obj(obj); 00273 return NULL; 00274 } 00275 00276 /* Now bind the parameters */ 00277 x = 1; 00278 00279 while((newparam = va_arg(ap, const char *))) { 00280 newval = va_arg(ap, const char *); 00281 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); 00282 } 00283 00284 res = ast_odbc_smart_execute(obj, stmt); 00285 00286 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00287 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); 00288 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00289 ast_odbc_release_obj(obj); 00290 return NULL; 00291 } 00292 00293 res = SQLNumResultCols(stmt, &colcount); 00294 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00295 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); 00296 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00297 ast_odbc_release_obj(obj); 00298 return NULL; 00299 } 00300 00301 cfg = ast_config_new(); 00302 if (!cfg) { 00303 ast_log(LOG_WARNING, "Out of memory!\n"); 00304 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00305 ast_odbc_release_obj(obj); 00306 return NULL; 00307 } 00308 00309 while ((res=SQLFetch(stmt)) != SQL_NO_DATA) { 00310 var = NULL; 00311 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00312 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); 00313 continue; 00314 } 00315 cat = ast_category_new(""); 00316 if (!cat) { 00317 ast_log(LOG_WARNING, "Out of memory!\n"); 00318 continue; 00319 } 00320 for (x=0;x<colcount;x++) { 00321 rowdata[0] = '\0'; 00322 collen = sizeof(coltitle); 00323 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 00324 &datatype, &colsize, &decimaldigits, &nullable); 00325 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00326 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); 00327 ast_category_destroy(cat); 00328 continue; 00329 } 00330 00331 indicator = 0; 00332 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator); 00333 if (indicator == SQL_NULL_DATA) 00334 continue; 00335 00336 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00337 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); 00338 ast_category_destroy(cat); 00339 continue; 00340 } 00341 stringp = rowdata; 00342 while(stringp) { 00343 chunk = strsep(&stringp, ";"); 00344 if (!ast_strlen_zero(ast_strip(chunk))) { 00345 if (initfield && !strcmp(initfield, coltitle)) 00346 ast_category_rename(cat, chunk); 00347 var = ast_variable_new(coltitle, chunk); 00348 ast_variable_append(cat, var); 00349 } 00350 } 00351 } 00352 ast_category_append(cfg, cat); 00353 } 00354 00355 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00356 ast_odbc_release_obj(obj); 00357 return cfg; 00358 } 00359 00360 static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap) 00361 { 00362 struct odbc_obj *obj; 00363 SQLHSTMT stmt; 00364 char sql[256]; 00365 SQLLEN rowcount=0; 00366 const char *newparam, *newval; 00367 int res; 00368 int x; 00369 va_list aq; 00370 00371 va_copy(aq, ap); 00372 00373 if (!table) 00374 return -1; 00375 00376 obj = ast_odbc_request_obj(database, 0); 00377 if (!obj) 00378 return -1; 00379 00380 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); 00381 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00382 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); 00383 ast_odbc_release_obj(obj); 00384 return -1; 00385 } 00386 00387 newparam = va_arg(aq, const char *); 00388 if (!newparam) { 00389 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00390 ast_odbc_release_obj(obj); 00391 return -1; 00392 } 00393 newval = va_arg(aq, const char *); 00394 snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam); 00395 while((newparam = va_arg(aq, const char *))) { 00396 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam); 00397 newval = va_arg(aq, const char *); 00398 } 00399 va_end(aq); 00400 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield); 00401 00402 res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); 00403 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00404 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); 00405 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00406 ast_odbc_release_obj(obj); 00407 return -1; 00408 } 00409 00410 /* Now bind the parameters */ 00411 x = 1; 00412 00413 while((newparam = va_arg(ap, const char *))) { 00414 newval = va_arg(ap, const char *); 00415 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); 00416 } 00417 00418 SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL); 00419 00420 res = ast_odbc_smart_execute(obj, stmt); 00421 00422 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00423 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); 00424 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00425 ast_odbc_release_obj(obj); 00426 return -1; 00427 } 00428 00429 res = SQLRowCount(stmt, &rowcount); 00430 SQLFreeHandle (SQL_HANDLE_STMT, stmt); 00431 ast_odbc_release_obj(obj); 00432 00433 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00434 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); 00435 return -1; 00436 } 00437 00438 if (rowcount >= 0) 00439 return (int)rowcount; 00440 00441 return -1; 00442 } 00443 00444 struct config_odbc_obj { 00445 char *sql; 00446 unsigned long id; 00447 unsigned long cat_metric; 00448 unsigned long var_metric; 00449 unsigned long commented; 00450 char filename[128]; 00451 char category[128]; 00452 char var_name[128]; 00453 char var_val[1024]; /* changed from 128 to 1024 via bug 8251 */ 00454 SQLLEN err; 00455 }; 00456 00457 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data) 00458 { 00459 struct config_odbc_obj *q = data; 00460 SQLHSTMT sth; 00461 int res; 00462 00463 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth); 00464 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00465 if (option_verbose > 3) 00466 ast_verbose( VERBOSE_PREFIX_4 "Failure in AllocStatement %d\n", res); 00467 return NULL; 00468 } 00469 00470 res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS); 00471 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00472 if (option_verbose > 3) 00473 ast_verbose( VERBOSE_PREFIX_4 "Error in PREPARE %d\n", res); 00474 SQLFreeHandle(SQL_HANDLE_STMT, sth); 00475 return NULL; 00476 } 00477 00478 SQLBindCol(sth, 1, SQL_C_ULONG, &q->id, sizeof(q->id), &q->err); 00479 SQLBindCol(sth, 2, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err); 00480 SQLBindCol(sth, 3, SQL_C_ULONG, &q->var_metric, sizeof(q->var_metric), &q->err); 00481 SQLBindCol(sth, 4, SQL_C_ULONG, &q->commented, sizeof(q->commented), &q->err); 00482 SQLBindCol(sth, 5, SQL_C_CHAR, q->filename, sizeof(q->filename), &q->err); 00483 SQLBindCol(sth, 6, SQL_C_CHAR, q->category, sizeof(q->category), &q->err); 00484 SQLBindCol(sth, 7, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err); 00485 SQLBindCol(sth, 8, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err); 00486 00487 return sth; 00488 } 00489 00490 static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments) 00491 { 00492 struct ast_variable *new_v; 00493 struct ast_category *cur_cat; 00494 int res = 0; 00495 struct odbc_obj *obj; 00496 char sql[255] = ""; 00497 unsigned int last_cat_metric = 0; 00498 SQLSMALLINT rowcount=0; 00499 SQLHSTMT stmt; 00500 char last[128] = ""; 00501 struct config_odbc_obj q; 00502 00503 memset(&q, 0, sizeof(q)); 00504 00505 if (!file || !strcmp (file, "res_config_odbc.conf")) 00506 return NULL; /* cant configure myself with myself ! */ 00507 00508 obj = ast_odbc_request_obj(database, 0); 00509 if (!obj) 00510 return NULL; 00511 00512 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); 00513 q.sql = sql; 00514 00515 stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q); 00516 00517 if (!stmt) { 00518 ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql); 00519 ast_odbc_release_obj(obj); 00520 return NULL; 00521 } 00522 00523 res = SQLNumResultCols(stmt, &rowcount); 00524 00525 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { 00526 ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql); 00527 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00528 ast_odbc_release_obj(obj); 00529 return NULL; 00530 } 00531 00532 if (!rowcount) { 00533 ast_log(LOG_NOTICE, "found nothing\n"); 00534 ast_odbc_release_obj(obj); 00535 return cfg; 00536 } 00537 00538 cur_cat = ast_config_get_current_category(cfg); 00539 00540 while ((res = SQLFetch(stmt)) != SQL_NO_DATA) { 00541 if (!strcmp (q.var_name, "#include")) { 00542 if (!ast_config_internal_load(q.var_val, cfg, 0)) { 00543 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00544 ast_odbc_release_obj(obj); 00545 return NULL; 00546 } 00547 continue; 00548 } 00549 if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) { 00550 cur_cat = ast_category_new(q.category); 00551 if (!cur_cat) { 00552 ast_log(LOG_WARNING, "Out of memory!\n"); 00553 break; 00554 } 00555 strcpy(last, q.category); 00556 last_cat_metric = q.cat_metric; 00557 ast_category_append(cfg, cur_cat); 00558 } 00559 00560 new_v = ast_variable_new(q.var_name, q.var_val); 00561 ast_variable_append(cur_cat, new_v); 00562 } 00563 00564 SQLFreeHandle(SQL_HANDLE_STMT, stmt); 00565 ast_odbc_release_obj(obj); 00566 return cfg; 00567 } 00568 00569 static struct ast_config_engine odbc_engine = { 00570 .name = "odbc", 00571 .load_func = config_odbc, 00572 .realtime_func = realtime_odbc, 00573 .realtime_multi_func = realtime_multi_odbc, 00574 .update_func = update_odbc 00575 }; 00576 00577 static int unload_module (void) 00578 { 00579 ast_module_user_hangup_all(); 00580 ast_config_engine_deregister(&odbc_engine); 00581 if (option_verbose) 00582 ast_verbose("res_config_odbc unloaded.\n"); 00583 return 0; 00584 } 00585 00586 static int load_module (void) 00587 { 00588 ast_config_engine_register(&odbc_engine); 00589 if (option_verbose) 00590 ast_verbose("res_config_odbc loaded.\n"); 00591 return 0; 00592 } 00593 00594 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "ODBC Configuration", 00595 .load = load_module, 00596 .unload = unload_module, 00597 );