avpops_db.c

Go to the documentation of this file.
00001 /*
00002  * $Id: avpops_db.c 5585 2009-02-10 21:39:56Z miconda $
00003  *
00004  * Copyright (C) 2004-2006 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00021  *
00022  * History:
00023  * ---------
00024  *  2004-10-04  first version (ramona)
00025  *  2004-11-11  added support for db schemes for avp_db_load (ramona)
00026  */
00027 
00028 
00029 #include <stdlib.h>
00030 #include <string.h>
00031 
00032 #include "../../mem/mem.h"
00033 #include "../../mem/shm_mem.h"
00034 #include "../../db/db.h"
00035 #include "../../dprint.h"
00036 #include "avpops_parse.h"
00037 #include "avpops_db.h"
00038 
00039 
00040 static db_con_t  *db_hdl=0;     /* DB handler */
00041 static db_func_t avpops_dbf;    /* DB functions */
00042 static str       def_table;    /* default DB table */
00043 static str      **db_columns;  /* array with names of DB columns */
00044 
00045 static db_key_t   keys_cmp[3]; /* array of keys and values used in selection */
00046 static db_val_t   vals_cmp[3]; /* statement as in "select" and "delete" */
00047 
00048 /* linked list with all defined DB schemes */
00049 static struct db_scheme  *db_scheme_list=0;
00050 
00051 
00052 int avpops_db_bind(const str* db_url)
00053 {
00054    if (db_bind_mod(db_url, &avpops_dbf ))
00055    {
00056       LM_CRIT("cannot bind to database module! "
00057          "Did you load a database module ?\n");
00058       return -1;
00059    }
00060 
00061    if (!DB_CAPABILITY(avpops_dbf, DB_CAP_ALL))
00062    {
00063       LM_CRIT("database modules does not "
00064          "provide all functions needed by avpops module\n");
00065       return -1;
00066    }
00067 
00068    return 0;
00069 
00070 }
00071 
00072 
00073 int avpops_db_init(const str* db_url, const str* db_table, str** db_cols)
00074 {
00075    
00076    db_hdl = avpops_dbf.init(db_url);
00077    if (db_hdl==0)
00078    {
00079       LM_ERR("cannot initialize database connection\n");
00080       goto error;
00081    }
00082    if (avpops_dbf.use_table(db_hdl, db_table)<0)
00083    {
00084       LM_ERR("cannot select table \"%.*s\"\n", db_table->len, db_table->s);
00085       goto error;
00086    }
00087    def_table.s = db_table->s;
00088    def_table.len = db_table->len;
00089    db_columns = db_cols;
00090 
00091    return 0;
00092 error:
00093    if (db_hdl)
00094    {
00095       avpops_dbf.close(db_hdl);
00096       db_hdl=0;
00097    }
00098    return -1;
00099 }
00100 
00101 
00102 int avp_add_db_scheme( modparam_t type, void* val)
00103 {
00104    struct db_scheme *scheme;
00105 
00106    scheme = (struct db_scheme*)pkg_malloc( sizeof(struct db_scheme) );
00107    if (scheme==0)
00108    {
00109       LM_ERR("no more pkg memory\n");
00110       goto error;
00111    }
00112    memset( scheme, 0, sizeof(struct db_scheme));
00113 
00114    /* parse the scheme */
00115    if ( parse_avp_db_scheme( (char*)val, scheme)!=0 )
00116    {
00117       LM_ERR("failed to parse scheme\n");
00118       goto error;
00119    }
00120 
00121    /* check for duplicates */
00122    if ( avp_get_db_scheme(&scheme->name)!=0 )
00123    {
00124       LM_ERR("duplicated scheme name <%.*s>\n",
00125          scheme->name.len,scheme->name.s);
00126       goto error;
00127    }
00128 
00129    /* print scheme */
00130    LM_DBG("new scheme <%.*s> added\n"
00131       "\t\tuuid_col=<%.*s>\n\t\tusername_col=<%.*s>\n"
00132       "\t\tdomain_col=<%.*s>\n\t\tvalue_col=<%.*s>\n"
00133       "\t\tdb_flags=%d\n\t\ttable=<%.*s>\n",
00134       scheme->name.len,scheme->name.s,
00135       scheme->uuid_col.len, scheme->uuid_col.s, scheme->username_col.len,
00136       scheme->username_col.s, scheme->domain_col.len, scheme->domain_col.s,
00137       scheme->value_col.len, scheme->value_col.s, scheme->db_flags,
00138       scheme->table.len, scheme->table.s);
00139 
00140    scheme->next = db_scheme_list;
00141    db_scheme_list = scheme;
00142 
00143    return 0;
00144 error:
00145    return -1;
00146 }
00147 
00148 
00149 struct db_scheme *avp_get_db_scheme (str *name)
00150 {
00151    struct db_scheme *scheme;
00152 
00153    for( scheme=db_scheme_list ; scheme ; scheme=scheme->next )
00154       if ( name->len==scheme->name.len &&
00155       !strcasecmp( name->s, scheme->name.s) )
00156          return scheme;
00157    return 0;
00158 }
00159 
00160 
00161 static inline int set_table( const str *table, char *func)
00162 {
00163    if (table && table->s)
00164    {
00165       if ( avpops_dbf.use_table( db_hdl, table)<0 )
00166       {
00167          LM_ERR("db-%s: cannot set table \"%.*s\"\n", func, table->len, table->s);
00168          return -1;
00169       }
00170    } else {
00171       if ( avpops_dbf.use_table( db_hdl, &def_table)<0 )
00172       {
00173          LM_ERR("db-%s: cannot set table \"%.*s\"\n", func, def_table.len, def_table.s);
00174          return -1;
00175       }
00176    }
00177    return 0;
00178 }
00179 
00180 
00181 
00182 static inline int prepare_selection( str *uuid, str *username, str *domain,
00183                               char *attr, struct db_scheme *scheme)
00184 {
00185    unsigned int nr_keys_cmp;
00186 
00187    nr_keys_cmp = 0;
00188    if (uuid)
00189    {
00190       /* uuid column */
00191       keys_cmp[ nr_keys_cmp ] =
00192          (scheme&&scheme->uuid_col.s)?&scheme->uuid_col:db_columns[0];
00193       vals_cmp[ nr_keys_cmp ].type = DB_STR;
00194       vals_cmp[ nr_keys_cmp ].nul  = 0;
00195       vals_cmp[ nr_keys_cmp ].val.str_val = *uuid;
00196       nr_keys_cmp++;
00197    } else {
00198       if (username)
00199       {
00200          /* username column */
00201          keys_cmp[ nr_keys_cmp ] =
00202          (scheme&&scheme->username_col.s)?&scheme->username_col:db_columns[4];
00203          vals_cmp[ nr_keys_cmp ].type = DB_STR;
00204          vals_cmp[ nr_keys_cmp ].nul  = 0;
00205          vals_cmp[ nr_keys_cmp ].val.str_val = *username;
00206          nr_keys_cmp++;
00207       }
00208       if (domain)
00209       {
00210          /* domain column */
00211          keys_cmp[ nr_keys_cmp ] =
00212          (scheme&&scheme->domain_col.s)?&scheme->domain_col:db_columns[5];
00213          vals_cmp[ nr_keys_cmp ].type = DB_STR;
00214          vals_cmp[ nr_keys_cmp ].nul  = 0;
00215          vals_cmp[ nr_keys_cmp ].val.str_val = *domain;
00216          nr_keys_cmp++;
00217       }
00218    }
00219    if (attr && scheme==0)
00220    {
00221       /* attribute name column */
00222       keys_cmp[ nr_keys_cmp ] = db_columns[1];
00223       vals_cmp[ nr_keys_cmp ].type = DB_STRING;
00224       vals_cmp[ nr_keys_cmp ].nul  = 0;
00225       vals_cmp[ nr_keys_cmp ].val.string_val = attr;
00226       nr_keys_cmp++;
00227    }
00228    return nr_keys_cmp;
00229 }
00230 
00231 
00232 db_res_t *db_load_avp( str *uuid, str *username, str *domain,
00233                      char *attr, const str *table, struct db_scheme *scheme)
00234 {
00235    static db_key_t   keys_ret[3];
00236    unsigned int      nr_keys_cmp;
00237    unsigned int      nr_keys_ret;
00238    db_res_t          *res = NULL;
00239 
00240    /* prepare DB query */
00241    nr_keys_cmp = prepare_selection( uuid, username, domain, attr, scheme);
00242 
00243    /* set table */
00244    if (set_table( scheme?&scheme->table:table ,"load")!=0)
00245       return 0;
00246 
00247    /* return keys */
00248    if (scheme==0)
00249    {
00250       keys_ret[0] = db_columns[2]; /*value*/
00251       keys_ret[1] = db_columns[1]; /*attribute*/
00252       keys_ret[2] = db_columns[3]; /*type*/
00253       nr_keys_ret = 3;
00254    } else {
00255       /* value */
00256       keys_ret[0] = scheme->value_col.s?&scheme->value_col:db_columns[2];
00257       nr_keys_ret = 1;
00258    }
00259 
00260    /* do the DB query */
00261    if ( avpops_dbf.query( db_hdl, keys_cmp, 0/*op*/, vals_cmp, keys_ret,
00262          nr_keys_cmp, nr_keys_ret, 0/*order*/, &res) < 0)
00263       return 0;
00264 
00265    return res;
00266 }
00267 
00268 
00269 void db_close_query( db_res_t *res )
00270 {
00271    LM_DBG("close avp query\n");
00272    avpops_dbf.free_result( db_hdl, res);
00273 }
00274 
00275 
00276 int db_store_avp( db_key_t *keys, db_val_t *vals, int n, const str *table)
00277 {
00278    int r;
00279    if (set_table( table ,"store")!=0)
00280       return -1;
00281 
00282    r = avpops_dbf.insert( db_hdl, keys, vals, n);
00283    if (r<0)
00284    {
00285       LM_ERR("insert failed\n");
00286       return -1;
00287    }
00288    return 0;
00289 }
00290 
00291 
00292 
00293 int db_delete_avp( str *uuid, str *username, str *domain, char *attr,
00294                                              const str *table)
00295 {
00296    unsigned int  nr_keys_cmp;
00297 
00298    /* prepare DB query */
00299    nr_keys_cmp = prepare_selection( uuid, username, domain, attr, 0);
00300 
00301    /* set table */
00302    if (set_table( table ,"delete")!=0)
00303       return -1;
00304 
00305    /* do the DB query */
00306    if ( avpops_dbf.delete( db_hdl, keys_cmp, 0, vals_cmp, nr_keys_cmp) < 0)
00307       return 0;
00308 
00309    return 0;
00310 }
00311 
00312 int db_query_avp(struct sip_msg *msg, char *query, pvname_list_t* dest)
00313 {
00314    int_str avp_val;
00315    int_str avp_name;
00316    unsigned short avp_type;
00317    db_res_t* db_res = NULL;
00318    int i, j;
00319    pvname_list_t* crt;
00320    static str query_str;
00321    
00322    if(query==NULL)
00323    {
00324       LM_ERR("bad parameter\n");
00325       return -1;
00326    }
00327    
00328    query_str.s = query;
00329    query_str.len = strlen(query);
00330    
00331    if(avpops_dbf.raw_query(db_hdl, &query_str, &db_res)!=0)
00332    {
00333       LM_ERR("cannot do the query\n");
00334       return -1;
00335    }
00336 
00337    if(db_res==NULL || RES_ROW_N(db_res)<=0 || RES_COL_N(db_res)<=0)
00338    {
00339       LM_DBG("no result after query\n");
00340       db_close_query( db_res );
00341       return -2;
00342    }
00343 
00344    LM_DBG("rows [%d]\n", RES_ROW_N(db_res));
00345    /* reverse order of rows so that first row get's in front of avp list */
00346    for(i = RES_ROW_N(db_res)-1; i >= 0; i--) 
00347    {
00348       LM_DBG("row [%d]\n", i);
00349       crt = dest;
00350       for(j = 0; j < RES_COL_N(db_res); j++) 
00351       {
00352          if(RES_ROWS(db_res)[i].values[j].nul)
00353             goto next_avp;
00354          avp_type = 0;
00355          if(crt==NULL)
00356          {
00357             avp_name.n = j+1;
00358          } else {
00359             if(pv_get_avp_name(msg, &crt->sname.pvp, &avp_name,
00360                      &avp_type)!=0)
00361             {
00362                LM_ERR("cant get avp name [%d/%d]\n", i, j);
00363                goto next_avp;
00364             }
00365          }
00366          switch(RES_ROWS(db_res)[i].values[j].type)
00367          {
00368             case DB_STRING:
00369                avp_type |= AVP_VAL_STR;
00370                avp_val.s.s=
00371                   (char*)RES_ROWS(db_res)[i].values[j].val.string_val;
00372                avp_val.s.len=strlen(avp_val.s.s);
00373                if(avp_val.s.len<=0)
00374                   goto next_avp;
00375             break;
00376             case DB_STR:
00377                avp_type |= AVP_VAL_STR;
00378                avp_val.s.len=
00379                   RES_ROWS(db_res)[i].values[j].val.str_val.len;
00380                avp_val.s.s=
00381                   (char*)RES_ROWS(db_res)[i].values[j].val.str_val.s;
00382                if(avp_val.s.len<=0)
00383                   goto next_avp;
00384             break;
00385             case DB_BLOB:
00386                avp_type |= AVP_VAL_STR;
00387                avp_val.s.len=
00388                   RES_ROWS(db_res)[i].values[j].val.blob_val.len;
00389                avp_val.s.s=
00390                   (char*)RES_ROWS(db_res)[i].values[j].val.blob_val.s;
00391                if(avp_val.s.len<=0)
00392                   goto next_avp;
00393             break;
00394             case DB_INT:
00395                avp_val.n
00396                   = (int)RES_ROWS(db_res)[i].values[j].val.int_val;
00397             break;
00398             case DB_DATETIME:
00399                avp_val.n
00400                   = (int)RES_ROWS(db_res)[i].values[j].val.time_val;
00401             break;
00402             case DB_BITMAP:
00403                avp_val.n
00404                   = (int)RES_ROWS(db_res)[i].values[j].val.bitmap_val;
00405             break;
00406             default:
00407                goto next_avp;
00408          }
00409          if(add_avp(avp_type, avp_name, avp_val)!=0)
00410          {
00411             LM_ERR("unable to add avp\n");
00412             db_close_query( db_res );
00413             return -1;
00414          }
00415 next_avp:
00416          if(crt)
00417          {
00418             crt = crt->next;
00419             if(crt==NULL)
00420                break;
00421          }
00422       }
00423    }
00424 
00425    db_close_query( db_res );
00426    return 0;
00427 }

Generated on Thu May 17 12:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6