So I'm currently working on a Berkeley database through C, and I ran into a little problem concerning allowing duplicate data. If I don't allow duplicate entries through DB->set_flags and I iterate through the items in the database with a cursor, everything works just fine. The moment I add the DB->set_flags line in my program, and change nothing else, I get a segmentation fault and I don't know how to fix it, considering it works just fine without duplicate entries. The code is as follows:

DB *dates_db;
db_create(&dates_db, NULL, 0);
dates_db->set_flags(dates_db, DB_DUP);
dates_db->open(dates_db, NULL, "da.idx", NULL, DB_BTREE, 0, 0664);

DBT key, data;
memset(&key, 0, sizeof(key)); 
memset(&data, 0, sizeof(data));

DBC *DBpointer;
dates_db->cursor(dates_db, NULL, &DBpointer, 0);

while(DBpointer->c_get(DBpointer, &key, &data, DB_NEXT) != DB_NOTFOUND)
{
    printf("The key is: %s\nThe data is: %s\n", (char *)key.data, (char *)data.data);
}

Can anyone please tell me what I need to add? I've checked the sourceforge page that has all the information about Berkeley DB and as far as I know, I only need to add the DB->set_flags line to allow duplicate entries, but could there be something I've missed?

有帮助吗?

解决方案

For a start, you should always check return values when a function can fail.

Specifically, db_create, set_flags, open, cursor all return an error indication.

If, as you seem to indicate in a comment, it's the c_get causing the SIGSEGV, you may want to ensure that the cursor was indeed created properly.

Changing:

DBC *DBpointer;
dates_db->cursor(dates_db, NULL, &DBpointer, 0);

to:

DBC *DBpointer = (DBC*)0xdeadbeef;
int rc = dates_db->cursor(dates_db, NULL, &DBpointer, 0);
printf ("DEBUG: %d %p\n", rc, DBpointer);
fflush (stdio); // and possibly also: fsync (fileno (stdio));

would be a good start.

Better would be to go all the way and use something like:

#define CHKERR(x) if(rc!=0){printf("%s err=%d\n",x,rc);fflush(stdout);exit(1);}
int rc;
DB *dates_db;

rc = db_create(&dates_db, NULL, 0);
CHKERR("create");

rc = dates_db->set_flags(dates_db, DB_DUP);
CHKERR("set_flags");

rc = dates_db->open(dates_db, NULL, "da.idx", NULL, DB_BTREE, 0, 0664);
CHKERR("open");

DBT key, data;
memset(&key, 0, sizeof(key)); 
memset(&data, 0, sizeof(data));

DBC *DBpointer;
rc = dates_db->cursor(dates_db, NULL, &DBpointer, 0);
CHKERR("cursor");

while((rc = DBpointer->c_get(DBpointer, &key, &data, DB_NEXT)) != DB_NOTFOUND)
{
    CHKERR("c_get");
    printf("The key is: %s\nThe data is: %s\n", (char *)key.data, (char *)data.data);
}

Based on a further comment that you're getting error 22 on the open call, that's EINVAL (on my system at least) which means one of your parameters is incorrect.

Based on web searches, there appear to be a few variations on the open call, ranging between five and seven arguments. Some Oracle BDB doco states that it takes five argument (no database pointer and not transaction pointer) but the sample code in the same document (and other Oracle doco) has your seven-argument form.

It may be worthwhile looking into your BDB header files to see which one you should be using.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top