Reputation: 7268
In a C++ program I am trying to set a custom comparison function for a Berkeley DB, using the Db::set_bt_function
member function (the DB is opened as a BTREE type). My code works fine when I'm not changing the comparison function; I can put and get keys/values using Db::put
and Db::get
.
To try the set_bt_function
method, I defined my own "lexicographic comparison" as follows:
int compkeys(Db *db, const Dbt *dbt1, const Dbt *dbt2, size_t *locp) {
size_t s = dbt1->get_size() > dbt2->get_size() ? dbt2->get_size() : dbt1->get_size();
int c = std::memcmp(dbt1->get_data(), dbt2->get_data(), s);
if(c != 0) return c;
if(dbt1->get_size() < dbt2->get_size()) return -1;
if(dbt1->get_size() > dbt2->get_size()) return 1;
return 0;
}
So this should lead to exactly the same behavior as my reference code, when the comparison function isn't changed, since by default Berkeley DB uses lexicographical order.
Yet, when using this comparison function, Db::get
doesn't work anymore. It returns -30999 (DB_BUFFER_SMALL).
Here is what I am doing to get the value associated with a given key:
Db* _dbm = ... /* DB is open */
std::vector<char> mykey;
... /* mykey is set to some content */
Dbt db_key((void*)(mykey.data()), uint32_t(mykey.size()));
Dbt db_data;
db_key.set_flags(DB_DBT_USERMEM);
db_data.set_flags(DB_DBT_MALLOC);
int status = _dbm->get(NULL, &db_key, &db_data, 0);
... /* check status, do something with db_data */
free(db_data.get_data());
Any idea why this code works when I'm not setting the comparison function, and doesn't when I am?
Note: if I access key/values using a cursor (Dbc::get
) I don't have this issue.
Upvotes: 2
Views: 249
Reputation: 3206
The DB_BUFFER_SMALL
error in this case is complaining about your db_key Dbt
. You need to call db_key.set_ulen(uint32_t(mykey.size()))
to tell BDB how much space you've allocated to hold the keys that come out of the database.
Things get a little weirder when you're using a custom comparison function. You can have data in the key that's not part of the compare - and not in the key that you passed in to get()
. For this reason, BDB returns the key it found in the database in your db_key.
When setting the ulen
, make it large enough to hold any key that can come back from the database. You may find that it's saner to just keep a char
array on the stack to deal with this key in/out behavior.
Upvotes: 2