Thu Jul 9 13:40:39 2009

Asterisk developer's documentation


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    <depend>ltdl</depend>
00034    <depend>res_odbc</depend>
00035  ***/
00036 
00037 #include "asterisk.h"
00038 
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 129764 $")
00040 
00041 #include "asterisk/file.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/config.h"
00045 #include "asterisk/module.h"
00046 #include "asterisk/lock.h"
00047 #include "asterisk/res_odbc.h"
00048 #include "asterisk/utils.h"
00049 
00050 struct custom_prepare_struct {
00051    const char *sql;
00052    const char *extra;
00053    va_list ap;
00054 };
00055 
00056 static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
00057 {
00058    int res, x = 1;
00059    struct custom_prepare_struct *cps = data;
00060    const char *newparam, *newval;
00061    SQLHSTMT stmt;
00062    va_list ap;
00063 
00064    va_copy(ap, cps->ap);
00065 
00066    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
00067    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00068       ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
00069       return NULL;
00070    }
00071 
00072    res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS);
00073    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00074       ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql);
00075       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00076       return NULL;
00077    }
00078 
00079    while ((newparam = va_arg(ap, const char *))) {
00080       newval = va_arg(ap, const char *);
00081       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
00082    }
00083    va_end(ap);
00084 
00085    if (!ast_strlen_zero(cps->extra))
00086       SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(cps->extra), 0, (void *)cps->extra, 0, NULL);
00087    return stmt;
00088 }
00089 
00090 /*!
00091  * \brief Excute an SQL query and return ast_variable list
00092  * \param database
00093  * \param table
00094  * \param ap list containing one or more field/operator/value set.
00095  *
00096  * Select database and preform query on table, prepare the sql statement
00097  * Sub-in the values to the prepared statement and execute it. Return results
00098  * as a ast_variable list.
00099  *
00100  * \retval var on success
00101  * \retval NULL on failure
00102 */
00103 static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
00104 {
00105    struct odbc_obj *obj;
00106    SQLHSTMT stmt;
00107    char sql[1024];
00108    char coltitle[256];
00109    char rowdata[2048];
00110    char *op;
00111    const char *newparam, *newval;
00112    char *stringp;
00113    char *chunk;
00114    SQLSMALLINT collen;
00115    int res;
00116    int x;
00117    struct ast_variable *var=NULL, *prev=NULL;
00118    SQLULEN colsize;
00119    SQLSMALLINT colcount=0;
00120    SQLSMALLINT datatype;
00121    SQLSMALLINT decimaldigits;
00122    SQLSMALLINT nullable;
00123    SQLLEN indicator;
00124    va_list aq;
00125    struct custom_prepare_struct cps = { .sql = sql };
00126 
00127    va_copy(cps.ap, ap);
00128    va_copy(aq, ap);
00129 
00130    if (!table)
00131       return NULL;
00132 
00133    obj = ast_odbc_request_obj(database, 0);
00134 
00135    if (!obj) {
00136       ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
00137       return NULL;
00138    }
00139 
00140    newparam = va_arg(aq, const char *);
00141    if (!newparam) {
00142       ast_odbc_release_obj(obj);
00143       return NULL;
00144    }
00145    newval = va_arg(aq, const char *);
00146    op = !strchr(newparam, ' ') ? " =" : "";
00147    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
00148       strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00149    while((newparam = va_arg(aq, const char *))) {
00150       op = !strchr(newparam, ' ') ? " =" : "";
00151       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
00152          strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00153       newval = va_arg(aq, const char *);
00154    }
00155    va_end(aq);
00156 
00157    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00158 
00159    if (!stmt) {
00160       ast_odbc_release_obj(obj);
00161       return NULL;
00162    }
00163 
00164    res = SQLNumResultCols(stmt, &colcount);
00165    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00166       ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00167       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00168       ast_odbc_release_obj(obj);
00169       return NULL;
00170    }
00171 
00172    res = SQLFetch(stmt);
00173    if (res == SQL_NO_DATA) {
00174       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00175       ast_odbc_release_obj(obj);
00176       return NULL;
00177    }
00178    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00179       ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00180       SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00181       ast_odbc_release_obj(obj);
00182       return NULL;
00183    }
00184    for (x = 0; x < colcount; x++) {
00185       rowdata[0] = '\0';
00186       collen = sizeof(coltitle);
00187       res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
00188                &datatype, &colsize, &decimaldigits, &nullable);
00189       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00190          ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00191          if (var)
00192             ast_variables_destroy(var);
00193          ast_odbc_release_obj(obj);
00194          return NULL;
00195       }
00196 
00197       indicator = 0;
00198       res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
00199       if (indicator == SQL_NULL_DATA)
00200          rowdata[0] = '\0';
00201       else if (ast_strlen_zero(rowdata)) {
00202          /* Because we encode the empty string for a NULL, we will encode
00203           * actual empty strings as a string containing a single whitespace. */
00204          ast_copy_string(rowdata, " ", sizeof(rowdata));
00205       }
00206 
00207       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00208          ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00209          if (var)
00210             ast_variables_destroy(var);
00211          ast_odbc_release_obj(obj);
00212          return NULL;
00213       }
00214       stringp = rowdata;
00215       while(stringp) {
00216          chunk = strsep(&stringp, ";");
00217          if (!ast_strlen_zero(ast_strip(chunk))) {
00218             if (prev) {
00219                prev->next = ast_variable_new(coltitle, chunk, "");
00220                if (prev->next)
00221                   prev = prev->next;
00222             } else 
00223                prev = var = ast_variable_new(coltitle, chunk, "");
00224          }
00225       }
00226    }
00227 
00228 
00229    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00230    ast_odbc_release_obj(obj);
00231    return var;
00232 }
00233 
00234 /*!
00235  * \brief Excute an Select query and return ast_config list
00236  * \param database
00237  * \param table
00238  * \param ap list containing one or more field/operator/value set.
00239  *
00240  * Select database and preform query on table, prepare the sql statement
00241  * Sub-in the values to the prepared statement and execute it. 
00242  * Execute this prepared query against several ODBC connected databases.
00243  * Return results as an ast_config variable.
00244  *
00245  * \retval var on success
00246  * \retval NULL on failure
00247 */
00248 static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap)
00249 {
00250    struct odbc_obj *obj;
00251    SQLHSTMT stmt;
00252    char sql[1024];
00253    char coltitle[256];
00254    char rowdata[2048];
00255    const char *initfield=NULL;
00256    char *op;
00257    const char *newparam, *newval;
00258    char *stringp;
00259    char *chunk;
00260    SQLSMALLINT collen;
00261    int res;
00262    int x;
00263    struct ast_variable *var=NULL;
00264    struct ast_config *cfg=NULL;
00265    struct ast_category *cat=NULL;
00266    SQLULEN colsize;
00267    SQLSMALLINT colcount=0;
00268    SQLSMALLINT datatype;
00269    SQLSMALLINT decimaldigits;
00270    SQLSMALLINT nullable;
00271    SQLLEN indicator;
00272    struct custom_prepare_struct cps = { .sql = sql };
00273    va_list aq;
00274 
00275    va_copy(cps.ap, ap);
00276    va_copy(aq, ap);
00277 
00278    if (!table)
00279       return NULL;
00280 
00281    obj = ast_odbc_request_obj(database, 0);
00282    if (!obj)
00283       return NULL;
00284 
00285    newparam = va_arg(aq, const char *);
00286    if (!newparam)  {
00287       ast_odbc_release_obj(obj);
00288       return NULL;
00289    }
00290    initfield = ast_strdupa(newparam);
00291    if ((op = strchr(initfield, ' '))) 
00292       *op = '\0';
00293    newval = va_arg(aq, const char *);
00294    op = !strchr(newparam, ' ') ? " =" : "";
00295    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
00296       strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00297    while((newparam = va_arg(aq, const char *))) {
00298       op = !strchr(newparam, ' ') ? " =" : "";
00299       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
00300          strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
00301       newval = va_arg(aq, const char *);
00302    }
00303    if (initfield)
00304       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00305    va_end(aq);
00306 
00307    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00308 
00309    if (!stmt) {
00310       ast_odbc_release_obj(obj);
00311       return NULL;
00312    }
00313 
00314    res = SQLNumResultCols(stmt, &colcount);
00315    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00316       ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
00317       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00318       ast_odbc_release_obj(obj);
00319       return NULL;
00320    }
00321 
00322    cfg = ast_config_new();
00323    if (!cfg) {
00324       ast_log(LOG_WARNING, "Out of memory!\n");
00325       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00326       ast_odbc_release_obj(obj);
00327       return NULL;
00328    }
00329 
00330    while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
00331       var = NULL;
00332       if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00333          ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
00334          continue;
00335       }
00336       cat = ast_category_new("","",99999);
00337       if (!cat) {
00338          ast_log(LOG_WARNING, "Out of memory!\n");
00339          continue;
00340       }
00341       for (x=0;x<colcount;x++) {
00342          rowdata[0] = '\0';
00343          collen = sizeof(coltitle);
00344          res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
00345                   &datatype, &colsize, &decimaldigits, &nullable);
00346          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00347             ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
00348             ast_category_destroy(cat);
00349             continue;
00350          }
00351 
00352          indicator = 0;
00353          res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
00354          if (indicator == SQL_NULL_DATA)
00355             continue;
00356 
00357          if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00358             ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
00359             ast_category_destroy(cat);
00360             continue;
00361          }
00362          stringp = rowdata;
00363          while(stringp) {
00364             chunk = strsep(&stringp, ";");
00365             if (!ast_strlen_zero(ast_strip(chunk))) {
00366                if (initfield && !strcmp(initfield, coltitle))
00367                   ast_category_rename(cat, chunk);
00368                var = ast_variable_new(coltitle, chunk, "");
00369                ast_variable_append(cat, var);
00370             }
00371          }
00372       }
00373       ast_category_append(cfg, cat);
00374    }
00375 
00376    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00377    ast_odbc_release_obj(obj);
00378    return cfg;
00379 }
00380 
00381 /*!
00382  * \brief Excute an UPDATE query
00383  * \param database
00384  * \param table
00385  * \param keyfield where clause field
00386  * \param lookup value of field for where clause
00387  * \param ap list containing one or more field/value set(s).
00388  *
00389  * Update a database table, prepare the sql statement using keyfield and lookup
00390  * control the number of records to change. All values to be changed are stored in ap list.
00391  * Sub-in the values to the prepared statement and execute it.
00392  *
00393  * \retval number of rows affected
00394  * \retval -1 on failure
00395 */
00396 static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
00397 {
00398    struct odbc_obj *obj;
00399    SQLHSTMT stmt;
00400    char sql[256];
00401    SQLLEN rowcount=0;
00402    const char *newparam, *newval;
00403    int res;
00404    va_list aq;
00405    struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
00406 
00407    va_copy(cps.ap, ap);
00408    va_copy(aq, ap);
00409    
00410    if (!table)
00411       return -1;
00412 
00413    obj = ast_odbc_request_obj(database, 0);
00414    if (!obj)
00415       return -1;
00416 
00417    newparam = va_arg(aq, const char *);
00418    if (!newparam)  {
00419       ast_odbc_release_obj(obj);
00420       return -1;
00421    }
00422    newval = va_arg(aq, const char *);
00423    snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
00424    while((newparam = va_arg(aq, const char *))) {
00425       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
00426       newval = va_arg(aq, const char *);
00427    }
00428    va_end(aq);
00429    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
00430 
00431    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00432 
00433    if (!stmt) {
00434       ast_odbc_release_obj(obj);
00435       return -1;
00436    }
00437 
00438    res = SQLRowCount(stmt, &rowcount);
00439    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00440    ast_odbc_release_obj(obj);
00441 
00442    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00443       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00444       return -1;
00445    }
00446 
00447    if (rowcount >= 0)
00448       return (int)rowcount;
00449 
00450    return -1;
00451 }
00452 
00453 /*!
00454  * \brief Excute an INSERT query
00455  * \param database
00456  * \param table
00457  * \param ap list containing one or more field/value set(s)
00458  *
00459  * Insert a new record into database table, prepare the sql statement.
00460  * All values to be changed are stored in ap list.
00461  * Sub-in the values to the prepared statement and execute it.
00462  *
00463  * \retval number of rows affected
00464  * \retval -1 on failure
00465 */
00466 static int store_odbc(const char *database, const char *table, va_list ap)
00467 {
00468    struct odbc_obj *obj;
00469    SQLHSTMT stmt;
00470    char sql[256];
00471    char keys[256];
00472    char vals[256];
00473    SQLLEN rowcount=0;
00474    const char *newparam, *newval;
00475    int res;
00476    va_list aq;
00477    struct custom_prepare_struct cps = { .sql = sql, .extra = NULL };
00478 
00479    va_copy(cps.ap, ap);
00480    va_copy(aq, ap);
00481    
00482    if (!table)
00483       return -1;
00484 
00485    obj = ast_odbc_request_obj(database, 0);
00486    if (!obj)
00487       return -1;
00488 
00489    newparam = va_arg(aq, const char *);
00490    if (!newparam)  {
00491       ast_odbc_release_obj(obj);
00492       return -1;
00493    }
00494    newval = va_arg(aq, const char *);
00495    snprintf(keys, sizeof(keys), "%s", newparam);
00496    ast_copy_string(vals, "?", sizeof(vals));
00497    while ((newparam = va_arg(aq, const char *))) {
00498       snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam);
00499       snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
00500       newval = va_arg(aq, const char *);
00501    }
00502    va_end(aq);
00503    snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
00504 
00505    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00506 
00507    if (!stmt) {
00508       ast_odbc_release_obj(obj);
00509       return -1;
00510    }
00511 
00512    res = SQLRowCount(stmt, &rowcount);
00513    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00514    ast_odbc_release_obj(obj);
00515 
00516    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00517       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00518       return -1;
00519    }
00520 
00521    if (rowcount >= 0)
00522       return (int)rowcount;
00523 
00524    return -1;
00525 }
00526 
00527 /*!
00528  * \brief Excute an DELETE query
00529  * \param database
00530  * \param table
00531  * \param keyfield where clause field
00532  * \param lookup value of field for where clause
00533  * \param ap list containing one or more field/value set(s)
00534  *
00535  * Delete a row from a database table, prepare the sql statement using keyfield and lookup
00536  * control the number of records to change. Additional params to match rows are stored in ap list.
00537  * Sub-in the values to the prepared statement and execute it.
00538  *
00539  * \retval number of rows affected
00540  * \retval -1 on failure
00541 */
00542 static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
00543 {
00544    struct odbc_obj *obj;
00545    SQLHSTMT stmt;
00546    char sql[256];
00547    SQLLEN rowcount=0;
00548    const char *newparam, *newval;
00549    int res;
00550    va_list aq;
00551    struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
00552 
00553    va_copy(cps.ap, ap);
00554    va_copy(aq, ap);
00555    
00556    if (!table)
00557       return -1;
00558 
00559    obj = ast_odbc_request_obj(database, 0);
00560    if (!obj)
00561       return -1;
00562 
00563    snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
00564    while((newparam = va_arg(aq, const char *))) {
00565       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam);
00566       newval = va_arg(aq, const char *);
00567    }
00568    va_end(aq);
00569    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
00570 
00571    stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
00572 
00573    if (!stmt) {
00574       ast_odbc_release_obj(obj);
00575       return -1;
00576    }
00577 
00578    res = SQLRowCount(stmt, &rowcount);
00579    SQLFreeHandle (SQL_HANDLE_STMT, stmt);
00580    ast_odbc_release_obj(obj);
00581 
00582    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00583       ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
00584       return -1;
00585    }
00586 
00587    if (rowcount >= 0)
00588       return (int)rowcount;
00589 
00590    return -1;
00591 }
00592 
00593 
00594 struct config_odbc_obj {
00595    char *sql;
00596    unsigned long cat_metric;
00597    char category[128];
00598    char var_name[128];
00599    char var_val[1024]; /* changed from 128 to 1024 via bug 8251 */
00600    SQLLEN err;
00601 };
00602 
00603 static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
00604 {
00605    struct config_odbc_obj *q = data;
00606    SQLHSTMT sth;
00607    int res;
00608 
00609    res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
00610    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00611       ast_verb(4, "Failure in AllocStatement %d\n", res);
00612       return NULL;
00613    }
00614 
00615    res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
00616    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00617       ast_verb(4, "Error in PREPARE %d\n", res);
00618       SQLFreeHandle(SQL_HANDLE_STMT, sth);
00619       return NULL;
00620    }
00621 
00622    SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
00623    SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
00624    SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
00625    SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
00626 
00627    return sth;
00628 }
00629 
00630 static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
00631 {
00632    struct ast_variable *new_v;
00633    struct ast_category *cur_cat;
00634    int res = 0;
00635    struct odbc_obj *obj;
00636    char sqlbuf[1024] = "";
00637    char *sql = sqlbuf;
00638    size_t sqlleft = sizeof(sqlbuf);
00639    unsigned int last_cat_metric = 0;
00640    SQLSMALLINT rowcount = 0;
00641    SQLHSTMT stmt;
00642    char last[128] = "";
00643    struct config_odbc_obj q;
00644    struct ast_flags loader_flags = { 0 };
00645 
00646    memset(&q, 0, sizeof(q));
00647 
00648    if (!file || !strcmp (file, "res_config_odbc.conf"))
00649       return NULL;      /* cant configure myself with myself ! */
00650 
00651    obj = ast_odbc_request_obj(database, 0);
00652    if (!obj)
00653       return NULL;
00654 
00655    ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
00656    ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
00657    ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
00658    q.sql = sqlbuf;
00659 
00660    stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
00661 
00662    if (!stmt) {
00663       ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
00664       ast_odbc_release_obj(obj);
00665       return NULL;
00666    }
00667 
00668    res = SQLNumResultCols(stmt, &rowcount);
00669 
00670    if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
00671       ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
00672       SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00673       ast_odbc_release_obj(obj);
00674       return NULL;
00675    }
00676 
00677    if (!rowcount) {
00678       ast_log(LOG_NOTICE, "found nothing\n");
00679       ast_odbc_release_obj(obj);
00680       return cfg;
00681    }
00682 
00683    cur_cat = ast_config_get_current_category(cfg);
00684 
00685    while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
00686       if (!strcmp (q.var_name, "#include")) {
00687          if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "", who_asked)) {
00688             SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00689             ast_odbc_release_obj(obj);
00690             return NULL;
00691          }
00692          continue;
00693       } 
00694       if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
00695          cur_cat = ast_category_new(q.category, "", 99999);
00696          if (!cur_cat) {
00697             ast_log(LOG_WARNING, "Out of memory!\n");
00698             break;
00699          }
00700          strcpy(last, q.category);
00701          last_cat_metric   = q.cat_metric;
00702          ast_category_append(cfg, cur_cat);
00703       }
00704 
00705       new_v = ast_variable_new(q.var_name, q.var_val, "");
00706       ast_variable_append(cur_cat, new_v);
00707    }
00708 
00709    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
00710    ast_odbc_release_obj(obj);
00711    return cfg;
00712 }
00713 
00714 static struct ast_config_engine odbc_engine = {
00715    .name = "odbc",
00716    .load_func = config_odbc,
00717    .realtime_func = realtime_odbc,
00718    .realtime_multi_func = realtime_multi_odbc,
00719    .store_func = store_odbc,
00720    .destroy_func = destroy_odbc,
00721    .update_func = update_odbc
00722 };
00723 
00724 static int unload_module (void)
00725 {
00726    ast_config_engine_deregister(&odbc_engine);
00727    ast_verb(1, "res_config_odbc unloaded.\n");
00728    return 0;
00729 }
00730 
00731 static int load_module (void)
00732 {
00733    ast_config_engine_register(&odbc_engine);
00734    ast_verb(1, "res_config_odbc loaded.\n");
00735    return 0;
00736 }
00737 
00738 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Realtime ODBC configuration",
00739       .load = load_module,
00740       .unload = unload_module,
00741       );

Generated on Thu Jul 9 13:40:39 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7