/* -*- mode: C; c-basic-offset: 4 -*- */ #ident "Copyright (c) 2007 Tokutek Inc. All rights reserved." #include <string.h> #include <db.h> #include <assert.h> #include <errno.h> #include <sys/stat.h> #include "test.h" // ENVDIR is defined in the Makefile typedef struct { int32_t pkey; int32_t junk; int32_t skey; } DATA; int callback_init_data; int callback_set_malloc; int callback_return_DONOTINDEX; DB* db; DB* sdb; DB_TXN *const null_txn = 0; DB_ENV *dbenv = 0; /* * getname -- extracts a secondary key (the last name) from a primary * key/data pair */ static int getskey (DB *UU(secondary), const DBT *UU(pkey), const DBT *pdata, DBT *skey) { /* * Since the secondary key is a simple structure member of the * record, we don't have to do anything fancy to return it. If * we have composite keys that need to be constructed from the * record, rather than simply pointing into it, then the user's * function might need to allocate space and copy data. In * this case, the DB_DBT_APPMALLOC flag should be set in the * secondary key DBT. */ DATA* entry; if (verbose) { printf("callback: init[%d],malloc[%d],%sINDEX\n", callback_init_data, callback_set_malloc, callback_return_DONOTINDEX ? "DONOT" : ""); fflush(stdout); } memset(skey, 0, sizeof(DBT)); entry = (DATA*)pdata->data; if (callback_set_malloc) skey->flags = DB_DBT_APPMALLOC; if (callback_init_data) { skey->size = sizeof(entry->skey); if (callback_set_malloc) { skey->data = malloc(skey->size); memcpy(skey->data, &entry->skey, skey->size); } else skey->data = &entry->skey; } else { skey->data = NULL; skey->size = 0; } if (callback_return_DONOTINDEX) return DB_DONOTINDEX; return 0; } static void second_setup (void) { int r; /* Open/create primary */ r = db_create(&db, dbenv, 0); CKERR(r); r = db->open(db, null_txn, ENVDIR "/primary.db", NULL, DB_BTREE, DB_CREATE, 0600); CKERR(r); r = db_create(&sdb, dbenv, 0); CKERR(r); r = sdb->open(sdb, null_txn, ENVDIR "/secondary.db", NULL, DB_BTREE, DB_CREATE, 0600); CKERR(r); /* Associate the secondary with the primary. */ r = db->associate(db, null_txn, sdb, getskey, 0); CKERR(r); } static void insert (void) { int r; DATA entry; DBT data; DBT key; entry.pkey = 2; entry.junk = 3; entry.skey = 5; dbt_init(&key, &entry.pkey, sizeof(entry.pkey)); dbt_init(&data, &entry, sizeof(entry)); r = db->put(db, null_txn, &key, &data, 0); CKERR(r); } static void check_secondary (int expect_r) { int r; DBC *c; DBT skey; DBT data; dbt_init(&skey, 0, 0); dbt_init(&data, 0, 0); r = sdb->cursor(sdb, null_txn, &c, 0); CKERR(r); r = c->c_get(c, &skey, &data, DB_FIRST); CKERR2(r, expect_r); r = c->c_close(c); CKERR(r); } static void close_dbs (void) { int r; r = db->close(db, 0); CKERR(r); r = sdb->close(sdb, 0); CKERR(r); } int main(int argc, const char *argv[]) { int i; parse_args(argc, argv); for (i = 0; i < (1<<3); i++) { system("rm -rf " ENVDIR); mkdir(ENVDIR, 0777); second_setup(); check_secondary(DB_NOTFOUND); callback_init_data = i & (1 << 0); callback_set_malloc = i & (1 << 1); callback_return_DONOTINDEX = i & (1 << 2); insert(); check_secondary(callback_return_DONOTINDEX ? DB_NOTFOUND : 0); // For recent versions of BDB, we don't need to free any malloced object, even if it we returned DB_DONOTINDEX because if we malloced it then we set DB_DBT_APPMALLOC // Older versions of BDB didn't free it. Which versions did? close_dbs(); } return 0; }