You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
380 lines
8.3 KiB
380 lines
8.3 KiB
3 years ago
|
//
|
||
|
// 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 <http://www.htdig.org/>
|
||
|
// 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
|
||
|
// <http://www.gnu.org/copyleft/lgpl.html>
|
||
|
//
|
||
|
// $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 <fcntl.h>
|
||
|
#include <errno.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#ifdef HAVE_STD
|
||
|
#include <fstream>
|
||
|
#ifdef HAVE_NAMESPACES
|
||
|
using namespace std;
|
||
|
#endif
|
||
|
#else
|
||
|
#include <fstream.h>
|
||
|
#endif /* HAVE_STD */
|
||
|
|
||
|
#ifndef _MSC_VER /* _WIN32 */
|
||
|
#include <unistd.h>
|
||
|
#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);
|
||
|
}
|
||
|
|