/* * 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; }
int bdblib_valtochar(bdb_table_p tp, db_fld_t *fld, int fld_count, char *kout, int *klen, int ktype) { char *p; static char sk[MAX_ROW_SIZE]; // subkey(sk) val char* delim = DELIM; char* cNULL = "NULL"; int len, total, sum; int i, j, k; bdb_fld_t *f; p = kout; len = sum = total = 0; i = j = k = 0; if(tp==NULL) return -1; if(fld==NULL || fld_count<1) return -1; if(kout==NULL || klen==NULL ) return -1; if( *klen < 1) return -1; memset(sk, 0, MAX_ROW_SIZE); total = *klen; *klen = 0; //sum /* schema has specified keys verify all schema keys are provided use 'NULL' for those that are missing. */ for(i=0; i<tp->ncols; i++) { /* i indexes columns in schema order */ if(ktype) { /* keymode; skip over non-key columns */ if(tp->colp[i]->flag==0) continue; } for(j=0; j<fld_count; j++) { f = DB_GET_PAYLOAD(fld + j); /* j indexes the columns provided in _k which may be less than the total required by the schema. the app does not know the order of the columns in our schema! */ k = f->col_pos; /* * k index will remap back to our schema order; like i */ if(i == k) { /* KEY was provided; append to buffer; _k[j] contains a key, but its a key that corresponds to column k of our schema. now we know its a match, and we dont need index k for anything else */ len = total - sum; if ( bdb_val2str((fld+j), sk, &len) != 0) { ERR("Destination buffer too short for subval %s\n",sk); return -4; } sum += len; if(sum > total) { ERR("Destination buffer too short for subval %s\n",sk); return -5; } strncpy(p, sk, len); p += len; *klen = sum; sum += DELIM_LEN; if(sum > total) { ERR("Destination buffer too short for delim \n"); return -5; } /* append delim */ strncpy(p, delim, DELIM_LEN); p += DELIM_LEN; *klen = sum; /* take us out of inner for loop and at the end of the outer loop to look for our next schema key */ goto next; } } /* NO KEY provided; use the column default value (dv) i.e _tp->colp[i]->dv */ len = tp->colp[i]->dv.len; sum += len; if(sum > total) { ERR("Destination buffer too short for subval %s\n",cNULL); return -5; } strncpy(p, tp->colp[i]->dv.s, len); p += len; *klen = sum; sum += DELIM_LEN; if(sum > total) { ERR("Destination buffer too short for delim \n"); return -5; } strncpy(p, delim, DELIM_LEN); p += DELIM_LEN; *klen = sum; next: continue; } return 0; }