db_berkeley.c

Go to the documentation of this file.
00001 /*
00002  * $Id: db_berkeley.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * db_berkeley module, portions of this code were templated using
00005  * the dbtext and postgres modules.
00006 
00007  * Copyright (C) 2007 Cisco Systems
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  * 
00025  * History:
00026  * --------
00027  * 2007-09-19  genesis (wiquan)
00028  */
00029 
00030 #include <stdio.h>
00031 #include <unistd.h>
00032 #include <sys/stat.h>
00033 
00034 
00035 #include "../../str.h"
00036 #include "../../ut.h"
00037 #include "../../mem/mem.h"
00038 
00039 #include "../../sr_module.h"
00040 #include "../../db/db_res.h"
00041 #include "../../db/db.h"
00042 #include "db_berkeley.h"
00043 #include "bdb_lib.h"
00044 #include "bdb_res.h"
00045 #include "bdb_mi.h"
00046 
00047 #ifndef CFG_DIR
00048 #define CFG_DIR "/tmp"
00049 #endif
00050 
00051 #define BDB_ID    "berkeley://"
00052 #define BDB_ID_LEN   (sizeof(BDB_ID)-1)
00053 #define BDB_PATH_LEN 256
00054 
00055 #define BDB_KEY   1
00056 #define BDB_VALUE 0
00057 
00058 MODULE_VERSION
00059 
00060 int auto_reload = 0;
00061 int log_enable  = 0;
00062 int journal_roll_interval = 0;
00063 
00064 static int mod_init(void);
00065 static void destroy(void);
00066 
00067 int bdb_bind_api(db_func_t *dbb);
00068 
00069 /*
00070  * Exported functions
00071  */
00072 static cmd_export_t cmds[] = {
00073    {"db_bind_api",    (cmd_function)bdb_bind_api,   0, 0, 0, 0},
00074    {0, 0, 0, 0, 0, 0}
00075 };
00076 
00077 
00078 /*
00079  * Exported parameters
00080  */
00081 static param_export_t params[] = {
00082    {"auto_reload",        INT_PARAM, &auto_reload },
00083    {"log_enable",         INT_PARAM, &log_enable  },
00084    {"journal_roll_interval", INT_PARAM, &journal_roll_interval  },
00085    {0, 0, 0}
00086 };
00087 
00088 /*
00089  * Exported MI functions
00090  */
00091 static mi_export_t mi_cmds[] = {
00092    { MI_BDB_RELOAD, mi_bdb_reload, 0, 0, 0 },
00093    { 0, 0, 0, 0, 0}
00094 };
00095 
00096 struct module_exports exports = {   
00097    "db_berkeley",
00098    DEFAULT_DLFLAGS, /* dlopen flags */
00099    cmds,     /* Exported functions */
00100    params,   /* Exported parameters */
00101    0,        /* exported statistics */
00102    mi_cmds,  /* exported MI functions */
00103    0,        /* exported pseudo-variables */
00104    0,        /* extra processes */
00105    mod_init, /* module initialization function */
00106    0,        /* response function*/
00107    destroy,  /* destroy function */
00108    0         /* per-child init function */
00109 };
00110 
00111 
00112 static int mod_init(void)
00113 {
00114    db_parms_t p;
00115    
00116    p.auto_reload = auto_reload;
00117    p.log_enable = log_enable;
00118    p.cache_size  = (4 * 1024 * 1024); //4Mb
00119    p.journal_roll_interval = journal_roll_interval;
00120    
00121    if(bdblib_init(&p))
00122       return -1;
00123 
00124    return 0;
00125 }
00126 
00127 static void destroy(void)
00128 {
00129    bdblib_destroy();
00130 }
00131 
00132 int bdb_bind_api(db_func_t *dbb)
00133 {
00134    if(dbb==NULL)
00135       return -1;
00136 
00137    memset(dbb, 0, sizeof(db_func_t));
00138 
00139    dbb->use_table   = bdb_use_table;
00140    dbb->init        = bdb_init;
00141    dbb->close       = bdb_close;
00142    dbb->query       = (db_query_f)bdb_query;
00143    dbb->free_result = bdb_free_query;
00144    dbb->insert      = (db_insert_f)bdb_insert;
00145    dbb->delete      = (db_delete_f)bdb_delete; 
00146    dbb->update      = (db_update_f)bdb_update;
00147 
00148    return 0;
00149 }
00150 
00151 int bdb_use_table(db_con_t* _h, const str* _t)
00152 {
00153    return db_use_table(_h, _t);
00154 }
00155 
00156 /*
00157  * Initialize database connection
00158  */
00159 db_con_t* bdb_init(const str* _sqlurl)
00160 {
00161    db_con_t* _res;
00162    str _s;
00163    char bdb_path[BDB_PATH_LEN];
00164    
00165    if (!_sqlurl || !_sqlurl->s) {
00166       LM_ERR("invalid parameter value\n");
00167       return 0;
00168    }
00169    
00170    _s.s = _sqlurl->s;
00171    _s.len = _sqlurl->len;
00172    if(_s.len <= BDB_ID_LEN || strncmp(_s.s, BDB_ID, BDB_ID_LEN)!=0)
00173    {
00174       LM_ERR("invalid database URL - should be:"
00175          " <%s[/]path/to/directory>\n", BDB_ID);
00176       return NULL;
00177    }
00178    _s.s   += BDB_ID_LEN;
00179    _s.len -= BDB_ID_LEN;
00180    
00181    if(_s.s[0]!='/')
00182    {
00183       if(sizeof(CFG_DIR)+_s.len+2 > BDB_PATH_LEN)
00184       {
00185          LM_ERR("path to database is too long\n");
00186          return NULL;
00187       }
00188       strcpy(bdb_path, CFG_DIR);
00189       bdb_path[sizeof(CFG_DIR)] = '/';
00190       strncpy(&bdb_path[sizeof(CFG_DIR)+1], _s.s, _s.len);
00191       _s.len += sizeof(CFG_DIR);
00192       _s.s = bdb_path;
00193    }
00194    
00195    _res = pkg_malloc(sizeof(db_con_t)+sizeof(bdb_con_t));
00196    if (!_res)
00197    {
00198       LM_ERR("No private memory left\n");
00199       return NULL;
00200    }
00201    memset(_res, 0, sizeof(db_con_t) + sizeof(bdb_con_t));
00202    _res->tail = (unsigned long)((char*)_res+sizeof(db_con_t));
00203 
00204    LM_INFO("using database at: %.*s", _s.len, _s.s);
00205    BDB_CON_CONNECTION(_res) = bdblib_get_db(&_s);
00206    if (!BDB_CON_CONNECTION(_res))
00207    {
00208       LM_ERR("cannot get the link to database\n");
00209       return NULL;
00210    }
00211 
00212     return _res;
00213 }
00214 
00215 
00216 /*
00217  * Close a database connection
00218  */
00219 void bdb_close(db_con_t* _h)
00220 {
00221    if(BDB_CON_RESULT(_h))
00222       db_free_result(BDB_CON_RESULT(_h));
00223    pkg_free(_h);
00224 }
00225 
00226 /* 
00227  * n can be the dbenv path or a table name
00228 */
00229 int bdb_reload(char* _n)
00230 {
00231    int rc = 0;
00232 #ifdef BDB_EXTRA_DEBUG
00233    LM_DBG("[bdb_reload] Initiate RELOAD in %s\n", _n);
00234 #endif
00235 
00236    if ((rc = bdblib_close(_n)) != 0) 
00237    {  LM_ERR("[bdb_reload] Error while closing db_berkeley DB.\n");
00238       return rc;
00239    }
00240 
00241    if ((rc = bdblib_reopen(_n)) != 0) 
00242    {  LM_ERR("[bdb_reload] Error while reopening db_berkeley DB.\n");
00243       return rc;
00244    }
00245 
00246 #ifdef BDB_EXTRA_DEBUG
00247    LM_DBG("[bdb_reload] RELOAD successful in %s\n", _n);
00248 #endif
00249 
00250    return rc;
00251 }
00252 
00253 /*
00254  * Attempts to reload a Berkeley database; reloads when the inode changes
00255  */
00256 void bdb_check_reload(db_con_t* _con)
00257 {
00258    str s;
00259    char* p;
00260    int rc, len;
00261    struct stat st;
00262    database_p db;
00263    char n[MAX_ROW_SIZE];
00264    char t[MAX_TABLENAME_SIZE];
00265    table_p tp = NULL;
00266    tbl_cache_p tbc = NULL;
00267    
00268    p=n;
00269    rc = len = 0;
00270    
00271    /*get dbenv name*/
00272    db = BDB_CON_CONNECTION(_con);
00273    if(!db->dbenv) return;
00274    s.s = db->name.s;
00275    s.len = db->name.len;
00276    len+=s.len;
00277    
00278    if(len > MAX_ROW_SIZE)
00279    {  LM_ERR("dbenv name too long \n");
00280       return;
00281    }
00282    
00283    strncpy(p, s.s, s.len);
00284    p+=s.len;
00285    
00286    len++;
00287    if(len > MAX_ROW_SIZE)
00288    {  LM_ERR("dbenv name too long \n");
00289       return;
00290    }
00291    
00292    /*append slash */
00293    *p = '/';
00294    p++;
00295    
00296    /*get table name*/
00297    s.s = CON_TABLE(_con)->s;
00298    s.len = CON_TABLE(_con)->len;
00299    len+=s.len;
00300    
00301    if((len>MAX_ROW_SIZE) || (s.len > MAX_TABLENAME_SIZE) )
00302    {  LM_ERR("table name too long \n");
00303       return;
00304    }
00305 
00306    strncpy(t, s.s, s.len);
00307    t[s.len] = 0;
00308    
00309    strncpy(p, s.s, s.len);
00310    p+=s.len;
00311    *p=0;
00312    
00313    if( (tbc = bdblib_get_table(db, &s)) == NULL)
00314       return;
00315    
00316    if( (tp = tbc->dtp) == NULL)
00317       return;
00318    
00319    LM_DBG("stat file [%.*s]\n", len, n);
00320    rc = stat(n, &st);
00321    if(!rc)
00322    {  if((tp->ino!=0) && (st.st_ino != tp->ino))
00323          bdb_reload(t); /*file changed on disk*/
00324       
00325       tp->ino = st.st_ino;
00326    }
00327 
00328 }
00329 
00330 
00331 /*
00332  * Free all memory allocated by get_result
00333  */
00334 int bdb_free_query(db_con_t* _h, db_res_t* _r)
00335 {
00336    if(_r)
00337       db_free_result(_r);
00338    if(_h)
00339       BDB_CON_RESULT(_h) = NULL;
00340    return 0;
00341 }
00342 
00343 
00344 /*
00345  * Query table for specified rows
00346  * _con: structure representing database connection
00347  * _k: key names
00348  * _op: operators
00349  * _v: values of the keys that must match
00350  * _c: column names to return
00351  * _n: number of key=values pairs to compare
00352  * _nc: number of columns to return
00353  * _o: order by the specified column
00354  */
00355 int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, 
00356          db_key_t* _c, int _n, int _nc, db_key_t _o, db_res_t** _r)
00357 {
00358    tbl_cache_p _tbc = NULL;
00359    table_p _tp = NULL;
00360    char kbuf[MAX_ROW_SIZE];
00361    char dbuf[MAX_ROW_SIZE];
00362    u_int32_t i, len, ret; 
00363    int klen=MAX_ROW_SIZE;
00364    int *lkey=NULL, *lres=NULL;
00365    DBT key, data;
00366    DB *db;
00367    DBC *dbcp;
00368 
00369    if ((!_con) || (!_r) || !CON_TABLE(_con))
00370    {
00371 #ifdef BDB_EXTRA_DEBUG
00372       LM_ERR("Invalid parameter value\n");
00373 #endif
00374       return -1;
00375    }
00376    *_r = NULL;
00377    
00378    /*check if underlying DB file has changed inode */
00379    if(auto_reload)
00380       bdb_check_reload(_con);
00381 
00382    _tbc = bdblib_get_table(BDB_CON_CONNECTION(_con), (str*)CON_TABLE(_con));
00383    if(!_tbc)
00384    {  LM_WARN("table does not exist!\n");
00385       return -1;
00386    }
00387 
00388    _tp = _tbc->dtp;
00389    if(!_tp)
00390    {  LM_WARN("table not loaded!\n");
00391       return -1;
00392    }
00393 
00394 #ifdef BDB_EXTRA_DEBUG
00395    LM_DBG("QUERY in %.*s\n", _tp->name.len, _tp->name.s);
00396 
00397    if (_o)  LM_DBG("DONT-CARE : _o: order by the specified column \n");
00398    if (_op) LM_DBG("DONT-CARE : _op: operators for refining query \n");
00399 #endif
00400    
00401    db = _tp->db;
00402    if(!db) return -1;
00403    
00404    memset(&key, 0, sizeof(DBT));
00405    memset(kbuf, 0, MAX_ROW_SIZE);
00406    memset(&data, 0, sizeof(DBT));
00407    memset(dbuf, 0, MAX_ROW_SIZE);
00408    
00409    data.data = dbuf;
00410    data.ulen = MAX_ROW_SIZE;
00411    data.flags = DB_DBT_USERMEM;
00412 
00413    /* if _c is NULL and _nc is zero, you will get all table 
00414       columns in the result
00415    */
00416    if (_c)
00417    {  lres = bdb_get_colmap(_tbc->dtp, _c, _nc);
00418       if(!lres)
00419       {  ret = -1;
00420          goto error;
00421       }
00422    }
00423    
00424    if(_k)
00425    {  lkey = bdb_get_colmap(_tbc->dtp, _k, _n);
00426       if(!lkey) 
00427       {  ret = -1;
00428          goto error;
00429       }
00430    }
00431    else
00432    {
00433       DB_HASH_STAT st;
00434       memset(&st, 0, sizeof(DB_HASH_STAT));
00435       i =0 ;
00436 
00437 #ifdef BDB_EXTRA_DEBUG
00438       LM_DBG("SELECT * FROM %.*s\n", _tp->name.len, _tp->name.s);
00439 #endif
00440 
00441       /* Acquire a cursor for the database. */
00442       if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) 
00443       {  LM_ERR("Error creating cursor\n");
00444          goto error;
00445       }
00446       
00447       /*count the number of records*/
00448       while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0)
00449       {  if(!strncasecmp((char*)key.data,"METADATA",8)) 
00450             continue;
00451          i++;
00452       }
00453       
00454       dbcp->c_close(dbcp);
00455       ret=0;
00456       
00457 #ifdef BDB_EXTRA_DEBUG
00458       LM_DBG("%i = SELECT COUNT(*) FROM %.*s\n", i, _tp->name.len, _tp->name.s);
00459 #endif
00460 
00461       *_r = db_new_result();
00462       if (!*_r) 
00463       {  LM_ERR("no memory left for result \n");
00464          ret = -2;
00465          goto error;
00466       }
00467       
00468       if(i == 0)
00469       {  
00470          /*return empty table*/
00471          RES_ROW_N(*_r) = 0;
00472          BDB_CON_RESULT(_con) = *_r;
00473          return 0;
00474       }
00475       
00476       /*allocate N rows in the result*/
00477       RES_ROW_N(*_r) = i;
00478       len  = sizeof(db_row_t) * i;
00479       RES_ROWS(*_r) = (db_row_t*)pkg_malloc( len );
00480       memset(RES_ROWS(*_r), 0, len);
00481       
00482       /*fill in the column part of db_res_t (metadata) */
00483       if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) 
00484       {  LM_ERR("Error while getting column names\n");
00485          goto error;
00486       }
00487       
00488       /* Acquire a cursor for the database. */
00489       if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) 
00490       {  LM_ERR("Error creating cursor\n");
00491          goto error;
00492       }
00493 
00494       /*convert each record into a row in the result*/
00495       i =0 ;
00496       while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0)
00497       {
00498          if(!strncasecmp((char*)key.data,"METADATA",8)) 
00499             continue;
00500          
00501 #ifdef BDB_EXTRA_DEBUG
00502       LM_DBG("KEY: [%.*s]\nDATA: [%.*s]\n"
00503          , (int)   key.size
00504          , (char *)key.data
00505          , (int)   data.size
00506          , (char *)data.data);
00507 #endif
00508 
00509          /*fill in the row part of db_res_t */
00510          if ((ret=bdb_append_row( *_r, dbuf, lres, i)) < 0) 
00511          {  LM_ERR("Error while converting row\n");
00512             goto error;
00513          }
00514          i++;
00515       }
00516       
00517       dbcp->c_close(dbcp);
00518       BDB_CON_RESULT(_con) = *_r;
00519       return 0; 
00520    }
00521 
00522    if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) 
00523    {  LM_ERR("error in query key \n");
00524       goto error;
00525    }
00526 
00527    key.data = kbuf;
00528    key.ulen = MAX_ROW_SIZE;
00529    key.flags = DB_DBT_USERMEM;
00530    key.size = klen;
00531 
00532    data.data = dbuf;
00533    data.ulen = MAX_ROW_SIZE;
00534    data.flags = DB_DBT_USERMEM;
00535 
00536    /*create an empty db_res_t which gets returned even if no result*/
00537    *_r = db_new_result();
00538    if (!*_r) 
00539    {  LM_ERR("no memory left for result \n");
00540       ret = -2;
00541       goto error;
00542    }
00543    RES_ROW_N(*_r) = 0;
00544    BDB_CON_RESULT(_con) = *_r;
00545 
00546 #ifdef BDB_EXTRA_DEBUG
00547       LM_DBG("SELECT  KEY: [%.*s]\n"
00548          , (int)   key.size
00549          , (char *)key.data );
00550 #endif
00551 
00552    /*query Berkely DB*/
00553    if ((ret = db->get(db, NULL, &key, &data, 0)) == 0) 
00554    {
00555 #ifdef BDB_EXTRA_DEBUG
00556       LM_DBG("RESULT\nKEY:  [%.*s]\nDATA: [%.*s]\n"
00557          , (int)   key.size
00558          , (char *)key.data
00559          , (int)   data.size
00560          , (char *)data.data);
00561 #endif
00562 
00563       /*fill in the col part of db_res_t */
00564       if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) 
00565       {  LM_ERR("Error while getting column names\n");
00566          goto error;
00567       }
00568       /*fill in the row part of db_res_t */
00569       if ((ret=bdb_convert_row( *_r, dbuf, lres)) < 0) 
00570       {  LM_ERR("Error while converting row\n");
00571          goto error;
00572       }
00573       
00574    }
00575    else
00576    {  
00577       /*Berkeley DB error handler*/
00578       switch(ret)
00579       {
00580       
00581       case DB_NOTFOUND:
00582       
00583 #ifdef BDB_EXTRA_DEBUG
00584          LM_DBG("NO RESULT for QUERY \n");
00585 #endif
00586       
00587          ret=0;
00588          break;
00589       /*The following are all critical/fatal */
00590       case DB_LOCK_DEADLOCK:  
00591       // The operation was selected to resolve a deadlock. 
00592       case DB_SECONDARY_BAD:
00593       // A secondary index references a nonexistent primary key. 
00594       case DB_RUNRECOVERY:
00595       default:
00596          LM_CRIT("DB->get error: %s.\n", db_strerror(ret));
00597          bdblib_recover(_tp,ret);
00598          goto error;
00599       }
00600    }
00601    
00602    if(lkey)
00603       pkg_free(lkey);
00604    if(lres)
00605       pkg_free(lres);
00606    
00607    return ret;
00608    
00609 error:
00610    if(lkey)
00611       pkg_free(lkey);
00612    if(lres)
00613       pkg_free(lres);
00614    if(*_r) 
00615       db_free_result(*_r);
00616    *_r = NULL;
00617    
00618    return ret;
00619 }
00620 
00621 
00622 
00623 /*
00624  * Raw SQL query
00625  */
00626 int bdb_raw_query(db_con_t* _h, char* _s, db_res_t** _r)
00627 {
00628    LM_CRIT("DB RAW QUERY not implemented!\n");
00629    return -1;
00630 }
00631 
00632 /*
00633  * Insert a row into table
00634  */
00635 int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n)
00636 {
00637    tbl_cache_p _tbc = NULL;
00638    table_p _tp = NULL;
00639    char kbuf[MAX_ROW_SIZE];
00640    char dbuf[MAX_ROW_SIZE];
00641    int i, j, ret, klen, dlen;
00642    int *lkey=NULL;
00643    DBT key, data;
00644    DB *db;
00645 
00646    i = j = ret = 0;
00647    klen=MAX_ROW_SIZE;
00648    dlen=MAX_ROW_SIZE;
00649 
00650    if ((!_h) || (!_v) || !CON_TABLE(_h))
00651    {  return -1;
00652    }
00653 
00654    if (!_k)
00655    {
00656 #ifdef BDB_EXTRA_DEBUG
00657    LM_ERR("DB INSERT without KEYs not implemented! \n");
00658 #endif
00659       return -2;
00660    }
00661 
00662    _tbc = bdblib_get_table(BDB_CON_CONNECTION(_h), (str*)CON_TABLE(_h));
00663    if(!_tbc)
00664    {  LM_WARN("table does not exist!\n");
00665       return -3;
00666    }
00667 
00668    _tp = _tbc->dtp;
00669    if(!_tp)
00670    {  LM_WARN("table not loaded!\n");
00671       return -4;
00672    }
00673 
00674 #ifdef BDB_EXTRA_DEBUG
00675    LM_DBG("INSERT in %.*s\n", _tp->name.len, _tp->name.s );
00676 #endif
00677    
00678    db = _tp->db;
00679    memset(&key, 0, sizeof(DBT));
00680    memset(kbuf, 0, klen);
00681    
00682    if(_tp->ncols<_n) 
00683    {  LM_WARN("more values than columns!!\n");
00684       return -5;
00685    }
00686 
00687    lkey = bdb_get_colmap(_tp, _k, _n);
00688    if(!lkey)  return -7;
00689 
00690    /* verify col types provided */
00691    for(i=0; i<_n; i++)
00692    {  j = (lkey)?lkey[i]:i;
00693       if(bdb_is_neq_type(_tp->colp[j]->type, _v[i].type))
00694       {
00695          LM_WARN("incompatible types v[%d] - c[%d]!\n", i, j);
00696          ret = -8;
00697          goto error;
00698       }
00699    }
00700    
00701    /* make the key */
00702    if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) 
00703    {  LM_ERR("Error in bdblib_valtochar  \n");
00704       ret = -9;
00705       goto error;
00706    }
00707    
00708    key.data = kbuf;
00709    key.ulen = MAX_ROW_SIZE;
00710    key.flags = DB_DBT_USERMEM;
00711    key.size = klen;
00712 
00713    //make the value (row)
00714    memset(&data, 0, sizeof(DBT));
00715    memset(dbuf, 0, MAX_ROW_SIZE);
00716 
00717    if ( (ret = bdblib_valtochar(_tp, lkey, dbuf, &dlen, _v, _n, BDB_VALUE)) != 0 ) 
00718    {  LM_ERR("Error in bdblib_valtochar \n");
00719       ret = -9;
00720       goto error;
00721    }
00722 
00723    data.data = dbuf;
00724    data.ulen = MAX_ROW_SIZE;
00725    data.flags = DB_DBT_USERMEM;
00726    data.size = dlen;
00727 
00728    if ((ret = db->put(db, NULL, &key, &data, 0)) == 0) 
00729    {
00730       bdblib_log(JLOG_INSERT, _tp, dbuf, dlen);
00731 
00732 #ifdef BDB_EXTRA_DEBUG
00733    LM_DBG("INSERT\nKEY:  [%.*s]\nDATA: [%.*s]\n"
00734       , (int)   key.size
00735       , (char *)key.data
00736       , (int)   data.size
00737       , (char *)data.data);
00738 #endif
00739    }
00740    else
00741    {  /*Berkeley DB error handler*/
00742       switch(ret)
00743       {
00744       /*The following are all critical/fatal */
00745       case DB_LOCK_DEADLOCK:  
00746       /* The operation was selected to resolve a deadlock. */ 
00747       
00748       case DB_RUNRECOVERY:
00749       default:
00750          LM_CRIT("DB->put error: %s.\n", db_strerror(ret));
00751          bdblib_recover(_tp, ret);
00752          goto error;
00753       }
00754    }
00755    
00756 error:
00757    if(lkey)
00758       pkg_free(lkey);
00759    
00760    return ret;
00761 
00762 }
00763 
00764 /*
00765  * Delete a row from table
00766  *
00767  * To delete ALL rows:
00768  *   do Not specify any keys, or values, and _n <=0
00769  *
00770  */
00771 int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n)
00772 {
00773    tbl_cache_p _tbc = NULL;
00774    table_p _tp = NULL;
00775    char kbuf[MAX_ROW_SIZE];
00776    int i, j, ret, klen;
00777    int *lkey=NULL;
00778    DBT key;
00779    DB *db;
00780    DBC *dbcp;
00781 
00782    i = j = ret = 0;
00783    klen=MAX_ROW_SIZE;
00784 
00785    if (_op)
00786       return ( _bdb_delete_cursor(_h, _k, _op, _v, _n) );
00787 
00788    if ((!_h) || !CON_TABLE(_h))
00789       return -1;
00790 
00791    _tbc = bdblib_get_table(BDB_CON_CONNECTION(_h), (str*)CON_TABLE(_h));
00792    if(!_tbc)
00793    {  LM_WARN("table does not exist!\n");
00794       return -3;
00795    }
00796 
00797    _tp = _tbc->dtp;
00798    if(!_tp)
00799    {  LM_WARN("table not loaded!\n");
00800       return -4;
00801    }
00802 
00803 #ifdef BDB_EXTRA_DEBUG
00804       LM_DBG("DELETE in %.*s\n", _tp->name.len, _tp->name.s );
00805 #endif
00806 
00807    db = _tp->db;
00808    memset(&key, 0, sizeof(DBT));
00809    memset(kbuf, 0, klen);
00810 
00811    if(!_k || !_v || _n<=0)
00812    {
00813       /* Acquire a cursor for the database. */
00814       if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR) ) != 0) 
00815       {  LM_ERR("Error creating cursor\n");
00816          goto error;
00817       }
00818       
00819       while ((ret = dbcp->c_get(dbcp, &key, NULL, DB_NEXT)) == 0)
00820       {
00821          if(!strncasecmp((char*)key.data,"METADATA",8)) 
00822             continue;
00823 #ifdef BDB_EXTRA_DEBUG
00824          LM_DBG("KEY: [%.*s]\n"
00825             , (int)   key.size
00826             , (char *)key.data);
00827 #endif
00828          ret = dbcp->c_del(dbcp, 0);
00829       }
00830       
00831       dbcp->c_close(dbcp);
00832       return 0;
00833    }
00834 
00835    lkey = bdb_get_colmap(_tp, _k, _n);
00836    if(!lkey)  return -5;
00837 
00838    /* make the key */
00839    if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) 
00840    {  LM_ERR("Error in bdblib_makekey\n");
00841       ret = -6;
00842       goto error;
00843    }
00844 
00845    key.data = kbuf;
00846    key.ulen = MAX_ROW_SIZE;
00847    key.flags = DB_DBT_USERMEM;
00848    key.size = klen;
00849 
00850    if ((ret = db->del(db, NULL, &key, 0)) == 0)
00851    {
00852       bdblib_log(JLOG_DELETE, _tp, kbuf, klen);
00853 
00854 #ifdef BDB_EXTRA_DEBUG
00855       LM_DBG("DELETED ROW \n KEY: %s \n", (char *)key.data);
00856 #endif
00857    }
00858    else
00859    {  /*Berkeley DB error handler*/
00860       switch(ret){
00861          
00862       case DB_NOTFOUND:
00863          ret = 0;
00864          break;
00865          
00866       /*The following are all critical/fatal */
00867       case DB_LOCK_DEADLOCK:  
00868       /* The operation was selected to resolve a deadlock. */ 
00869       case DB_SECONDARY_BAD:
00870       /* A secondary index references a nonexistent primary key. */
00871       case DB_RUNRECOVERY:
00872       default:
00873          LM_CRIT("DB->del error: %s.\n"
00874             , db_strerror(ret));
00875          bdblib_recover(_tp, ret);
00876          goto error;
00877       }
00878    }
00879 
00880    ret = 0;
00881    
00882 error:
00883    if(lkey)
00884       pkg_free(lkey);
00885    
00886    return ret;
00887 
00888 }
00889 
00890 /*
00891 _bdb_delete_cursor -- called from bdb_delete when the query involves operators 
00892   other than equal '='. Adds support for queries like this:
00893    DELETE from SomeTable WHERE _k[0] < _v[0]
00894   In this case, the keys _k are not the actually schema keys, so we need to 
00895   iterate via cursor to perform this operation.
00896 */
00897 int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n)
00898 {
00899    tbl_cache_p _tbc = NULL;
00900    table_p _tp = NULL;
00901    db_res_t* _r   = NULL;
00902    char kbuf[MAX_ROW_SIZE];
00903    char dbuf[MAX_ROW_SIZE];
00904    int i, ret, klen=MAX_ROW_SIZE;
00905    DBT key, data;
00906    DB *db;
00907    DBC *dbcp;
00908    int *lkey=NULL;
00909    
00910    i = ret = 0;
00911    
00912    if ((!_h) || !CON_TABLE(_h))
00913       return -1;
00914 
00915    _tbc = bdblib_get_table(BDB_CON_CONNECTION(_h), (str*)CON_TABLE(_h));
00916    if(!_tbc)
00917    {  LM_WARN("table does not exist!\n");
00918       return -3;
00919    }
00920 
00921    _tp = _tbc->dtp;
00922    if(!_tp)
00923    {  LM_WARN("table not loaded!\n");
00924       return -4;
00925    }
00926    
00927 #ifdef BDB_EXTRA_DEBUG
00928    LM_DBG("DELETE by cursor in %.*s\n", _tp->name.len, _tp->name.s );
00929 #endif
00930 
00931    if(_k)
00932    {  lkey = bdb_get_colmap(_tp, _k, _n);
00933       if(!lkey) 
00934       {  ret = -1;
00935          goto error;
00936       }
00937    }
00938    
00939    /* create an empty db_res_t which gets returned even if no result */
00940    _r = db_new_result();
00941    if (!_r) 
00942    {  LM_ERR("no memory for result \n");
00943    }
00944    
00945    RES_ROW_N(_r) = 0;
00946    
00947    /* fill in the col part of db_res_t */
00948    if ((ret = bdb_get_columns(_tp, _r, 0, 0)) != 0) 
00949    {  LM_ERR("Error while getting column names\n");
00950       goto error;
00951    }
00952    
00953    db = _tp->db;
00954    memset(&key, 0, sizeof(DBT));
00955    memset(kbuf, 0, klen);
00956    memset(&data, 0, sizeof(DBT));
00957    memset(dbuf, 0, MAX_ROW_SIZE);
00958    
00959    data.data = dbuf;
00960    data.ulen = MAX_ROW_SIZE;
00961    data.flags = DB_DBT_USERMEM;
00962    
00963    /* Acquire a cursor for the database. */
00964    if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR)) != 0) 
00965    {  LM_ERR("Error creating cursor\n");
00966    }
00967    
00968    while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0)
00969    {
00970       if(!strncasecmp((char*)key.data,"METADATA",8))
00971          continue;
00972       
00973       /*fill in the row part of db_res_t */
00974       if ((ret=bdb_convert_row( _r, dbuf, 0)) < 0) 
00975       {  LM_ERR("Error while converting row\n");
00976          goto error;
00977       }
00978       
00979       if(bdb_row_match(_k, _op, _v, _n, _r, lkey ))
00980       {
00981 
00982 #ifdef BDB_EXTRA_DEBUG
00983          LM_DBG("DELETE ROW by KEY:  [%.*s]\n", (int) key.size, 
00984             (char *)key.data);
00985 #endif
00986 
00987          if((ret = dbcp->c_del(dbcp, 0)) != 0)
00988          {  
00989             /* Berkeley DB error handler */
00990             LM_CRIT("DB->get error: %s.\n", db_strerror(ret));
00991             bdblib_recover(_tp,ret);
00992          }
00993          
00994       }
00995       
00996       memset(dbuf, 0, MAX_ROW_SIZE);
00997       db_free_rows( _r);
00998    }
00999    ret = 0;
01000    
01001 error:
01002    if(dbcp)
01003       dbcp->c_close(dbcp);
01004    if(_r)
01005       db_free_result(_r);
01006    if(lkey)
01007       pkg_free(lkey);
01008    
01009    return ret;
01010 }
01011 
01012 /*
01013  * Updates a row in table
01014  * Limitation: only knows how to update a single row
01015  *
01016  * _con: structure representing database connection
01017  * _k: key names
01018  * _op: operators
01019  * _v: values of the keys that must match
01020  * _uk: update keys; cols that need to be updated 
01021  * _uv: update values; col values that need to be commited
01022  * _un: number of rows to update
01023  */
01024 int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v,
01025          db_key_t* _uk, db_val_t* _uv, int _n, int _un)
01026 {
01027    char *c, *t;
01028    int ret, i, qcol, len, sum;
01029    int *lkey=NULL;
01030    tbl_cache_p _tbc = NULL;
01031    table_p _tp = NULL;
01032    char kbuf[MAX_ROW_SIZE];
01033    char qbuf[MAX_ROW_SIZE];
01034    char ubuf[MAX_ROW_SIZE];
01035    DBT key, qdata, udata;
01036    DB *db;
01037    
01038    sum = ret = i = qcol = len = 0;
01039    
01040    if (!_con || !CON_TABLE(_con) || !_uk || !_uv || _un <= 0)
01041       return -1;
01042 
01043    _tbc = bdblib_get_table(BDB_CON_CONNECTION(_con), (str*)CON_TABLE(_con));
01044    if(!_tbc)
01045    {  LM_ERR("table does not exist\n");
01046       return -1;
01047    }
01048 
01049    _tp = _tbc->dtp;
01050    if(!_tp)
01051    {  LM_ERR("table not loaded\n");
01052       return -1;
01053    }
01054    
01055    db = _tp->db;
01056    if(!db)
01057    {  LM_ERR("DB null ptr\n");
01058       return -1;
01059    }
01060    
01061 #ifdef BDB_EXTRA_DEBUG
01062    LM_DBG("UPDATE in %.*s\n", _tp->name.len, _tp->name.s);
01063    if (_op) LM_DBG("DONT-CARE : _op: operators for refining query \n");
01064 #endif
01065    
01066    memset(&key, 0, sizeof(DBT));
01067    memset(kbuf, 0, MAX_ROW_SIZE);
01068    memset(&qdata, 0, sizeof(DBT));
01069    memset(qbuf, 0, MAX_ROW_SIZE);
01070    
01071    qdata.data = qbuf;
01072    qdata.ulen = MAX_ROW_SIZE;
01073    qdata.flags = DB_DBT_USERMEM;
01074    
01075    if(_k)
01076    {  lkey = bdb_get_colmap(_tbc->dtp, _k, _n);
01077       if(!lkey) return -4;
01078    }
01079    else
01080    {
01081       LM_ERR("Null keys in update _k=0 \n");
01082       return -1;
01083    }
01084    
01085    len = MAX_ROW_SIZE;
01086    
01087    if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &len, _v, _n, BDB_KEY)) != 0 ) 
01088    {  LM_ERR("Error in query key \n");
01089       goto cleanup;
01090    }
01091    
01092    if(lkey) pkg_free(lkey);
01093    
01094    key.data = kbuf;
01095    key.ulen = MAX_ROW_SIZE;
01096    key.flags = DB_DBT_USERMEM;
01097    key.size = len;
01098    
01099    /*stage 1: QUERY Berkely DB*/
01100    if ((ret = db->get(db, NULL, &key, &qdata, 0)) == 0) 
01101    {
01102 
01103 #ifdef BDB_EXTRA_DEBUG
01104       LM_DBG("RESULT\nKEY:  [%.*s]\nDATA: [%.*s]\n"
01105          , (int)   key.size
01106          , (char *)key.data
01107          , (int)   qdata.size
01108          , (char *)qdata.data);
01109 #endif
01110 
01111    }
01112    else
01113    {  goto db_error;
01114    }
01115    
01116    /* stage 2: UPDATE row with new values */
01117    
01118    /* map the provided keys to those in our schema */ 
01119    lkey = bdb_get_colmap(_tbc->dtp, _uk, _un);
01120    if(!lkey) return -4;
01121    
01122    /* build a new row for update data (udata) */
01123    memset(&udata, 0, sizeof(DBT));
01124    memset(ubuf, 0, MAX_ROW_SIZE);
01125    
01126    /* loop over each column of the qbuf and copy it to our new ubuf unless
01127       its a field that needs to update
01128    */
01129    c = strtok(qbuf, DELIM);
01130    t = ubuf;
01131    while( c!=NULL)
01132    {  char* delim = DELIM;
01133       int k;
01134       
01135       len = strlen(c);
01136       sum+=len;
01137       
01138       if(sum > MAX_ROW_SIZE)
01139       {  LM_ERR("value too long for string \n");
01140          ret = -3;
01141          goto cleanup;
01142       }
01143       
01144       for(i=0;i<_un;i++)
01145       {
01146          k = lkey[i];
01147          if (qcol == k)
01148          {  /* update this col */
01149             int j = MAX_ROW_SIZE - sum;
01150             if( bdb_val2str( &_uv[i], t, &j) )
01151             {  LM_ERR("value too long for string \n");
01152                ret = -3;
01153                goto cleanup;
01154             }
01155 
01156             goto next;
01157          }
01158          
01159       }
01160       
01161       /* copy original column to the new column */
01162       strncpy(t, c, len);
01163 
01164 next:
01165       t+=len;
01166       
01167       /* append DELIM */
01168       sum += DELIM_LEN;
01169       if(sum > MAX_ROW_SIZE)
01170       {  LM_ERR("value too long for string \n");
01171          ret = -3;
01172          goto cleanup;
01173       }
01174       
01175       strncpy(t, delim, DELIM_LEN);
01176       t += DELIM_LEN;
01177       
01178       c = strtok(NULL, DELIM);
01179       qcol++;
01180    }
01181    
01182    ubuf[sum]  = '0';
01183    udata.data = ubuf;
01184    udata.ulen  = MAX_ROW_SIZE;
01185    udata.flags = DB_DBT_USERMEM;
01186    udata.size  = sum;
01187 
01188 #ifdef BDB_EXTRA_DEBUG
01189    LM_DBG("MODIFIED Data\nKEY:  [%.*s]\nDATA: [%.*s]\n"
01190       , (int)   key.size
01191       , (char *)key.data
01192       , (int)   udata.size
01193       , (char *)udata.data);
01194 #endif
01195    /* stage 3: DELETE old row using key*/
01196    if ((ret = db->del(db, NULL, &key, 0)) == 0)
01197    {
01198 #ifdef BDB_EXTRA_DEBUG
01199       LM_DBG("DELETED ROW\nKEY: %s \n", (char *)key.data);
01200 #endif
01201    }
01202    else
01203    {  goto db_error;
01204    }
01205    
01206    /* stage 4: INSERT new row with key*/
01207    if ((ret = db->put(db, NULL, &key, &udata, 0)) == 0) 
01208    {
01209       bdblib_log(JLOG_UPDATE, _tp, ubuf, sum);
01210 #ifdef BDB_EXTRA_DEBUG
01211    LM_DBG("INSERT \nKEY:  [%.*s]\nDATA: [%.*s]\n"
01212       , (int)   key.size
01213       , (char *)key.data
01214       , (int)   udata.size
01215       , (char *)udata.data);
01216 #endif
01217    }
01218    else
01219    {  goto db_error;
01220    }
01221 
01222 #ifdef BDB_EXTRA_DEBUG
01223    LM_DBG("UPDATE COMPLETE \n");
01224 #endif
01225 
01226 
01227 cleanup:
01228    if(lkey)
01229       pkg_free(lkey);
01230    
01231    return ret;
01232 
01233 
01234 db_error:
01235 
01236    /*Berkeley DB error handler*/
01237    switch(ret)
01238    {
01239    
01240    case DB_NOTFOUND:
01241    
01242 #ifdef BDB_EXTRA_DEBUG
01243       LM_DBG("NO RESULT \n");
01244 #endif
01245       return -1;
01246    
01247    /* The following are all critical/fatal */
01248    case DB_LOCK_DEADLOCK:  
01249    /* The operation was selected to resolve a deadlock. */
01250    case DB_SECONDARY_BAD:
01251    /* A secondary index references a nonexistent primary key.*/ 
01252    case DB_RUNRECOVERY:
01253    default:
01254       LM_CRIT("DB->get error: %s.\n", db_strerror(ret));
01255       bdblib_recover(_tp,ret);
01256    }
01257    
01258    if(lkey)
01259       pkg_free(lkey);
01260    
01261    return ret;
01262 }

Generated on Mon May 21 18:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6