📄 cxx_db.cpp
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1997-2002 * Sleepycat Software. All rights reserved. */#include "db_config.h"#ifndef lintstatic const char revid[] = "$Id: cxx_db.cpp,v 11.71 2002/08/26 22:13:36 mjc Exp $";#endif /* not lint */#include <errno.h>#include <string.h>#include "db_cxx.h"#include "dbinc/cxx_int.h"#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc_auto/db_auto.h"#include "dbinc_auto/crdel_auto.h"#include "dbinc/db_dispatch.h"#include "dbinc_auto/db_ext.h"#include "dbinc_auto/common_ext.h"// Helper macros for simple methods that pass through to the// underlying C method. It may return an error or raise an exception.// Note this macro expects that input _argspec is an argument// list element (e.g., "char *arg") and that _arglist is the arguments// that should be passed through to the C method (e.g., "(db, arg)")//#define DB_METHOD(_name, _argspec, _arglist, _retok) \int Db::_name _argspec \{ \ int ret; \ DB *db = unwrap(this); \ \ ret = db->_name _arglist; \ if (!_retok(ret)) \ DB_ERROR("Db::" # _name, ret, error_policy()); \ return (ret); \}#define DB_METHOD_CHECKED(_name, _cleanup, _argspec, _arglist, _retok) \int Db::_name _argspec \{ \ int ret; \ DB *db = unwrap(this); \ \ if (!db) { \ DB_ERROR("Db::" # _name, EINVAL, error_policy()); \ return (EINVAL); \ } \ if (_cleanup) \ cleanup(); \ ret = db->_name _arglist; \ if (!_retok(ret)) \ DB_ERROR("Db::" # _name, ret, error_policy()); \ return (ret); \}#define DB_METHOD_QUIET(_name, _argspec, _arglist) \int Db::_name _argspec \{ \ DB *db = unwrap(this); \ \ return (db->_name _arglist); \}#define DB_METHOD_VOID(_name, _argspec, _arglist) \void Db::_name _argspec \{ \ DB *db = unwrap(this); \ \ db->_name _arglist; \}// A truism for the Db object is that there is a valid// DB handle from the constructor until close().// After the close, the DB handle is invalid and// no operations are permitted on the Db (other than// destructor). Leaving the Db handle open and not// doing a close is generally considered an error.//// We used to allow Db objects to be closed and reopened.// This implied always keeping a valid DB object, and// coordinating the open objects between Db/DbEnv turned// out to be overly complicated. Now we do not allow this.Db::Db(DbEnv *env, u_int32_t flags): imp_(0), env_(env), construct_error_(0), flags_(0), construct_flags_(flags), append_recno_callback_(0), associate_callback_(0), bt_compare_callback_(0), bt_prefix_callback_(0), dup_compare_callback_(0), feedback_callback_(0), h_hash_callback_(0){ if (env_ == 0) flags_ |= DB_CXX_PRIVATE_ENV; if ((construct_error_ = initialize()) != 0) DB_ERROR("Db::Db", construct_error_, error_policy());}// If the DB handle is still open, we close it. This is to make stack// allocation of Db objects easier so that they are cleaned up in the error// path. If the environment was closed prior to this, it may cause a trap, but// an error message is generated during the environment close. Applications// should call close explicitly in normal (non-exceptional) cases to check the// return value.//Db::~Db(){ DB *db; db = unwrap(this); if (db != NULL) { cleanup(); (void)db->close(db, 0); }}// private method to initialize during constructor.// initialize must create a backing DB object,// and if that creates a new DB_ENV, it must be tied to a new DbEnv.//int Db::initialize(){ DB *db; DB_ENV *cenv = unwrap(env_); int ret; u_int32_t cxx_flags; cxx_flags = construct_flags_ & DB_CXX_NO_EXCEPTIONS; // Create a new underlying DB object. // We rely on the fact that if a NULL DB_ENV* is given, // one is allocated by DB. // if ((ret = db_create(&db, cenv, construct_flags_ & ~cxx_flags)) != 0) return (ret); // Associate the DB with this object imp_ = wrap(db); db->api_internal = this; // Create a new DbEnv from a DB_ENV* if it was created locally. // It is deleted in Db::close(). // if ((flags_ & DB_CXX_PRIVATE_ENV) != 0) env_ = new DbEnv(db->dbenv, cxx_flags); return (0);}// private method to cleanup after destructor or during close.// If the environment was created by this Db object, we optionally// delete it, or return it so the caller can delete it after// last use.//void Db::cleanup(){ DB *db = unwrap(this); if (db != NULL) { // extra safety db->api_internal = 0; imp_ = 0; // we must dispose of the DbEnv object if // we created it. This will be the case // if a NULL DbEnv was passed into the constructor. // The underlying DB_ENV object will be inaccessible // after the close, so we must clean it up now. // if ((flags_ & DB_CXX_PRIVATE_ENV) != 0) { env_->cleanup(); delete env_; env_ = 0; } }}// Return a tristate value corresponding to whether we should// throw exceptions on errors:// ON_ERROR_RETURN// ON_ERROR_THROW// ON_ERROR_UNKNOWN//int Db::error_policy(){ if (env_ != NULL) return (env_->error_policy()); else { // If the env_ is null, that means that the user // did not attach an environment, so the correct error // policy can be deduced from constructor flags // for this Db. // if ((construct_flags_ & DB_CXX_NO_EXCEPTIONS) != 0) { return (ON_ERROR_RETURN); } else { return (ON_ERROR_THROW); } }}int Db::close(u_int32_t flags){ DB *db = unwrap(this); int ret; // after a DB->close (no matter if success or failure), // the underlying DB object must not be accessed, // so we clean up in advance. // cleanup(); // It's safe to throw an error after the close, // since our error mechanism does not peer into // the DB* structures. // if ((ret = db->close(db, flags)) != 0) DB_ERROR("Db::close", ret, error_policy()); return (ret);}// The following cast implies that Dbc can be no larger than DBCDB_METHOD(cursor, (DbTxn *txnid, Dbc **cursorp, u_int32_t flags), (db, unwrap(txnid), (DBC **)cursorp, flags), DB_RETOK_STD)DB_METHOD(del, (DbTxn *txnid, Dbt *key, u_int32_t flags), (db, unwrap(txnid), key, flags), DB_RETOK_DBDEL)void Db::err(int error, const char *format, ...){ DB *db = unwrap(this); DB_REAL_ERR(db->dbenv, error, 1, 1, format);}void Db::errx(const char *format, ...){ DB *db = unwrap(this); DB_REAL_ERR(db->dbenv, 0, 0, 1, format);}DB_METHOD(fd, (int *fdp), (db, fdp), DB_RETOK_STD)int Db::get(DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags){ DB *db = unwrap(this); int ret; ret = db->get(db, unwrap(txnid), key, value, flags); if (!DB_RETOK_DBGET(ret)) { if (ret == ENOMEM && DB_OVERFLOWED_DBT(value)) DB_ERROR_DBT("Db::get", value, error_policy()); else DB_ERROR("Db::get", ret, error_policy()); } return (ret);}int Db::get_byteswapped(int *isswapped){ DB *db = (DB *)unwrapConst(this); return (db->get_byteswapped(db, isswapped));}int Db::get_type(DBTYPE *dbtype){ DB *db = (DB *)unwrapConst(this); return (db->get_type(db, dbtype));}// Dbc is a "compatible" subclass of DBC - that is, no virtual functions// or even extra data members, so these casts, although technically// non-portable, "should" always be okay.DB_METHOD(join, (Dbc **curslist, Dbc **cursorp, u_int32_t flags), (db, (DBC **)curslist, (DBC **)cursorp, flags), DB_RETOK_STD)DB_METHOD(key_range, (DbTxn *txnid, Dbt *key, DB_KEY_RANGE *results, u_int32_t flags),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -