PageRenderTime 22ms CodeModel.GetById 59ms app.highlight 327ms RepoModel.GetById 2ms app.codeStats 1ms

/Modules/_bsddb.c

http://unladen-swallow.googlecode.com/
C | 7581 lines | 6090 code | 1117 blank | 374 comment | 772 complexity | b1b0974700e2265929347f1ae37b6bf2 MD5 | raw file
   1/*----------------------------------------------------------------------
   2  Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA
   3  and Andrew Kuchling. All rights reserved.
   4
   5  Redistribution and use in source and binary forms, with or without
   6  modification, are permitted provided that the following conditions are
   7  met:
   8
   9    o Redistributions of source code must retain the above copyright
  10      notice, this list of conditions, and the disclaimer that follows.
  11
  12    o Redistributions in binary form must reproduce the above copyright
  13      notice, this list of conditions, and the following disclaimer in
  14      the documentation and/or other materials provided with the
  15      distribution.
  16
  17    o Neither the name of Digital Creations nor the names of its
  18      contributors may be used to endorse or promote products derived
  19      from this software without specific prior written permission.
  20
  21  THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
  22  IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  23  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  24  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL
  25  CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  29  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  30  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  31  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  32  DAMAGE.
  33------------------------------------------------------------------------*/
  34
  35
  36/*
  37 * Handwritten code to wrap version 3.x of the Berkeley DB library,
  38 * written to replace a SWIG-generated file.  It has since been updated
  39 * to compile with Berkeley DB versions 3.2 through 4.2.
  40 *
  41 * This module was started by Andrew Kuchling to remove the dependency
  42 * on SWIG in a package by Gregory P. Smith who based his work on a
  43 * similar package by Robin Dunn <robin@alldunn.com> which wrapped
  44 * Berkeley DB 2.7.x.
  45 *
  46 * Development of this module then returned full circle back to Robin Dunn
  47 * who worked on behalf of Digital Creations to complete the wrapping of
  48 * the DB 3.x API and to build a solid unit test suite.  Robin has
  49 * since gone onto other projects (wxPython).
  50 *
  51 * Gregory P. Smith <greg@krypto.org> was once again the maintainer.
  52 *
  53 * Since January 2008, new maintainer is Jesus Cea <jcea@jcea.es>.
  54 * Jesus Cea licenses this code to PSF under a Contributor Agreement.
  55 *
  56 * Use the pybsddb-users@lists.sf.net mailing list for all questions.
  57 * Things can change faster than the header of this file is updated.  This
  58 * file is shared with the PyBSDDB project at SourceForge:
  59 *
  60 * http://pybsddb.sf.net
  61 *
  62 * This file should remain backward compatible with Python 2.1, but see PEP
  63 * 291 for the most current backward compatibility requirements:
  64 *
  65 * http://www.python.org/peps/pep-0291.html
  66 *
  67 * This module contains 6 types:
  68 *
  69 * DB           (Database)
  70 * DBCursor     (Database Cursor)
  71 * DBEnv        (database environment)
  72 * DBTxn        (An explicit database transaction)
  73 * DBLock       (A lock handle)
  74 * DBSequence   (Sequence)
  75 *
  76 */
  77
  78/* --------------------------------------------------------------------- */
  79
  80/*
  81 * Portions of this module, associated unit tests and build scripts are the
  82 * result of a contract with The Written Word (http://thewrittenword.com/)
  83 * Many thanks go out to them for causing me to raise the bar on quality and
  84 * functionality, resulting in a better bsddb3 package for all of us to use.
  85 *
  86 * --Robin
  87 */
  88
  89/* --------------------------------------------------------------------- */
  90
  91#include <stddef.h>   /* for offsetof() */
  92#include <Python.h>
  93
  94#define COMPILING_BSDDB_C
  95#include "bsddb.h"
  96#undef COMPILING_BSDDB_C
  97
  98static char *rcs_id = "$Id: _bsddb.c 66568 2008-09-23 18:54:08Z jesus.cea $";
  99
 100/* --------------------------------------------------------------------- */
 101/* Various macro definitions */
 102
 103#if (PY_VERSION_HEX < 0x02050000)
 104typedef int Py_ssize_t;
 105#endif
 106
 107#if (PY_VERSION_HEX < 0x02060000)  /* really: before python trunk r63675 */
 108/* This code now uses PyBytes* API function names instead of PyString*.
 109 * These #defines map to their equivalent on earlier python versions.    */
 110#define PyBytes_FromStringAndSize PyString_FromStringAndSize
 111#define PyBytes_FromString PyString_FromString
 112#define PyBytes_AsStringAndSize PyString_AsStringAndSize
 113#define PyBytes_Check PyString_Check
 114#define PyBytes_GET_SIZE PyString_GET_SIZE
 115#define PyBytes_AS_STRING PyString_AS_STRING
 116#endif
 117
 118#if (PY_VERSION_HEX >= 0x03000000)
 119#define NUMBER_Check    PyLong_Check
 120#define NUMBER_AsLong   PyLong_AsLong
 121#define NUMBER_FromLong PyLong_FromLong
 122#else
 123#define NUMBER_Check    PyInt_Check
 124#define NUMBER_AsLong   PyInt_AsLong
 125#define NUMBER_FromLong PyInt_FromLong
 126#endif
 127
 128#ifdef WITH_THREAD
 129
 130/* These are for when calling Python --> C */
 131#define MYDB_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS;
 132#define MYDB_END_ALLOW_THREADS Py_END_ALLOW_THREADS;
 133
 134/* For 2.3, use the PyGILState_ calls */
 135#if (PY_VERSION_HEX >= 0x02030000)
 136#define MYDB_USE_GILSTATE
 137#endif
 138
 139/* and these are for calling C --> Python */
 140#if defined(MYDB_USE_GILSTATE)
 141#define MYDB_BEGIN_BLOCK_THREADS \
 142		PyGILState_STATE __savestate = PyGILState_Ensure();
 143#define MYDB_END_BLOCK_THREADS \
 144		PyGILState_Release(__savestate);
 145#else /* MYDB_USE_GILSTATE */
 146/* Pre GILState API - do it the long old way */
 147static PyInterpreterState* _db_interpreterState = NULL;
 148#define MYDB_BEGIN_BLOCK_THREADS {                              \
 149        PyThreadState* prevState;                               \
 150        PyThreadState* newState;                                \
 151        PyEval_AcquireLock();                                   \
 152        newState  = PyThreadState_New(_db_interpreterState);    \
 153        prevState = PyThreadState_Swap(newState);
 154
 155#define MYDB_END_BLOCK_THREADS                                  \
 156        newState = PyThreadState_Swap(prevState);               \
 157        PyThreadState_Clear(newState);                          \
 158        PyEval_ReleaseLock();                                   \
 159        PyThreadState_Delete(newState);                         \
 160        }
 161#endif /* MYDB_USE_GILSTATE */
 162
 163#else
 164/* Compiled without threads - avoid all this cruft */
 165#define MYDB_BEGIN_ALLOW_THREADS
 166#define MYDB_END_ALLOW_THREADS
 167#define MYDB_BEGIN_BLOCK_THREADS
 168#define MYDB_END_BLOCK_THREADS
 169
 170#endif
 171
 172/* Should DB_INCOMPLETE be turned into a warning or an exception? */
 173#define INCOMPLETE_IS_WARNING 1
 174
 175/* --------------------------------------------------------------------- */
 176/* Exceptions */
 177
 178static PyObject* DBError;               /* Base class, all others derive from this */
 179static PyObject* DBCursorClosedError;   /* raised when trying to use a closed cursor object */
 180static PyObject* DBKeyEmptyError;       /* DB_KEYEMPTY: also derives from KeyError */
 181static PyObject* DBKeyExistError;       /* DB_KEYEXIST */
 182static PyObject* DBLockDeadlockError;   /* DB_LOCK_DEADLOCK */
 183static PyObject* DBLockNotGrantedError; /* DB_LOCK_NOTGRANTED */
 184static PyObject* DBNotFoundError;       /* DB_NOTFOUND: also derives from KeyError */
 185static PyObject* DBOldVersionError;     /* DB_OLD_VERSION */
 186static PyObject* DBRunRecoveryError;    /* DB_RUNRECOVERY */
 187static PyObject* DBVerifyBadError;      /* DB_VERIFY_BAD */
 188static PyObject* DBNoServerError;       /* DB_NOSERVER */
 189static PyObject* DBNoServerHomeError;   /* DB_NOSERVER_HOME */
 190static PyObject* DBNoServerIDError;     /* DB_NOSERVER_ID */
 191static PyObject* DBPageNotFoundError;   /* DB_PAGE_NOTFOUND */
 192static PyObject* DBSecondaryBadError;   /* DB_SECONDARY_BAD */
 193
 194#if !INCOMPLETE_IS_WARNING
 195static PyObject* DBIncompleteError;     /* DB_INCOMPLETE */
 196#endif
 197
 198static PyObject* DBInvalidArgError;     /* EINVAL */
 199static PyObject* DBAccessError;         /* EACCES */
 200static PyObject* DBNoSpaceError;        /* ENOSPC */
 201static PyObject* DBNoMemoryError;       /* DB_BUFFER_SMALL (ENOMEM when < 4.3) */
 202static PyObject* DBAgainError;          /* EAGAIN */
 203static PyObject* DBBusyError;           /* EBUSY  */
 204static PyObject* DBFileExistsError;     /* EEXIST */
 205static PyObject* DBNoSuchFileError;     /* ENOENT */
 206static PyObject* DBPermissionsError;    /* EPERM  */
 207
 208#if (DBVER >= 42)
 209static PyObject* DBRepHandleDeadError;  /* DB_REP_HANDLE_DEAD */
 210#endif
 211
 212static PyObject* DBRepUnavailError;     /* DB_REP_UNAVAIL */
 213
 214#if (DBVER < 43)
 215#define	DB_BUFFER_SMALL		ENOMEM
 216#endif
 217
 218
 219/* --------------------------------------------------------------------- */
 220/* Structure definitions */
 221
 222#if PYTHON_API_VERSION < 1010
 223#error "Python 2.1 or later required"
 224#endif
 225
 226
 227/* Defaults for moduleFlags in DBEnvObject and DBObject. */
 228#define DEFAULT_GET_RETURNS_NONE                1
 229#define DEFAULT_CURSOR_SET_RETURNS_NONE         1   /* 0 in pybsddb < 4.2, python < 2.4 */
 230
 231
 232/* See comment in Python 2.6 "object.h" */
 233#ifndef staticforward
 234#define staticforward static
 235#endif
 236#ifndef statichere
 237#define statichere static
 238#endif
 239
 240staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type,
 241              DBLock_Type;
 242#if (DBVER >= 43)
 243staticforward PyTypeObject DBSequence_Type;
 244#endif
 245
 246#ifndef Py_TYPE
 247/* for compatibility with Python 2.5 and earlier */
 248#define Py_TYPE(ob)              (((PyObject*)(ob))->ob_type)
 249#endif
 250
 251#define DBObject_Check(v)           (Py_TYPE(v) == &DB_Type)
 252#define DBCursorObject_Check(v)     (Py_TYPE(v) == &DBCursor_Type)
 253#define DBEnvObject_Check(v)        (Py_TYPE(v) == &DBEnv_Type)
 254#define DBTxnObject_Check(v)        (Py_TYPE(v) == &DBTxn_Type)
 255#define DBLockObject_Check(v)       (Py_TYPE(v) == &DBLock_Type)
 256#if (DBVER >= 43)
 257#define DBSequenceObject_Check(v)   (Py_TYPE(v) == &DBSequence_Type)
 258#endif
 259
 260#if (DBVER < 46)
 261  #define _DBC_close(dbc)           dbc->c_close(dbc)
 262  #define _DBC_count(dbc,a,b)       dbc->c_count(dbc,a,b)
 263  #define _DBC_del(dbc,a)           dbc->c_del(dbc,a)
 264  #define _DBC_dup(dbc,a,b)         dbc->c_dup(dbc,a,b)
 265  #define _DBC_get(dbc,a,b,c)       dbc->c_get(dbc,a,b,c)
 266  #define _DBC_pget(dbc,a,b,c,d)    dbc->c_pget(dbc,a,b,c,d)
 267  #define _DBC_put(dbc,a,b,c)       dbc->c_put(dbc,a,b,c)
 268#else
 269  #define _DBC_close(dbc)           dbc->close(dbc)
 270  #define _DBC_count(dbc,a,b)       dbc->count(dbc,a,b)
 271  #define _DBC_del(dbc,a)           dbc->del(dbc,a)
 272  #define _DBC_dup(dbc,a,b)         dbc->dup(dbc,a,b)
 273  #define _DBC_get(dbc,a,b,c)       dbc->get(dbc,a,b,c)
 274  #define _DBC_pget(dbc,a,b,c,d)    dbc->pget(dbc,a,b,c,d)
 275  #define _DBC_put(dbc,a,b,c)       dbc->put(dbc,a,b,c)
 276#endif
 277
 278
 279/* --------------------------------------------------------------------- */
 280/* Utility macros and functions */
 281
 282#define INSERT_IN_DOUBLE_LINKED_LIST(backlink,object)                   \
 283    {                                                                   \
 284        object->sibling_next=backlink;                                  \
 285        object->sibling_prev_p=&(backlink);                             \
 286        backlink=object;                                                \
 287        if (object->sibling_next) {                                     \
 288          object->sibling_next->sibling_prev_p=&(object->sibling_next); \
 289        }                                                               \
 290    }
 291
 292#define EXTRACT_FROM_DOUBLE_LINKED_LIST(object)                          \
 293    {                                                                    \
 294        if (object->sibling_next) {                                      \
 295            object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
 296        }                                                                \
 297        *(object->sibling_prev_p)=object->sibling_next;                  \
 298    }
 299
 300#define EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(object)               \
 301    {                                                                    \
 302        if (object->sibling_next) {                                      \
 303            object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
 304        }                                                                \
 305        if (object->sibling_prev_p) {                                    \
 306            *(object->sibling_prev_p)=object->sibling_next;              \
 307        }                                                                \
 308    }
 309
 310#define INSERT_IN_DOUBLE_LINKED_LIST_TXN(backlink,object)  \
 311    {                                                      \
 312        object->sibling_next_txn=backlink;                 \
 313        object->sibling_prev_p_txn=&(backlink);            \
 314        backlink=object;                                   \
 315        if (object->sibling_next_txn) {                    \
 316            object->sibling_next_txn->sibling_prev_p_txn=  \
 317                &(object->sibling_next_txn);               \
 318        }                                                  \
 319    }
 320
 321#define EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(object)             \
 322    {                                                           \
 323        if (object->sibling_next_txn) {                         \
 324            object->sibling_next_txn->sibling_prev_p_txn=       \
 325                object->sibling_prev_p_txn;                     \
 326        }                                                       \
 327        *(object->sibling_prev_p_txn)=object->sibling_next_txn; \
 328    }
 329
 330
 331#define RETURN_IF_ERR()          \
 332    if (makeDBError(err)) {      \
 333        return NULL;             \
 334    }
 335
 336#define RETURN_NONE()  Py_INCREF(Py_None); return Py_None;
 337
 338#define _CHECK_OBJECT_NOT_CLOSED(nonNull, pyErrObj, name) \
 339    if ((nonNull) == NULL) {          \
 340        PyObject *errTuple = NULL;    \
 341        errTuple = Py_BuildValue("(is)", 0, #name " object has been closed"); \
 342        if (errTuple) { \
 343            PyErr_SetObject((pyErrObj), errTuple);  \
 344            Py_DECREF(errTuple);          \
 345        } \
 346        return NULL;                  \
 347    }
 348
 349#define CHECK_DB_NOT_CLOSED(dbobj) \
 350        _CHECK_OBJECT_NOT_CLOSED(dbobj->db, DBError, DB)
 351
 352#define CHECK_ENV_NOT_CLOSED(env) \
 353        _CHECK_OBJECT_NOT_CLOSED(env->db_env, DBError, DBEnv)
 354
 355#define CHECK_CURSOR_NOT_CLOSED(curs) \
 356        _CHECK_OBJECT_NOT_CLOSED(curs->dbc, DBCursorClosedError, DBCursor)
 357
 358#if (DBVER >= 43)
 359#define CHECK_SEQUENCE_NOT_CLOSED(curs) \
 360        _CHECK_OBJECT_NOT_CLOSED(curs->sequence, DBError, DBSequence)
 361#endif
 362
 363#define CHECK_DBFLAG(mydb, flag)    (((mydb)->flags & (flag)) || \
 364                                     (((mydb)->myenvobj != NULL) && ((mydb)->myenvobj->flags & (flag))))
 365
 366#define CLEAR_DBT(dbt)              (memset(&(dbt), 0, sizeof(dbt)))
 367
 368#define FREE_DBT(dbt)               if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \
 369                                         dbt.data != NULL) { free(dbt.data); dbt.data = NULL; }
 370
 371
 372static int makeDBError(int err);
 373
 374
 375/* Return the access method type of the DBObject */
 376static int _DB_get_type(DBObject* self)
 377{
 378    DBTYPE type;
 379    int err;
 380
 381    err = self->db->get_type(self->db, &type);
 382    if (makeDBError(err)) {
 383        return -1;
 384    }
 385    return type;
 386}
 387
 388
 389/* Create a DBT structure (containing key and data values) from Python
 390   strings.  Returns 1 on success, 0 on an error. */
 391static int make_dbt(PyObject* obj, DBT* dbt)
 392{
 393    CLEAR_DBT(*dbt);
 394    if (obj == Py_None) {
 395        /* no need to do anything, the structure has already been zeroed */
 396    }
 397    else if (!PyArg_Parse(obj, "s#", &dbt->data, &dbt->size)) {
 398        PyErr_SetString(PyExc_TypeError,
 399#if (PY_VERSION_HEX < 0x03000000)
 400                        "Data values must be of type string or None.");
 401#else
 402                        "Data values must be of type bytes or None.");
 403#endif
 404        return 0;
 405    }
 406    return 1;
 407}
 408
 409
 410/* Recno and Queue DBs can have integer keys.  This function figures out
 411   what's been given, verifies that it's allowed, and then makes the DBT.
 412
 413   Caller MUST call FREE_DBT(key) when done. */
 414static int
 415make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags)
 416{
 417    db_recno_t recno;
 418    int type;
 419
 420    CLEAR_DBT(*key);
 421    if (keyobj == Py_None) {
 422        type = _DB_get_type(self);
 423        if (type == -1)
 424            return 0;
 425        if (type == DB_RECNO || type == DB_QUEUE) {
 426            PyErr_SetString(
 427                PyExc_TypeError,
 428                "None keys not allowed for Recno and Queue DB's");
 429            return 0;
 430        }
 431        /* no need to do anything, the structure has already been zeroed */
 432    }
 433
 434    else if (PyBytes_Check(keyobj)) {
 435        /* verify access method type */
 436        type = _DB_get_type(self);
 437        if (type == -1)
 438            return 0;
 439        if (type == DB_RECNO || type == DB_QUEUE) {
 440            PyErr_SetString(
 441                PyExc_TypeError,
 442#if (PY_VERSION_HEX < 0x03000000)
 443                "String keys not allowed for Recno and Queue DB's");
 444#else
 445                "Bytes keys not allowed for Recno and Queue DB's");
 446#endif
 447            return 0;
 448        }
 449
 450        /*
 451         * NOTE(gps): I don't like doing a data copy here, it seems
 452         * wasteful.  But without a clean way to tell FREE_DBT if it
 453         * should free key->data or not we have to.  Other places in
 454         * the code check for DB_THREAD and forceably set DBT_MALLOC
 455         * when we otherwise would leave flags 0 to indicate that.
 456         */
 457        key->data = malloc(PyBytes_GET_SIZE(keyobj));
 458        if (key->data == NULL) {
 459            PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
 460            return 0;
 461        }
 462        memcpy(key->data, PyBytes_AS_STRING(keyobj),
 463               PyBytes_GET_SIZE(keyobj));
 464        key->flags = DB_DBT_REALLOC;
 465        key->size = PyBytes_GET_SIZE(keyobj);
 466    }
 467
 468    else if (NUMBER_Check(keyobj)) {
 469        /* verify access method type */
 470        type = _DB_get_type(self);
 471        if (type == -1)
 472            return 0;
 473        if (type == DB_BTREE && pflags != NULL) {
 474            /* if BTREE then an Integer key is allowed with the
 475             * DB_SET_RECNO flag */
 476            *pflags |= DB_SET_RECNO;
 477        }
 478        else if (type != DB_RECNO && type != DB_QUEUE) {
 479            PyErr_SetString(
 480                PyExc_TypeError,
 481                "Integer keys only allowed for Recno and Queue DB's");
 482            return 0;
 483        }
 484
 485        /* Make a key out of the requested recno, use allocated space so DB
 486         * will be able to realloc room for the real key if needed. */
 487        recno = NUMBER_AsLong(keyobj);
 488        key->data = malloc(sizeof(db_recno_t));
 489        if (key->data == NULL) {
 490            PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
 491            return 0;
 492        }
 493        key->ulen = key->size = sizeof(db_recno_t);
 494        memcpy(key->data, &recno, sizeof(db_recno_t));
 495        key->flags = DB_DBT_REALLOC;
 496    }
 497    else {
 498        PyErr_Format(PyExc_TypeError,
 499#if (PY_VERSION_HEX < 0x03000000)
 500                     "String or Integer object expected for key, %s found",
 501#else
 502                     "Bytes or Integer object expected for key, %s found",
 503#endif
 504                     Py_TYPE(keyobj)->tp_name);
 505        return 0;
 506    }
 507
 508    return 1;
 509}
 510
 511
 512/* Add partial record access to an existing DBT data struct.
 513   If dlen and doff are set, then the DB_DBT_PARTIAL flag will be set
 514   and the data storage/retrieval will be done using dlen and doff. */
 515static int add_partial_dbt(DBT* d, int dlen, int doff) {
 516    /* if neither were set we do nothing (-1 is the default value) */
 517    if ((dlen == -1) && (doff == -1)) {
 518        return 1;
 519    }
 520
 521    if ((dlen < 0) || (doff < 0)) {
 522        PyErr_SetString(PyExc_TypeError, "dlen and doff must both be >= 0");
 523        return 0;
 524    }
 525
 526    d->flags = d->flags | DB_DBT_PARTIAL;
 527    d->dlen = (unsigned int) dlen;
 528    d->doff = (unsigned int) doff;
 529    return 1;
 530}
 531
 532/* a safe strcpy() without the zeroing behaviour and semantics of strncpy. */
 533/* TODO: make this use the native libc strlcpy() when available (BSD)      */
 534unsigned int our_strlcpy(char* dest, const char* src, unsigned int n)
 535{
 536    unsigned int srclen, copylen;
 537
 538    srclen = strlen(src);
 539    if (n <= 0)
 540	return srclen;
 541    copylen = (srclen > n-1) ? n-1 : srclen;
 542    /* populate dest[0] thru dest[copylen-1] */
 543    memcpy(dest, src, copylen);
 544    /* guarantee null termination */
 545    dest[copylen] = 0;
 546
 547    return srclen;
 548}
 549
 550/* Callback used to save away more information about errors from the DB
 551 * library. */
 552static char _db_errmsg[1024];
 553#if (DBVER <= 42)
 554static void _db_errorCallback(const char* prefix, char* msg)
 555#else
 556static void _db_errorCallback(const DB_ENV *db_env,
 557	const char* prefix, const char* msg)
 558#endif
 559{
 560    our_strlcpy(_db_errmsg, msg, sizeof(_db_errmsg));
 561}
 562
 563
 564/*
 565** We need these functions because some results
 566** are undefined if pointer is NULL. Some other
 567** give None instead of "".
 568**
 569** This functions are static and will be
 570** -I hope- inlined.
 571*/
 572static const char *DummyString = "This string is a simple placeholder";
 573static PyObject *Build_PyString(const char *p,int s)
 574{
 575  if (!p) {
 576    p=DummyString;
 577    assert(s==0);
 578  }
 579  return PyBytes_FromStringAndSize(p,s);
 580}
 581
 582static PyObject *BuildValue_S(const void *p,int s)
 583{
 584  if (!p) {
 585    p=DummyString;
 586    assert(s==0);
 587  }
 588  return PyBytes_FromStringAndSize(p, s);
 589}
 590
 591static PyObject *BuildValue_SS(const void *p1,int s1,const void *p2,int s2)
 592{
 593PyObject *a, *b, *r;
 594
 595  if (!p1) {
 596    p1=DummyString;
 597    assert(s1==0);
 598  }
 599  if (!p2) {
 600    p2=DummyString;
 601    assert(s2==0);
 602  }
 603
 604  if (!(a = PyBytes_FromStringAndSize(p1, s1))) {
 605      return NULL;
 606  }
 607  if (!(b = PyBytes_FromStringAndSize(p2, s2))) {
 608      Py_DECREF(a);
 609      return NULL;
 610  }
 611
 612#if (PY_VERSION_HEX >= 0x02040000)
 613  r = PyTuple_Pack(2, a, b) ;
 614#else
 615  r = Py_BuildValue("OO", a, b);
 616#endif
 617  Py_DECREF(a);
 618  Py_DECREF(b);
 619  return r;
 620}
 621
 622static PyObject *BuildValue_IS(int i,const void *p,int s)
 623{
 624  PyObject *a, *r;
 625
 626  if (!p) {
 627    p=DummyString;
 628    assert(s==0);
 629  }
 630
 631  if (!(a = PyBytes_FromStringAndSize(p, s))) {
 632      return NULL;
 633  }
 634
 635  r = Py_BuildValue("iO", i, a);
 636  Py_DECREF(a);
 637  return r;
 638}
 639
 640static PyObject *BuildValue_LS(long l,const void *p,int s)
 641{
 642  PyObject *a, *r;
 643
 644  if (!p) {
 645    p=DummyString;
 646    assert(s==0);
 647  }
 648
 649  if (!(a = PyBytes_FromStringAndSize(p, s))) {
 650      return NULL;
 651  }
 652
 653  r = Py_BuildValue("lO", l, a);
 654  Py_DECREF(a);
 655  return r;
 656}
 657
 658
 659
 660/* make a nice exception object to raise for errors. */
 661static int makeDBError(int err)
 662{
 663    char errTxt[2048];  /* really big, just in case... */
 664    PyObject *errObj = NULL;
 665    PyObject *errTuple = NULL;
 666    int exceptionRaised = 0;
 667    unsigned int bytes_left;
 668
 669    switch (err) {
 670        case 0:                     /* successful, no error */      break;
 671
 672#if (DBVER < 41)
 673        case DB_INCOMPLETE:
 674#if INCOMPLETE_IS_WARNING
 675            bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt));
 676            /* Ensure that bytes_left never goes negative */
 677            if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) {
 678                bytes_left = sizeof(errTxt) - bytes_left - 4 - 1;
 679		assert(bytes_left >= 0);
 680                strcat(errTxt, " -- ");
 681                strncat(errTxt, _db_errmsg, bytes_left);
 682            }
 683            _db_errmsg[0] = 0;
 684            exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt);
 685
 686#else  /* do an exception instead */
 687        errObj = DBIncompleteError;
 688#endif
 689        break;
 690#endif /* DBVER < 41 */
 691
 692        case DB_KEYEMPTY:           errObj = DBKeyEmptyError;       break;
 693        case DB_KEYEXIST:           errObj = DBKeyExistError;       break;
 694        case DB_LOCK_DEADLOCK:      errObj = DBLockDeadlockError;   break;
 695        case DB_LOCK_NOTGRANTED:    errObj = DBLockNotGrantedError; break;
 696        case DB_NOTFOUND:           errObj = DBNotFoundError;       break;
 697        case DB_OLD_VERSION:        errObj = DBOldVersionError;     break;
 698        case DB_RUNRECOVERY:        errObj = DBRunRecoveryError;    break;
 699        case DB_VERIFY_BAD:         errObj = DBVerifyBadError;      break;
 700        case DB_NOSERVER:           errObj = DBNoServerError;       break;
 701        case DB_NOSERVER_HOME:      errObj = DBNoServerHomeError;   break;
 702        case DB_NOSERVER_ID:        errObj = DBNoServerIDError;     break;
 703        case DB_PAGE_NOTFOUND:      errObj = DBPageNotFoundError;   break;
 704        case DB_SECONDARY_BAD:      errObj = DBSecondaryBadError;   break;
 705        case DB_BUFFER_SMALL:       errObj = DBNoMemoryError;       break;
 706
 707#if (DBVER >= 43)
 708	/* ENOMEM and DB_BUFFER_SMALL were one and the same until 4.3 */
 709	case ENOMEM:  errObj = PyExc_MemoryError;   break;
 710#endif
 711        case EINVAL:  errObj = DBInvalidArgError;   break;
 712        case EACCES:  errObj = DBAccessError;       break;
 713        case ENOSPC:  errObj = DBNoSpaceError;      break;
 714        case EAGAIN:  errObj = DBAgainError;        break;
 715        case EBUSY :  errObj = DBBusyError;         break;
 716        case EEXIST:  errObj = DBFileExistsError;   break;
 717        case ENOENT:  errObj = DBNoSuchFileError;   break;
 718        case EPERM :  errObj = DBPermissionsError;  break;
 719
 720#if (DBVER >= 42)
 721        case DB_REP_HANDLE_DEAD : errObj = DBRepHandleDeadError; break;
 722#endif
 723
 724        case DB_REP_UNAVAIL : errObj = DBRepUnavailError; break;
 725
 726        default:      errObj = DBError;             break;
 727    }
 728
 729    if (errObj != NULL) {
 730        bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt));
 731        /* Ensure that bytes_left never goes negative */
 732        if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) {
 733            bytes_left = sizeof(errTxt) - bytes_left - 4 - 1;
 734            assert(bytes_left >= 0);
 735            strcat(errTxt, " -- ");
 736            strncat(errTxt, _db_errmsg, bytes_left);
 737        }
 738        _db_errmsg[0] = 0;
 739
 740        errTuple = Py_BuildValue("(is)", err, errTxt);
 741        if (errTuple == NULL) {
 742            Py_DECREF(errObj);
 743            return !0;
 744        }
 745        PyErr_SetObject(errObj, errTuple);
 746        Py_DECREF(errTuple);
 747    }
 748
 749    return ((errObj != NULL) || exceptionRaised);
 750}
 751
 752
 753
 754/* set a type exception */
 755static void makeTypeError(char* expected, PyObject* found)
 756{
 757    PyErr_Format(PyExc_TypeError, "Expected %s argument, %s found.",
 758                 expected, Py_TYPE(found)->tp_name);
 759}
 760
 761
 762/* verify that an obj is either None or a DBTxn, and set the txn pointer */
 763static int checkTxnObj(PyObject* txnobj, DB_TXN** txn)
 764{
 765    if (txnobj == Py_None || txnobj == NULL) {
 766        *txn = NULL;
 767        return 1;
 768    }
 769    if (DBTxnObject_Check(txnobj)) {
 770        *txn = ((DBTxnObject*)txnobj)->txn;
 771        return 1;
 772    }
 773    else
 774        makeTypeError("DBTxn", txnobj);
 775    return 0;
 776}
 777
 778
 779/* Delete a key from a database
 780  Returns 0 on success, -1 on an error.  */
 781static int _DB_delete(DBObject* self, DB_TXN *txn, DBT *key, int flags)
 782{
 783    int err;
 784
 785    MYDB_BEGIN_ALLOW_THREADS;
 786    err = self->db->del(self->db, txn, key, 0);
 787    MYDB_END_ALLOW_THREADS;
 788    if (makeDBError(err)) {
 789        return -1;
 790    }
 791    self->haveStat = 0;
 792    return 0;
 793}
 794
 795
 796/* Store a key into a database
 797   Returns 0 on success, -1 on an error.  */
 798static int _DB_put(DBObject* self, DB_TXN *txn, DBT *key, DBT *data, int flags)
 799{
 800    int err;
 801
 802    MYDB_BEGIN_ALLOW_THREADS;
 803    err = self->db->put(self->db, txn, key, data, flags);
 804    MYDB_END_ALLOW_THREADS;
 805    if (makeDBError(err)) {
 806        return -1;
 807    }
 808    self->haveStat = 0;
 809    return 0;
 810}
 811
 812/* Get a key/data pair from a cursor */
 813static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
 814			       PyObject *args, PyObject *kwargs, char *format)
 815{
 816    int err;
 817    PyObject* retval = NULL;
 818    DBT key, data;
 819    int dlen = -1;
 820    int doff = -1;
 821    int flags = 0;
 822    static char* kwnames[] = { "flags", "dlen", "doff", NULL };
 823
 824    if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, kwnames,
 825				     &flags, &dlen, &doff)) 
 826      return NULL;
 827
 828    CHECK_CURSOR_NOT_CLOSED(self);
 829
 830    flags |= extra_flags;
 831    CLEAR_DBT(key);
 832    CLEAR_DBT(data);
 833    if (!add_partial_dbt(&data, dlen, doff))
 834        return NULL;
 835
 836    MYDB_BEGIN_ALLOW_THREADS;
 837    err = _DBC_get(self->dbc, &key, &data, flags);
 838    MYDB_END_ALLOW_THREADS;
 839
 840    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
 841	    && self->mydb->moduleFlags.getReturnsNone) {
 842        Py_INCREF(Py_None);
 843        retval = Py_None;
 844    }
 845    else if (makeDBError(err)) {
 846        retval = NULL;
 847    }
 848    else {  /* otherwise, success! */
 849
 850        /* if Recno or Queue, return the key as an Int */
 851        switch (_DB_get_type(self->mydb)) {
 852        case -1:
 853            retval = NULL;
 854            break;
 855
 856        case DB_RECNO:
 857        case DB_QUEUE:
 858            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
 859            break;
 860        case DB_HASH:
 861        case DB_BTREE:
 862        default:
 863            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
 864            break;
 865        }
 866    }
 867    return retval;
 868}
 869
 870
 871/* add an integer to a dictionary using the given name as a key */
 872static void _addIntToDict(PyObject* dict, char *name, int value)
 873{
 874    PyObject* v = NUMBER_FromLong((long) value);
 875    if (!v || PyDict_SetItemString(dict, name, v))
 876        PyErr_Clear();
 877
 878    Py_XDECREF(v);
 879}
 880
 881/* The same, when the value is a time_t */
 882static void _addTimeTToDict(PyObject* dict, char *name, time_t value)
 883{
 884    PyObject* v;
 885	/* if the value fits in regular int, use that. */
 886#ifdef PY_LONG_LONG
 887	if (sizeof(time_t) > sizeof(long))
 888		v = PyLong_FromLongLong((PY_LONG_LONG) value);
 889	else
 890#endif
 891		v = NUMBER_FromLong((long) value);
 892    if (!v || PyDict_SetItemString(dict, name, v))
 893        PyErr_Clear();
 894
 895    Py_XDECREF(v);
 896}
 897
 898#if (DBVER >= 43)
 899/* add an db_seq_t to a dictionary using the given name as a key */
 900static void _addDb_seq_tToDict(PyObject* dict, char *name, db_seq_t value)
 901{
 902    PyObject* v = PyLong_FromLongLong(value);
 903    if (!v || PyDict_SetItemString(dict, name, v))
 904        PyErr_Clear();
 905
 906    Py_XDECREF(v);
 907}
 908#endif
 909
 910static void _addDB_lsnToDict(PyObject* dict, char *name, DB_LSN value)
 911{
 912    PyObject *v = Py_BuildValue("(ll)",value.file,value.offset);
 913    if (!v || PyDict_SetItemString(dict, name, v))
 914        PyErr_Clear();
 915
 916    Py_XDECREF(v);
 917}
 918
 919/* --------------------------------------------------------------------- */
 920/* Allocators and deallocators */
 921
 922static DBObject*
 923newDBObject(DBEnvObject* arg, int flags)
 924{
 925    DBObject* self;
 926    DB_ENV* db_env = NULL;
 927    int err;
 928
 929    self = PyObject_New(DBObject, &DB_Type);
 930    if (self == NULL)
 931        return NULL;
 932
 933    self->haveStat = 0;
 934    self->flags = 0;
 935    self->setflags = 0;
 936    self->myenvobj = NULL;
 937    self->db = NULL;
 938    self->children_cursors = NULL;
 939#if (DBVER >=43)
 940    self->children_sequences = NULL;
 941#endif
 942    self->associateCallback = NULL;
 943    self->btCompareCallback = NULL;
 944    self->primaryDBType = 0;
 945    Py_INCREF(Py_None);
 946    self->private_obj = Py_None;
 947    self->in_weakreflist = NULL;
 948
 949    /* keep a reference to our python DBEnv object */
 950    if (arg) {
 951        Py_INCREF(arg);
 952        self->myenvobj = arg;
 953        db_env = arg->db_env;
 954        INSERT_IN_DOUBLE_LINKED_LIST(self->myenvobj->children_dbs,self);
 955    } else {
 956      self->sibling_prev_p=NULL;
 957      self->sibling_next=NULL;
 958    }
 959    self->txn=NULL;
 960    self->sibling_prev_p_txn=NULL;
 961    self->sibling_next_txn=NULL;
 962
 963    if (self->myenvobj)
 964        self->moduleFlags = self->myenvobj->moduleFlags;
 965    else
 966        self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
 967        self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
 968
 969    MYDB_BEGIN_ALLOW_THREADS;
 970    err = db_create(&self->db, db_env, flags);
 971    if (self->db != NULL) {
 972        self->db->set_errcall(self->db, _db_errorCallback);
 973        self->db->app_private = (void*)self;
 974    }
 975    MYDB_END_ALLOW_THREADS;
 976    /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs
 977     * list so that a DBEnv can refuse to close without aborting any open
 978     * DBTxns and closing any open DBs first. */
 979    if (makeDBError(err)) {
 980        if (self->myenvobj) {
 981            Py_DECREF(self->myenvobj);
 982            self->myenvobj = NULL;
 983        }
 984        Py_DECREF(self);
 985        self = NULL;
 986    }
 987    return self;
 988}
 989
 990
 991/* Forward declaration */
 992static PyObject *DB_close_internal(DBObject* self, int flags, int do_not_close);
 993
 994static void
 995DB_dealloc(DBObject* self)
 996{
 997  PyObject *dummy;
 998
 999    if (self->db != NULL) {
1000        dummy=DB_close_internal(self, 0, 0);
1001        /*
1002        ** Raising exceptions while doing
1003        ** garbage collection is a fatal error.
1004        */
1005        if (dummy)
1006            Py_DECREF(dummy);
1007        else
1008            PyErr_Clear();
1009    }
1010    if (self->in_weakreflist != NULL) {
1011        PyObject_ClearWeakRefs((PyObject *) self);
1012    }
1013    if (self->myenvobj) {
1014        Py_DECREF(self->myenvobj);
1015        self->myenvobj = NULL;
1016    }
1017    if (self->associateCallback != NULL) {
1018        Py_DECREF(self->associateCallback);
1019        self->associateCallback = NULL;
1020    }
1021    if (self->btCompareCallback != NULL) {
1022        Py_DECREF(self->btCompareCallback);
1023        self->btCompareCallback = NULL;
1024    }
1025    Py_DECREF(self->private_obj);
1026    PyObject_Del(self);
1027}
1028
1029static DBCursorObject*
1030newDBCursorObject(DBC* dbc, DBTxnObject *txn, DBObject* db)
1031{
1032    DBCursorObject* self = PyObject_New(DBCursorObject, &DBCursor_Type);
1033    if (self == NULL)
1034        return NULL;
1035
1036    self->dbc = dbc;
1037    self->mydb = db;
1038
1039    INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_cursors,self);
1040    if (txn && ((PyObject *)txn!=Py_None)) {
1041	    INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->children_cursors,self);
1042	    self->txn=txn;
1043    } else {
1044	    self->txn=NULL;
1045    }
1046
1047    self->in_weakreflist = NULL;
1048    Py_INCREF(self->mydb);
1049    return self;
1050}
1051
1052
1053/* Forward declaration */
1054static PyObject *DBC_close_internal(DBCursorObject* self);
1055
1056static void
1057DBCursor_dealloc(DBCursorObject* self)
1058{
1059    PyObject *dummy;
1060
1061    if (self->dbc != NULL) {
1062        dummy=DBC_close_internal(self);
1063        /*
1064        ** Raising exceptions while doing
1065        ** garbage collection is a fatal error.
1066        */
1067        if (dummy)
1068            Py_DECREF(dummy);
1069        else
1070            PyErr_Clear();
1071    }
1072    if (self->in_weakreflist != NULL) {
1073        PyObject_ClearWeakRefs((PyObject *) self);
1074    }
1075    Py_DECREF(self->mydb);
1076    PyObject_Del(self);
1077}
1078
1079
1080static DBEnvObject*
1081newDBEnvObject(int flags)
1082{
1083    int err;
1084    DBEnvObject* self = PyObject_New(DBEnvObject, &DBEnv_Type);
1085    if (self == NULL)
1086        return NULL;
1087
1088    self->db_env = NULL;
1089    self->closed = 1;
1090    self->flags = flags;
1091    self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
1092    self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
1093    self->children_dbs = NULL;
1094    self->children_txns = NULL;
1095    Py_INCREF(Py_None);
1096    self->private_obj = Py_None;
1097    Py_INCREF(Py_None);
1098    self->rep_transport = Py_None;
1099    self->in_weakreflist = NULL;
1100    self->event_notifyCallback = NULL;
1101
1102    MYDB_BEGIN_ALLOW_THREADS;
1103    err = db_env_create(&self->db_env, flags);
1104    MYDB_END_ALLOW_THREADS;
1105    if (makeDBError(err)) {
1106        Py_DECREF(self);
1107        self = NULL;
1108    }
1109    else {
1110        self->db_env->set_errcall(self->db_env, _db_errorCallback);
1111        self->db_env->app_private = self;
1112    }
1113    return self;
1114}
1115
1116/* Forward declaration */
1117static PyObject *DBEnv_close_internal(DBEnvObject* self, int flags);
1118
1119static void
1120DBEnv_dealloc(DBEnvObject* self)
1121{
1122  PyObject *dummy;
1123
1124    if (self->db_env) {
1125        dummy=DBEnv_close_internal(self, 0);
1126        /*
1127        ** Raising exceptions while doing
1128        ** garbage collection is a fatal error.
1129        */
1130        if (dummy)
1131            Py_DECREF(dummy);
1132        else
1133            PyErr_Clear();
1134    }
1135
1136    Py_XDECREF(self->event_notifyCallback);
1137    self->event_notifyCallback = NULL;
1138
1139    if (self->in_weakreflist != NULL) {
1140        PyObject_ClearWeakRefs((PyObject *) self);
1141    }
1142    Py_DECREF(self->private_obj);
1143    Py_DECREF(self->rep_transport);
1144    PyObject_Del(self);
1145}
1146
1147
1148static DBTxnObject*
1149newDBTxnObject(DBEnvObject* myenv, DBTxnObject *parent, DB_TXN *txn, int flags)
1150{
1151    int err;
1152    DB_TXN *parent_txn = NULL;
1153
1154    DBTxnObject* self = PyObject_New(DBTxnObject, &DBTxn_Type);
1155    if (self == NULL)
1156        return NULL;
1157
1158    self->in_weakreflist = NULL;
1159    self->children_txns = NULL;
1160    self->children_dbs = NULL;
1161    self->children_cursors = NULL;
1162    self->children_sequences = NULL;
1163    self->flag_prepare = 0;
1164    self->parent_txn = NULL;
1165    self->env = NULL;
1166
1167    if (parent && ((PyObject *)parent!=Py_None)) {
1168        parent_txn = parent->txn;
1169    }
1170
1171    if (txn) {
1172        self->txn = txn;
1173    } else {
1174        MYDB_BEGIN_ALLOW_THREADS;
1175        err = myenv->db_env->txn_begin(myenv->db_env, parent_txn, &(self->txn), flags);
1176        MYDB_END_ALLOW_THREADS;
1177
1178        if (makeDBError(err)) {
1179            Py_DECREF(self);
1180            return NULL;
1181        }
1182    }
1183
1184    /* Can't use 'parent' because could be 'parent==Py_None' */
1185    if (parent_txn) {
1186        self->parent_txn = parent;
1187        Py_INCREF(parent);
1188        self->env = NULL;
1189        INSERT_IN_DOUBLE_LINKED_LIST(parent->children_txns, self);
1190    } else {
1191        self->parent_txn = NULL;
1192        Py_INCREF(myenv);
1193        self->env = myenv;
1194        INSERT_IN_DOUBLE_LINKED_LIST(myenv->children_txns, self);
1195    }
1196
1197    return self;
1198}
1199
1200/* Forward declaration */
1201static PyObject *
1202DBTxn_abort_discard_internal(DBTxnObject* self, int discard);
1203
1204static void
1205DBTxn_dealloc(DBTxnObject* self)
1206{
1207  PyObject *dummy;
1208
1209    if (self->txn) {
1210        int flag_prepare = self->flag_prepare;
1211
1212        dummy=DBTxn_abort_discard_internal(self,0);
1213        /*
1214        ** Raising exceptions while doing
1215        ** garbage collection is a fatal error.
1216        */
1217        if (dummy)
1218            Py_DECREF(dummy);
1219        else
1220            PyErr_Clear();
1221
1222        if (!flag_prepare) {
1223            PyErr_Warn(PyExc_RuntimeWarning,
1224              "DBTxn aborted in destructor.  No prior commit() or abort().");
1225        }
1226    }
1227
1228    if (self->in_weakreflist != NULL) {
1229        PyObject_ClearWeakRefs((PyObject *) self);
1230    }
1231
1232    if (self->env) {
1233        Py_DECREF(self->env);
1234    } else {
1235        Py_DECREF(self->parent_txn);
1236    }
1237    PyObject_Del(self);
1238}
1239
1240
1241static DBLockObject*
1242newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj,
1243                db_lockmode_t lock_mode, int flags)
1244{
1245    int err;
1246    DBLockObject* self = PyObject_New(DBLockObject, &DBLock_Type);
1247    if (self == NULL)
1248        return NULL;
1249    self->in_weakreflist = NULL;
1250
1251    MYDB_BEGIN_ALLOW_THREADS;
1252    err = myenv->db_env->lock_get(myenv->db_env, locker, flags, obj, lock_mode,
1253                                  &self->lock);
1254    MYDB_END_ALLOW_THREADS;
1255    if (makeDBError(err)) {
1256        Py_DECREF(self);
1257        self = NULL;
1258    }
1259
1260    return self;
1261}
1262
1263
1264static void
1265DBLock_dealloc(DBLockObject* self)
1266{
1267    if (self->in_weakreflist != NULL) {
1268        PyObject_ClearWeakRefs((PyObject *) self);
1269    }
1270    /* TODO: is this lock held? should we release it? */
1271
1272    PyObject_Del(self);
1273}
1274
1275
1276#if (DBVER >= 43)
1277static DBSequenceObject*
1278newDBSequenceObject(DBObject* mydb,  int flags)
1279{
1280    int err;
1281    DBSequenceObject* self = PyObject_New(DBSequenceObject, &DBSequence_Type);
1282    if (self == NULL)
1283        return NULL;
1284    Py_INCREF(mydb);
1285    self->mydb = mydb;
1286
1287    INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_sequences,self);
1288    self->txn = NULL;
1289
1290    self->in_weakreflist = NULL;
1291
1292    MYDB_BEGIN_ALLOW_THREADS;
1293    err = db_sequence_create(&self->sequence, self->mydb->db, flags);
1294    MYDB_END_ALLOW_THREADS;
1295    if (makeDBError(err)) {
1296        Py_DECREF(self);
1297        self = NULL;
1298    }
1299
1300    return self;
1301}
1302
1303/* Forward declaration */
1304static PyObject
1305*DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close);
1306
1307static void
1308DBSequence_dealloc(DBSequenceObject* self)
1309{
1310    PyObject *dummy;
1311
1312    if (self->sequence != NULL) {
1313        dummy=DBSequence_close_internal(self,0,0);
1314        /*
1315        ** Raising exceptions while doing
1316        ** garbage collection is a fatal error.
1317        */
1318        if (dummy)
1319            Py_DECREF(dummy);
1320        else
1321            PyErr_Clear();
1322    }
1323
1324    if (self->in_weakreflist != NULL) {
1325        PyObject_ClearWeakRefs((PyObject *) self);
1326    }
1327
1328    Py_DECREF(self->mydb);
1329    PyObject_Del(self);
1330}
1331#endif
1332
1333/* --------------------------------------------------------------------- */
1334/* DB methods */
1335
1336static PyObject*
1337DB_append(DBObject* self, PyObject* args, PyObject* kwargs)
1338{
1339    PyObject* txnobj = NULL;
1340    PyObject* dataobj;
1341    db_recno_t recno;
1342    DBT key, data;
1343    DB_TXN *txn = NULL;
1344    static char* kwnames[] = { "data", "txn", NULL };
1345
1346    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:append", kwnames,
1347                                     &dataobj, &txnobj))
1348        return NULL;
1349
1350    CHECK_DB_NOT_CLOSED(self);
1351
1352    /* make a dummy key out of a recno */
1353    recno = 0;
1354    CLEAR_DBT(key);
1355    key.data = &recno;
1356    key.size = sizeof(recno);
1357    key.ulen = key.size;
1358    key.flags = DB_DBT_USERMEM;
1359
1360    if (!make_dbt(dataobj, &data)) return NULL;
1361    if (!checkTxnObj(txnobj, &txn)) return NULL;
1362
1363    if (-1 == _DB_put(self, txn, &key, &data, DB_APPEND))
1364        return NULL;
1365
1366    return NUMBER_FromLong(recno);
1367}
1368
1369
1370static int
1371_db_associateCallback(DB* db, const DBT* priKey, const DBT* priData,
1372                      DBT* secKey)
1373{
1374    int       retval = DB_DONOTINDEX;
1375    DBObject* secondaryDB = (DBObject*)db->app_private;
1376    PyObject* callback = secondaryDB->associateCallback;
1377    int       type = secondaryDB->primaryDBType;
1378    PyObject* args;
1379    PyObject* result = NULL;
1380
1381
1382    if (callback != NULL) {
1383        MYDB_BEGIN_BLOCK_THREADS;
1384
1385        if (type == DB_RECNO || type == DB_QUEUE)
1386            args = BuildValue_LS(*((db_recno_t*)priKey->data), priData->data, priData->size);
1387        else
1388            args = BuildValue_SS(priKey->data, priKey->size, priData->data, priData->size);
1389        if (args != NULL) {
1390                result = PyEval_CallObject(callback, args);
1391        }
1392        if (args == NULL || result == NULL) {
1393            PyErr_Print();
1394        }
1395        else if (result == Py_None) {
1396            retval = DB_DONOTINDEX;
1397        }
1398        else if (NUMBER_Check(result)) {
1399            retval = NUMBER_AsLong(result);
1400        }
1401        else if (PyBytes_Check(result)) {
1402            char* data;
1403            Py_ssize_t size;
1404
1405            CLEAR_DBT(*secKey);
1406            PyBytes_AsStringAndSize(result, &data, &size);
1407            secKey->flags = DB_DBT_APPMALLOC;   /* DB will free */
1408            secKey->data = malloc(size);        /* TODO, check this */
1409	    if (secKey->data) {
1410		memcpy(secKey->data, data, size);
1411		secKey->size = size;
1412		retval = 0;
1413	    }
1414	    else {
1415		PyErr_SetString(PyExc_MemoryError,
1416                                "malloc failed in _db_associateCallback");
1417		PyErr_Print();
1418	    }
1419        }
1420        else {
1421            PyErr_SetString(
1422               PyExc_TypeError,
1423               "DB associate callback should return DB_DONOTINDEX or string.");
1424            PyErr_Print();
1425        }
1426
1427        Py_XDECREF(args);
1428        Py_XDECREF(result);
1429
1430        MYDB_END_BLOCK_THREADS;
1431    }
1432    return retval;
1433}
1434
1435
1436static PyObject*
1437DB_associate(DBObject* self, PyObject* args, PyObject* kwargs)
1438{
1439    int err, flags=0;
1440    DBObject* secondaryDB;
1441    PyObject* callback;
1442#if (DBVER >= 41)
1443    PyObject *txnobj = NULL;
1444    DB_TXN *txn = NULL;
1445    static char* kwnames[] = {"secondaryDB", "callback", "flags", "txn",
1446                                    NULL};
1447#else
1448    static char* kwnames[] = {"secondaryDB", "callback", "flags", NULL};
1449#endif
1450
1451#if (DBVER >= 41)
1452    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iO:associate", kwnames,
1453                                     &secondaryDB, &callback, &flags,
1454                                     &txnobj)) {
1455#else
1456    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:associate", kwnames,
1457                                     &secondaryDB, &callback, &flags)) {
1458#endif
1459        return NULL;
1460    }
1461
1462#if (DBVER >= 41)
1463    if (!checkTxnObj(txnobj, &txn)) return NULL;
1464#endif
1465
1466    CHECK_DB_NOT_CLOSED(self);
1467    if (!DBObject_Check(secondaryDB)) {
1468        makeTypeError("DB", (PyObject*)secondaryDB);
1469        return NULL;
1470    }
1471    CHECK_DB_NOT_CLOSED(secondaryDB);
1472    if (callback == Py_None) {
1473        callback = NULL;
1474    }
1475    else if (!PyCallable_Check(callback)) {
1476        makeTypeError("Callable", callback);
1477        return NULL;
1478    }
1479
1480    /* Save a reference to the callback in the secondary DB. */
1481    Py_XDECREF(secondaryDB->associateCallback);
1482    Py_XINCREF(callback);
1483    secondaryDB->associateCallback = callback;
1484    secondaryDB->primaryDBType = _DB_get_type(self);
1485
1486    /* PyEval_InitThreads is called here due to a quirk in python 1.5
1487     * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>:
1488     * The global interepreter lock is not initialized until the first
1489     * thread is created using thread.start_new_thread() or fork() is
1490     * called.  that would cause the ALLOW_THREADS here to segfault due
1491     * to a null pointer reference if no threads or child processes
1492     * have been created.  This works around that and is a no-op if
1493     * threads have already been initialized.
1494     *  (see pybsddb-users mailing list post on 2002-08-07)
1495     */
1496#ifdef WITH_THREAD
1497    PyEval_InitThreads();
1498#endif
1499    MYDB_BEGIN_ALLOW_THREADS;
1500#if (DBVER >= 41)
1501    err = self->db->associate(self->db,
1502	                      txn,
1503                              secondaryDB->db,
1504                              _db_associateCallback,
1505                              flags);
1506#else
1507    err = self->db->associate(self->db,
1508                              secondaryDB->db,
1509                              _db_associateCallback,
1510                              flags);
1511#endif
1512    MYDB_END_ALLOW_THREADS;
1513
1514    if (err) {
1515        Py_XDECREF(secondaryDB->associateCallback);
1516        secondaryDB->associateCallback = NULL;
1517        secondaryDB->primaryDBType = 0;
1518    }
1519
1520    RETURN_IF_ERR();
1521    RETURN_NONE();
1522}
1523
1524
1525static PyObject*
1526DB_close_internal(DBObject* self, int flags, int do_not_close)
1527{
1528    PyObject *dummy;
1529    int err = 0;
1530
1531    if (self->db != NULL) {
1532        /* Can be NULL if db is not in an environment */
1533        EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(self);
1534
1535        if (self->txn) {
1536            EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
1537            self->txn=NULL;
1538        }
1539
1540        while(self->children_cursors) {
1541          dummy=DBC_close_internal(self->children_cursors);
1542          Py_XDECREF(dummy);
1543        }
1544
1545#if (DBVER >= 43)
1546        while(self->children_sequences) {
1547            dummy=DBSequence_close_internal(self->children_sequences,0,0);
1548            Py_XDECREF(dummy);
1549        }
1550#endif
1551
1552        /*
1553        ** "do_not_close" is used to dispose all related objects in the
1554        ** tree, without actually releasing the "root" object.
1555        ** This is done, for example, because function calls like
1556        ** "DB.verify()" implicitly close the underlying handle. So
1557        ** the handle doesn't need to be closed, but related objects
1558        ** must be cleaned up.
1559        */
1560        if (!do_not_close) {
1561            MYDB_BEGIN_ALLOW_THREADS;
1562            err = self->db->close(self->db, flags);
1563            MYDB_END_ALLOW_THREADS;
1564            self->db = NULL;
1565        }
1566        RETURN_IF_ERR();
1567    }
1568    RETURN_NONE();
1569}
1570
1571static PyObject*
1572DB_close(DBObject* self, PyObject* args)
1573{
1574    int flags=0;
1575    if (!PyArg_ParseTuple(args,"|i:close", &flags))
1576        return NULL;
1577    return DB_close_internal(self, flags, 0);
1578}
1579
1580
1581static PyObject*
1582_DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
1583{
1584    int err, flags=0, type;
1585    PyObject* txnobj = NULL;
1586    PyObject* retval = NULL;
1587    DBT key, data;
1588    DB_TXN *txn = NULL;
1589    static char* kwnames[] = { "txn", "flags", NULL };
1590
1591    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:consume", kwnames,
1592                                     &txnobj, &flags))
1593        return NULL;
1594
1595    CHECK_DB_NOT_CLOSED(self);
1596    type = _DB_get_type(self);
1597    if (type == -1)
1598        return NULL;
1599    if (type != DB_QUEUE) {
1600        PyErr_SetString(PyExc_TypeError,
1601                        "Consume methods only allowed for Queue DB's");
1602        return NULL;
1603    }
1604    if (!checkTxnObj(txnobj, &txn))
1605        return NULL;
1606
1607    CLEAR_DBT(key);
1608    CLEAR_DBT(data);
1609    if (CHECK_DBFLAG(self, DB_THREAD)) {
1610        /* Tell Berkeley DB to malloc the return value (thread safe) */
1611        data.flags = DB_DBT_MALLOC;
1612        key.flags = DB_DBT_MALLOC;
1613    }
1614
1615    MYDB_BEGIN_ALLOW_THREADS;
1616    err = self->db->get(self->db, txn, &key, &data, flags|consume_flag);
1617    MYDB_END_ALLOW_THREADS;
1618
1619    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1620	    && self->moduleFlags.getReturnsNone) {
1621        err = 0;
1622        Py_INCREF(Py_None);
1623        retval = Py_None;
1624    }
1625    else if (!err) {
1626        retval = BuildValue_SS(key.data, key.size, data.data, data.size);
1627        FREE_DBT(key);
1628        FREE_DBT(data);
1629    }
1630
1631    RETURN_IF_ERR();
1632    return retval;
1633}
1634
1635static PyObject*
1636DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
1637{
1638    return _DB_consume(self, args, kwargs, DB_CONSUME);
1639}
1640
1641static PyObject*
1642DB_consume_wait(DBObject* self, PyObject* args, PyObject* kwargs,
1643                int consume_flag)
1644{
1645    return _DB_consume(self, args, kwargs, DB_CONSUME_WAIT);
1646}
1647
1648
1649static PyObject*
1650DB_cursor(DBObject* self, PyObject* args, PyObject* kwargs)
1651{
1652    int err, flags=0;
1653    DBC* dbc;
1654    PyObject* txnobj = NULL;
1655    DB_TXN *txn = NULL;
1656    static char* kwnames[] = { "txn", "flags", NULL };
1657
1658    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames,
1659                                     &txnobj, &flags))
1660        return NULL;
1661    CHECK_DB_NOT_CLOSED(self);
1662    if (!checkTxnObj(txnobj, &txn))
1663        return NULL;
1664
1665    MYDB_BEGIN_ALLOW_THREADS;
1666    err = self->db->cursor(self->db, txn, &dbc, flags);
1667    MYDB_END_ALLOW_THREADS;
1668    RETURN_IF_ERR();
1669    return (PyObject*) newDBCursorObject(dbc, (DBTxnObject *)txnobj, self);
1670}
1671
1672
1673static PyObject*
1674DB_delete(DBObject* self, PyObject* args, PyObject* kwargs)
1675{
1676    PyObject* txnobj = NULL;
1677    int flags = 0;
1678    PyObject* keyobj;
1679    DBT key;
1680    DB_TXN *txn = NULL;
1681    static char* kwnames[] = { "key", "txn", "flags", NULL };
1682
1683    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:delete", kwnames,
1684                                     &keyobj, &txnobj, &flags))
1685        return NULL;
1686    CHECK_DB_NOT_CLOSED(self);
1687    if (!make_key_dbt(self, keyobj, &key, NULL))
1688        return NULL;
1689    if (!checkTxnObj(txnobj, &txn)) {
1690        FREE_DBT(key);
1691        return NULL;
1692    }
1693
1694    if (-1 == _DB_delete(self, txn, &key, 0)) {
1695        FREE_DBT(key);
1696        return NULL;
1697    }
1698
1699    FREE_DBT(key);
1700    RETURN_NONE();
1701}
1702
1703
1704static PyObject*
1705DB_fd(DBObject* self)
1706{
1707    int err, the_fd;
1708
1709    CHECK_DB_NOT_CLOSED(self);
1710
1711    MYDB_BEGIN_ALLOW_THREADS;
1712    err = self->db->fd(self->db, &the_fd);
1713    MYDB_END_ALLOW_THREADS;
1714    RETURN_IF_ERR();
1715    return NUMBER_FromLong(the_fd);
1716}
1717
1718
1719static PyObject*
1720DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
1721{
1722    int err, flags=0;
1723    PyObject* txnobj = NULL;
1724    PyObject* keyobj;
1725    PyObject* dfltobj = NULL;
1726    PyObject* retval = NULL;
1727    int dlen = -1;
1728    int doff = -1;
1729    DBT key, data;
1730    DB_TXN *txn = NULL;
1731    static char* kwnames[] = {"key", "default", "txn", "flags", "dlen",
1732                                    "doff", NULL};
1733
1734    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:get", kwnames,
1735                                     &keyobj, &dfltobj, &txnobj, &flags, &dlen,
1736                                     &doff))
1737        return NULL;
1738
1739    CHECK_DB_NOT_CLOSED(self);
1740    if (!make_key_dbt(self, keyobj, &key, &flags))
1741        return NULL;
1742    if (!checkTxnObj(txnobj, &txn)) {
1743        FREE_DBT(key);
1744        return NULL;
1745    }
1746
1747    CLEAR_DBT(data);
1748    if (CHECK_DBFLAG(self, DB_THREAD)) {
1749        /* Tell Berkeley DB to malloc the return value (thread safe) */
1750        data.flags = DB_DBT_MALLOC;
1751    }
1752    if (!add_partial_dbt(&data, dlen, doff)) {
1753        FREE_DBT(key);
1754        return NULL;
1755    }
1756
1757    MYDB_BEGIN_ALLOW_THREADS;
1758    err = self->db->get(self->db, txn, &key, &data, flags);
1759    MYDB_END_ALLOW_THREADS;
1760
1761    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) {
1762        err = 0;
1763        Py_INCREF(dfltobj);
1764        retval = dfltobj;
1765    }
1766    else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1767	     && self->moduleFlags.getReturnsNone) {
1768        err = 0;
1769        Py_INCREF(Py_None);
1770        retval = Py_None;
1771    }
1772    else if (!err) {
1773        if (flags & DB_SET_RECNO) /* return both key and data */
1774            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
1775        else /* return just the data */
1776            retval = Build_PyString(data.data, data.size);
1777        FREE_DBT(data);
1778    }
1779    FREE_DBT(key);
1780
1781    RETURN_IF_ERR();
1782    return retval;
1783}
1784
1785static PyObject*
1786DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
1787{
1788    int err, flags=0;
1789    PyObject* txnobj = NULL;
1790    PyObject* keyobj;
1791    PyObject* dfltobj = NULL;
1792    PyObject* retval = NULL;
1793    int dlen = -1;
1794    int doff = -1;
1795    DBT key, pkey, data;
1796    DB_TXN *txn = NULL;
1797    static char* kwnames[] = {"key", "default", "txn", "flags", "dlen",
1798                                    "doff", NULL};
1799
1800    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:pget", kwnames,
1801                                     &keyobj, &dfltobj, &txnobj, &flags, &dlen,
1802                                     &doff))
1803        return NULL;
1804
1805    CHECK_DB_NOT_CLOSED(self);
1806    if (!make_key_dbt(self, keyobj, &key, &flags))
1807        return NULL;
1808    if (!checkTxnObj(txnobj, &txn)) {
1809        FREE_DBT(key);
1810        return NULL;
1811    }
1812
1813    CLEAR_DBT(data);
1814    if (CHECK_DBFLAG(self, DB_THREAD)) {
1815        /* Tell Berkeley DB to malloc the return value (thread safe) */
1816        data.flags = DB_DBT_MALLOC;
1817    }
1818    if (!add_partial_dbt(&data, dlen, doff)) {
1819        FREE_DBT(key);
1820        return NULL;
1821    }
1822
1823    CLEAR_DBT(pkey);
1824    pkey.flags = DB_DBT_MALLOC;
1825
1826    MYDB_BEGIN_ALLOW_THREADS;
1827    err = self->db->pget(self->db, txn, &key, &pkey, &data, flags);
1828    MYDB_END_ALLOW_THREADS;
1829
1830    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) {
1831        err = 0;
1832        Py_INCREF(dfltobj);
1833        retval = dfltobj;
1834    }
1835    else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1836	     && self->moduleFlags.getReturnsNone) {
1837        err = 0;
1838        Py_INCREF(Py_None);
1839        retval = Py_None;
1840    }
1841    else if (!err) {
1842        PyObject *pkeyObj;
1843        PyObject *dataObj;
1844        dataObj = Build_PyString(data.data, data.size);
1845
1846        if (self->primaryDBType == DB_RECNO ||
1847            self->primaryDBType == DB_QUEUE)
1848            pkeyObj = NUMBER_FromLong(*(int *)pkey.data);
1849        else
1850            pkeyObj = Build_PyString(pkey.data, pkey.size);
1851
1852        if (flags & DB_SET_RECNO) /* return key , pkey and data */
1853        {
1854            PyObject *keyObj;
1855            int type = _DB_get_type(self);
1856            if (type == DB_RECNO || type == DB_QUEUE)
1857                keyObj = NUMBER_FromLong(*(int *)key.data);
1858            else
1859                keyObj = Build_PyString(key.data, key.size);
1860#if (PY_VERSION_HEX >= 0x02040000)
1861            retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
1862#else
1863            retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj);
1864#endif
1865            Py_DECREF(keyObj);
1866        }
1867        else /* return just the pkey and data */
1868        {
1869#if (PY_VERSION_HEX >= 0x02040000)
1870            retval = PyTuple_Pack(2, pkeyObj, dataObj);
1871#else
1872            retval = Py_BuildValue("OO", pkeyObj, dataObj);
1873#endif
1874        }
1875        Py_DECREF(dataObj);
1876        Py_DECREF(pkeyObj);
1877        FREE_DBT(pkey);
1878        FREE_DBT(data);
1879    }
1880    FREE_DBT(key);
1881
1882    RETURN_IF_ERR();
1883    return retval;
1884}
1885
1886
1887/* Return size of entry */
1888static PyObject*
1889DB_get_size(DBObject* self, PyObject* args, PyObject* kwargs)
1890{
1891    int err, flags=0;
1892    PyObject* txnobj = NULL;
1893    PyObject* keyobj;
1894    PyObject* retval = NULL;
1895    DBT key, data;
1896    DB_TXN *txn = NULL;
1897    static char* kwnames[] = { "key", "txn", NULL };
1898
1899    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:get_size", kwnames,
1900                                     &keyobj, &txnobj))
1901        return NULL;
1902    CHECK_DB_NOT_CLOSED(self);
1903    if (!make_key_dbt(self, keyobj, &key, &flags))
1904        return NULL;
1905    if (!checkTxnObj(txnobj, &txn)) {
1906        FREE_DBT(key);
1907        return NULL;
1908    }
1909    CLEAR_DBT(data);
1910
1911    /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and
1912       thus getting the record size. */
1913    data.flags = DB_DBT_USERMEM;
1914    data.ulen = 0;
1915    MYDB_BEGIN_ALLOW_THREADS;
1916    err = self->db->get(self->db, txn, &key, &data, flags);
1917    MYDB_END_ALLOW_THREADS;
1918    if (err == DB_BUFFER_SMALL) {
1919        retval = NUMBER_FromLong((long)data.size);
1920        err = 0;
1921    }
1922
1923    FREE_DBT(key);
1924    FREE_DBT(data);
1925    RETURN_IF_ERR();
1926    return retval;
1927}
1928
1929
1930static PyObject*
1931DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
1932{
1933    int err, flags=0;
1934    PyObject* txnobj = NULL;
1935    PyObject* keyobj;
1936    PyObject* dataobj;
1937    PyObject* retval = NULL;
1938    DBT key, data;
1939    void *orig_data;
1940    DB_TXN *txn = NULL;
1941    static char* kwnames[] = { "key", "data", "txn", "flags", NULL };
1942
1943    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oi:get_both", kwnames,
1944                                     &keyobj, &dataobj, &txnobj, &flags))
1945        return NULL;
1946
1947    CHECK_DB_NOT_CLOSED(self);
1948    if (!make_key_dbt(self, keyobj, &key, NULL))
1949        return NULL;
1950    if ( !make_dbt(dataobj, &data) ||
1951         !checkTxnObj(txnobj, &txn) )
1952    {
1953        FREE_DBT(key);
1954        return NULL;
1955    }
1956
1957    flags |= DB_GET_BOTH;
1958    orig_data = data.data;
1959
1960    if (CHECK_DBFLAG(self, DB_THREAD)) {
1961        /* Tell Berkeley DB to malloc the return value (thread safe) */
1962        /* XXX(nnorwitz): At least 4.4.20 and 4.5.20 require this flag. */
1963        data.flags = DB_DBT_MALLOC;
1964    }
1965
1966    MYDB_BEGIN_ALLOW_THREADS;
1967    err = self->db->get(self->db, txn, &key, &data, flags);
1968    MYDB_END_ALLOW_THREADS;
1969
1970    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1971	    && self->moduleFlags.getReturnsNone) {
1972        err = 0;
1973        Py_INCREF(Py_None);
1974        retval = Py_None;
1975    }
1976    else if (!err) {
1977        /* XXX(nnorwitz): can we do: retval = dataobj; Py_INCREF(retval); */
1978        retval = Build_PyString(data.data, data.size);
1979
1980        /* Even though the flags require DB_DBT_MALLOC, data is not always
1981           allocated.  4.4: allocated, 4.5: *not* allocated. :-( */
1982        if (data.data != orig_data)
1983            FREE_DBT(data);
1984    }
1985
1986    FREE_DBT(key);
1987    RETURN_IF_ERR();
1988    return retval;
1989}
1990
1991
1992static PyObject*
1993DB_get_byteswapped(DBObject* self)
1994{
1995    int err = 0;
1996    int retval = -1;
1997
1998    CHECK_DB_NOT_CLOSED(self);
1999
2000    MYDB_BEGIN_ALLOW_THREADS;
2001    err = self->db->get_byteswapped(self->db, &retval);
2002    MYDB_END_ALLOW_THREADS;
2003    RETURN_IF_ERR();
2004    return NUMBER_FromLong(retval);
2005}
2006
2007
2008static PyObject*
2009DB_get_type(DBObject* self)
2010{
2011    int type;
2012
2013    CHECK_DB_NOT_CLOSED(self);
2014
2015    type = _DB_get_type(self);
2016    if (type == -1)
2017        return NULL;
2018    return NUMBER_FromLong(type);
2019}
2020
2021
2022static PyObject*
2023DB_join(DBObject* self, PyObject* args)
2024{
2025    int err, flags=0;
2026    int length, x;
2027    PyObject* cursorsObj;
2028    DBC** cursors;
2029    DBC*  dbc;
2030
2031    if (!PyArg_ParseTuple(args,"O|i:join", &cursorsObj, &flags))
2032        return NULL;
2033
2034    CHECK_DB_NOT_CLOSED(self);
2035
2036    if (!PySequence_Check(cursorsObj)) {
2037        PyErr_SetString(PyExc_TypeError,
2038                        "Sequence of DBCursor objects expected");
2039        return NULL;
2040    }
2041
2042    length = PyObject_Length(cursorsObj);
2043    cursors = malloc((length+1) * sizeof(DBC*));
2044    if (!cursors) {
2045	PyErr_NoMemory();
2046	return NULL;
2047    }
2048
2049    cursors[length] = NULL;
2050    for (x=0; x<length; x++) {
2051        PyObject* item = PySequence_GetItem(cursorsObj, x);
2052        if (item == NULL) {
2053            free(cursors);
2054            return NULL;
2055        }
2056        if (!DBCursorObject_Check(item)) {
2057            PyErr_SetString(PyExc_TypeError,
2058                            "Sequence of DBCursor objects expected");
2059            free(cursors);
2060            return NULL;
2061        }
2062        cursors[x] = ((DBCursorObject*)item)->dbc;
2063        Py_DECREF(item);
2064    }
2065
2066    MYDB_BEGIN_ALLOW_THREADS;
2067    err = self->db->join(self->db, cursors, &dbc, flags);
2068    MYDB_END_ALLOW_THREADS;
2069    free(cursors);
2070    RETURN_IF_ERR();
2071
2072    /* FIXME: this is a buggy interface.  The returned cursor
2073       contains internal references to the passed in cursors
2074       but does not hold python references to them or prevent
2075       them from being closed prematurely.  This can cause
2076       python to crash when things are done in the wrong order. */
2077    return (PyObject*) newDBCursorObject(dbc, NULL, self);
2078}
2079
2080
2081static PyObject*
2082DB_key_range(DBObject* self, PyObject* args, PyObject* kwargs)
2083{
2084    int err, flags=0;
2085    PyObject* txnobj = NULL;
2086    PyObject* keyobj;
2087    DBT key;
2088    DB_TXN *txn = NULL;
2089    DB_KEY_RANGE range;
2090    static char* kwnames[] = { "key", "txn", "flags", NULL };
2091
2092    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:key_range", kwnames,
2093                                     &keyobj, &txnobj, &flags))
2094        return NULL;
2095    CHECK_DB_NOT_CLOSED(self);
2096    if (!make_dbt(keyobj, &key))
2097        /* BTree only, don't need to allow for an int key */
2098        return NULL;
2099    if (!checkTxnObj(txnobj, &txn))
2100        return NULL;
2101
2102    MYDB_BEGIN_ALLOW_THREADS;
2103    err = self->db->key_range(self->db, txn, &key, &range, flags);
2104    MYDB_END_ALLOW_THREADS;
2105
2106    RETURN_IF_ERR();
2107    return Py_BuildValue("ddd", range.less, range.equal, range.greater);
2108}
2109
2110
2111static PyObject*
2112DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
2113{
2114    int err, type = DB_UNKNOWN, flags=0, mode=0660;
2115    char* filename = NULL;
2116    char* dbname = NULL;
2117#if (DBVER >= 41)
2118    PyObject *txnobj = NULL;
2119    DB_TXN *txn = NULL;
2120    /* with dbname */
2121    static char* kwnames[] = {
2122        "filename", "dbname", "dbtype", "flags", "mode", "txn", NULL};
2123    /* without dbname */
2124    static char* kwnames_basic[] = {
2125        "filename", "dbtype", "flags", "mode", "txn", NULL};
2126#else
2127    /* with dbname */
2128    static char* kwnames[] = {
2129        "filename", "dbname", "dbtype", "flags", "mode", NULL};
2130    /* without dbname */
2131    static char* kwnames_basic[] = {
2132        "filename", "dbtype", "flags", "mode", NULL};
2133#endif
2134
2135#if (DBVER >= 41)
2136    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziiiO:open", kwnames,
2137				     &filename, &dbname, &type, &flags, &mode,
2138                                     &txnobj))
2139#else
2140    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziii:open", kwnames,
2141				     &filename, &dbname, &type, &flags,
2142                                     &mode))
2143#endif
2144    {
2145	PyErr_Clear();
2146	type = DB_UNKNOWN; flags = 0; mode = 0660;
2147	filename = NULL; dbname = NULL;
2148#if (DBVER >= 41)
2149	if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iiiO:open",
2150                                         kwnames_basic,
2151					 &filename, &type, &flags, &mode,
2152                                         &txnobj))
2153	    return NULL;
2154#else
2155	if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iii:open",
2156                                         kwnames_basic,
2157					 &filename, &type, &flags, &mode))
2158	    return NULL;
2159#endif
2160    }
2161
2162#if (DBVER >= 41)
2163    if (!checkTxnObj(txnobj, &txn)) return NULL;
2164#endif
2165
2166    if (NULL == self->db) {
2167        PyObject *t = Py_BuildValue("(is)", 0,
2168                                "Cannot call open() twice for DB object");
2169        if (t) {
2170            PyErr_SetObject(DBError, t);
2171            Py_DECREF(t);
2172        }
2173        return NULL;
2174    }
2175
2176#if (DBVER >= 41)
2177    if (txn) {  /* Can't use 'txnobj' because could be 'txnobj==Py_None' */
2178        INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_dbs,self);
2179        self->txn=(DBTxnObject *)txnobj;
2180    } else {
2181        self->txn=NULL;
2182    }
2183#else
2184    self->txn=NULL;
2185#endif
2186
2187    MYDB_BEGIN_ALLOW_THREADS;
2188#if (DBVER >= 41)
2189    err = self->db->open(self->db, txn, filename, dbname, type, flags, mode);
2190#else
2191    err = self->db->open(self->db, filename, dbname, type, flags, mode);
2192#endif
2193    MYDB_END_ALLOW_THREADS;
2194    if (makeDBError(err)) {
2195        PyObject *dummy;
2196
2197        dummy=DB_close_internal(self, 0, 0);
2198        Py_XDECREF(dummy);
2199        return NULL;
2200    }
2201
2202#if (DBVER >= 42)
2203    self->db->get_flags(self->db, &self->setflags);
2204#endif
2205
2206    self->flags = flags;
2207
2208    RETURN_NONE();
2209}
2210
2211
2212static PyObject*
2213DB_put(DBObject* self, PyObject* args, PyObject* kwargs)
2214{
2215    int flags=0;
2216    PyObject* txnobj = NULL;
2217    int dlen = -1;
2218    int doff = -1;
2219    PyObject* keyobj, *dataobj, *retval;
2220    DBT key, data;
2221    DB_TXN *txn = NULL;
2222    static char* kwnames[] = { "key", "data", "txn", "flags", "dlen",
2223                                     "doff", NULL };
2224
2225    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oiii:put", kwnames,
2226                         &keyobj, &dataobj, &txnobj, &flags, &dlen, &doff))
2227        return NULL;
2228
2229    CHECK_DB_NOT_CLOSED(self);
2230    if (!make_key_dbt(self, keyobj, &key, NULL))
2231        return NULL;
2232    if ( !make_dbt(dataobj, &data) ||
2233         !add_partial_dbt(&data, dlen, doff) ||
2234         !checkTxnObj(txnobj, &txn) )
2235    {
2236        FREE_DBT(key);
2237        return NULL;
2238    }
2239
2240    if (-1 == _DB_put(self, txn, &key, &data, flags)) {
2241        FREE_DBT(key);
2242        return NULL;
2243    }
2244
2245    if (flags & DB_APPEND)
2246        retval = NUMBER_FromLong(*((db_recno_t*)key.data));
2247    else {
2248        retval = Py_None;
2249        Py_INCREF(retval);
2250    }
2251    FREE_DBT(key);
2252    return retval;
2253}
2254
2255
2256
2257static PyObject*
2258DB_remove(DBObject* self, PyObject* args, PyObject* kwargs)
2259{
2260    char* filename;
2261    char* database = NULL;
2262    int err, flags=0;
2263    static char* kwnames[] = { "filename", "dbname", "flags", NULL};
2264
2265    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zi:remove", kwnames,
2266                                     &filename, &database, &flags))
2267        return NULL;
2268    CHECK_DB_NOT_CLOSED(self);
2269
2270    EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(self);
2271
2272    MYDB_BEGIN_ALLOW_THREADS;
2273    err = self->db->remove(self->db, filename, database, flags);
2274    MYDB_END_ALLOW_THREADS;
2275
2276    self->db = NULL;
2277    RETURN_IF_ERR();
2278    RETURN_NONE();
2279}
2280
2281
2282
2283static PyObject*
2284DB_rename(DBObject* self, PyObject* args)
2285{
2286    char* filename;
2287    char* database;
2288    char* newname;
2289    int err, flags=0;
2290
2291    if (!PyArg_ParseTuple(args, "sss|i:rename", &filename, &database, &newname,
2292                          &flags))
2293        return NULL;
2294    CHECK_DB_NOT_CLOSED(self);
2295
2296    MYDB_BEGIN_ALLOW_THREADS;
2297    err = self->db->rename(self->db, filename, database, newname, flags);
2298    MYDB_END_ALLOW_THREADS;
2299    RETURN_IF_ERR();
2300    RETURN_NONE();
2301}
2302
2303
2304static PyObject*
2305DB_get_private(DBObject* self)
2306{
2307    /* We can give out the private field even if db is closed */
2308    Py_INCREF(self->private_obj);
2309    return self->private_obj;
2310}
2311
2312static PyObject*
2313DB_set_private(DBObject* self, PyObject* private_obj)
2314{
2315    /* We can set the private field even if db is closed */
2316    Py_DECREF(self->private_obj);
2317    Py_INCREF(private_obj);
2318    self->private_obj = private_obj;
2319    RETURN_NONE();
2320}
2321
2322
2323static PyObject*
2324DB_set_bt_minkey(DBObject* self, PyObject* args)
2325{
2326    int err, minkey;
2327
2328    if (!PyArg_ParseTuple(args,"i:set_bt_minkey", &minkey ))
2329        return NULL;
2330    CHECK_DB_NOT_CLOSED(self);
2331
2332    MYDB_BEGIN_ALLOW_THREADS;
2333    err = self->db->set_bt_minkey(self->db, minkey);
2334    MYDB_END_ALLOW_THREADS;
2335    RETURN_IF_ERR();
2336    RETURN_NONE();
2337}
2338
2339static int
2340_default_cmp(const DBT *leftKey,
2341	     const DBT *rightKey)
2342{
2343  int res;
2344  int lsize = leftKey->size, rsize = rightKey->size;
2345
2346  res = memcmp(leftKey->data, rightKey->data,
2347	       lsize < rsize ? lsize : rsize);
2348
2349  if (res == 0) {
2350      if (lsize < rsize) {
2351	  res = -1;
2352      }
2353      else if (lsize > rsize) {
2354	  res = 1;
2355      }
2356  }
2357  return res;
2358}
2359
2360static int
2361_db_compareCallback(DB* db,
2362		    const DBT *leftKey,
2363		    const DBT *rightKey)
2364{
2365    int res = 0;
2366    PyObject *args;
2367    PyObject *result = NULL;
2368    DBObject *self = (DBObject *)db->app_private;
2369
2370    if (self == NULL || self->btCompareCallback == NULL) {
2371	MYDB_BEGIN_BLOCK_THREADS;
2372	PyErr_SetString(PyExc_TypeError,
2373			(self == 0
2374			 ? "DB_bt_compare db is NULL."
2375			 : "DB_bt_compare callback is NULL."));
2376	/* we're in a callback within the DB code, we can't raise */
2377	PyErr_Print();
2378	res = _default_cmp(leftKey, rightKey);
2379	MYDB_END_BLOCK_THREADS;
2380    } else {
2381	MYDB_BEGIN_BLOCK_THREADS;
2382
2383	args = BuildValue_SS(leftKey->data, leftKey->size, rightKey->data, rightKey->size);
2384	if (args != NULL) {
2385		/* XXX(twouters) I highly doubt this INCREF is correct */
2386		Py_INCREF(self);
2387		result = PyEval_CallObject(self->btCompareCallback, args);
2388	}
2389	if (args == NULL || result == NULL) {
2390	    /* we're in a callback within the DB code, we can't raise */
2391	    PyErr_Print();
2392	    res = _default_cmp(leftKey, rightKey);
2393	} else if (NUMBER_Check(result)) {
2394	    res = NUMBER_AsLong(result);
2395	} else {
2396	    PyErr_SetString(PyExc_TypeError,
2397			    "DB_bt_compare callback MUST return an int.");
2398	    /* we're in a callback within the DB code, we can't raise */
2399	    PyErr_Print();
2400	    res = _default_cmp(leftKey, rightKey);
2401	}
2402
2403	Py_XDECREF(args);
2404	Py_XDECREF(result);
2405
2406	MYDB_END_BLOCK_THREADS;
2407    }
2408    return res;
2409}
2410
2411static PyObject*
2412DB_set_bt_compare(DBObject* self, PyObject* comparator)
2413{
2414    int err;
2415    PyObject *tuple, *result;
2416
2417    CHECK_DB_NOT_CLOSED(self);
2418
2419    if (!PyCallable_Check(comparator)) {
2420	makeTypeError("Callable", comparator);
2421	return NULL;
2422    }
2423
2424    /*
2425     * Perform a test call of the comparator function with two empty
2426     * string objects here.  verify that it returns an int (0).
2427     * err if not.
2428     */
2429    tuple = Py_BuildValue("(ss)", "", "");
2430    result = PyEval_CallObject(comparator, tuple);
2431    Py_DECREF(tuple);
2432    if (result == NULL)
2433        return NULL;
2434    if (!NUMBER_Check(result)) {
2435	PyErr_SetString(PyExc_TypeError,
2436		        "callback MUST return an int");
2437	return NULL;
2438    } else if (NUMBER_AsLong(result) != 0) {
2439	PyErr_SetString(PyExc_TypeError,
2440		        "callback failed to return 0 on two empty strings");
2441	return NULL;
2442    }
2443    Py_DECREF(result);
2444
2445    /* We don't accept multiple set_bt_compare operations, in order to
2446     * simplify the code. This would have no real use, as one cannot
2447     * change the function once the db is opened anyway */
2448    if (self->btCompareCallback != NULL) {
2449	PyErr_SetString(PyExc_RuntimeError, "set_bt_compare() cannot be called more than once");
2450	return NULL;
2451    }
2452
2453    Py_INCREF(comparator);
2454    self->btCompareCallback = comparator;
2455
2456    /* This is to workaround a problem with un-initialized threads (see
2457       comment in DB_associate) */
2458#ifdef WITH_THREAD
2459    PyEval_InitThreads();
2460#endif
2461
2462    err = self->db->set_bt_compare(self->db, _db_compareCallback);
2463
2464    if (err) {
2465	/* restore the old state in case of error */
2466	Py_DECREF(comparator);
2467	self->btCompareCallback = NULL;
2468    }
2469
2470    RETURN_IF_ERR();
2471    RETURN_NONE();
2472}
2473
2474
2475static PyObject*
2476DB_set_cachesize(DBObject* self, PyObject* args)
2477{
2478    int err;
2479    int gbytes = 0, bytes = 0, ncache = 0;
2480
2481    if (!PyArg_ParseTuple(args,"ii|i:set_cachesize",
2482                          &gbytes,&bytes,&ncache))
2483        return NULL;
2484    CHECK_DB_NOT_CLOSED(self);
2485
2486    MYDB_BEGIN_ALLOW_THREADS;
2487    err = self->db->set_cachesize(self->db, gbytes, bytes, ncache);
2488    MYDB_END_ALLOW_THREADS;
2489    RETURN_IF_ERR();
2490    RETURN_NONE();
2491}
2492
2493
2494static PyObject*
2495DB_set_flags(DBObject* self, PyObject* args)
2496{
2497    int err, flags;
2498
2499    if (!PyArg_ParseTuple(args,"i:set_flags", &flags))
2500        return NULL;
2501    CHECK_DB_NOT_CLOSED(self);
2502
2503    MYDB_BEGIN_ALLOW_THREADS;
2504    err = self->db->set_flags(self->db, flags);
2505    MYDB_END_ALLOW_THREADS;
2506    RETURN_IF_ERR();
2507
2508    self->setflags |= flags;
2509    RETURN_NONE();
2510}
2511
2512
2513static PyObject*
2514DB_set_h_ffactor(DBObject* self, PyObject* args)
2515{
2516    int err, ffactor;
2517
2518    if (!PyArg_ParseTuple(args,"i:set_h_ffactor", &ffactor))
2519        return NULL;
2520    CHECK_DB_NOT_CLOSED(self);
2521
2522    MYDB_BEGIN_ALLOW_THREADS;
2523    err = self->db->set_h_ffactor(self->db, ffactor);
2524    MYDB_END_ALLOW_THREADS;
2525    RETURN_IF_ERR();
2526    RETURN_NONE();
2527}
2528
2529
2530static PyObject*
2531DB_set_h_nelem(DBObject* self, PyObject* args)
2532{
2533    int err, nelem;
2534
2535    if (!PyArg_ParseTuple(args,"i:set_h_nelem", &nelem))
2536        return NULL;
2537    CHECK_DB_NOT_CLOSED(self);
2538
2539    MYDB_BEGIN_ALLOW_THREADS;
2540    err = self->db->set_h_nelem(self->db, nelem);
2541    MYDB_END_ALLOW_THREADS;
2542    RETURN_IF_ERR();
2543    RETURN_NONE();
2544}
2545
2546
2547static PyObject*
2548DB_set_lorder(DBObject* self, PyObject* args)
2549{
2550    int err, lorder;
2551
2552    if (!PyArg_ParseTuple(args,"i:set_lorder", &lorder))
2553        return NULL;
2554    CHECK_DB_NOT_CLOSED(self);
2555
2556    MYDB_BEGIN_ALLOW_THREADS;
2557    err = self->db->set_lorder(self->db, lorder);
2558    MYDB_END_ALLOW_THREADS;
2559    RETURN_IF_ERR();
2560    RETURN_NONE();
2561}
2562
2563
2564static PyObject*
2565DB_set_pagesize(DBObject* self, PyObject* args)
2566{
2567    int err, pagesize;
2568
2569    if (!PyArg_ParseTuple(args,"i:set_pagesize", &pagesize))
2570        return NULL;
2571    CHECK_DB_NOT_CLOSED(self);
2572
2573    MYDB_BEGIN_ALLOW_THREADS;
2574    err = self->db->set_pagesize(self->db, pagesize);
2575    MYDB_END_ALLOW_THREADS;
2576    RETURN_IF_ERR();
2577    RETURN_NONE();
2578}
2579
2580
2581static PyObject*
2582DB_set_re_delim(DBObject* self, PyObject* args)
2583{
2584    int err;
2585    char delim;
2586
2587    if (!PyArg_ParseTuple(args,"b:set_re_delim", &delim)) {
2588        PyErr_Clear();
2589        if (!PyArg_ParseTuple(args,"c:set_re_delim", &delim))
2590            return NULL;
2591    }
2592
2593    CHECK_DB_NOT_CLOSED(self);
2594
2595    MYDB_BEGIN_ALLOW_THREADS;
2596    err = self->db->set_re_delim(self->db, delim);
2597    MYDB_END_ALLOW_THREADS;
2598    RETURN_IF_ERR();
2599    RETURN_NONE();
2600}
2601
2602static PyObject*
2603DB_set_re_len(DBObject* self, PyObject* args)
2604{
2605    int err, len;
2606
2607    if (!PyArg_ParseTuple(args,"i:set_re_len", &len))
2608        return NULL;
2609    CHECK_DB_NOT_CLOSED(self);
2610
2611    MYDB_BEGIN_ALLOW_THREADS;
2612    err = self->db->set_re_len(self->db, len);
2613    MYDB_END_ALLOW_THREADS;
2614    RETURN_IF_ERR();
2615    RETURN_NONE();
2616}
2617
2618
2619static PyObject*
2620DB_set_re_pad(DBObject* self, PyObject* args)
2621{
2622    int err;
2623    char pad;
2624
2625    if (!PyArg_ParseTuple(args,"b:set_re_pad", &pad)) {
2626        PyErr_Clear();
2627        if (!PyArg_ParseTuple(args,"c:set_re_pad", &pad))
2628            return NULL;
2629    }
2630    CHECK_DB_NOT_CLOSED(self);
2631
2632    MYDB_BEGIN_ALLOW_THREADS;
2633    err = self->db->set_re_pad(self->db, pad);
2634    MYDB_END_ALLOW_THREADS;
2635    RETURN_IF_ERR();
2636    RETURN_NONE();
2637}
2638
2639
2640static PyObject*
2641DB_set_re_source(DBObject* self, PyObject* args)
2642{
2643    int err;
2644    char *re_source;
2645
2646    if (!PyArg_ParseTuple(args,"s:set_re_source", &re_source))
2647        return NULL;
2648    CHECK_DB_NOT_CLOSED(self);
2649
2650    MYDB_BEGIN_ALLOW_THREADS;
2651    err = self->db->set_re_source(self->db, re_source);
2652    MYDB_END_ALLOW_THREADS;
2653    RETURN_IF_ERR();
2654    RETURN_NONE();
2655}
2656
2657
2658static PyObject*
2659DB_set_q_extentsize(DBObject* self, PyObject* args)
2660{
2661    int err;
2662    int extentsize;
2663
2664    if (!PyArg_ParseTuple(args,"i:set_q_extentsize", &extentsize))
2665        return NULL;
2666    CHECK_DB_NOT_CLOSED(self);
2667
2668    MYDB_BEGIN_ALLOW_THREADS;
2669    err = self->db->set_q_extentsize(self->db, extentsize);
2670    MYDB_END_ALLOW_THREADS;
2671    RETURN_IF_ERR();
2672    RETURN_NONE();
2673}
2674
2675static PyObject*
2676DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
2677{
2678    int err, flags = 0, type;
2679    void* sp;
2680    PyObject* d;
2681#if (DBVER >= 43)
2682    PyObject* txnobj = NULL;
2683    DB_TXN *txn = NULL;
2684    static char* kwnames[] = { "flags", "txn", NULL };
2685#else
2686    static char* kwnames[] = { "flags", NULL };
2687#endif
2688
2689#if (DBVER >= 43)
2690    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO:stat", kwnames,
2691                                     &flags, &txnobj))
2692        return NULL;
2693    if (!checkTxnObj(txnobj, &txn))
2694        return NULL;
2695#else
2696    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags))
2697        return NULL;
2698#endif
2699    CHECK_DB_NOT_CLOSED(self);
2700
2701    MYDB_BEGIN_ALLOW_THREADS;
2702#if (DBVER >= 43)
2703    err = self->db->stat(self->db, txn, &sp, flags);
2704#else
2705    err = self->db->stat(self->db, &sp, flags);
2706#endif
2707    MYDB_END_ALLOW_THREADS;
2708    RETURN_IF_ERR();
2709
2710    self->haveStat = 1;
2711
2712    /* Turn the stat structure into a dictionary */
2713    type = _DB_get_type(self);
2714    if ((type == -1) || ((d = PyDict_New()) == NULL)) {
2715        free(sp);
2716        return NULL;
2717    }
2718
2719#define MAKE_HASH_ENTRY(name)  _addIntToDict(d, #name, ((DB_HASH_STAT*)sp)->hash_##name)
2720#define MAKE_BT_ENTRY(name)    _addIntToDict(d, #name, ((DB_BTREE_STAT*)sp)->bt_##name)
2721#define MAKE_QUEUE_ENTRY(name) _addIntToDict(d, #name, ((DB_QUEUE_STAT*)sp)->qs_##name)
2722
2723    switch (type) {
2724    case DB_HASH:
2725        MAKE_HASH_ENTRY(magic);
2726        MAKE_HASH_ENTRY(version);
2727        MAKE_HASH_ENTRY(nkeys);
2728        MAKE_HASH_ENTRY(ndata);
2729#if (DBVER >= 46)
2730        MAKE_HASH_ENTRY(pagecnt);
2731#endif
2732        MAKE_HASH_ENTRY(pagesize);
2733#if (DBVER < 41)
2734        MAKE_HASH_ENTRY(nelem);
2735#endif
2736        MAKE_HASH_ENTRY(ffactor);
2737        MAKE_HASH_ENTRY(buckets);
2738        MAKE_HASH_ENTRY(free);
2739        MAKE_HASH_ENTRY(bfree);
2740        MAKE_HASH_ENTRY(bigpages);
2741        MAKE_HASH_ENTRY(big_bfree);
2742        MAKE_HASH_ENTRY(overflows);
2743        MAKE_HASH_ENTRY(ovfl_free);
2744        MAKE_HASH_ENTRY(dup);
2745        MAKE_HASH_ENTRY(dup_free);
2746        break;
2747
2748    case DB_BTREE:
2749    case DB_RECNO:
2750        MAKE_BT_ENTRY(magic);
2751        MAKE_BT_ENTRY(version);
2752        MAKE_BT_ENTRY(nkeys);
2753        MAKE_BT_ENTRY(ndata);
2754#if (DBVER >= 46)
2755        MAKE_BT_ENTRY(pagecnt);
2756#endif
2757        MAKE_BT_ENTRY(pagesize);
2758        MAKE_BT_ENTRY(minkey);
2759        MAKE_BT_ENTRY(re_len);
2760        MAKE_BT_ENTRY(re_pad);
2761        MAKE_BT_ENTRY(levels);
2762        MAKE_BT_ENTRY(int_pg);
2763        MAKE_BT_ENTRY(leaf_pg);
2764        MAKE_BT_ENTRY(dup_pg);
2765        MAKE_BT_ENTRY(over_pg);
2766#if (DBVER >= 43)
2767        MAKE_BT_ENTRY(empty_pg);
2768#endif
2769        MAKE_BT_ENTRY(free);
2770        MAKE_BT_ENTRY(int_pgfree);
2771        MAKE_BT_ENTRY(leaf_pgfree);
2772        MAKE_BT_ENTRY(dup_pgfree);
2773        MAKE_BT_ENTRY(over_pgfree);
2774        break;
2775
2776    case DB_QUEUE:
2777        MAKE_QUEUE_ENTRY(magic);
2778        MAKE_QUEUE_ENTRY(version);
2779        MAKE_QUEUE_ENTRY(nkeys);
2780        MAKE_QUEUE_ENTRY(ndata);
2781        MAKE_QUEUE_ENTRY(pagesize);
2782#if (DBVER >= 41)
2783        MAKE_QUEUE_ENTRY(extentsize);
2784#endif
2785        MAKE_QUEUE_ENTRY(pages);
2786        MAKE_QUEUE_ENTRY(re_len);
2787        MAKE_QUEUE_ENTRY(re_pad);
2788        MAKE_QUEUE_ENTRY(pgfree);
2789#if (DBVER == 31)
2790        MAKE_QUEUE_ENTRY(start);
2791#endif
2792        MAKE_QUEUE_ENTRY(first_recno);
2793        MAKE_QUEUE_ENTRY(cur_recno);
2794        break;
2795
2796    default:
2797        PyErr_SetString(PyExc_TypeError, "Unknown DB type, unable to stat");
2798        Py_DECREF(d);
2799        d = NULL;
2800    }
2801
2802#undef MAKE_HASH_ENTRY
2803#undef MAKE_BT_ENTRY
2804#undef MAKE_QUEUE_ENTRY
2805
2806    free(sp);
2807    return d;
2808}
2809
2810static PyObject*
2811DB_sync(DBObject* self, PyObject* args)
2812{
2813    int err;
2814    int flags = 0;
2815
2816    if (!PyArg_ParseTuple(args,"|i:sync", &flags ))
2817        return NULL;
2818    CHECK_DB_NOT_CLOSED(self);
2819
2820    MYDB_BEGIN_ALLOW_THREADS;
2821    err = self->db->sync(self->db, flags);
2822    MYDB_END_ALLOW_THREADS;
2823    RETURN_IF_ERR();
2824    RETURN_NONE();
2825}
2826
2827
2828static PyObject*
2829DB_truncate(DBObject* self, PyObject* args, PyObject* kwargs)
2830{
2831    int err, flags=0;
2832    u_int32_t count=0;
2833    PyObject* txnobj = NULL;
2834    DB_TXN *txn = NULL;
2835    static char* kwnames[] = { "txn", "flags", NULL };
2836
2837    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames,
2838                                     &txnobj, &flags))
2839        return NULL;
2840    CHECK_DB_NOT_CLOSED(self);
2841    if (!checkTxnObj(txnobj, &txn))
2842        return NULL;
2843
2844    MYDB_BEGIN_ALLOW_THREADS;
2845    err = self->db->truncate(self->db, txn, &count, flags);
2846    MYDB_END_ALLOW_THREADS;
2847    RETURN_IF_ERR();
2848    return NUMBER_FromLong(count);
2849}
2850
2851
2852static PyObject*
2853DB_upgrade(DBObject* self, PyObject* args)
2854{
2855    int err, flags=0;
2856    char *filename;
2857
2858    if (!PyArg_ParseTuple(args,"s|i:upgrade", &filename, &flags))
2859        return NULL;
2860    CHECK_DB_NOT_CLOSED(self);
2861
2862    MYDB_BEGIN_ALLOW_THREADS;
2863    err = self->db->upgrade(self->db, filename, flags);
2864    MYDB_END_ALLOW_THREADS;
2865    RETURN_IF_ERR();
2866    RETURN_NONE();
2867}
2868
2869
2870static PyObject*
2871DB_verify(DBObject* self, PyObject* args, PyObject* kwargs)
2872{
2873    int err, flags=0;
2874    char* fileName;
2875    char* dbName=NULL;
2876    char* outFileName=NULL;
2877    FILE* outFile=NULL;
2878    static char* kwnames[] = { "filename", "dbname", "outfile", "flags",
2879                                     NULL };
2880
2881    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzi:verify", kwnames,
2882                                     &fileName, &dbName, &outFileName, &flags))
2883        return NULL;
2884
2885    CHECK_DB_NOT_CLOSED(self);
2886    if (outFileName)
2887        outFile = fopen(outFileName, "w");
2888	/* XXX(nnorwitz): it should probably be an exception if outFile
2889	   can't be opened. */
2890
2891    {  /* DB.verify acts as a DB handle destructor (like close) */
2892        PyObject *error;
2893
2894        error=DB_close_internal(self, 0, 1);
2895        if (error ) {
2896          return error;
2897        }
2898     }
2899
2900    MYDB_BEGIN_ALLOW_THREADS;
2901    err = self->db->verify(self->db, fileName, dbName, outFile, flags);
2902    MYDB_END_ALLOW_THREADS;
2903
2904    self->db = NULL;  /* Implicit close; related objects already released */
2905
2906    if (outFile)
2907        fclose(outFile);
2908
2909    RETURN_IF_ERR();
2910    RETURN_NONE();
2911}
2912
2913
2914static PyObject*
2915DB_set_get_returns_none(DBObject* self, PyObject* args)
2916{
2917    int flags=0;
2918    int oldValue=0;
2919
2920    if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
2921        return NULL;
2922    CHECK_DB_NOT_CLOSED(self);
2923
2924    if (self->moduleFlags.getReturnsNone)
2925        ++oldValue;
2926    if (self->moduleFlags.cursorSetReturnsNone)
2927        ++oldValue;
2928    self->moduleFlags.getReturnsNone = (flags >= 1);
2929    self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
2930    return NUMBER_FromLong(oldValue);
2931}
2932
2933#if (DBVER >= 41)
2934static PyObject*
2935DB_set_encrypt(DBObject* self, PyObject* args, PyObject* kwargs)
2936{
2937    int err;
2938    u_int32_t flags=0;
2939    char *passwd = NULL;
2940    static char* kwnames[] = { "passwd", "flags", NULL };
2941
2942    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames,
2943		&passwd, &flags)) {
2944	return NULL;
2945    }
2946
2947    MYDB_BEGIN_ALLOW_THREADS;
2948    err = self->db->set_encrypt(self->db, passwd, flags);
2949    MYDB_END_ALLOW_THREADS;
2950
2951    RETURN_IF_ERR();
2952    RETURN_NONE();
2953}
2954#endif /* DBVER >= 41 */
2955
2956
2957/*-------------------------------------------------------------- */
2958/* Mapping and Dictionary-like access routines */
2959
2960Py_ssize_t DB_length(PyObject* _self)
2961{
2962    int err;
2963    Py_ssize_t size = 0;
2964    int flags = 0;
2965    void* sp;
2966    DBObject* self = (DBObject*)_self;
2967
2968    if (self->db == NULL) {
2969        PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed");
2970        if (t) {
2971            PyErr_SetObject(DBError, t);
2972            Py_DECREF(t);
2973        }
2974        return -1;
2975    }
2976
2977    if (self->haveStat) {  /* Has the stat function been called recently?  If
2978                              so, we can use the cached value. */
2979        flags = DB_FAST_STAT;
2980    }
2981
2982    MYDB_BEGIN_ALLOW_THREADS;
2983redo_stat_for_length:
2984#if (DBVER >= 43)
2985    err = self->db->stat(self->db, /*txnid*/ NULL, &sp, flags);
2986#else
2987    err = self->db->stat(self->db, &sp, flags);
2988#endif
2989
2990    /* All the stat structures have matching fields upto the ndata field,
2991       so we can use any of them for the type cast */
2992    size = ((DB_BTREE_STAT*)sp)->bt_ndata;
2993
2994    /* A size of 0 could mean that Berkeley DB no longer had the stat values cached.
2995     * redo a full stat to make sure.
2996     *   Fixes SF python bug 1493322, pybsddb bug 1184012
2997     */
2998    if (size == 0 && (flags & DB_FAST_STAT)) {
2999        flags = 0;
3000        if (!err)
3001            free(sp);
3002        goto redo_stat_for_length;
3003    }
3004
3005    MYDB_END_ALLOW_THREADS;
3006
3007    if (err)
3008        return -1;
3009
3010    self->haveStat = 1;
3011
3012    free(sp);
3013    return size;
3014}
3015
3016
3017PyObject* DB_subscript(DBObject* self, PyObject* keyobj)
3018{
3019    int err;
3020    PyObject* retval;
3021    DBT key;
3022    DBT data;
3023
3024    CHECK_DB_NOT_CLOSED(self);
3025    if (!make_key_dbt(self, keyobj, &key, NULL))
3026        return NULL;
3027
3028    CLEAR_DBT(data);
3029    if (CHECK_DBFLAG(self, DB_THREAD)) {
3030        /* Tell Berkeley DB to malloc the return value (thread safe) */
3031        data.flags = DB_DBT_MALLOC;
3032    }
3033    MYDB_BEGIN_ALLOW_THREADS;
3034    err = self->db->get(self->db, NULL, &key, &data, 0);
3035    MYDB_END_ALLOW_THREADS;
3036    if (err == DB_NOTFOUND || err == DB_KEYEMPTY) {
3037        PyErr_SetObject(PyExc_KeyError, keyobj);
3038        retval = NULL;
3039    }
3040    else if (makeDBError(err)) {
3041        retval = NULL;
3042    }
3043    else {
3044        retval = Build_PyString(data.data, data.size);
3045        FREE_DBT(data);
3046    }
3047
3048    FREE_DBT(key);
3049    return retval;
3050}
3051
3052
3053static int
3054DB_ass_sub(DBObject* self, PyObject* keyobj, PyObject* dataobj)
3055{
3056    DBT key, data;
3057    int retval;
3058    int flags = 0;
3059
3060    if (self->db == NULL) {
3061        PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed");
3062        if (t) {
3063            PyErr_SetObject(DBError, t);
3064            Py_DECREF(t);
3065        }
3066        return -1;
3067    }
3068
3069    if (!make_key_dbt(self, keyobj, &key, NULL))
3070        return -1;
3071
3072    if (dataobj != NULL) {
3073        if (!make_dbt(dataobj, &data))
3074            retval =  -1;
3075        else {
3076            if (self->setflags & (DB_DUP|DB_DUPSORT))
3077                /* dictionaries shouldn't have duplicate keys */
3078                flags = DB_NOOVERWRITE;
3079            retval = _DB_put(self, NULL, &key, &data, flags);
3080
3081            if ((retval == -1) &&  (self->setflags & (DB_DUP|DB_DUPSORT))) {
3082                /* try deleting any old record that matches and then PUT it
3083                 * again... */
3084                _DB_delete(self, NULL, &key, 0);
3085                PyErr_Clear();
3086                retval = _DB_put(self, NULL, &key, &data, flags);
3087            }
3088        }
3089    }
3090    else {
3091        /* dataobj == NULL, so delete the key */
3092        retval = _DB_delete(self, NULL, &key, 0);
3093    }
3094    FREE_DBT(key);
3095    return retval;
3096}
3097
3098
3099static PyObject*
3100DB_has_key(DBObject* self, PyObject* args, PyObject* kwargs)
3101{
3102    int err;
3103    PyObject* keyobj;
3104    DBT key, data;
3105    PyObject* txnobj = NULL;
3106    DB_TXN *txn = NULL;
3107    static char* kwnames[] = {"key","txn", NULL};
3108
3109    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:has_key", kwnames,
3110                &keyobj, &txnobj))
3111        return NULL;
3112
3113    CHECK_DB_NOT_CLOSED(self);
3114    if (!make_key_dbt(self, keyobj, &key, NULL))
3115        return NULL;
3116    if (!checkTxnObj(txnobj, &txn)) {
3117        FREE_DBT(key);
3118        return NULL;
3119    }
3120
3121    /* This causes DB_BUFFER_SMALL to be returned when the db has the key because
3122       it has a record but can't allocate a buffer for the data.  This saves
3123       having to deal with data we won't be using.
3124     */
3125    CLEAR_DBT(data);
3126    data.flags = DB_DBT_USERMEM;
3127
3128    MYDB_BEGIN_ALLOW_THREADS;
3129    err = self->db->get(self->db, txn, &key, &data, 0);
3130    MYDB_END_ALLOW_THREADS;
3131    FREE_DBT(key);
3132
3133    if (err == DB_BUFFER_SMALL || err == 0) {
3134        return NUMBER_FromLong(1);
3135    } else if (err == DB_NOTFOUND || err == DB_KEYEMPTY) {
3136        return NUMBER_FromLong(0);
3137    }
3138
3139    makeDBError(err);
3140    return NULL;
3141}
3142
3143
3144#define _KEYS_LIST      1
3145#define _VALUES_LIST    2
3146#define _ITEMS_LIST     3
3147
3148static PyObject*
3149_DB_make_list(DBObject* self, DB_TXN* txn, int type)
3150{
3151    int err, dbtype;
3152    DBT key;
3153    DBT data;
3154    DBC *cursor;
3155    PyObject* list;
3156    PyObject* item = NULL;
3157
3158    CHECK_DB_NOT_CLOSED(self);
3159    CLEAR_DBT(key);
3160    CLEAR_DBT(data);
3161
3162    dbtype = _DB_get_type(self);
3163    if (dbtype == -1)
3164        return NULL;
3165
3166    list = PyList_New(0);
3167    if (list == NULL)
3168        return NULL;
3169
3170    /* get a cursor */
3171    MYDB_BEGIN_ALLOW_THREADS;
3172    err = self->db->cursor(self->db, txn, &cursor, 0);
3173    MYDB_END_ALLOW_THREADS;
3174    if (makeDBError(err)) {
3175        Py_DECREF(list);
3176        return NULL;
3177    }
3178
3179    while (1) { /* use the cursor to traverse the DB, collecting items */
3180        MYDB_BEGIN_ALLOW_THREADS;
3181        err = _DBC_get(cursor, &key, &data, DB_NEXT);
3182        MYDB_END_ALLOW_THREADS;
3183
3184        if (err) {
3185            /* for any error, break out of the loop */
3186            break;
3187        }
3188
3189        switch (type) {
3190        case _KEYS_LIST:
3191            switch(dbtype) {
3192            case DB_BTREE:
3193            case DB_HASH:
3194            default:
3195                item = Build_PyString(key.data, key.size);
3196                break;
3197            case DB_RECNO:
3198            case DB_QUEUE:
3199                item = NUMBER_FromLong(*((db_recno_t*)key.data));
3200                break;
3201            }
3202            break;
3203
3204        case _VALUES_LIST:
3205            item = Build_PyString(data.data, data.size);
3206            break;
3207
3208        case _ITEMS_LIST:
3209            switch(dbtype) {
3210            case DB_BTREE:
3211            case DB_HASH:
3212            default:
3213                item = BuildValue_SS(key.data, key.size, data.data, data.size);
3214                break;
3215            case DB_RECNO:
3216            case DB_QUEUE:
3217                item = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3218                break;
3219            }
3220            break;
3221        default:
3222            PyErr_Format(PyExc_ValueError, "Unknown key type 0x%x", type);
3223            item = NULL;
3224            break;
3225        }
3226        if (item == NULL) {
3227            Py_DECREF(list);
3228            list = NULL;
3229            goto done;
3230        }
3231        if (PyList_Append(list, item)) {
3232            Py_DECREF(list);
3233            Py_DECREF(item);
3234            list = NULL;
3235            goto done;
3236        }
3237        Py_DECREF(item);
3238    }
3239
3240    /* DB_NOTFOUND || DB_KEYEMPTY is okay, it means we got to the end */
3241    if (err != DB_NOTFOUND && err != DB_KEYEMPTY && makeDBError(err)) {
3242        Py_DECREF(list);
3243        list = NULL;
3244    }
3245
3246 done:
3247    MYDB_BEGIN_ALLOW_THREADS;
3248    _DBC_close(cursor);
3249    MYDB_END_ALLOW_THREADS;
3250    return list;
3251}
3252
3253
3254static PyObject*
3255DB_keys(DBObject* self, PyObject* args)
3256{
3257    PyObject* txnobj = NULL;
3258    DB_TXN *txn = NULL;
3259
3260    if (!PyArg_UnpackTuple(args, "keys", 0, 1, &txnobj))
3261        return NULL;
3262    if (!checkTxnObj(txnobj, &txn))
3263        return NULL;
3264    return _DB_make_list(self, txn, _KEYS_LIST);
3265}
3266
3267
3268static PyObject*
3269DB_items(DBObject* self, PyObject* args)
3270{
3271    PyObject* txnobj = NULL;
3272    DB_TXN *txn = NULL;
3273
3274    if (!PyArg_UnpackTuple(args, "items", 0, 1, &txnobj))
3275        return NULL;
3276    if (!checkTxnObj(txnobj, &txn))
3277        return NULL;
3278    return _DB_make_list(self, txn, _ITEMS_LIST);
3279}
3280
3281
3282static PyObject*
3283DB_values(DBObject* self, PyObject* args)
3284{
3285    PyObject* txnobj = NULL;
3286    DB_TXN *txn = NULL;
3287
3288    if (!PyArg_UnpackTuple(args, "values", 0, 1, &txnobj))
3289        return NULL;
3290    if (!checkTxnObj(txnobj, &txn))
3291        return NULL;
3292    return _DB_make_list(self, txn, _VALUES_LIST);
3293}
3294
3295/* --------------------------------------------------------------------- */
3296/* DBCursor methods */
3297
3298
3299static PyObject*
3300DBC_close_internal(DBCursorObject* self)
3301{
3302    int err = 0;
3303
3304    if (self->dbc != NULL) {
3305        EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
3306        if (self->txn) {
3307            EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
3308            self->txn=NULL;
3309        }
3310
3311        MYDB_BEGIN_ALLOW_THREADS;
3312        err = _DBC_close(self->dbc);
3313        MYDB_END_ALLOW_THREADS;
3314        self->dbc = NULL;
3315    }
3316    RETURN_IF_ERR();
3317    RETURN_NONE();
3318}
3319
3320static PyObject*
3321DBC_close(DBCursorObject* self)
3322{
3323    return DBC_close_internal(self);
3324}
3325
3326
3327static PyObject*
3328DBC_count(DBCursorObject* self, PyObject* args)
3329{
3330    int err = 0;
3331    db_recno_t count;
3332    int flags = 0;
3333
3334    if (!PyArg_ParseTuple(args, "|i:count", &flags))
3335        return NULL;
3336
3337    CHECK_CURSOR_NOT_CLOSED(self);
3338
3339    MYDB_BEGIN_ALLOW_THREADS;
3340    err = _DBC_count(self->dbc, &count, flags);
3341    MYDB_END_ALLOW_THREADS;
3342    RETURN_IF_ERR();
3343
3344    return NUMBER_FromLong(count);
3345}
3346
3347
3348static PyObject*
3349DBC_current(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3350{
3351    return _DBCursor_get(self,DB_CURRENT,args,kwargs,"|iii:current");
3352}
3353
3354
3355static PyObject*
3356DBC_delete(DBCursorObject* self, PyObject* args)
3357{
3358    int err, flags=0;
3359
3360    if (!PyArg_ParseTuple(args, "|i:delete", &flags))
3361        return NULL;
3362
3363    CHECK_CURSOR_NOT_CLOSED(self);
3364
3365    MYDB_BEGIN_ALLOW_THREADS;
3366    err = _DBC_del(self->dbc, flags);
3367    MYDB_END_ALLOW_THREADS;
3368    RETURN_IF_ERR();
3369
3370    self->mydb->haveStat = 0;
3371    RETURN_NONE();
3372}
3373
3374
3375static PyObject*
3376DBC_dup(DBCursorObject* self, PyObject* args)
3377{
3378    int err, flags =0;
3379    DBC* dbc = NULL;
3380
3381    if (!PyArg_ParseTuple(args, "|i:dup", &flags))
3382        return NULL;
3383
3384    CHECK_CURSOR_NOT_CLOSED(self);
3385
3386    MYDB_BEGIN_ALLOW_THREADS;
3387    err = _DBC_dup(self->dbc, &dbc, flags);
3388    MYDB_END_ALLOW_THREADS;
3389    RETURN_IF_ERR();
3390
3391    return (PyObject*) newDBCursorObject(dbc, self->txn, self->mydb);
3392}
3393
3394static PyObject*
3395DBC_first(DBCursorObject* self, PyObject* args, PyObject* kwargs)
3396{
3397    return _DBCursor_get(self,DB_FIRST,args,kwargs,"|iii:first");
3398}
3399
3400
3401static PyObject*
3402DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3403{
3404    int err, flags=0;
3405    PyObject* keyobj = NULL;
3406    PyObject* dataobj = NULL;
3407    PyObject* retval = NULL;
3408    int dlen = -1;
3409    int doff = -1;
3410    DBT key, data;
3411    static char* kwnames[] = { "key","data", "flags", "dlen", "doff",
3412                                     NULL };
3413
3414    CLEAR_DBT(key);
3415    CLEAR_DBT(data);
3416    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:get", &kwnames[2],
3417				     &flags, &dlen, &doff))
3418    {
3419        PyErr_Clear();
3420        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:get",
3421                                         &kwnames[1],
3422					 &keyobj, &flags, &dlen, &doff))
3423        {
3424            PyErr_Clear();
3425            if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:get",
3426                                             kwnames, &keyobj, &dataobj,
3427                                             &flags, &dlen, &doff))
3428            {
3429                return NULL;
3430	    }
3431	}
3432    }
3433
3434    CHECK_CURSOR_NOT_CLOSED(self);
3435
3436    if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
3437        return NULL;
3438    if ( (dataobj && !make_dbt(dataobj, &data)) ||
3439         (!add_partial_dbt(&data, dlen, doff)) )
3440    {
3441        FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3442        return NULL;
3443    }
3444
3445    MYDB_BEGIN_ALLOW_THREADS;
3446    err = _DBC_get(self->dbc, &key, &data, flags);
3447    MYDB_END_ALLOW_THREADS;
3448
3449    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3450	    && self->mydb->moduleFlags.getReturnsNone) {
3451        Py_INCREF(Py_None);
3452        retval = Py_None;
3453    }
3454    else if (makeDBError(err)) {
3455        retval = NULL;
3456    }
3457    else {
3458        switch (_DB_get_type(self->mydb)) {
3459        case -1:
3460            retval = NULL;
3461            break;
3462        case DB_BTREE:
3463        case DB_HASH:
3464        default:
3465            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3466            break;
3467        case DB_RECNO:
3468        case DB_QUEUE:
3469            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3470            break;
3471        }
3472    }
3473    FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3474    return retval;
3475}
3476
3477static PyObject*
3478DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3479{
3480    int err, flags=0;
3481    PyObject* keyobj = NULL;
3482    PyObject* dataobj = NULL;
3483    PyObject* retval = NULL;
3484    int dlen = -1;
3485    int doff = -1;
3486    DBT key, pkey, data;
3487    static char* kwnames_keyOnly[] = { "key", "flags", "dlen", "doff", NULL };
3488    static char* kwnames[] = { "key", "data", "flags", "dlen", "doff", NULL };
3489
3490    CLEAR_DBT(key);
3491    CLEAR_DBT(data);
3492    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:pget", &kwnames[2],
3493				     &flags, &dlen, &doff))
3494    {
3495        PyErr_Clear();
3496        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:pget",
3497                                         kwnames_keyOnly, 
3498					 &keyobj, &flags, &dlen, &doff))
3499        {
3500            PyErr_Clear();
3501            if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:pget",
3502                                             kwnames, &keyobj, &dataobj,
3503                                             &flags, &dlen, &doff))
3504            {
3505                return NULL;
3506	    }
3507	}
3508    }
3509
3510    CHECK_CURSOR_NOT_CLOSED(self);
3511
3512    if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
3513        return NULL;
3514    if ( (dataobj && !make_dbt(dataobj, &data)) ||
3515         (!add_partial_dbt(&data, dlen, doff)) ) {
3516        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3517        return NULL;
3518    }
3519
3520    CLEAR_DBT(pkey);
3521    pkey.flags = DB_DBT_MALLOC;
3522
3523    MYDB_BEGIN_ALLOW_THREADS;
3524    err = _DBC_pget(self->dbc, &key, &pkey, &data, flags);
3525    MYDB_END_ALLOW_THREADS;
3526
3527    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3528	    && self->mydb->moduleFlags.getReturnsNone) {
3529        Py_INCREF(Py_None);
3530        retval = Py_None;
3531    }
3532    else if (makeDBError(err)) {
3533        retval = NULL;
3534    }
3535    else {
3536        PyObject *pkeyObj;
3537        PyObject *dataObj;
3538        dataObj = Build_PyString(data.data, data.size);
3539
3540        if (self->mydb->primaryDBType == DB_RECNO ||
3541            self->mydb->primaryDBType == DB_QUEUE)
3542            pkeyObj = NUMBER_FromLong(*(int *)pkey.data);
3543        else
3544            pkeyObj = Build_PyString(pkey.data, pkey.size);
3545
3546        if (key.data && key.size) /* return key, pkey and data */
3547        {
3548            PyObject *keyObj;
3549            int type = _DB_get_type(self->mydb);
3550            if (type == DB_RECNO || type == DB_QUEUE)
3551                keyObj = NUMBER_FromLong(*(int *)key.data);
3552            else
3553                keyObj = Build_PyString(key.data, key.size);
3554#if (PY_VERSION_HEX >= 0x02040000)
3555            retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
3556#else
3557            retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj);
3558#endif
3559            Py_DECREF(keyObj);
3560            FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3561        }
3562        else /* return just the pkey and data */
3563        {
3564#if (PY_VERSION_HEX >= 0x02040000)
3565            retval = PyTuple_Pack(2, pkeyObj, dataObj);
3566#else
3567            retval = Py_BuildValue("OO", pkeyObj, dataObj);
3568#endif
3569        }
3570        Py_DECREF(dataObj);
3571        Py_DECREF(pkeyObj);
3572        FREE_DBT(pkey);
3573    }
3574    /* the only time REALLOC should be set is if we used an integer
3575     * key that make_key_dbt malloc'd for us.  always free these. */
3576    if (key.flags & DB_DBT_REALLOC) {  /* 'make_key_dbt' could do a 'malloc' */
3577        FREE_DBT(key);
3578    }
3579    return retval;
3580}
3581
3582
3583static PyObject*
3584DBC_get_recno(DBCursorObject* self)
3585{
3586    int err;
3587    db_recno_t recno;
3588    DBT key;
3589    DBT data;
3590
3591    CHECK_CURSOR_NOT_CLOSED(self);
3592
3593    CLEAR_DBT(key);
3594    CLEAR_DBT(data);
3595
3596    MYDB_BEGIN_ALLOW_THREADS;
3597    err = _DBC_get(self->dbc, &key, &data, DB_GET_RECNO);
3598    MYDB_END_ALLOW_THREADS;
3599    RETURN_IF_ERR();
3600
3601    recno = *((db_recno_t*)data.data);
3602    return NUMBER_FromLong(recno);
3603}
3604
3605
3606static PyObject*
3607DBC_last(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3608{
3609    return _DBCursor_get(self,DB_LAST,args,kwargs,"|iii:last");
3610}
3611
3612
3613static PyObject*
3614DBC_next(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3615{
3616    return _DBCursor_get(self,DB_NEXT,args,kwargs,"|iii:next");
3617}
3618
3619
3620static PyObject*
3621DBC_prev(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3622{
3623    return _DBCursor_get(self,DB_PREV,args,kwargs,"|iii:prev");
3624}
3625
3626
3627static PyObject*
3628DBC_put(DBCursorObject* self, PyObject* args, PyObject* kwargs)
3629{
3630    int err, flags = 0;
3631    PyObject* keyobj, *dataobj;
3632    DBT key, data;
3633    static char* kwnames[] = { "key", "data", "flags", "dlen", "doff",
3634                                     NULL };
3635    int dlen = -1;
3636    int doff = -1;
3637
3638    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iii:put", kwnames,
3639				     &keyobj, &dataobj, &flags, &dlen, &doff))
3640        return NULL;
3641
3642    CHECK_CURSOR_NOT_CLOSED(self);
3643
3644    if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
3645        return NULL;
3646    if (!make_dbt(dataobj, &data) ||
3647        !add_partial_dbt(&data, dlen, doff) )
3648    {
3649        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3650        return NULL;
3651    }
3652
3653    MYDB_BEGIN_ALLOW_THREADS;
3654    err = _DBC_put(self->dbc, &key, &data, flags);
3655    MYDB_END_ALLOW_THREADS;
3656    FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3657    RETURN_IF_ERR();
3658    self->mydb->haveStat = 0;
3659    RETURN_NONE();
3660}
3661
3662
3663static PyObject*
3664DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3665{
3666    int err, flags = 0;
3667    DBT key, data;
3668    PyObject* retval, *keyobj;
3669    static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL };
3670    int dlen = -1;
3671    int doff = -1;
3672
3673    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set", kwnames,
3674				     &keyobj, &flags, &dlen, &doff))
3675        return NULL;
3676
3677    CHECK_CURSOR_NOT_CLOSED(self);
3678
3679    if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
3680        return NULL;
3681
3682    CLEAR_DBT(data);
3683    if (!add_partial_dbt(&data, dlen, doff)) {
3684        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3685        return NULL;
3686    }
3687
3688    MYDB_BEGIN_ALLOW_THREADS;
3689    err = _DBC_get(self->dbc, &key, &data, flags|DB_SET);
3690    MYDB_END_ALLOW_THREADS;
3691    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3692	    && self->mydb->moduleFlags.cursorSetReturnsNone) {
3693        Py_INCREF(Py_None);
3694        retval = Py_None;
3695    }
3696    else if (makeDBError(err)) {
3697        retval = NULL;
3698    }
3699    else {
3700        switch (_DB_get_type(self->mydb)) {
3701        case -1:
3702            retval = NULL;
3703            break;
3704        case DB_BTREE:
3705        case DB_HASH:
3706        default:
3707            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3708            break;
3709        case DB_RECNO:
3710        case DB_QUEUE:
3711            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3712            break;
3713        }
3714        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3715    }
3716    /* the only time REALLOC should be set is if we used an integer
3717     * key that make_key_dbt malloc'd for us.  always free these. */
3718    if (key.flags & DB_DBT_REALLOC) {
3719        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3720    }
3721
3722    return retval;
3723}
3724
3725
3726static PyObject*
3727DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
3728{
3729    int err, flags = 0;
3730    DBT key, data;
3731    PyObject* retval, *keyobj;
3732    static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL };
3733    int dlen = -1;
3734    int doff = -1;
3735
3736    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set_range", kwnames,
3737				     &keyobj, &flags, &dlen, &doff))
3738        return NULL;
3739
3740    CHECK_CURSOR_NOT_CLOSED(self);
3741
3742    if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
3743        return NULL;
3744
3745    CLEAR_DBT(data);
3746    if (!add_partial_dbt(&data, dlen, doff)) {
3747        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3748        return NULL;
3749    }
3750    MYDB_BEGIN_ALLOW_THREADS;
3751    err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
3752    MYDB_END_ALLOW_THREADS;
3753    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3754	    && self->mydb->moduleFlags.cursorSetReturnsNone) {
3755        Py_INCREF(Py_None);
3756        retval = Py_None;
3757    }
3758    else if (makeDBError(err)) {
3759        retval = NULL;
3760    }
3761    else {
3762        switch (_DB_get_type(self->mydb)) {
3763        case -1:
3764            retval = NULL;
3765            break;
3766        case DB_BTREE:
3767        case DB_HASH:
3768        default:
3769            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3770            break;
3771        case DB_RECNO:
3772        case DB_QUEUE:
3773            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3774            break;
3775        }
3776        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3777    }
3778    /* the only time REALLOC should be set is if we used an integer
3779     * key that make_key_dbt malloc'd for us.  always free these. */
3780    if (key.flags & DB_DBT_REALLOC) {
3781        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3782    }
3783
3784    return retval;
3785}
3786
3787static PyObject*
3788_DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
3789                  int flags, unsigned int returnsNone)
3790{
3791    int err;
3792    DBT key, data;
3793    PyObject* retval;
3794
3795    /* the caller did this:  CHECK_CURSOR_NOT_CLOSED(self); */
3796    if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
3797        return NULL;
3798    if (!make_dbt(dataobj, &data)) {
3799        FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3800        return NULL;
3801    }
3802
3803    MYDB_BEGIN_ALLOW_THREADS;
3804    err = _DBC_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
3805    MYDB_END_ALLOW_THREADS;
3806    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && returnsNone) {
3807        Py_INCREF(Py_None);
3808        retval = Py_None;
3809    }
3810    else if (makeDBError(err)) {
3811        retval = NULL;
3812    }
3813    else {
3814        switch (_DB_get_type(self->mydb)) {
3815        case -1:
3816            retval = NULL;
3817            break;
3818        case DB_BTREE:
3819        case DB_HASH:
3820        default:
3821            retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3822            break;
3823        case DB_RECNO:
3824        case DB_QUEUE:
3825            retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3826            break;
3827        }
3828    }
3829
3830    FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
3831    return retval;
3832}
3833
3834static PyObject*
3835DBC_get_both(DBCursorObject* self, PyObject* args)
3836{
3837    int flags=0;
3838    PyObject *keyobj, *dataobj;
3839
3840    if (!PyArg_ParseTuple(args, "OO|i:get_both", &keyobj, &dataobj, &flags))
3841        return NULL;
3842
3843    /* if the cursor is closed, self->mydb may be invalid */
3844    CHECK_CURSOR_NOT_CLOSED(self);
3845
3846    return _DBC_get_set_both(self, keyobj, dataobj, flags,
3847                self->mydb->moduleFlags.getReturnsNone);
3848}
3849
3850/* Return size of entry */
3851static PyObject*
3852DBC_get_current_size(DBCursorObject* self)
3853{
3854    int err, flags=DB_CURRENT;
3855    PyObject* retval = NULL;
3856    DBT key, data;
3857
3858    CHECK_CURSOR_NOT_CLOSED(self);
3859    CLEAR_DBT(key);
3860    CLEAR_DBT(data);
3861
3862    /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and thus
3863       getting the record size. */
3864    data.flags = DB_DBT_USERMEM;
3865    data.ulen = 0;
3866    MYDB_BEGIN_ALLOW_THREADS;
3867    err = _DBC_get(self->dbc, &key, &data, flags);
3868    MYDB_END_ALLOW_THREADS;
3869    if (err == DB_BUFFER_SMALL || !err) {
3870        /* DB_BUFFER_SMALL means positive size, !err means zero length value */
3871        retval = NUMBER_FromLong((long)data.size);
3872        err = 0;
3873    }
3874
3875    RETURN_IF_ERR();
3876    return retval;
3877}
3878
3879static PyObject*
3880DBC_set_both(DBCursorObject* self, PyObject* args)
3881{
3882    int flags=0;
3883    PyObject *keyobj, *dataobj;
3884
3885    if (!PyArg_ParseTuple(args, "OO|i:set_both", &keyobj, &dataobj, &flags))
3886        return NULL;
3887
3888    /* if the cursor is closed, self->mydb may be invalid */
3889    CHECK_CURSOR_NOT_CLOSED(self);
3890
3891    return _DBC_get_set_both(self, keyobj, dataobj, flags,
3892                self->mydb->moduleFlags.cursorSetReturnsNone);
3893}
3894
3895
3896static PyObject*
3897DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3898{
3899    int err, irecno, flags=0;
3900    db_recno_t recno;
3901    DBT key, data;
3902    PyObject* retval;
3903    int dlen = -1;
3904    int doff = -1;
3905    static char* kwnames[] = { "recno","flags", "dlen", "doff", NULL };
3906
3907    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii:set_recno", kwnames,
3908				     &irecno, &flags, &dlen, &doff))
3909      return NULL;
3910
3911    CHECK_CURSOR_NOT_CLOSED(self);
3912
3913    CLEAR_DBT(key);
3914    recno = (db_recno_t) irecno;
3915    /* use allocated space so DB will be able to realloc room for the real
3916     * key */
3917    key.data = malloc(sizeof(db_recno_t));
3918    if (key.data == NULL) {
3919        PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
3920        return NULL;
3921    }
3922    key.size = sizeof(db_recno_t);
3923    key.ulen = key.size;
3924    memcpy(key.data, &recno, sizeof(db_recno_t));
3925    key.flags = DB_DBT_REALLOC;
3926
3927    CLEAR_DBT(data);
3928    if (!add_partial_dbt(&data, dlen, doff)) {
3929        FREE_DBT(key);
3930        return NULL;
3931    }
3932
3933    MYDB_BEGIN_ALLOW_THREADS;
3934    err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
3935    MYDB_END_ALLOW_THREADS;
3936    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3937	    && self->mydb->moduleFlags.cursorSetReturnsNone) {
3938        Py_INCREF(Py_None);
3939        retval = Py_None;
3940    }
3941    else if (makeDBError(err)) {
3942        retval = NULL;
3943    }
3944    else {  /* Can only be used for BTrees, so no need to return int key */
3945        retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3946    }
3947    FREE_DBT(key);
3948
3949    return retval;
3950}
3951
3952
3953static PyObject*
3954DBC_consume(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3955{
3956    return _DBCursor_get(self,DB_CONSUME,args,kwargs,"|iii:consume");
3957}
3958
3959
3960static PyObject*
3961DBC_next_dup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3962{
3963    return _DBCursor_get(self,DB_NEXT_DUP,args,kwargs,"|iii:next_dup");
3964}
3965
3966
3967static PyObject*
3968DBC_next_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3969{
3970    return _DBCursor_get(self,DB_NEXT_NODUP,args,kwargs,"|iii:next_nodup");
3971}
3972
3973
3974static PyObject*
3975DBC_prev_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3976{
3977    return _DBCursor_get(self,DB_PREV_NODUP,args,kwargs,"|iii:prev_nodup");
3978}
3979
3980
3981static PyObject*
3982DBC_join_item(DBCursorObject* self, PyObject* args)
3983{
3984    int err, flags=0;
3985    DBT key, data;
3986    PyObject* retval;
3987
3988    if (!PyArg_ParseTuple(args, "|i:join_item", &flags))
3989        return NULL;
3990
3991    CHECK_CURSOR_NOT_CLOSED(self);
3992
3993    CLEAR_DBT(key);
3994    CLEAR_DBT(data);
3995
3996    MYDB_BEGIN_ALLOW_THREADS;
3997    err = _DBC_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
3998    MYDB_END_ALLOW_THREADS;
3999    if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
4000	    && self->mydb->moduleFlags.getReturnsNone) {
4001        Py_INCREF(Py_None);
4002        retval = Py_None;
4003    }
4004    else if (makeDBError(err)) {
4005        retval = NULL;
4006    }
4007    else {
4008        retval = BuildValue_S(key.data, key.size);
4009    }
4010
4011    return retval;
4012}
4013
4014
4015
4016/* --------------------------------------------------------------------- */
4017/* DBEnv methods */
4018
4019
4020static PyObject*
4021DBEnv_close_internal(DBEnvObject* self, int flags)
4022{
4023    PyObject *dummy;
4024    int err;
4025
4026    if (!self->closed) {      /* Don't close more than once */
4027        while(self->children_txns) {
4028          dummy=DBTxn_abort_discard_internal(self->children_txns,0);
4029          Py_XDECREF(dummy);
4030        }
4031        while(self->children_dbs) {
4032          dummy=DB_close_internal(self->children_dbs, 0, 0);
4033          Py_XDECREF(dummy);
4034        }
4035    }
4036
4037    self->closed = 1;
4038    if (self->db_env) {
4039        MYDB_BEGIN_ALLOW_THREADS;
4040        err = self->db_env->close(self->db_env, flags);
4041        MYDB_END_ALLOW_THREADS;
4042        /* after calling DBEnv->close, regardless of error, this DBEnv
4043         * may not be accessed again (Berkeley DB docs). */
4044        self->db_env = NULL;
4045        RETURN_IF_ERR();
4046    }
4047    RETURN_NONE();
4048}
4049
4050static PyObject*
4051DBEnv_close(DBEnvObject* self, PyObject* args)
4052{
4053    int flags = 0;
4054
4055    if (!PyArg_ParseTuple(args, "|i:close", &flags))
4056        return NULL;
4057    return DBEnv_close_internal(self, flags);
4058}
4059
4060
4061static PyObject*
4062DBEnv_open(DBEnvObject* self, PyObject* args)
4063{
4064    int err, flags=0, mode=0660;
4065    char *db_home;
4066
4067    if (!PyArg_ParseTuple(args, "z|ii:open", &db_home, &flags, &mode))
4068        return NULL;
4069
4070    CHECK_ENV_NOT_CLOSED(self);
4071
4072    MYDB_BEGIN_ALLOW_THREADS;
4073    err = self->db_env->open(self->db_env, db_home, flags, mode);
4074    MYDB_END_ALLOW_THREADS;
4075    RETURN_IF_ERR();
4076    self->closed = 0;
4077    self->flags = flags;
4078    RETURN_NONE();
4079}
4080
4081
4082static PyObject*
4083DBEnv_remove(DBEnvObject* self, PyObject* args)
4084{
4085    int err, flags=0;
4086    char *db_home;
4087
4088    if (!PyArg_ParseTuple(args, "s|i:remove", &db_home, &flags))
4089        return NULL;
4090    CHECK_ENV_NOT_CLOSED(self);
4091    MYDB_BEGIN_ALLOW_THREADS;
4092    err = self->db_env->remove(self->db_env, db_home, flags);
4093    MYDB_END_ALLOW_THREADS;
4094    RETURN_IF_ERR();
4095    RETURN_NONE();
4096}
4097
4098#if (DBVER >= 41)
4099static PyObject*
4100DBEnv_dbremove(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4101{
4102    int err;
4103    u_int32_t flags=0;
4104    char *file = NULL;
4105    char *database = NULL;
4106    PyObject *txnobj = NULL;
4107    DB_TXN *txn = NULL;
4108    static char* kwnames[] = { "file", "database", "txn", "flags",
4109                                     NULL };
4110
4111    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zOi:dbremove", kwnames,
4112		&file, &database, &txnobj, &flags)) {
4113	return NULL;
4114    }
4115    if (!checkTxnObj(txnobj, &txn)) {
4116        return NULL;
4117    }
4118    CHECK_ENV_NOT_CLOSED(self);
4119    MYDB_BEGIN_ALLOW_THREADS;
4120    err = self->db_env->dbremove(self->db_env, txn, file, database, flags);
4121    MYDB_END_ALLOW_THREADS;
4122    RETURN_IF_ERR();
4123    RETURN_NONE();
4124}
4125
4126static PyObject*
4127DBEnv_dbrename(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4128{
4129    int err;
4130    u_int32_t flags=0;
4131    char *file = NULL;
4132    char *database = NULL;
4133    char *newname = NULL;
4134    PyObject *txnobj = NULL;
4135    DB_TXN *txn = NULL;
4136    static char* kwnames[] = { "file", "database", "newname", "txn",
4137                                     "flags", NULL };
4138
4139    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "szs|Oi:dbrename", kwnames,
4140		&file, &database, &newname, &txnobj, &flags)) {
4141	return NULL;
4142    }
4143    if (!checkTxnObj(txnobj, &txn)) {
4144        return NULL;
4145    }
4146    CHECK_ENV_NOT_CLOSED(self);
4147    MYDB_BEGIN_ALLOW_THREADS;
4148    err = self->db_env->dbrename(self->db_env, txn, file, database, newname,
4149                                 flags);
4150    MYDB_END_ALLOW_THREADS;
4151    RETURN_IF_ERR();
4152    RETURN_NONE();
4153}
4154
4155static PyObject*
4156DBEnv_set_encrypt(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4157{
4158    int err;
4159    u_int32_t flags=0;
4160    char *passwd = NULL;
4161    static char* kwnames[] = { "passwd", "flags", NULL };
4162
4163    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames,
4164		&passwd, &flags)) {
4165	return NULL;
4166    }
4167
4168    MYDB_BEGIN_ALLOW_THREADS;
4169    err = self->db_env->set_encrypt(self->db_env, passwd, flags);
4170    MYDB_END_ALLOW_THREADS;
4171
4172    RETURN_IF_ERR();
4173    RETURN_NONE();
4174}
4175#endif /* DBVER >= 41 */
4176
4177static PyObject*
4178DBEnv_set_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4179{
4180    int err;
4181    u_int32_t flags=0;
4182    u_int32_t timeout = 0;
4183    static char* kwnames[] = { "timeout", "flags", NULL };
4184
4185    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames,
4186		&timeout, &flags)) {
4187	return NULL;
4188    }
4189
4190    MYDB_BEGIN_ALLOW_THREADS;
4191    err = self->db_env->set_timeout(self->db_env, (db_timeout_t)timeout, flags);
4192    MYDB_END_ALLOW_THREADS;
4193
4194    RETURN_IF_ERR();
4195    RETURN_NONE();
4196}
4197
4198static PyObject*
4199DBEnv_set_shm_key(DBEnvObject* self, PyObject* args)
4200{
4201    int err;
4202    long shm_key = 0;
4203
4204    if (!PyArg_ParseTuple(args, "l:set_shm_key", &shm_key))
4205        return NULL;
4206    CHECK_ENV_NOT_CLOSED(self);
4207
4208    err = self->db_env->set_shm_key(self->db_env, shm_key);
4209    RETURN_IF_ERR();
4210    RETURN_NONE();
4211}
4212
4213static PyObject*
4214DBEnv_set_cachesize(DBEnvObject* self, PyObject* args)
4215{
4216    int err, gbytes=0, bytes=0, ncache=0;
4217
4218    if (!PyArg_ParseTuple(args, "ii|i:set_cachesize",
4219                          &gbytes, &bytes, &ncache))
4220        return NULL;
4221    CHECK_ENV_NOT_CLOSED(self);
4222
4223    MYDB_BEGIN_ALLOW_THREADS;
4224    err = self->db_env->set_cachesize(self->db_env, gbytes, bytes, ncache);
4225    MYDB_END_ALLOW_THREADS;
4226    RETURN_IF_ERR();
4227    RETURN_NONE();
4228}
4229
4230
4231static PyObject*
4232DBEnv_set_flags(DBEnvObject* self, PyObject* args)
4233{
4234    int err, flags=0, onoff=0;
4235
4236    if (!PyArg_ParseTuple(args, "ii:set_flags",
4237                          &flags, &onoff))
4238        return NULL;
4239    CHECK_ENV_NOT_CLOSED(self);
4240
4241    MYDB_BEGIN_ALLOW_THREADS;
4242    err = self->db_env->set_flags(self->db_env, flags, onoff);
4243    MYDB_END_ALLOW_THREADS;
4244    RETURN_IF_ERR();
4245    RETURN_NONE();
4246}
4247
4248
4249#if (DBVER >= 47)
4250static PyObject*
4251DBEnv_log_set_config(DBEnvObject* self, PyObject* args)
4252{
4253    int err, flags, onoff;
4254
4255    if (!PyArg_ParseTuple(args, "ii:log_set_config",
4256                          &flags, &onoff))
4257        return NULL;
4258    CHECK_ENV_NOT_CLOSED(self);
4259
4260    MYDB_BEGIN_ALLOW_THREADS;
4261    err = self->db_env->log_set_config(self->db_env, flags, onoff);
4262    MYDB_END_ALLOW_THREADS;
4263    RETURN_IF_ERR();
4264    RETURN_NONE();
4265}
4266#endif /* DBVER >= 47 */
4267
4268
4269static PyObject*
4270DBEnv_set_data_dir(DBEnvObject* self, PyObject* args)
4271{
4272    int err;
4273    char *dir;
4274
4275    if (!PyArg_ParseTuple(args, "s:set_data_dir", &dir))
4276        return NULL;
4277    CHECK_ENV_NOT_CLOSED(self);
4278
4279    MYDB_BEGIN_ALLOW_THREADS;
4280    err = self->db_env->set_data_dir(self->db_env, dir);
4281    MYDB_END_ALLOW_THREADS;
4282    RETURN_IF_ERR();
4283    RETURN_NONE();
4284}
4285
4286
4287static PyObject*
4288DBEnv_set_lg_bsize(DBEnvObject* self, PyObject* args)
4289{
4290    int err, lg_bsize;
4291
4292    if (!PyArg_ParseTuple(args, "i:set_lg_bsize", &lg_bsize))
4293        return NULL;
4294    CHECK_ENV_NOT_CLOSED(self);
4295
4296    MYDB_BEGIN_ALLOW_THREADS;
4297    err = self->db_env->set_lg_bsize(self->db_env, lg_bsize);
4298    MYDB_END_ALLOW_THREADS;
4299    RETURN_IF_ERR();
4300    RETURN_NONE();
4301}
4302
4303
4304static PyObject*
4305DBEnv_set_lg_dir(DBEnvObject* self, PyObject* args)
4306{
4307    int err;
4308    char *dir;
4309
4310    if (!PyArg_ParseTuple(args, "s:set_lg_dir", &dir))
4311        return NULL;
4312    CHECK_ENV_NOT_CLOSED(self);
4313
4314    MYDB_BEGIN_ALLOW_THREADS;
4315    err = self->db_env->set_lg_dir(self->db_env, dir);
4316    MYDB_END_ALLOW_THREADS;
4317    RETURN_IF_ERR();
4318    RETURN_NONE();
4319}
4320
4321static PyObject*
4322DBEnv_set_lg_max(DBEnvObject* self, PyObject* args)
4323{
4324    int err, lg_max;
4325
4326    if (!PyArg_ParseTuple(args, "i:set_lg_max", &lg_max))
4327        return NULL;
4328    CHECK_ENV_NOT_CLOSED(self);
4329
4330    MYDB_BEGIN_ALLOW_THREADS;
4331    err = self->db_env->set_lg_max(self->db_env, lg_max);
4332    MYDB_END_ALLOW_THREADS;
4333    RETURN_IF_ERR();
4334    RETURN_NONE();
4335}
4336
4337#if (DBVER >= 42)
4338static PyObject*
4339DBEnv_get_lg_max(DBEnvObject* self)
4340{
4341    int err;
4342    u_int32_t lg_max;
4343
4344    CHECK_ENV_NOT_CLOSED(self);
4345
4346    MYDB_BEGIN_ALLOW_THREADS;
4347    err = self->db_env->get_lg_max(self->db_env, &lg_max);
4348    MYDB_END_ALLOW_THREADS;
4349    RETURN_IF_ERR();
4350    return NUMBER_FromLong(lg_max);
4351}
4352#endif
4353
4354
4355static PyObject*
4356DBEnv_set_lg_regionmax(DBEnvObject* self, PyObject* args)
4357{
4358    int err, lg_max;
4359
4360    if (!PyArg_ParseTuple(args, "i:set_lg_regionmax", &lg_max))
4361        return NULL;
4362    CHECK_ENV_NOT_CLOSED(self);
4363
4364    MYDB_BEGIN_ALLOW_THREADS;
4365    err = self->db_env->set_lg_regionmax(self->db_env, lg_max);
4366    MYDB_END_ALLOW_THREADS;
4367    RETURN_IF_ERR();
4368    RETURN_NONE();
4369}
4370
4371
4372static PyObject*
4373DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args)
4374{
4375    int err, lk_detect;
4376
4377    if (!PyArg_ParseTuple(args, "i:set_lk_detect", &lk_detect))
4378        return NULL;
4379    CHECK_ENV_NOT_CLOSED(self);
4380
4381    MYDB_BEGIN_ALLOW_THREADS;
4382    err = self->db_env->set_lk_detect(self->db_env, lk_detect);
4383    MYDB_END_ALLOW_THREADS;
4384    RETURN_IF_ERR();
4385    RETURN_NONE();
4386}
4387
4388
4389#if (DBVER < 45)
4390static PyObject*
4391DBEnv_set_lk_max(DBEnvObject* self, PyObject* args)
4392{
4393    int err, max;
4394
4395    if (!PyArg_ParseTuple(args, "i:set_lk_max", &max))
4396        return NULL;
4397    CHECK_ENV_NOT_CLOSED(self);
4398
4399    MYDB_BEGIN_ALLOW_THREADS;
4400    err = self->db_env->set_lk_max(self->db_env, max);
4401    MYDB_END_ALLOW_THREADS;
4402    RETURN_IF_ERR();
4403    RETURN_NONE();
4404}
4405#endif
4406
4407
4408
4409static PyObject*
4410DBEnv_set_lk_max_locks(DBEnvObject* self, PyObject* args)
4411{
4412    int err, max;
4413
4414    if (!PyArg_ParseTuple(args, "i:set_lk_max_locks", &max))
4415        return NULL;
4416    CHECK_ENV_NOT_CLOSED(self);
4417
4418    MYDB_BEGIN_ALLOW_THREADS;
4419    err = self->db_env->set_lk_max_locks(self->db_env, max);
4420    MYDB_END_ALLOW_THREADS;
4421    RETURN_IF_ERR();
4422    RETURN_NONE();
4423}
4424
4425
4426static PyObject*
4427DBEnv_set_lk_max_lockers(DBEnvObject* self, PyObject* args)
4428{
4429    int err, max;
4430
4431    if (!PyArg_ParseTuple(args, "i:set_lk_max_lockers", &max))
4432        return NULL;
4433    CHECK_ENV_NOT_CLOSED(self);
4434
4435    MYDB_BEGIN_ALLOW_THREADS;
4436    err = self->db_env->set_lk_max_lockers(self->db_env, max);
4437    MYDB_END_ALLOW_THREADS;
4438    RETURN_IF_ERR();
4439    RETURN_NONE();
4440}
4441
4442
4443static PyObject*
4444DBEnv_set_lk_max_objects(DBEnvObject* self, PyObject* args)
4445{
4446    int err, max;
4447
4448    if (!PyArg_ParseTuple(args, "i:set_lk_max_objects", &max))
4449        return NULL;
4450    CHECK_ENV_NOT_CLOSED(self);
4451
4452    MYDB_BEGIN_ALLOW_THREADS;
4453    err = self->db_env->set_lk_max_objects(self->db_env, max);
4454    MYDB_END_ALLOW_THREADS;
4455    RETURN_IF_ERR();
4456    RETURN_NONE();
4457}
4458
4459
4460static PyObject*
4461DBEnv_set_mp_mmapsize(DBEnvObject* self, PyObject* args)
4462{
4463    int err, mp_mmapsize;
4464
4465    if (!PyArg_ParseTuple(args, "i:set_mp_mmapsize", &mp_mmapsize))
4466        return NULL;
4467    CHECK_ENV_NOT_CLOSED(self);
4468
4469    MYDB_BEGIN_ALLOW_THREADS;
4470    err = self->db_env->set_mp_mmapsize(self->db_env, mp_mmapsize);
4471    MYDB_END_ALLOW_THREADS;
4472    RETURN_IF_ERR();
4473    RETURN_NONE();
4474}
4475
4476
4477static PyObject*
4478DBEnv_set_tmp_dir(DBEnvObject* self, PyObject* args)
4479{
4480    int err;
4481    char *dir;
4482
4483    if (!PyArg_ParseTuple(args, "s:set_tmp_dir", &dir))
4484        return NULL;
4485    CHECK_ENV_NOT_CLOSED(self);
4486
4487    MYDB_BEGIN_ALLOW_THREADS;
4488    err = self->db_env->set_tmp_dir(self->db_env, dir);
4489    MYDB_END_ALLOW_THREADS;
4490    RETURN_IF_ERR();
4491    RETURN_NONE();
4492}
4493
4494
4495static PyObject*
4496DBEnv_txn_recover(DBEnvObject* self)
4497{
4498    int flags = DB_FIRST;
4499    int err, i;
4500    PyObject *list, *tuple, *gid;
4501    DBTxnObject *txn;
4502#define PREPLIST_LEN 16
4503    DB_PREPLIST preplist[PREPLIST_LEN];
4504    long retp;
4505
4506    CHECK_ENV_NOT_CLOSED(self);
4507
4508    list=PyList_New(0);
4509    if (!list)
4510        return NULL;
4511    while (!0) {
4512        MYDB_BEGIN_ALLOW_THREADS
4513        err=self->db_env->txn_recover(self->db_env,
4514                        preplist, PREPLIST_LEN, &retp, flags);
4515#undef PREPLIST_LEN
4516        MYDB_END_ALLOW_THREADS
4517        if (err) {
4518            Py_DECREF(list);
4519            RETURN_IF_ERR();
4520        }
4521        if (!retp) break;
4522        flags=DB_NEXT;  /* Prepare for next loop pass */
4523        for (i=0; i<retp; i++) {
4524            gid=PyBytes_FromStringAndSize((char *)(preplist[i].gid),
4525                                DB_XIDDATASIZE);
4526            if (!gid) {
4527                Py_DECREF(list);
4528                return NULL;
4529            }
4530            txn=newDBTxnObject(self, NULL, preplist[i].txn, flags);
4531            if (!txn) {
4532                Py_DECREF(list);
4533                Py_DECREF(gid);
4534                return NULL;
4535            }
4536            txn->flag_prepare=1;  /* Recover state */
4537            tuple=PyTuple_New(2);
4538            if (!tuple) {
4539                Py_DECREF(list);
4540                Py_DECREF(gid);
4541                Py_DECREF(txn);
4542                return NULL;
4543            }
4544            if (PyTuple_SetItem(tuple, 0, gid)) {
4545                Py_DECREF(list);
4546                Py_DECREF(gid);
4547                Py_DECREF(txn);
4548                Py_DECREF(tuple);
4549                return NULL;
4550            }
4551            if (PyTuple_SetItem(tuple, 1, (PyObject *)txn)) {
4552                Py_DECREF(list);
4553                Py_DECREF(txn);
4554                Py_DECREF(tuple); /* This delete the "gid" also */
4555                return NULL;
4556            }
4557            if (PyList_Append(list, tuple)) {
4558                Py_DECREF(list);
4559                Py_DECREF(tuple);/* This delete the "gid" and the "txn" also */
4560                return NULL;
4561            }
4562            Py_DECREF(tuple);
4563        }
4564    }
4565    return list;
4566}
4567
4568static PyObject*
4569DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4570{
4571    int flags = 0;
4572    PyObject* txnobj = NULL;
4573    DB_TXN *txn = NULL;
4574    static char* kwnames[] = { "parent", "flags", NULL };
4575
4576    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:txn_begin", kwnames,
4577                                     &txnobj, &flags))
4578        return NULL;
4579
4580    if (!checkTxnObj(txnobj, &txn))
4581        return NULL;
4582    CHECK_ENV_NOT_CLOSED(self);
4583
4584    return (PyObject*)newDBTxnObject(self, (DBTxnObject *)txnobj, NULL, flags);
4585}
4586
4587
4588static PyObject*
4589DBEnv_txn_checkpoint(DBEnvObject* self, PyObject* args)
4590{
4591    int err, kbyte=0, min=0, flags=0;
4592
4593    if (!PyArg_ParseTuple(args, "|iii:txn_checkpoint", &kbyte, &min, &flags))
4594        return NULL;
4595    CHECK_ENV_NOT_CLOSED(self);
4596
4597    MYDB_BEGIN_ALLOW_THREADS;
4598    err = self->db_env->txn_checkpoint(self->db_env, kbyte, min, flags);
4599    MYDB_END_ALLOW_THREADS;
4600    RETURN_IF_ERR();
4601    RETURN_NONE();
4602}
4603
4604
4605static PyObject*
4606DBEnv_set_tx_max(DBEnvObject* self, PyObject* args)
4607{
4608    int err, max;
4609
4610    if (!PyArg_ParseTuple(args, "i:set_tx_max", &max))
4611        return NULL;
4612    CHECK_ENV_NOT_CLOSED(self);
4613
4614    err = self->db_env->set_tx_max(self->db_env, max);
4615    RETURN_IF_ERR();
4616    RETURN_NONE();
4617}
4618
4619
4620static PyObject*
4621DBEnv_set_tx_timestamp(DBEnvObject* self, PyObject* args)
4622{
4623    int err;
4624    long stamp;
4625    time_t timestamp;
4626
4627    if (!PyArg_ParseTuple(args, "l:set_tx_timestamp", &stamp))
4628        return NULL;
4629    CHECK_ENV_NOT_CLOSED(self);
4630    timestamp = (time_t)stamp;
4631    err = self->db_env->set_tx_timestamp(self->db_env, &timestamp);
4632    RETURN_IF_ERR();
4633    RETURN_NONE();
4634}
4635
4636
4637static PyObject*
4638DBEnv_lock_detect(DBEnvObject* self, PyObject* args)
4639{
4640    int err, atype, flags=0;
4641    int aborted = 0;
4642
4643    if (!PyArg_ParseTuple(args, "i|i:lock_detect", &atype, &flags))
4644        return NULL;
4645    CHECK_ENV_NOT_CLOSED(self);
4646
4647    MYDB_BEGIN_ALLOW_THREADS;
4648    err = self->db_env->lock_detect(self->db_env, flags, atype, &aborted);
4649    MYDB_END_ALLOW_THREADS;
4650    RETURN_IF_ERR();
4651    return NUMBER_FromLong(aborted);
4652}
4653
4654
4655static PyObject*
4656DBEnv_lock_get(DBEnvObject* self, PyObject* args)
4657{
4658    int flags=0;
4659    int locker, lock_mode;
4660    DBT obj;
4661    PyObject* objobj;
4662
4663    if (!PyArg_ParseTuple(args, "iOi|i:lock_get", &locker, &objobj, &lock_mode, &flags))
4664        return NULL;
4665
4666
4667    if (!make_dbt(objobj, &obj))
4668        return NULL;
4669
4670    return (PyObject*)newDBLockObject(self, locker, &obj, lock_mode, flags);
4671}
4672
4673
4674static PyObject*
4675DBEnv_lock_id(DBEnvObject* self)
4676{
4677    int err;
4678    u_int32_t theID;
4679
4680    CHECK_ENV_NOT_CLOSED(self);
4681    MYDB_BEGIN_ALLOW_THREADS;
4682    err = self->db_env->lock_id(self->db_env, &theID);
4683    MYDB_END_ALLOW_THREADS;
4684    RETURN_IF_ERR();
4685
4686    return NUMBER_FromLong((long)theID);
4687}
4688
4689static PyObject*
4690DBEnv_lock_id_free(DBEnvObject* self, PyObject* args)
4691{
4692    int err;
4693    u_int32_t theID;
4694
4695    if (!PyArg_ParseTuple(args, "I:lock_id_free", &theID))
4696        return NULL;
4697
4698    CHECK_ENV_NOT_CLOSED(self);
4699    MYDB_BEGIN_ALLOW_THREADS;
4700    err = self->db_env->lock_id_free(self->db_env, theID);
4701    MYDB_END_ALLOW_THREADS;
4702    RETURN_IF_ERR();
4703    RETURN_NONE();
4704}
4705
4706static PyObject*
4707DBEnv_lock_put(DBEnvObject* self, PyObject* args)
4708{
4709    int err;
4710    DBLockObject* dblockobj;
4711
4712    if (!PyArg_ParseTuple(args, "O!:lock_put", &DBLock_Type, &dblockobj))
4713        return NULL;
4714
4715    CHECK_ENV_NOT_CLOSED(self);
4716    MYDB_BEGIN_ALLOW_THREADS;
4717    err = self->db_env->lock_put(self->db_env, &dblockobj->lock);
4718    MYDB_END_ALLOW_THREADS;
4719    RETURN_IF_ERR();
4720    RETURN_NONE();
4721}
4722
4723#if (DBVER >= 44)
4724static PyObject*
4725DBEnv_lsn_reset(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4726{
4727    int err;
4728    char *file;
4729    u_int32_t flags = 0;
4730    static char* kwnames[] = { "file", "flags", NULL};
4731
4732    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|i:lsn_reset", kwnames,
4733                                     &file, &flags))
4734        return NULL;
4735    CHECK_ENV_NOT_CLOSED(self);
4736
4737    MYDB_BEGIN_ALLOW_THREADS;
4738    err = self->db_env->lsn_reset(self->db_env, file, flags);
4739    MYDB_END_ALLOW_THREADS;
4740    RETURN_IF_ERR();
4741    RETURN_NONE();
4742}
4743#endif /* DBVER >= 4.4 */
4744
4745static PyObject*
4746DBEnv_log_stat(DBEnvObject* self, PyObject* args)
4747{
4748    int err;
4749    DB_LOG_STAT* statp = NULL;
4750    PyObject* d = NULL;
4751    u_int32_t flags = 0;
4752
4753    if (!PyArg_ParseTuple(args, "|i:log_stat", &flags))
4754        return NULL;
4755    CHECK_ENV_NOT_CLOSED(self);
4756
4757    MYDB_BEGIN_ALLOW_THREADS;
4758    err = self->db_env->log_stat(self->db_env, &statp, flags);
4759    MYDB_END_ALLOW_THREADS;
4760    RETURN_IF_ERR();
4761
4762    /* Turn the stat structure into a dictionary */
4763    d = PyDict_New();
4764    if (d == NULL) {
4765        if (statp)
4766            free(statp);
4767        return NULL;
4768    }
4769
4770#define MAKE_ENTRY(name)  _addIntToDict(d, #name, statp->st_##name)
4771
4772    MAKE_ENTRY(magic);
4773    MAKE_ENTRY(version);
4774    MAKE_ENTRY(mode);
4775    MAKE_ENTRY(lg_bsize);
4776#if (DBVER >= 44)
4777    MAKE_ENTRY(lg_size);
4778    MAKE_ENTRY(record);
4779#endif
4780#if (DBVER < 41)
4781    MAKE_ENTRY(lg_max);
4782#endif
4783    MAKE_ENTRY(w_mbytes);
4784    MAKE_ENTRY(w_bytes);
4785    MAKE_ENTRY(wc_mbytes);
4786    MAKE_ENTRY(wc_bytes);
4787    MAKE_ENTRY(wcount);
4788    MAKE_ENTRY(wcount_fill);
4789#if (DBVER >= 44)
4790    MAKE_ENTRY(rcount);
4791#endif
4792    MAKE_ENTRY(scount);
4793    MAKE_ENTRY(cur_file);
4794    MAKE_ENTRY(cur_offset);
4795    MAKE_ENTRY(disk_file);
4796    MAKE_ENTRY(disk_offset);
4797    MAKE_ENTRY(maxcommitperflush);
4798    MAKE_ENTRY(mincommitperflush);
4799    MAKE_ENTRY(regsize);
4800    MAKE_ENTRY(region_wait);
4801    MAKE_ENTRY(region_nowait);
4802
4803#undef MAKE_ENTRY
4804    free(statp);
4805    return d;
4806} /* DBEnv_log_stat */
4807
4808
4809static PyObject*
4810DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
4811{
4812    int err;
4813    DB_LOCK_STAT* sp;
4814    PyObject* d = NULL;
4815    u_int32_t flags = 0;
4816
4817    if (!PyArg_ParseTuple(args, "|i:lock_stat", &flags))
4818        return NULL;
4819    CHECK_ENV_NOT_CLOSED(self);
4820
4821    MYDB_BEGIN_ALLOW_THREADS;
4822    err = self->db_env->lock_stat(self->db_env, &sp, flags);
4823    MYDB_END_ALLOW_THREADS;
4824    RETURN_IF_ERR();
4825
4826    /* Turn the stat structure into a dictionary */
4827    d = PyDict_New();
4828    if (d == NULL) {
4829        free(sp);
4830        return NULL;
4831    }
4832
4833#define MAKE_ENTRY(name)  _addIntToDict(d, #name, sp->st_##name)
4834
4835#if (DBVER < 41)
4836    MAKE_ENTRY(lastid);
4837#endif
4838#if (DBVER >=41)
4839    MAKE_ENTRY(id);
4840    MAKE_ENTRY(cur_maxid);
4841#endif
4842    MAKE_ENTRY(nmodes);
4843    MAKE_ENTRY(maxlocks);
4844    MAKE_ENTRY(maxlockers);
4845    MAKE_ENTRY(maxobjects);
4846    MAKE_ENTRY(nlocks);
4847    MAKE_ENTRY(maxnlocks);
4848    MAKE_ENTRY(nlockers);
4849    MAKE_ENTRY(maxnlockers);
4850    MAKE_ENTRY(nobjects);
4851    MAKE_ENTRY(maxnobjects);
4852    MAKE_ENTRY(nrequests);
4853    MAKE_ENTRY(nreleases);
4854#if (DBVER >= 44)
4855    MAKE_ENTRY(nupgrade);
4856    MAKE_ENTRY(ndowngrade);
4857#endif
4858#if (DBVER < 44)
4859    MAKE_ENTRY(nnowaits);       /* these were renamed in 4.4 */
4860    MAKE_ENTRY(nconflicts);
4861#else
4862    MAKE_ENTRY(lock_nowait);
4863    MAKE_ENTRY(lock_wait);
4864#endif
4865    MAKE_ENTRY(ndeadlocks);
4866#if (DBVER >= 41)
4867    MAKE_ENTRY(locktimeout);
4868    MAKE_ENTRY(txntimeout);
4869#endif
4870    MAKE_ENTRY(nlocktimeouts);
4871    MAKE_ENTRY(ntxntimeouts);
4872#if (DBVER >= 46)
4873    MAKE_ENTRY(objs_wait);
4874    MAKE_ENTRY(objs_nowait);
4875    MAKE_ENTRY(lockers_wait);
4876    MAKE_ENTRY(lockers_nowait);
4877#if (DBVER >= 47)
4878    MAKE_ENTRY(lock_wait);
4879    MAKE_ENTRY(lock_nowait);
4880#else
4881    MAKE_ENTRY(locks_wait);
4882    MAKE_ENTRY(locks_nowait);
4883#endif
4884    MAKE_ENTRY(hash_len);
4885#endif
4886    MAKE_ENTRY(regsize);
4887    MAKE_ENTRY(region_wait);
4888    MAKE_ENTRY(region_nowait);
4889
4890#undef MAKE_ENTRY
4891    free(sp);
4892    return d;
4893}
4894
4895static PyObject*
4896DBEnv_log_flush(DBEnvObject* self)
4897{
4898    int err;
4899
4900    CHECK_ENV_NOT_CLOSED(self);
4901
4902    MYDB_BEGIN_ALLOW_THREADS
4903    err = self->db_env->log_flush(self->db_env, NULL);
4904    MYDB_END_ALLOW_THREADS
4905
4906    RETURN_IF_ERR();
4907    RETURN_NONE();
4908}
4909
4910static PyObject*
4911DBEnv_log_archive(DBEnvObject* self, PyObject* args)
4912{
4913    int flags=0;
4914    int err;
4915    char **log_list = NULL;
4916    PyObject* list;
4917    PyObject* item = NULL;
4918
4919    if (!PyArg_ParseTuple(args, "|i:log_archive", &flags))
4920        return NULL;
4921
4922    CHECK_ENV_NOT_CLOSED(self);
4923    MYDB_BEGIN_ALLOW_THREADS;
4924    err = self->db_env->log_archive(self->db_env, &log_list, flags);
4925    MYDB_END_ALLOW_THREADS;
4926    RETURN_IF_ERR();
4927
4928    list = PyList_New(0);
4929    if (list == NULL) {
4930        if (log_list)
4931            free(log_list);
4932        return NULL;
4933    }
4934
4935    if (log_list) {
4936        char **log_list_start;
4937        for (log_list_start = log_list; *log_list != NULL; ++log_list) {
4938            item = PyBytes_FromString (*log_list);
4939            if (item == NULL) {
4940                Py_DECREF(list);
4941                list = NULL;
4942                break;
4943            }
4944            if (PyList_Append(list, item)) {
4945                Py_DECREF(list);
4946                list = NULL;
4947                Py_DECREF(item);
4948                break;
4949            }
4950            Py_DECREF(item);
4951        }
4952        free(log_list_start);
4953    }
4954    return list;
4955}
4956
4957
4958static PyObject*
4959DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
4960{
4961    int err;
4962    DB_TXN_STAT* sp;
4963    PyObject* d = NULL;
4964    u_int32_t flags=0;
4965
4966    if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
4967        return NULL;
4968    CHECK_ENV_NOT_CLOSED(self);
4969
4970    MYDB_BEGIN_ALLOW_THREADS;
4971    err = self->db_env->txn_stat(self->db_env, &sp, flags);
4972    MYDB_END_ALLOW_THREADS;
4973    RETURN_IF_ERR();
4974
4975    /* Turn the stat structure into a dictionary */
4976    d = PyDict_New();
4977    if (d == NULL) {
4978        free(sp);
4979        return NULL;
4980    }
4981
4982#define MAKE_ENTRY(name)        _addIntToDict(d, #name, sp->st_##name)
4983#define MAKE_TIME_T_ENTRY(name) _addTimeTToDict(d, #name, sp->st_##name)
4984#define MAKE_DB_LSN_ENTRY(name) _addDB_lsnToDict(d, #name, sp->st_##name)
4985
4986    MAKE_DB_LSN_ENTRY(last_ckp);
4987    MAKE_TIME_T_ENTRY(time_ckp);
4988    MAKE_ENTRY(last_txnid);
4989    MAKE_ENTRY(maxtxns);
4990    MAKE_ENTRY(nactive);
4991    MAKE_ENTRY(maxnactive);
4992#if (DBVER >= 45)
4993    MAKE_ENTRY(nsnapshot);
4994    MAKE_ENTRY(maxnsnapshot);
4995#endif
4996    MAKE_ENTRY(nbegins);
4997    MAKE_ENTRY(naborts);
4998    MAKE_ENTRY(ncommits);
4999    MAKE_ENTRY(nrestores);
5000    MAKE_ENTRY(regsize);
5001    MAKE_ENTRY(region_wait);
5002    MAKE_ENTRY(region_nowait);
5003
5004#undef MAKE_DB_LSN_ENTRY
5005#undef MAKE_ENTRY
5006#undef MAKE_TIME_T_ENTRY
5007    free(sp);
5008    return d;
5009}
5010
5011
5012static PyObject*
5013DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
5014{
5015    int flags=0;
5016    int oldValue=0;
5017
5018    if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
5019        return NULL;
5020    CHECK_ENV_NOT_CLOSED(self);
5021
5022    if (self->moduleFlags.getReturnsNone)
5023        ++oldValue;
5024    if (self->moduleFlags.cursorSetReturnsNone)
5025        ++oldValue;
5026    self->moduleFlags.getReturnsNone = (flags >= 1);
5027    self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
5028    return NUMBER_FromLong(oldValue);
5029}
5030
5031static PyObject*
5032DBEnv_get_private(DBEnvObject* self)
5033{
5034    /* We can give out the private field even if dbenv is closed */
5035    Py_INCREF(self->private_obj);
5036    return self->private_obj;
5037}
5038
5039static PyObject*
5040DBEnv_set_private(DBEnvObject* self, PyObject* private_obj)
5041{
5042    /* We can set the private field even if dbenv is closed */
5043    Py_DECREF(self->private_obj);
5044    Py_INCREF(private_obj);
5045    self->private_obj = private_obj;
5046    RETURN_NONE();
5047}
5048
5049
5050static PyObject*
5051DBEnv_set_rpc_server(DBEnvObject* self, PyObject* args, PyObject* kwargs)
5052{
5053    int err;
5054    char *host;
5055    long cl_timeout=0, sv_timeout=0;
5056
5057    static char* kwnames[] = { "host", "cl_timeout", "sv_timeout", NULL};
5058
5059    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ll:set_rpc_server", kwnames,
5060                                     &host, &cl_timeout, &sv_timeout))
5061        return NULL;
5062    CHECK_ENV_NOT_CLOSED(self);
5063
5064    MYDB_BEGIN_ALLOW_THREADS;
5065    err = self->db_env->set_rpc_server(self->db_env, NULL, host, cl_timeout,
5066            sv_timeout, 0);
5067    MYDB_END_ALLOW_THREADS;
5068    RETURN_IF_ERR();
5069    RETURN_NONE();
5070}
5071
5072static PyObject*
5073DBEnv_set_verbose(DBEnvObject* self, PyObject* args)
5074{
5075    int err;
5076    int which, onoff;
5077
5078    if (!PyArg_ParseTuple(args, "ii:set_verbose", &which, &onoff)) {
5079        return NULL;
5080    }
5081    CHECK_ENV_NOT_CLOSED(self);
5082    MYDB_BEGIN_ALLOW_THREADS;
5083    err = self->db_env->set_verbose(self->db_env, which, onoff);
5084    MYDB_END_ALLOW_THREADS;
5085    RETURN_IF_ERR();
5086    RETURN_NONE();
5087}
5088
5089#if (DBVER >= 42)
5090static PyObject*
5091DBEnv_get_verbose(DBEnvObject* self, PyObject* args)
5092{
5093    int err;
5094    int which;
5095    int verbose;
5096
5097    if (!PyArg_ParseTuple(args, "i:get_verbose", &which)) {
5098        return NULL;
5099    }
5100    CHECK_ENV_NOT_CLOSED(self);
5101    MYDB_BEGIN_ALLOW_THREADS;
5102    err = self->db_env->get_verbose(self->db_env, which, &verbose);
5103    MYDB_END_ALLOW_THREADS;
5104    RETURN_IF_ERR();
5105    return PyBool_FromLong(verbose);
5106}
5107#endif
5108
5109#if (DBVER >= 45)
5110static void
5111_dbenv_event_notifyCallback(DB_ENV* db_env, u_int32_t event, void *event_info)
5112{
5113    DBEnvObject *dbenv;
5114    PyObject* callback;
5115    PyObject* args;
5116    PyObject* result = NULL;
5117
5118    MYDB_BEGIN_BLOCK_THREADS;
5119    dbenv = (DBEnvObject *)db_env->app_private;
5120    callback = dbenv->event_notifyCallback;
5121    if (callback) {
5122        if (event == DB_EVENT_REP_NEWMASTER) {
5123            args = Py_BuildValue("(Oii)", dbenv, event, *((int *)event_info));
5124        } else {
5125            args = Py_BuildValue("(OiO)", dbenv, event, Py_None);
5126        }
5127        if (args) {
5128            result = PyEval_CallObject(callback, args);
5129        }
5130        if ((!args) || (!result)) {
5131            PyErr_Print();
5132        }
5133        Py_XDECREF(args);
5134        Py_XDECREF(result);
5135    }
5136    MYDB_END_BLOCK_THREADS;
5137}
5138#endif
5139
5140#if (DBVER >= 45)
5141static PyObject*
5142DBEnv_set_event_notify(DBEnvObject* self, PyObject* notifyFunc)
5143{
5144    int err;
5145
5146    CHECK_ENV_NOT_CLOSED(self);
5147
5148    if (!PyCallable_Check(notifyFunc)) {
5149	    makeTypeError("Callable", notifyFunc);
5150	    return NULL;
5151    }
5152
5153    Py_XDECREF(self->event_notifyCallback);
5154    Py_INCREF(notifyFunc);
5155    self->event_notifyCallback = notifyFunc;
5156
5157    /* This is to workaround a problem with un-initialized threads (see
5158       comment in DB_associate) */
5159#ifdef WITH_THREAD
5160    PyEval_InitThreads();
5161#endif
5162
5163    MYDB_BEGIN_ALLOW_THREADS;
5164    err = self->db_env->set_event_notify(self->db_env, _dbenv_event_notifyCallback);
5165    MYDB_END_ALLOW_THREADS;
5166
5167    if (err) {
5168	    Py_DECREF(notifyFunc);
5169	    self->event_notifyCallback = NULL;
5170    }
5171
5172    RETURN_IF_ERR();
5173    RETURN_NONE();
5174}
5175#endif
5176
5177
5178/* --------------------------------------------------------------------- */
5179/* REPLICATION METHODS: Base Replication */
5180
5181
5182static PyObject*
5183DBEnv_rep_process_message(DBEnvObject* self, PyObject* args)
5184{
5185    int err;
5186    PyObject *control_py, *rec_py;
5187    DBT control, rec;
5188    int envid;
5189#if (DBVER >= 42)
5190    DB_LSN lsn;
5191#endif
5192
5193    if (!PyArg_ParseTuple(args, "OOi:rep_process_message", &control_py,
5194                &rec_py, &envid))
5195        return NULL;
5196    CHECK_ENV_NOT_CLOSED(self);
5197
5198    if (!make_dbt(control_py, &control))
5199        return NULL;
5200    if (!make_dbt(rec_py, &rec))
5201        return NULL;
5202
5203    MYDB_BEGIN_ALLOW_THREADS;
5204#if (DBVER >= 46)
5205    err = self->db_env->rep_process_message(self->db_env, &control, &rec,
5206            envid, &lsn);
5207#else
5208#if (DBVER >= 42)
5209    err = self->db_env->rep_process_message(self->db_env, &control, &rec,
5210            &envid, &lsn);
5211#else
5212    err = self->db_env->rep_process_message(self->db_env, &control, &rec,
5213            &envid);
5214#endif
5215#endif
5216    MYDB_END_ALLOW_THREADS;
5217    switch (err) {
5218        case DB_REP_NEWMASTER :
5219          return Py_BuildValue("(iO)", envid, Py_None);
5220          break;
5221
5222        case DB_REP_DUPMASTER :
5223        case DB_REP_HOLDELECTION :
5224#if (DBVER >= 44)
5225        case DB_REP_IGNORE :
5226        case DB_REP_JOIN_FAILURE :
5227#endif
5228            return Py_BuildValue("(iO)", err, Py_None);
5229            break;
5230        case DB_REP_NEWSITE :
5231            {
5232                PyObject *tmp, *r;
5233
5234                if (!(tmp = PyBytes_FromStringAndSize(rec.data, rec.size))) {
5235                    return NULL;
5236                }
5237
5238                r = Py_BuildValue("(iO)", err, tmp);
5239                Py_DECREF(tmp);
5240                return r;
5241                break;
5242            }
5243#if (DBVER >= 42)
5244        case DB_REP_NOTPERM :
5245        case DB_REP_ISPERM :
5246            return Py_BuildValue("(i(ll))", err, lsn.file, lsn.offset);
5247            break;
5248#endif
5249    }
5250    RETURN_IF_ERR();
5251    return Py_BuildValue("(OO)", Py_None, Py_None);
5252}
5253
5254static int
5255_DBEnv_rep_transportCallback(DB_ENV* db_env, const DBT* control, const DBT* rec,
5256        const DB_LSN *lsn, int envid, u_int32_t flags)
5257{
5258    DBEnvObject *dbenv;
5259    PyObject* rep_transport;
5260    PyObject* args;
5261    PyObject *a, *b;
5262    PyObject* result = NULL;
5263    int ret=0;
5264
5265    MYDB_BEGIN_BLOCK_THREADS;
5266    dbenv = (DBEnvObject *)db_env->app_private;
5267    rep_transport = dbenv->rep_transport;
5268
5269    /*
5270    ** The errors in 'a' or 'b' are detected in "Py_BuildValue".
5271    */
5272    a = PyBytes_FromStringAndSize(control->data, control->size);
5273    b = PyBytes_FromStringAndSize(rec->data, rec->size);
5274
5275    args = Py_BuildValue(
5276#if (PY_VERSION_HEX >= 0x02040000)
5277            "(OOO(ll)iI)",
5278#else
5279            "(OOO(ll)ii)",
5280#endif
5281            dbenv,
5282            a, b,
5283            lsn->file, lsn->offset, envid, flags);
5284    if (args) {
5285        result = PyEval_CallObject(rep_transport, args);
5286    }
5287
5288    if ((!args) || (!result)) {
5289        PyErr_Print();
5290        ret = -1;
5291    }
5292    Py_XDECREF(a);
5293    Py_XDECREF(b);
5294    Py_XDECREF(args);
5295    Py_XDECREF(result);
5296    MYDB_END_BLOCK_THREADS;
5297    return ret;
5298}
5299
5300#if (DBVER <= 41)
5301static int
5302_DBEnv_rep_transportCallbackOLD(DB_ENV* db_env, const DBT* control, const DBT* rec,
5303        int envid, u_int32_t flags)
5304{
5305    DB_LSN lsn;
5306
5307    lsn.file = -1;  /* Dummy values */
5308    lsn.offset = -1;
5309    return _DBEnv_rep_transportCallback(db_env, control, rec, &lsn, envid,
5310            flags);
5311}
5312#endif
5313
5314static PyObject*
5315DBEnv_rep_set_transport(DBEnvObject* self, PyObject* args)
5316{
5317    int err;
5318    int envid;
5319    PyObject *rep_transport;
5320
5321    if (!PyArg_ParseTuple(args, "iO:rep_set_transport", &envid, &rep_transport))
5322        return NULL;
5323    CHECK_ENV_NOT_CLOSED(self);
5324    if (!PyCallable_Check(rep_transport)) {
5325        makeTypeError("Callable", rep_transport);
5326        return NULL;
5327    }
5328
5329    MYDB_BEGIN_ALLOW_THREADS;
5330#if (DBVER >=45)
5331    err = self->db_env->rep_set_transport(self->db_env, envid,
5332            &_DBEnv_rep_transportCallback);
5333#else
5334#if (DBVER >= 42)
5335    err = self->db_env->set_rep_transport(self->db_env, envid,
5336            &_DBEnv_rep_transportCallback);
5337#else
5338    err = self->db_env->set_rep_transport(self->db_env, envid,
5339            &_DBEnv_rep_transportCallbackOLD);
5340#endif
5341#endif
5342    MYDB_END_ALLOW_THREADS;
5343    RETURN_IF_ERR();
5344
5345    Py_DECREF(self->rep_transport);
5346    Py_INCREF(rep_transport);
5347    self->rep_transport = rep_transport;
5348    RETURN_NONE();
5349}
5350
5351#if (DBVER >= 47)
5352static PyObject*
5353DBEnv_rep_set_request(DBEnvObject* self, PyObject* args)
5354{
5355    int err;
5356    unsigned int minimum, maximum;
5357
5358    if (!PyArg_ParseTuple(args,"II:rep_set_request", &minimum, &maximum))
5359        return NULL;
5360    CHECK_ENV_NOT_CLOSED(self);
5361
5362    MYDB_BEGIN_ALLOW_THREADS;
5363    err = self->db_env->rep_set_request(self->db_env, minimum, maximum);
5364    MYDB_END_ALLOW_THREADS;
5365    RETURN_IF_ERR();
5366    RETURN_NONE();
5367}
5368
5369static PyObject*
5370DBEnv_rep_get_request(DBEnvObject* self)
5371{
5372    int err;
5373    u_int32_t minimum, maximum;
5374
5375    CHECK_ENV_NOT_CLOSED(self);
5376    MYDB_BEGIN_ALLOW_THREADS;
5377    err = self->db_env->rep_get_request(self->db_env, &minimum, &maximum);
5378    MYDB_END_ALLOW_THREADS;
5379    RETURN_IF_ERR();
5380#if (PY_VERSION_HEX >= 0x02040000)
5381    return Py_BuildValue("II", minimum, maximum);
5382#else
5383    return Py_BuildValue("ii", minimum, maximum);
5384#endif
5385}
5386#endif
5387
5388#if (DBVER >= 45)
5389static PyObject*
5390DBEnv_rep_set_limit(DBEnvObject* self, PyObject* args)
5391{
5392    int err;
5393    int limit;
5394
5395    if (!PyArg_ParseTuple(args,"i:rep_set_limit", &limit))
5396        return NULL;
5397    CHECK_ENV_NOT_CLOSED(self);
5398
5399    MYDB_BEGIN_ALLOW_THREADS;
5400    err = self->db_env->rep_set_limit(self->db_env, 0, limit);
5401    MYDB_END_ALLOW_THREADS;
5402    RETURN_IF_ERR();
5403    RETURN_NONE();
5404}
5405
5406static PyObject*
5407DBEnv_rep_get_limit(DBEnvObject* self)
5408{
5409    int err;
5410    u_int32_t gbytes, bytes;
5411
5412    CHECK_ENV_NOT_CLOSED(self);
5413    MYDB_BEGIN_ALLOW_THREADS;
5414    err = self->db_env->rep_get_limit(self->db_env, &gbytes, &bytes);
5415    MYDB_END_ALLOW_THREADS;
5416    RETURN_IF_ERR();
5417    return NUMBER_FromLong(bytes);
5418}
5419#endif
5420
5421#if (DBVER >= 44)
5422static PyObject*
5423DBEnv_rep_set_config(DBEnvObject* self, PyObject* args)
5424{
5425    int err;
5426    int which;
5427    int onoff;
5428
5429    if (!PyArg_ParseTuple(args,"ii:rep_set_config", &which, &onoff))
5430        return NULL;
5431    CHECK_ENV_NOT_CLOSED(self);
5432
5433    MYDB_BEGIN_ALLOW_THREADS;
5434    err = self->db_env->rep_set_config(self->db_env, which, onoff);
5435    MYDB_END_ALLOW_THREADS;
5436    RETURN_IF_ERR();
5437    RETURN_NONE();
5438}
5439
5440static PyObject*
5441DBEnv_rep_get_config(DBEnvObject* self, PyObject* args)
5442{
5443    int err;
5444    int which;
5445    int onoff;
5446
5447    if (!PyArg_ParseTuple(args, "i:rep_get_config", &which)) {
5448        return NULL;
5449    }
5450    CHECK_ENV_NOT_CLOSED(self);
5451    MYDB_BEGIN_ALLOW_THREADS;
5452    err = self->db_env->rep_get_config(self->db_env, which, &onoff);
5453    MYDB_END_ALLOW_THREADS;
5454    RETURN_IF_ERR();
5455    return PyBool_FromLong(onoff);
5456}
5457#endif
5458
5459#if (DBVER >= 46)
5460static PyObject*
5461DBEnv_rep_elect(DBEnvObject* self, PyObject* args)
5462{
5463    int err;
5464    u_int32_t nsites, nvotes;
5465
5466    if (!PyArg_ParseTuple(args, "II:rep_elect", &nsites, &nvotes)) {
5467        return NULL;
5468    }
5469    CHECK_ENV_NOT_CLOSED(self);
5470    MYDB_BEGIN_ALLOW_THREADS;
5471    err = self->db_env->rep_elect(self->db_env, nvotes, nvotes, 0);
5472    MYDB_END_ALLOW_THREADS;
5473    RETURN_IF_ERR();
5474    RETURN_NONE();
5475}
5476#endif
5477
5478static PyObject*
5479DBEnv_rep_start(DBEnvObject* self, PyObject* args, PyObject* kwargs)
5480{
5481    int err;
5482    PyObject *cdata_py = Py_None;
5483    DBT cdata;
5484    int flags;
5485    static char* kwnames[] = {"flags","cdata", NULL};
5486
5487    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
5488                "i|O:rep_start", kwnames, &flags, &cdata_py))
5489    {
5490	    return NULL;
5491    }
5492    CHECK_ENV_NOT_CLOSED(self);
5493
5494    if (!make_dbt(cdata_py, &cdata))
5495        return NULL;
5496
5497    MYDB_BEGIN_ALLOW_THREADS;
5498    err = self->db_env->rep_start(self->db_env, cdata.size ? &cdata : NULL,
5499            flags);
5500    MYDB_END_ALLOW_THREADS;
5501    RETURN_IF_ERR();
5502    RETURN_NONE();
5503}
5504
5505#if (DBVER >= 44)
5506static PyObject*
5507DBEnv_rep_sync(DBEnvObject* self)
5508{
5509    int err;
5510
5511    CHECK_ENV_NOT_CLOSED(self);
5512    MYDB_BEGIN_ALLOW_THREADS;
5513    err = self->db_env->rep_sync(self->db_env, 0);
5514    MYDB_END_ALLOW_THREADS;
5515    RETURN_IF_ERR();
5516    RETURN_NONE();
5517}
5518#endif
5519
5520
5521#if (DBVER >= 45)
5522static PyObject*
5523DBEnv_rep_set_nsites(DBEnvObject* self, PyObject* args)
5524{
5525    int err;
5526    int nsites;
5527
5528    if (!PyArg_ParseTuple(args, "i:rep_set_nsites", &nsites)) {
5529        return NULL;
5530    }
5531    CHECK_ENV_NOT_CLOSED(self);
5532    MYDB_BEGIN_ALLOW_THREADS;
5533    err = self->db_env->rep_set_nsites(self->db_env, nsites);
5534    MYDB_END_ALLOW_THREADS;
5535    RETURN_IF_ERR();
5536    RETURN_NONE();
5537}
5538
5539static PyObject*
5540DBEnv_rep_get_nsites(DBEnvObject* self)
5541{
5542    int err;
5543#if (DBVER >= 47)
5544    u_int32_t nsites;
5545#else
5546    int nsites;
5547#endif
5548
5549    CHECK_ENV_NOT_CLOSED(self);
5550    MYDB_BEGIN_ALLOW_THREADS;
5551    err = self->db_env->rep_get_nsites(self->db_env, &nsites);
5552    MYDB_END_ALLOW_THREADS;
5553    RETURN_IF_ERR();
5554    return NUMBER_FromLong(nsites);
5555}
5556
5557static PyObject*
5558DBEnv_rep_set_priority(DBEnvObject* self, PyObject* args)
5559{
5560    int err;
5561    int priority;
5562
5563    if (!PyArg_ParseTuple(args, "i:rep_set_priority", &priority)) {
5564        return NULL;
5565    }
5566    CHECK_ENV_NOT_CLOSED(self);
5567    MYDB_BEGIN_ALLOW_THREADS;
5568    err = self->db_env->rep_set_priority(self->db_env, priority);
5569    MYDB_END_ALLOW_THREADS;
5570    RETURN_IF_ERR();
5571    RETURN_NONE();
5572}
5573
5574static PyObject*
5575DBEnv_rep_get_priority(DBEnvObject* self)
5576{
5577    int err;
5578#if (DBVER >= 47)
5579    u_int32_t priority;
5580#else
5581    int priority;
5582#endif
5583
5584    CHECK_ENV_NOT_CLOSED(self);
5585    MYDB_BEGIN_ALLOW_THREADS;
5586    err = self->db_env->rep_get_priority(self->db_env, &priority);
5587    MYDB_END_ALLOW_THREADS;
5588    RETURN_IF_ERR();
5589    return NUMBER_FromLong(priority);
5590}
5591
5592static PyObject*
5593DBEnv_rep_set_timeout(DBEnvObject* self, PyObject* args)
5594{
5595    int err;
5596    int which, timeout;
5597
5598    if (!PyArg_ParseTuple(args, "ii:rep_set_timeout", &which, &timeout)) {
5599        return NULL;
5600    }
5601    CHECK_ENV_NOT_CLOSED(self);
5602    MYDB_BEGIN_ALLOW_THREADS;
5603    err = self->db_env->rep_set_timeout(self->db_env, which, timeout);
5604    MYDB_END_ALLOW_THREADS;
5605    RETURN_IF_ERR();
5606    RETURN_NONE();
5607}
5608
5609static PyObject*
5610DBEnv_rep_get_timeout(DBEnvObject* self, PyObject* args)
5611{
5612    int err;
5613    int which;
5614    u_int32_t timeout;
5615
5616    if (!PyArg_ParseTuple(args, "i:rep_get_timeout", &which)) {
5617        return NULL;
5618    }
5619    CHECK_ENV_NOT_CLOSED(self);
5620    MYDB_BEGIN_ALLOW_THREADS;
5621    err = self->db_env->rep_get_timeout(self->db_env, which, &timeout);
5622    MYDB_END_ALLOW_THREADS;
5623    RETURN_IF_ERR();
5624    return NUMBER_FromLong(timeout);
5625}
5626#endif
5627
5628/* --------------------------------------------------------------------- */
5629/* REPLICATION METHODS: Replication Manager */
5630
5631#if (DBVER >= 45)
5632static PyObject*
5633DBEnv_repmgr_start(DBEnvObject* self, PyObject* args, PyObject*
5634        kwargs)
5635{
5636    int err;
5637    int nthreads, flags;
5638    static char* kwnames[] = {"nthreads","flags", NULL};
5639
5640    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
5641                "ii:repmgr_start", kwnames, &nthreads, &flags))
5642    {
5643	    return NULL;
5644    }
5645    CHECK_ENV_NOT_CLOSED(self);
5646    MYDB_BEGIN_ALLOW_THREADS;
5647    err = self->db_env->repmgr_start(self->db_env, nthreads, flags);
5648    MYDB_END_ALLOW_THREADS;
5649    RETURN_IF_ERR();
5650    RETURN_NONE();
5651}
5652
5653static PyObject*
5654DBEnv_repmgr_set_local_site(DBEnvObject* self, PyObject* args, PyObject*
5655        kwargs)
5656{
5657    int err;
5658    char *host;
5659    int port;
5660    int flags = 0;
5661    static char* kwnames[] = {"host", "port", "flags", NULL};
5662
5663    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
5664                "si|i:repmgr_set_local_site", kwnames, &host, &port, &flags))
5665    {
5666	    return NULL;
5667    }
5668    CHECK_ENV_NOT_CLOSED(self);
5669    MYDB_BEGIN_ALLOW_THREADS;
5670    err = self->db_env->repmgr_set_local_site(self->db_env, host, port, flags);
5671    MYDB_END_ALLOW_THREADS;
5672    RETURN_IF_ERR();
5673    RETURN_NONE();
5674}
5675
5676static PyObject*
5677DBEnv_repmgr_add_remote_site(DBEnvObject* self, PyObject* args, PyObject*
5678        kwargs)
5679{
5680    int err;
5681    char *host;
5682    int port;
5683    int flags = 0;
5684    int eidp;
5685    static char* kwnames[] = {"host", "port", "flags", NULL};
5686
5687    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
5688                "si|i:repmgr_add_remote_site", kwnames, &host, &port, &flags))
5689    {
5690	    return NULL;
5691    }
5692    CHECK_ENV_NOT_CLOSED(self);
5693    MYDB_BEGIN_ALLOW_THREADS;
5694    err = self->db_env->repmgr_add_remote_site(self->db_env, host, port, &eidp, flags);
5695    MYDB_END_ALLOW_THREADS;
5696    RETURN_IF_ERR();
5697    return NUMBER_FromLong(eidp);
5698}
5699
5700static PyObject*
5701DBEnv_repmgr_set_ack_policy(DBEnvObject* self, PyObject* args)
5702{
5703    int err;
5704    int ack_policy;
5705
5706    if (!PyArg_ParseTuple(args, "i:repmgr_set_ack_policy", &ack_policy))
5707    {
5708	    return NULL;
5709    }
5710    CHECK_ENV_NOT_CLOSED(self);
5711    MYDB_BEGIN_ALLOW_THREADS;
5712    err = self->db_env->repmgr_set_ack_policy(self->db_env, ack_policy);
5713    MYDB_END_ALLOW_THREADS;
5714    RETURN_IF_ERR();
5715    RETURN_NONE();
5716}
5717
5718static PyObject*
5719DBEnv_repmgr_get_ack_policy(DBEnvObject* self)
5720{
5721    int err;
5722    int ack_policy;
5723
5724    CHECK_ENV_NOT_CLOSED(self);
5725    MYDB_BEGIN_ALLOW_THREADS;
5726    err = self->db_env->repmgr_get_ack_policy(self->db_env, &ack_policy);
5727    MYDB_END_ALLOW_THREADS;
5728    RETURN_IF_ERR();
5729    return NUMBER_FromLong(ack_policy);
5730}
5731
5732static PyObject*
5733DBEnv_repmgr_site_list(DBEnvObject* self)
5734{
5735    int err;
5736    unsigned int countp;
5737    DB_REPMGR_SITE *listp;
5738    PyObject *stats, *key, *tuple;
5739
5740    CHECK_ENV_NOT_CLOSED(self);
5741    MYDB_BEGIN_ALLOW_THREADS;
5742    err = self->db_env->repmgr_site_list(self->db_env, &countp, &listp);
5743    MYDB_END_ALLOW_THREADS;
5744    RETURN_IF_ERR();
5745
5746    stats=PyDict_New();
5747    if (stats == NULL) {
5748        free(listp);
5749        return NULL;
5750    }
5751
5752    for(;countp--;) {
5753        key=NUMBER_FromLong(listp[countp].eid);
5754        if(!key) {
5755            Py_DECREF(stats);
5756            free(listp);
5757            return NULL;
5758        }
5759#if (PY_VERSION_HEX >= 0x02040000)
5760        tuple=Py_BuildValue("(sII)", listp[countp].host,
5761                listp[countp].port, listp[countp].status);
5762#else
5763        tuple=Py_BuildValue("(sii)", listp[countp].host,
5764                listp[countp].port, listp[countp].status);
5765#endif
5766        if(!tuple) {
5767            Py_DECREF(key);
5768            Py_DECREF(stats);
5769            free(listp);
5770            return NULL;
5771        }
5772        if(PyDict_SetItem(stats, key, tuple)) {
5773            Py_DECREF(key);
5774            Py_DECREF(tuple);
5775            Py_DECREF(stats);
5776            free(listp);
5777            return NULL;
5778        }
5779    }
5780    free(listp);
5781    return stats;
5782}
5783#endif
5784
5785#if (DBVER >= 46)
5786static PyObject*
5787DBEnv_repmgr_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
5788{
5789    int err;
5790    int flags=0;
5791    static char* kwnames[] = { "flags", NULL };
5792
5793    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat_print",
5794                kwnames, &flags))
5795    {
5796        return NULL;
5797    }
5798    CHECK_ENV_NOT_CLOSED(self);
5799    MYDB_BEGIN_ALLOW_THREADS;
5800    err = self->db_env->repmgr_stat_print(self->db_env, flags);
5801    MYDB_END_ALLOW_THREADS;
5802    RETURN_IF_ERR();
5803    RETURN_NONE();
5804}
5805
5806static PyObject*
5807DBEnv_repmgr_stat(DBEnvObject* self, PyObject* args, PyObject *kwargs)
5808{
5809    int err;
5810    int flags=0;
5811    DB_REPMGR_STAT *statp;
5812    PyObject *stats;
5813    static char* kwnames[] = { "flags", NULL };
5814
5815    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat",
5816                kwnames, &flags))
5817    {
5818        return NULL;
5819    }
5820    CHECK_ENV_NOT_CLOSED(self);
5821    MYDB_BEGIN_ALLOW_THREADS;
5822    err = self->db_env->repmgr_stat(self->db_env, &statp, flags);
5823    MYDB_END_ALLOW_THREADS;
5824    RETURN_IF_ERR();
5825
5826    stats=PyDict_New();
5827    if (stats == NULL) {
5828        free(statp);
5829        return NULL;
5830    }
5831
5832#define MAKE_ENTRY(name)  _addIntToDict(stats, #name, statp->st_##name)
5833
5834    MAKE_ENTRY(perm_failed);
5835    MAKE_ENTRY(msgs_queued);
5836    MAKE_ENTRY(msgs_dropped);
5837    MAKE_ENTRY(connection_drop);
5838    MAKE_ENTRY(connect_fail);
5839
5840#undef MAKE_ENTRY
5841
5842    free(statp);
5843    return stats;
5844}
5845#endif
5846
5847
5848/* --------------------------------------------------------------------- */
5849/* DBTxn methods */
5850
5851
5852static void _close_transaction_cursors(DBTxnObject* txn)
5853{
5854    PyObject *dummy;
5855
5856    while(txn->children_cursors) {
5857        PyErr_Warn(PyExc_RuntimeWarning,
5858            "Must close cursors before resolving a transaction.");
5859        dummy=DBC_close_internal(txn->children_cursors);
5860        Py_XDECREF(dummy);
5861    }
5862}
5863
5864static void _promote_transaction_dbs_and_sequences(DBTxnObject *txn)
5865{
5866    DBObject *db;
5867#if (DBVER >= 43)
5868    DBSequenceObject *dbs;
5869#endif
5870
5871    while (txn->children_dbs) {
5872        db=txn->children_dbs;
5873        EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(db);
5874        if (txn->parent_txn) {
5875            INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_dbs,db);
5876            db->txn=txn->parent_txn;
5877        } else {
5878            /* The db is already linked to its environment,
5879            ** so nothing to do.
5880            */
5881            db->txn=NULL; 
5882        }
5883    }
5884
5885#if (DBVER >= 43)
5886    while (txn->children_sequences) {
5887        dbs=txn->children_sequences;
5888        EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(dbs);
5889        if (txn->parent_txn) {
5890            INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_sequences,dbs);
5891            dbs->txn=txn->parent_txn;
5892        } else {
5893            /* The sequence is already linked to its
5894            ** parent db. Nothing to do.
5895            */
5896            dbs->txn=NULL;
5897        }
5898    }
5899#endif
5900}
5901
5902
5903static PyObject*
5904DBTxn_commit(DBTxnObject* self, PyObject* args)
5905{
5906    int flags=0, err;
5907    DB_TXN *txn;
5908
5909    if (!PyArg_ParseTuple(args, "|i:commit", &flags))
5910        return NULL;
5911
5912    _close_transaction_cursors(self);
5913
5914    if (!self->txn) {
5915        PyObject *t =  Py_BuildValue("(is)", 0, "DBTxn must not be used "
5916                                     "after txn_commit, txn_abort "
5917                                     "or txn_discard");
5918        if (t) {
5919            PyErr_SetObject(DBError, t);
5920            Py_DECREF(t);
5921        }
5922        return NULL;
5923    }
5924    self->flag_prepare=0;
5925    txn = self->txn;
5926    self->txn = NULL;   /* this DB_TXN is no longer valid after this call */
5927
5928    EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
5929
5930    MYDB_BEGIN_ALLOW_THREADS;
5931    err = txn->commit(txn, flags);
5932    MYDB_END_ALLOW_THREADS;
5933
5934    _promote_transaction_dbs_and_sequences(self);
5935
5936    RETURN_IF_ERR();
5937    RETURN_NONE();
5938}
5939
5940static PyObject*
5941DBTxn_prepare(DBTxnObject* self, PyObject* args)
5942{
5943    int err;
5944    char* gid=NULL;
5945    int   gid_size=0;
5946
5947    if (!PyArg_ParseTuple(args, "s#:prepare", &gid, &gid_size))
5948        return NULL;
5949
5950    if (gid_size != DB_XIDDATASIZE) {
5951        PyErr_SetString(PyExc_TypeError,
5952                        "gid must be DB_XIDDATASIZE bytes long");
5953        return NULL;
5954    }
5955
5956    if (!self->txn) {
5957        PyObject *t = Py_BuildValue("(is)", 0,"DBTxn must not be used "
5958                                    "after txn_commit, txn_abort "
5959                                    "or txn_discard");
5960        if (t) {
5961            PyErr_SetObject(DBError, t);
5962            Py_DECREF(t);
5963        }
5964        return NULL;
5965    }
5966    self->flag_prepare=1;  /* Prepare state */
5967    MYDB_BEGIN_ALLOW_THREADS;
5968    err = self->txn->prepare(self->txn, (u_int8_t*)gid);
5969    MYDB_END_ALLOW_THREADS;
5970    RETURN_IF_ERR();
5971    RETURN_NONE();
5972}
5973
5974
5975static PyObject*
5976DBTxn_abort_discard_internal(DBTxnObject* self, int discard)
5977{
5978    PyObject *dummy;
5979    int err=0;
5980    DB_TXN *txn;
5981
5982    if (!self->txn) {
5983        PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
5984                                    "after txn_commit, txn_abort "
5985                                    "or txn_discard");
5986        if (t) {
5987            PyErr_SetObject(DBError, t);
5988            Py_DECREF(t);
5989        }
5990        return NULL;
5991    }
5992    txn = self->txn;
5993    self->txn = NULL;   /* this DB_TXN is no longer valid after this call */
5994
5995    _close_transaction_cursors(self);
5996#if (DBVER >= 43)
5997    while (self->children_sequences) {
5998        dummy=DBSequence_close_internal(self->children_sequences,0,0);
5999        Py_XDECREF(dummy);
6000    }
6001#endif
6002    while (self->children_dbs) {
6003        dummy=DB_close_internal(self->children_dbs, 0, 0);
6004        Py_XDECREF(dummy);
6005    }
6006
6007    EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
6008
6009    MYDB_BEGIN_ALLOW_THREADS;
6010    if (discard) {
6011        assert(!self->flag_prepare);
6012        err = txn->discard(txn,0);
6013    } else {
6014        /*
6015        ** If the transaction is in the "prepare" or "recover" state,
6016        ** we better do not implicitly abort it.
6017        */
6018        if (!self->flag_prepare) {
6019            err = txn->abort(txn);
6020        }
6021    }
6022    MYDB_END_ALLOW_THREADS;
6023    RETURN_IF_ERR();
6024    RETURN_NONE();
6025}
6026
6027static PyObject*
6028DBTxn_abort(DBTxnObject* self)
6029{
6030    self->flag_prepare=0;
6031    _close_transaction_cursors(self);
6032
6033    return DBTxn_abort_discard_internal(self,0);
6034}
6035
6036static PyObject*
6037DBTxn_discard(DBTxnObject* self)
6038{
6039    self->flag_prepare=0;
6040    _close_transaction_cursors(self);
6041
6042    return DBTxn_abort_discard_internal(self,1);
6043}
6044
6045
6046static PyObject*
6047DBTxn_id(DBTxnObject* self)
6048{
6049    int id;
6050
6051    if (!self->txn) {
6052        PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
6053                                    "after txn_commit, txn_abort "
6054                                    "or txn_discard");
6055        if (t) {
6056            PyErr_SetObject(DBError, t);
6057            Py_DECREF(t);
6058        }
6059        return NULL;
6060    }
6061    MYDB_BEGIN_ALLOW_THREADS;
6062    id = self->txn->id(self->txn);
6063    MYDB_END_ALLOW_THREADS;
6064    return NUMBER_FromLong(id);
6065}
6066
6067#if (DBVER >= 43)
6068/* --------------------------------------------------------------------- */
6069/* DBSequence methods */
6070
6071
6072static PyObject*
6073DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close)
6074{
6075    int err=0;
6076
6077    if (self->sequence!=NULL) {
6078        EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
6079        if (self->txn) {
6080            EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
6081            self->txn=NULL;
6082        }
6083
6084        /*
6085        ** "do_not_close" is used to dispose all related objects in the
6086        ** tree, without actually releasing the "root" object.
6087        ** This is done, for example, because function calls like
6088        ** "DBSequence.remove()" implicitly close the underlying handle. So
6089        ** the handle doesn't need to be closed, but related objects
6090        ** must be cleaned up.
6091        */
6092        if (!do_not_close) {
6093            MYDB_BEGIN_ALLOW_THREADS
6094            err = self->sequence->close(self->sequence, flags);
6095            MYDB_END_ALLOW_THREADS
6096        }
6097        self->sequence = NULL;
6098
6099        RETURN_IF_ERR();
6100    }
6101
6102    RETURN_NONE();
6103}
6104
6105static PyObject*
6106DBSequence_close(DBSequenceObject* self, PyObject* args)
6107{
6108    int flags=0;
6109    if (!PyArg_ParseTuple(args,"|i:close", &flags))
6110        return NULL;
6111
6112    return DBSequence_close_internal(self,flags,0);
6113}
6114
6115static PyObject*
6116DBSequence_get(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
6117{
6118    int err, flags = 0;
6119    int delta = 1;
6120    db_seq_t value;
6121    PyObject *txnobj = NULL;
6122    DB_TXN *txn = NULL;
6123    static char* kwnames[] = {"delta", "txn", "flags", NULL };
6124    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iOi:get", kwnames, &delta, &txnobj, &flags))
6125        return NULL;
6126    CHECK_SEQUENCE_NOT_CLOSED(self)
6127
6128    if (!checkTxnObj(txnobj, &txn))
6129        return NULL;
6130
6131    MYDB_BEGIN_ALLOW_THREADS
6132    err = self->sequence->get(self->sequence, txn, delta, &value, flags);
6133    MYDB_END_ALLOW_THREADS
6134
6135    RETURN_IF_ERR();
6136    return PyLong_FromLongLong(value);
6137}
6138
6139static PyObject*
6140DBSequence_get_dbp(DBSequenceObject* self)
6141{
6142    CHECK_SEQUENCE_NOT_CLOSED(self)
6143    Py_INCREF(self->mydb);
6144    return (PyObject* )self->mydb;
6145}
6146
6147static PyObject*
6148DBSequence_get_key(DBSequenceObject* self)
6149{
6150    int err;
6151    DBT key;
6152    PyObject *retval = NULL;
6153
6154    key.flags = DB_DBT_MALLOC;
6155    CHECK_SEQUENCE_NOT_CLOSED(self)
6156    MYDB_BEGIN_ALLOW_THREADS
6157    err = self->sequence->get_key(self->sequence, &key);
6158    MYDB_END_ALLOW_THREADS
6159
6160    if (!err)
6161        retval = Build_PyString(key.data, key.size);
6162
6163    FREE_DBT(key);
6164    RETURN_IF_ERR();
6165
6166    return retval;
6167}
6168
6169static PyObject*
6170DBSequence_init_value(DBSequenceObject* self, PyObject* args)
6171{
6172    int err;
6173    PY_LONG_LONG value;
6174    db_seq_t value2;
6175    if (!PyArg_ParseTuple(args,"L:init_value", &value))
6176        return NULL;
6177    CHECK_SEQUENCE_NOT_CLOSED(self)
6178
6179    value2=value; /* If truncation, compiler should show a warning */
6180    MYDB_BEGIN_ALLOW_THREADS
6181    err = self->sequence->initial_value(self->sequence, value2);
6182    MYDB_END_ALLOW_THREADS
6183
6184    RETURN_IF_ERR();
6185
6186    RETURN_NONE();
6187}
6188
6189static PyObject*
6190DBSequence_open(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
6191{
6192    int err, flags = 0;
6193    PyObject* keyobj;
6194    PyObject *txnobj = NULL;
6195    DB_TXN *txn = NULL;
6196    DBT key;
6197
6198    static char* kwnames[] = {"key", "txn", "flags", NULL };
6199    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:open", kwnames, &keyobj, &txnobj, &flags))
6200        return NULL;
6201
6202    if (!checkTxnObj(txnobj, &txn))
6203        return NULL;
6204
6205    if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
6206        return NULL;
6207
6208    MYDB_BEGIN_ALLOW_THREADS
6209    err = self->sequence->open(self->sequence, txn, &key, flags);
6210    MYDB_END_ALLOW_THREADS
6211
6212    FREE_DBT(key);
6213    RETURN_IF_ERR();
6214
6215    if (txn) {
6216        INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_sequences,self);
6217        self->txn=(DBTxnObject *)txnobj;
6218    }
6219
6220    RETURN_NONE();
6221}
6222
6223static PyObject*
6224DBSequence_remove(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
6225{
6226    PyObject *dummy;
6227    int err, flags = 0;
6228    PyObject *txnobj = NULL;
6229    DB_TXN *txn = NULL;
6230
6231    static char* kwnames[] = {"txn", "flags", NULL };
6232    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:remove", kwnames, &txnobj, &flags))
6233        return NULL;
6234
6235    if (!checkTxnObj(txnobj, &txn))
6236        return NULL;
6237
6238    CHECK_SEQUENCE_NOT_CLOSED(self)
6239
6240    MYDB_BEGIN_ALLOW_THREADS
6241    err = self->sequence->remove(self->sequence, txn, flags);
6242    MYDB_END_ALLOW_THREADS
6243
6244    dummy=DBSequence_close_internal(self,flags,1);
6245    Py_XDECREF(dummy);
6246
6247    RETURN_IF_ERR();
6248    RETURN_NONE();
6249}
6250
6251static PyObject*
6252DBSequence_set_cachesize(DBSequenceObject* self, PyObject* args)
6253{
6254    int err, size;
6255    if (!PyArg_ParseTuple(args,"i:set_cachesize", &size))
6256        return NULL;
6257    CHECK_SEQUENCE_NOT_CLOSED(self)
6258
6259    MYDB_BEGIN_ALLOW_THREADS
6260    err = self->sequence->set_cachesize(self->sequence, size);
6261    MYDB_END_ALLOW_THREADS
6262
6263    RETURN_IF_ERR();
6264    RETURN_NONE();
6265}
6266
6267static PyObject*
6268DBSequence_get_cachesize(DBSequenceObject* self)
6269{
6270    int err, size;
6271
6272    CHECK_SEQUENCE_NOT_CLOSED(self)
6273
6274    MYDB_BEGIN_ALLOW_THREADS
6275    err = self->sequence->get_cachesize(self->sequence, &size);
6276    MYDB_END_ALLOW_THREADS
6277
6278    RETURN_IF_ERR();
6279    return NUMBER_FromLong(size);
6280}
6281
6282static