/*
 * $Id: t-bdb-secondary-0.c,v 1.1 2005/07/29 22:05:44 ca Exp $
 */

/*
**  Just an example program how to use a secondary index;
**  taken from the BDB docs.
*/

#include "sm/generic.h"
SM_RCSID("@(#)$Id: t-bdb-secondary-0.c,v 1.1 2005/07/29 22:05:44 ca Exp $")

#include <stdio.h>
#include "sm/bdb.h"

struct student_record
{
	char student_id[4];
	char last_name[15];
	char first_name[15];
};

typedef struct student_record student_record_T;

void
handle_error(int ret)
{
	fprintf(stderr, "fail: %d\n", ret);
	exit(ret);
}

/*
 * getname -- extracts a secondary key (the last name) from a primary key/data
 * pair
 */

static int
getname(DB * dbp, const DBT * 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.
	 */

	memset(skey, 0, sizeof(DBT));
	skey->data = ((struct student_record *) pdata->data)->last_name;
	skey->size = sizeof((struct student_record *) pdata->data)->last_name;
	return (0);
}

static DB *dbp, *sdbp;
void
second(void)
{
	int ret;
#define dbenv	NULL

	/* Open/create primary */
	if ((ret = db_create(&dbp, dbenv, 0)) != 0)
		handle_error(ret);
	if ((ret = dbp->open(dbp, NULL,
			"students.db", NULL, DB_BTREE, DB_CREATE, 0600)) != 0)
		handle_error(ret);

	/*
	 * Open/create secondary. Note that it supports duplicate data * items,
	 * since last names might not be unique.
	 */

	if ((ret = db_create(&sdbp, dbenv, 0)) != 0)
		handle_error(ret);
	if ((ret = sdbp->set_flags(sdbp, DB_DUP | DB_DUPSORT)) != 0)
		handle_error(ret);
	if ((ret = sdbp->open(sdbp, NULL, "lastname.db", NULL, DB_BTREE,
				DB_CREATE, 0600)) != 0)
		handle_error(ret);

	/* Associate the secondary with the primary. */
	if ((ret = dbp->associate(dbp, NULL, sdbp, getname, 0)) != 0)
		handle_error(ret);
}

#define new_student(st, id, last, first)	\
	do {	\
		strlcpy((st).student_id, (id), sizeof((st).student_id)); \
		strlcpy((st).last_name, (last), sizeof((st).last_name)); \
		strlcpy((st).first_name, (first), sizeof((st).first_name)); \
	} while (0)

static void
closedb(void)
{
	int ret;

	if ((ret = dbp->close(dbp, 0)) != 0)
		handle_error(ret);
}

static void
putst(student_record_T * s0)
{
	int ret;
	DBT data, key;

#define txn	NULL

	memset(&key, 0, sizeof(key));
	memset(&data, 0, sizeof(data));
	key.data = s0->student_id;
	key.size = sizeof(s0->student_id);
	data.data = s0;
	data.size = sizeof(*s0);
	if ((ret = dbp->put(dbp, txn, &key, &data, 0)) != 0)
		handle_error(ret);
}

static void
bdb0(void)
{
	int ret;
	DBT data, key;
	DBC *dbcp;
	student_record_T s0, s1, s2;

	new_student(s0, "id0", "last0", "first0");
	new_student(s1, "id1", "last1", "first1");
	new_student(s2, "id2", "last2", "first2");

	second();

	putst(&s0);
	putst(&s2);
	putst(&s1);

	/* Acquire a cursor for the database. */
	if ((ret = dbp->cursor(sdbp, NULL, &dbcp, 0)) != 0)
	{
		sdbp->err(sdbp, ret, "DB->cursor");
		goto err;
	}

	/* Initialize the key/data return pair. */
	memset(&key, 0, sizeof(key));
	memset(&data, 0, sizeof(data));

#if 0
	while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0)
		printf("%.*s : %.*s\n",
			(int)key.size, (char *)key.data,
			(int)data.size, (char *)data.data);
	if (ret != DB_NOTFOUND)
	{
		sdbp->err(sdbp, ret, "DBcursor->get");
		goto err;
	}
#else
	if ((ret = dbcp->c_get(dbcp, &key, &data, DB_LAST)) == 0)
		printf("%.*s : %.*s\n",
			(int)key.size, (char *)key.data,
			(int)data.size, (char *)data.data);
	if ((ret = dbcp->c_del(dbcp, 0)) != 0)
		sdbp->err(sdbp, ret, "DBcursor->c_del");
	if ((ret = dbcp->c_get(dbcp, &key, &data, DB_LAST)) == 0)
		printf("%.*s : %.*s\n",
			(int)key.size, (char *)key.data,
			(int)data.size, (char *)data.data);
#endif

err:
	if ((ret = dbcp->c_close(dbcp)) != 0)
	{
		sdbp->err(sdbp, ret, "DBcursor->close");
	}

	closedb();
}


static void
usage(const char *prg)
{
	exit(-1);
}

int
main(int argc, char **argv)
{
	int ch;

	while ((ch = getopt(argc, argv, "V")) != -1)
	{
		switch (ch)
		{
		default:
			usage(argv[0]);
			return -1;
		}
	}
	bdb0();
	return (0);
}


syntax highlighted by Code2HTML, v. 0.9.1