//
// DB2_db.cc
//
// DB2_db: Implements the Berkeley B-Tree database as a Database object
// (including duplicate values to allow duplicate word entries)
//
// Part of the ht://Dig package
// Copyright (c) 1999-2004 The ht://Dig Group
// For copyright details, see the file COPYING in your distribution
// or the GNU Library General Public License (LGPL) version 2 or later
//
//
// $Id: DB2_db.cc,v 1.26 2004/05/28 13:15:20 lha Exp $
//
#ifdef HAVE_CONFIG_H
#include "htconfig.h"
#endif /* HAVE_CONFIG_H */
#include
#include
#include
#ifdef HAVE_STD
#include
#ifdef HAVE_NAMESPACES
using namespace std;
#endif
#else
#include
#endif /* HAVE_STD */
#ifndef _MSC_VER /* _WIN32 */
#include
#endif
#include "DB2_db.h"
#include "HtConfiguration.h"
// Default cache size in kilobytes.
// Maybe this should be an config option, just for easy testing and
// determination for best system performance
// NOTE: page size is 1KB - do not change!!
#define CACHE_SIZE_IN_KB 64
//*****************************************************************************
// DB2_db::DB2_db()
//
DB2_db::DB2_db()
{
isOpen = 0;
_compare = 0;
_prefix = 0;
}
//*****************************************************************************
// DB2_db::~DB2_db()
//
DB2_db::~DB2_db()
{
Close();
}
//*****************************************************************************
//
int
DB2_db::Open(const char *filename, int flags, int mode)
{
//
// Initialize the database environment.
//
if((dbenv = db_init((char *)NULL)) == 0) return NOTOK;
if(CDB_db_create(&dbp, dbenv, 0) != 0) return NOTOK;
if(_compare) dbp->set_bt_compare(dbp, _compare);
if(_prefix) dbp->set_bt_prefix(dbp, _prefix);
//
// Open the database.
//
if((errno = dbp->open(dbp, filename, NULL, db_type, flags, mode)) == 0)
{
//
// Acquire a cursor for the database.
//
if ((seqrc = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0)
{
seqerr = seqrc;
Close();
return NOTOK;
}
isOpen = 1;
return OK;
}
else
{
return NOTOK;
}
}
//*****************************************************************************
// int DB2_db::Close()
//
int
DB2_db::Close()
{
if(isOpen)
{
//
// Close cursor, database and clean up environment
//
(void)(dbcp->c_close)(dbcp);
(void)(dbp->close)(dbp, 0);
(void)(dbenv->close(dbenv, 0));
dbenv = 0;
}
isOpen = 0;
return OK;
}
//*****************************************************************************
// char *DB2_db::Get_Next(String &item, String &key)
//
char *
DB2_db::Get_Next(String &item, String &key)
{
if (isOpen && !seqrc)
{
//
// Return values
//
key = skey;
lkey = skey;
item = data;
//
// Search for the next record
//
DBT local_key;
DBT local_data;
memset(&local_key, 0, sizeof(DBT));
memset(&local_data, 0, sizeof(DBT));
local_key.data = skey.get();
local_key.size = skey.length();
seqrc = dbcp->c_get(dbcp, &local_key, &local_data, DB_NEXT);
seqerr = seqrc;
if(!seqrc) {
data = 0;
data.append((char*)local_data.data, (int)local_data.size);
skey = 0;
skey.append((char*)local_key.data, (int)local_key.size);
}
return lkey.get();
}
else
return 0;
}
//*****************************************************************************
// void DB2_db::Start_Seq()
//
void
DB2_db::Start_Seq(const String& key)
{
DBT local_key;
DBT local_data;
memset(&local_key, 0, sizeof(DBT));
memset(&local_data, 0, sizeof(DBT));
skey = key;
local_key.data = skey.get();
local_key.size = skey.length();
if (isOpen && dbp)
{
//
// Okay, get the first key. Use DB_SET_RANGE for finding partial
// keys also. If you set it to DB_SET, and the words book, books
// and bookstore do exists, it will find them if you specify
// book*. However if you specify boo* if will not find
// anything. Setting to DB_SET_RANGE will still find the `first'
// word after boo* (which is book).
//
seqrc = dbcp->c_get(dbcp, &local_key, &local_data, DB_SET_RANGE);
seqerr = seqrc;
if(!seqrc) {
data = 0;
data.append((char*)local_data.data, (int)local_data.size);
skey = 0;
skey.append((char*)local_key.data, (int)local_key.size);
}
}
}
//*****************************************************************************
// void DB2_db::Start_Get()
//
void
DB2_db::Start_Get()
{
DBT local_key;
DBT local_data;
memset(&local_key, 0, sizeof(DBT));
memset(&local_data, 0, sizeof(DBT));
if (isOpen && dbp)
{
//
// Okay, get the first key. Use DB_SET_RANGE for finding partial
// keys also. If you set it to DB_SET, and the words book, books
// and bookstore do exists, it will find them if you specify
// book*. However if you specify boo* if will not find
// anything. Setting to DB_SET_RANGE will still find the `first'
// word after boo* (which is book).
//
seqrc = dbcp->c_get(dbcp, &local_key, &local_data, DB_FIRST);
seqerr = seqrc;
if(!seqrc) {
data = 0;
data.append((char*)local_data.data, (int)local_data.size);
skey = 0;
skey.append((char*)local_key.data, (int)local_key.size);
}
}
}
//*****************************************************************************
// int DB2_db::Put(const String &key, const String &data)
//
int
DB2_db::Put(const String &key, const String &data)
{
DBT k, d;
memset(&k, 0, sizeof(DBT));
memset(&d, 0, sizeof(DBT));
if (!isOpen)
return NOTOK;
k.data = (char*)key.get();
k.size = key.length();
d.data = (char*)data.get();
d.size = data.length();
//
// A 0 in the flags in put means replace, if you didn't specify DB_DUP
// somewhere else...
//
return (dbp->put)(dbp, NULL, &k, &d, 0) == 0 ? OK : NOTOK;
}
//*****************************************************************************
// int DB2_db::Get(const String &key, String &data)
//
int
DB2_db::Get(const String &key, String &data)
{
DBT k, d;
memset(&k, 0, sizeof(DBT));
memset(&d, 0, sizeof(DBT));
//
// k arg of get should be const but is not. Harmless cast.
//
k.data = (char*)key.get();
k.size = key.length();
int rc = dbp->get(dbp, NULL, &k, &d, 0);
if (rc)
return NOTOK;
data = 0;
data.append((char *)d.data, d.size);
return OK;
}
//*****************************************************************************
// int DB2_db::Exists(const String &key)
//
int
DB2_db::Exists(const String &key)
{
String data;
if (!isOpen)
return 0;
return Get(key, data);
}
//*****************************************************************************
// int DB2_db::Delete(const String &key)
//
int
DB2_db::Delete(const String &key)
{
DBT k;
memset(&k, 0, sizeof(DBT));
if (!isOpen)
return 0;
k.data = (char*)key.get();
k.size = key.length();
return (dbp->del)(dbp, NULL, &k, 0);
}
//*****************************************************************************
// DB2_db *DB2_db::getDatabaseInstance()
//
DB2_db *
DB2_db::getDatabaseInstance(DBTYPE)
{
return new DB2_db();
}
//*****************************************************************************
// void Error(const char *error_prefix, char *message);
//
void Error(const char *error_prefix, char *message)
{
// We don't do anything here, it's mostly a stub so we can set a breakpoint
// for debugging purposes
fprintf(stderr, "%s: %s\n", error_prefix, message);
}
//******************************************************************************
/*
* db_init --
* Initialize the environment. Only returns a pointer
*/
DB_ENV *
DB2_db::db_init(char *home)
{
DB_ENV *dbenv;
char *progname = "DB2 problem...";
int error;
if((error = CDB_db_env_create(&dbenv, 0)) != 0) {
fprintf(stderr, "DB2_db: CDB_db_env_create %s\n", CDB_db_strerror(error));
return 0;
}
dbenv->set_errpfx(dbenv, progname);
dbenv->set_errcall(dbenv, &Error);
if((error = dbenv->open(dbenv, (const char*)home, NULL, DB_CREATE | DB_PRIVATE | DB_INIT_LOCK | DB_INIT_MPOOL, 0666)) != 0) {
dbenv->err(dbenv, error, "open %s", (home ? home : ""));
return 0;
}
return (dbenv);
}