[Date Prev][Date Next] [Chronological] [Thread] [Top]

using cursors in LDBM back end with gdbm (ITS#450)

Programs such as slapindex that step through an LDBM back end database,
entry by entry, use the cursor variable

static LDBMCursor *cursorp = NULL;

in servers/slapd/back-ldbm/tools.c to keep track where they are in the
database. This cursorp variable is passed to ldbm_firstkey() and
ldbm_nextkey(), and those functions are expected to do their own database
dependant method of cursoring.

Those firstkey and nextkey functions appear in libraries/libldbm/ldbm.c,
once for each type of database (dbm, ndbm, gdbm, etc). The gdbm (and dbm)
version of ldbm_firstkey() and ldbm_lastkey() do not make use of the
cursor variable! Instead, the "key" variable is passed to the 
gdbm_nextkey() function as the cursor, and that "key" variable is
just a local variable in the calling function, so it has junk in it from
the stack. The result is that the value returned by gdbm_nextkey() is
indeterminant, (but most likely a "not found" value).

ldbm_firstkey() and ldbm_lastkey() need to do the ugly task of copying
fetched values into the cursor. The data fetched will most likely be
free'd before the next call to ldbm_nextkey(), so a complete copy must be

Here is the reimplementation of those too functions that I wrote and am
using. They are for gdbm, and similar versions could be made for dbm.
(As you can probably guess, I'm not real clear on this whole CVS checkin

-Mark Adamson
 Carnegie Mellon University

circa line 523 in version 1.36

ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
	Datum d, *cur;

	d = gdbm_firstkey( ldbm );

	/* Store the first key in the cursor */
	if (*dbcp) free (*dbcp);
	cur = (Datum *)malloc(sizeof(Datum));
	if (cur) {
		cur->dsize = d.dsize;
		if (cur->dsize) {
			cur->dptr = (char *)malloc(cur->dsize);
			if (cur->dptr)
				memcpy(cur->dptr, d.dptr, cur->dsize);
			else {
				cur = NULL;
			cur->dptr = NULL;
	*dbcp = (LDBMCursor *)cur;

	return d;

ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
	Datum *cur;

	/* Load the cursor into the key */
	cur = (Datum *)dbcp;
	if (cur == NULL) {
		key.dptr = 0;
		key.dsize = 0;
		return key;
	key.dptr = cur->dptr;
	key.dsize = cur->dsize;

	key = gdbm_nextkey( ldbm, key );

	/* Save this datum back into the key */
	if (cur->dsize == key.dsize)   /* Reuse the same dptr space */
		memcpy(cur->dptr, key.dptr, cur->dsize);
	else {
		cur->dsize = key.dsize;
		cur->dptr = (char *)realloc(cur->dptr, cur->dsize);
		if (cur->dsize) {
			if (cur->dptr) memcpy(cur->dptr, key.dptr,
			else cur->dsize = 0;
			cur->dptr = NULL;
	return key;