1

I implemented the following GBDM example:

#include <boost/lexical_cast.hpp>
#include <gdbm.h>
#include <iostream>
#include <string>
#include <string.h>

struct record
{
    int a;
    int b;
};

int main(int argc, char* argv[])
{
    GDBM_FILE db;

    db = gdbm_open("gdbm.db", 512, GDBM_WRCREAT | GDBM_NOLOCK | GDBM_SYNC, 0664, NULL);

    datum lekey;
    datum levalue;
    for (int i = 0; i < 10; ++i) {
        record r;
        r.a = i;
        r.b = i + 1;
        lekey.dptr = (char*) boost::lexical_cast<std::string>(i).c_str();
        lekey.dsize = strlen(lekey.dptr) + 1;
        levalue.dptr = (char*) &r;
        levalue.dsize = sizeof(record);
        gdbm_store(db, lekey, levalue, GDBM_INSERT);
    }
    gdbm_sync(db);

    for(lekey = gdbm_firstkey(db);
        lekey.dptr != NULL;
        lekey = gdbm_nextkey(db, lekey)) {
        levalue = gdbm_fetch(db, lekey);
        record* r = (record*) levalue.dptr;
        if (r) {
            std::cout << lekey.dptr << " " << r->a << " " << r->b << std::endl;
            free(levalue.dptr);
        }
    }

    gdbm_close(db);

    return 0;
}

The output is the following:

$ ./gdbm_example 
3 3 4
6 6 7
2 2 3
9 9 10
5 5 6
1 1 2
8 8 9
4 4 5

Why would 0 0 1 and 7 7 8 be left out? Is this a bug or am I doing something wrong?

bruno nery
  • 2,022
  • 2
  • 20
  • 31

2 Answers2

2

Joachim is right, using boost::lexical_cast is out of place here. Rewrite your example using this:

std::string s;
std::stringstream str;
str << i;
s = str.str();
lekey.dptr = (char*) s.c_str();

and it will work as expected.

  • Same problem, different output :P - I was using boost::lexical_cast because I'm implementing this with different key-value databases (this one was originally written to LevelDB). – bruno nery May 31 '12 at 15:29
  • The program was using the old database, never mind. I erased it and it started working like a charm :) – bruno nery Jun 01 '12 at 15:57
1

A problem might be this line:

lekey.dptr = (char*) boost::lexical_cast<std::string>(i).c_str();

This stores the pointer to a temporary variable, and so is undefined behavior.

The key doesn't have to be a string, it can as well be a number, so you can use e.g.:

lekey.dptr = &i;
lekey.dsize = sizeof(i);
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Changing it to integer made the problem worse: now I only get two items on the output :(. I'm using gdbm 1.10 - any change my setup is the problem? – bruno nery May 31 '12 at 15:32
  • @brunonery Then keep it as strings, just store it in a variable inside the loop as suggested in Sergeys answer. – Some programmer dude Jun 01 '12 at 06:00
  • Actually, I forgot to erase the database file (so it was using the messed up version). I'm choosing your answer because you pointed out I could use non-string keys :) – bruno nery Jun 01 '12 at 15:58