/** Prepare a query * @param cmd DB command structure * @param bcmd berkey DB command structure * @return 0 on success, -1 on error */ int bdb_prepare_query(db_cmd_t *cmd, bdb_cmd_t *bcmd) { bdb_tcache_t *tbc = NULL; bdb_table_t *tp = NULL; bdb_fld_t *f; db_fld_t *fld; int mode; int i; if(bcmd->bcon == NULL || bcmd->bcon->dbp == NULL) return -1; tbc = bdblib_get_table(bcmd->bcon->dbp, &cmd->table); if(tbc == NULL) { ERR("bdb: table does not exist!\n"); return -1; } tp = tbc->dtp; if(tp == NULL || tp->db == NULL) { ERR("bdb: table not loaded!\n"); return -1; } mode = 0; if(!DB_FLD_EMPTY(cmd->result)) { /* columns to be returned provided */ if(cmd->result_count > tp->ncols) { ERR("bdb: too many columns in query\n"); goto error; } } else { mode = 1; cmd->result = db_fld(tp->ncols + 1); cmd->result_count = tp->ncols; for(i = 0; i < cmd->result_count; i++) { if(bdb_fld(cmd->result + i, cmd->table.s) < 0) goto error; } } for(i = 0; i < cmd->result_count; i++) { fld = cmd->result + i; f = DB_GET_PAYLOAD(fld); if(mode == 1) { DBG("bdb: column name [%.*s]\n", tp->colp[i]->name.len, tp->colp[i]->name.s); f->name = pkg_malloc(tp->colp[i]->name.len + 1); if(f->name == NULL) { ERR("bdb: Out of private memory\n"); goto error; } strncpy(f->name, tp->colp[i]->name.s, tp->colp[i]->name.len); f->name[tp->colp[i]->name.len] = '\0'; fld->name = f->name; fld->type = tp->colp[i]->type; f->col_pos = i; } else { f->col_pos = bdb_get_colpos(tp, fld->name); if(f->col_pos == -1) { ERR("bdb: Column not found\n"); goto error; } } switch(fld->type) { case DB_INT: case DB_BITMAP: case DB_FLOAT: case DB_DOUBLE: case DB_DATETIME: case DB_STR: if(!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE); if(f->buf.s == NULL) { ERR("bdb: No memory left\n"); goto error; } fld[i].v.lstr.s = f->buf.s; break; case DB_CSTR: if(!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE); if(f->buf.s == NULL) { ERR("bdb: No memory left\n"); goto error; } fld[i].v.cstr = f->buf.s; break; case DB_BLOB: if(!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE); if(f->buf.s == NULL) { ERR("mysql: No memory left\n"); goto error; } fld[i].v.blob.s = f->buf.s; break; case DB_NONE: /* Eliminates gcc warning */ break; } } if(!DB_FLD_EMPTY(cmd->match)) { if(cmd->match_count > tp->ncols) { ERR("bdb: too many columns in match struct of query\n"); goto error; } for(i = 0; i < cmd->match_count; i++) { fld = cmd->result + i; f = DB_GET_PAYLOAD(fld); f->col_pos = bdb_get_colpos(tp, fld->name); if(f->col_pos == -1) { ERR("bdb: Match column not found\n"); goto error; } } } return 0; error: return -1; }
/* _bdb_delete_cursor -- called from bdb_delete when the query involves operators other than equal '='. Adds support for queries like this: DELETE from SomeTable WHERE _k[0] < _v[0] In this case, the keys _k are not the actually schema keys, so we need to iterate via cursor to perform this operation. */ int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) { tbl_cache_p _tbc = NULL; table_p _tp = NULL; db_res_t* _r = NULL; char kbuf[MAX_ROW_SIZE]; char dbuf[MAX_ROW_SIZE]; int i, ret, klen=MAX_ROW_SIZE; DBT key, data; DB *db; DBC *dbcp; int *lkey=NULL; str s; i = ret = 0; if ((!_h) || !CON_TABLE(_h)) return -1; s.s = (char*)CON_TABLE(_h); s.len = strlen(CON_TABLE(_h)); _tbc = bdblib_get_table(BDB_CON_CONNECTION(_h), &s); if(!_tbc) { LM_WARN("table does not exist!\n"); return -3; } _tp = _tbc->dtp; if(!_tp) { LM_WARN("table not loaded!\n"); return -4; } #ifdef BDB_EXTRA_DEBUG LM_DBG("DELETE by cursor in %.*s\n", _tp->name.len, _tp->name.s ); #endif if(_k) { lkey = bdb_get_colmap(_tp, _k, _n); if(!lkey) { ret = -1; goto error; } } /* create an empty db_res_t which gets returned even if no result */ _r = db_new_result(); if (!_r) { LM_ERR("no memory for result \n"); } RES_ROW_N(_r) = 0; /* fill in the col part of db_res_t */ if ((ret = bdb_get_columns(_tp, _r, 0, 0)) != 0) { LM_ERR("Error while getting column names\n"); goto error; } db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, klen); memset(&data, 0, sizeof(DBT)); memset(dbuf, 0, MAX_ROW_SIZE); data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; /* Acquire a cursor for the database. */ if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR)) != 0) { LM_ERR("Error creating cursor\n"); } while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { if(!strncasecmp((char*)key.data,"METADATA",8)) continue; /*fill in the row part of db_res_t */ if ((ret=bdb_convert_row( _r, dbuf, 0)) < 0) { LM_ERR("Error while converting row\n"); goto error; } if(bdb_row_match(_k, _op, _v, _n, _r, lkey )) { #ifdef BDB_EXTRA_DEBUG LM_DBG("DELETE ROW by KEY: [%.*s]\n", (int) key.size, (char *)key.data); #endif if((ret = dbcp->c_del(dbcp, 0)) != 0) { /* Berkeley DB error handler */ LM_CRIT("DB->get error: %s.\n", db_strerror(ret)); bdblib_recover(_tp,ret); } } memset(dbuf, 0, MAX_ROW_SIZE); bdb_free_rows( _r); } ret = 0; error: if(dbcp) dbcp->c_close(dbcp); if(_r) bdb_free_result(_r); if(lkey) pkg_free(lkey); return ret; }
/** * Execute a query * @param cmd DB command structure * @param bcmd Berkely DB command structure * @return 0 on success, -1 on error */ int bdb_query(db_cmd_t *cmd, bdb_cmd_t *bcmd) { DBT key; DB *db; static char kbuf[MAX_ROW_SIZE]; int klen; bdb_tcache_t *tbc = NULL; bdb_table_t *tp = NULL; if(bcmd->bcon == NULL || bcmd->bcon->dbp == NULL) return -1; tbc = bdblib_get_table(bcmd->bcon->dbp, &cmd->table); if(tbc == NULL) { ERR("bdb: table does not exist!\n"); return -1; } tp = tbc->dtp; if(tp == NULL) { ERR("bdb: table not loaded!\n"); return -1; } db = tp->db; if(db == NULL) { ERR("bdb: db structure not initialized!\n"); return -1; } if(DB_FLD_EMPTY(cmd->match)) { /* no match constraint */ if(db->cursor(db, NULL, &bcmd->dbcp, 0) != 0) { ERR("bdb: error creating cursor\n"); goto error; } bcmd->skey.len = 0; return 0; } memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, MAX_ROW_SIZE); klen = MAX_ROW_SIZE; if(bdblib_valtochar(tp, cmd->match, cmd->match_count, kbuf, &klen, BDB_KEY) != 0) { ERR("bdb: error creating key\n"); goto error; } if(klen > bcmd->skey_size || bcmd->skey.s == NULL) { if(bcmd->skey.s != NULL) pkg_free(bcmd->skey.s); bcmd->skey.s = (char *)pkg_malloc(klen * sizeof(char)); if(bcmd->skey.s == NULL) { ERR("bdb: no pkg memory\n"); goto error; } bcmd->skey_size = klen; } memcpy(bcmd->skey.s, kbuf, klen); bcmd->skey.len = klen; return 0; error: return -1; }
/* * Delete a row from table * * To delete ALL rows: * do Not specify any keys, or values, and _n <=0 * */ int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) { tbl_cache_p _tbc = NULL; table_p _tp = NULL; char kbuf[MAX_ROW_SIZE]; int i, j, ret, klen; int *lkey=NULL; DBT key; DB *db; DBC *dbcp; str s; i = j = ret = 0; klen=MAX_ROW_SIZE; if (_op) return ( _bdb_delete_cursor(_h, _k, _op, _v, _n) ); if ((!_h) || !CON_TABLE(_h)) return -1; s.s = (char*)CON_TABLE(_h); s.len = strlen(CON_TABLE(_h)); _tbc = bdblib_get_table(BDB_CON_CONNECTION(_h), &s); if(!_tbc) { LM_WARN("table does not exist!\n"); return -3; } _tp = _tbc->dtp; if(!_tp) { LM_WARN("table not loaded!\n"); return -4; } #ifdef BDB_EXTRA_DEBUG LM_DBG("DELETE in %.*s\n", _tp->name.len, _tp->name.s ); #endif db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, klen); if(!_k || !_v || _n<=0) { /* Acquire a cursor for the database. */ if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR) ) != 0) { LM_ERR("Error creating cursor\n"); goto error; } while ((ret = dbcp->c_get(dbcp, &key, NULL, DB_NEXT)) == 0) { if(!strncasecmp((char*)key.data,"METADATA",8)) continue; #ifdef BDB_EXTRA_DEBUG LM_DBG("KEY: [%.*s]\n" , (int) key.size , (char *)key.data); #endif ret = dbcp->c_del(dbcp, 0); } dbcp->c_close(dbcp); return 0; } lkey = bdb_get_colmap(_tp, _k, _n); if(!lkey) return -5; /* make the key */ if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) { LM_ERR("Error in bdblib_makekey\n"); ret = -6; goto error; } key.data = kbuf; key.ulen = MAX_ROW_SIZE; key.flags = DB_DBT_USERMEM; key.size = klen; if ((ret = db->del(db, NULL, &key, 0)) == 0) { bdblib_log(JLOG_DELETE, _tp, kbuf, klen); #ifdef BDB_EXTRA_DEBUG LM_DBG("DELETED ROW \n KEY: %s \n", (char *)key.data); #endif } else { /*Berkeley DB error handler*/ switch(ret) { case DB_NOTFOUND: ret = 0; break; /*The following are all critical/fatal */ case DB_LOCK_DEADLOCK: /* The operation was selected to resolve a deadlock. */ case DB_SECONDARY_BAD: /* A secondary index references a nonexistent primary key. */ case DB_RUNRECOVERY: default: LM_CRIT("DB->del error: %s.\n" , db_strerror(ret)); bdblib_recover(_tp, ret); goto error; } } ret = 0; error: if(lkey) pkg_free(lkey); return ret; }
/* * Insert a row into table */ int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) { tbl_cache_p _tbc = NULL; table_p _tp = NULL; char kbuf[MAX_ROW_SIZE]; char dbuf[MAX_ROW_SIZE]; int i, j, ret, klen, dlen; int *lkey=NULL; DBT key, data; DB *db; str s; i = j = ret = 0; klen=MAX_ROW_SIZE; dlen=MAX_ROW_SIZE; if ((!_h) || (!_v) || !CON_TABLE(_h)) { return -1; } if (!_k) { #ifdef BDB_EXTRA_DEBUG LM_ERR("DB INSERT without KEYs not implemented! \n"); #endif return -2; } s.s = (char*)CON_TABLE(_h); s.len = strlen(CON_TABLE(_h)); _tbc = bdblib_get_table(BDB_CON_CONNECTION(_h), &s); if(!_tbc) { LM_WARN("table does not exist!\n"); return -3; } _tp = _tbc->dtp; if(!_tp) { LM_WARN("table not loaded!\n"); return -4; } #ifdef BDB_EXTRA_DEBUG LM_DBG("INSERT in %.*s\n", _tp->name.len, _tp->name.s ); #endif db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, klen); if(_tp->ncols<_n) { LM_WARN("more values than columns!!\n"); return -5; } lkey = bdb_get_colmap(_tp, _k, _n); if(!lkey) return -7; /* verify col types provided */ for(i=0; i<_n; i++) { j = (lkey)?lkey[i]:i; if(bdb_is_neq_type(_tp->colp[j]->type, _v[i].type)) { LM_WARN("incompatible types v[%d] - c[%d]!\n", i, j); ret = -8; goto error; } } /* make the key */ if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) { LM_ERR("Error in bdblib_valtochar \n"); ret = -9; goto error; } key.data = kbuf; key.ulen = MAX_ROW_SIZE; key.flags = DB_DBT_USERMEM; key.size = klen; //make the value (row) memset(&data, 0, sizeof(DBT)); memset(dbuf, 0, MAX_ROW_SIZE); if ( (ret = bdblib_valtochar(_tp, lkey, dbuf, &dlen, _v, _n, BDB_VALUE)) != 0 ) { LM_ERR("Error in bdblib_valtochar \n"); ret = -9; goto error; } data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; data.size = dlen; if ((ret = db->put(db, NULL, &key, &data, 0)) == 0) { bdblib_log(JLOG_INSERT, _tp, dbuf, dlen); #ifdef BDB_EXTRA_DEBUG LM_DBG("INSERT\nKEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size , (char *)key.data , (int) data.size , (char *)data.data); #endif } else { /*Berkeley DB error handler*/ switch(ret) { /*The following are all critical/fatal */ case DB_LOCK_DEADLOCK: /* The operation was selected to resolve a deadlock. */ case DB_RUNRECOVERY: default: LM_CRIT("DB->put error: %s.\n", db_strerror(ret)); bdblib_recover(_tp, ret); goto error; } } error: if(lkey) pkg_free(lkey); return ret; }
/* * Query table for specified rows * _con: structure representing database connection * _k: key names * _op: operators * _v: values of the keys that must match * _c: column names to return * _n: number of key=values pairs to compare * _nc: number of columns to return * _o: order by the specified column */ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _c, int _n, int _nc, db_key_t _o, db_res_t** _r) { tbl_cache_p _tbc = NULL; table_p _tp = NULL; char kbuf[MAX_ROW_SIZE]; char dbuf[MAX_ROW_SIZE]; u_int32_t i, len, ret; int klen=MAX_ROW_SIZE; int *lkey=NULL, *lres=NULL; str s; DBT key, data; DB *db; DBC *dbcp; if ((!_con) || (!_r) || !CON_TABLE(_con)) { #ifdef BDB_EXTRA_DEBUG LM_ERR("Invalid parameter value\n"); #endif return -1; } *_r = NULL; /*check if underlying DB file has changed inode */ if(auto_reload) bdb_check_reload(_con); s.s = (char*)CON_TABLE(_con); s.len = strlen(CON_TABLE(_con)); _tbc = bdblib_get_table(BDB_CON_CONNECTION(_con), &s); if(!_tbc) { LM_WARN("table does not exist!\n"); return -1; } _tp = _tbc->dtp; if(!_tp) { LM_WARN("table not loaded!\n"); return -1; } #ifdef BDB_EXTRA_DEBUG LM_DBG("QUERY in %.*s\n", _tp->name.len, _tp->name.s); if (_o) LM_DBG("DONT-CARE : _o: order by the specified column \n"); if (_op) LM_DBG("DONT-CARE : _op: operators for refining query \n"); #endif db = _tp->db; if(!db) return -1; memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, MAX_ROW_SIZE); memset(&data, 0, sizeof(DBT)); memset(dbuf, 0, MAX_ROW_SIZE); data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; /* if _c is NULL and _nc is zero, you will get all table columns in the result */ if (_c) { lres = bdb_get_colmap(_tbc->dtp, _c, _nc); if(!lres) { ret = -1; goto error; } } if(_k) { lkey = bdb_get_colmap(_tbc->dtp, _k, _n); if(!lkey) { ret = -1; goto error; } } else { DB_HASH_STAT st; memset(&st, 0, sizeof(DB_HASH_STAT)); i =0 ; #ifdef BDB_EXTRA_DEBUG LM_DBG("SELECT * FROM %.*s\n", _tp->name.len, _tp->name.s); #endif /* Acquire a cursor for the database. */ if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) { LM_ERR("Error creating cursor\n"); goto error; } /*count the number of records*/ while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { if(!strncasecmp((char*)key.data,"METADATA",8)) continue; i++; } dbcp->c_close(dbcp); ret=0; #ifdef BDB_EXTRA_DEBUG LM_DBG("%i = SELECT COUNT(*) FROM %.*s\n", i, _tp->name.len, _tp->name.s); #endif *_r = db_new_result(); if (!*_r) { LM_ERR("no memory left for result \n"); ret = -2; goto error; } if(i == 0) { /*return empty table*/ RES_ROW_N(*_r) = 0; BDB_CON_RESULT(_con) = *_r; return 0; } /*allocate N rows in the result*/ RES_ROW_N(*_r) = i; len = sizeof(db_row_t) * i; RES_ROWS(*_r) = (db_row_t*)pkg_malloc( len ); memset(RES_ROWS(*_r), 0, len); /*fill in the column part of db_res_t (metadata) */ if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) { LM_ERR("Error while getting column names\n"); goto error; } /* Acquire a cursor for the database. */ if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) { LM_ERR("Error creating cursor\n"); goto error; } /*convert each record into a row in the result*/ i =0 ; while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { if(!strncasecmp((char*)key.data,"METADATA",8)) continue; #ifdef BDB_EXTRA_DEBUG LM_DBG("KEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size , (char *)key.data , (int) data.size , (char *)data.data); #endif /*fill in the row part of db_res_t */ if ((ret=bdb_append_row( *_r, dbuf, lres, i)) < 0) { LM_ERR("Error while converting row\n"); goto error; } i++; } dbcp->c_close(dbcp); BDB_CON_RESULT(_con) = *_r; return 0; } if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) { LM_ERR("error in query key \n"); goto error; } key.data = kbuf; key.ulen = MAX_ROW_SIZE; key.flags = DB_DBT_USERMEM; key.size = klen; data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; /*create an empty db_res_t which gets returned even if no result*/ *_r = db_new_result(); if (!*_r) { LM_ERR("no memory left for result \n"); ret = -2; goto error; } RES_ROW_N(*_r) = 0; BDB_CON_RESULT(_con) = *_r; #ifdef BDB_EXTRA_DEBUG LM_DBG("SELECT KEY: [%.*s]\n" , (int) key.size , (char *)key.data ); #endif /*query Berkely DB*/ if ((ret = db->get(db, NULL, &key, &data, 0)) == 0) { #ifdef BDB_EXTRA_DEBUG LM_DBG("RESULT\nKEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size , (char *)key.data , (int) data.size , (char *)data.data); #endif /*fill in the col part of db_res_t */ if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) { LM_ERR("Error while getting column names\n"); goto error; } /*fill in the row part of db_res_t */ if ((ret=bdb_convert_row( *_r, dbuf, lres)) < 0) { LM_ERR("Error while converting row\n"); goto error; } } else { /*Berkeley DB error handler*/ switch(ret) { case DB_NOTFOUND: #ifdef BDB_EXTRA_DEBUG LM_DBG("NO RESULT for QUERY \n"); #endif ret=0; break; /*The following are all critical/fatal */ case DB_LOCK_DEADLOCK: // The operation was selected to resolve a deadlock. case DB_SECONDARY_BAD: // A secondary index references a nonexistent primary key. case DB_RUNRECOVERY: default: LM_CRIT("DB->get error: %s.\n", db_strerror(ret)); bdblib_recover(_tp,ret); goto error; } } if(lkey) pkg_free(lkey); if(lres) pkg_free(lres); return ret; error: if(lkey) pkg_free(lkey); if(lres) pkg_free(lres); if(*_r) bdb_free_result(*_r); *_r = NULL; return ret; }
/* * Attempts to reload a Berkeley database; reloads when the inode changes */ void bdb_check_reload(db_con_t* _con) { str s; char* p; int rc, len; struct stat st; database_p db; char n[MAX_ROW_SIZE]; char t[MAX_TABLENAME_SIZE]; table_p tp = NULL; tbl_cache_p tbc = NULL; p=n; rc = len = 0; /*get dbenv name*/ db = BDB_CON_CONNECTION(_con); if(!db->dbenv) return; s.s = db->name.s; s.len = db->name.len; len+=s.len; if(len > MAX_ROW_SIZE) { LM_ERR("dbenv name too long \n"); return; } strncpy(p, s.s, s.len); p+=s.len; len++; if(len > MAX_ROW_SIZE) { LM_ERR("dbenv name too long \n"); return; } /*append slash */ *p = '/'; p++; /*get table name*/ s.s = (char*)CON_TABLE(_con); s.len = strlen(CON_TABLE(_con)); len+=s.len; if((len>MAX_ROW_SIZE) || (s.len > MAX_TABLENAME_SIZE) ) { LM_ERR("table name too long \n"); return; } strncpy(t, s.s, s.len); t[s.len] = 0; strncpy(p, s.s, s.len); p+=s.len; *p=0; if( (tbc = bdblib_get_table(db, &s)) == NULL) return; if( (tp = tbc->dtp) == NULL) return; LM_DBG("stat file [%.*s]\n", len, n); rc = stat(n, &st); if(!rc) { if((tp->ino!=0) && (st.st_ino != tp->ino)) bdb_reload(t); /*file changed on disk*/ tp->ino = st.st_ino; } }
/* * Updates a row in table * Limitation: only knows how to update a single row * * _con: structure representing database connection * _k: key names * _op: operators * _v: values of the keys that must match * _uk: update keys; cols that need to be updated * _uv: update values; col values that need to be commited * _un: number of rows to update */ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _uk, db_val_t* _uv, int _n, int _un) { str s; char *c, *t; int ret, i, qcol, len, sum; int *lkey=NULL; tbl_cache_p _tbc = NULL; table_p _tp = NULL; char kbuf[MAX_ROW_SIZE]; char qbuf[MAX_ROW_SIZE]; char ubuf[MAX_ROW_SIZE]; DBT key, qdata, udata; DB *db; sum = ret = i = qcol = len = 0; if (!_con || !CON_TABLE(_con) || !_uk || !_uv || _un <= 0) return -1; s.s = (char*)CON_TABLE(_con); s.len = strlen(CON_TABLE(_con)); _tbc = bdblib_get_table(BDB_CON_CONNECTION(_con), &s); if(!_tbc) { LM_ERR("table does not exist\n"); return -1; } _tp = _tbc->dtp; if(!_tp) { LM_ERR("table not loaded\n"); return -1; } db = _tp->db; if(!db) { LM_ERR("DB null ptr\n"); return -1; } #ifdef BDB_EXTRA_DEBUG LM_DBG("UPDATE in %.*s\n", _tp->name.len, _tp->name.s); if (_op) LM_DBG("DONT-CARE : _op: operators for refining query \n"); #endif memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, MAX_ROW_SIZE); memset(&qdata, 0, sizeof(DBT)); memset(qbuf, 0, MAX_ROW_SIZE); qdata.data = qbuf; qdata.ulen = MAX_ROW_SIZE; qdata.flags = DB_DBT_USERMEM; if(_k) { lkey = bdb_get_colmap(_tbc->dtp, _k, _n); if(!lkey) return -4; } else { LM_ERR("Null keys in update _k=0 \n"); return -1; } len = MAX_ROW_SIZE; if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &len, _v, _n, BDB_KEY)) != 0 ) { LM_ERR("Error in query key \n"); goto cleanup; } if(lkey) pkg_free(lkey); key.data = kbuf; key.ulen = MAX_ROW_SIZE; key.flags = DB_DBT_USERMEM; key.size = len; /*stage 1: QUERY Berkely DB*/ if ((ret = db->get(db, NULL, &key, &qdata, 0)) == 0) { #ifdef BDB_EXTRA_DEBUG LM_DBG("RESULT\nKEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size , (char *)key.data , (int) qdata.size , (char *)qdata.data); #endif } else { goto db_error; } /* stage 2: UPDATE row with new values */ /* map the provided keys to those in our schema */ lkey = bdb_get_colmap(_tbc->dtp, _uk, _un); if(!lkey) return -4; /* build a new row for update data (udata) */ memset(&udata, 0, sizeof(DBT)); memset(ubuf, 0, MAX_ROW_SIZE); /* loop over each column of the qbuf and copy it to our new ubuf unless its a field that needs to update */ c = strtok(qbuf, DELIM); t = ubuf; while( c!=NULL) { char* delim = DELIM; int k; len = strlen(c); sum+=len; if(sum > MAX_ROW_SIZE) { LM_ERR("value too long for string \n"); ret = -3; goto cleanup; } for(i=0; i<_un; i++) { k = lkey[i]; if (qcol == k) { /* update this col */ int j = MAX_ROW_SIZE - sum; if( bdb_val2str( &_uv[i], t, &j) ) { LM_ERR("value too long for string \n"); ret = -3; goto cleanup; } goto next; } } /* copy original column to the new column */ strncpy(t, c, len); next: t+=len; /* append DELIM */ sum += DELIM_LEN; if(sum > MAX_ROW_SIZE) { LM_ERR("value too long for string \n"); ret = -3; goto cleanup; } strncpy(t, delim, DELIM_LEN); t += DELIM_LEN; c = strtok(NULL, DELIM); qcol++; } ubuf[sum] = '0'; udata.data = ubuf; udata.ulen = MAX_ROW_SIZE; udata.flags = DB_DBT_USERMEM; udata.size = sum; #ifdef BDB_EXTRA_DEBUG LM_DBG("MODIFIED Data\nKEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size , (char *)key.data , (int) udata.size , (char *)udata.data); #endif /* stage 3: DELETE old row using key*/ if ((ret = db->del(db, NULL, &key, 0)) == 0) { #ifdef BDB_EXTRA_DEBUG LM_DBG("DELETED ROW\nKEY: %s \n", (char *)key.data); #endif } else { goto db_error; } /* stage 4: INSERT new row with key*/ if ((ret = db->put(db, NULL, &key, &udata, 0)) == 0) { bdblib_log(JLOG_UPDATE, _tp, ubuf, sum); #ifdef BDB_EXTRA_DEBUG LM_DBG("INSERT \nKEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size , (char *)key.data , (int) udata.size , (char *)udata.data); #endif } else { goto db_error; } #ifdef BDB_EXTRA_DEBUG LM_DBG("UPDATE COMPLETE \n"); #endif cleanup: if(lkey) pkg_free(lkey); return ret; db_error: /*Berkeley DB error handler*/ switch(ret) { case DB_NOTFOUND: #ifdef BDB_EXTRA_DEBUG LM_DBG("NO RESULT \n"); #endif return -1; /* The following are all critical/fatal */ case DB_LOCK_DEADLOCK: /* The operation was selected to resolve a deadlock. */ case DB_SECONDARY_BAD: /* A secondary index references a nonexistent primary key.*/ case DB_RUNRECOVERY: default: LM_CRIT("DB->get error: %s.\n", db_strerror(ret)); bdblib_recover(_tp,ret); } if(lkey) pkg_free(lkey); return ret; }