mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-17 01:26:25 +00:00
381 lines
11 KiB
C
381 lines
11 KiB
C
|
/*-
|
||
|
* See the file LICENSE for redistribution information.
|
||
|
*
|
||
|
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
|
||
|
*
|
||
|
* $Id$
|
||
|
*/
|
||
|
/*
|
||
|
* Test combination of DB_DBT_PARTIAL and flags in DB->get, DB->pget,
|
||
|
* DBcursor->get, DBcursor->pget.
|
||
|
*
|
||
|
* TestPartial.c
|
||
|
*/
|
||
|
#include <sys/types.h>
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "db.h"
|
||
|
#include "CuTest.h"
|
||
|
#include "test_util.h"
|
||
|
|
||
|
const char *dbName = "TestPartial.db";
|
||
|
const char *sdbName = "TestPartialSec.db";
|
||
|
|
||
|
int expected = EINVAL;
|
||
|
|
||
|
/* Test utilities declaration */
|
||
|
static void CheckDbPartial(CuTest *, DB *, int, u_int32_t, int);
|
||
|
static void CheckCursorPartial(CuTest *, DB *, int, u_int32_t, int);
|
||
|
static int CloseDb(DB *);
|
||
|
static int Getkeystring(DB *, const DBT *, const DBT *, DBT *);
|
||
|
static void OpenDb(CuTest *, DB *, DB **, const char *, DBTYPE, u_int32_t);
|
||
|
static void PopulateDb(CuTest *, DB *, u_int32_t, u_int32_t);
|
||
|
|
||
|
int TestPartialSuiteSetup(CuSuite *ct) {
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int TestPartialSuiteTeardown(CuSuite *ct) {
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int TestPartialTestSetup(CuTest *ct) {
|
||
|
remove(dbName);
|
||
|
remove(sdbName);
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int TestPartialTestTeardown(CuTest *ct) {
|
||
|
remove(dbName);
|
||
|
remove(sdbName);
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/* Test cases */
|
||
|
int TestDbPartialGet(CuTest *ct) {
|
||
|
DB *pdb;
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, 0);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckDbPartial(ct, pdb, 0, 0, expected);
|
||
|
CheckDbPartial(ct, pdb, 0, DB_GET_BOTH, expected);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, DB_RECNUM);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckDbPartial(ct, pdb, 0, DB_SET_RECNO, 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_QUEUE, 0);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckDbPartial(ct, pdb, 0, DB_CONSUME, 0);
|
||
|
CheckDbPartial(ct, pdb, 0, DB_CONSUME_WAIT, 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int TestDbPartialPGet(CuTest *ct) {
|
||
|
DB *pdb, *sdb;
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, 0);
|
||
|
OpenDb(ct, pdb, &sdb, sdbName, DB_BTREE, 0);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckDbPartial(ct, sdb, 1, 0, expected);
|
||
|
CheckDbPartial(ct, sdb, 1, DB_GET_BOTH, expected);
|
||
|
CuAssert(ct, "DB->close", CloseDb(sdb) == 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
CuAssert(ct, "remove()", remove(sdbName) == 0);
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, 0);
|
||
|
OpenDb(ct, pdb, &sdb, sdbName, DB_BTREE, DB_RECNUM);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckDbPartial(ct, sdb, 1, DB_SET_RECNO, 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(sdb) == 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
CuAssert(ct, "remove()", remove(sdbName) == 0);
|
||
|
|
||
|
/* DB_CONSUME makes no sense on a secondary index, so no test. */
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int TestCursorPartialGet(CuTest *ct) {
|
||
|
DB *pdb;
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, 0);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_GET_BOTH, expected);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_GET_BOTH_RANGE, expected);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_SET, expected);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_SET_RANGE, 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, DB_RECNUM);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_GET_RECNO, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_SET_RECNO, 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, DB_DUP);
|
||
|
PopulateDb(ct, pdb, 100, 3);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_CURRENT, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_FIRST, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_LAST, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_NEXT, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_NEXT_DUP, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_NEXT_NODUP, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_PREV, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_PREV_DUP, 0);
|
||
|
CheckCursorPartial(ct, pdb, 0, DB_PREV_NODUP, 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int TestCursorPartialPGet(CuTest *ct) {
|
||
|
DB *pdb, *sdb;
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, 0);
|
||
|
OpenDb(ct, pdb, &sdb, sdbName, DB_BTREE, 0);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckCursorPartial(ct, sdb, 1, DB_GET_BOTH, expected);
|
||
|
CheckCursorPartial(ct, sdb, 1, DB_GET_BOTH_RANGE, expected);
|
||
|
CheckCursorPartial(ct, sdb, 1, DB_SET, expected);
|
||
|
CheckCursorPartial(ct, sdb, 1, DB_SET_RANGE, 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(sdb) == 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
CuAssert(ct, "remove()", remove(sdbName) == 0);
|
||
|
|
||
|
OpenDb(ct, NULL, &pdb, dbName, DB_BTREE, 0);
|
||
|
OpenDb(ct, pdb, &sdb, sdbName, DB_BTREE, DB_RECNUM);
|
||
|
PopulateDb(ct, pdb, 100, 1);
|
||
|
CheckCursorPartial(ct, sdb, 1, DB_SET_RECNO, 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(sdb) == 0);
|
||
|
CuAssert(ct, "DB->close", CloseDb(pdb) == 0);
|
||
|
CuAssert(ct, "remove()", remove(dbName) == 0);
|
||
|
CuAssert(ct, "remove()", remove(sdbName) == 0);
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/* Test utilities */
|
||
|
static void CheckDbPartial(CuTest *ct,
|
||
|
DB *dbp, int isSec, u_int32_t flags, int value) {
|
||
|
DBT key, data, pkey;
|
||
|
char kstr[10], dstr[14];
|
||
|
u_int32_t indx = 5, dupindx = 0;
|
||
|
db_recno_t rid = 5;
|
||
|
|
||
|
memset(&key, 0, sizeof(DBT));
|
||
|
memset(&data, 0, sizeof(DBT));
|
||
|
memset(&pkey, 0, sizeof(DBT));
|
||
|
memset(kstr, 0, sizeof(char) * 10);
|
||
|
memset(dstr, 0, sizeof(char) * 14);
|
||
|
|
||
|
key.doff = 2;
|
||
|
key.dlen = 1;
|
||
|
key.flags = DB_DBT_PARTIAL;
|
||
|
if (flags == DB_CONSUME || flags == DB_CONSUME_WAIT ||
|
||
|
flags == DB_SET_RECNO) {
|
||
|
if (flags == DB_SET_RECNO) {
|
||
|
key.data = &rid;
|
||
|
key.size = sizeof(db_recno_t);
|
||
|
}
|
||
|
} else if (flags == DB_GET_BOTH || flags == 0) {
|
||
|
memcpy(kstr, &indx, sizeof(u_int32_t));
|
||
|
memcpy(kstr + 4, "hello", sizeof(char) * 5);
|
||
|
key.data = kstr;
|
||
|
key.size = 10;
|
||
|
if (flags == DB_GET_BOTH) {
|
||
|
if (isSec == 0) {
|
||
|
memcpy(dstr, kstr, sizeof(char) * 9);
|
||
|
memcpy(dstr + 9, &dupindx, sizeof(u_int32_t));
|
||
|
data.data = dstr;
|
||
|
data.size = 14;
|
||
|
} else {
|
||
|
pkey.data = kstr;
|
||
|
pkey.size = 10;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
fprintf(stderr, "Invalid test flags: %d\n", flags);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (isSec == 0) {
|
||
|
CuAssert(ct, "DB->get",
|
||
|
dbp->get(dbp, NULL, &key, &data, flags) == value);
|
||
|
if (value == 0)
|
||
|
CuAssert(ct, "Partial DBT size", key.size == key.dlen);
|
||
|
} else {
|
||
|
CuAssert(ct, "DB->pget",
|
||
|
dbp->pget(dbp, NULL, &key, &pkey, &data, flags) == value);
|
||
|
if (value == 0)
|
||
|
CuAssert(ct, "Partial DBT size", key.size == key.dlen);
|
||
|
|
||
|
/* Partial pkey is always invalid. */
|
||
|
pkey.doff = 1;
|
||
|
pkey.dlen = 2;
|
||
|
pkey.flags = DB_DBT_PARTIAL;
|
||
|
CuAssert(ct, "DB->pget", dbp->pget(dbp, NULL, &key, &pkey,
|
||
|
&data, flags) == expected);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void CheckCursorPartial(CuTest *ct,
|
||
|
DB *dbp, int isSec, u_int32_t flags, int value) {
|
||
|
DBT key, data, pkey;
|
||
|
DBC *cursor = NULL;
|
||
|
char kstr[10], dstr[14];
|
||
|
u_int32_t indx = 5, dupindx = 0;
|
||
|
db_recno_t rid = 5;
|
||
|
|
||
|
memset(&key, 0, sizeof(DBT));
|
||
|
memset(&data, 0, sizeof(DBT));
|
||
|
memset(&pkey, 0, sizeof(DBT));
|
||
|
memset(kstr, 0, sizeof(char) * 10);
|
||
|
memcpy(kstr, &indx, sizeof(u_int32_t));
|
||
|
memcpy(kstr + 4, "hello", sizeof(char) * 5);
|
||
|
memset(dstr, 0, sizeof(char) * 14);
|
||
|
memcpy(dstr, kstr, sizeof(char) * 9);
|
||
|
memcpy(dstr + 9, &dupindx, sizeof(u_int32_t));
|
||
|
|
||
|
CuAssert(ct, "DB->cursor", dbp->cursor(dbp, NULL, &cursor, 0) == 0);
|
||
|
|
||
|
key.doff = 2;
|
||
|
key.dlen = 1;
|
||
|
key.flags = DB_DBT_PARTIAL;
|
||
|
if (flags == DB_SET_RECNO) {
|
||
|
key.data = &rid;
|
||
|
key.size = sizeof(db_recno_t);
|
||
|
} else if (flags == DB_GET_BOTH || flags == DB_GET_BOTH_RANGE ||
|
||
|
flags == DB_SET || flags == DB_SET_RANGE) {
|
||
|
key.data = kstr;
|
||
|
key.size = 10;
|
||
|
if (flags == DB_GET_BOTH || flags == DB_GET_BOTH_RANGE) {
|
||
|
if (isSec == 0) {
|
||
|
data.data = dstr;
|
||
|
data.size = 14;
|
||
|
} else {
|
||
|
pkey.data = kstr;
|
||
|
pkey.size = 10;
|
||
|
}
|
||
|
}
|
||
|
} else if (flags == DB_CURRENT || flags == DB_GET_RECNO ||
|
||
|
flags == DB_NEXT || flags == DB_NEXT_DUP ||
|
||
|
flags == DB_NEXT_NODUP) {
|
||
|
CuAssert(ct, "DBC->get",
|
||
|
cursor->get(cursor, &key, &data, DB_FIRST) == 0);
|
||
|
} else if (flags == DB_PREV || flags == DB_PREV_DUP ||
|
||
|
flags == DB_PREV_NODUP) {
|
||
|
CuAssert(ct, "DBC->get",
|
||
|
cursor->get(cursor, &key, &data, DB_LAST) == 0);
|
||
|
} else {
|
||
|
if (flags != DB_FIRST && flags != DB_LAST) {
|
||
|
fprintf(stderr, "Invalid test flags: %d\n", flags);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (isSec == 0) {
|
||
|
CuAssert(ct, "DBC->get",
|
||
|
cursor->get(cursor, &key, &data, flags) == value);
|
||
|
if (value == 0)
|
||
|
CuAssert(ct, "Partial DBT size", key.size == key.dlen);
|
||
|
} else {
|
||
|
CuAssert(ct, "DBC->pget",
|
||
|
cursor->pget(cursor, &key, &pkey, &data, flags) == value);
|
||
|
if (value == 0)
|
||
|
CuAssert(ct, "Partial DBT size", key.size == key.dlen);
|
||
|
|
||
|
/* Partial pkey is always invalid. */
|
||
|
pkey.doff = 1;
|
||
|
pkey.dlen = 2;
|
||
|
pkey.flags = DB_DBT_PARTIAL;
|
||
|
CuAssert(ct, "DBC->pget", cursor->pget(cursor, &key, &pkey,
|
||
|
&data, flags) == expected);
|
||
|
}
|
||
|
|
||
|
cursor->close(cursor);
|
||
|
}
|
||
|
|
||
|
static int CloseDb(DB *dbp) {
|
||
|
return dbp->close(dbp, 0);
|
||
|
}
|
||
|
|
||
|
static void OpenDb(CuTest *ct, DB *ldbp, DB **dbpp, const char *dbName,
|
||
|
DBTYPE type, u_int32_t openFlags) {
|
||
|
DB *dbp = NULL;
|
||
|
|
||
|
CuAssert(ct, "db_create", db_create(&dbp, NULL, 0) == 0);
|
||
|
dbp->set_errcall(dbp, NULL);
|
||
|
CuAssert(ct, "DB->set_flags", dbp->set_flags(dbp, openFlags) == 0);
|
||
|
if (type == DB_QUEUE)
|
||
|
CuAssert(ct, "DB->set_re_len",
|
||
|
dbp->set_re_len(dbp, ldbp == NULL ? 14 : 10) == 0);
|
||
|
CuAssert(ct, "DB->open", dbp->open(dbp, NULL, dbName, NULL, type,
|
||
|
DB_CREATE, 0) == 0);
|
||
|
if (ldbp != NULL)
|
||
|
CuAssert(ct, "DB->associate", ldbp->associate(ldbp, NULL, dbp,
|
||
|
Getkeystring, 0) == 0);
|
||
|
*dbpp = dbp;
|
||
|
}
|
||
|
|
||
|
static int Getkeystring(
|
||
|
DB *secondary, const DBT *pkey, const DBT *pdata, DBT *skey)
|
||
|
{
|
||
|
memset(skey, 0, sizeof(DBT));
|
||
|
skey->data = pdata->data;
|
||
|
skey->size = pkey->size;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
static void PopulateDb(CuTest *ct, DB *db, u_int32_t nkeys, u_int32_t ndups) {
|
||
|
DBT key, data;
|
||
|
char kstr[10], dstr[14];
|
||
|
DBTYPE type;
|
||
|
u_int32_t i, j, start;
|
||
|
|
||
|
start = 0;
|
||
|
memset(&key, 0, sizeof(DBT));
|
||
|
memset(&data, 0, sizeof(DBT));
|
||
|
memset(kstr, 0, sizeof(char) * 10);
|
||
|
memcpy(kstr + 4, "hello", 5 * sizeof(char));
|
||
|
memset(dstr, 0, sizeof(char) * 14);
|
||
|
|
||
|
CuAssert(ct, "DB->get_type", db->get_type(db, &type) == 0);
|
||
|
|
||
|
for (i = 1; i <= nkeys; i++) {
|
||
|
key.data = kstr;
|
||
|
if (type == DB_BTREE || type == DB_HASH) {
|
||
|
memcpy(kstr, &i, sizeof(u_int32_t));
|
||
|
key.size = sizeof(char) * 10;
|
||
|
} else {
|
||
|
memcpy(kstr, &i, sizeof(u_int32_t));
|
||
|
key.size = sizeof(db_recno_t);
|
||
|
}
|
||
|
for (j = 0; j < ndups; j++) {
|
||
|
memcpy(dstr, kstr, sizeof(char) * 9);
|
||
|
memcpy(dstr + 9, &j, sizeof(u_int32_t));
|
||
|
data.data = dstr;
|
||
|
data.size = sizeof(char) * 14;
|
||
|
|
||
|
CuAssert(ct, "DB->put",
|
||
|
db->put(db, NULL, &key, &data, 0) == 0);
|
||
|
}
|
||
|
}
|
||
|
}
|