[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
made.

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
thang).

-Mark Adamson
 Carnegie Mellon University



libraries/libldbm/ldbm.c
circa line 523 in version 1.36


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

	LDBM_LOCK;
	d = gdbm_firstkey( ldbm );
	LDBM_UNLOCK;

	/* 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 {
				free(cur);
				cur = NULL;
			}
		}
		else
			cur->dptr = NULL;
	}
	*dbcp = (LDBMCursor *)cur;


	return d;
}

Datum
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;

	LDBM_LOCK;
	key = gdbm_nextkey( ldbm, key );
	LDBM_UNLOCK;

	/* 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,
cur->dsize);
			else cur->dsize = 0;
		}
		else
			cur->dptr = NULL;
	}
	return key;
}