Start packaging the bz2 python module as it is needed for building Qt5
[profile/ivi/python.git] / Modules / _bsddb.c
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  * More datatypes added:
77  *
78  * DBLogCursor  (Log Cursor)
79  *
80  */
81
82 /* --------------------------------------------------------------------- */
83
84 /*
85  * Portions of this module, associated unit tests and build scripts are the
86  * result of a contract with The Written Word (http://thewrittenword.com/)
87  * Many thanks go out to them for causing me to raise the bar on quality and
88  * functionality, resulting in a better bsddb3 package for all of us to use.
89  *
90  * --Robin
91  */
92
93 /* --------------------------------------------------------------------- */
94
95 #include <stddef.h>   /* for offsetof() */
96 #include <Python.h>
97
98 #define COMPILING_BSDDB_C
99 #include "bsddb.h"
100 #undef COMPILING_BSDDB_C
101
102 static char *rcs_id = "$Id$";
103
104 /* --------------------------------------------------------------------- */
105 /* Various macro definitions */
106
107 #if (PY_VERSION_HEX < 0x02050000)
108 typedef int Py_ssize_t;
109 #endif
110
111 #if (PY_VERSION_HEX < 0x02060000)  /* really: before python trunk r63675 */
112 /* This code now uses PyBytes* API function names instead of PyString*.
113  * These #defines map to their equivalent on earlier python versions.    */
114 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
115 #define PyBytes_FromString PyString_FromString
116 #define PyBytes_AsStringAndSize PyString_AsStringAndSize
117 #define PyBytes_Check PyString_Check
118 #define PyBytes_GET_SIZE PyString_GET_SIZE
119 #define PyBytes_AS_STRING PyString_AS_STRING
120 #endif
121
122 #if (PY_VERSION_HEX >= 0x03000000)
123 #define NUMBER_Check    PyLong_Check
124 #define NUMBER_AsLong   PyLong_AsLong
125 #define NUMBER_FromLong PyLong_FromLong
126 #else
127 #define NUMBER_Check    PyInt_Check
128 #define NUMBER_AsLong   PyInt_AsLong
129 #define NUMBER_FromLong PyInt_FromLong
130 #endif
131
132 #ifdef WITH_THREAD
133
134 /* These are for when calling Python --> C */
135 #define MYDB_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS;
136 #define MYDB_END_ALLOW_THREADS Py_END_ALLOW_THREADS;
137
138 /* For 2.3, use the PyGILState_ calls */
139 #if (PY_VERSION_HEX >= 0x02030000)
140 #define MYDB_USE_GILSTATE
141 #endif
142
143 /* and these are for calling C --> Python */
144 #if defined(MYDB_USE_GILSTATE)
145 #define MYDB_BEGIN_BLOCK_THREADS \
146                 PyGILState_STATE __savestate = PyGILState_Ensure();
147 #define MYDB_END_BLOCK_THREADS \
148                 PyGILState_Release(__savestate);
149 #else /* MYDB_USE_GILSTATE */
150 /* Pre GILState API - do it the long old way */
151 static PyInterpreterState* _db_interpreterState = NULL;
152 #define MYDB_BEGIN_BLOCK_THREADS {                              \
153         PyThreadState* prevState;                               \
154         PyThreadState* newState;                                \
155         PyEval_AcquireLock();                                   \
156         newState  = PyThreadState_New(_db_interpreterState);    \
157         prevState = PyThreadState_Swap(newState);
158
159 #define MYDB_END_BLOCK_THREADS                                  \
160         newState = PyThreadState_Swap(prevState);               \
161         PyThreadState_Clear(newState);                          \
162         PyEval_ReleaseLock();                                   \
163         PyThreadState_Delete(newState);                         \
164         }
165 #endif /* MYDB_USE_GILSTATE */
166
167 #else
168 /* Compiled without threads - avoid all this cruft */
169 #define MYDB_BEGIN_ALLOW_THREADS
170 #define MYDB_END_ALLOW_THREADS
171 #define MYDB_BEGIN_BLOCK_THREADS
172 #define MYDB_END_BLOCK_THREADS
173
174 #endif
175
176 /* --------------------------------------------------------------------- */
177 /* Exceptions */
178
179 static PyObject* DBError;               /* Base class, all others derive from this */
180 static PyObject* DBCursorClosedError;   /* raised when trying to use a closed cursor object */
181 static PyObject* DBKeyEmptyError;       /* DB_KEYEMPTY: also derives from KeyError */
182 static PyObject* DBKeyExistError;       /* DB_KEYEXIST */
183 static PyObject* DBLockDeadlockError;   /* DB_LOCK_DEADLOCK */
184 static PyObject* DBLockNotGrantedError; /* DB_LOCK_NOTGRANTED */
185 static PyObject* DBNotFoundError;       /* DB_NOTFOUND: also derives from KeyError */
186 static PyObject* DBOldVersionError;     /* DB_OLD_VERSION */
187 static PyObject* DBRunRecoveryError;    /* DB_RUNRECOVERY */
188 static PyObject* DBVerifyBadError;      /* DB_VERIFY_BAD */
189 static PyObject* DBNoServerError;       /* DB_NOSERVER */
190 static PyObject* DBNoServerHomeError;   /* DB_NOSERVER_HOME */
191 static PyObject* DBNoServerIDError;     /* DB_NOSERVER_ID */
192 static PyObject* DBPageNotFoundError;   /* DB_PAGE_NOTFOUND */
193 static PyObject* DBSecondaryBadError;   /* DB_SECONDARY_BAD */
194
195 static PyObject* DBInvalidArgError;     /* EINVAL */
196 static PyObject* DBAccessError;         /* EACCES */
197 static PyObject* DBNoSpaceError;        /* ENOSPC */
198 static PyObject* DBNoMemoryError;       /* DB_BUFFER_SMALL (ENOMEM when < 4.3) */
199 static PyObject* DBAgainError;          /* EAGAIN */
200 static PyObject* DBBusyError;           /* EBUSY  */
201 static PyObject* DBFileExistsError;     /* EEXIST */
202 static PyObject* DBNoSuchFileError;     /* ENOENT */
203 static PyObject* DBPermissionsError;    /* EPERM  */
204
205 #if (DBVER >= 42)
206 static PyObject* DBRepHandleDeadError;  /* DB_REP_HANDLE_DEAD */
207 #endif
208 #if (DBVER >= 44)
209 static PyObject* DBRepLockoutError;     /* DB_REP_LOCKOUT */
210 #endif
211
212 #if (DBVER >= 46)
213 static PyObject* DBRepLeaseExpiredError; /* DB_REP_LEASE_EXPIRED */
214 #endif
215
216 #if (DBVER >= 47)
217 static PyObject* DBForeignConflictError; /* DB_FOREIGN_CONFLICT */
218 #endif
219
220
221 static PyObject* DBRepUnavailError;     /* DB_REP_UNAVAIL */
222
223 #if (DBVER < 43)
224 #define DB_BUFFER_SMALL         ENOMEM
225 #endif
226
227 #if (DBVER < 48)
228 #define DB_GID_SIZE DB_XIDDATASIZE
229 #endif
230
231
232 /* --------------------------------------------------------------------- */
233 /* Structure definitions */
234
235 #if PYTHON_API_VERSION < 1010
236 #error "Python 2.1 or later required"
237 #endif
238
239
240 /* Defaults for moduleFlags in DBEnvObject and DBObject. */
241 #define DEFAULT_GET_RETURNS_NONE                1
242 #define DEFAULT_CURSOR_SET_RETURNS_NONE         1   /* 0 in pybsddb < 4.2, python < 2.4 */
243
244
245 /* See comment in Python 2.6 "object.h" */
246 #ifndef staticforward
247 #define staticforward static
248 #endif
249 #ifndef statichere
250 #define statichere static
251 #endif
252
253 staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type,
254               DBLock_Type, DBLogCursor_Type;
255 #if (DBVER >= 43)
256 staticforward PyTypeObject DBSequence_Type;
257 #endif
258
259 #ifndef Py_TYPE
260 /* for compatibility with Python 2.5 and earlier */
261 #define Py_TYPE(ob)              (((PyObject*)(ob))->ob_type)
262 #endif
263
264 #define DBObject_Check(v)           (Py_TYPE(v) == &DB_Type)
265 #define DBCursorObject_Check(v)     (Py_TYPE(v) == &DBCursor_Type)
266 #define DBLogCursorObject_Check(v)  (Py_TYPE(v) == &DBLogCursor_Type)
267 #define DBEnvObject_Check(v)        (Py_TYPE(v) == &DBEnv_Type)
268 #define DBTxnObject_Check(v)        (Py_TYPE(v) == &DBTxn_Type)
269 #define DBLockObject_Check(v)       (Py_TYPE(v) == &DBLock_Type)
270 #if (DBVER >= 43)
271 #define DBSequenceObject_Check(v)   (Py_TYPE(v) == &DBSequence_Type)
272 #endif
273
274 #if (DBVER < 46)
275   #define _DBC_close(dbc)           dbc->c_close(dbc)
276   #define _DBC_count(dbc,a,b)       dbc->c_count(dbc,a,b)
277   #define _DBC_del(dbc,a)           dbc->c_del(dbc,a)
278   #define _DBC_dup(dbc,a,b)         dbc->c_dup(dbc,a,b)
279   #define _DBC_get(dbc,a,b,c)       dbc->c_get(dbc,a,b,c)
280   #define _DBC_pget(dbc,a,b,c,d)    dbc->c_pget(dbc,a,b,c,d)
281   #define _DBC_put(dbc,a,b,c)       dbc->c_put(dbc,a,b,c)
282 #else
283   #define _DBC_close(dbc)           dbc->close(dbc)
284   #define _DBC_count(dbc,a,b)       dbc->count(dbc,a,b)
285   #define _DBC_del(dbc,a)           dbc->del(dbc,a)
286   #define _DBC_dup(dbc,a,b)         dbc->dup(dbc,a,b)
287   #define _DBC_get(dbc,a,b,c)       dbc->get(dbc,a,b,c)
288   #define _DBC_pget(dbc,a,b,c,d)    dbc->pget(dbc,a,b,c,d)
289   #define _DBC_put(dbc,a,b,c)       dbc->put(dbc,a,b,c)
290 #endif
291
292
293 /* --------------------------------------------------------------------- */
294 /* Utility macros and functions */
295
296 #define INSERT_IN_DOUBLE_LINKED_LIST(backlink,object)                   \
297     {                                                                   \
298         object->sibling_next=backlink;                                  \
299         object->sibling_prev_p=&(backlink);                             \
300         backlink=object;                                                \
301         if (object->sibling_next) {                                     \
302           object->sibling_next->sibling_prev_p=&(object->sibling_next); \
303         }                                                               \
304     }
305
306 #define EXTRACT_FROM_DOUBLE_LINKED_LIST(object)                          \
307     {                                                                    \
308         if (object->sibling_next) {                                      \
309             object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
310         }                                                                \
311         *(object->sibling_prev_p)=object->sibling_next;                  \
312     }
313
314 #define EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(object)               \
315     {                                                                    \
316         if (object->sibling_next) {                                      \
317             object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
318         }                                                                \
319         if (object->sibling_prev_p) {                                    \
320             *(object->sibling_prev_p)=object->sibling_next;              \
321         }                                                                \
322     }
323
324 #define INSERT_IN_DOUBLE_LINKED_LIST_TXN(backlink,object)  \
325     {                                                      \
326         object->sibling_next_txn=backlink;                 \
327         object->sibling_prev_p_txn=&(backlink);            \
328         backlink=object;                                   \
329         if (object->sibling_next_txn) {                    \
330             object->sibling_next_txn->sibling_prev_p_txn=  \
331                 &(object->sibling_next_txn);               \
332         }                                                  \
333     }
334
335 #define EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(object)             \
336     {                                                           \
337         if (object->sibling_next_txn) {                         \
338             object->sibling_next_txn->sibling_prev_p_txn=       \
339                 object->sibling_prev_p_txn;                     \
340         }                                                       \
341         *(object->sibling_prev_p_txn)=object->sibling_next_txn; \
342     }
343
344
345 #define RETURN_IF_ERR()          \
346     if (makeDBError(err)) {      \
347         return NULL;             \
348     }
349
350 #define RETURN_NONE()  Py_INCREF(Py_None); return Py_None;
351
352 #define _CHECK_OBJECT_NOT_CLOSED(nonNull, pyErrObj, name) \
353     if ((nonNull) == NULL) {          \
354         PyObject *errTuple = NULL;    \
355         errTuple = Py_BuildValue("(is)", 0, #name " object has been closed"); \
356         if (errTuple) { \
357             PyErr_SetObject((pyErrObj), errTuple);  \
358             Py_DECREF(errTuple);          \
359         } \
360         return NULL;                  \
361     }
362
363 #define CHECK_DB_NOT_CLOSED(dbobj) \
364         _CHECK_OBJECT_NOT_CLOSED(dbobj->db, DBError, DB)
365
366 #define CHECK_ENV_NOT_CLOSED(env) \
367         _CHECK_OBJECT_NOT_CLOSED(env->db_env, DBError, DBEnv)
368
369 #define CHECK_CURSOR_NOT_CLOSED(curs) \
370         _CHECK_OBJECT_NOT_CLOSED(curs->dbc, DBCursorClosedError, DBCursor)
371
372 #define CHECK_LOGCURSOR_NOT_CLOSED(logcurs) \
373         _CHECK_OBJECT_NOT_CLOSED(logcurs->logc, DBCursorClosedError, DBLogCursor)
374
375 #if (DBVER >= 43)
376 #define CHECK_SEQUENCE_NOT_CLOSED(curs) \
377         _CHECK_OBJECT_NOT_CLOSED(curs->sequence, DBError, DBSequence)
378 #endif
379
380 #define CHECK_DBFLAG(mydb, flag)    (((mydb)->flags & (flag)) || \
381                                      (((mydb)->myenvobj != NULL) && ((mydb)->myenvobj->flags & (flag))))
382
383 #define CLEAR_DBT(dbt)              (memset(&(dbt), 0, sizeof(dbt)))
384
385 #define FREE_DBT(dbt)               if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \
386                                          dbt.data != NULL) { free(dbt.data); dbt.data = NULL; }
387
388
389 static int makeDBError(int err);
390
391
392 /* Return the access method type of the DBObject */
393 static int _DB_get_type(DBObject* self)
394 {
395     DBTYPE type;
396     int err;
397
398     err = self->db->get_type(self->db, &type);
399     if (makeDBError(err)) {
400         return -1;
401     }
402     return type;
403 }
404
405
406 /* Create a DBT structure (containing key and data values) from Python
407    strings.  Returns 1 on success, 0 on an error. */
408 static int make_dbt(PyObject* obj, DBT* dbt)
409 {
410     CLEAR_DBT(*dbt);
411     if (obj == Py_None) {
412         /* no need to do anything, the structure has already been zeroed */
413     }
414     else if (!PyArg_Parse(obj, "s#", &dbt->data, &dbt->size)) {
415         PyErr_SetString(PyExc_TypeError,
416 #if (PY_VERSION_HEX < 0x03000000)
417                         "Data values must be of type string or None.");
418 #else
419                         "Data values must be of type bytes or None.");
420 #endif
421         return 0;
422     }
423     return 1;
424 }
425
426
427 /* Recno and Queue DBs can have integer keys.  This function figures out
428    what's been given, verifies that it's allowed, and then makes the DBT.
429
430    Caller MUST call FREE_DBT(key) when done. */
431 static int
432 make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags)
433 {
434     db_recno_t recno;
435     int type;
436
437     CLEAR_DBT(*key);
438     if (keyobj == Py_None) {
439         type = _DB_get_type(self);
440         if (type == -1)
441             return 0;
442         if (type == DB_RECNO || type == DB_QUEUE) {
443             PyErr_SetString(
444                 PyExc_TypeError,
445                 "None keys not allowed for Recno and Queue DB's");
446             return 0;
447         }
448         /* no need to do anything, the structure has already been zeroed */
449     }
450
451     else if (PyBytes_Check(keyobj)) {
452         /* verify access method type */
453         type = _DB_get_type(self);
454         if (type == -1)
455             return 0;
456         if (type == DB_RECNO || type == DB_QUEUE) {
457             PyErr_SetString(
458                 PyExc_TypeError,
459 #if (PY_VERSION_HEX < 0x03000000)
460                 "String keys not allowed for Recno and Queue DB's");
461 #else
462                 "Bytes keys not allowed for Recno and Queue DB's");
463 #endif
464             return 0;
465         }
466
467         /*
468          * NOTE(gps): I don't like doing a data copy here, it seems
469          * wasteful.  But without a clean way to tell FREE_DBT if it
470          * should free key->data or not we have to.  Other places in
471          * the code check for DB_THREAD and forceably set DBT_MALLOC
472          * when we otherwise would leave flags 0 to indicate that.
473          */
474         key->data = malloc(PyBytes_GET_SIZE(keyobj));
475         if (key->data == NULL) {
476             PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
477             return 0;
478         }
479         memcpy(key->data, PyBytes_AS_STRING(keyobj),
480                PyBytes_GET_SIZE(keyobj));
481         key->flags = DB_DBT_REALLOC;
482         key->size = PyBytes_GET_SIZE(keyobj);
483     }
484
485     else if (NUMBER_Check(keyobj)) {
486         /* verify access method type */
487         type = _DB_get_type(self);
488         if (type == -1)
489             return 0;
490         if (type == DB_BTREE && pflags != NULL) {
491             /* if BTREE then an Integer key is allowed with the
492              * DB_SET_RECNO flag */
493             *pflags |= DB_SET_RECNO;
494         }
495         else if (type != DB_RECNO && type != DB_QUEUE) {
496             PyErr_SetString(
497                 PyExc_TypeError,
498                 "Integer keys only allowed for Recno and Queue DB's");
499             return 0;
500         }
501
502         /* Make a key out of the requested recno, use allocated space so DB
503          * will be able to realloc room for the real key if needed. */
504         recno = NUMBER_AsLong(keyobj);
505         key->data = malloc(sizeof(db_recno_t));
506         if (key->data == NULL) {
507             PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
508             return 0;
509         }
510         key->ulen = key->size = sizeof(db_recno_t);
511         memcpy(key->data, &recno, sizeof(db_recno_t));
512         key->flags = DB_DBT_REALLOC;
513     }
514     else {
515         PyErr_Format(PyExc_TypeError,
516 #if (PY_VERSION_HEX < 0x03000000)
517                      "String or Integer object expected for key, %s found",
518 #else
519                      "Bytes or Integer object expected for key, %s found",
520 #endif
521                      Py_TYPE(keyobj)->tp_name);
522         return 0;
523     }
524
525     return 1;
526 }
527
528
529 /* Add partial record access to an existing DBT data struct.
530    If dlen and doff are set, then the DB_DBT_PARTIAL flag will be set
531    and the data storage/retrieval will be done using dlen and doff. */
532 static int add_partial_dbt(DBT* d, int dlen, int doff) {
533     /* if neither were set we do nothing (-1 is the default value) */
534     if ((dlen == -1) && (doff == -1)) {
535         return 1;
536     }
537
538     if ((dlen < 0) || (doff < 0)) {
539         PyErr_SetString(PyExc_TypeError, "dlen and doff must both be >= 0");
540         return 0;
541     }
542
543     d->flags = d->flags | DB_DBT_PARTIAL;
544     d->dlen = (unsigned int) dlen;
545     d->doff = (unsigned int) doff;
546     return 1;
547 }
548
549 /* a safe strcpy() without the zeroing behaviour and semantics of strncpy. */
550 /* TODO: make this use the native libc strlcpy() when available (BSD)      */
551 unsigned int our_strlcpy(char* dest, const char* src, unsigned int n)
552 {
553     unsigned int srclen, copylen;
554
555     srclen = strlen(src);
556     if (n <= 0)
557         return srclen;
558     copylen = (srclen > n-1) ? n-1 : srclen;
559     /* populate dest[0] thru dest[copylen-1] */
560     memcpy(dest, src, copylen);
561     /* guarantee null termination */
562     dest[copylen] = 0;
563
564     return srclen;
565 }
566
567 /* Callback used to save away more information about errors from the DB
568  * library. */
569 static char _db_errmsg[1024];
570 #if (DBVER <= 42)
571 static void _db_errorCallback(const char* prefix, char* msg)
572 #else
573 static void _db_errorCallback(const DB_ENV *db_env,
574         const char* prefix, const char* msg)
575 #endif
576 {
577     our_strlcpy(_db_errmsg, msg, sizeof(_db_errmsg));
578 }
579
580
581 /*
582 ** We need these functions because some results
583 ** are undefined if pointer is NULL. Some other
584 ** give None instead of "".
585 **
586 ** This functions are static and will be
587 ** -I hope- inlined.
588 */
589 static const char *DummyString = "This string is a simple placeholder";
590 static PyObject *Build_PyString(const char *p,int s)
591 {
592   if (!p) {
593     p=DummyString;
594     assert(s==0);
595   }
596   return PyBytes_FromStringAndSize(p,s);
597 }
598
599 static PyObject *BuildValue_S(const void *p,int s)
600 {
601   if (!p) {
602     p=DummyString;
603     assert(s==0);
604   }
605   return PyBytes_FromStringAndSize(p, s);
606 }
607
608 static PyObject *BuildValue_SS(const void *p1,int s1,const void *p2,int s2)
609 {
610 PyObject *a, *b, *r;
611
612   if (!p1) {
613     p1=DummyString;
614     assert(s1==0);
615   }
616   if (!p2) {
617     p2=DummyString;
618     assert(s2==0);
619   }
620
621   if (!(a = PyBytes_FromStringAndSize(p1, s1))) {
622       return NULL;
623   }
624   if (!(b = PyBytes_FromStringAndSize(p2, s2))) {
625       Py_DECREF(a);
626       return NULL;
627   }
628
629 #if (PY_VERSION_HEX >= 0x02040000)
630   r = PyTuple_Pack(2, a, b) ;
631 #else
632   r = Py_BuildValue("OO", a, b);
633 #endif
634   Py_DECREF(a);
635   Py_DECREF(b);
636   return r;
637 }
638
639 static PyObject *BuildValue_IS(int i,const void *p,int s)
640 {
641   PyObject *a, *r;
642
643   if (!p) {
644     p=DummyString;
645     assert(s==0);
646   }
647
648   if (!(a = PyBytes_FromStringAndSize(p, s))) {
649       return NULL;
650   }
651
652   r = Py_BuildValue("iO", i, a);
653   Py_DECREF(a);
654   return r;
655 }
656
657 static PyObject *BuildValue_LS(long l,const void *p,int s)
658 {
659   PyObject *a, *r;
660
661   if (!p) {
662     p=DummyString;
663     assert(s==0);
664   }
665
666   if (!(a = PyBytes_FromStringAndSize(p, s))) {
667       return NULL;
668   }
669
670   r = Py_BuildValue("lO", l, a);
671   Py_DECREF(a);
672   return r;
673 }
674
675
676
677 /* make a nice exception object to raise for errors. */
678 static int makeDBError(int err)
679 {
680     char errTxt[2048];  /* really big, just in case... */
681     PyObject *errObj = NULL;
682     PyObject *errTuple = NULL;
683     int exceptionRaised = 0;
684     unsigned int bytes_left;
685
686     switch (err) {
687         case 0:                     /* successful, no error */
688             return 0;
689
690         case DB_KEYEMPTY:           errObj = DBKeyEmptyError;       break;
691         case DB_KEYEXIST:           errObj = DBKeyExistError;       break;
692         case DB_LOCK_DEADLOCK:      errObj = DBLockDeadlockError;   break;
693         case DB_LOCK_NOTGRANTED:    errObj = DBLockNotGrantedError; break;
694         case DB_NOTFOUND:           errObj = DBNotFoundError;       break;
695         case DB_OLD_VERSION:        errObj = DBOldVersionError;     break;
696         case DB_RUNRECOVERY:        errObj = DBRunRecoveryError;    break;
697         case DB_VERIFY_BAD:         errObj = DBVerifyBadError;      break;
698         case DB_NOSERVER:           errObj = DBNoServerError;       break;
699         case DB_NOSERVER_HOME:      errObj = DBNoServerHomeError;   break;
700         case DB_NOSERVER_ID:        errObj = DBNoServerIDError;     break;
701         case DB_PAGE_NOTFOUND:      errObj = DBPageNotFoundError;   break;
702         case DB_SECONDARY_BAD:      errObj = DBSecondaryBadError;   break;
703         case DB_BUFFER_SMALL:       errObj = DBNoMemoryError;       break;
704
705 #if (DBVER >= 43)
706         /* ENOMEM and DB_BUFFER_SMALL were one and the same until 4.3 */
707         case ENOMEM:  errObj = PyExc_MemoryError;   break;
708 #endif
709         case EINVAL:  errObj = DBInvalidArgError;   break;
710         case EACCES:  errObj = DBAccessError;       break;
711         case ENOSPC:  errObj = DBNoSpaceError;      break;
712         case EAGAIN:  errObj = DBAgainError;        break;
713         case EBUSY :  errObj = DBBusyError;         break;
714         case EEXIST:  errObj = DBFileExistsError;   break;
715         case ENOENT:  errObj = DBNoSuchFileError;   break;
716         case EPERM :  errObj = DBPermissionsError;  break;
717
718 #if (DBVER >= 42)
719         case DB_REP_HANDLE_DEAD : errObj = DBRepHandleDeadError; break;
720 #endif
721 #if (DBVER >= 44)
722         case DB_REP_LOCKOUT : errObj = DBRepLockoutError; break;
723 #endif
724
725 #if (DBVER >= 46)
726         case DB_REP_LEASE_EXPIRED : errObj = DBRepLeaseExpiredError; break;
727 #endif
728
729 #if (DBVER >= 47)
730         case DB_FOREIGN_CONFLICT : errObj = DBForeignConflictError; break;
731 #endif
732
733         case DB_REP_UNAVAIL : errObj = DBRepUnavailError; break;
734
735         default:      errObj = DBError;             break;
736     }
737
738     if (errObj != NULL) {
739         bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt));
740         /* Ensure that bytes_left never goes negative */
741         if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) {
742             bytes_left = sizeof(errTxt) - bytes_left - 4 - 1;
743             assert(bytes_left >= 0);
744             strcat(errTxt, " -- ");
745             strncat(errTxt, _db_errmsg, bytes_left);
746         }
747         _db_errmsg[0] = 0;
748
749         errTuple = Py_BuildValue("(is)", err, errTxt);
750         if (errTuple == NULL) {
751             Py_DECREF(errObj);
752             return !0;
753         }
754         PyErr_SetObject(errObj, errTuple);
755         Py_DECREF(errTuple);
756     }
757
758     return ((errObj != NULL) || exceptionRaised);
759 }
760
761
762
763 /* set a type exception */
764 static void makeTypeError(char* expected, PyObject* found)
765 {
766     PyErr_Format(PyExc_TypeError, "Expected %s argument, %s found.",
767                  expected, Py_TYPE(found)->tp_name);
768 }
769
770
771 /* verify that an obj is either None or a DBTxn, and set the txn pointer */
772 static int checkTxnObj(PyObject* txnobj, DB_TXN** txn)
773 {
774     if (txnobj == Py_None || txnobj == NULL) {
775         *txn = NULL;
776         return 1;
777     }
778     if (DBTxnObject_Check(txnobj)) {
779         *txn = ((DBTxnObject*)txnobj)->txn;
780         return 1;
781     }
782     else
783         makeTypeError("DBTxn", txnobj);
784     return 0;
785 }
786
787
788 /* Delete a key from a database
789   Returns 0 on success, -1 on an error.  */
790 static int _DB_delete(DBObject* self, DB_TXN *txn, DBT *key, int flags)
791 {
792     int err;
793
794     MYDB_BEGIN_ALLOW_THREADS;
795     err = self->db->del(self->db, txn, key, 0);
796     MYDB_END_ALLOW_THREADS;
797     if (makeDBError(err)) {
798         return -1;
799     }
800     return 0;
801 }
802
803
804 /* Store a key into a database
805    Returns 0 on success, -1 on an error.  */
806 static int _DB_put(DBObject* self, DB_TXN *txn, DBT *key, DBT *data, int flags)
807 {
808     int err;
809
810     MYDB_BEGIN_ALLOW_THREADS;
811     err = self->db->put(self->db, txn, key, data, flags);
812     MYDB_END_ALLOW_THREADS;
813     if (makeDBError(err)) {
814         return -1;
815     }
816     return 0;
817 }
818
819 /* Get a key/data pair from a cursor */
820 static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
821                                PyObject *args, PyObject *kwargs, char *format)
822 {
823     int err;
824     PyObject* retval = NULL;
825     DBT key, data;
826     int dlen = -1;
827     int doff = -1;
828     int flags = 0;
829     static char* kwnames[] = { "flags", "dlen", "doff", NULL };
830
831     if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, kwnames,
832                                      &flags, &dlen, &doff))
833       return NULL;
834
835     CHECK_CURSOR_NOT_CLOSED(self);
836
837     flags |= extra_flags;
838     CLEAR_DBT(key);
839     CLEAR_DBT(data);
840     if (!add_partial_dbt(&data, dlen, doff))
841         return NULL;
842
843     MYDB_BEGIN_ALLOW_THREADS;
844     err = _DBC_get(self->dbc, &key, &data, flags);
845     MYDB_END_ALLOW_THREADS;
846
847     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
848             && self->mydb->moduleFlags.getReturnsNone) {
849         Py_INCREF(Py_None);
850         retval = Py_None;
851     }
852     else if (makeDBError(err)) {
853         retval = NULL;
854     }
855     else {  /* otherwise, success! */
856
857         /* if Recno or Queue, return the key as an Int */
858         switch (_DB_get_type(self->mydb)) {
859         case -1:
860             retval = NULL;
861             break;
862
863         case DB_RECNO:
864         case DB_QUEUE:
865             retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
866             break;
867         case DB_HASH:
868         case DB_BTREE:
869         default:
870             retval = BuildValue_SS(key.data, key.size, data.data, data.size);
871             break;
872         }
873     }
874     return retval;
875 }
876
877
878 /* add an integer to a dictionary using the given name as a key */
879 static void _addIntToDict(PyObject* dict, char *name, int value)
880 {
881     PyObject* v = NUMBER_FromLong((long) value);
882     if (!v || PyDict_SetItemString(dict, name, v))
883         PyErr_Clear();
884
885     Py_XDECREF(v);
886 }
887
888 /* The same, when the value is a time_t */
889 static void _addTimeTToDict(PyObject* dict, char *name, time_t value)
890 {
891     PyObject* v;
892         /* if the value fits in regular int, use that. */
893 #ifdef PY_LONG_LONG
894         if (sizeof(time_t) > sizeof(long))
895                 v = PyLong_FromLongLong((PY_LONG_LONG) value);
896         else
897 #endif
898                 v = NUMBER_FromLong((long) value);
899     if (!v || PyDict_SetItemString(dict, name, v))
900         PyErr_Clear();
901
902     Py_XDECREF(v);
903 }
904
905 #if (DBVER >= 43)
906 /* add an db_seq_t to a dictionary using the given name as a key */
907 static void _addDb_seq_tToDict(PyObject* dict, char *name, db_seq_t value)
908 {
909     PyObject* v = PyLong_FromLongLong(value);
910     if (!v || PyDict_SetItemString(dict, name, v))
911         PyErr_Clear();
912
913     Py_XDECREF(v);
914 }
915 #endif
916
917 static void _addDB_lsnToDict(PyObject* dict, char *name, DB_LSN value)
918 {
919     PyObject *v = Py_BuildValue("(ll)",value.file,value.offset);
920     if (!v || PyDict_SetItemString(dict, name, v))
921         PyErr_Clear();
922
923     Py_XDECREF(v);
924 }
925
926 /* --------------------------------------------------------------------- */
927 /* Allocators and deallocators */
928
929 static DBObject*
930 newDBObject(DBEnvObject* arg, int flags)
931 {
932     DBObject* self;
933     DB_ENV* db_env = NULL;
934     int err;
935
936     self = PyObject_New(DBObject, &DB_Type);
937     if (self == NULL)
938         return NULL;
939
940     self->flags = 0;
941     self->setflags = 0;
942     self->myenvobj = NULL;
943     self->db = NULL;
944     self->children_cursors = NULL;
945 #if (DBVER >=43)
946     self->children_sequences = NULL;
947 #endif
948     self->associateCallback = NULL;
949     self->btCompareCallback = NULL;
950     self->primaryDBType = 0;
951     Py_INCREF(Py_None);
952     self->private_obj = Py_None;
953     self->in_weakreflist = NULL;
954
955     /* keep a reference to our python DBEnv object */
956     if (arg) {
957         Py_INCREF(arg);
958         self->myenvobj = arg;
959         db_env = arg->db_env;
960         INSERT_IN_DOUBLE_LINKED_LIST(self->myenvobj->children_dbs,self);
961     } else {
962       self->sibling_prev_p=NULL;
963       self->sibling_next=NULL;
964     }
965     self->txn=NULL;
966     self->sibling_prev_p_txn=NULL;
967     self->sibling_next_txn=NULL;
968
969     if (self->myenvobj)
970         self->moduleFlags = self->myenvobj->moduleFlags;
971     else
972         self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
973         self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
974
975     MYDB_BEGIN_ALLOW_THREADS;
976     err = db_create(&self->db, db_env, flags);
977     if (self->db != NULL) {
978         self->db->set_errcall(self->db, _db_errorCallback);
979         self->db->app_private = (void*)self;
980     }
981     MYDB_END_ALLOW_THREADS;
982     /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs
983      * list so that a DBEnv can refuse to close without aborting any open
984      * DBTxns and closing any open DBs first. */
985     if (makeDBError(err)) {
986         if (self->myenvobj) {
987             Py_DECREF(self->myenvobj);
988             self->myenvobj = NULL;
989         }
990         Py_DECREF(self);
991         self = NULL;
992     }
993     return self;
994 }
995
996
997 /* Forward declaration */
998 static PyObject *DB_close_internal(DBObject* self, int flags, int do_not_close);
999
1000 static void
1001 DB_dealloc(DBObject* self)
1002 {
1003   PyObject *dummy;
1004
1005     if (self->db != NULL) {
1006         dummy=DB_close_internal(self, 0, 0);
1007         /*
1008         ** Raising exceptions while doing
1009         ** garbage collection is a fatal error.
1010         */
1011         if (dummy)
1012             Py_DECREF(dummy);
1013         else
1014             PyErr_Clear();
1015     }
1016     if (self->in_weakreflist != NULL) {
1017         PyObject_ClearWeakRefs((PyObject *) self);
1018     }
1019     if (self->myenvobj) {
1020         Py_DECREF(self->myenvobj);
1021         self->myenvobj = NULL;
1022     }
1023     if (self->associateCallback != NULL) {
1024         Py_DECREF(self->associateCallback);
1025         self->associateCallback = NULL;
1026     }
1027     if (self->btCompareCallback != NULL) {
1028         Py_DECREF(self->btCompareCallback);
1029         self->btCompareCallback = NULL;
1030     }
1031     Py_DECREF(self->private_obj);
1032     PyObject_Del(self);
1033 }
1034
1035 static DBCursorObject*
1036 newDBCursorObject(DBC* dbc, DBTxnObject *txn, DBObject* db)
1037 {
1038     DBCursorObject* self = PyObject_New(DBCursorObject, &DBCursor_Type);
1039     if (self == NULL)
1040         return NULL;
1041
1042     self->dbc = dbc;
1043     self->mydb = db;
1044
1045     INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_cursors,self);
1046     if (txn && ((PyObject *)txn!=Py_None)) {
1047             INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->children_cursors,self);
1048             self->txn=txn;
1049     } else {
1050             self->txn=NULL;
1051     }
1052
1053     self->in_weakreflist = NULL;
1054     Py_INCREF(self->mydb);
1055     return self;
1056 }
1057
1058
1059 /* Forward declaration */
1060 static PyObject *DBC_close_internal(DBCursorObject* self);
1061
1062 static void
1063 DBCursor_dealloc(DBCursorObject* self)
1064 {
1065     PyObject *dummy;
1066
1067     if (self->dbc != NULL) {
1068         dummy=DBC_close_internal(self);
1069         /*
1070         ** Raising exceptions while doing
1071         ** garbage collection is a fatal error.
1072         */
1073         if (dummy)
1074             Py_DECREF(dummy);
1075         else
1076             PyErr_Clear();
1077     }
1078     if (self->in_weakreflist != NULL) {
1079         PyObject_ClearWeakRefs((PyObject *) self);
1080     }
1081     Py_DECREF(self->mydb);
1082     PyObject_Del(self);
1083 }
1084
1085
1086 static DBLogCursorObject*
1087 newDBLogCursorObject(DB_LOGC* dblogc, DBEnvObject* env)
1088 {
1089     DBLogCursorObject* self;
1090
1091     self = PyObject_New(DBLogCursorObject, &DBLogCursor_Type);
1092
1093     if (self == NULL)
1094         return NULL;
1095
1096     self->logc = dblogc;
1097     self->env = env;
1098
1099     INSERT_IN_DOUBLE_LINKED_LIST(self->env->children_logcursors, self);
1100
1101     self->in_weakreflist = NULL;
1102     Py_INCREF(self->env);
1103     return self;
1104 }
1105
1106
1107 /* Forward declaration */
1108 static PyObject *DBLogCursor_close_internal(DBLogCursorObject* self);
1109
1110 static void
1111 DBLogCursor_dealloc(DBLogCursorObject* self)
1112 {
1113     PyObject *dummy;
1114
1115     if (self->logc != NULL) {
1116         dummy = DBLogCursor_close_internal(self);
1117         /*
1118         ** Raising exceptions while doing
1119         ** garbage collection is a fatal error.
1120         */
1121         if (dummy)
1122             Py_DECREF(dummy);
1123         else
1124             PyErr_Clear();
1125     }
1126     if (self->in_weakreflist != NULL) {
1127         PyObject_ClearWeakRefs((PyObject *) self);
1128     }
1129     Py_DECREF(self->env);
1130     PyObject_Del(self);
1131 }
1132
1133
1134 static DBEnvObject*
1135 newDBEnvObject(int flags)
1136 {
1137     int err;
1138     DBEnvObject* self = PyObject_New(DBEnvObject, &DBEnv_Type);
1139     if (self == NULL)
1140         return NULL;
1141
1142     self->db_env = NULL;
1143     self->closed = 1;
1144     self->flags = flags;
1145     self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
1146     self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
1147     self->children_dbs = NULL;
1148     self->children_txns = NULL;
1149     self->children_logcursors = NULL ;
1150     Py_INCREF(Py_None);
1151     self->private_obj = Py_None;
1152     Py_INCREF(Py_None);
1153     self->rep_transport = Py_None;
1154     self->in_weakreflist = NULL;
1155     self->event_notifyCallback = NULL;
1156
1157     MYDB_BEGIN_ALLOW_THREADS;
1158     err = db_env_create(&self->db_env, flags);
1159     MYDB_END_ALLOW_THREADS;
1160     if (makeDBError(err)) {
1161         Py_DECREF(self);
1162         self = NULL;
1163     }
1164     else {
1165         self->db_env->set_errcall(self->db_env, _db_errorCallback);
1166         self->db_env->app_private = self;
1167     }
1168     return self;
1169 }
1170
1171 /* Forward declaration */
1172 static PyObject *DBEnv_close_internal(DBEnvObject* self, int flags);
1173
1174 static void
1175 DBEnv_dealloc(DBEnvObject* self)
1176 {
1177   PyObject *dummy;
1178
1179     if (self->db_env) {
1180         dummy=DBEnv_close_internal(self, 0);
1181         /*
1182         ** Raising exceptions while doing
1183         ** garbage collection is a fatal error.
1184         */
1185         if (dummy)
1186             Py_DECREF(dummy);
1187         else
1188             PyErr_Clear();
1189     }
1190
1191     Py_XDECREF(self->event_notifyCallback);
1192     self->event_notifyCallback = NULL;
1193
1194     if (self->in_weakreflist != NULL) {
1195         PyObject_ClearWeakRefs((PyObject *) self);
1196     }
1197     Py_DECREF(self->private_obj);
1198     Py_DECREF(self->rep_transport);
1199     PyObject_Del(self);
1200 }
1201
1202
1203 static DBTxnObject*
1204 newDBTxnObject(DBEnvObject* myenv, DBTxnObject *parent, DB_TXN *txn, int flags)
1205 {
1206     int err;
1207     DB_TXN *parent_txn = NULL;
1208
1209     DBTxnObject* self = PyObject_New(DBTxnObject, &DBTxn_Type);
1210     if (self == NULL)
1211         return NULL;
1212
1213     self->in_weakreflist = NULL;
1214     self->children_txns = NULL;
1215     self->children_dbs = NULL;
1216     self->children_cursors = NULL;
1217     self->children_sequences = NULL;
1218     self->flag_prepare = 0;
1219     self->parent_txn = NULL;
1220     self->env = NULL;
1221     /* We initialize just in case "txn_begin" fails */
1222     self->txn = NULL;
1223
1224     if (parent && ((PyObject *)parent!=Py_None)) {
1225         parent_txn = parent->txn;
1226     }
1227
1228     if (txn) {
1229         self->txn = txn;
1230     } else {
1231         MYDB_BEGIN_ALLOW_THREADS;
1232         err = myenv->db_env->txn_begin(myenv->db_env, parent_txn, &(self->txn), flags);
1233         MYDB_END_ALLOW_THREADS;
1234
1235         if (makeDBError(err)) {
1236             /* Free object half initialized */
1237             Py_DECREF(self);
1238             return NULL;
1239         }
1240     }
1241
1242     /* Can't use 'parent' because could be 'parent==Py_None' */
1243     if (parent_txn) {
1244         self->parent_txn = parent;
1245         Py_INCREF(parent);
1246         self->env = NULL;
1247         INSERT_IN_DOUBLE_LINKED_LIST(parent->children_txns, self);
1248     } else {
1249         self->parent_txn = NULL;
1250         Py_INCREF(myenv);
1251         self->env = myenv;
1252         INSERT_IN_DOUBLE_LINKED_LIST(myenv->children_txns, self);
1253     }
1254
1255     return self;
1256 }
1257
1258 /* Forward declaration */
1259 static PyObject *
1260 DBTxn_abort_discard_internal(DBTxnObject* self, int discard);
1261
1262 static void
1263 DBTxn_dealloc(DBTxnObject* self)
1264 {
1265   PyObject *dummy;
1266
1267     if (self->txn) {
1268         int flag_prepare = self->flag_prepare;
1269
1270         dummy=DBTxn_abort_discard_internal(self, 0);
1271         /*
1272         ** Raising exceptions while doing
1273         ** garbage collection is a fatal error.
1274         */
1275         if (dummy)
1276             Py_DECREF(dummy);
1277         else
1278             PyErr_Clear();
1279
1280         if (!flag_prepare) {
1281             PyErr_Warn(PyExc_RuntimeWarning,
1282               "DBTxn aborted in destructor.  No prior commit() or abort().");
1283         }
1284     }
1285
1286     if (self->in_weakreflist != NULL) {
1287         PyObject_ClearWeakRefs((PyObject *) self);
1288     }
1289
1290     if (self->env) {
1291         Py_DECREF(self->env);
1292     } else {
1293         /*
1294         ** We can have "self->env==NULL" and "self->parent_txn==NULL"
1295         ** if something happens when creating the transaction object
1296         ** and we abort the object while half done.
1297         */
1298         Py_XDECREF(self->parent_txn);
1299     }
1300     PyObject_Del(self);
1301 }
1302
1303
1304 static DBLockObject*
1305 newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj,
1306                 db_lockmode_t lock_mode, int flags)
1307 {
1308     int err;
1309     DBLockObject* self = PyObject_New(DBLockObject, &DBLock_Type);
1310     if (self == NULL)
1311         return NULL;
1312     self->in_weakreflist = NULL;
1313     self->lock_initialized = 0;  /* Just in case the call fails */
1314
1315     MYDB_BEGIN_ALLOW_THREADS;
1316     err = myenv->db_env->lock_get(myenv->db_env, locker, flags, obj, lock_mode,
1317                                   &self->lock);
1318     MYDB_END_ALLOW_THREADS;
1319     if (makeDBError(err)) {
1320         Py_DECREF(self);
1321         self = NULL;
1322     } else {
1323         self->lock_initialized = 1;
1324     }
1325
1326     return self;
1327 }
1328
1329
1330 static void
1331 DBLock_dealloc(DBLockObject* self)
1332 {
1333     if (self->in_weakreflist != NULL) {
1334         PyObject_ClearWeakRefs((PyObject *) self);
1335     }
1336     /* TODO: is this lock held? should we release it? */
1337     /* CAUTION: The lock can be not initialized if the creation has failed */
1338
1339     PyObject_Del(self);
1340 }
1341
1342
1343 #if (DBVER >= 43)
1344 static DBSequenceObject*
1345 newDBSequenceObject(DBObject* mydb,  int flags)
1346 {
1347     int err;
1348     DBSequenceObject* self = PyObject_New(DBSequenceObject, &DBSequence_Type);
1349     if (self == NULL)
1350         return NULL;
1351     Py_INCREF(mydb);
1352     self->mydb = mydb;
1353
1354     INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_sequences,self);
1355     self->txn = NULL;
1356
1357     self->in_weakreflist = NULL;
1358     self->sequence = NULL;  /* Just in case the call fails */
1359
1360     MYDB_BEGIN_ALLOW_THREADS;
1361     err = db_sequence_create(&self->sequence, self->mydb->db, flags);
1362     MYDB_END_ALLOW_THREADS;
1363     if (makeDBError(err)) {
1364         Py_DECREF(self);
1365         self = NULL;
1366     }
1367
1368     return self;
1369 }
1370
1371 /* Forward declaration */
1372 static PyObject
1373 *DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close);
1374
1375 static void
1376 DBSequence_dealloc(DBSequenceObject* self)
1377 {
1378     PyObject *dummy;
1379
1380     if (self->sequence != NULL) {
1381         dummy=DBSequence_close_internal(self,0,0);
1382         /*
1383         ** Raising exceptions while doing
1384         ** garbage collection is a fatal error.
1385         */
1386         if (dummy)
1387             Py_DECREF(dummy);
1388         else
1389             PyErr_Clear();
1390     }
1391
1392     if (self->in_weakreflist != NULL) {
1393         PyObject_ClearWeakRefs((PyObject *) self);
1394     }
1395
1396     Py_DECREF(self->mydb);
1397     PyObject_Del(self);
1398 }
1399 #endif
1400
1401 /* --------------------------------------------------------------------- */
1402 /* DB methods */
1403
1404 static PyObject*
1405 DB_append(DBObject* self, PyObject* args, PyObject* kwargs)
1406 {
1407     PyObject* txnobj = NULL;
1408     PyObject* dataobj;
1409     db_recno_t recno;
1410     DBT key, data;
1411     DB_TXN *txn = NULL;
1412     static char* kwnames[] = { "data", "txn", NULL };
1413
1414     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:append", kwnames,
1415                                      &dataobj, &txnobj))
1416         return NULL;
1417
1418     CHECK_DB_NOT_CLOSED(self);
1419
1420     /* make a dummy key out of a recno */
1421     recno = 0;
1422     CLEAR_DBT(key);
1423     key.data = &recno;
1424     key.size = sizeof(recno);
1425     key.ulen = key.size;
1426     key.flags = DB_DBT_USERMEM;
1427
1428     if (!make_dbt(dataobj, &data)) return NULL;
1429     if (!checkTxnObj(txnobj, &txn)) return NULL;
1430
1431     if (-1 == _DB_put(self, txn, &key, &data, DB_APPEND))
1432         return NULL;
1433
1434     return NUMBER_FromLong(recno);
1435 }
1436
1437
1438 static int
1439 _db_associateCallback(DB* db, const DBT* priKey, const DBT* priData,
1440                       DBT* secKey)
1441 {
1442     int       retval = DB_DONOTINDEX;
1443     DBObject* secondaryDB = (DBObject*)db->app_private;
1444     PyObject* callback = secondaryDB->associateCallback;
1445     int       type = secondaryDB->primaryDBType;
1446     PyObject* args;
1447     PyObject* result = NULL;
1448
1449
1450     if (callback != NULL) {
1451         MYDB_BEGIN_BLOCK_THREADS;
1452
1453         if (type == DB_RECNO || type == DB_QUEUE)
1454             args = BuildValue_LS(*((db_recno_t*)priKey->data), priData->data, priData->size);
1455         else
1456             args = BuildValue_SS(priKey->data, priKey->size, priData->data, priData->size);
1457         if (args != NULL) {
1458                 result = PyEval_CallObject(callback, args);
1459         }
1460         if (args == NULL || result == NULL) {
1461             PyErr_Print();
1462         }
1463         else if (result == Py_None) {
1464             retval = DB_DONOTINDEX;
1465         }
1466         else if (NUMBER_Check(result)) {
1467             retval = NUMBER_AsLong(result);
1468         }
1469         else if (PyBytes_Check(result)) {
1470             char* data;
1471             Py_ssize_t size;
1472
1473             CLEAR_DBT(*secKey);
1474             PyBytes_AsStringAndSize(result, &data, &size);
1475             secKey->flags = DB_DBT_APPMALLOC;   /* DB will free */
1476             secKey->data = malloc(size);        /* TODO, check this */
1477             if (secKey->data) {
1478                 memcpy(secKey->data, data, size);
1479                 secKey->size = size;
1480                 retval = 0;
1481             }
1482             else {
1483                 PyErr_SetString(PyExc_MemoryError,
1484                                 "malloc failed in _db_associateCallback");
1485                 PyErr_Print();
1486             }
1487         }
1488 #if (DBVER >= 46)
1489         else if (PyList_Check(result))
1490         {
1491             char* data;
1492             Py_ssize_t size;
1493             int i, listlen;
1494             DBT* dbts;
1495
1496             listlen = PyList_Size(result);
1497
1498             dbts = (DBT *)malloc(sizeof(DBT) * listlen);
1499
1500             for (i=0; i<listlen; i++)
1501             {
1502                 if (!PyBytes_Check(PyList_GetItem(result, i)))
1503                 {
1504                     PyErr_SetString(
1505                        PyExc_TypeError,
1506 #if (PY_VERSION_HEX < 0x03000000)
1507 "The list returned by DB->associate callback should be a list of strings.");
1508 #else
1509 "The list returned by DB->associate callback should be a list of bytes.");
1510 #endif
1511                     PyErr_Print();
1512                 }
1513
1514                 PyBytes_AsStringAndSize(
1515                     PyList_GetItem(result, i),
1516                     &data, &size);
1517
1518                 CLEAR_DBT(dbts[i]);
1519                 dbts[i].data = malloc(size);          /* TODO, check this */
1520
1521                 if (dbts[i].data)
1522                 {
1523                     memcpy(dbts[i].data, data, size);
1524                     dbts[i].size = size;
1525                     dbts[i].ulen = dbts[i].size;
1526                     dbts[i].flags = DB_DBT_APPMALLOC;  /* DB will free */
1527                 }
1528                 else
1529                 {
1530                     PyErr_SetString(PyExc_MemoryError,
1531                         "malloc failed in _db_associateCallback (list)");
1532                     PyErr_Print();
1533                 }
1534             }
1535
1536             CLEAR_DBT(*secKey);
1537
1538             secKey->data = dbts;
1539             secKey->size = listlen;
1540             secKey->flags = DB_DBT_APPMALLOC | DB_DBT_MULTIPLE;
1541             retval = 0;
1542         }
1543 #endif
1544         else {
1545             PyErr_SetString(
1546                PyExc_TypeError,
1547 #if (PY_VERSION_HEX < 0x03000000)
1548 "DB associate callback should return DB_DONOTINDEX/string/list of strings.");
1549 #else
1550 "DB associate callback should return DB_DONOTINDEX/bytes/list of bytes.");
1551 #endif
1552             PyErr_Print();
1553         }
1554
1555         Py_XDECREF(args);
1556         Py_XDECREF(result);
1557
1558         MYDB_END_BLOCK_THREADS;
1559     }
1560     return retval;
1561 }
1562
1563
1564 static PyObject*
1565 DB_associate(DBObject* self, PyObject* args, PyObject* kwargs)
1566 {
1567     int err, flags=0;
1568     DBObject* secondaryDB;
1569     PyObject* callback;
1570     PyObject *txnobj = NULL;
1571     DB_TXN *txn = NULL;
1572     static char* kwnames[] = {"secondaryDB", "callback", "flags", "txn",
1573                                     NULL};
1574
1575     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iO:associate", kwnames,
1576                                      &secondaryDB, &callback, &flags,
1577                                      &txnobj)) {
1578         return NULL;
1579     }
1580
1581     if (!checkTxnObj(txnobj, &txn)) return NULL;
1582
1583     CHECK_DB_NOT_CLOSED(self);
1584     if (!DBObject_Check(secondaryDB)) {
1585         makeTypeError("DB", (PyObject*)secondaryDB);
1586         return NULL;
1587     }
1588     CHECK_DB_NOT_CLOSED(secondaryDB);
1589     if (callback == Py_None) {
1590         callback = NULL;
1591     }
1592     else if (!PyCallable_Check(callback)) {
1593         makeTypeError("Callable", callback);
1594         return NULL;
1595     }
1596
1597     /* Save a reference to the callback in the secondary DB. */
1598     Py_XDECREF(secondaryDB->associateCallback);
1599     Py_XINCREF(callback);
1600     secondaryDB->associateCallback = callback;
1601     secondaryDB->primaryDBType = _DB_get_type(self);
1602
1603     /* PyEval_InitThreads is called here due to a quirk in python 1.5
1604      * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>:
1605      * The global interepreter lock is not initialized until the first
1606      * thread is created using thread.start_new_thread() or fork() is
1607      * called.  that would cause the ALLOW_THREADS here to segfault due
1608      * to a null pointer reference if no threads or child processes
1609      * have been created.  This works around that and is a no-op if
1610      * threads have already been initialized.
1611      *  (see pybsddb-users mailing list post on 2002-08-07)
1612      */
1613 #ifdef WITH_THREAD
1614     PyEval_InitThreads();
1615 #endif
1616     MYDB_BEGIN_ALLOW_THREADS;
1617     err = self->db->associate(self->db,
1618                               txn,
1619                               secondaryDB->db,
1620                               _db_associateCallback,
1621                               flags);
1622     MYDB_END_ALLOW_THREADS;
1623
1624     if (err) {
1625         Py_XDECREF(secondaryDB->associateCallback);
1626         secondaryDB->associateCallback = NULL;
1627         secondaryDB->primaryDBType = 0;
1628     }
1629
1630     RETURN_IF_ERR();
1631     RETURN_NONE();
1632 }
1633
1634
1635 static PyObject*
1636 DB_close_internal(DBObject* self, int flags, int do_not_close)
1637 {
1638     PyObject *dummy;
1639     int err = 0;
1640
1641     if (self->db != NULL) {
1642         /* Can be NULL if db is not in an environment */
1643         EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(self);
1644
1645         if (self->txn) {
1646             EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
1647             self->txn=NULL;
1648         }
1649
1650         while(self->children_cursors) {
1651           dummy=DBC_close_internal(self->children_cursors);
1652           Py_XDECREF(dummy);
1653         }
1654
1655 #if (DBVER >= 43)
1656         while(self->children_sequences) {
1657             dummy=DBSequence_close_internal(self->children_sequences,0,0);
1658             Py_XDECREF(dummy);
1659         }
1660 #endif
1661
1662         /*
1663         ** "do_not_close" is used to dispose all related objects in the
1664         ** tree, without actually releasing the "root" object.
1665         ** This is done, for example, because function calls like
1666         ** "DB.verify()" implicitly close the underlying handle. So
1667         ** the handle doesn't need to be closed, but related objects
1668         ** must be cleaned up.
1669         */
1670         if (!do_not_close) {
1671             MYDB_BEGIN_ALLOW_THREADS;
1672             err = self->db->close(self->db, flags);
1673             MYDB_END_ALLOW_THREADS;
1674             self->db = NULL;
1675         }
1676         RETURN_IF_ERR();
1677     }
1678     RETURN_NONE();
1679 }
1680
1681 static PyObject*
1682 DB_close(DBObject* self, PyObject* args)
1683 {
1684     int flags=0;
1685     if (!PyArg_ParseTuple(args,"|i:close", &flags))
1686         return NULL;
1687     return DB_close_internal(self, flags, 0);
1688 }
1689
1690
1691 static PyObject*
1692 _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
1693 {
1694     int err, flags=0, type;
1695     PyObject* txnobj = NULL;
1696     PyObject* retval = NULL;
1697     DBT key, data;
1698     DB_TXN *txn = NULL;
1699     static char* kwnames[] = { "txn", "flags", NULL };
1700
1701     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:consume", kwnames,
1702                                      &txnobj, &flags))
1703         return NULL;
1704
1705     CHECK_DB_NOT_CLOSED(self);
1706     type = _DB_get_type(self);
1707     if (type == -1)
1708         return NULL;
1709     if (type != DB_QUEUE) {
1710         PyErr_SetString(PyExc_TypeError,
1711                         "Consume methods only allowed for Queue DB's");
1712         return NULL;
1713     }
1714     if (!checkTxnObj(txnobj, &txn))
1715         return NULL;
1716
1717     CLEAR_DBT(key);
1718     CLEAR_DBT(data);
1719     if (CHECK_DBFLAG(self, DB_THREAD)) {
1720         /* Tell Berkeley DB to malloc the return value (thread safe) */
1721         data.flags = DB_DBT_MALLOC;
1722         key.flags = DB_DBT_MALLOC;
1723     }
1724
1725     MYDB_BEGIN_ALLOW_THREADS;
1726     err = self->db->get(self->db, txn, &key, &data, flags|consume_flag);
1727     MYDB_END_ALLOW_THREADS;
1728
1729     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1730             && self->moduleFlags.getReturnsNone) {
1731         err = 0;
1732         Py_INCREF(Py_None);
1733         retval = Py_None;
1734     }
1735     else if (!err) {
1736         retval = BuildValue_SS(key.data, key.size, data.data, data.size);
1737         FREE_DBT(key);
1738         FREE_DBT(data);
1739     }
1740
1741     RETURN_IF_ERR();
1742     return retval;
1743 }
1744
1745 static PyObject*
1746 DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
1747 {
1748     return _DB_consume(self, args, kwargs, DB_CONSUME);
1749 }
1750
1751 static PyObject*
1752 DB_consume_wait(DBObject* self, PyObject* args, PyObject* kwargs,
1753                 int consume_flag)
1754 {
1755     return _DB_consume(self, args, kwargs, DB_CONSUME_WAIT);
1756 }
1757
1758
1759 static PyObject*
1760 DB_cursor(DBObject* self, PyObject* args, PyObject* kwargs)
1761 {
1762     int err, flags=0;
1763     DBC* dbc;
1764     PyObject* txnobj = NULL;
1765     DB_TXN *txn = NULL;
1766     static char* kwnames[] = { "txn", "flags", NULL };
1767
1768     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames,
1769                                      &txnobj, &flags))
1770         return NULL;
1771     CHECK_DB_NOT_CLOSED(self);
1772     if (!checkTxnObj(txnobj, &txn))
1773         return NULL;
1774
1775     MYDB_BEGIN_ALLOW_THREADS;
1776     err = self->db->cursor(self->db, txn, &dbc, flags);
1777     MYDB_END_ALLOW_THREADS;
1778     RETURN_IF_ERR();
1779     return (PyObject*) newDBCursorObject(dbc, (DBTxnObject *)txnobj, self);
1780 }
1781
1782
1783 static PyObject*
1784 DB_delete(DBObject* self, PyObject* args, PyObject* kwargs)
1785 {
1786     PyObject* txnobj = NULL;
1787     int flags = 0;
1788     PyObject* keyobj;
1789     DBT key;
1790     DB_TXN *txn = NULL;
1791     static char* kwnames[] = { "key", "txn", "flags", NULL };
1792
1793     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:delete", kwnames,
1794                                      &keyobj, &txnobj, &flags))
1795         return NULL;
1796     CHECK_DB_NOT_CLOSED(self);
1797     if (!make_key_dbt(self, keyobj, &key, NULL))
1798         return NULL;
1799     if (!checkTxnObj(txnobj, &txn)) {
1800         FREE_DBT(key);
1801         return NULL;
1802     }
1803
1804     if (-1 == _DB_delete(self, txn, &key, 0)) {
1805         FREE_DBT(key);
1806         return NULL;
1807     }
1808
1809     FREE_DBT(key);
1810     RETURN_NONE();
1811 }
1812
1813
1814 #if (DBVER >= 47)
1815 /*
1816 ** This function is available since Berkeley DB 4.4,
1817 ** but 4.6 version is so buggy that we only support
1818 ** it from BDB 4.7 and newer.
1819 */
1820 static PyObject*
1821 DB_compact(DBObject* self, PyObject* args, PyObject* kwargs)
1822 {
1823     PyObject* txnobj = NULL;
1824     PyObject *startobj = NULL, *stopobj = NULL;
1825     int flags = 0;
1826     DB_TXN *txn = NULL;
1827     DBT *start_p = NULL, *stop_p = NULL;
1828     DBT start, stop;
1829     int err;
1830     DB_COMPACT c_data = { 0 };
1831     static char* kwnames[] = { "txn", "start", "stop", "flags",
1832                                "compact_fillpercent", "compact_pages",
1833                                "compact_timeout", NULL };
1834
1835
1836     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOiiiI:compact", kwnames,
1837                                      &txnobj, &startobj, &stopobj, &flags,
1838                                      &c_data.compact_fillpercent,
1839                                      &c_data.compact_pages,
1840                                      &c_data.compact_timeout))
1841         return NULL;
1842
1843     CHECK_DB_NOT_CLOSED(self);
1844     if (!checkTxnObj(txnobj, &txn)) {
1845         return NULL;
1846     }
1847
1848     if (startobj && make_key_dbt(self, startobj, &start, NULL)) {
1849         start_p = &start;
1850     }
1851     if (stopobj && make_key_dbt(self, stopobj, &stop, NULL)) {
1852         stop_p = &stop;
1853     }
1854
1855     MYDB_BEGIN_ALLOW_THREADS;
1856     err = self->db->compact(self->db, txn, start_p, stop_p, &c_data,
1857                             flags, NULL);
1858     MYDB_END_ALLOW_THREADS;
1859
1860     if (startobj)
1861         FREE_DBT(start);
1862     if (stopobj)
1863         FREE_DBT(stop);
1864
1865     RETURN_IF_ERR();
1866
1867     return PyLong_FromUnsignedLong(c_data.compact_pages_truncated);
1868 }
1869 #endif
1870
1871
1872 static PyObject*
1873 DB_fd(DBObject* self)
1874 {
1875     int err, the_fd;
1876
1877     CHECK_DB_NOT_CLOSED(self);
1878
1879     MYDB_BEGIN_ALLOW_THREADS;
1880     err = self->db->fd(self->db, &the_fd);
1881     MYDB_END_ALLOW_THREADS;
1882     RETURN_IF_ERR();
1883     return NUMBER_FromLong(the_fd);
1884 }
1885
1886
1887 #if (DBVER >= 46)
1888 static PyObject*
1889 DB_exists(DBObject* self, PyObject* args, PyObject* kwargs)
1890 {
1891     int err, flags=0;
1892     PyObject* txnobj = NULL;
1893     PyObject* keyobj;
1894     DBT key;
1895     DB_TXN *txn;
1896
1897     static char* kwnames[] = {"key", "txn", "flags", NULL};
1898
1899     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:exists", kwnames,
1900                 &keyobj, &txnobj, &flags))
1901         return NULL;
1902
1903     CHECK_DB_NOT_CLOSED(self);
1904     if (!make_key_dbt(self, keyobj, &key, NULL))
1905         return NULL;
1906     if (!checkTxnObj(txnobj, &txn)) {
1907         FREE_DBT(key);
1908         return NULL;
1909     }
1910
1911     MYDB_BEGIN_ALLOW_THREADS;
1912     err = self->db->exists(self->db, txn, &key, flags);
1913     MYDB_END_ALLOW_THREADS;
1914
1915     FREE_DBT(key);
1916
1917     if (!err) {
1918         Py_INCREF(Py_True);
1919         return Py_True;
1920     }
1921     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)) {
1922         Py_INCREF(Py_False);
1923         return Py_False;
1924     }
1925
1926     /*
1927     ** If we reach there, there was an error. The
1928     ** "return" should be unreachable.
1929     */
1930     RETURN_IF_ERR();
1931     assert(0);  /* This coude SHOULD be unreachable */
1932     return NULL;
1933 }
1934 #endif
1935
1936 static PyObject*
1937 DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
1938 {
1939     int err, flags=0;
1940     PyObject* txnobj = NULL;
1941     PyObject* keyobj;
1942     PyObject* dfltobj = NULL;
1943     PyObject* retval = NULL;
1944     int dlen = -1;
1945     int doff = -1;
1946     DBT key, data;
1947     DB_TXN *txn = NULL;
1948     static char* kwnames[] = {"key", "default", "txn", "flags", "dlen",
1949                                     "doff", NULL};
1950
1951     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:get", kwnames,
1952                                      &keyobj, &dfltobj, &txnobj, &flags, &dlen,
1953                                      &doff))
1954         return NULL;
1955
1956     CHECK_DB_NOT_CLOSED(self);
1957     if (!make_key_dbt(self, keyobj, &key, &flags))
1958         return NULL;
1959     if (!checkTxnObj(txnobj, &txn)) {
1960         FREE_DBT(key);
1961         return NULL;
1962     }
1963
1964     CLEAR_DBT(data);
1965     if (CHECK_DBFLAG(self, DB_THREAD)) {
1966         /* Tell Berkeley DB to malloc the return value (thread safe) */
1967         data.flags = DB_DBT_MALLOC;
1968     }
1969     if (!add_partial_dbt(&data, dlen, doff)) {
1970         FREE_DBT(key);
1971         return NULL;
1972     }
1973
1974     MYDB_BEGIN_ALLOW_THREADS;
1975     err = self->db->get(self->db, txn, &key, &data, flags);
1976     MYDB_END_ALLOW_THREADS;
1977
1978     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) {
1979         err = 0;
1980         Py_INCREF(dfltobj);
1981         retval = dfltobj;
1982     }
1983     else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1984              && self->moduleFlags.getReturnsNone) {
1985         err = 0;
1986         Py_INCREF(Py_None);
1987         retval = Py_None;
1988     }
1989     else if (!err) {
1990         if (flags & DB_SET_RECNO) /* return both key and data */
1991             retval = BuildValue_SS(key.data, key.size, data.data, data.size);
1992         else /* return just the data */
1993             retval = Build_PyString(data.data, data.size);
1994         FREE_DBT(data);
1995     }
1996     FREE_DBT(key);
1997
1998     RETURN_IF_ERR();
1999     return retval;
2000 }
2001
2002 static PyObject*
2003 DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
2004 {
2005     int err, flags=0;
2006     PyObject* txnobj = NULL;
2007     PyObject* keyobj;
2008     PyObject* dfltobj = NULL;
2009     PyObject* retval = NULL;
2010     int dlen = -1;
2011     int doff = -1;
2012     DBT key, pkey, data;
2013     DB_TXN *txn = NULL;
2014     static char* kwnames[] = {"key", "default", "txn", "flags", "dlen",
2015                                     "doff", NULL};
2016
2017     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:pget", kwnames,
2018                                      &keyobj, &dfltobj, &txnobj, &flags, &dlen,
2019                                      &doff))
2020         return NULL;
2021
2022     CHECK_DB_NOT_CLOSED(self);
2023     if (!make_key_dbt(self, keyobj, &key, &flags))
2024         return NULL;
2025     if (!checkTxnObj(txnobj, &txn)) {
2026         FREE_DBT(key);
2027         return NULL;
2028     }
2029
2030     CLEAR_DBT(data);
2031     if (CHECK_DBFLAG(self, DB_THREAD)) {
2032         /* Tell Berkeley DB to malloc the return value (thread safe) */
2033         data.flags = DB_DBT_MALLOC;
2034     }
2035     if (!add_partial_dbt(&data, dlen, doff)) {
2036         FREE_DBT(key);
2037         return NULL;
2038     }
2039
2040     CLEAR_DBT(pkey);
2041     pkey.flags = DB_DBT_MALLOC;
2042
2043     MYDB_BEGIN_ALLOW_THREADS;
2044     err = self->db->pget(self->db, txn, &key, &pkey, &data, flags);
2045     MYDB_END_ALLOW_THREADS;
2046
2047     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) {
2048         err = 0;
2049         Py_INCREF(dfltobj);
2050         retval = dfltobj;
2051     }
2052     else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
2053              && self->moduleFlags.getReturnsNone) {
2054         err = 0;
2055         Py_INCREF(Py_None);
2056         retval = Py_None;
2057     }
2058     else if (!err) {
2059         PyObject *pkeyObj;
2060         PyObject *dataObj;
2061         dataObj = Build_PyString(data.data, data.size);
2062
2063         if (self->primaryDBType == DB_RECNO ||
2064             self->primaryDBType == DB_QUEUE)
2065             pkeyObj = NUMBER_FromLong(*(int *)pkey.data);
2066         else
2067             pkeyObj = Build_PyString(pkey.data, pkey.size);
2068
2069         if (flags & DB_SET_RECNO) /* return key , pkey and data */
2070         {
2071             PyObject *keyObj;
2072             int type = _DB_get_type(self);
2073             if (type == DB_RECNO || type == DB_QUEUE)
2074                 keyObj = NUMBER_FromLong(*(int *)key.data);
2075             else
2076                 keyObj = Build_PyString(key.data, key.size);
2077 #if (PY_VERSION_HEX >= 0x02040000)
2078             retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
2079 #else
2080             retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj);
2081 #endif
2082             Py_DECREF(keyObj);
2083         }
2084         else /* return just the pkey and data */
2085         {
2086 #if (PY_VERSION_HEX >= 0x02040000)
2087             retval = PyTuple_Pack(2, pkeyObj, dataObj);
2088 #else
2089             retval = Py_BuildValue("OO", pkeyObj, dataObj);
2090 #endif
2091         }
2092         Py_DECREF(dataObj);
2093         Py_DECREF(pkeyObj);
2094         FREE_DBT(pkey);
2095         FREE_DBT(data);
2096     }
2097     FREE_DBT(key);
2098
2099     RETURN_IF_ERR();
2100     return retval;
2101 }
2102
2103
2104 /* Return size of entry */
2105 static PyObject*
2106 DB_get_size(DBObject* self, PyObject* args, PyObject* kwargs)
2107 {
2108     int err, flags=0;
2109     PyObject* txnobj = NULL;
2110     PyObject* keyobj;
2111     PyObject* retval = NULL;
2112     DBT key, data;
2113     DB_TXN *txn = NULL;
2114     static char* kwnames[] = { "key", "txn", NULL };
2115
2116     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:get_size", kwnames,
2117                                      &keyobj, &txnobj))
2118         return NULL;
2119     CHECK_DB_NOT_CLOSED(self);
2120     if (!make_key_dbt(self, keyobj, &key, &flags))
2121         return NULL;
2122     if (!checkTxnObj(txnobj, &txn)) {
2123         FREE_DBT(key);
2124         return NULL;
2125     }
2126     CLEAR_DBT(data);
2127
2128     /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and
2129        thus getting the record size. */
2130     data.flags = DB_DBT_USERMEM;
2131     data.ulen = 0;
2132     MYDB_BEGIN_ALLOW_THREADS;
2133     err = self->db->get(self->db, txn, &key, &data, flags);
2134     MYDB_END_ALLOW_THREADS;
2135     if (err == DB_BUFFER_SMALL) {
2136         retval = NUMBER_FromLong((long)data.size);
2137         err = 0;
2138     }
2139
2140     FREE_DBT(key);
2141     FREE_DBT(data);
2142     RETURN_IF_ERR();
2143     return retval;
2144 }
2145
2146
2147 static PyObject*
2148 DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
2149 {
2150     int err, flags=0;
2151     PyObject* txnobj = NULL;
2152     PyObject* keyobj;
2153     PyObject* dataobj;
2154     PyObject* retval = NULL;
2155     DBT key, data;
2156     void *orig_data;
2157     DB_TXN *txn = NULL;
2158     static char* kwnames[] = { "key", "data", "txn", "flags", NULL };
2159
2160     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oi:get_both", kwnames,
2161                                      &keyobj, &dataobj, &txnobj, &flags))
2162         return NULL;
2163
2164     CHECK_DB_NOT_CLOSED(self);
2165     if (!make_key_dbt(self, keyobj, &key, NULL))
2166         return NULL;
2167     if ( !make_dbt(dataobj, &data) ||
2168          !checkTxnObj(txnobj, &txn) )
2169     {
2170         FREE_DBT(key);
2171         return NULL;
2172     }
2173
2174     flags |= DB_GET_BOTH;
2175     orig_data = data.data;
2176
2177     if (CHECK_DBFLAG(self, DB_THREAD)) {
2178         /* Tell Berkeley DB to malloc the return value (thread safe) */
2179         /* XXX(nnorwitz): At least 4.4.20 and 4.5.20 require this flag. */
2180         data.flags = DB_DBT_MALLOC;
2181     }
2182
2183     MYDB_BEGIN_ALLOW_THREADS;
2184     err = self->db->get(self->db, txn, &key, &data, flags);
2185     MYDB_END_ALLOW_THREADS;
2186
2187     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
2188             && self->moduleFlags.getReturnsNone) {
2189         err = 0;
2190         Py_INCREF(Py_None);
2191         retval = Py_None;
2192     }
2193     else if (!err) {
2194         /* XXX(nnorwitz): can we do: retval = dataobj; Py_INCREF(retval); */
2195         retval = Build_PyString(data.data, data.size);
2196
2197         /* Even though the flags require DB_DBT_MALLOC, data is not always
2198            allocated.  4.4: allocated, 4.5: *not* allocated. :-( */
2199         if (data.data != orig_data)
2200             FREE_DBT(data);
2201     }
2202
2203     FREE_DBT(key);
2204     RETURN_IF_ERR();
2205     return retval;
2206 }
2207
2208
2209 static PyObject*
2210 DB_get_byteswapped(DBObject* self)
2211 {
2212     int err = 0;
2213     int retval = -1;
2214
2215     CHECK_DB_NOT_CLOSED(self);
2216
2217     MYDB_BEGIN_ALLOW_THREADS;
2218     err = self->db->get_byteswapped(self->db, &retval);
2219     MYDB_END_ALLOW_THREADS;
2220     RETURN_IF_ERR();
2221     return NUMBER_FromLong(retval);
2222 }
2223
2224
2225 static PyObject*
2226 DB_get_type(DBObject* self)
2227 {
2228     int type;
2229
2230     CHECK_DB_NOT_CLOSED(self);
2231
2232     type = _DB_get_type(self);
2233     if (type == -1)
2234         return NULL;
2235     return NUMBER_FromLong(type);
2236 }
2237
2238
2239 static PyObject*
2240 DB_join(DBObject* self, PyObject* args)
2241 {
2242     int err, flags=0;
2243     int length, x;
2244     PyObject* cursorsObj;
2245     DBC** cursors;
2246     DBC*  dbc;
2247
2248     if (!PyArg_ParseTuple(args,"O|i:join", &cursorsObj, &flags))
2249         return NULL;
2250
2251     CHECK_DB_NOT_CLOSED(self);
2252
2253     if (!PySequence_Check(cursorsObj)) {
2254         PyErr_SetString(PyExc_TypeError,
2255                         "Sequence of DBCursor objects expected");
2256         return NULL;
2257     }
2258
2259     length = PyObject_Length(cursorsObj);
2260     cursors = malloc((length+1) * sizeof(DBC*));
2261     if (!cursors) {
2262         PyErr_NoMemory();
2263         return NULL;
2264     }
2265
2266     cursors[length] = NULL;
2267     for (x=0; x<length; x++) {
2268         PyObject* item = PySequence_GetItem(cursorsObj, x);
2269         if (item == NULL) {
2270             free(cursors);
2271             return NULL;
2272         }
2273         if (!DBCursorObject_Check(item)) {
2274             PyErr_SetString(PyExc_TypeError,
2275                             "Sequence of DBCursor objects expected");
2276             free(cursors);
2277             return NULL;
2278         }
2279         cursors[x] = ((DBCursorObject*)item)->dbc;
2280         Py_DECREF(item);
2281     }
2282
2283     MYDB_BEGIN_ALLOW_THREADS;
2284     err = self->db->join(self->db, cursors, &dbc, flags);
2285     MYDB_END_ALLOW_THREADS;
2286     free(cursors);
2287     RETURN_IF_ERR();
2288
2289     /* FIXME: this is a buggy interface.  The returned cursor
2290        contains internal references to the passed in cursors
2291        but does not hold python references to them or prevent
2292        them from being closed prematurely.  This can cause
2293        python to crash when things are done in the wrong order. */
2294     return (PyObject*) newDBCursorObject(dbc, NULL, self);
2295 }
2296
2297
2298 static PyObject*
2299 DB_key_range(DBObject* self, PyObject* args, PyObject* kwargs)
2300 {
2301     int err, flags=0;
2302     PyObject* txnobj = NULL;
2303     PyObject* keyobj;
2304     DBT key;
2305     DB_TXN *txn = NULL;
2306     DB_KEY_RANGE range;
2307     static char* kwnames[] = { "key", "txn", "flags", NULL };
2308
2309     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:key_range", kwnames,
2310                                      &keyobj, &txnobj, &flags))
2311         return NULL;
2312     CHECK_DB_NOT_CLOSED(self);
2313     if (!make_dbt(keyobj, &key))
2314         /* BTree only, don't need to allow for an int key */
2315         return NULL;
2316     if (!checkTxnObj(txnobj, &txn))
2317         return NULL;
2318
2319     MYDB_BEGIN_ALLOW_THREADS;
2320     err = self->db->key_range(self->db, txn, &key, &range, flags);
2321     MYDB_END_ALLOW_THREADS;
2322
2323     RETURN_IF_ERR();
2324     return Py_BuildValue("ddd", range.less, range.equal, range.greater);
2325 }
2326
2327
2328 static PyObject*
2329 DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
2330 {
2331     int err, type = DB_UNKNOWN, flags=0, mode=0660;
2332     char* filename = NULL;
2333     char* dbname = NULL;
2334     PyObject *txnobj = NULL;
2335     DB_TXN *txn = NULL;
2336     /* with dbname */
2337     static char* kwnames[] = {
2338         "filename", "dbname", "dbtype", "flags", "mode", "txn", NULL};
2339     /* without dbname */
2340     static char* kwnames_basic[] = {
2341         "filename", "dbtype", "flags", "mode", "txn", NULL};
2342
2343     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziiiO:open", kwnames,
2344                                      &filename, &dbname, &type, &flags, &mode,
2345                                      &txnobj))
2346     {
2347         PyErr_Clear();
2348         type = DB_UNKNOWN; flags = 0; mode = 0660;
2349         filename = NULL; dbname = NULL;
2350         if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iiiO:open",
2351                                          kwnames_basic,
2352                                          &filename, &type, &flags, &mode,
2353                                          &txnobj))
2354             return NULL;
2355     }
2356
2357     if (!checkTxnObj(txnobj, &txn)) return NULL;
2358
2359     if (NULL == self->db) {
2360         PyObject *t = Py_BuildValue("(is)", 0,
2361                                 "Cannot call open() twice for DB object");
2362         if (t) {
2363             PyErr_SetObject(DBError, t);
2364             Py_DECREF(t);
2365         }
2366         return NULL;
2367     }
2368
2369     if (txn) {  /* Can't use 'txnobj' because could be 'txnobj==Py_None' */
2370         INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_dbs,self);
2371         self->txn=(DBTxnObject *)txnobj;
2372     } else {
2373         self->txn=NULL;
2374     }
2375
2376     MYDB_BEGIN_ALLOW_THREADS;
2377     err = self->db->open(self->db, txn, filename, dbname, type, flags, mode);
2378     MYDB_END_ALLOW_THREADS;
2379
2380     if (makeDBError(err)) {
2381         PyObject *dummy;
2382
2383         dummy=DB_close_internal(self, 0, 0);
2384         Py_XDECREF(dummy);
2385         return NULL;
2386     }
2387
2388 #if (DBVER >= 42)
2389     self->db->get_flags(self->db, &self->setflags);
2390 #endif
2391
2392     self->flags = flags;
2393
2394     RETURN_NONE();
2395 }
2396
2397
2398 static PyObject*
2399 DB_put(DBObject* self, PyObject* args, PyObject* kwargs)
2400 {
2401     int flags=0;
2402     PyObject* txnobj = NULL;
2403     int dlen = -1;
2404     int doff = -1;
2405     PyObject* keyobj, *dataobj, *retval;
2406     DBT key, data;
2407     DB_TXN *txn = NULL;
2408     static char* kwnames[] = { "key", "data", "txn", "flags", "dlen",
2409                                      "doff", NULL };
2410
2411     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oiii:put", kwnames,
2412                          &keyobj, &dataobj, &txnobj, &flags, &dlen, &doff))
2413         return NULL;
2414
2415     CHECK_DB_NOT_CLOSED(self);
2416     if (!make_key_dbt(self, keyobj, &key, NULL))
2417         return NULL;
2418     if ( !make_dbt(dataobj, &data) ||
2419          !add_partial_dbt(&data, dlen, doff) ||
2420          !checkTxnObj(txnobj, &txn) )
2421     {
2422         FREE_DBT(key);
2423         return NULL;
2424     }
2425
2426     if (-1 == _DB_put(self, txn, &key, &data, flags)) {
2427         FREE_DBT(key);
2428         return NULL;
2429     }
2430
2431     if (flags & DB_APPEND)
2432         retval = NUMBER_FromLong(*((db_recno_t*)key.data));
2433     else {
2434         retval = Py_None;
2435         Py_INCREF(retval);
2436     }
2437     FREE_DBT(key);
2438     return retval;
2439 }
2440
2441
2442
2443 static PyObject*
2444 DB_remove(DBObject* self, PyObject* args, PyObject* kwargs)
2445 {
2446     char* filename;
2447     char* database = NULL;
2448     int err, flags=0;
2449     static char* kwnames[] = { "filename", "dbname", "flags", NULL};
2450
2451     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zi:remove", kwnames,
2452                                      &filename, &database, &flags))
2453         return NULL;
2454     CHECK_DB_NOT_CLOSED(self);
2455
2456     EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(self);
2457
2458     MYDB_BEGIN_ALLOW_THREADS;
2459     err = self->db->remove(self->db, filename, database, flags);
2460     MYDB_END_ALLOW_THREADS;
2461
2462     self->db = NULL;
2463     RETURN_IF_ERR();
2464     RETURN_NONE();
2465 }
2466
2467
2468
2469 static PyObject*
2470 DB_rename(DBObject* self, PyObject* args)
2471 {
2472     char* filename;
2473     char* database;
2474     char* newname;
2475     int err, flags=0;
2476
2477     if (!PyArg_ParseTuple(args, "sss|i:rename", &filename, &database, &newname,
2478                           &flags))
2479         return NULL;
2480     CHECK_DB_NOT_CLOSED(self);
2481
2482     MYDB_BEGIN_ALLOW_THREADS;
2483     err = self->db->rename(self->db, filename, database, newname, flags);
2484     MYDB_END_ALLOW_THREADS;
2485     RETURN_IF_ERR();
2486     RETURN_NONE();
2487 }
2488
2489
2490 static PyObject*
2491 DB_get_private(DBObject* self)
2492 {
2493     /* We can give out the private field even if db is closed */
2494     Py_INCREF(self->private_obj);
2495     return self->private_obj;
2496 }
2497
2498 static PyObject*
2499 DB_set_private(DBObject* self, PyObject* private_obj)
2500 {
2501     /* We can set the private field even if db is closed */
2502     Py_DECREF(self->private_obj);
2503     Py_INCREF(private_obj);
2504     self->private_obj = private_obj;
2505     RETURN_NONE();
2506 }
2507
2508 #if (DBVER >= 46)
2509 static PyObject*
2510 DB_set_priority(DBObject* self, PyObject* args)
2511 {
2512     int err, priority;
2513
2514     if (!PyArg_ParseTuple(args,"i:set_priority", &priority))
2515         return NULL;
2516     CHECK_DB_NOT_CLOSED(self);
2517
2518     MYDB_BEGIN_ALLOW_THREADS;
2519     err = self->db->set_priority(self->db, priority);
2520     MYDB_END_ALLOW_THREADS;
2521     RETURN_IF_ERR();
2522     RETURN_NONE();
2523 }
2524
2525 static PyObject*
2526 DB_get_priority(DBObject* self)
2527 {
2528     int err = 0;
2529     DB_CACHE_PRIORITY priority;
2530
2531     CHECK_DB_NOT_CLOSED(self);
2532
2533     MYDB_BEGIN_ALLOW_THREADS;
2534     err = self->db->get_priority(self->db, &priority);
2535     MYDB_END_ALLOW_THREADS;
2536     RETURN_IF_ERR();
2537     return NUMBER_FromLong(priority);
2538 }
2539 #endif
2540
2541 static PyObject*
2542 DB_set_q_extentsize(DBObject* self, PyObject* args)
2543 {
2544     int err;
2545     u_int32_t extentsize;
2546
2547     if (!PyArg_ParseTuple(args,"i:set_q_extentsize", &extentsize))
2548         return NULL;
2549     CHECK_DB_NOT_CLOSED(self);
2550
2551     MYDB_BEGIN_ALLOW_THREADS;
2552     err = self->db->set_q_extentsize(self->db, extentsize);
2553     MYDB_END_ALLOW_THREADS;
2554     RETURN_IF_ERR();
2555     RETURN_NONE();
2556 }
2557
2558 #if (DBVER >= 42)
2559 static PyObject*
2560 DB_get_q_extentsize(DBObject* self)
2561 {
2562     int err = 0;
2563     u_int32_t extentsize;
2564
2565     CHECK_DB_NOT_CLOSED(self);
2566
2567     MYDB_BEGIN_ALLOW_THREADS;
2568     err = self->db->get_q_extentsize(self->db, &extentsize);
2569     MYDB_END_ALLOW_THREADS;
2570     RETURN_IF_ERR();
2571     return NUMBER_FromLong(extentsize);
2572 }
2573 #endif
2574
2575 static PyObject*
2576 DB_set_bt_minkey(DBObject* self, PyObject* args)
2577 {
2578     int err, minkey;
2579
2580     if (!PyArg_ParseTuple(args,"i:set_bt_minkey", &minkey))
2581         return NULL;
2582     CHECK_DB_NOT_CLOSED(self);
2583
2584     MYDB_BEGIN_ALLOW_THREADS;
2585     err = self->db->set_bt_minkey(self->db, minkey);
2586     MYDB_END_ALLOW_THREADS;
2587     RETURN_IF_ERR();
2588     RETURN_NONE();
2589 }
2590
2591 #if (DBVER >= 42)
2592 static PyObject*
2593 DB_get_bt_minkey(DBObject* self)
2594 {
2595     int err;
2596     u_int32_t bt_minkey;
2597
2598     CHECK_DB_NOT_CLOSED(self);
2599
2600     MYDB_BEGIN_ALLOW_THREADS;
2601     err = self->db->get_bt_minkey(self->db, &bt_minkey);
2602     MYDB_END_ALLOW_THREADS;
2603     RETURN_IF_ERR();
2604     return NUMBER_FromLong(bt_minkey);
2605 }
2606 #endif
2607
2608 static int
2609 _default_cmp(const DBT *leftKey,
2610              const DBT *rightKey)
2611 {
2612   int res;
2613   int lsize = leftKey->size, rsize = rightKey->size;
2614
2615   res = memcmp(leftKey->data, rightKey->data,
2616                lsize < rsize ? lsize : rsize);
2617
2618   if (res == 0) {
2619       if (lsize < rsize) {
2620           res = -1;
2621       }
2622       else if (lsize > rsize) {
2623           res = 1;
2624       }
2625   }
2626   return res;
2627 }
2628
2629 static int
2630 _db_compareCallback(DB* db,
2631                     const DBT *leftKey,
2632                     const DBT *rightKey)
2633 {
2634     int res = 0;
2635     PyObject *args;
2636     PyObject *result = NULL;
2637     DBObject *self = (DBObject *)db->app_private;
2638
2639     if (self == NULL || self->btCompareCallback == NULL) {
2640         MYDB_BEGIN_BLOCK_THREADS;
2641         PyErr_SetString(PyExc_TypeError,
2642                         (self == 0
2643                          ? "DB_bt_compare db is NULL."
2644                          : "DB_bt_compare callback is NULL."));
2645         /* we're in a callback within the DB code, we can't raise */
2646         PyErr_Print();
2647         res = _default_cmp(leftKey, rightKey);
2648         MYDB_END_BLOCK_THREADS;
2649     } else {
2650         MYDB_BEGIN_BLOCK_THREADS;
2651
2652         args = BuildValue_SS(leftKey->data, leftKey->size, rightKey->data, rightKey->size);
2653         if (args != NULL) {
2654                 result = PyEval_CallObject(self->btCompareCallback, args);
2655         }
2656         if (args == NULL || result == NULL) {
2657             /* we're in a callback within the DB code, we can't raise */
2658             PyErr_Print();
2659             res = _default_cmp(leftKey, rightKey);
2660         } else if (NUMBER_Check(result)) {
2661             res = NUMBER_AsLong(result);
2662         } else {
2663             PyErr_SetString(PyExc_TypeError,
2664                             "DB_bt_compare callback MUST return an int.");
2665             /* we're in a callback within the DB code, we can't raise */
2666             PyErr_Print();
2667             res = _default_cmp(leftKey, rightKey);
2668         }
2669
2670         Py_XDECREF(args);
2671         Py_XDECREF(result);
2672
2673         MYDB_END_BLOCK_THREADS;
2674     }
2675     return res;
2676 }
2677
2678 static PyObject*
2679 DB_set_bt_compare(DBObject* self, PyObject* comparator)
2680 {
2681     int err;
2682     PyObject *tuple, *result;
2683
2684     CHECK_DB_NOT_CLOSED(self);
2685
2686     if (!PyCallable_Check(comparator)) {
2687         makeTypeError("Callable", comparator);
2688         return NULL;
2689     }
2690
2691     /*
2692      * Perform a test call of the comparator function with two empty
2693      * string objects here.  verify that it returns an int (0).
2694      * err if not.
2695      */
2696     tuple = Py_BuildValue("(ss)", "", "");
2697     result = PyEval_CallObject(comparator, tuple);
2698     Py_DECREF(tuple);
2699     if (result == NULL)
2700         return NULL;
2701     if (!NUMBER_Check(result)) {
2702         Py_DECREF(result);
2703         PyErr_SetString(PyExc_TypeError,
2704                         "callback MUST return an int");
2705         return NULL;
2706     } else if (NUMBER_AsLong(result) != 0) {
2707         Py_DECREF(result);
2708         PyErr_SetString(PyExc_TypeError,
2709                         "callback failed to return 0 on two empty strings");
2710         return NULL;
2711     }
2712     Py_DECREF(result);
2713
2714     /* We don't accept multiple set_bt_compare operations, in order to
2715      * simplify the code. This would have no real use, as one cannot
2716      * change the function once the db is opened anyway */
2717     if (self->btCompareCallback != NULL) {
2718         PyErr_SetString(PyExc_RuntimeError, "set_bt_compare() cannot be called more than once");
2719         return NULL;
2720     }
2721
2722     Py_INCREF(comparator);
2723     self->btCompareCallback = comparator;
2724
2725     /* This is to workaround a problem with un-initialized threads (see
2726        comment in DB_associate) */
2727 #ifdef WITH_THREAD
2728     PyEval_InitThreads();
2729 #endif
2730
2731     err = self->db->set_bt_compare(self->db, _db_compareCallback);
2732
2733     if (err) {
2734         /* restore the old state in case of error */
2735         Py_DECREF(comparator);
2736         self->btCompareCallback = NULL;
2737     }
2738
2739     RETURN_IF_ERR();
2740     RETURN_NONE();
2741 }
2742
2743
2744 static PyObject*
2745 DB_set_cachesize(DBObject* self, PyObject* args)
2746 {
2747     int err;
2748     int gbytes = 0, bytes = 0, ncache = 0;
2749
2750     if (!PyArg_ParseTuple(args,"ii|i:set_cachesize",
2751                           &gbytes,&bytes,&ncache))
2752         return NULL;
2753     CHECK_DB_NOT_CLOSED(self);
2754
2755     MYDB_BEGIN_ALLOW_THREADS;
2756     err = self->db->set_cachesize(self->db, gbytes, bytes, ncache);
2757     MYDB_END_ALLOW_THREADS;
2758     RETURN_IF_ERR();
2759     RETURN_NONE();
2760 }
2761
2762 #if (DBVER >= 42)
2763 static PyObject*
2764 DB_get_cachesize(DBObject* self)
2765 {
2766     int err;
2767     u_int32_t gbytes, bytes;
2768     int ncache;
2769
2770     CHECK_DB_NOT_CLOSED(self);
2771
2772     MYDB_BEGIN_ALLOW_THREADS;
2773     err = self->db->get_cachesize(self->db, &gbytes, &bytes, &ncache);
2774     MYDB_END_ALLOW_THREADS;
2775
2776     RETURN_IF_ERR();
2777
2778     return Py_BuildValue("(iii)", gbytes, bytes, ncache);
2779 }
2780 #endif
2781
2782 static PyObject*
2783 DB_set_flags(DBObject* self, PyObject* args)
2784 {
2785     int err, flags;
2786
2787     if (!PyArg_ParseTuple(args,"i:set_flags", &flags))
2788         return NULL;
2789     CHECK_DB_NOT_CLOSED(self);
2790
2791     MYDB_BEGIN_ALLOW_THREADS;
2792     err = self->db->set_flags(self->db, flags);
2793     MYDB_END_ALLOW_THREADS;
2794     RETURN_IF_ERR();
2795
2796     self->setflags |= flags;
2797     RETURN_NONE();
2798 }
2799
2800 #if (DBVER >= 42)
2801 static PyObject*
2802 DB_get_flags(DBObject* self)
2803 {
2804     int err;
2805     u_int32_t flags;
2806
2807     CHECK_DB_NOT_CLOSED(self);
2808
2809     MYDB_BEGIN_ALLOW_THREADS;
2810     err = self->db->get_flags(self->db, &flags);
2811     MYDB_END_ALLOW_THREADS;
2812     RETURN_IF_ERR();
2813     return NUMBER_FromLong(flags);
2814 }
2815 #endif
2816
2817 static PyObject*
2818 DB_set_h_ffactor(DBObject* self, PyObject* args)
2819 {
2820     int err, ffactor;
2821
2822     if (!PyArg_ParseTuple(args,"i:set_h_ffactor", &ffactor))
2823         return NULL;
2824     CHECK_DB_NOT_CLOSED(self);
2825
2826     MYDB_BEGIN_ALLOW_THREADS;
2827     err = self->db->set_h_ffactor(self->db, ffactor);
2828     MYDB_END_ALLOW_THREADS;
2829     RETURN_IF_ERR();
2830     RETURN_NONE();
2831 }
2832
2833 #if (DBVER >= 42)
2834 static PyObject*
2835 DB_get_h_ffactor(DBObject* self)
2836 {
2837     int err;
2838     u_int32_t ffactor;
2839
2840     CHECK_DB_NOT_CLOSED(self);
2841
2842     MYDB_BEGIN_ALLOW_THREADS;
2843     err = self->db->get_h_ffactor(self->db, &ffactor);
2844     MYDB_END_ALLOW_THREADS;
2845     RETURN_IF_ERR();
2846     return NUMBER_FromLong(ffactor);
2847 }
2848 #endif
2849
2850 static PyObject*
2851 DB_set_h_nelem(DBObject* self, PyObject* args)
2852 {
2853     int err, nelem;
2854
2855     if (!PyArg_ParseTuple(args,"i:set_h_nelem", &nelem))
2856         return NULL;
2857     CHECK_DB_NOT_CLOSED(self);
2858
2859     MYDB_BEGIN_ALLOW_THREADS;
2860     err = self->db->set_h_nelem(self->db, nelem);
2861     MYDB_END_ALLOW_THREADS;
2862     RETURN_IF_ERR();
2863     RETURN_NONE();
2864 }
2865
2866 #if (DBVER >= 42)
2867 static PyObject*
2868 DB_get_h_nelem(DBObject* self)
2869 {
2870     int err;
2871     u_int32_t nelem;
2872
2873     CHECK_DB_NOT_CLOSED(self);
2874
2875     MYDB_BEGIN_ALLOW_THREADS;
2876     err = self->db->get_h_nelem(self->db, &nelem);
2877     MYDB_END_ALLOW_THREADS;
2878     RETURN_IF_ERR();
2879     return NUMBER_FromLong(nelem);
2880 }
2881 #endif
2882
2883 static PyObject*
2884 DB_set_lorder(DBObject* self, PyObject* args)
2885 {
2886     int err, lorder;
2887
2888     if (!PyArg_ParseTuple(args,"i:set_lorder", &lorder))
2889         return NULL;
2890     CHECK_DB_NOT_CLOSED(self);
2891
2892     MYDB_BEGIN_ALLOW_THREADS;
2893     err = self->db->set_lorder(self->db, lorder);
2894     MYDB_END_ALLOW_THREADS;
2895     RETURN_IF_ERR();
2896     RETURN_NONE();
2897 }
2898
2899 #if (DBVER >= 42)
2900 static PyObject*
2901 DB_get_lorder(DBObject* self)
2902 {
2903     int err;
2904     int lorder;
2905
2906     CHECK_DB_NOT_CLOSED(self);
2907
2908     MYDB_BEGIN_ALLOW_THREADS;
2909     err = self->db->get_lorder(self->db, &lorder);
2910     MYDB_END_ALLOW_THREADS;
2911     RETURN_IF_ERR();
2912     return NUMBER_FromLong(lorder);
2913 }
2914 #endif
2915
2916 static PyObject*
2917 DB_set_pagesize(DBObject* self, PyObject* args)
2918 {
2919     int err, pagesize;
2920
2921     if (!PyArg_ParseTuple(args,"i:set_pagesize", &pagesize))
2922         return NULL;
2923     CHECK_DB_NOT_CLOSED(self);
2924
2925     MYDB_BEGIN_ALLOW_THREADS;
2926     err = self->db->set_pagesize(self->db, pagesize);
2927     MYDB_END_ALLOW_THREADS;
2928     RETURN_IF_ERR();
2929     RETURN_NONE();
2930 }
2931
2932 #if (DBVER >= 42)
2933 static PyObject*
2934 DB_get_pagesize(DBObject* self)
2935 {
2936     int err;
2937     u_int32_t pagesize;
2938
2939     CHECK_DB_NOT_CLOSED(self);
2940
2941     MYDB_BEGIN_ALLOW_THREADS;
2942     err = self->db->get_pagesize(self->db, &pagesize);
2943     MYDB_END_ALLOW_THREADS;
2944     RETURN_IF_ERR();
2945     return NUMBER_FromLong(pagesize);
2946 }
2947 #endif
2948
2949 static PyObject*
2950 DB_set_re_delim(DBObject* self, PyObject* args)
2951 {
2952     int err;
2953     char delim;
2954
2955     if (!PyArg_ParseTuple(args,"b:set_re_delim", &delim)) {
2956         PyErr_Clear();
2957         if (!PyArg_ParseTuple(args,"c:set_re_delim", &delim))
2958             return NULL;
2959     }
2960
2961     CHECK_DB_NOT_CLOSED(self);
2962
2963     MYDB_BEGIN_ALLOW_THREADS;
2964     err = self->db->set_re_delim(self->db, delim);
2965     MYDB_END_ALLOW_THREADS;
2966     RETURN_IF_ERR();
2967     RETURN_NONE();
2968 }
2969
2970 #if (DBVER >= 42)
2971 static PyObject*
2972 DB_get_re_delim(DBObject* self)
2973 {
2974     int err, re_delim;
2975
2976     CHECK_DB_NOT_CLOSED(self);
2977
2978     MYDB_BEGIN_ALLOW_THREADS;
2979     err = self->db->get_re_delim(self->db, &re_delim);
2980     MYDB_END_ALLOW_THREADS;
2981     RETURN_IF_ERR();
2982     return NUMBER_FromLong(re_delim);
2983 }
2984 #endif
2985
2986 static PyObject*
2987 DB_set_re_len(DBObject* self, PyObject* args)
2988 {
2989     int err, len;
2990
2991     if (!PyArg_ParseTuple(args,"i:set_re_len", &len))
2992         return NULL;
2993     CHECK_DB_NOT_CLOSED(self);
2994
2995     MYDB_BEGIN_ALLOW_THREADS;
2996     err = self->db->set_re_len(self->db, len);
2997     MYDB_END_ALLOW_THREADS;
2998     RETURN_IF_ERR();
2999     RETURN_NONE();
3000 }
3001
3002 #if (DBVER >= 42)
3003 static PyObject*
3004 DB_get_re_len(DBObject* self)
3005 {
3006     int err;
3007     u_int32_t re_len;
3008
3009     CHECK_DB_NOT_CLOSED(self);
3010
3011     MYDB_BEGIN_ALLOW_THREADS;
3012     err = self->db->get_re_len(self->db, &re_len);
3013     MYDB_END_ALLOW_THREADS;
3014     RETURN_IF_ERR();
3015     return NUMBER_FromLong(re_len);
3016 }
3017 #endif
3018
3019 static PyObject*
3020 DB_set_re_pad(DBObject* self, PyObject* args)
3021 {
3022     int err;
3023     char pad;
3024
3025     if (!PyArg_ParseTuple(args,"b:set_re_pad", &pad)) {
3026         PyErr_Clear();
3027         if (!PyArg_ParseTuple(args,"c:set_re_pad", &pad))
3028             return NULL;
3029     }
3030     CHECK_DB_NOT_CLOSED(self);
3031
3032     MYDB_BEGIN_ALLOW_THREADS;
3033     err = self->db->set_re_pad(self->db, pad);
3034     MYDB_END_ALLOW_THREADS;
3035     RETURN_IF_ERR();
3036     RETURN_NONE();
3037 }
3038
3039 #if (DBVER >= 42)
3040 static PyObject*
3041 DB_get_re_pad(DBObject* self)
3042 {
3043     int err, re_pad;
3044
3045     CHECK_DB_NOT_CLOSED(self);
3046
3047     MYDB_BEGIN_ALLOW_THREADS;
3048     err = self->db->get_re_pad(self->db, &re_pad);
3049     MYDB_END_ALLOW_THREADS;
3050     RETURN_IF_ERR();
3051     return NUMBER_FromLong(re_pad);
3052 }
3053 #endif
3054
3055 static PyObject*
3056 DB_set_re_source(DBObject* self, PyObject* args)
3057 {
3058     int err;
3059     char *source;
3060
3061     if (!PyArg_ParseTuple(args,"s:set_re_source", &source))
3062         return NULL;
3063     CHECK_DB_NOT_CLOSED(self);
3064
3065     MYDB_BEGIN_ALLOW_THREADS;
3066     err = self->db->set_re_source(self->db, source);
3067     MYDB_END_ALLOW_THREADS;
3068     RETURN_IF_ERR();
3069     RETURN_NONE();
3070 }
3071
3072 #if (DBVER >= 42)
3073 static PyObject*
3074 DB_get_re_source(DBObject* self)
3075 {
3076     int err;
3077     const char *source;
3078
3079     CHECK_DB_NOT_CLOSED(self);
3080
3081     MYDB_BEGIN_ALLOW_THREADS;
3082     err = self->db->get_re_source(self->db, &source);
3083     MYDB_END_ALLOW_THREADS;
3084     RETURN_IF_ERR();
3085     return PyBytes_FromString(source);
3086 }
3087 #endif
3088
3089 static PyObject*
3090 DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
3091 {
3092     int err, flags = 0, type;
3093     void* sp;
3094     PyObject* d;
3095 #if (DBVER >= 43)
3096     PyObject* txnobj = NULL;
3097     DB_TXN *txn = NULL;
3098     static char* kwnames[] = { "flags", "txn", NULL };
3099 #else
3100     static char* kwnames[] = { "flags", NULL };
3101 #endif
3102
3103 #if (DBVER >= 43)
3104     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO:stat", kwnames,
3105                                      &flags, &txnobj))
3106         return NULL;
3107     if (!checkTxnObj(txnobj, &txn))
3108         return NULL;
3109 #else
3110     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags))
3111         return NULL;
3112 #endif
3113     CHECK_DB_NOT_CLOSED(self);
3114
3115     MYDB_BEGIN_ALLOW_THREADS;
3116 #if (DBVER >= 43)
3117     err = self->db->stat(self->db, txn, &sp, flags);
3118 #else
3119     err = self->db->stat(self->db, &sp, flags);
3120 #endif
3121     MYDB_END_ALLOW_THREADS;
3122     RETURN_IF_ERR();
3123
3124     /* Turn the stat structure into a dictionary */
3125     type = _DB_get_type(self);
3126     if ((type == -1) || ((d = PyDict_New()) == NULL)) {
3127         free(sp);
3128         return NULL;
3129     }
3130
3131 #define MAKE_HASH_ENTRY(name)  _addIntToDict(d, #name, ((DB_HASH_STAT*)sp)->hash_##name)
3132 #define MAKE_BT_ENTRY(name)    _addIntToDict(d, #name, ((DB_BTREE_STAT*)sp)->bt_##name)
3133 #define MAKE_QUEUE_ENTRY(name) _addIntToDict(d, #name, ((DB_QUEUE_STAT*)sp)->qs_##name)
3134
3135     switch (type) {
3136     case DB_HASH:
3137         MAKE_HASH_ENTRY(magic);
3138         MAKE_HASH_ENTRY(version);
3139         MAKE_HASH_ENTRY(nkeys);
3140         MAKE_HASH_ENTRY(ndata);
3141 #if (DBVER >= 46)
3142         MAKE_HASH_ENTRY(pagecnt);
3143 #endif
3144         MAKE_HASH_ENTRY(pagesize);
3145         MAKE_HASH_ENTRY(ffactor);
3146         MAKE_HASH_ENTRY(buckets);
3147         MAKE_HASH_ENTRY(free);
3148         MAKE_HASH_ENTRY(bfree);
3149         MAKE_HASH_ENTRY(bigpages);
3150         MAKE_HASH_ENTRY(big_bfree);
3151         MAKE_HASH_ENTRY(overflows);
3152         MAKE_HASH_ENTRY(ovfl_free);
3153         MAKE_HASH_ENTRY(dup);
3154         MAKE_HASH_ENTRY(dup_free);
3155         break;
3156
3157     case DB_BTREE:
3158     case DB_RECNO:
3159         MAKE_BT_ENTRY(magic);
3160         MAKE_BT_ENTRY(version);
3161         MAKE_BT_ENTRY(nkeys);
3162         MAKE_BT_ENTRY(ndata);
3163 #if (DBVER >= 46)
3164         MAKE_BT_ENTRY(pagecnt);
3165 #endif
3166         MAKE_BT_ENTRY(pagesize);
3167         MAKE_BT_ENTRY(minkey);
3168         MAKE_BT_ENTRY(re_len);
3169         MAKE_BT_ENTRY(re_pad);
3170         MAKE_BT_ENTRY(levels);
3171         MAKE_BT_ENTRY(int_pg);
3172         MAKE_BT_ENTRY(leaf_pg);
3173         MAKE_BT_ENTRY(dup_pg);
3174         MAKE_BT_ENTRY(over_pg);
3175 #if (DBVER >= 43)
3176         MAKE_BT_ENTRY(empty_pg);
3177 #endif
3178         MAKE_BT_ENTRY(free);
3179         MAKE_BT_ENTRY(int_pgfree);
3180         MAKE_BT_ENTRY(leaf_pgfree);
3181         MAKE_BT_ENTRY(dup_pgfree);
3182         MAKE_BT_ENTRY(over_pgfree);
3183         break;
3184
3185     case DB_QUEUE:
3186         MAKE_QUEUE_ENTRY(magic);
3187         MAKE_QUEUE_ENTRY(version);
3188         MAKE_QUEUE_ENTRY(nkeys);
3189         MAKE_QUEUE_ENTRY(ndata);
3190         MAKE_QUEUE_ENTRY(pagesize);
3191         MAKE_QUEUE_ENTRY(extentsize);
3192         MAKE_QUEUE_ENTRY(pages);
3193         MAKE_QUEUE_ENTRY(re_len);
3194         MAKE_QUEUE_ENTRY(re_pad);
3195         MAKE_QUEUE_ENTRY(pgfree);
3196 #if (DBVER == 31)
3197         MAKE_QUEUE_ENTRY(start);
3198 #endif
3199         MAKE_QUEUE_ENTRY(first_recno);
3200         MAKE_QUEUE_ENTRY(cur_recno);
3201         break;
3202
3203     default:
3204         PyErr_SetString(PyExc_TypeError, "Unknown DB type, unable to stat");
3205         Py_DECREF(d);
3206         d = NULL;
3207     }
3208
3209 #undef MAKE_HASH_ENTRY
3210 #undef MAKE_BT_ENTRY
3211 #undef MAKE_QUEUE_ENTRY
3212
3213     free(sp);
3214     return d;
3215 }
3216
3217 #if (DBVER >= 43)
3218 static PyObject*
3219 DB_stat_print(DBObject* self, PyObject* args, PyObject *kwargs)
3220 {
3221     int err;
3222     int flags=0;
3223     static char* kwnames[] = { "flags", NULL };
3224
3225     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat_print",
3226                 kwnames, &flags))
3227     {
3228         return NULL;
3229     }
3230     CHECK_DB_NOT_CLOSED(self);
3231     MYDB_BEGIN_ALLOW_THREADS;
3232     err = self->db->stat_print(self->db, flags);
3233     MYDB_END_ALLOW_THREADS;
3234     RETURN_IF_ERR();
3235     RETURN_NONE();
3236 }
3237 #endif
3238
3239
3240 static PyObject*
3241 DB_sync(DBObject* self, PyObject* args)
3242 {
3243     int err;
3244     int flags = 0;
3245
3246     if (!PyArg_ParseTuple(args,"|i:sync", &flags ))
3247         return NULL;
3248     CHECK_DB_NOT_CLOSED(self);
3249
3250     MYDB_BEGIN_ALLOW_THREADS;
3251     err = self->db->sync(self->db, flags);
3252     MYDB_END_ALLOW_THREADS;
3253     RETURN_IF_ERR();
3254     RETURN_NONE();
3255 }
3256
3257
3258 static PyObject*
3259 DB_truncate(DBObject* self, PyObject* args, PyObject* kwargs)
3260 {
3261     int err, flags=0;
3262     u_int32_t count=0;
3263     PyObject* txnobj = NULL;
3264     DB_TXN *txn = NULL;
3265     static char* kwnames[] = { "txn", "flags", NULL };
3266
3267     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames,
3268                                      &txnobj, &flags))
3269         return NULL;
3270     CHECK_DB_NOT_CLOSED(self);
3271     if (!checkTxnObj(txnobj, &txn))
3272         return NULL;
3273
3274     MYDB_BEGIN_ALLOW_THREADS;
3275     err = self->db->truncate(self->db, txn, &count, flags);
3276     MYDB_END_ALLOW_THREADS;
3277     RETURN_IF_ERR();
3278     return NUMBER_FromLong(count);
3279 }
3280
3281
3282 static PyObject*
3283 DB_upgrade(DBObject* self, PyObject* args)
3284 {
3285     int err, flags=0;
3286     char *filename;
3287
3288     if (!PyArg_ParseTuple(args,"s|i:upgrade", &filename, &flags))
3289         return NULL;
3290     CHECK_DB_NOT_CLOSED(self);
3291
3292     MYDB_BEGIN_ALLOW_THREADS;
3293     err = self->db->upgrade(self->db, filename, flags);
3294     MYDB_END_ALLOW_THREADS;
3295     RETURN_IF_ERR();
3296     RETURN_NONE();
3297 }
3298
3299
3300 static PyObject*
3301 DB_verify(DBObject* self, PyObject* args, PyObject* kwargs)
3302 {
3303     int err, flags=0;
3304     char* fileName;
3305     char* dbName=NULL;
3306     char* outFileName=NULL;
3307     FILE* outFile=NULL;
3308     static char* kwnames[] = { "filename", "dbname", "outfile", "flags",
3309                                      NULL };
3310
3311     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzi:verify", kwnames,
3312                                      &fileName, &dbName, &outFileName, &flags))
3313         return NULL;
3314
3315     CHECK_DB_NOT_CLOSED(self);
3316     if (outFileName)
3317         outFile = fopen(outFileName, "w");
3318         /* XXX(nnorwitz): it should probably be an exception if outFile
3319            can't be opened. */
3320
3321     {  /* DB.verify acts as a DB handle destructor (like close) */
3322         PyObject *error;
3323
3324         error=DB_close_internal(self, 0, 1);
3325         if (error) {
3326           return error;
3327         }
3328      }
3329
3330     MYDB_BEGIN_ALLOW_THREADS;
3331     err = self->db->verify(self->db, fileName, dbName, outFile, flags);
3332     MYDB_END_ALLOW_THREADS;
3333
3334     self->db = NULL;  /* Implicit close; related objects already released */
3335
3336     if (outFile)
3337         fclose(outFile);
3338
3339     RETURN_IF_ERR();
3340     RETURN_NONE();
3341 }
3342
3343
3344 static PyObject*
3345 DB_set_get_returns_none(DBObject* self, PyObject* args)
3346 {
3347     int flags=0;
3348     int oldValue=0;
3349
3350     if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
3351         return NULL;
3352     CHECK_DB_NOT_CLOSED(self);
3353
3354     if (self->moduleFlags.getReturnsNone)
3355         ++oldValue;
3356     if (self->moduleFlags.cursorSetReturnsNone)
3357         ++oldValue;
3358     self->moduleFlags.getReturnsNone = (flags >= 1);
3359     self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
3360     return NUMBER_FromLong(oldValue);
3361 }
3362
3363 static PyObject*
3364 DB_set_encrypt(DBObject* self, PyObject* args, PyObject* kwargs)
3365 {
3366     int err;
3367     u_int32_t flags=0;
3368     char *passwd = NULL;
3369     static char* kwnames[] = { "passwd", "flags", NULL };
3370
3371     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames,
3372                 &passwd, &flags)) {
3373         return NULL;
3374     }
3375
3376     MYDB_BEGIN_ALLOW_THREADS;
3377     err = self->db->set_encrypt(self->db, passwd, flags);
3378     MYDB_END_ALLOW_THREADS;
3379
3380     RETURN_IF_ERR();
3381     RETURN_NONE();
3382 }
3383
3384 #if (DBVER >= 42)
3385 static PyObject*
3386 DB_get_encrypt_flags(DBObject* self)
3387 {
3388     int err;
3389     u_int32_t flags;
3390
3391     MYDB_BEGIN_ALLOW_THREADS;
3392     err = self->db->get_encrypt_flags(self->db, &flags);
3393     MYDB_END_ALLOW_THREADS;
3394
3395     RETURN_IF_ERR();
3396
3397     return NUMBER_FromLong(flags);
3398 }
3399 #endif
3400
3401
3402
3403 /*-------------------------------------------------------------- */
3404 /* Mapping and Dictionary-like access routines */
3405
3406 Py_ssize_t DB_length(PyObject* _self)
3407 {
3408     int err;
3409     Py_ssize_t size = 0;
3410     void* sp;
3411     DBObject* self = (DBObject*)_self;
3412
3413     if (self->db == NULL) {
3414         PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed");
3415         if (t) {
3416             PyErr_SetObject(DBError, t);
3417             Py_DECREF(t);
3418         }
3419         return -1;
3420     }
3421
3422     MYDB_BEGIN_ALLOW_THREADS;
3423 #if (DBVER >= 43)
3424     err = self->db->stat(self->db, /*txnid*/ NULL, &sp, 0);
3425 #else
3426     err = self->db->stat(self->db, &sp, 0);
3427 #endif
3428     MYDB_END_ALLOW_THREADS;
3429
3430     /* All the stat structures have matching fields upto the ndata field,
3431        so we can use any of them for the type cast */
3432     size = ((DB_BTREE_STAT*)sp)->bt_ndata;
3433
3434     if (err)
3435         return -1;
3436
3437     free(sp);
3438     return size;
3439 }
3440
3441
3442 PyObject* DB_subscript(DBObject* self, PyObject* keyobj)
3443 {
3444     int err;
3445     PyObject* retval;
3446     DBT key;
3447     DBT data;
3448
3449     CHECK_DB_NOT_CLOSED(self);
3450     if (!make_key_dbt(self, keyobj, &key, NULL))
3451         return NULL;
3452
3453     CLEAR_DBT(data);
3454     if (CHECK_DBFLAG(self, DB_THREAD)) {
3455         /* Tell Berkeley DB to malloc the return value (thread safe) */
3456         data.flags = DB_DBT_MALLOC;
3457     }
3458     MYDB_BEGIN_ALLOW_THREADS;
3459     err = self->db->get(self->db, NULL, &key, &data, 0);
3460     MYDB_END_ALLOW_THREADS;
3461     if (err == DB_NOTFOUND || err == DB_KEYEMPTY) {
3462         PyErr_SetObject(PyExc_KeyError, keyobj);
3463         retval = NULL;
3464     }
3465     else if (makeDBError(err)) {
3466         retval = NULL;
3467     }
3468     else {
3469         retval = Build_PyString(data.data, data.size);
3470         FREE_DBT(data);
3471     }
3472
3473     FREE_DBT(key);
3474     return retval;
3475 }
3476
3477
3478 static int
3479 DB_ass_sub(DBObject* self, PyObject* keyobj, PyObject* dataobj)
3480 {
3481     DBT key, data;
3482     int retval;
3483     int flags = 0;
3484
3485     if (self->db == NULL) {
3486         PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed");
3487         if (t) {
3488             PyErr_SetObject(DBError, t);
3489             Py_DECREF(t);
3490         }
3491         return -1;
3492     }
3493
3494     if (!make_key_dbt(self, keyobj, &key, NULL))
3495         return -1;
3496
3497     if (dataobj != NULL) {
3498         if (!make_dbt(dataobj, &data))
3499             retval =  -1;
3500         else {
3501             if (self->setflags & (DB_DUP|DB_DUPSORT))
3502                 /* dictionaries shouldn't have duplicate keys */
3503                 flags = DB_NOOVERWRITE;
3504             retval = _DB_put(self, NULL, &key, &data, flags);
3505
3506             if ((retval == -1) &&  (self->setflags & (DB_DUP|DB_DUPSORT))) {
3507                 /* try deleting any old record that matches and then PUT it
3508                  * again... */
3509                 _DB_delete(self, NULL, &key, 0);
3510                 PyErr_Clear();
3511                 retval = _DB_put(self, NULL, &key, &data, flags);
3512             }
3513         }
3514     }
3515     else {
3516         /* dataobj == NULL, so delete the key */
3517         retval = _DB_delete(self, NULL, &key, 0);
3518     }
3519     FREE_DBT(key);
3520     return retval;
3521 }
3522
3523
3524 static PyObject*
3525 _DB_has_key(DBObject* self, PyObject* keyobj, PyObject* txnobj)
3526 {
3527     int err;
3528     DBT key;
3529     DB_TXN *txn = NULL;
3530
3531     CHECK_DB_NOT_CLOSED(self);
3532     if (!make_key_dbt(self, keyobj, &key, NULL))
3533         return NULL;
3534     if (!checkTxnObj(txnobj, &txn)) {
3535         FREE_DBT(key);
3536         return NULL;
3537     }
3538
3539 #if (DBVER < 46)
3540     /* This causes DB_BUFFER_SMALL to be returned when the db has the key because
3541        it has a record but can't allocate a buffer for the data.  This saves
3542        having to deal with data we won't be using.
3543      */
3544     {
3545         DBT data ;
3546         CLEAR_DBT(data);
3547         data.flags = DB_DBT_USERMEM;
3548
3549         MYDB_BEGIN_ALLOW_THREADS;
3550         err = self->db->get(self->db, txn, &key, &data, 0);
3551         MYDB_END_ALLOW_THREADS;
3552     }
3553 #else
3554     MYDB_BEGIN_ALLOW_THREADS;
3555     err = self->db->exists(self->db, txn, &key, 0);
3556     MYDB_END_ALLOW_THREADS;
3557 #endif
3558
3559     FREE_DBT(key);
3560
3561     /*
3562     ** DB_BUFFER_SMALL is only used if we use "get".
3563     ** We can drop it when we only use "exists",
3564     ** when we drop suport for Berkeley DB < 4.6.
3565     */
3566     if (err == DB_BUFFER_SMALL || err == 0) {
3567         Py_INCREF(Py_True);
3568         return Py_True;
3569     } else if (err == DB_NOTFOUND || err == DB_KEYEMPTY) {
3570         Py_INCREF(Py_False);
3571         return Py_False;
3572     }
3573
3574     makeDBError(err);
3575     return NULL;
3576 }
3577
3578 static PyObject*
3579 DB_has_key(DBObject* self, PyObject* args, PyObject* kwargs)
3580 {
3581     PyObject* keyobj;
3582     PyObject* txnobj = NULL;
3583     static char* kwnames[] = {"key","txn", NULL};
3584
3585     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:has_key", kwnames,
3586                 &keyobj, &txnobj))
3587         return NULL;
3588
3589     return _DB_has_key(self, keyobj, txnobj);
3590 }
3591
3592
3593 static int DB_contains(DBObject* self, PyObject* keyobj)
3594 {
3595     PyObject* result;
3596     int result2 = 0;
3597
3598     result = _DB_has_key(self, keyobj, NULL) ;
3599     if (result == NULL) {
3600         return -1; /* Propague exception */
3601     }
3602     if (result != Py_False) {
3603         result2 = 1;
3604     }
3605
3606     Py_DECREF(result);
3607     return result2;
3608 }
3609
3610
3611 #define _KEYS_LIST      1
3612 #define _VALUES_LIST    2
3613 #define _ITEMS_LIST     3
3614
3615 static PyObject*
3616 _DB_make_list(DBObject* self, DB_TXN* txn, int type)
3617 {
3618     int err, dbtype;
3619     DBT key;
3620     DBT data;
3621     DBC *cursor;
3622     PyObject* list;
3623     PyObject* item = NULL;
3624
3625     CHECK_DB_NOT_CLOSED(self);
3626     CLEAR_DBT(key);
3627     CLEAR_DBT(data);
3628
3629     dbtype = _DB_get_type(self);
3630     if (dbtype == -1)
3631         return NULL;
3632
3633     list = PyList_New(0);
3634     if (list == NULL)
3635         return NULL;
3636
3637     /* get a cursor */
3638     MYDB_BEGIN_ALLOW_THREADS;
3639     err = self->db->cursor(self->db, txn, &cursor, 0);
3640     MYDB_END_ALLOW_THREADS;
3641     if (makeDBError(err)) {
3642         Py_DECREF(list);
3643         return NULL;
3644     }
3645
3646     while (1) { /* use the cursor to traverse the DB, collecting items */
3647         MYDB_BEGIN_ALLOW_THREADS;
3648         err = _DBC_get(cursor, &key, &data, DB_NEXT);
3649         MYDB_END_ALLOW_THREADS;
3650
3651         if (err) {
3652             /* for any error, break out of the loop */
3653             break;
3654         }
3655
3656         switch (type) {
3657         case _KEYS_LIST:
3658             switch(dbtype) {
3659             case DB_BTREE:
3660             case DB_HASH:
3661             default:
3662                 item = Build_PyString(key.data, key.size);
3663                 break;
3664             case DB_RECNO:
3665             case DB_QUEUE:
3666                 item = NUMBER_FromLong(*((db_recno_t*)key.data));
3667                 break;
3668             }
3669             break;
3670
3671         case _VALUES_LIST:
3672             item = Build_PyString(data.data, data.size);
3673             break;
3674
3675         case _ITEMS_LIST:
3676             switch(dbtype) {
3677             case DB_BTREE:
3678             case DB_HASH:
3679             default:
3680                 item = BuildValue_SS(key.data, key.size, data.data, data.size);
3681                 break;
3682             case DB_RECNO:
3683             case DB_QUEUE:
3684                 item = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3685                 break;
3686             }
3687             break;
3688         default:
3689             PyErr_Format(PyExc_ValueError, "Unknown key type 0x%x", type);
3690             item = NULL;
3691             break;
3692         }
3693         if (item == NULL) {
3694             Py_DECREF(list);
3695             list = NULL;
3696             goto done;
3697         }
3698         if (PyList_Append(list, item)) {
3699             Py_DECREF(list);
3700             Py_DECREF(item);
3701             list = NULL;
3702             goto done;
3703         }
3704         Py_DECREF(item);
3705     }
3706
3707     /* DB_NOTFOUND || DB_KEYEMPTY is okay, it means we got to the end */
3708     if (err != DB_NOTFOUND && err != DB_KEYEMPTY && makeDBError(err)) {
3709         Py_DECREF(list);
3710         list = NULL;
3711     }
3712
3713  done:
3714     MYDB_BEGIN_ALLOW_THREADS;
3715     _DBC_close(cursor);
3716     MYDB_END_ALLOW_THREADS;
3717     return list;
3718 }
3719
3720
3721 static PyObject*
3722 DB_keys(DBObject* self, PyObject* args)
3723 {
3724     PyObject* txnobj = NULL;
3725     DB_TXN *txn = NULL;
3726
3727     if (!PyArg_UnpackTuple(args, "keys", 0, 1, &txnobj))
3728         return NULL;
3729     if (!checkTxnObj(txnobj, &txn))
3730         return NULL;
3731     return _DB_make_list(self, txn, _KEYS_LIST);
3732 }
3733
3734
3735 static PyObject*
3736 DB_items(DBObject* self, PyObject* args)
3737 {
3738     PyObject* txnobj = NULL;
3739     DB_TXN *txn = NULL;
3740
3741     if (!PyArg_UnpackTuple(args, "items", 0, 1, &txnobj))
3742         return NULL;
3743     if (!checkTxnObj(txnobj, &txn))
3744         return NULL;
3745     return _DB_make_list(self, txn, _ITEMS_LIST);
3746 }
3747
3748
3749 static PyObject*
3750 DB_values(DBObject* self, PyObject* args)
3751 {
3752     PyObject* txnobj = NULL;
3753     DB_TXN *txn = NULL;
3754
3755     if (!PyArg_UnpackTuple(args, "values", 0, 1, &txnobj))
3756         return NULL;
3757     if (!checkTxnObj(txnobj, &txn))
3758         return NULL;
3759     return _DB_make_list(self, txn, _VALUES_LIST);
3760 }
3761
3762 /* --------------------------------------------------------------------- */
3763 /* DBLogCursor methods */
3764
3765
3766 static PyObject*
3767 DBLogCursor_close_internal(DBLogCursorObject* self)
3768 {
3769     int err = 0;
3770
3771     if (self->logc != NULL) {
3772         EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
3773
3774         MYDB_BEGIN_ALLOW_THREADS;
3775         err = self->logc->close(self->logc, 0);
3776         MYDB_END_ALLOW_THREADS;
3777         self->logc = NULL;
3778     }
3779     RETURN_IF_ERR();
3780     RETURN_NONE();
3781 }
3782
3783 static PyObject*
3784 DBLogCursor_close(DBLogCursorObject* self)
3785 {
3786     return DBLogCursor_close_internal(self);
3787 }
3788
3789
3790 static PyObject*
3791 _DBLogCursor_get(DBLogCursorObject* self, int flag, DB_LSN *lsn2)
3792 {
3793     int err;
3794     DBT data;
3795     DB_LSN lsn = {0, 0};
3796     PyObject *dummy, *retval;
3797
3798     CLEAR_DBT(data);
3799     data.flags = DB_DBT_MALLOC; /* Berkeley DB must do the malloc */
3800
3801     CHECK_LOGCURSOR_NOT_CLOSED(self);
3802
3803     if (lsn2)
3804         lsn = *lsn2;
3805
3806     MYDB_BEGIN_ALLOW_THREADS;
3807     err = self->logc->get(self->logc, &lsn, &data, flag);
3808     MYDB_END_ALLOW_THREADS;
3809
3810     if (err == DB_NOTFOUND) {
3811         Py_INCREF(Py_None);
3812         retval = Py_None;
3813     }
3814     else if (makeDBError(err)) {
3815         retval = NULL;
3816     }
3817     else {
3818         retval = dummy = BuildValue_S(data.data, data.size);
3819         if (dummy) {
3820             retval = Py_BuildValue("(ii)O", lsn.file, lsn.offset, dummy);
3821             Py_DECREF(dummy);
3822         }
3823     }
3824
3825     FREE_DBT(data);
3826     return retval;
3827 }
3828
3829 static PyObject*
3830 DBLogCursor_current(DBLogCursorObject* self)
3831 {
3832     return _DBLogCursor_get(self, DB_CURRENT, NULL);
3833 }
3834
3835 static PyObject*
3836 DBLogCursor_first(DBLogCursorObject* self)
3837 {
3838     return _DBLogCursor_get(self, DB_FIRST, NULL);
3839 }
3840
3841 static PyObject*
3842 DBLogCursor_last(DBLogCursorObject* self)
3843 {
3844     return _DBLogCursor_get(self, DB_LAST, NULL);
3845 }
3846
3847 static PyObject*
3848 DBLogCursor_next(DBLogCursorObject* self)
3849 {
3850     return _DBLogCursor_get(self, DB_NEXT, NULL);
3851 }
3852
3853 static PyObject*
3854 DBLogCursor_prev(DBLogCursorObject* self)
3855 {
3856     return _DBLogCursor_get(self, DB_PREV, NULL);
3857 }
3858
3859 static PyObject*
3860 DBLogCursor_set(DBLogCursorObject* self, PyObject* args)
3861 {
3862     DB_LSN lsn;
3863
3864     if (!PyArg_ParseTuple(args, "(ii):set", &lsn.file, &lsn.offset))
3865         return NULL;
3866
3867     return _DBLogCursor_get(self, DB_SET, &lsn);
3868 }
3869
3870
3871
3872 /* --------------------------------------------------------------------- */
3873 /* DBCursor methods */
3874
3875
3876 static PyObject*
3877 DBC_close_internal(DBCursorObject* self)
3878 {
3879     int err = 0;
3880
3881     if (self->dbc != NULL) {
3882         EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
3883         if (self->txn) {
3884             EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
3885             self->txn=NULL;
3886         }
3887
3888         MYDB_BEGIN_ALLOW_THREADS;
3889         err = _DBC_close(self->dbc);
3890         MYDB_END_ALLOW_THREADS;
3891         self->dbc = NULL;
3892     }
3893     RETURN_IF_ERR();
3894     RETURN_NONE();
3895 }
3896
3897 static PyObject*
3898 DBC_close(DBCursorObject* self)
3899 {
3900     return DBC_close_internal(self);
3901 }
3902
3903
3904 static PyObject*
3905 DBC_count(DBCursorObject* self, PyObject* args)
3906 {
3907     int err = 0;
3908     db_recno_t count;
3909     int flags = 0;
3910
3911     if (!PyArg_ParseTuple(args, "|i:count", &flags))
3912         return NULL;
3913
3914     CHECK_CURSOR_NOT_CLOSED(self);
3915
3916     MYDB_BEGIN_ALLOW_THREADS;
3917     err = _DBC_count(self->dbc, &count, flags);
3918     MYDB_END_ALLOW_THREADS;
3919     RETURN_IF_ERR();
3920
3921     return NUMBER_FromLong(count);
3922 }
3923
3924
3925 static PyObject*
3926 DBC_current(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3927 {
3928     return _DBCursor_get(self,DB_CURRENT,args,kwargs,"|iii:current");
3929 }
3930
3931
3932 static PyObject*
3933 DBC_delete(DBCursorObject* self, PyObject* args)
3934 {
3935     int err, flags=0;
3936
3937     if (!PyArg_ParseTuple(args, "|i:delete", &flags))
3938         return NULL;
3939
3940     CHECK_CURSOR_NOT_CLOSED(self);
3941
3942     MYDB_BEGIN_ALLOW_THREADS;
3943     err = _DBC_del(self->dbc, flags);
3944     MYDB_END_ALLOW_THREADS;
3945     RETURN_IF_ERR();
3946
3947     RETURN_NONE();
3948 }
3949
3950
3951 static PyObject*
3952 DBC_dup(DBCursorObject* self, PyObject* args)
3953 {
3954     int err, flags =0;
3955     DBC* dbc = NULL;
3956
3957     if (!PyArg_ParseTuple(args, "|i:dup", &flags))
3958         return NULL;
3959
3960     CHECK_CURSOR_NOT_CLOSED(self);
3961
3962     MYDB_BEGIN_ALLOW_THREADS;
3963     err = _DBC_dup(self->dbc, &dbc, flags);
3964     MYDB_END_ALLOW_THREADS;
3965     RETURN_IF_ERR();
3966
3967     return (PyObject*) newDBCursorObject(dbc, self->txn, self->mydb);
3968 }
3969
3970 static PyObject*
3971 DBC_first(DBCursorObject* self, PyObject* args, PyObject* kwargs)
3972 {
3973     return _DBCursor_get(self,DB_FIRST,args,kwargs,"|iii:first");
3974 }
3975
3976
3977 static PyObject*
3978 DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3979 {
3980     int err, flags=0;
3981     PyObject* keyobj = NULL;
3982     PyObject* dataobj = NULL;
3983     PyObject* retval = NULL;
3984     int dlen = -1;
3985     int doff = -1;
3986     DBT key, data;
3987     static char* kwnames[] = { "key","data", "flags", "dlen", "doff",
3988                                      NULL };
3989
3990     CLEAR_DBT(key);
3991     CLEAR_DBT(data);
3992     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:get", &kwnames[2],
3993                                      &flags, &dlen, &doff))
3994     {
3995         PyErr_Clear();
3996         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:get",
3997                                          &kwnames[1],
3998                                          &keyobj, &flags, &dlen, &doff))
3999         {
4000             PyErr_Clear();
4001             if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:get",
4002                                              kwnames, &keyobj, &dataobj,
4003                                              &flags, &dlen, &doff))
4004             {
4005                 return NULL;
4006             }
4007         }
4008     }
4009
4010     CHECK_CURSOR_NOT_CLOSED(self);
4011
4012     if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
4013         return NULL;
4014     if ( (dataobj && !make_dbt(dataobj, &data)) ||
4015          (!add_partial_dbt(&data, dlen, doff)) )
4016     {
4017         FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
4018         return NULL;
4019     }
4020
4021     MYDB_BEGIN_ALLOW_THREADS;
4022     err = _DBC_get(self->dbc, &key, &data, flags);
4023     MYDB_END_ALLOW_THREADS;
4024
4025     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
4026             && self->mydb->moduleFlags.getReturnsNone) {
4027         Py_INCREF(Py_None);
4028         retval = Py_None;
4029     }
4030     else if (makeDBError(err)) {
4031         retval = NULL;
4032     }
4033     else {
4034         switch (_DB_get_type(self->mydb)) {
4035         case -1:
4036             retval = NULL;
4037             break;
4038         case DB_BTREE:
4039         case DB_HASH:
4040         default:
4041             retval = BuildValue_SS(key.data, key.size, data.data, data.size);
4042             break;
4043         case DB_RECNO:
4044         case DB_QUEUE:
4045             retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
4046             break;
4047         }
4048     }
4049     FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4050     return retval;
4051 }
4052
4053 static PyObject*
4054 DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4055 {
4056     int err, flags=0;
4057     PyObject* keyobj = NULL;
4058     PyObject* dataobj = NULL;
4059     PyObject* retval = NULL;
4060     int dlen = -1;
4061     int doff = -1;
4062     DBT key, pkey, data;
4063     static char* kwnames_keyOnly[] = { "key", "flags", "dlen", "doff", NULL };
4064     static char* kwnames[] = { "key", "data", "flags", "dlen", "doff", NULL };
4065
4066     CLEAR_DBT(key);
4067     CLEAR_DBT(data);
4068     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:pget", &kwnames[2],
4069                                      &flags, &dlen, &doff))
4070     {
4071         PyErr_Clear();
4072         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:pget",
4073                                          kwnames_keyOnly,
4074                                          &keyobj, &flags, &dlen, &doff))
4075         {
4076             PyErr_Clear();
4077             if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:pget",
4078                                              kwnames, &keyobj, &dataobj,
4079                                              &flags, &dlen, &doff))
4080             {
4081                 return NULL;
4082             }
4083         }
4084     }
4085
4086     CHECK_CURSOR_NOT_CLOSED(self);
4087
4088     if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
4089         return NULL;
4090     if ( (dataobj && !make_dbt(dataobj, &data)) ||
4091          (!add_partial_dbt(&data, dlen, doff)) ) {
4092         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4093         return NULL;
4094     }
4095
4096     CLEAR_DBT(pkey);
4097     pkey.flags = DB_DBT_MALLOC;
4098
4099     MYDB_BEGIN_ALLOW_THREADS;
4100     err = _DBC_pget(self->dbc, &key, &pkey, &data, flags);
4101     MYDB_END_ALLOW_THREADS;
4102
4103     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
4104             && self->mydb->moduleFlags.getReturnsNone) {
4105         Py_INCREF(Py_None);
4106         retval = Py_None;
4107     }
4108     else if (makeDBError(err)) {
4109         retval = NULL;
4110     }
4111     else {
4112         PyObject *pkeyObj;
4113         PyObject *dataObj;
4114         dataObj = Build_PyString(data.data, data.size);
4115
4116         if (self->mydb->primaryDBType == DB_RECNO ||
4117             self->mydb->primaryDBType == DB_QUEUE)
4118             pkeyObj = NUMBER_FromLong(*(int *)pkey.data);
4119         else
4120             pkeyObj = Build_PyString(pkey.data, pkey.size);
4121
4122         if (key.data && key.size) /* return key, pkey and data */
4123         {
4124             PyObject *keyObj;
4125             int type = _DB_get_type(self->mydb);
4126             if (type == DB_RECNO || type == DB_QUEUE)
4127                 keyObj = NUMBER_FromLong(*(int *)key.data);
4128             else
4129                 keyObj = Build_PyString(key.data, key.size);
4130 #if (PY_VERSION_HEX >= 0x02040000)
4131             retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
4132 #else
4133             retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj);
4134 #endif
4135             Py_DECREF(keyObj);
4136             FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4137         }
4138         else /* return just the pkey and data */
4139         {
4140 #if (PY_VERSION_HEX >= 0x02040000)
4141             retval = PyTuple_Pack(2, pkeyObj, dataObj);
4142 #else
4143             retval = Py_BuildValue("OO", pkeyObj, dataObj);
4144 #endif
4145         }
4146         Py_DECREF(dataObj);
4147         Py_DECREF(pkeyObj);
4148         FREE_DBT(pkey);
4149     }
4150     /* the only time REALLOC should be set is if we used an integer
4151      * key that make_key_dbt malloc'd for us.  always free these. */
4152     if (key.flags & DB_DBT_REALLOC) {  /* 'make_key_dbt' could do a 'malloc' */
4153         FREE_DBT(key);
4154     }
4155     return retval;
4156 }
4157
4158
4159 static PyObject*
4160 DBC_get_recno(DBCursorObject* self)
4161 {
4162     int err;
4163     db_recno_t recno;
4164     DBT key;
4165     DBT data;
4166
4167     CHECK_CURSOR_NOT_CLOSED(self);
4168
4169     CLEAR_DBT(key);
4170     CLEAR_DBT(data);
4171
4172     MYDB_BEGIN_ALLOW_THREADS;
4173     err = _DBC_get(self->dbc, &key, &data, DB_GET_RECNO);
4174     MYDB_END_ALLOW_THREADS;
4175     RETURN_IF_ERR();
4176
4177     recno = *((db_recno_t*)data.data);
4178     return NUMBER_FromLong(recno);
4179 }
4180
4181
4182 static PyObject*
4183 DBC_last(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4184 {
4185     return _DBCursor_get(self,DB_LAST,args,kwargs,"|iii:last");
4186 }
4187
4188
4189 static PyObject*
4190 DBC_next(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4191 {
4192     return _DBCursor_get(self,DB_NEXT,args,kwargs,"|iii:next");
4193 }
4194
4195
4196 static PyObject*
4197 DBC_prev(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4198 {
4199     return _DBCursor_get(self,DB_PREV,args,kwargs,"|iii:prev");
4200 }
4201
4202
4203 static PyObject*
4204 DBC_put(DBCursorObject* self, PyObject* args, PyObject* kwargs)
4205 {
4206     int err, flags = 0;
4207     PyObject* keyobj, *dataobj;
4208     DBT key, data;
4209     static char* kwnames[] = { "key", "data", "flags", "dlen", "doff",
4210                                      NULL };
4211     int dlen = -1;
4212     int doff = -1;
4213
4214     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iii:put", kwnames,
4215                                      &keyobj, &dataobj, &flags, &dlen, &doff))
4216         return NULL;
4217
4218     CHECK_CURSOR_NOT_CLOSED(self);
4219
4220     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
4221         return NULL;
4222     if (!make_dbt(dataobj, &data) ||
4223         !add_partial_dbt(&data, dlen, doff) )
4224     {
4225         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4226         return NULL;
4227     }
4228
4229     MYDB_BEGIN_ALLOW_THREADS;
4230     err = _DBC_put(self->dbc, &key, &data, flags);
4231     MYDB_END_ALLOW_THREADS;
4232     FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4233     RETURN_IF_ERR();
4234     RETURN_NONE();
4235 }
4236
4237
4238 static PyObject*
4239 DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4240 {
4241     int err, flags = 0;
4242     DBT key, data;
4243     PyObject* retval, *keyobj;
4244     static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL };
4245     int dlen = -1;
4246     int doff = -1;
4247
4248     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set", kwnames,
4249                                      &keyobj, &flags, &dlen, &doff))
4250         return NULL;
4251
4252     CHECK_CURSOR_NOT_CLOSED(self);
4253
4254     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
4255         return NULL;
4256
4257     CLEAR_DBT(data);
4258     if (!add_partial_dbt(&data, dlen, doff)) {
4259         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4260         return NULL;
4261     }
4262
4263     MYDB_BEGIN_ALLOW_THREADS;
4264     err = _DBC_get(self->dbc, &key, &data, flags|DB_SET);
4265     MYDB_END_ALLOW_THREADS;
4266     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
4267             && self->mydb->moduleFlags.cursorSetReturnsNone) {
4268         Py_INCREF(Py_None);
4269         retval = Py_None;
4270     }
4271     else if (makeDBError(err)) {
4272         retval = NULL;
4273     }
4274     else {
4275         switch (_DB_get_type(self->mydb)) {
4276         case -1:
4277             retval = NULL;
4278             break;
4279         case DB_BTREE:
4280         case DB_HASH:
4281         default:
4282             retval = BuildValue_SS(key.data, key.size, data.data, data.size);
4283             break;
4284         case DB_RECNO:
4285         case DB_QUEUE:
4286             retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
4287             break;
4288         }
4289         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4290     }
4291     /* the only time REALLOC should be set is if we used an integer
4292      * key that make_key_dbt malloc'd for us.  always free these. */
4293     if (key.flags & DB_DBT_REALLOC) {
4294         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4295     }
4296
4297     return retval;
4298 }
4299
4300
4301 static PyObject*
4302 DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
4303 {
4304     int err, flags = 0;
4305     DBT key, data;
4306     PyObject* retval, *keyobj;
4307     static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL };
4308     int dlen = -1;
4309     int doff = -1;
4310
4311     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set_range", kwnames,
4312                                      &keyobj, &flags, &dlen, &doff))
4313         return NULL;
4314
4315     CHECK_CURSOR_NOT_CLOSED(self);
4316
4317     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
4318         return NULL;
4319
4320     CLEAR_DBT(data);
4321     if (!add_partial_dbt(&data, dlen, doff)) {
4322         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4323         return NULL;
4324     }
4325     MYDB_BEGIN_ALLOW_THREADS;
4326     err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
4327     MYDB_END_ALLOW_THREADS;
4328     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
4329             && self->mydb->moduleFlags.cursorSetReturnsNone) {
4330         Py_INCREF(Py_None);
4331         retval = Py_None;
4332     }
4333     else if (makeDBError(err)) {
4334         retval = NULL;
4335     }
4336     else {
4337         switch (_DB_get_type(self->mydb)) {
4338         case -1:
4339             retval = NULL;
4340             break;
4341         case DB_BTREE:
4342         case DB_HASH:
4343         default:
4344             retval = BuildValue_SS(key.data, key.size, data.data, data.size);
4345             break;
4346         case DB_RECNO:
4347         case DB_QUEUE:
4348             retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
4349             break;
4350         }
4351         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4352     }
4353     /* the only time REALLOC should be set is if we used an integer
4354      * key that make_key_dbt malloc'd for us.  always free these. */
4355     if (key.flags & DB_DBT_REALLOC) {
4356         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4357     }
4358
4359     return retval;
4360 }
4361
4362 static PyObject*
4363 _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
4364                   int flags, unsigned int returnsNone)
4365 {
4366     int err;
4367     DBT key, data;
4368     PyObject* retval;
4369
4370     /* the caller did this:  CHECK_CURSOR_NOT_CLOSED(self); */
4371     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
4372         return NULL;
4373     if (!make_dbt(dataobj, &data)) {
4374         FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4375         return NULL;
4376     }
4377
4378     MYDB_BEGIN_ALLOW_THREADS;
4379     err = _DBC_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
4380     MYDB_END_ALLOW_THREADS;
4381     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && returnsNone) {
4382         Py_INCREF(Py_None);
4383         retval = Py_None;
4384     }
4385     else if (makeDBError(err)) {
4386         retval = NULL;
4387     }
4388     else {
4389         switch (_DB_get_type(self->mydb)) {
4390         case -1:
4391             retval = NULL;
4392             break;
4393         case DB_BTREE:
4394         case DB_HASH:
4395         default:
4396             retval = BuildValue_SS(key.data, key.size, data.data, data.size);
4397             break;
4398         case DB_RECNO:
4399         case DB_QUEUE:
4400             retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
4401             break;
4402         }
4403     }
4404
4405     FREE_DBT(key);  /* 'make_key_dbt' could do a 'malloc' */
4406     return retval;
4407 }
4408
4409 static PyObject*
4410 DBC_get_both(DBCursorObject* self, PyObject* args)
4411 {
4412     int flags=0;
4413     PyObject *keyobj, *dataobj;
4414
4415     if (!PyArg_ParseTuple(args, "OO|i:get_both", &keyobj, &dataobj, &flags))
4416         return NULL;
4417
4418     /* if the cursor is closed, self->mydb may be invalid */
4419     CHECK_CURSOR_NOT_CLOSED(self);
4420
4421     return _DBC_get_set_both(self, keyobj, dataobj, flags,
4422                 self->mydb->moduleFlags.getReturnsNone);
4423 }
4424
4425 /* Return size of entry */
4426 static PyObject*
4427 DBC_get_current_size(DBCursorObject* self)
4428 {
4429     int err, flags=DB_CURRENT;
4430     PyObject* retval = NULL;
4431     DBT key, data;
4432
4433     CHECK_CURSOR_NOT_CLOSED(self);
4434     CLEAR_DBT(key);
4435     CLEAR_DBT(data);
4436
4437     /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and thus
4438        getting the record size. */
4439     data.flags = DB_DBT_USERMEM;
4440     data.ulen = 0;
4441     MYDB_BEGIN_ALLOW_THREADS;
4442     err = _DBC_get(self->dbc, &key, &data, flags);
4443     MYDB_END_ALLOW_THREADS;
4444     if (err == DB_BUFFER_SMALL || !err) {
4445         /* DB_BUFFER_SMALL means positive size, !err means zero length value */
4446         retval = NUMBER_FromLong((long)data.size);
4447         err = 0;
4448     }
4449
4450     RETURN_IF_ERR();
4451     return retval;
4452 }
4453
4454 static PyObject*
4455 DBC_set_both(DBCursorObject* self, PyObject* args)
4456 {
4457     int flags=0;
4458     PyObject *keyobj, *dataobj;
4459
4460     if (!PyArg_ParseTuple(args, "OO|i:set_both", &keyobj, &dataobj, &flags))
4461         return NULL;
4462
4463     /* if the cursor is closed, self->mydb may be invalid */
4464     CHECK_CURSOR_NOT_CLOSED(self);
4465
4466     return _DBC_get_set_both(self, keyobj, dataobj, flags,
4467                 self->mydb->moduleFlags.cursorSetReturnsNone);
4468 }
4469
4470
4471 static PyObject*
4472 DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4473 {
4474     int err, irecno, flags=0;
4475     db_recno_t recno;
4476     DBT key, data;
4477     PyObject* retval;
4478     int dlen = -1;
4479     int doff = -1;
4480     static char* kwnames[] = { "recno","flags", "dlen", "doff", NULL };
4481
4482     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii:set_recno", kwnames,
4483                                      &irecno, &flags, &dlen, &doff))
4484       return NULL;
4485
4486     CHECK_CURSOR_NOT_CLOSED(self);
4487
4488     CLEAR_DBT(key);
4489     recno = (db_recno_t) irecno;
4490     /* use allocated space so DB will be able to realloc room for the real
4491      * key */
4492     key.data = malloc(sizeof(db_recno_t));
4493     if (key.data == NULL) {
4494         PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
4495         return NULL;
4496     }
4497     key.size = sizeof(db_recno_t);
4498     key.ulen = key.size;
4499     memcpy(key.data, &recno, sizeof(db_recno_t));
4500     key.flags = DB_DBT_REALLOC;
4501
4502     CLEAR_DBT(data);
4503     if (!add_partial_dbt(&data, dlen, doff)) {
4504         FREE_DBT(key);
4505         return NULL;
4506     }
4507
4508     MYDB_BEGIN_ALLOW_THREADS;
4509     err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
4510     MYDB_END_ALLOW_THREADS;
4511     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
4512             && self->mydb->moduleFlags.cursorSetReturnsNone) {
4513         Py_INCREF(Py_None);
4514         retval = Py_None;
4515     }
4516     else if (makeDBError(err)) {
4517         retval = NULL;
4518     }
4519     else {  /* Can only be used for BTrees, so no need to return int key */
4520         retval = BuildValue_SS(key.data, key.size, data.data, data.size);
4521     }
4522     FREE_DBT(key);
4523
4524     return retval;
4525 }
4526
4527
4528 static PyObject*
4529 DBC_consume(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4530 {
4531     return _DBCursor_get(self,DB_CONSUME,args,kwargs,"|iii:consume");
4532 }
4533
4534
4535 static PyObject*
4536 DBC_next_dup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4537 {
4538     return _DBCursor_get(self,DB_NEXT_DUP,args,kwargs,"|iii:next_dup");
4539 }
4540
4541
4542 static PyObject*
4543 DBC_next_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4544 {
4545     return _DBCursor_get(self,DB_NEXT_NODUP,args,kwargs,"|iii:next_nodup");
4546 }
4547
4548 #if (DBVER >= 46)
4549 static PyObject*
4550 DBC_prev_dup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4551 {
4552     return _DBCursor_get(self,DB_PREV_DUP,args,kwargs,"|iii:prev_dup");
4553 }
4554 #endif
4555
4556 static PyObject*
4557 DBC_prev_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
4558 {
4559     return _DBCursor_get(self,DB_PREV_NODUP,args,kwargs,"|iii:prev_nodup");
4560 }
4561
4562
4563 static PyObject*
4564 DBC_join_item(DBCursorObject* self, PyObject* args)
4565 {
4566     int err, flags=0;
4567     DBT key, data;
4568     PyObject* retval;
4569
4570     if (!PyArg_ParseTuple(args, "|i:join_item", &flags))
4571         return NULL;
4572
4573     CHECK_CURSOR_NOT_CLOSED(self);
4574
4575     CLEAR_DBT(key);
4576     CLEAR_DBT(data);
4577
4578     MYDB_BEGIN_ALLOW_THREADS;
4579     err = _DBC_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
4580     MYDB_END_ALLOW_THREADS;
4581     if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
4582             && self->mydb->moduleFlags.getReturnsNone) {
4583         Py_INCREF(Py_None);
4584         retval = Py_None;
4585     }
4586     else if (makeDBError(err)) {
4587         retval = NULL;
4588     }
4589     else {
4590         retval = BuildValue_S(key.data, key.size);
4591     }
4592
4593     return retval;
4594 }
4595
4596
4597 #if (DBVER >= 46)
4598 static PyObject*
4599 DBC_set_priority(DBCursorObject* self, PyObject* args, PyObject* kwargs)
4600 {
4601     int err, priority;
4602     static char* kwnames[] = { "priority", NULL };
4603
4604     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:set_priority", kwnames,
4605                                      &priority))
4606         return NULL;
4607
4608     CHECK_CURSOR_NOT_CLOSED(self);
4609
4610     MYDB_BEGIN_ALLOW_THREADS;
4611     err = self->dbc->set_priority(self->dbc, priority);
4612     MYDB_END_ALLOW_THREADS;
4613     RETURN_IF_ERR();
4614     RETURN_NONE();
4615 }
4616
4617
4618 static PyObject*
4619 DBC_get_priority(DBCursorObject* self)
4620 {
4621     int err;
4622     DB_CACHE_PRIORITY priority;
4623
4624     CHECK_CURSOR_NOT_CLOSED(self);
4625
4626     MYDB_BEGIN_ALLOW_THREADS;
4627     err = self->dbc->get_priority(self->dbc, &priority);
4628     MYDB_END_ALLOW_THREADS;
4629     RETURN_IF_ERR();
4630     return NUMBER_FromLong(priority);
4631 }
4632 #endif
4633
4634
4635
4636 /* --------------------------------------------------------------------- */
4637 /* DBEnv methods */
4638
4639
4640 static PyObject*
4641 DBEnv_close_internal(DBEnvObject* self, int flags)
4642 {
4643     PyObject *dummy;
4644     int err;
4645
4646     if (!self->closed) {      /* Don't close more than once */
4647         while(self->children_txns) {
4648             dummy = DBTxn_abort_discard_internal(self->children_txns, 0);
4649             Py_XDECREF(dummy);
4650         }
4651         while(self->children_dbs) {
4652             dummy = DB_close_internal(self->children_dbs, 0, 0);
4653             Py_XDECREF(dummy);
4654         }
4655         while(self->children_logcursors) {
4656             dummy = DBLogCursor_close_internal(self->children_logcursors);
4657             Py_XDECREF(dummy);
4658         }
4659     }
4660
4661     self->closed = 1;
4662     if (self->db_env) {
4663         MYDB_BEGIN_ALLOW_THREADS;
4664         err = self->db_env->close(self->db_env, flags);
4665         MYDB_END_ALLOW_THREADS;
4666         /* after calling DBEnv->close, regardless of error, this DBEnv
4667          * may not be accessed again (Berkeley DB docs). */
4668         self->db_env = NULL;
4669         RETURN_IF_ERR();
4670     }
4671     RETURN_NONE();
4672 }
4673
4674 static PyObject*
4675 DBEnv_close(DBEnvObject* self, PyObject* args)
4676 {
4677     int flags = 0;
4678
4679     if (!PyArg_ParseTuple(args, "|i:close", &flags))
4680         return NULL;
4681     return DBEnv_close_internal(self, flags);
4682 }
4683
4684
4685 static PyObject*
4686 DBEnv_open(DBEnvObject* self, PyObject* args)
4687 {
4688     int err, flags=0, mode=0660;
4689     char *db_home;
4690
4691     if (!PyArg_ParseTuple(args, "z|ii:open", &db_home, &flags, &mode))
4692         return NULL;
4693
4694     CHECK_ENV_NOT_CLOSED(self);
4695
4696     MYDB_BEGIN_ALLOW_THREADS;
4697     err = self->db_env->open(self->db_env, db_home, flags, mode);
4698     MYDB_END_ALLOW_THREADS;
4699     RETURN_IF_ERR();
4700     self->closed = 0;
4701     self->flags = flags;
4702     RETURN_NONE();
4703 }
4704
4705
4706 static PyObject*
4707 DBEnv_memp_stat(DBEnvObject* self, PyObject* args, PyObject *kwargs)
4708 {
4709     int err;
4710     DB_MPOOL_STAT *gsp;
4711     DB_MPOOL_FSTAT **fsp, **fsp2;
4712     PyObject* d = NULL, *d2, *d3, *r;
4713     u_int32_t flags = 0;
4714     static char* kwnames[] = { "flags", NULL };
4715
4716     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:memp_stat",
4717                 kwnames, &flags))
4718         return NULL;
4719
4720     CHECK_ENV_NOT_CLOSED(self);
4721
4722     MYDB_BEGIN_ALLOW_THREADS;
4723     err = self->db_env->memp_stat(self->db_env, &gsp, &fsp, flags);
4724     MYDB_END_ALLOW_THREADS;
4725     RETURN_IF_ERR();
4726
4727     /* Turn the stat structure into a dictionary */
4728     d = PyDict_New();
4729     if (d == NULL) {
4730         if (gsp)
4731             free(gsp);
4732         return NULL;
4733     }
4734
4735 #define MAKE_ENTRY(name)  _addIntToDict(d, #name, gsp->st_##name)
4736
4737     MAKE_ENTRY(gbytes);
4738     MAKE_ENTRY(ncache);
4739 #if (DBVER >= 46)
4740     MAKE_ENTRY(max_ncache);
4741 #endif
4742     MAKE_ENTRY(regsize);
4743 #if (DBVER >= 43)
4744     MAKE_ENTRY(mmapsize);
4745     MAKE_ENTRY(maxopenfd);
4746     MAKE_ENTRY(maxwrite);
4747     MAKE_ENTRY(maxwrite_sleep);
4748 #endif
4749     MAKE_ENTRY(map);
4750     MAKE_ENTRY(cache_hit);
4751     MAKE_ENTRY(cache_miss);
4752     MAKE_ENTRY(page_create);
4753     MAKE_ENTRY(page_in);
4754     MAKE_ENTRY(page_out);
4755     MAKE_ENTRY(ro_evict);
4756     MAKE_ENTRY(rw_evict);
4757     MAKE_ENTRY(page_trickle);
4758     MAKE_ENTRY(pages);
4759     MAKE_ENTRY(page_clean);
4760     MAKE_ENTRY(page_dirty);
4761     MAKE_ENTRY(hash_buckets);
4762     MAKE_ENTRY(hash_searches);
4763     MAKE_ENTRY(hash_longest);
4764     MAKE_ENTRY(hash_examined);
4765     MAKE_ENTRY(hash_nowait);
4766     MAKE_ENTRY(hash_wait);
4767 #if (DBVER >= 45)
4768     MAKE_ENTRY(hash_max_nowait);
4769 #endif
4770     MAKE_ENTRY(hash_max_wait);
4771     MAKE_ENTRY(region_wait);
4772     MAKE_ENTRY(region_nowait);
4773 #if (DBVER >= 45)
4774     MAKE_ENTRY(mvcc_frozen);
4775     MAKE_ENTRY(mvcc_thawed);
4776     MAKE_ENTRY(mvcc_freed);
4777 #endif
4778     MAKE_ENTRY(alloc);
4779     MAKE_ENTRY(alloc_buckets);
4780     MAKE_ENTRY(alloc_max_buckets);
4781     MAKE_ENTRY(alloc_pages);
4782     MAKE_ENTRY(alloc_max_pages);
4783 #if (DBVER >= 45)
4784     MAKE_ENTRY(io_wait);
4785 #endif
4786 #if (DBVER >= 48)
4787     MAKE_ENTRY(sync_interrupted);
4788 #endif
4789
4790 #undef MAKE_ENTRY
4791     free(gsp);
4792
4793     d2 = PyDict_New();
4794     if (d2 == NULL) {
4795         Py_DECREF(d);
4796         if (fsp)
4797             free(fsp);
4798         return NULL;
4799     }
4800 #define MAKE_ENTRY(name)  _addIntToDict(d3, #name, (*fsp2)->st_##name)
4801     for(fsp2=fsp;*fsp2; fsp2++) {
4802         d3 = PyDict_New();
4803         if (d3 == NULL) {
4804             Py_DECREF(d);
4805             Py_DECREF(d2);
4806             if (fsp)
4807                 free(fsp);
4808             return NULL;
4809         }
4810         MAKE_ENTRY(pagesize);
4811         MAKE_ENTRY(cache_hit);
4812         MAKE_ENTRY(cache_miss);
4813         MAKE_ENTRY(map);
4814         MAKE_ENTRY(page_create);
4815         MAKE_ENTRY(page_in);
4816         MAKE_ENTRY(page_out);
4817         if(PyDict_SetItemString(d2, (*fsp2)->file_name, d3)) {
4818             Py_DECREF(d);
4819             Py_DECREF(d2);
4820             Py_DECREF(d3);
4821             if (fsp)
4822                 free(fsp);
4823             return NULL;
4824         }
4825         Py_DECREF(d3);
4826     }
4827
4828 #undef MAKE_ENTRY
4829     free(fsp);
4830
4831     r = Py_BuildValue("(OO)", d, d2);
4832     Py_DECREF(d);
4833     Py_DECREF(d2);
4834     return r;
4835 }
4836
4837 #if (DBVER >= 43)
4838 static PyObject*
4839 DBEnv_memp_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
4840 {
4841     int err;
4842     int flags=0;
4843     static char* kwnames[] = { "flags", NULL };
4844
4845     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:memp_stat_print",
4846                 kwnames, &flags))
4847     {
4848         return NULL;
4849     }
4850     CHECK_ENV_NOT_CLOSED(self);
4851     MYDB_BEGIN_ALLOW_THREADS;
4852     err = self->db_env->memp_stat_print(self->db_env, flags);
4853     MYDB_END_ALLOW_THREADS;
4854     RETURN_IF_ERR();
4855     RETURN_NONE();
4856 }
4857 #endif
4858
4859
4860 static PyObject*
4861 DBEnv_memp_trickle(DBEnvObject* self, PyObject* args)
4862 {
4863     int err, percent, nwrotep;
4864
4865     if (!PyArg_ParseTuple(args, "i:memp_trickle", &percent))
4866         return NULL;
4867     CHECK_ENV_NOT_CLOSED(self);
4868     MYDB_BEGIN_ALLOW_THREADS;
4869     err = self->db_env->memp_trickle(self->db_env, percent, &nwrotep);
4870     MYDB_END_ALLOW_THREADS;
4871     RETURN_IF_ERR();
4872     return NUMBER_FromLong(nwrotep);
4873 }
4874
4875 static PyObject*
4876 DBEnv_memp_sync(DBEnvObject* self, PyObject* args)
4877 {
4878     int err;
4879     DB_LSN lsn = {0, 0};
4880     DB_LSN *lsn_p = NULL;
4881
4882     if (!PyArg_ParseTuple(args, "|(ii):memp_sync", &lsn.file, &lsn.offset))
4883         return NULL;
4884     if ((lsn.file!=0) || (lsn.offset!=0)) {
4885         lsn_p = &lsn;
4886     }
4887     CHECK_ENV_NOT_CLOSED(self);
4888     MYDB_BEGIN_ALLOW_THREADS;
4889     err = self->db_env->memp_sync(self->db_env, lsn_p);
4890     MYDB_END_ALLOW_THREADS;
4891     RETURN_IF_ERR();
4892     RETURN_NONE();
4893 }
4894
4895 static PyObject*
4896 DBEnv_remove(DBEnvObject* self, PyObject* args)
4897 {
4898     int err, flags=0;
4899     char *db_home;
4900
4901     if (!PyArg_ParseTuple(args, "s|i:remove", &db_home, &flags))
4902         return NULL;
4903     CHECK_ENV_NOT_CLOSED(self);
4904     MYDB_BEGIN_ALLOW_THREADS;
4905     err = self->db_env->remove(self->db_env, db_home, flags);
4906     MYDB_END_ALLOW_THREADS;
4907     RETURN_IF_ERR();
4908     RETURN_NONE();
4909 }
4910
4911 static PyObject*
4912 DBEnv_dbremove(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4913 {
4914     int err;
4915     u_int32_t flags=0;
4916     char *file = NULL;
4917     char *database = NULL;
4918     PyObject *txnobj = NULL;
4919     DB_TXN *txn = NULL;
4920     static char* kwnames[] = { "file", "database", "txn", "flags",
4921                                      NULL };
4922
4923     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zOi:dbremove", kwnames,
4924                 &file, &database, &txnobj, &flags)) {
4925         return NULL;
4926     }
4927     if (!checkTxnObj(txnobj, &txn)) {
4928         return NULL;
4929     }
4930     CHECK_ENV_NOT_CLOSED(self);
4931     MYDB_BEGIN_ALLOW_THREADS;
4932     err = self->db_env->dbremove(self->db_env, txn, file, database, flags);
4933     MYDB_END_ALLOW_THREADS;
4934     RETURN_IF_ERR();
4935     RETURN_NONE();
4936 }
4937
4938 static PyObject*
4939 DBEnv_dbrename(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4940 {
4941     int err;
4942     u_int32_t flags=0;
4943     char *file = NULL;
4944     char *database = NULL;
4945     char *newname = NULL;
4946     PyObject *txnobj = NULL;
4947     DB_TXN *txn = NULL;
4948     static char* kwnames[] = { "file", "database", "newname", "txn",
4949                                      "flags", NULL };
4950
4951     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "szs|Oi:dbrename", kwnames,
4952                 &file, &database, &newname, &txnobj, &flags)) {
4953         return NULL;
4954     }
4955     if (!checkTxnObj(txnobj, &txn)) {
4956         return NULL;
4957     }
4958     CHECK_ENV_NOT_CLOSED(self);
4959     MYDB_BEGIN_ALLOW_THREADS;
4960     err = self->db_env->dbrename(self->db_env, txn, file, database, newname,
4961                                  flags);
4962     MYDB_END_ALLOW_THREADS;
4963     RETURN_IF_ERR();
4964     RETURN_NONE();
4965 }
4966
4967
4968
4969 static PyObject*
4970 DBEnv_set_encrypt(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4971 {
4972     int err;
4973     u_int32_t flags=0;
4974     char *passwd = NULL;
4975     static char* kwnames[] = { "passwd", "flags", NULL };
4976
4977     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames,
4978                 &passwd, &flags)) {
4979         return NULL;
4980     }
4981
4982     MYDB_BEGIN_ALLOW_THREADS;
4983     err = self->db_env->set_encrypt(self->db_env, passwd, flags);
4984     MYDB_END_ALLOW_THREADS;
4985
4986     RETURN_IF_ERR();
4987     RETURN_NONE();
4988 }
4989
4990 #if (DBVER >= 42)
4991 static PyObject*
4992 DBEnv_get_encrypt_flags(DBEnvObject* self)
4993 {
4994     int err;
4995     u_int32_t flags;
4996
4997     CHECK_ENV_NOT_CLOSED(self);
4998
4999     MYDB_BEGIN_ALLOW_THREADS;
5000     err = self->db_env->get_encrypt_flags(self->db_env, &flags);
5001     MYDB_END_ALLOW_THREADS;
5002
5003     RETURN_IF_ERR();
5004
5005     return NUMBER_FromLong(flags);
5006 }
5007
5008 static PyObject*
5009 DBEnv_get_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs)
5010 {
5011     int err;
5012     int flag;
5013     u_int32_t timeout;
5014     static char* kwnames[] = {"flag", NULL };
5015
5016     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:get_timeout", kwnames,
5017                 &flag)) {
5018         return NULL;
5019     }
5020     CHECK_ENV_NOT_CLOSED(self);
5021
5022     MYDB_BEGIN_ALLOW_THREADS;
5023     err = self->db_env->get_timeout(self->db_env, &timeout, flag);
5024     MYDB_END_ALLOW_THREADS;
5025     RETURN_IF_ERR();
5026     return NUMBER_FromLong(timeout);
5027 }
5028 #endif
5029
5030
5031 static PyObject*
5032 DBEnv_set_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs)
5033 {
5034     int err;
5035     u_int32_t flags=0;
5036     u_int32_t timeout = 0;
5037     static char* kwnames[] = { "timeout", "flags", NULL };
5038
5039     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames,
5040                 &timeout, &flags)) {
5041         return NULL;
5042     }
5043
5044     MYDB_BEGIN_ALLOW_THREADS;
5045     err = self->db_env->set_timeout(self->db_env, (db_timeout_t)timeout, flags);
5046     MYDB_END_ALLOW_THREADS;
5047
5048     RETURN_IF_ERR();
5049     RETURN_NONE();
5050 }
5051
5052 static PyObject*
5053 DBEnv_set_shm_key(DBEnvObject* self, PyObject* args)
5054 {
5055     int err;
5056     long shm_key = 0;
5057
5058     if (!PyArg_ParseTuple(args, "l:set_shm_key", &shm_key))
5059         return NULL;
5060     CHECK_ENV_NOT_CLOSED(self);
5061
5062     err = self->db_env->set_shm_key(self->db_env, shm_key);
5063     RETURN_IF_ERR();
5064     RETURN_NONE();
5065 }
5066
5067 #if (DBVER >= 42)
5068 static PyObject*
5069 DBEnv_get_shm_key(DBEnvObject* self)
5070 {
5071     int err;
5072     long shm_key;
5073
5074     CHECK_ENV_NOT_CLOSED(self);
5075
5076     MYDB_BEGIN_ALLOW_THREADS;
5077     err = self->db_env->get_shm_key(self->db_env, &shm_key);
5078     MYDB_END_ALLOW_THREADS;
5079
5080     RETURN_IF_ERR();
5081
5082     return NUMBER_FromLong(shm_key);
5083 }
5084 #endif
5085
5086 #if (DBVER >= 46)
5087 static PyObject*
5088 DBEnv_set_cache_max(DBEnvObject* self, PyObject* args)
5089 {
5090     int err, gbytes, bytes;
5091
5092     if (!PyArg_ParseTuple(args, "ii:set_cache_max",
5093                           &gbytes, &bytes))
5094         return NULL;
5095     CHECK_ENV_NOT_CLOSED(self);
5096
5097     MYDB_BEGIN_ALLOW_THREADS;
5098     err = self->db_env->set_cache_max(self->db_env, gbytes, bytes);
5099     MYDB_END_ALLOW_THREADS;
5100     RETURN_IF_ERR();
5101     RETURN_NONE();
5102 }
5103
5104 static PyObject*
5105 DBEnv_get_cache_max(DBEnvObject* self)
5106 {
5107     int err;
5108     u_int32_t gbytes, bytes;
5109
5110     CHECK_ENV_NOT_CLOSED(self);
5111
5112     MYDB_BEGIN_ALLOW_THREADS;
5113     err = self->db_env->get_cache_max(self->db_env, &gbytes, &bytes);
5114     MYDB_END_ALLOW_THREADS;
5115
5116     RETURN_IF_ERR();
5117
5118     return Py_BuildValue("(ii)", gbytes, bytes);
5119 }
5120 #endif
5121
5122 #if (DBVER >= 46)
5123 static PyObject*
5124 DBEnv_set_thread_count(DBEnvObject* self, PyObject* args)
5125 {
5126     int err;
5127     u_int32_t count;
5128
5129     if (!PyArg_ParseTuple(args, "i:set_thread_count", &count))
5130         return NULL;
5131     CHECK_ENV_NOT_CLOSED(self);
5132
5133     MYDB_BEGIN_ALLOW_THREADS;
5134     err = self->db_env->set_thread_count(self->db_env, count);
5135     MYDB_END_ALLOW_THREADS;
5136     RETURN_IF_ERR();
5137     RETURN_NONE();
5138 }
5139
5140 static PyObject*
5141 DBEnv_get_thread_count(DBEnvObject* self)
5142 {
5143     int err;
5144     u_int32_t count;
5145
5146     CHECK_ENV_NOT_CLOSED(self);
5147
5148     MYDB_BEGIN_ALLOW_THREADS;
5149     err = self->db_env->get_thread_count(self->db_env, &count);
5150     MYDB_END_ALLOW_THREADS;
5151     RETURN_IF_ERR();
5152     return NUMBER_FromLong(count);
5153 }
5154 #endif
5155
5156 static PyObject*
5157 DBEnv_set_cachesize(DBEnvObject* self, PyObject* args)
5158 {
5159     int err, gbytes=0, bytes=0, ncache=0;
5160
5161     if (!PyArg_ParseTuple(args, "ii|i:set_cachesize",
5162                           &gbytes, &bytes, &ncache))
5163         return NULL;
5164     CHECK_ENV_NOT_CLOSED(self);
5165
5166     MYDB_BEGIN_ALLOW_THREADS;
5167     err = self->db_env->set_cachesize(self->db_env, gbytes, bytes, ncache);
5168     MYDB_END_ALLOW_THREADS;
5169     RETURN_IF_ERR();
5170     RETURN_NONE();
5171 }
5172
5173 #if (DBVER >= 42)
5174 static PyObject*
5175 DBEnv_get_cachesize(DBEnvObject* self)
5176 {
5177     int err;
5178     u_int32_t gbytes, bytes;
5179     int ncache;
5180
5181     CHECK_ENV_NOT_CLOSED(self);
5182
5183     MYDB_BEGIN_ALLOW_THREADS;
5184     err = self->db_env->get_cachesize(self->db_env, &gbytes, &bytes, &ncache);
5185     MYDB_END_ALLOW_THREADS;
5186
5187     RETURN_IF_ERR();
5188
5189     return Py_BuildValue("(iii)", gbytes, bytes, ncache);
5190 }
5191 #endif
5192
5193
5194 static PyObject*
5195 DBEnv_set_flags(DBEnvObject* self, PyObject* args)
5196 {
5197     int err, flags=0, onoff=0;
5198
5199     if (!PyArg_ParseTuple(args, "ii:set_flags",
5200                           &flags, &onoff))
5201         return NULL;
5202     CHECK_ENV_NOT_CLOSED(self);
5203
5204     MYDB_BEGIN_ALLOW_THREADS;
5205     err = self->db_env->set_flags(self->db_env, flags, onoff);
5206     MYDB_END_ALLOW_THREADS;
5207     RETURN_IF_ERR();
5208     RETURN_NONE();
5209 }
5210
5211 #if (DBVER >= 42)
5212 static PyObject*
5213 DBEnv_get_flags(DBEnvObject* self)
5214 {
5215     int err;
5216     u_int32_t flags;
5217
5218     CHECK_ENV_NOT_CLOSED(self);
5219
5220     MYDB_BEGIN_ALLOW_THREADS;
5221     err = self->db_env->get_flags(self->db_env, &flags);
5222     MYDB_END_ALLOW_THREADS;
5223     RETURN_IF_ERR();
5224     return NUMBER_FromLong(flags);
5225 }
5226 #endif
5227
5228 #if (DBVER >= 47)
5229 static PyObject*
5230 DBEnv_log_set_config(DBEnvObject* self, PyObject* args)
5231 {
5232     int err, flags, onoff;
5233
5234     if (!PyArg_ParseTuple(args, "ii:log_set_config",
5235                           &flags, &onoff))
5236         return NULL;
5237     CHECK_ENV_NOT_CLOSED(self);
5238
5239     MYDB_BEGIN_ALLOW_THREADS;
5240     err = self->db_env->log_set_config(self->db_env, flags, onoff);
5241     MYDB_END_ALLOW_THREADS;
5242     RETURN_IF_ERR();
5243     RETURN_NONE();
5244 }
5245
5246 static PyObject*
5247 DBEnv_log_get_config(DBEnvObject* self, PyObject* args)
5248 {
5249     int err, flag, onoff;
5250
5251     if (!PyArg_ParseTuple(args, "i:log_get_config", &flag))
5252         return NULL;
5253     CHECK_ENV_NOT_CLOSED(self);
5254
5255     MYDB_BEGIN_ALLOW_THREADS;
5256     err = self->db_env->log_get_config(self->db_env, flag, &onoff);
5257     MYDB_END_ALLOW_THREADS;
5258     RETURN_IF_ERR();
5259     return PyBool_FromLong(onoff);
5260 }
5261 #endif /* DBVER >= 47 */
5262
5263 #if (DBVER >= 44)
5264 static PyObject*
5265 DBEnv_mutex_set_max(DBEnvObject* self, PyObject* args)
5266 {
5267     int err;
5268     int value;
5269
5270     if (!PyArg_ParseTuple(args, "i:mutex_set_max", &value))
5271         return NULL;
5272
5273     CHECK_ENV_NOT_CLOSED(self);
5274
5275     MYDB_BEGIN_ALLOW_THREADS;
5276     err = self->db_env->mutex_set_max(self->db_env, value);
5277     MYDB_END_ALLOW_THREADS;
5278
5279     RETURN_IF_ERR();
5280     RETURN_NONE();
5281 }
5282
5283 static PyObject*
5284 DBEnv_mutex_get_max(DBEnvObject* self)
5285 {
5286     int err;
5287     u_int32_t value;
5288
5289     CHECK_ENV_NOT_CLOSED(self);
5290
5291     MYDB_BEGIN_ALLOW_THREADS;
5292     err = self->db_env->mutex_get_max(self->db_env, &value);
5293     MYDB_END_ALLOW_THREADS;
5294
5295     RETURN_IF_ERR();
5296
5297     return NUMBER_FromLong(value);
5298 }
5299
5300 static PyObject*
5301 DBEnv_mutex_set_align(DBEnvObject* self, PyObject* args)
5302 {
5303     int err;
5304     int align;
5305
5306     if (!PyArg_ParseTuple(args, "i:mutex_set_align", &align))
5307         return NULL;
5308
5309     CHECK_ENV_NOT_CLOSED(self);
5310
5311     MYDB_BEGIN_ALLOW_THREADS;
5312     err = self->db_env->mutex_set_align(self->db_env, align);
5313     MYDB_END_ALLOW_THREADS;
5314
5315     RETURN_IF_ERR();
5316     RETURN_NONE();
5317 }
5318
5319 static PyObject*
5320 DBEnv_mutex_get_align(DBEnvObject* self)
5321 {
5322     int err;
5323     u_int32_t align;
5324
5325     CHECK_ENV_NOT_CLOSED(self);
5326
5327     MYDB_BEGIN_ALLOW_THREADS;
5328     err = self->db_env->mutex_get_align(self->db_env, &align);
5329     MYDB_END_ALLOW_THREADS;
5330
5331     RETURN_IF_ERR();
5332
5333     return NUMBER_FromLong(align);
5334 }
5335
5336 static PyObject*
5337 DBEnv_mutex_set_increment(DBEnvObject* self, PyObject* args)
5338 {
5339     int err;
5340     int increment;
5341
5342     if (!PyArg_ParseTuple(args, "i:mutex_set_increment", &increment))
5343         return NULL;
5344
5345     CHECK_ENV_NOT_CLOSED(self);
5346
5347     MYDB_BEGIN_ALLOW_THREADS;
5348     err = self->db_env->mutex_set_increment(self->db_env, increment);
5349     MYDB_END_ALLOW_THREADS;
5350
5351     RETURN_IF_ERR();
5352     RETURN_NONE();
5353 }
5354
5355 static PyObject*
5356 DBEnv_mutex_get_increment(DBEnvObject* self)
5357 {
5358     int err;
5359     u_int32_t increment;
5360
5361     CHECK_ENV_NOT_CLOSED(self);
5362
5363     MYDB_BEGIN_ALLOW_THREADS;
5364     err = self->db_env->mutex_get_increment(self->db_env, &increment);
5365     MYDB_END_ALLOW_THREADS;
5366
5367     RETURN_IF_ERR();
5368
5369     return NUMBER_FromLong(increment);
5370 }
5371
5372 static PyObject*
5373 DBEnv_mutex_set_tas_spins(DBEnvObject* self, PyObject* args)
5374 {
5375     int err;
5376     int tas_spins;
5377
5378     if (!PyArg_ParseTuple(args, "i:mutex_set_tas_spins", &tas_spins))
5379         return NULL;
5380
5381     CHECK_ENV_NOT_CLOSED(self);
5382
5383     MYDB_BEGIN_ALLOW_THREADS;
5384     err = self->db_env->mutex_set_tas_spins(self->db_env, tas_spins);
5385     MYDB_END_ALLOW_THREADS;
5386
5387     RETURN_IF_ERR();
5388     RETURN_NONE();
5389 }
5390
5391 static PyObject*
5392 DBEnv_mutex_get_tas_spins(DBEnvObject* self)
5393 {
5394     int err;
5395     u_int32_t tas_spins;
5396
5397     CHECK_ENV_NOT_CLOSED(self);
5398
5399     MYDB_BEGIN_ALLOW_THREADS;
5400     err = self->db_env->mutex_get_tas_spins(self->db_env, &tas_spins);
5401     MYDB_END_ALLOW_THREADS;
5402
5403     RETURN_IF_ERR();
5404
5405     return NUMBER_FromLong(tas_spins);
5406 }
5407 #endif
5408
5409 static PyObject*
5410 DBEnv_set_data_dir(DBEnvObject* self, PyObject* args)
5411 {
5412     int err;
5413     char *dir;
5414
5415     if (!PyArg_ParseTuple(args, "s:set_data_dir", &dir))
5416         return NULL;
5417     CHECK_ENV_NOT_CLOSED(self);
5418
5419     MYDB_BEGIN_ALLOW_THREADS;
5420     err = self->db_env->set_data_dir(self->db_env, dir);
5421     MYDB_END_ALLOW_THREADS;
5422     RETURN_IF_ERR();
5423     RETURN_NONE();
5424 }
5425
5426 #if (DBVER >= 42)
5427 static PyObject*
5428 DBEnv_get_data_dirs(DBEnvObject* self)
5429 {
5430     int err;
5431     PyObject *tuple;
5432     PyObject *item;
5433     const char **dirpp;
5434     int size, i;
5435
5436     CHECK_ENV_NOT_CLOSED(self);
5437
5438     MYDB_BEGIN_ALLOW_THREADS;
5439     err = self->db_env->get_data_dirs(self->db_env, &dirpp);
5440     MYDB_END_ALLOW_THREADS;
5441
5442     RETURN_IF_ERR();
5443
5444     /*
5445     ** Calculate size. Python C API
5446     ** actually allows for tuple resizing,
5447     ** but this is simple enough.
5448     */
5449     for (size=0; *(dirpp+size) ; size++);
5450
5451     tuple = PyTuple_New(size);
5452     if (!tuple)
5453         return NULL;
5454
5455     for (i=0; i<size; i++) {
5456         item = PyBytes_FromString (*(dirpp+i));
5457         if (item == NULL) {
5458             Py_DECREF(tuple);
5459             tuple = NULL;
5460             break;
5461         }
5462         PyTuple_SET_ITEM(tuple, i, item);
5463     }
5464     return tuple;
5465 }
5466 #endif
5467
5468 #if (DBVER >= 44)
5469 static PyObject*
5470 DBEnv_set_lg_filemode(DBEnvObject* self, PyObject* args)
5471 {
5472     int err, filemode;
5473
5474     if (!PyArg_ParseTuple(args, "i:set_lg_filemode", &filemode))
5475         return NULL;
5476     CHECK_ENV_NOT_CLOSED(self);
5477
5478     MYDB_BEGIN_ALLOW_THREADS;
5479     err = self->db_env->set_lg_filemode(self->db_env, filemode);
5480     MYDB_END_ALLOW_THREADS;
5481     RETURN_IF_ERR();
5482     RETURN_NONE();
5483 }
5484
5485 static PyObject*
5486 DBEnv_get_lg_filemode(DBEnvObject* self)
5487 {
5488     int err, filemode;
5489
5490     CHECK_ENV_NOT_CLOSED(self);
5491
5492     MYDB_BEGIN_ALLOW_THREADS;
5493     err = self->db_env->get_lg_filemode(self->db_env, &filemode);
5494     MYDB_END_ALLOW_THREADS;
5495     RETURN_IF_ERR();
5496     return NUMBER_FromLong(filemode);
5497 }
5498 #endif
5499
5500 static PyObject*
5501 DBEnv_set_lg_bsize(DBEnvObject* self, PyObject* args)
5502 {
5503     int err, lg_bsize;
5504
5505     if (!PyArg_ParseTuple(args, "i:set_lg_bsize", &lg_bsize))
5506         return NULL;
5507     CHECK_ENV_NOT_CLOSED(self);
5508
5509     MYDB_BEGIN_ALLOW_THREADS;
5510     err = self->db_env->set_lg_bsize(self->db_env, lg_bsize);
5511     MYDB_END_ALLOW_THREADS;
5512     RETURN_IF_ERR();
5513     RETURN_NONE();
5514 }
5515
5516 #if (DBVER >= 42)
5517 static PyObject*
5518 DBEnv_get_lg_bsize(DBEnvObject* self)
5519 {
5520     int err;
5521     u_int32_t lg_bsize;
5522
5523     CHECK_ENV_NOT_CLOSED(self);
5524
5525     MYDB_BEGIN_ALLOW_THREADS;
5526     err = self->db_env->get_lg_bsize(self->db_env, &lg_bsize);
5527     MYDB_END_ALLOW_THREADS;
5528     RETURN_IF_ERR();
5529     return NUMBER_FromLong(lg_bsize);
5530 }
5531 #endif
5532
5533 static PyObject*
5534 DBEnv_set_lg_dir(DBEnvObject* self, PyObject* args)
5535 {
5536     int err;
5537     char *dir;
5538
5539     if (!PyArg_ParseTuple(args, "s:set_lg_dir", &dir))
5540         return NULL;
5541     CHECK_ENV_NOT_CLOSED(self);
5542
5543     MYDB_BEGIN_ALLOW_THREADS;
5544     err = self->db_env->set_lg_dir(self->db_env, dir);
5545     MYDB_END_ALLOW_THREADS;
5546     RETURN_IF_ERR();
5547     RETURN_NONE();
5548 }
5549
5550 #if (DBVER >= 42)
5551 static PyObject*
5552 DBEnv_get_lg_dir(DBEnvObject* self)
5553 {
5554     int err;
5555     const char *dirp;
5556
5557     CHECK_ENV_NOT_CLOSED(self);
5558
5559     MYDB_BEGIN_ALLOW_THREADS;
5560     err = self->db_env->get_lg_dir(self->db_env, &dirp);
5561     MYDB_END_ALLOW_THREADS;
5562     RETURN_IF_ERR();
5563     return PyBytes_FromString(dirp);
5564 }
5565 #endif
5566
5567 static PyObject*
5568 DBEnv_set_lg_max(DBEnvObject* self, PyObject* args)
5569 {
5570     int err, lg_max;
5571
5572     if (!PyArg_ParseTuple(args, "i:set_lg_max", &lg_max))
5573         return NULL;
5574     CHECK_ENV_NOT_CLOSED(self);
5575
5576     MYDB_BEGIN_ALLOW_THREADS;
5577     err = self->db_env->set_lg_max(self->db_env, lg_max);
5578     MYDB_END_ALLOW_THREADS;
5579     RETURN_IF_ERR();
5580     RETURN_NONE();
5581 }
5582
5583 #if (DBVER >= 42)
5584 static PyObject*
5585 DBEnv_get_lg_max(DBEnvObject* self)
5586 {
5587     int err;
5588     u_int32_t lg_max;
5589
5590     CHECK_ENV_NOT_CLOSED(self);
5591
5592     MYDB_BEGIN_ALLOW_THREADS;
5593     err = self->db_env->get_lg_max(self->db_env, &lg_max);
5594     MYDB_END_ALLOW_THREADS;
5595     RETURN_IF_ERR();
5596     return NUMBER_FromLong(lg_max);
5597 }
5598 #endif
5599
5600
5601 static PyObject*
5602 DBEnv_set_lg_regionmax(DBEnvObject* self, PyObject* args)
5603 {
5604     int err, lg_max;
5605
5606     if (!PyArg_ParseTuple(args, "i:set_lg_regionmax", &lg_max))
5607         return NULL;
5608     CHECK_ENV_NOT_CLOSED(self);
5609
5610     MYDB_BEGIN_ALLOW_THREADS;
5611     err = self->db_env->set_lg_regionmax(self->db_env, lg_max);
5612     MYDB_END_ALLOW_THREADS;
5613     RETURN_IF_ERR();
5614     RETURN_NONE();
5615 }
5616
5617 #if (DBVER >= 42)
5618 static PyObject*
5619 DBEnv_get_lg_regionmax(DBEnvObject* self)
5620 {
5621     int err;
5622     u_int32_t lg_regionmax;
5623
5624     CHECK_ENV_NOT_CLOSED(self);
5625
5626     MYDB_BEGIN_ALLOW_THREADS;
5627     err = self->db_env->get_lg_regionmax(self->db_env, &lg_regionmax);
5628     MYDB_END_ALLOW_THREADS;
5629     RETURN_IF_ERR();
5630     return NUMBER_FromLong(lg_regionmax);
5631 }
5632 #endif
5633
5634 #if (DBVER >= 47)
5635 static PyObject*
5636 DBEnv_set_lk_partitions(DBEnvObject* self, PyObject* args)
5637 {
5638     int err, lk_partitions;
5639
5640     if (!PyArg_ParseTuple(args, "i:set_lk_partitions", &lk_partitions))
5641         return NULL;
5642     CHECK_ENV_NOT_CLOSED(self);
5643
5644     MYDB_BEGIN_ALLOW_THREADS;
5645     err = self->db_env->set_lk_partitions(self->db_env, lk_partitions);
5646     MYDB_END_ALLOW_THREADS;
5647     RETURN_IF_ERR();
5648     RETURN_NONE();
5649 }
5650
5651 static PyObject*
5652 DBEnv_get_lk_partitions(DBEnvObject* self)
5653 {
5654     int err;
5655     u_int32_t lk_partitions;
5656
5657     CHECK_ENV_NOT_CLOSED(self);
5658
5659     MYDB_BEGIN_ALLOW_THREADS;
5660     err = self->db_env->get_lk_partitions(self->db_env, &lk_partitions);
5661     MYDB_END_ALLOW_THREADS;
5662     RETURN_IF_ERR();
5663     return NUMBER_FromLong(lk_partitions);
5664 }
5665 #endif
5666
5667 static PyObject*
5668 DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args)
5669 {
5670     int err, lk_detect;
5671
5672     if (!PyArg_ParseTuple(args, "i:set_lk_detect", &lk_detect))
5673         return NULL;
5674     CHECK_ENV_NOT_CLOSED(self);
5675
5676     MYDB_BEGIN_ALLOW_THREADS;
5677     err = self->db_env->set_lk_detect(self->db_env, lk_detect);
5678     MYDB_END_ALLOW_THREADS;
5679     RETURN_IF_ERR();
5680     RETURN_NONE();
5681 }
5682
5683 #if (DBVER >= 42)
5684 static PyObject*
5685 DBEnv_get_lk_detect(DBEnvObject* self)
5686 {
5687     int err;
5688     u_int32_t lk_detect;
5689
5690     CHECK_ENV_NOT_CLOSED(self);
5691
5692     MYDB_BEGIN_ALLOW_THREADS;
5693     err = self->db_env->get_lk_detect(self->db_env, &lk_detect);
5694     MYDB_END_ALLOW_THREADS;
5695     RETURN_IF_ERR();
5696     return NUMBER_FromLong(lk_detect);
5697 }
5698 #endif
5699
5700
5701 #if (DBVER < 45)
5702 static PyObject*
5703 DBEnv_set_lk_max(DBEnvObject* self, PyObject* args)
5704 {
5705     int err, max;
5706
5707     if (!PyArg_ParseTuple(args, "i:set_lk_max", &max))
5708         return NULL;
5709     CHECK_ENV_NOT_CLOSED(self);
5710
5711     MYDB_BEGIN_ALLOW_THREADS;
5712     err = self->db_env->set_lk_max(self->db_env, max);
5713     MYDB_END_ALLOW_THREADS;
5714     RETURN_IF_ERR();
5715     RETURN_NONE();
5716 }
5717 #endif
5718
5719
5720
5721 static PyObject*
5722 DBEnv_set_lk_max_locks(DBEnvObject* self, PyObject* args)
5723 {
5724     int err, max;
5725
5726     if (!PyArg_ParseTuple(args, "i:set_lk_max_locks", &max))
5727         return NULL;
5728     CHECK_ENV_NOT_CLOSED(self);
5729
5730     MYDB_BEGIN_ALLOW_THREADS;
5731     err = self->db_env->set_lk_max_locks(self->db_env, max);
5732     MYDB_END_ALLOW_THREADS;
5733     RETURN_IF_ERR();
5734     RETURN_NONE();
5735 }
5736
5737 #if (DBVER >= 42)
5738 static PyObject*
5739 DBEnv_get_lk_max_locks(DBEnvObject* self)
5740 {
5741     int err;
5742     u_int32_t lk_max;
5743
5744     CHECK_ENV_NOT_CLOSED(self);
5745
5746     MYDB_BEGIN_ALLOW_THREADS;
5747     err = self->db_env->get_lk_max_locks(self->db_env, &lk_max);
5748     MYDB_END_ALLOW_THREADS;
5749     RETURN_IF_ERR();
5750     return NUMBER_FromLong(lk_max);
5751 }
5752 #endif
5753
5754 static PyObject*
5755 DBEnv_set_lk_max_lockers(DBEnvObject* self, PyObject* args)
5756 {
5757     int err, max;
5758
5759     if (!PyArg_ParseTuple(args, "i:set_lk_max_lockers", &max))
5760         return NULL;
5761     CHECK_ENV_NOT_CLOSED(self);
5762
5763     MYDB_BEGIN_ALLOW_THREADS;
5764     err = self->db_env->set_lk_max_lockers(self->db_env, max);
5765     MYDB_END_ALLOW_THREADS;
5766     RETURN_IF_ERR();
5767     RETURN_NONE();
5768 }
5769
5770 #if (DBVER >= 42)
5771 static PyObject*
5772 DBEnv_get_lk_max_lockers(DBEnvObject* self)
5773 {
5774     int err;
5775     u_int32_t lk_max;
5776
5777     CHECK_ENV_NOT_CLOSED(self);
5778
5779     MYDB_BEGIN_ALLOW_THREADS;
5780     err = self->db_env->get_lk_max_lockers(self->db_env, &lk_max);
5781     MYDB_END_ALLOW_THREADS;
5782     RETURN_IF_ERR();
5783     return NUMBER_FromLong(lk_max);
5784 }
5785 #endif
5786
5787 static PyObject*
5788 DBEnv_set_lk_max_objects(DBEnvObject* self, PyObject* args)
5789 {
5790     int err, max;
5791
5792     if (!PyArg_ParseTuple(args, "i:set_lk_max_objects", &max))
5793         return NULL;
5794     CHECK_ENV_NOT_CLOSED(self);
5795
5796     MYDB_BEGIN_ALLOW_THREADS;
5797     err = self->db_env->set_lk_max_objects(self->db_env, max);
5798     MYDB_END_ALLOW_THREADS;
5799     RETURN_IF_ERR();
5800     RETURN_NONE();
5801 }
5802
5803 #if (DBVER >= 42)
5804 static PyObject*
5805 DBEnv_get_lk_max_objects(DBEnvObject* self)
5806 {
5807     int err;
5808     u_int32_t lk_max;
5809
5810     CHECK_ENV_NOT_CLOSED(self);
5811
5812     MYDB_BEGIN_ALLOW_THREADS;
5813     err = self->db_env->get_lk_max_objects(self->db_env, &lk_max);
5814     MYDB_END_ALLOW_THREADS;
5815     RETURN_IF_ERR();
5816     return NUMBER_FromLong(lk_max);
5817 }
5818 #endif
5819
5820 #if (DBVER >= 42)
5821 static PyObject*
5822 DBEnv_get_mp_mmapsize(DBEnvObject* self)
5823 {
5824     int err;
5825     size_t mmapsize;
5826
5827     CHECK_ENV_NOT_CLOSED(self);
5828
5829     MYDB_BEGIN_ALLOW_THREADS;
5830     err = self->db_env->get_mp_mmapsize(self->db_env, &mmapsize);
5831     MYDB_END_ALLOW_THREADS;
5832     RETURN_IF_ERR();
5833     return NUMBER_FromLong(mmapsize);
5834 }
5835 #endif
5836
5837
5838 static PyObject*
5839 DBEnv_set_mp_mmapsize(DBEnvObject* self, PyObject* args)
5840 {
5841     int err, mp_mmapsize;
5842
5843     if (!PyArg_ParseTuple(args, "i:set_mp_mmapsize", &mp_mmapsize))
5844         return NULL;
5845     CHECK_ENV_NOT_CLOSED(self);
5846
5847     MYDB_BEGIN_ALLOW_THREADS;
5848     err = self->db_env->set_mp_mmapsize(self->db_env, mp_mmapsize);
5849     MYDB_END_ALLOW_THREADS;
5850     RETURN_IF_ERR();
5851     RETURN_NONE();
5852 }
5853
5854
5855 static PyObject*
5856 DBEnv_set_tmp_dir(DBEnvObject* self, PyObject* args)
5857 {
5858     int err;
5859     char *dir;
5860
5861     if (!PyArg_ParseTuple(args, "s:set_tmp_dir", &dir))
5862         return NULL;
5863     CHECK_ENV_NOT_CLOSED(self);
5864
5865     MYDB_BEGIN_ALLOW_THREADS;
5866     err = self->db_env->set_tmp_dir(self->db_env, dir);
5867     MYDB_END_ALLOW_THREADS;
5868     RETURN_IF_ERR();
5869     RETURN_NONE();
5870 }
5871
5872
5873 #if (DBVER >= 42)
5874 static PyObject*
5875 DBEnv_get_tmp_dir(DBEnvObject* self)
5876 {
5877     int err;
5878     const char *dirpp;
5879
5880     CHECK_ENV_NOT_CLOSED(self);
5881
5882     MYDB_BEGIN_ALLOW_THREADS;
5883     err = self->db_env->get_tmp_dir(self->db_env, &dirpp);
5884     MYDB_END_ALLOW_THREADS;
5885
5886     RETURN_IF_ERR();
5887
5888     return PyBytes_FromString(dirpp);
5889 }
5890 #endif
5891
5892
5893 static PyObject*
5894 DBEnv_txn_recover(DBEnvObject* self)
5895 {
5896     int flags = DB_FIRST;
5897     int err, i;
5898     PyObject *list, *tuple, *gid;
5899     DBTxnObject *txn;
5900 #define PREPLIST_LEN 16
5901     DB_PREPLIST preplist[PREPLIST_LEN];
5902 #if (DBVER < 48)
5903     long retp;
5904 #else
5905     u_int32_t retp;
5906 #endif
5907
5908     CHECK_ENV_NOT_CLOSED(self);
5909
5910     list=PyList_New(0);
5911     if (!list)
5912         return NULL;
5913     while (!0) {
5914         MYDB_BEGIN_ALLOW_THREADS
5915         err=self->db_env->txn_recover(self->db_env,
5916                         preplist, PREPLIST_LEN, &retp, flags);
5917 #undef PREPLIST_LEN
5918         MYDB_END_ALLOW_THREADS
5919         if (err) {
5920             Py_DECREF(list);
5921             RETURN_IF_ERR();
5922         }
5923         if (!retp) break;
5924         flags=DB_NEXT;  /* Prepare for next loop pass */
5925         for (i=0; i<retp; i++) {
5926             gid=PyBytes_FromStringAndSize((char *)(preplist[i].gid),
5927                                 DB_GID_SIZE);
5928             if (!gid) {
5929                 Py_DECREF(list);
5930                 return NULL;
5931             }
5932             txn=newDBTxnObject(self, NULL, preplist[i].txn, 0);
5933             if (!txn) {
5934                 Py_DECREF(list);
5935                 Py_DECREF(gid);
5936                 return NULL;
5937             }
5938             txn->flag_prepare=1;  /* Recover state */
5939             tuple=PyTuple_New(2);
5940             if (!tuple) {
5941                 Py_DECREF(list);
5942                 Py_DECREF(gid);
5943                 Py_DECREF(txn);
5944                 return NULL;
5945             }
5946             if (PyTuple_SetItem(tuple, 0, gid)) {
5947                 Py_DECREF(list);
5948                 Py_DECREF(gid);
5949                 Py_DECREF(txn);
5950                 Py_DECREF(tuple);
5951                 return NULL;
5952             }
5953             if (PyTuple_SetItem(tuple, 1, (PyObject *)txn)) {
5954                 Py_DECREF(list);
5955                 Py_DECREF(txn);
5956                 Py_DECREF(tuple); /* This delete the "gid" also */
5957                 return NULL;
5958             }
5959             if (PyList_Append(list, tuple)) {
5960                 Py_DECREF(list);
5961                 Py_DECREF(tuple);/* This delete the "gid" and the "txn" also */
5962                 return NULL;
5963             }
5964             Py_DECREF(tuple);
5965         }
5966     }
5967     return list;
5968 }
5969
5970 static PyObject*
5971 DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs)
5972 {
5973     int flags = 0;
5974     PyObject* txnobj = NULL;
5975     DB_TXN *txn = NULL;
5976     static char* kwnames[] = { "parent", "flags", NULL };
5977
5978     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:txn_begin", kwnames,
5979                                      &txnobj, &flags))
5980         return NULL;
5981
5982     if (!checkTxnObj(txnobj, &txn))
5983         return NULL;
5984     CHECK_ENV_NOT_CLOSED(self);
5985
5986     return (PyObject*)newDBTxnObject(self, (DBTxnObject *)txnobj, NULL, flags);
5987 }
5988
5989
5990 static PyObject*
5991 DBEnv_txn_checkpoint(DBEnvObject* self, PyObject* args)
5992 {
5993     int err, kbyte=0, min=0, flags=0;
5994
5995     if (!PyArg_ParseTuple(args, "|iii:txn_checkpoint", &kbyte, &min, &flags))
5996         return NULL;
5997     CHECK_ENV_NOT_CLOSED(self);
5998
5999     MYDB_BEGIN_ALLOW_THREADS;
6000     err = self->db_env->txn_checkpoint(self->db_env, kbyte, min, flags);
6001     MYDB_END_ALLOW_THREADS;
6002     RETURN_IF_ERR();
6003     RETURN_NONE();
6004 }
6005
6006
6007 #if (DBVER >= 42)
6008 static PyObject*
6009 DBEnv_get_tx_max(DBEnvObject* self)
6010 {
6011     int err;
6012     u_int32_t max;
6013
6014     CHECK_ENV_NOT_CLOSED(self);
6015
6016     MYDB_BEGIN_ALLOW_THREADS;
6017     err = self->db_env->get_tx_max(self->db_env, &max);
6018     MYDB_END_ALLOW_THREADS;
6019     RETURN_IF_ERR();
6020     return PyLong_FromUnsignedLong(max);
6021 }
6022 #endif
6023
6024
6025 static PyObject*
6026 DBEnv_set_tx_max(DBEnvObject* self, PyObject* args)
6027 {
6028     int err, max;
6029
6030     if (!PyArg_ParseTuple(args, "i:set_tx_max", &max))
6031         return NULL;
6032     CHECK_ENV_NOT_CLOSED(self);
6033
6034     MYDB_BEGIN_ALLOW_THREADS;
6035     err = self->db_env->set_tx_max(self->db_env, max);
6036     MYDB_END_ALLOW_THREADS;
6037     RETURN_IF_ERR();
6038     RETURN_NONE();
6039 }
6040
6041
6042 #if (DBVER >= 42)
6043 static PyObject*
6044 DBEnv_get_tx_timestamp(DBEnvObject* self)
6045 {
6046     int err;
6047     time_t timestamp;
6048
6049     CHECK_ENV_NOT_CLOSED(self);
6050
6051     MYDB_BEGIN_ALLOW_THREADS;
6052     err = self->db_env->get_tx_timestamp(self->db_env, &timestamp);
6053     MYDB_END_ALLOW_THREADS;
6054     RETURN_IF_ERR();
6055     return NUMBER_FromLong(timestamp);
6056 }
6057 #endif
6058
6059 static PyObject*
6060 DBEnv_set_tx_timestamp(DBEnvObject* self, PyObject* args)
6061 {
6062     int err;
6063     long stamp;
6064     time_t timestamp;
6065
6066     if (!PyArg_ParseTuple(args, "l:set_tx_timestamp", &stamp))
6067         return NULL;
6068     CHECK_ENV_NOT_CLOSED(self);
6069     timestamp = (time_t)stamp;
6070     MYDB_BEGIN_ALLOW_THREADS;
6071     err = self->db_env->set_tx_timestamp(self->db_env, &timestamp);
6072     MYDB_END_ALLOW_THREADS;
6073     RETURN_IF_ERR();
6074     RETURN_NONE();
6075 }
6076
6077
6078 static PyObject*
6079 DBEnv_lock_detect(DBEnvObject* self, PyObject* args)
6080 {
6081     int err, atype, flags=0;
6082     int aborted = 0;
6083
6084     if (!PyArg_ParseTuple(args, "i|i:lock_detect", &atype, &flags))
6085         return NULL;
6086     CHECK_ENV_NOT_CLOSED(self);
6087
6088     MYDB_BEGIN_ALLOW_THREADS;
6089     err = self->db_env->lock_detect(self->db_env, flags, atype, &aborted);
6090     MYDB_END_ALLOW_THREADS;
6091     RETURN_IF_ERR();
6092     return NUMBER_FromLong(aborted);
6093 }
6094
6095
6096 static PyObject*
6097 DBEnv_lock_get(DBEnvObject* self, PyObject* args)
6098 {
6099     int flags=0;
6100     int locker, lock_mode;
6101     DBT obj;
6102     PyObject* objobj;
6103
6104     if (!PyArg_ParseTuple(args, "iOi|i:lock_get", &locker, &objobj, &lock_mode, &flags))
6105         return NULL;
6106
6107
6108     if (!make_dbt(objobj, &obj))
6109         return NULL;
6110
6111     return (PyObject*)newDBLockObject(self, locker, &obj, lock_mode, flags);
6112 }
6113
6114
6115 static PyObject*
6116 DBEnv_lock_id(DBEnvObject* self)
6117 {
6118     int err;
6119     u_int32_t theID;
6120
6121     CHECK_ENV_NOT_CLOSED(self);
6122     MYDB_BEGIN_ALLOW_THREADS;
6123     err = self->db_env->lock_id(self->db_env, &theID);
6124     MYDB_END_ALLOW_THREADS;
6125     RETURN_IF_ERR();
6126
6127     return NUMBER_FromLong((long)theID);
6128 }
6129
6130 static PyObject*
6131 DBEnv_lock_id_free(DBEnvObject* self, PyObject* args)
6132 {
6133     int err;
6134     u_int32_t theID;
6135
6136     if (!PyArg_ParseTuple(args, "I:lock_id_free", &theID))
6137         return NULL;
6138
6139     CHECK_ENV_NOT_CLOSED(self);
6140     MYDB_BEGIN_ALLOW_THREADS;
6141     err = self->db_env->lock_id_free(self->db_env, theID);
6142     MYDB_END_ALLOW_THREADS;
6143     RETURN_IF_ERR();
6144     RETURN_NONE();
6145 }
6146
6147 static PyObject*
6148 DBEnv_lock_put(DBEnvObject* self, PyObject* args)
6149 {
6150     int err;
6151     DBLockObject* dblockobj;
6152
6153     if (!PyArg_ParseTuple(args, "O!:lock_put", &DBLock_Type, &dblockobj))
6154         return NULL;
6155
6156     CHECK_ENV_NOT_CLOSED(self);
6157     MYDB_BEGIN_ALLOW_THREADS;
6158     err = self->db_env->lock_put(self->db_env, &dblockobj->lock);
6159     MYDB_END_ALLOW_THREADS;
6160     RETURN_IF_ERR();
6161     RETURN_NONE();
6162 }
6163
6164 #if (DBVER >= 44)
6165 static PyObject*
6166 DBEnv_fileid_reset(DBEnvObject* self, PyObject* args, PyObject* kwargs)
6167 {
6168     int err;
6169     char *file;
6170     u_int32_t flags = 0;
6171     static char* kwnames[] = { "file", "flags", NULL};
6172
6173     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|i:fileid_reset", kwnames,
6174                                      &file, &flags))
6175         return NULL;
6176     CHECK_ENV_NOT_CLOSED(self);
6177
6178     MYDB_BEGIN_ALLOW_THREADS;
6179     err = self->db_env->fileid_reset(self->db_env, file, flags);
6180     MYDB_END_ALLOW_THREADS;
6181     RETURN_IF_ERR();
6182     RETURN_NONE();
6183 }
6184
6185 static PyObject*
6186 DBEnv_lsn_reset(DBEnvObject* self, PyObject* args, PyObject* kwargs)
6187 {
6188     int err;
6189     char *file;
6190     u_int32_t flags = 0;
6191     static char* kwnames[] = { "file", "flags", NULL};
6192
6193     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|i:lsn_reset", kwnames,
6194                                      &file, &flags))
6195         return NULL;
6196     CHECK_ENV_NOT_CLOSED(self);
6197
6198     MYDB_BEGIN_ALLOW_THREADS;
6199     err = self->db_env->lsn_reset(self->db_env, file, flags);
6200     MYDB_END_ALLOW_THREADS;
6201     RETURN_IF_ERR();
6202     RETURN_NONE();
6203 }
6204 #endif /* DBVER >= 4.4 */
6205
6206
6207 #if (DBVER >= 43)
6208 static PyObject*
6209 DBEnv_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
6210 {
6211     int err;
6212     int flags=0;
6213     static char* kwnames[] = { "flags", NULL };
6214
6215     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat_print",
6216                 kwnames, &flags))
6217     {
6218         return NULL;
6219     }
6220     CHECK_ENV_NOT_CLOSED(self);
6221     MYDB_BEGIN_ALLOW_THREADS;
6222     err = self->db_env->stat_print(self->db_env, flags);
6223     MYDB_END_ALLOW_THREADS;
6224     RETURN_IF_ERR();
6225     RETURN_NONE();
6226 }
6227 #endif
6228
6229
6230 static PyObject*
6231 DBEnv_log_stat(DBEnvObject* self, PyObject* args)
6232 {
6233     int err;
6234     DB_LOG_STAT* statp = NULL;
6235     PyObject* d = NULL;
6236     u_int32_t flags = 0;
6237
6238     if (!PyArg_ParseTuple(args, "|i:log_stat", &flags))
6239         return NULL;
6240     CHECK_ENV_NOT_CLOSED(self);
6241
6242     MYDB_BEGIN_ALLOW_THREADS;
6243     err = self->db_env->log_stat(self->db_env, &statp, flags);
6244     MYDB_END_ALLOW_THREADS;
6245     RETURN_IF_ERR();
6246
6247     /* Turn the stat structure into a dictionary */
6248     d = PyDict_New();
6249     if (d == NULL) {
6250         if (statp)
6251             free(statp);
6252         return NULL;
6253     }
6254
6255 #define MAKE_ENTRY(name)  _addIntToDict(d, #name, statp->st_##name)
6256
6257     MAKE_ENTRY(magic);
6258     MAKE_ENTRY(version);
6259     MAKE_ENTRY(mode);
6260     MAKE_ENTRY(lg_bsize);
6261 #if (DBVER >= 44)
6262     MAKE_ENTRY(lg_size);
6263     MAKE_ENTRY(record);
6264 #endif
6265     MAKE_ENTRY(w_mbytes);
6266     MAKE_ENTRY(w_bytes);
6267     MAKE_ENTRY(wc_mbytes);
6268     MAKE_ENTRY(wc_bytes);
6269     MAKE_ENTRY(wcount);
6270     MAKE_ENTRY(wcount_fill);
6271 #if (DBVER >= 44)
6272     MAKE_ENTRY(rcount);
6273 #endif
6274     MAKE_ENTRY(scount);
6275     MAKE_ENTRY(cur_file);
6276     MAKE_ENTRY(cur_offset);
6277     MAKE_ENTRY(disk_file);
6278     MAKE_ENTRY(disk_offset);
6279     MAKE_ENTRY(maxcommitperflush);
6280     MAKE_ENTRY(mincommitperflush);
6281     MAKE_ENTRY(regsize);
6282     MAKE_ENTRY(region_wait);
6283     MAKE_ENTRY(region_nowait);
6284
6285 #undef MAKE_ENTRY
6286     free(statp);
6287     return d;
6288 } /* DBEnv_log_stat */
6289
6290
6291 #if (DBVER >= 43)
6292 static PyObject*
6293 DBEnv_log_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
6294 {
6295     int err;
6296     int flags=0;
6297     static char* kwnames[] = { "flags", NULL };
6298
6299     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:log_stat_print",
6300                 kwnames, &flags))
6301     {
6302         return NULL;
6303     }
6304     CHECK_ENV_NOT_CLOSED(self);
6305     MYDB_BEGIN_ALLOW_THREADS;
6306     err = self->db_env->log_stat_print(self->db_env, flags);
6307     MYDB_END_ALLOW_THREADS;
6308     RETURN_IF_ERR();
6309     RETURN_NONE();
6310 }
6311 #endif
6312
6313
6314 static PyObject*
6315 DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
6316 {
6317     int err;
6318     DB_LOCK_STAT* sp;
6319     PyObject* d = NULL;
6320     u_int32_t flags = 0;
6321
6322     if (!PyArg_ParseTuple(args, "|i:lock_stat", &flags))
6323         return NULL;
6324     CHECK_ENV_NOT_CLOSED(self);
6325
6326     MYDB_BEGIN_ALLOW_THREADS;
6327     err = self->db_env->lock_stat(self->db_env, &sp, flags);
6328     MYDB_END_ALLOW_THREADS;
6329     RETURN_IF_ERR();
6330
6331     /* Turn the stat structure into a dictionary */
6332     d = PyDict_New();
6333     if (d == NULL) {
6334         free(sp);
6335         return NULL;
6336     }
6337
6338 #define MAKE_ENTRY(name)  _addIntToDict(d, #name, sp->st_##name)
6339
6340     MAKE_ENTRY(id);
6341     MAKE_ENTRY(cur_maxid);
6342     MAKE_ENTRY(nmodes);
6343     MAKE_ENTRY(maxlocks);
6344     MAKE_ENTRY(maxlockers);
6345     MAKE_ENTRY(maxobjects);
6346     MAKE_ENTRY(nlocks);
6347     MAKE_ENTRY(maxnlocks);
6348     MAKE_ENTRY(nlockers);
6349     MAKE_ENTRY(maxnlockers);
6350     MAKE_ENTRY(nobjects);
6351     MAKE_ENTRY(maxnobjects);
6352     MAKE_ENTRY(nrequests);
6353     MAKE_ENTRY(nreleases);
6354 #if (DBVER >= 44)
6355     MAKE_ENTRY(nupgrade);
6356     MAKE_ENTRY(ndowngrade);
6357 #endif
6358 #if (DBVER < 44)
6359     MAKE_ENTRY(nnowaits);       /* these were renamed in 4.4 */
6360     MAKE_ENTRY(nconflicts);
6361 #else
6362     MAKE_ENTRY(lock_nowait);
6363     MAKE_ENTRY(lock_wait);
6364 #endif
6365     MAKE_ENTRY(ndeadlocks);
6366     MAKE_ENTRY(locktimeout);
6367     MAKE_ENTRY(txntimeout);
6368     MAKE_ENTRY(nlocktimeouts);
6369     MAKE_ENTRY(ntxntimeouts);
6370 #if (DBVER >= 46)
6371     MAKE_ENTRY(objs_wait);
6372     MAKE_ENTRY(objs_nowait);
6373     MAKE_ENTRY(lockers_wait);
6374     MAKE_ENTRY(lockers_nowait);
6375 #if (DBVER >= 47)
6376     MAKE_ENTRY(lock_wait);
6377     MAKE_ENTRY(lock_nowait);
6378 #else
6379     MAKE_ENTRY(locks_wait);
6380     MAKE_ENTRY(locks_nowait);
6381 #endif
6382     MAKE_ENTRY(hash_len);
6383 #endif
6384     MAKE_ENTRY(regsize);
6385     MAKE_ENTRY(region_wait);
6386     MAKE_ENTRY(region_nowait);
6387
6388 #undef MAKE_ENTRY
6389     free(sp);
6390     return d;
6391 }
6392
6393 #if (DBVER >= 43)
6394 static PyObject*
6395 DBEnv_lock_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
6396 {
6397     int err;
6398     int flags=0;
6399     static char* kwnames[] = { "flags", NULL };
6400
6401     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:lock_stat_print",
6402                 kwnames, &flags))
6403     {
6404         return NULL;
6405     }
6406     CHECK_ENV_NOT_CLOSED(self);
6407     MYDB_BEGIN_ALLOW_THREADS;
6408     err = self->db_env->lock_stat_print(self->db_env, flags);
6409     MYDB_END_ALLOW_THREADS;
6410     RETURN_IF_ERR();
6411     RETURN_NONE();
6412 }
6413 #endif
6414
6415
6416 static PyObject*
6417 DBEnv_log_cursor(DBEnvObject* self)
6418 {
6419     int err;
6420     DB_LOGC* dblogc;
6421
6422     CHECK_ENV_NOT_CLOSED(self);
6423
6424     MYDB_BEGIN_ALLOW_THREADS;
6425     err = self->db_env->log_cursor(self->db_env, &dblogc, 0);
6426     MYDB_END_ALLOW_THREADS;
6427     RETURN_IF_ERR();
6428     return (PyObject*) newDBLogCursorObject(dblogc, self);
6429 }
6430
6431
6432 static PyObject*
6433 DBEnv_log_flush(DBEnvObject* self)
6434 {
6435     int err;
6436
6437     CHECK_ENV_NOT_CLOSED(self);
6438
6439     MYDB_BEGIN_ALLOW_THREADS
6440     err = self->db_env->log_flush(self->db_env, NULL);
6441     MYDB_END_ALLOW_THREADS
6442
6443     RETURN_IF_ERR();
6444     RETURN_NONE();
6445 }
6446
6447 static PyObject*
6448 DBEnv_log_file(DBEnvObject* self, PyObject* args)
6449 {
6450     int err;
6451     DB_LSN lsn = {0, 0};
6452     int size = 20;
6453     char *name = NULL;
6454     PyObject *retval;
6455
6456     if (!PyArg_ParseTuple(args, "(ii):log_file", &lsn.file, &lsn.offset))
6457         return NULL;
6458
6459     CHECK_ENV_NOT_CLOSED(self);
6460
6461     do {
6462         name = malloc(size);
6463         if (!name) {
6464             PyErr_NoMemory();
6465             return NULL;
6466         }
6467         MYDB_BEGIN_ALLOW_THREADS;
6468         err = self->db_env->log_file(self->db_env, &lsn, name, size);
6469         MYDB_END_ALLOW_THREADS;
6470         if (err == EINVAL) {
6471             free(name);
6472             size *= 2;
6473         } else if (err) {
6474             free(name);
6475             RETURN_IF_ERR();
6476             assert(0);  /* Unreachable... supposely */
6477             return NULL;
6478         }
6479 /*
6480 ** If the final buffer we try is too small, we will
6481 ** get this exception:
6482 ** DBInvalidArgError:
6483 **    (22, 'Invalid argument -- DB_ENV->log_file: name buffer is too short')
6484 */
6485     } while ((err == EINVAL) && (size<(1<<17)));
6486
6487     RETURN_IF_ERR();  /* Maybe the size is not the problem */
6488
6489     retval = Py_BuildValue("s", name);
6490     free(name);
6491     return retval;
6492 }
6493
6494
6495 #if (DBVER >= 44)
6496 static PyObject*
6497 DBEnv_log_printf(DBEnvObject* self, PyObject* args, PyObject *kwargs)
6498 {
6499     int err;
6500     char *string;
6501     PyObject *txnobj = NULL;
6502     DB_TXN *txn = NULL;
6503     static char* kwnames[] = {"string", "txn", NULL };
6504
6505     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|O:log_printf", kwnames,
6506                 &string, &txnobj))
6507         return NULL;
6508
6509     CHECK_ENV_NOT_CLOSED(self);
6510
6511     if (!checkTxnObj(txnobj, &txn))
6512         return NULL;
6513
6514     /*
6515     ** Do not use the format string directly, to avoid attacks.
6516     */
6517     MYDB_BEGIN_ALLOW_THREADS;
6518     err = self->db_env->log_printf(self->db_env, txn, "%s", string);
6519     MYDB_END_ALLOW_THREADS;
6520
6521     RETURN_IF_ERR();
6522     RETURN_NONE();
6523 }
6524 #endif
6525
6526
6527 static PyObject*
6528 DBEnv_log_archive(DBEnvObject* self, PyObject* args)
6529 {
6530     int flags=0;
6531     int err;
6532     char **log_list = NULL;
6533     PyObject* list;
6534     PyObject* item = NULL;
6535
6536     if (!PyArg_ParseTuple(args, "|i:log_archive", &flags))
6537         return NULL;
6538
6539     CHECK_ENV_NOT_CLOSED(self);
6540     MYDB_BEGIN_ALLOW_THREADS;
6541     err = self->db_env->log_archive(self->db_env, &log_list, flags);
6542     MYDB_END_ALLOW_THREADS;
6543     RETURN_IF_ERR();
6544
6545     list = PyList_New(0);
6546     if (list == NULL) {
6547         if (log_list)
6548             free(log_list);
6549         return NULL;
6550     }
6551
6552     if (log_list) {
6553         char **log_list_start;
6554         for (log_list_start = log_list; *log_list != NULL; ++log_list) {
6555             item = PyBytes_FromString (*log_list);
6556             if (item == NULL) {
6557                 Py_DECREF(list);
6558                 list = NULL;
6559                 break;
6560             }
6561             if (PyList_Append(list, item)) {
6562                 Py_DECREF(list);
6563                 list = NULL;
6564                 Py_DECREF(item);
6565                 break;
6566             }
6567             Py_DECREF(item);
6568         }
6569         free(log_list_start);
6570     }
6571     return list;
6572 }
6573
6574
6575 #if (DBVER >= 44)
6576 static PyObject*
6577 DBEnv_mutex_stat(DBEnvObject* self, PyObject* args)
6578 {
6579     int err;
6580     DB_MUTEX_STAT* statp = NULL;
6581     PyObject* d = NULL;
6582     u_int32_t flags = 0;
6583
6584     if (!PyArg_ParseTuple(args, "|i:mutex_stat", &flags))
6585         return NULL;
6586     CHECK_ENV_NOT_CLOSED(self);
6587
6588     MYDB_BEGIN_ALLOW_THREADS;
6589     err = self->db_env->mutex_stat(self->db_env, &statp, flags);
6590     MYDB_END_ALLOW_THREADS;
6591     RETURN_IF_ERR();
6592
6593     /* Turn the stat structure into a dictionary */
6594     d = PyDict_New();
6595     if (d == NULL) {
6596         if (statp)
6597             free(statp);
6598         return NULL;
6599     }
6600
6601 #define MAKE_ENTRY(name)  _addIntToDict(d, #name, statp->st_##name)
6602
6603     MAKE_ENTRY(mutex_align);
6604     MAKE_ENTRY(mutex_tas_spins);
6605     MAKE_ENTRY(mutex_cnt);
6606     MAKE_ENTRY(mutex_free);
6607     MAKE_ENTRY(mutex_inuse);
6608     MAKE_ENTRY(mutex_inuse_max);
6609     MAKE_ENTRY(regsize);
6610     MAKE_ENTRY(region_wait);
6611     MAKE_ENTRY(region_nowait);
6612
6613 #undef MAKE_ENTRY
6614     free(statp);
6615     return d;
6616 }
6617 #endif
6618
6619
6620 #if (DBVER >= 44)
6621 static PyObject*
6622 DBEnv_mutex_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
6623 {
6624     int err;
6625     int flags=0;
6626     static char* kwnames[] = { "flags", NULL };
6627
6628     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:mutex_stat_print",
6629                 kwnames, &flags))
6630     {
6631         return NULL;
6632     }
6633     CHECK_ENV_NOT_CLOSED(self);
6634     MYDB_BEGIN_ALLOW_THREADS;
6635     err = self->db_env->mutex_stat_print(self->db_env, flags);
6636     MYDB_END_ALLOW_THREADS;
6637     RETURN_IF_ERR();
6638     RETURN_NONE();
6639 }
6640 #endif
6641
6642
6643 #if (DBVER >= 43)
6644 static PyObject*
6645 DBEnv_txn_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
6646 {
6647     int err;
6648     int flags=0;
6649     static char* kwnames[] = { "flags", NULL };
6650
6651     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat_print",
6652                 kwnames, &flags))
6653     {
6654         return NULL;
6655     }
6656
6657     CHECK_ENV_NOT_CLOSED(self);
6658
6659     MYDB_BEGIN_ALLOW_THREADS;
6660     err = self->db_env->txn_stat_print(self->db_env, flags);
6661     MYDB_END_ALLOW_THREADS;
6662     RETURN_IF_ERR();
6663     RETURN_NONE();
6664 }
6665 #endif
6666
6667
6668 static PyObject*
6669 DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
6670 {
6671     int err;
6672     DB_TXN_STAT* sp;
6673     PyObject* d = NULL;
6674     u_int32_t flags=0;
6675
6676     if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
6677         return NULL;
6678     CHECK_ENV_NOT_CLOSED(self);
6679
6680     MYDB_BEGIN_ALLOW_THREADS;
6681     err = self->db_env->txn_stat(self->db_env, &sp, flags);
6682     MYDB_END_ALLOW_THREADS;
6683     RETURN_IF_ERR();
6684
6685     /* Turn the stat structure into a dictionary */
6686     d = PyDict_New();
6687     if (d == NULL) {
6688         free(sp);
6689         return NULL;
6690     }
6691
6692 #define MAKE_ENTRY(name)        _addIntToDict(d, #name, sp->st_##name)
6693 #define MAKE_TIME_T_ENTRY(name) _addTimeTToDict(d, #name, sp->st_##name)
6694 #define MAKE_DB_LSN_ENTRY(name) _addDB_lsnToDict(d, #name, sp->st_##name)
6695
6696     MAKE_DB_LSN_ENTRY(last_ckp);
6697     MAKE_TIME_T_ENTRY(time_ckp);
6698     MAKE_ENTRY(last_txnid);
6699     MAKE_ENTRY(maxtxns);
6700     MAKE_ENTRY(nactive);
6701     MAKE_ENTRY(maxnactive);
6702 #if (DBVER >= 45)
6703     MAKE_ENTRY(nsnapshot);
6704     MAKE_ENTRY(maxnsnapshot);
6705 #endif
6706     MAKE_ENTRY(nbegins);
6707     MAKE_ENTRY(naborts);
6708     MAKE_ENTRY(ncommits);
6709     MAKE_ENTRY(nrestores);
6710     MAKE_ENTRY(regsize);
6711     MAKE_ENTRY(region_wait);
6712     MAKE_ENTRY(region_nowait);
6713
6714 #undef MAKE_DB_LSN_ENTRY
6715 #undef MAKE_ENTRY
6716 #undef MAKE_TIME_T_ENTRY
6717     free(sp);
6718     return d;
6719 }
6720
6721
6722 static PyObject*
6723 DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
6724 {
6725     int flags=0;
6726     int oldValue=0;
6727
6728     if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
6729         return NULL;
6730     CHECK_ENV_NOT_CLOSED(self);
6731
6732     if (self->moduleFlags.getReturnsNone)
6733         ++oldValue;
6734     if (self->moduleFlags.cursorSetReturnsNone)
6735         ++oldValue;
6736     self->moduleFlags.getReturnsNone = (flags >= 1);
6737     self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
6738     return NUMBER_FromLong(oldValue);
6739 }
6740
6741 static PyObject*
6742 DBEnv_get_private(DBEnvObject* self)
6743 {
6744     /* We can give out the private field even if dbenv is closed */
6745     Py_INCREF(self->private_obj);
6746     return self->private_obj;
6747 }
6748
6749 static PyObject*
6750 DBEnv_set_private(DBEnvObject* self, PyObject* private_obj)
6751 {
6752     /* We can set the private field even if dbenv is closed */
6753     Py_DECREF(self->private_obj);
6754     Py_INCREF(private_obj);
6755     self->private_obj = private_obj;
6756     RETURN_NONE();
6757 }
6758
6759
6760 #if (DBVER < 48)
6761 static PyObject*
6762 DBEnv_set_rpc_server(DBEnvObject* self, PyObject* args, PyObject* kwargs)
6763 {
6764     int err;
6765     char *host;
6766     long cl_timeout=0, sv_timeout=0;
6767
6768     static char* kwnames[] = { "host", "cl_timeout", "sv_timeout", NULL};
6769
6770     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ll:set_rpc_server", kwnames,
6771                                      &host, &cl_timeout, &sv_timeout))
6772         return NULL;
6773     CHECK_ENV_NOT_CLOSED(self);
6774
6775     MYDB_BEGIN_ALLOW_THREADS;
6776     err = self->db_env->set_rpc_server(self->db_env, NULL, host, cl_timeout,
6777             sv_timeout, 0);
6778     MYDB_END_ALLOW_THREADS;
6779     RETURN_IF_ERR();
6780     RETURN_NONE();
6781 }
6782 #endif
6783
6784 #if (DBVER >= 43)
6785 static PyObject*
6786 DBEnv_set_mp_max_openfd(DBEnvObject* self, PyObject* args)
6787 {
6788     int err;
6789     int maxopenfd;
6790
6791     if (!PyArg_ParseTuple(args, "i:set_mp_max_openfd", &maxopenfd)) {
6792         return NULL;
6793     }
6794     CHECK_ENV_NOT_CLOSED(self);
6795     MYDB_BEGIN_ALLOW_THREADS;
6796     err = self->db_env->set_mp_max_openfd(self->db_env, maxopenfd);
6797     MYDB_END_ALLOW_THREADS;
6798     RETURN_IF_ERR();
6799     RETURN_NONE();
6800 }
6801
6802 static PyObject*
6803 DBEnv_get_mp_max_openfd(DBEnvObject* self)
6804 {
6805     int err;
6806     int maxopenfd;
6807
6808     CHECK_ENV_NOT_CLOSED(self);
6809
6810     MYDB_BEGIN_ALLOW_THREADS;
6811     err = self->db_env->get_mp_max_openfd(self->db_env, &maxopenfd);
6812     MYDB_END_ALLOW_THREADS;
6813     RETURN_IF_ERR();
6814     return NUMBER_FromLong(maxopenfd);
6815 }
6816
6817
6818 static PyObject*
6819 DBEnv_set_mp_max_write(DBEnvObject* self, PyObject* args)
6820 {
6821     int err;
6822     int maxwrite, maxwrite_sleep;
6823
6824     if (!PyArg_ParseTuple(args, "ii:set_mp_max_write", &maxwrite,
6825                 &maxwrite_sleep)) {
6826         return NULL;
6827     }
6828     CHECK_ENV_NOT_CLOSED(self);
6829     MYDB_BEGIN_ALLOW_THREADS;
6830     err = self->db_env->set_mp_max_write(self->db_env, maxwrite,
6831             maxwrite_sleep);
6832     MYDB_END_ALLOW_THREADS;
6833     RETURN_IF_ERR();
6834     RETURN_NONE();
6835 }
6836
6837 static PyObject*
6838 DBEnv_get_mp_max_write(DBEnvObject* self)
6839 {
6840     int err;
6841     int maxwrite;
6842 #if (DBVER >= 46)
6843     db_timeout_t maxwrite_sleep;
6844 #else
6845     int maxwrite_sleep;
6846 #endif
6847
6848     CHECK_ENV_NOT_CLOSED(self);
6849
6850     MYDB_BEGIN_ALLOW_THREADS;
6851     err = self->db_env->get_mp_max_write(self->db_env, &maxwrite,
6852             &maxwrite_sleep);
6853     MYDB_END_ALLOW_THREADS;
6854     RETURN_IF_ERR();
6855
6856     return Py_BuildValue("(ii)", maxwrite, (int)maxwrite_sleep);
6857 }
6858 #endif
6859
6860
6861 static PyObject*
6862 DBEnv_set_verbose(DBEnvObject* self, PyObject* args)
6863 {
6864     int err;
6865     int which, onoff;
6866
6867     if (!PyArg_ParseTuple(args, "ii:set_verbose", &which, &onoff)) {
6868         return NULL;
6869     }
6870     CHECK_ENV_NOT_CLOSED(self);
6871     MYDB_BEGIN_ALLOW_THREADS;
6872     err = self->db_env->set_verbose(self->db_env, which, onoff);
6873     MYDB_END_ALLOW_THREADS;
6874     RETURN_IF_ERR();
6875     RETURN_NONE();
6876 }
6877
6878 #if (DBVER >= 42)
6879 static PyObject*
6880 DBEnv_get_verbose(DBEnvObject* self, PyObject* args)
6881 {
6882     int err;
6883     int which;
6884     int verbose;
6885
6886     if (!PyArg_ParseTuple(args, "i:get_verbose", &which)) {
6887         return NULL;
6888     }
6889     CHECK_ENV_NOT_CLOSED(self);
6890     MYDB_BEGIN_ALLOW_THREADS;
6891     err = self->db_env->get_verbose(self->db_env, which, &verbose);
6892     MYDB_END_ALLOW_THREADS;
6893     RETURN_IF_ERR();
6894     return PyBool_FromLong(verbose);
6895 }
6896 #endif
6897
6898 #if (DBVER >= 45)
6899 static void
6900 _dbenv_event_notifyCallback(DB_ENV* db_env, u_int32_t event, void *event_info)
6901 {
6902     DBEnvObject *dbenv;
6903     PyObject* callback;
6904     PyObject* args;
6905     PyObject* result = NULL;
6906
6907     MYDB_BEGIN_BLOCK_THREADS;
6908     dbenv = (DBEnvObject *)db_env->app_private;
6909     callback = dbenv->event_notifyCallback;
6910     if (callback) {
6911         if (event == DB_EVENT_REP_NEWMASTER) {
6912             args = Py_BuildValue("(Oii)", dbenv, event, *((int *)event_info));
6913         } else {
6914             args = Py_BuildValue("(OiO)", dbenv, event, Py_None);
6915         }
6916         if (args) {
6917             result = PyEval_CallObject(callback, args);
6918         }
6919         if ((!args) || (!result)) {
6920             PyErr_Print();
6921         }
6922         Py_XDECREF(args);
6923         Py_XDECREF(result);
6924     }
6925     MYDB_END_BLOCK_THREADS;
6926 }
6927 #endif
6928
6929 #if (DBVER >= 45)
6930 static PyObject*
6931 DBEnv_set_event_notify(DBEnvObject* self, PyObject* notifyFunc)
6932 {
6933     int err;
6934
6935     CHECK_ENV_NOT_CLOSED(self);
6936
6937     if (!PyCallable_Check(notifyFunc)) {
6938             makeTypeError("Callable", notifyFunc);
6939             return NULL;
6940     }
6941
6942     Py_XDECREF(self->event_notifyCallback);
6943     Py_INCREF(notifyFunc);
6944     self->event_notifyCallback = notifyFunc;
6945
6946     /* This is to workaround a problem with un-initialized threads (see
6947        comment in DB_associate) */
6948 #ifdef WITH_THREAD
6949     PyEval_InitThreads();
6950 #endif
6951
6952     MYDB_BEGIN_ALLOW_THREADS;
6953     err = self->db_env->set_event_notify(self->db_env, _dbenv_event_notifyCallback);
6954     MYDB_END_ALLOW_THREADS;
6955
6956     if (err) {
6957             Py_DECREF(notifyFunc);
6958             self->event_notifyCallback = NULL;
6959     }
6960
6961     RETURN_IF_ERR();
6962     RETURN_NONE();
6963 }
6964 #endif
6965
6966
6967 /* --------------------------------------------------------------------- */
6968 /* REPLICATION METHODS: Base Replication */
6969
6970
6971 static PyObject*
6972 DBEnv_rep_process_message(DBEnvObject* self, PyObject* args)
6973 {
6974     int err;
6975     PyObject *control_py, *rec_py;
6976     DBT control, rec;
6977     int envid;
6978 #if (DBVER >= 42)
6979     DB_LSN lsn;
6980 #endif
6981
6982     if (!PyArg_ParseTuple(args, "OOi:rep_process_message", &control_py,
6983                 &rec_py, &envid))
6984         return NULL;
6985     CHECK_ENV_NOT_CLOSED(self);
6986
6987     if (!make_dbt(control_py, &control))
6988         return NULL;
6989     if (!make_dbt(rec_py, &rec))
6990         return NULL;
6991
6992     MYDB_BEGIN_ALLOW_THREADS;
6993 #if (DBVER >= 46)
6994     err = self->db_env->rep_process_message(self->db_env, &control, &rec,
6995             envid, &lsn);
6996 #else
6997 #if (DBVER >= 42)
6998     err = self->db_env->rep_process_message(self->db_env, &control, &rec,
6999             &envid, &lsn);
7000 #else
7001     err = self->db_env->rep_process_message(self->db_env, &control, &rec,
7002             &envid);
7003 #endif
7004 #endif
7005     MYDB_END_ALLOW_THREADS;
7006     switch (err) {
7007         case DB_REP_NEWMASTER :
7008           return Py_BuildValue("(iO)", envid, Py_None);
7009           break;
7010
7011         case DB_REP_DUPMASTER :
7012         case DB_REP_HOLDELECTION :
7013 #if (DBVER >= 44)
7014         case DB_REP_IGNORE :
7015         case DB_REP_JOIN_FAILURE :
7016 #endif
7017             return Py_BuildValue("(iO)", err, Py_None);
7018             break;
7019         case DB_REP_NEWSITE :
7020             {
7021                 PyObject *tmp, *r;
7022
7023                 if (!(tmp = PyBytes_FromStringAndSize(rec.data, rec.size))) {
7024                     return NULL;
7025                 }
7026
7027                 r = Py_BuildValue("(iO)", err, tmp);
7028                 Py_DECREF(tmp);
7029                 return r;
7030                 break;
7031             }
7032 #if (DBVER >= 42)
7033         case DB_REP_NOTPERM :
7034         case DB_REP_ISPERM :
7035             return Py_BuildValue("(i(ll))", err, lsn.file, lsn.offset);
7036             break;
7037 #endif
7038     }
7039     RETURN_IF_ERR();
7040     return Py_BuildValue("(OO)", Py_None, Py_None);
7041 }
7042
7043 static int
7044 _DBEnv_rep_transportCallback(DB_ENV* db_env, const DBT* control, const DBT* rec,
7045         const DB_LSN *lsn, int envid, u_int32_t flags)
7046 {
7047     DBEnvObject *dbenv;
7048     PyObject* rep_transport;
7049     PyObject* args;
7050     PyObject *a, *b;
7051     PyObject* result = NULL;
7052     int ret=0;
7053
7054     MYDB_BEGIN_BLOCK_THREADS;
7055     dbenv = (DBEnvObject *)db_env->app_private;
7056     rep_transport = dbenv->rep_transport;
7057
7058     /*
7059     ** The errors in 'a' or 'b' are detected in "Py_BuildValue".
7060     */
7061     a = PyBytes_FromStringAndSize(control->data, control->size);
7062     b = PyBytes_FromStringAndSize(rec->data, rec->size);
7063
7064     args = Py_BuildValue(
7065 #if (PY_VERSION_HEX >= 0x02040000)
7066             "(OOO(ll)iI)",
7067 #else
7068             "(OOO(ll)ii)",
7069 #endif
7070             dbenv,
7071             a, b,
7072             lsn->file, lsn->offset, envid, flags);
7073     if (args) {
7074         result = PyEval_CallObject(rep_transport, args);
7075     }
7076
7077     if ((!args) || (!result)) {
7078         PyErr_Print();
7079         ret = -1;
7080     }
7081     Py_XDECREF(a);
7082     Py_XDECREF(b);
7083     Py_XDECREF(args);
7084     Py_XDECREF(result);
7085     MYDB_END_BLOCK_THREADS;
7086     return ret;
7087 }
7088
7089 #if (DBVER <= 41)
7090 static int
7091 _DBEnv_rep_transportCallbackOLD(DB_ENV* db_env, const DBT* control, const DBT* rec,
7092         int envid, u_int32_t flags)
7093 {
7094     DB_LSN lsn;
7095
7096     lsn.file = -1;  /* Dummy values */
7097     lsn.offset = -1;
7098     return _DBEnv_rep_transportCallback(db_env, control, rec, &lsn, envid,
7099             flags);
7100 }
7101 #endif
7102
7103 static PyObject*
7104 DBEnv_rep_set_transport(DBEnvObject* self, PyObject* args)
7105 {
7106     int err;
7107     int envid;
7108     PyObject *rep_transport;
7109
7110     if (!PyArg_ParseTuple(args, "iO:rep_set_transport", &envid, &rep_transport))
7111         return NULL;
7112     CHECK_ENV_NOT_CLOSED(self);
7113     if (!PyCallable_Check(rep_transport)) {
7114         makeTypeError("Callable", rep_transport);
7115         return NULL;
7116     }
7117
7118     MYDB_BEGIN_ALLOW_THREADS;
7119 #if (DBVER >=45)
7120     err = self->db_env->rep_set_transport(self->db_env, envid,
7121             &_DBEnv_rep_transportCallback);
7122 #else
7123 #if (DBVER >= 42)
7124     err = self->db_env->set_rep_transport(self->db_env, envid,
7125             &_DBEnv_rep_transportCallback);
7126 #else
7127     err = self->db_env->set_rep_transport(self->db_env, envid,
7128             &_DBEnv_rep_transportCallbackOLD);
7129 #endif
7130 #endif
7131     MYDB_END_ALLOW_THREADS;
7132     RETURN_IF_ERR();
7133
7134     Py_DECREF(self->rep_transport);
7135     Py_INCREF(rep_transport);
7136     self->rep_transport = rep_transport;
7137     RETURN_NONE();
7138 }
7139
7140 #if (DBVER >= 47)
7141 static PyObject*
7142 DBEnv_rep_set_request(DBEnvObject* self, PyObject* args)
7143 {
7144     int err;
7145     unsigned int minimum, maximum;
7146
7147     if (!PyArg_ParseTuple(args,"II:rep_set_request", &minimum, &maximum))
7148         return NULL;
7149     CHECK_ENV_NOT_CLOSED(self);
7150
7151     MYDB_BEGIN_ALLOW_THREADS;
7152     err = self->db_env->rep_set_request(self->db_env, minimum, maximum);
7153     MYDB_END_ALLOW_THREADS;
7154     RETURN_IF_ERR();
7155     RETURN_NONE();
7156 }
7157
7158 static PyObject*
7159 DBEnv_rep_get_request(DBEnvObject* self)
7160 {
7161     int err;
7162     u_int32_t minimum, maximum;
7163
7164     CHECK_ENV_NOT_CLOSED(self);
7165     MYDB_BEGIN_ALLOW_THREADS;
7166     err = self->db_env->rep_get_request(self->db_env, &minimum, &maximum);
7167     MYDB_END_ALLOW_THREADS;
7168     RETURN_IF_ERR();
7169 #if (PY_VERSION_HEX >= 0x02040000)
7170     return Py_BuildValue("II", minimum, maximum);
7171 #else
7172     return Py_BuildValue("ii", minimum, maximum);
7173 #endif
7174 }
7175 #endif
7176
7177 #if (DBVER >= 45)
7178 static PyObject*
7179 DBEnv_rep_set_limit(DBEnvObject* self, PyObject* args)
7180 {
7181     int err;
7182     int limit;
7183
7184     if (!PyArg_ParseTuple(args,"i:rep_set_limit", &limit))
7185         return NULL;
7186     CHECK_ENV_NOT_CLOSED(self);
7187
7188     MYDB_BEGIN_ALLOW_THREADS;
7189     err = self->db_env->rep_set_limit(self->db_env, 0, limit);
7190     MYDB_END_ALLOW_THREADS;
7191     RETURN_IF_ERR();
7192     RETURN_NONE();
7193 }
7194
7195 static PyObject*
7196 DBEnv_rep_get_limit(DBEnvObject* self)
7197 {
7198     int err;
7199     u_int32_t gbytes, bytes;
7200
7201     CHECK_ENV_NOT_CLOSED(self);
7202     MYDB_BEGIN_ALLOW_THREADS;
7203     err = self->db_env->rep_get_limit(self->db_env, &gbytes, &bytes);
7204     MYDB_END_ALLOW_THREADS;
7205     RETURN_IF_ERR();
7206     return NUMBER_FromLong(bytes);
7207 }
7208 #endif
7209
7210 #if (DBVER >= 44)
7211 static PyObject*
7212 DBEnv_rep_set_config(DBEnvObject* self, PyObject* args)
7213 {
7214     int err;
7215     int which;
7216     int onoff;
7217
7218     if (!PyArg_ParseTuple(args,"ii:rep_set_config", &which, &onoff))
7219         return NULL;
7220     CHECK_ENV_NOT_CLOSED(self);
7221
7222     MYDB_BEGIN_ALLOW_THREADS;
7223     err = self->db_env->rep_set_config(self->db_env, which, onoff);
7224     MYDB_END_ALLOW_THREADS;
7225     RETURN_IF_ERR();
7226     RETURN_NONE();
7227 }
7228
7229 static PyObject*
7230 DBEnv_rep_get_config(DBEnvObject* self, PyObject* args)
7231 {
7232     int err;
7233     int which;
7234     int onoff;
7235
7236     if (!PyArg_ParseTuple(args, "i:rep_get_config", &which)) {
7237         return NULL;
7238     }
7239     CHECK_ENV_NOT_CLOSED(self);
7240     MYDB_BEGIN_ALLOW_THREADS;
7241     err = self->db_env->rep_get_config(self->db_env, which, &onoff);
7242     MYDB_END_ALLOW_THREADS;
7243     RETURN_IF_ERR();
7244     return PyBool_FromLong(onoff);
7245 }
7246 #endif
7247
7248 #if (DBVER >= 46)
7249 static PyObject*
7250 DBEnv_rep_elect(DBEnvObject* self, PyObject* args)
7251 {
7252     int err;
7253     u_int32_t nsites, nvotes;
7254
7255     if (!PyArg_ParseTuple(args, "II:rep_elect", &nsites, &nvotes)) {
7256         return NULL;
7257     }
7258     CHECK_ENV_NOT_CLOSED(self);
7259     MYDB_BEGIN_ALLOW_THREADS;
7260     err = self->db_env->rep_elect(self->db_env, nsites, nvotes, 0);
7261     MYDB_END_ALLOW_THREADS;
7262     RETURN_IF_ERR();
7263     RETURN_NONE();
7264 }
7265 #endif
7266
7267 static PyObject*
7268 DBEnv_rep_start(DBEnvObject* self, PyObject* args, PyObject* kwargs)
7269 {
7270     int err;
7271     PyObject *cdata_py = Py_None;
7272     DBT cdata;
7273     int flags;
7274     static char* kwnames[] = {"flags","cdata", NULL};
7275
7276     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
7277                 "i|O:rep_start", kwnames, &flags, &cdata_py))
7278     {
7279             return NULL;
7280     }
7281     CHECK_ENV_NOT_CLOSED(self);
7282
7283     if (!make_dbt(cdata_py, &cdata))
7284         return NULL;
7285
7286     MYDB_BEGIN_ALLOW_THREADS;
7287     err = self->db_env->rep_start(self->db_env, cdata.size ? &cdata : NULL,
7288             flags);
7289     MYDB_END_ALLOW_THREADS;
7290     RETURN_IF_ERR();
7291     RETURN_NONE();
7292 }
7293
7294 #if (DBVER >= 44)
7295 static PyObject*
7296 DBEnv_rep_sync(DBEnvObject* self)
7297 {
7298     int err;
7299
7300     CHECK_ENV_NOT_CLOSED(self);
7301     MYDB_BEGIN_ALLOW_THREADS;
7302     err = self->db_env->rep_sync(self->db_env, 0);
7303     MYDB_END_ALLOW_THREADS;
7304     RETURN_IF_ERR();
7305     RETURN_NONE();
7306 }
7307 #endif
7308
7309
7310 #if (DBVER >= 45)
7311 static PyObject*
7312 DBEnv_rep_set_nsites(DBEnvObject* self, PyObject* args)
7313 {
7314     int err;
7315     int nsites;
7316
7317     if (!PyArg_ParseTuple(args, "i:rep_set_nsites", &nsites)) {
7318         return NULL;
7319     }
7320     CHECK_ENV_NOT_CLOSED(self);
7321     MYDB_BEGIN_ALLOW_THREADS;
7322     err = self->db_env->rep_set_nsites(self->db_env, nsites);
7323     MYDB_END_ALLOW_THREADS;
7324     RETURN_IF_ERR();
7325     RETURN_NONE();
7326 }
7327
7328 static PyObject*
7329 DBEnv_rep_get_nsites(DBEnvObject* self)
7330 {
7331     int err;
7332 #if (DBVER >= 47)
7333     u_int32_t nsites;
7334 #else
7335     int nsites;
7336 #endif
7337
7338     CHECK_ENV_NOT_CLOSED(self);
7339     MYDB_BEGIN_ALLOW_THREADS;
7340     err = self->db_env->rep_get_nsites(self->db_env, &nsites);
7341     MYDB_END_ALLOW_THREADS;
7342     RETURN_IF_ERR();
7343     return NUMBER_FromLong(nsites);
7344 }
7345
7346 static PyObject*
7347 DBEnv_rep_set_priority(DBEnvObject* self, PyObject* args)
7348 {
7349     int err;
7350     int priority;
7351
7352     if (!PyArg_ParseTuple(args, "i:rep_set_priority", &priority)) {
7353         return NULL;
7354     }
7355     CHECK_ENV_NOT_CLOSED(self);
7356     MYDB_BEGIN_ALLOW_THREADS;
7357     err = self->db_env->rep_set_priority(self->db_env, priority);
7358     MYDB_END_ALLOW_THREADS;
7359     RETURN_IF_ERR();
7360     RETURN_NONE();
7361 }
7362
7363 static PyObject*
7364 DBEnv_rep_get_priority(DBEnvObject* self)
7365 {
7366     int err;
7367 #if (DBVER >= 47)
7368     u_int32_t priority;
7369 #else
7370     int priority;
7371 #endif
7372
7373     CHECK_ENV_NOT_CLOSED(self);
7374     MYDB_BEGIN_ALLOW_THREADS;
7375     err = self->db_env->rep_get_priority(self->db_env, &priority);
7376     MYDB_END_ALLOW_THREADS;
7377     RETURN_IF_ERR();
7378     return NUMBER_FromLong(priority);
7379 }
7380
7381 static PyObject*
7382 DBEnv_rep_set_timeout(DBEnvObject* self, PyObject* args)
7383 {
7384     int err;
7385     int which, timeout;
7386
7387     if (!PyArg_ParseTuple(args, "ii:rep_set_timeout", &which, &timeout)) {
7388         return NULL;
7389     }
7390     CHECK_ENV_NOT_CLOSED(self);
7391     MYDB_BEGIN_ALLOW_THREADS;
7392     err = self->db_env->rep_set_timeout(self->db_env, which, timeout);
7393     MYDB_END_ALLOW_THREADS;
7394     RETURN_IF_ERR();
7395     RETURN_NONE();
7396 }
7397
7398 static PyObject*
7399 DBEnv_rep_get_timeout(DBEnvObject* self, PyObject* args)
7400 {
7401     int err;
7402     int which;
7403     u_int32_t timeout;
7404
7405     if (!PyArg_ParseTuple(args, "i:rep_get_timeout", &which)) {
7406         return NULL;
7407     }
7408     CHECK_ENV_NOT_CLOSED(self);
7409     MYDB_BEGIN_ALLOW_THREADS;
7410     err = self->db_env->rep_get_timeout(self->db_env, which, &timeout);
7411     MYDB_END_ALLOW_THREADS;
7412     RETURN_IF_ERR();
7413     return NUMBER_FromLong(timeout);
7414 }
7415 #endif
7416
7417
7418 #if (DBVER >= 47)
7419 static PyObject*
7420 DBEnv_rep_set_clockskew(DBEnvObject* self, PyObject* args)
7421 {
7422     int err;
7423     unsigned int fast, slow;
7424
7425 #if (PY_VERSION_HEX >= 0x02040000)
7426     if (!PyArg_ParseTuple(args,"II:rep_set_clockskew", &fast, &slow))
7427         return NULL;
7428 #else
7429     if (!PyArg_ParseTuple(args,"ii:rep_set_clockskew", &fast, &slow))
7430         return NULL;
7431 #endif
7432
7433     CHECK_ENV_NOT_CLOSED(self);
7434
7435     MYDB_BEGIN_ALLOW_THREADS;
7436     err = self->db_env->rep_set_clockskew(self->db_env, fast, slow);
7437     MYDB_END_ALLOW_THREADS;
7438     RETURN_IF_ERR();
7439     RETURN_NONE();
7440 }
7441
7442 static PyObject*
7443 DBEnv_rep_get_clockskew(DBEnvObject* self)
7444 {
7445     int err;
7446     unsigned int fast, slow;
7447
7448     CHECK_ENV_NOT_CLOSED(self);
7449     MYDB_BEGIN_ALLOW_THREADS;
7450     err = self->db_env->rep_get_clockskew(self->db_env, &fast, &slow);
7451     MYDB_END_ALLOW_THREADS;
7452     RETURN_IF_ERR();
7453 #if (PY_VERSION_HEX >= 0x02040000)
7454     return Py_BuildValue("(II)", fast, slow);
7455 #else
7456     return Py_BuildValue("(ii)", fast, slow);
7457 #endif
7458 }
7459 #endif
7460
7461 #if (DBVER >= 43)
7462 static PyObject*
7463 DBEnv_rep_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
7464 {
7465     int err;
7466     int flags=0;
7467     static char* kwnames[] = { "flags", NULL };
7468
7469     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:rep_stat_print",
7470                 kwnames, &flags))
7471     {
7472         return NULL;
7473     }
7474     CHECK_ENV_NOT_CLOSED(self);
7475     MYDB_BEGIN_ALLOW_THREADS;
7476     err = self->db_env->rep_stat_print(self->db_env, flags);
7477     MYDB_END_ALLOW_THREADS;
7478     RETURN_IF_ERR();
7479     RETURN_NONE();
7480 }
7481 #endif
7482
7483 static PyObject*
7484 DBEnv_rep_stat(DBEnvObject* self, PyObject* args, PyObject *kwargs)
7485 {
7486     int err;
7487     int flags=0;
7488     DB_REP_STAT *statp;
7489     PyObject *stats;
7490     static char* kwnames[] = { "flags", NULL };
7491
7492     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:rep_stat",
7493                 kwnames, &flags))
7494     {
7495         return NULL;
7496     }
7497     CHECK_ENV_NOT_CLOSED(self);
7498     MYDB_BEGIN_ALLOW_THREADS;
7499     err = self->db_env->rep_stat(self->db_env, &statp, flags);
7500     MYDB_END_ALLOW_THREADS;
7501     RETURN_IF_ERR();
7502
7503     stats=PyDict_New();
7504     if (stats == NULL) {
7505         free(statp);
7506         return NULL;
7507     }
7508
7509 #define MAKE_ENTRY(name)  _addIntToDict(stats, #name, statp->st_##name)
7510 #define MAKE_DB_LSN_ENTRY(name) _addDB_lsnToDict(stats , #name, statp->st_##name)
7511
7512 #if (DBVER >= 44)
7513     MAKE_ENTRY(bulk_fills);
7514     MAKE_ENTRY(bulk_overflows);
7515     MAKE_ENTRY(bulk_records);
7516     MAKE_ENTRY(bulk_transfers);
7517     MAKE_ENTRY(client_rerequests);
7518     MAKE_ENTRY(client_svc_miss);
7519     MAKE_ENTRY(client_svc_req);
7520 #endif
7521     MAKE_ENTRY(dupmasters);
7522 #if (DBVER >= 43)
7523     MAKE_ENTRY(egen);
7524     MAKE_ENTRY(election_nvotes);
7525     MAKE_ENTRY(startup_complete);
7526     MAKE_ENTRY(pg_duplicated);
7527     MAKE_ENTRY(pg_records);
7528     MAKE_ENTRY(pg_requested);
7529     MAKE_ENTRY(next_pg);
7530     MAKE_ENTRY(waiting_pg);
7531 #endif
7532     MAKE_ENTRY(election_cur_winner);
7533     MAKE_ENTRY(election_gen);
7534     MAKE_DB_LSN_ENTRY(election_lsn);
7535     MAKE_ENTRY(election_nsites);
7536     MAKE_ENTRY(election_priority);
7537 #if (DBVER >= 44)
7538     MAKE_ENTRY(election_sec);
7539     MAKE_ENTRY(election_usec);
7540 #endif
7541     MAKE_ENTRY(election_status);
7542     MAKE_ENTRY(election_tiebreaker);
7543     MAKE_ENTRY(election_votes);
7544     MAKE_ENTRY(elections);
7545     MAKE_ENTRY(elections_won);
7546     MAKE_ENTRY(env_id);
7547     MAKE_ENTRY(env_priority);
7548     MAKE_ENTRY(gen);
7549     MAKE_ENTRY(log_duplicated);
7550     MAKE_ENTRY(log_queued);
7551     MAKE_ENTRY(log_queued_max);
7552     MAKE_ENTRY(log_queued_total);
7553     MAKE_ENTRY(log_records);
7554     MAKE_ENTRY(log_requested);
7555     MAKE_ENTRY(master);
7556     MAKE_ENTRY(master_changes);
7557 #if (DBVER >= 47)
7558     MAKE_ENTRY(max_lease_sec);
7559     MAKE_ENTRY(max_lease_usec);
7560     MAKE_DB_LSN_ENTRY(max_perm_lsn);
7561 #endif
7562     MAKE_ENTRY(msgs_badgen);
7563     MAKE_ENTRY(msgs_processed);
7564     MAKE_ENTRY(msgs_recover);
7565     MAKE_ENTRY(msgs_send_failures);
7566     MAKE_ENTRY(msgs_sent);
7567     MAKE_ENTRY(newsites);
7568     MAKE_DB_LSN_ENTRY(next_lsn);
7569     MAKE_ENTRY(nsites);
7570     MAKE_ENTRY(nthrottles);
7571     MAKE_ENTRY(outdated);
7572 #if (DBVER >= 46)
7573     MAKE_ENTRY(startsync_delayed);
7574 #endif
7575     MAKE_ENTRY(status);
7576     MAKE_ENTRY(txns_applied);
7577     MAKE_DB_LSN_ENTRY(waiting_lsn);
7578
7579 #undef MAKE_DB_LSN_ENTRY
7580 #undef MAKE_ENTRY
7581
7582     free(statp);
7583     return stats;
7584 }
7585
7586 /* --------------------------------------------------------------------- */
7587 /* REPLICATION METHODS: Replication Manager */
7588
7589 #if (DBVER >= 45)
7590 static PyObject*
7591 DBEnv_repmgr_start(DBEnvObject* self, PyObject* args, PyObject*
7592         kwargs)
7593 {
7594     int err;
7595     int nthreads, flags;
7596     static char* kwnames[] = {"nthreads","flags", NULL};
7597
7598     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
7599                 "ii:repmgr_start", kwnames, &nthreads, &flags))
7600     {
7601             return NULL;
7602     }
7603     CHECK_ENV_NOT_CLOSED(self);
7604     MYDB_BEGIN_ALLOW_THREADS;
7605     err = self->db_env->repmgr_start(self->db_env, nthreads, flags);
7606     MYDB_END_ALLOW_THREADS;
7607     RETURN_IF_ERR();
7608     RETURN_NONE();
7609 }
7610
7611 static PyObject*
7612 DBEnv_repmgr_set_local_site(DBEnvObject* self, PyObject* args, PyObject*
7613         kwargs)
7614 {
7615     int err;
7616     char *host;
7617     int port;
7618     int flags = 0;
7619     static char* kwnames[] = {"host", "port", "flags", NULL};
7620
7621     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
7622                 "si|i:repmgr_set_local_site", kwnames, &host, &port, &flags))
7623     {
7624             return NULL;
7625     }
7626     CHECK_ENV_NOT_CLOSED(self);
7627     MYDB_BEGIN_ALLOW_THREADS;
7628     err = self->db_env->repmgr_set_local_site(self->db_env, host, port, flags);
7629     MYDB_END_ALLOW_THREADS;
7630     RETURN_IF_ERR();
7631     RETURN_NONE();
7632 }
7633
7634 static PyObject*
7635 DBEnv_repmgr_add_remote_site(DBEnvObject* self, PyObject* args, PyObject*
7636         kwargs)
7637 {
7638     int err;
7639     char *host;
7640     int port;
7641     int flags = 0;
7642     int eidp;
7643     static char* kwnames[] = {"host", "port", "flags", NULL};
7644
7645     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
7646                 "si|i:repmgr_add_remote_site", kwnames, &host, &port, &flags))
7647     {
7648             return NULL;
7649     }
7650     CHECK_ENV_NOT_CLOSED(self);
7651     MYDB_BEGIN_ALLOW_THREADS;
7652     err = self->db_env->repmgr_add_remote_site(self->db_env, host, port, &eidp, flags);
7653     MYDB_END_ALLOW_THREADS;
7654     RETURN_IF_ERR();
7655     return NUMBER_FromLong(eidp);
7656 }
7657
7658 static PyObject*
7659 DBEnv_repmgr_set_ack_policy(DBEnvObject* self, PyObject* args)
7660 {
7661     int err;
7662     int ack_policy;
7663
7664     if (!PyArg_ParseTuple(args, "i:repmgr_set_ack_policy", &ack_policy))
7665     {
7666             return NULL;
7667     }
7668     CHECK_ENV_NOT_CLOSED(self);
7669     MYDB_BEGIN_ALLOW_THREADS;
7670     err = self->db_env->repmgr_set_ack_policy(self->db_env, ack_policy);
7671     MYDB_END_ALLOW_THREADS;
7672     RETURN_IF_ERR();
7673     RETURN_NONE();
7674 }
7675
7676 static PyObject*
7677 DBEnv_repmgr_get_ack_policy(DBEnvObject* self)
7678 {
7679     int err;
7680     int ack_policy;
7681
7682     CHECK_ENV_NOT_CLOSED(self);
7683     MYDB_BEGIN_ALLOW_THREADS;
7684     err = self->db_env->repmgr_get_ack_policy(self->db_env, &ack_policy);
7685     MYDB_END_ALLOW_THREADS;
7686     RETURN_IF_ERR();
7687     return NUMBER_FromLong(ack_policy);
7688 }
7689
7690 static PyObject*
7691 DBEnv_repmgr_site_list(DBEnvObject* self)
7692 {
7693     int err;
7694     unsigned int countp;
7695     DB_REPMGR_SITE *listp;
7696     PyObject *stats, *key, *tuple;
7697
7698     CHECK_ENV_NOT_CLOSED(self);
7699     MYDB_BEGIN_ALLOW_THREADS;
7700     err = self->db_env->repmgr_site_list(self->db_env, &countp, &listp);
7701     MYDB_END_ALLOW_THREADS;
7702     RETURN_IF_ERR();
7703
7704     stats=PyDict_New();
7705     if (stats == NULL) {
7706         free(listp);
7707         return NULL;
7708     }
7709
7710     for(;countp--;) {
7711         key=NUMBER_FromLong(listp[countp].eid);
7712         if(!key) {
7713             Py_DECREF(stats);
7714             free(listp);
7715             return NULL;
7716         }
7717 #if (PY_VERSION_HEX >= 0x02040000)
7718         tuple=Py_BuildValue("(sII)", listp[countp].host,
7719                 listp[countp].port, listp[countp].status);
7720 #else
7721         tuple=Py_BuildValue("(sii)", listp[countp].host,
7722                 listp[countp].port, listp[countp].status);
7723 #endif
7724         if(!tuple) {
7725             Py_DECREF(key);
7726             Py_DECREF(stats);
7727             free(listp);
7728             return NULL;
7729         }
7730         if(PyDict_SetItem(stats, key, tuple)) {
7731             Py_DECREF(key);
7732             Py_DECREF(tuple);
7733             Py_DECREF(stats);
7734             free(listp);
7735             return NULL;
7736         }
7737         Py_DECREF(key);
7738         Py_DECREF(tuple);
7739     }
7740     free(listp);
7741     return stats;
7742 }
7743 #endif
7744
7745 #if (DBVER >= 46)
7746 static PyObject*
7747 DBEnv_repmgr_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
7748 {
7749     int err;
7750     int flags=0;
7751     static char* kwnames[] = { "flags", NULL };
7752
7753     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat_print",
7754                 kwnames, &flags))
7755     {
7756         return NULL;
7757     }
7758     CHECK_ENV_NOT_CLOSED(self);
7759     MYDB_BEGIN_ALLOW_THREADS;
7760     err = self->db_env->repmgr_stat_print(self->db_env, flags);
7761     MYDB_END_ALLOW_THREADS;
7762     RETURN_IF_ERR();
7763     RETURN_NONE();
7764 }
7765
7766 static PyObject*
7767 DBEnv_repmgr_stat(DBEnvObject* self, PyObject* args, PyObject *kwargs)
7768 {
7769     int err;
7770     int flags=0;
7771     DB_REPMGR_STAT *statp;
7772     PyObject *stats;
7773     static char* kwnames[] = { "flags", NULL };
7774
7775     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat",
7776                 kwnames, &flags))
7777     {
7778         return NULL;
7779     }
7780     CHECK_ENV_NOT_CLOSED(self);
7781     MYDB_BEGIN_ALLOW_THREADS;
7782     err = self->db_env->repmgr_stat(self->db_env, &statp, flags);
7783     MYDB_END_ALLOW_THREADS;
7784     RETURN_IF_ERR();
7785
7786     stats=PyDict_New();
7787     if (stats == NULL) {
7788         free(statp);
7789         return NULL;
7790     }
7791
7792 #define MAKE_ENTRY(name)  _addIntToDict(stats, #name, statp->st_##name)
7793
7794     MAKE_ENTRY(perm_failed);
7795     MAKE_ENTRY(msgs_queued);
7796     MAKE_ENTRY(msgs_dropped);
7797     MAKE_ENTRY(connection_drop);
7798     MAKE_ENTRY(connect_fail);
7799
7800 #undef MAKE_ENTRY
7801
7802     free(statp);
7803     return stats;
7804 }
7805 #endif
7806
7807
7808 /* --------------------------------------------------------------------- */
7809 /* DBTxn methods */
7810
7811
7812 static void _close_transaction_cursors(DBTxnObject* txn)
7813 {
7814     PyObject *dummy;
7815
7816     while(txn->children_cursors) {
7817         PyErr_Warn(PyExc_RuntimeWarning,
7818             "Must close cursors before resolving a transaction.");
7819         dummy=DBC_close_internal(txn->children_cursors);
7820         Py_XDECREF(dummy);
7821     }
7822 }
7823
7824 static void _promote_transaction_dbs_and_sequences(DBTxnObject *txn)
7825 {
7826     DBObject *db;
7827 #if (DBVER >= 43)
7828     DBSequenceObject *dbs;
7829 #endif
7830
7831     while (txn->children_dbs) {
7832         db=txn->children_dbs;
7833         EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(db);
7834         if (txn->parent_txn) {
7835             INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_dbs,db);
7836             db->txn=txn->parent_txn;
7837         } else {
7838             /* The db is already linked to its environment,
7839             ** so nothing to do.
7840             */
7841             db->txn=NULL;
7842         }
7843     }
7844
7845 #if (DBVER >= 43)
7846     while (txn->children_sequences) {
7847         dbs=txn->children_sequences;
7848         EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(dbs);
7849         if (txn->parent_txn) {
7850             INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_sequences,dbs);
7851             dbs->txn=txn->parent_txn;
7852         } else {
7853             /* The sequence is already linked to its
7854             ** parent db. Nothing to do.
7855             */
7856             dbs->txn=NULL;
7857         }
7858     }
7859 #endif
7860 }
7861
7862
7863 static PyObject*
7864 DBTxn_commit(DBTxnObject* self, PyObject* args)
7865 {
7866     int flags=0, err;
7867     DB_TXN *txn;
7868
7869     if (!PyArg_ParseTuple(args, "|i:commit", &flags))
7870         return NULL;
7871
7872     _close_transaction_cursors(self);
7873
7874     if (!self->txn) {
7875         PyObject *t =  Py_BuildValue("(is)", 0, "DBTxn must not be used "
7876                                      "after txn_commit, txn_abort "
7877                                      "or txn_discard");
7878         if (t) {
7879             PyErr_SetObject(DBError, t);
7880             Py_DECREF(t);
7881         }
7882         return NULL;
7883     }
7884     self->flag_prepare=0;
7885     txn = self->txn;
7886     self->txn = NULL;   /* this DB_TXN is no longer valid after this call */
7887
7888     EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
7889
7890     MYDB_BEGIN_ALLOW_THREADS;
7891     err = txn->commit(txn, flags);
7892     MYDB_END_ALLOW_THREADS;
7893
7894     _promote_transaction_dbs_and_sequences(self);
7895
7896     RETURN_IF_ERR();
7897     RETURN_NONE();
7898 }
7899
7900 static PyObject*
7901 DBTxn_prepare(DBTxnObject* self, PyObject* args)
7902 {
7903     int err;
7904     char* gid=NULL;
7905     int   gid_size=0;
7906
7907     if (!PyArg_ParseTuple(args, "s#:prepare", &gid, &gid_size))
7908         return NULL;
7909
7910     if (gid_size != DB_GID_SIZE) {
7911         PyErr_SetString(PyExc_TypeError,
7912                         "gid must be DB_GID_SIZE bytes long");
7913         return NULL;
7914     }
7915
7916     if (!self->txn) {
7917         PyObject *t = Py_BuildValue("(is)", 0,"DBTxn must not be used "
7918                                     "after txn_commit, txn_abort "
7919                                     "or txn_discard");
7920         if (t) {
7921             PyErr_SetObject(DBError, t);
7922             Py_DECREF(t);
7923         }
7924         return NULL;
7925     }
7926     self->flag_prepare=1;  /* Prepare state */
7927     MYDB_BEGIN_ALLOW_THREADS;
7928     err = self->txn->prepare(self->txn, (u_int8_t*)gid);
7929     MYDB_END_ALLOW_THREADS;
7930     RETURN_IF_ERR();
7931     RETURN_NONE();
7932 }
7933
7934
7935 static PyObject*
7936 DBTxn_abort_discard_internal(DBTxnObject* self, int discard)
7937 {
7938     PyObject *dummy;
7939     int err=0;
7940     DB_TXN *txn;
7941
7942     if (!self->txn) {
7943         PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
7944                                     "after txn_commit, txn_abort "
7945                                     "or txn_discard");
7946         if (t) {
7947             PyErr_SetObject(DBError, t);
7948             Py_DECREF(t);
7949         }
7950         return NULL;
7951     }
7952     txn = self->txn;
7953     self->txn = NULL;   /* this DB_TXN is no longer valid after this call */
7954
7955     _close_transaction_cursors(self);
7956 #if (DBVER >= 43)
7957     while (self->children_sequences) {
7958         dummy=DBSequence_close_internal(self->children_sequences,0,0);
7959         Py_XDECREF(dummy);
7960     }
7961 #endif
7962     while (self->children_dbs) {
7963         dummy=DB_close_internal(self->children_dbs, 0, 0);
7964         Py_XDECREF(dummy);
7965     }
7966
7967     EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
7968
7969     MYDB_BEGIN_ALLOW_THREADS;
7970     if (discard) {
7971         assert(!self->flag_prepare);
7972         err = txn->discard(txn,0);
7973     } else {
7974         /*
7975         ** If the transaction is in the "prepare" or "recover" state,
7976         ** we better do not implicitly abort it.
7977         */
7978         if (!self->flag_prepare) {
7979             err = txn->abort(txn);
7980         }
7981     }
7982     MYDB_END_ALLOW_THREADS;
7983     RETURN_IF_ERR();
7984     RETURN_NONE();
7985 }
7986
7987 static PyObject*
7988 DBTxn_abort(DBTxnObject* self)
7989 {
7990     self->flag_prepare=0;
7991     _close_transaction_cursors(self);
7992
7993     return DBTxn_abort_discard_internal(self,0);
7994 }
7995
7996 static PyObject*
7997 DBTxn_discard(DBTxnObject* self)
7998 {
7999     self->flag_prepare=0;
8000     _close_transaction_cursors(self);
8001
8002     return DBTxn_abort_discard_internal(self,1);
8003 }
8004
8005
8006 static PyObject*
8007 DBTxn_id(DBTxnObject* self)
8008 {
8009     int id;
8010
8011     if (!self->txn) {
8012         PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
8013                                     "after txn_commit, txn_abort "
8014                                     "or txn_discard");
8015         if (t) {
8016             PyErr_SetObject(DBError, t);
8017             Py_DECREF(t);
8018         }
8019         return NULL;
8020     }
8021     MYDB_BEGIN_ALLOW_THREADS;
8022     id = self->txn->id(self->txn);
8023     MYDB_END_ALLOW_THREADS;
8024     return NUMBER_FromLong(id);
8025 }
8026
8027
8028 static PyObject*
8029 DBTxn_set_timeout(DBTxnObject* self, PyObject* args, PyObject* kwargs)
8030 {
8031     int err;
8032     u_int32_t flags=0;
8033     u_int32_t timeout = 0;
8034     static char* kwnames[] = { "timeout", "flags", NULL };
8035
8036     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames,
8037                 &timeout, &flags)) {
8038         return NULL;
8039     }
8040
8041     MYDB_BEGIN_ALLOW_THREADS;
8042     err = self->txn->set_timeout(self->txn, (db_timeout_t)timeout, flags);
8043     MYDB_END_ALLOW_THREADS;
8044
8045     RETURN_IF_ERR();
8046     RETURN_NONE();
8047 }
8048
8049
8050 #if (DBVER >= 44)
8051 static PyObject*
8052 DBTxn_set_name(DBTxnObject* self, PyObject* args)
8053 {
8054     int err;
8055     const char *name;
8056
8057     if (!PyArg_ParseTuple(args, "s:set_name", &name))
8058         return NULL;
8059
8060     MYDB_BEGIN_ALLOW_THREADS;
8061     err = self->txn->set_name(self->txn, name);
8062     MYDB_END_ALLOW_THREADS;
8063
8064     RETURN_IF_ERR();
8065     RETURN_NONE();
8066 }
8067 #endif
8068
8069
8070 #if (DBVER >= 44)
8071 static PyObject*
8072 DBTxn_get_name(DBTxnObject* self)
8073 {
8074     int err;
8075     const char *name;
8076
8077     MYDB_BEGIN_ALLOW_THREADS;
8078     err = self->txn->get_name(self->txn, &name);
8079     MYDB_END_ALLOW_THREADS;
8080
8081     RETURN_IF_ERR();
8082 #if (PY_VERSION_HEX < 0x03000000)
8083     if (!name) {
8084         return PyString_FromString("");
8085     }
8086     return PyString_FromString(name);
8087 #else
8088     if (!name) {
8089         return PyUnicode_FromString("");
8090     }
8091     return PyUnicode_FromString(name);
8092 #endif
8093 }
8094 #endif
8095
8096
8097 #if (DBVER >= 43)
8098 /* --------------------------------------------------------------------- */
8099 /* DBSequence methods */
8100
8101
8102 static PyObject*
8103 DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close)
8104 {
8105     int err=0;
8106
8107     if (self->sequence!=NULL) {
8108         EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
8109         if (self->txn) {
8110             EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
8111             self->txn=NULL;
8112         }
8113
8114         /*
8115         ** "do_not_close" is used to dispose all related objects in the
8116         ** tree, without actually releasing the "root" object.
8117         ** This is done, for example, because function calls like
8118         ** "DBSequence.remove()" implicitly close the underlying handle. So
8119         ** the handle doesn't need to be closed, but related objects
8120         ** must be cleaned up.
8121         */
8122         if (!do_not_close) {
8123             MYDB_BEGIN_ALLOW_THREADS
8124             err = self->sequence->close(self->sequence, flags);
8125             MYDB_END_ALLOW_THREADS
8126         }
8127         self->sequence = NULL;
8128
8129         RETURN_IF_ERR();
8130     }
8131
8132     RETURN_NONE();
8133 }
8134
8135 static PyObject*
8136 DBSequence_close(DBSequenceObject* self, PyObject* args)
8137 {
8138     int flags=0;
8139     if (!PyArg_ParseTuple(args,"|i:close", &flags))
8140         return NULL;
8141
8142     return DBSequence_close_internal(self,flags,0);
8143 }
8144
8145 static PyObject*
8146 DBSequence_get(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
8147 {
8148     int err, flags = 0;
8149     int delta = 1;
8150     db_seq_t value;
8151     PyObject *txnobj = NULL;
8152     DB_TXN *txn = NULL;
8153     static char* kwnames[] = {"delta", "txn", "flags", NULL };
8154     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iOi:get", kwnames, &delta, &txnobj, &flags))
8155         return NULL;
8156     CHECK_SEQUENCE_NOT_CLOSED(self)
8157
8158     if (!checkTxnObj(txnobj, &txn))
8159         return NULL;
8160
8161     MYDB_BEGIN_ALLOW_THREADS
8162     err = self->sequence->get(self->sequence, txn, delta, &value, flags);
8163     MYDB_END_ALLOW_THREADS
8164
8165     RETURN_IF_ERR();
8166     return PyLong_FromLongLong(value);
8167 }
8168
8169 static PyObject*
8170 DBSequence_get_dbp(DBSequenceObject* self)
8171 {
8172     CHECK_SEQUENCE_NOT_CLOSED(self)
8173     Py_INCREF(self->mydb);
8174     return (PyObject* )self->mydb;
8175 }
8176
8177 static PyObject*
8178 DBSequence_get_key(DBSequenceObject* self)
8179 {
8180     int err;
8181     DBT key;
8182     PyObject *retval = NULL;
8183
8184     key.flags = DB_DBT_MALLOC;
8185     CHECK_SEQUENCE_NOT_CLOSED(self)
8186     MYDB_BEGIN_ALLOW_THREADS
8187     err = self->sequence->get_key(self->sequence, &key);
8188     MYDB_END_ALLOW_THREADS
8189
8190     if (!err)
8191         retval = Build_PyString(key.data, key.size);
8192
8193     FREE_DBT(key);
8194     RETURN_IF_ERR();
8195
8196     return retval;
8197 }
8198
8199 static PyObject*
8200 DBSequence_initial_value(DBSequenceObject* self, PyObject* args)
8201 {
8202     int err;
8203     PY_LONG_LONG value;
8204     db_seq_t value2;
8205     if (!PyArg_ParseTuple(args,"L:initial_value", &value))
8206         return NULL;
8207     CHECK_SEQUENCE_NOT_CLOSED(self)
8208
8209     value2=value; /* If truncation, compiler should show a warning */
8210     MYDB_BEGIN_ALLOW_THREADS
8211     err = self->sequence->initial_value(self->sequence, value2);
8212     MYDB_END_ALLOW_THREADS
8213
8214     RETURN_IF_ERR();
8215
8216     RETURN_NONE();
8217 }
8218
8219 static PyObject*
8220 DBSequence_open(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
8221 {
8222     int err, flags = 0;
8223     PyObject* keyobj;
8224     PyObject *txnobj = NULL;
8225     DB_TXN *txn = NULL;
8226     DBT key;
8227
8228     static char* kwnames[] = {"key", "txn", "flags", NULL };
8229     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:open", kwnames, &keyobj, &txnobj, &flags))
8230         return NULL;
8231
8232     if (!checkTxnObj(txnobj, &txn))
8233         return NULL;
8234
8235     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
8236         return NULL;
8237
8238     MYDB_BEGIN_ALLOW_THREADS
8239     err = self->sequence->open(self->sequence, txn, &key, flags);
8240     MYDB_END_ALLOW_THREADS
8241
8242     FREE_DBT(key);
8243     RETURN_IF_ERR();
8244
8245     if (txn) {
8246         INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_sequences,self);
8247         self->txn=(DBTxnObject *)txnobj;
8248     }
8249
8250     RETURN_NONE();
8251 }
8252
8253 static PyObject*
8254 DBSequence_remove(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
8255 {
8256     PyObject *dummy;
8257     int err, flags = 0;
8258     PyObject *txnobj = NULL;
8259     DB_TXN *txn = NULL;
8260
8261     static char* kwnames[] = {"txn", "flags", NULL };
8262     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:remove", kwnames, &txnobj, &flags))
8263         return NULL;
8264
8265     if (!checkTxnObj(txnobj, &txn))
8266         return NULL;
8267
8268     CHECK_SEQUENCE_NOT_CLOSED(self)
8269
8270     MYDB_BEGIN_ALLOW_THREADS
8271     err = self->sequence->remove(self->sequence, txn, flags);
8272     MYDB_END_ALLOW_THREADS
8273
8274     dummy=DBSequence_close_internal(self,flags,1);
8275     Py_XDECREF(dummy);
8276
8277     RETURN_IF_ERR();
8278     RETURN_NONE();
8279 }
8280
8281 static PyObject*
8282 DBSequence_set_cachesize(DBSequenceObject* self, PyObject* args)
8283 {
8284     int err, size;
8285     if (!PyArg_ParseTuple(args,"i:set_cachesize", &size))
8286         return NULL;
8287     CHECK_SEQUENCE_NOT_CLOSED(self)
8288
8289     MYDB_BEGIN_ALLOW_THREADS
8290     err = self->sequence->set_cachesize(self->sequence, size);
8291     MYDB_END_ALLOW_THREADS
8292
8293     RETURN_IF_ERR();
8294     RETURN_NONE();
8295 }
8296
8297 static PyObject*
8298 DBSequence_get_cachesize(DBSequenceObject* self)
8299 {
8300     int err, size;
8301
8302     CHECK_SEQUENCE_NOT_CLOSED(self)
8303
8304     MYDB_BEGIN_ALLOW_THREADS
8305     err = self->sequence->get_cachesize(self->sequence, &size);
8306     MYDB_END_ALLOW_THREADS
8307
8308     RETURN_IF_ERR();
8309     return NUMBER_FromLong(size);
8310 }
8311
8312 static PyObject*
8313 DBSequence_set_flags(DBSequenceObject* self, PyObject* args)
8314 {
8315     int err, flags = 0;
8316     if (!PyArg_ParseTuple(args,"i:set_flags", &flags))
8317         return NULL;
8318     CHECK_SEQUENCE_NOT_CLOSED(self)
8319
8320     MYDB_BEGIN_ALLOW_THREADS
8321     err = self->sequence->set_flags(self->sequence, flags);
8322     MYDB_END_ALLOW_THREADS
8323
8324     RETURN_IF_ERR();
8325     RETURN_NONE();
8326 }
8327
8328 static PyObject*
8329 DBSequence_get_flags(DBSequenceObject* self)
8330 {
8331     unsigned int flags;
8332     int err;
8333
8334     CHECK_SEQUENCE_NOT_CLOSED(self)
8335
8336     MYDB_BEGIN_ALLOW_THREADS
8337     err = self->sequence->get_flags(self->sequence, &flags);
8338     MYDB_END_ALLOW_THREADS
8339
8340     RETURN_IF_ERR();
8341     return NUMBER_FromLong((int)flags);
8342 }
8343
8344 static PyObject*
8345 DBSequence_set_range(DBSequenceObject* self, PyObject* args)
8346 {
8347     int err;
8348     PY_LONG_LONG min, max;
8349     db_seq_t min2, max2;
8350     if (!PyArg_ParseTuple(args,"(LL):set_range", &min, &max))
8351         return NULL;
8352     CHECK_SEQUENCE_NOT_CLOSED(self)
8353
8354     min2=min;  /* If truncation, compiler should show a warning */
8355     max2=max;
8356     MYDB_BEGIN_ALLOW_THREADS
8357     err = self->sequence->set_range(self->sequence, min2, max2);
8358     MYDB_END_ALLOW_THREADS
8359
8360     RETURN_IF_ERR();
8361     RETURN_NONE();
8362 }
8363
8364 static PyObject*
8365 DBSequence_get_range(DBSequenceObject* self)
8366 {
8367     int err;
8368     PY_LONG_LONG min, max;
8369     db_seq_t min2, max2;
8370
8371     CHECK_SEQUENCE_NOT_CLOSED(self)
8372
8373     MYDB_BEGIN_ALLOW_THREADS
8374     err = self->sequence->get_range(self->sequence, &min2, &max2);
8375     MYDB_END_ALLOW_THREADS
8376
8377     RETURN_IF_ERR();
8378     min=min2;  /* If truncation, compiler should show a warning */
8379     max=max2;
8380     return Py_BuildValue("(LL)", min, max);
8381 }
8382
8383
8384 static PyObject*
8385 DBSequence_stat_print(DBSequenceObject* self, PyObject* args, PyObject *kwargs)
8386 {
8387     int err;
8388     int flags=0;
8389     static char* kwnames[] = { "flags", NULL };
8390
8391     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat_print",
8392                 kwnames, &flags))
8393     {
8394         return NULL;
8395     }
8396
8397     CHECK_SEQUENCE_NOT_CLOSED(self);
8398
8399     MYDB_BEGIN_ALLOW_THREADS;
8400     err = self->sequence->stat_print(self->sequence, flags);
8401     MYDB_END_ALLOW_THREADS;
8402     RETURN_IF_ERR();
8403     RETURN_NONE();
8404 }
8405
8406 static PyObject*
8407 DBSequence_stat(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
8408 {
8409     int err, flags = 0;
8410     DB_SEQUENCE_STAT* sp = NULL;
8411     PyObject* dict_stat;
8412     static char* kwnames[] = {"flags", NULL };
8413     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags))
8414         return NULL;
8415     CHECK_SEQUENCE_NOT_CLOSED(self);
8416
8417     MYDB_BEGIN_ALLOW_THREADS;
8418     err = self->sequence->stat(self->sequence, &sp, flags);
8419     MYDB_END_ALLOW_THREADS;
8420     RETURN_IF_ERR();
8421
8422     if ((dict_stat = PyDict_New()) == NULL) {
8423         free(sp);
8424         return NULL;
8425     }
8426
8427
8428 #define MAKE_INT_ENTRY(name)  _addIntToDict(dict_stat, #name, sp->st_##name)
8429 #define MAKE_LONG_LONG_ENTRY(name)  _addDb_seq_tToDict(dict_stat, #name, sp->st_##name)
8430
8431     MAKE_INT_ENTRY(wait);
8432     MAKE_INT_ENTRY(nowait);
8433     MAKE_LONG_LONG_ENTRY(current);
8434     MAKE_LONG_LONG_ENTRY(value);
8435     MAKE_LONG_LONG_ENTRY(last_value);
8436     MAKE_LONG_LONG_ENTRY(min);
8437     MAKE_LONG_LONG_ENTRY(max);
8438     MAKE_INT_ENTRY(cache_size);
8439     MAKE_INT_ENTRY(flags);
8440
8441 #undef MAKE_INT_ENTRY
8442 #undef MAKE_LONG_LONG_ENTRY
8443
8444     free(sp);
8445     return dict_stat;
8446 }
8447 #endif
8448
8449
8450 /* --------------------------------------------------------------------- */
8451 /* Method definition tables and type objects */
8452
8453 static PyMethodDef DB_methods[] = {
8454     {"append",          (PyCFunction)DB_append,         METH_VARARGS|METH_KEYWORDS},
8455     {"associate",       (PyCFunction)DB_associate,      METH_VARARGS|METH_KEYWORDS},
8456     {"close",           (PyCFunction)DB_close,          METH_VARARGS},
8457 #if (DBVER >= 47)
8458     {"compact",         (PyCFunction)DB_compact,        METH_VARARGS|METH_KEYWORDS},
8459 #endif
8460     {"consume",         (PyCFunction)DB_consume,        METH_VARARGS|METH_KEYWORDS},
8461     {"consume_wait",    (PyCFunction)DB_consume_wait,   METH_VARARGS|METH_KEYWORDS},
8462     {"cursor",          (PyCFunction)DB_cursor,         METH_VARARGS|METH_KEYWORDS},
8463     {"delete",          (PyCFunction)DB_delete,         METH_VARARGS|METH_KEYWORDS},
8464     {"fd",              (PyCFunction)DB_fd,             METH_NOARGS},
8465 #if (DBVER >= 46)
8466     {"exists",          (PyCFunction)DB_exists,
8467         METH_VARARGS|METH_KEYWORDS},
8468 #endif
8469     {"get",             (PyCFunction)DB_get,            METH_VARARGS|METH_KEYWORDS},
8470     {"pget",            (PyCFunction)DB_pget,           METH_VARARGS|METH_KEYWORDS},
8471     {"get_both",        (PyCFunction)DB_get_both,       METH_VARARGS|METH_KEYWORDS},
8472     {"get_byteswapped", (PyCFunction)DB_get_byteswapped,METH_NOARGS},
8473     {"get_size",        (PyCFunction)DB_get_size,       METH_VARARGS|METH_KEYWORDS},
8474     {"get_type",        (PyCFunction)DB_get_type,       METH_NOARGS},
8475     {"join",            (PyCFunction)DB_join,           METH_VARARGS},
8476     {"key_range",       (PyCFunction)DB_key_range,      METH_VARARGS|METH_KEYWORDS},
8477     {"has_key",         (PyCFunction)DB_has_key,        METH_VARARGS|METH_KEYWORDS},
8478     {"items",           (PyCFunction)DB_items,          METH_VARARGS},
8479     {"keys",            (PyCFunction)DB_keys,           METH_VARARGS},
8480     {"open",            (PyCFunction)DB_open,           METH_VARARGS|METH_KEYWORDS},
8481     {"put",             (PyCFunction)DB_put,            METH_VARARGS|METH_KEYWORDS},
8482     {"remove",          (PyCFunction)DB_remove,         METH_VARARGS|METH_KEYWORDS},
8483     {"rename",          (PyCFunction)DB_rename,         METH_VARARGS},
8484     {"set_bt_minkey",   (PyCFunction)DB_set_bt_minkey,  METH_VARARGS},
8485 #if (DBVER >= 42)
8486     {"get_bt_minkey",   (PyCFunction)DB_get_bt_minkey,  METH_NOARGS},
8487 #endif
8488     {"set_bt_compare",  (PyCFunction)DB_set_bt_compare, METH_O},
8489     {"set_cachesize",   (PyCFunction)DB_set_cachesize,  METH_VARARGS},
8490 #if (DBVER >= 42)
8491     {"get_cachesize",   (PyCFunction)DB_get_cachesize,  METH_NOARGS},
8492 #endif
8493     {"set_encrypt",     (PyCFunction)DB_set_encrypt,    METH_VARARGS|METH_KEYWORDS},
8494 #if (DBVER >= 42)
8495     {"get_encrypt_flags", (PyCFunction)DB_get_encrypt_flags, METH_NOARGS},
8496 #endif
8497
8498     {"set_flags",       (PyCFunction)DB_set_flags,      METH_VARARGS},
8499 #if (DBVER >= 42)
8500     {"get_flags",       (PyCFunction)DB_get_flags,      METH_NOARGS},
8501 #endif
8502     {"set_h_ffactor",   (PyCFunction)DB_set_h_ffactor,  METH_VARARGS},
8503 #if (DBVER >= 42)
8504     {"get_h_ffactor",   (PyCFunction)DB_get_h_ffactor,  METH_NOARGS},
8505 #endif
8506     {"set_h_nelem",     (PyCFunction)DB_set_h_nelem,    METH_VARARGS},
8507 #if (DBVER >= 42)
8508     {"get_h_nelem",     (PyCFunction)DB_get_h_nelem,    METH_NOARGS},
8509 #endif
8510     {"set_lorder",      (PyCFunction)DB_set_lorder,     METH_VARARGS},
8511 #if (DBVER >= 42)
8512     {"get_lorder",      (PyCFunction)DB_get_lorder,     METH_NOARGS},
8513 #endif
8514     {"set_pagesize",    (PyCFunction)DB_set_pagesize,   METH_VARARGS},
8515 #if (DBVER >= 42)
8516     {"get_pagesize",    (PyCFunction)DB_get_pagesize,   METH_NOARGS},
8517 #endif
8518     {"set_re_delim",    (PyCFunction)DB_set_re_delim,   METH_VARARGS},
8519 #if (DBVER >= 42)
8520     {"get_re_delim",    (PyCFunction)DB_get_re_delim,   METH_NOARGS},
8521 #endif
8522     {"set_re_len",      (PyCFunction)DB_set_re_len,     METH_VARARGS},
8523 #if (DBVER >= 42)
8524     {"get_re_len",      (PyCFunction)DB_get_re_len,     METH_NOARGS},
8525 #endif
8526     {"set_re_pad",      (PyCFunction)DB_set_re_pad,     METH_VARARGS},
8527 #if (DBVER >= 42)
8528     {"get_re_pad",      (PyCFunction)DB_get_re_pad,     METH_NOARGS},
8529 #endif
8530     {"set_re_source",   (PyCFunction)DB_set_re_source,  METH_VARARGS},
8531 #if (DBVER >= 42)
8532     {"get_re_source",   (PyCFunction)DB_get_re_source,  METH_NOARGS},
8533 #endif
8534     {"set_q_extentsize",(PyCFunction)DB_set_q_extentsize, METH_VARARGS},
8535 #if (DBVER >= 42)
8536     {"get_q_extentsize",(PyCFunction)DB_get_q_extentsize, METH_NOARGS},
8537 #endif
8538     {"set_private",     (PyCFunction)DB_set_private,    METH_O},
8539     {"get_private",     (PyCFunction)DB_get_private,    METH_NOARGS},
8540 #if (DBVER >= 46)
8541     {"set_priority",    (PyCFunction)DB_set_priority,   METH_VARARGS},
8542     {"get_priority",    (PyCFunction)DB_get_priority,   METH_NOARGS},
8543 #endif
8544     {"stat",            (PyCFunction)DB_stat,           METH_VARARGS|METH_KEYWORDS},
8545 #if (DBVER >= 43)
8546     {"stat_print",      (PyCFunction)DB_stat_print,
8547         METH_VARARGS|METH_KEYWORDS},
8548 #endif
8549     {"sync",            (PyCFunction)DB_sync,           METH_VARARGS},
8550     {"truncate",        (PyCFunction)DB_truncate,       METH_VARARGS|METH_KEYWORDS},
8551     {"type",            (PyCFunction)DB_get_type,       METH_NOARGS},
8552     {"upgrade",         (PyCFunction)DB_upgrade,        METH_VARARGS},
8553     {"values",          (PyCFunction)DB_values,         METH_VARARGS},
8554     {"verify",          (PyCFunction)DB_verify,         METH_VARARGS|METH_KEYWORDS},
8555     {"set_get_returns_none",(PyCFunction)DB_set_get_returns_none,      METH_VARARGS},
8556     {NULL,      NULL}       /* sentinel */
8557 };
8558
8559
8560 /* We need this to support __contains__() */
8561 static PySequenceMethods DB_sequence = {
8562     0, /* sq_length, mapping wins here */
8563     0, /* sq_concat */
8564     0, /* sq_repeat */
8565     0, /* sq_item */
8566     0, /* sq_slice */
8567     0, /* sq_ass_item */
8568     0, /* sq_ass_slice */
8569     (objobjproc)DB_contains, /* sq_contains */
8570     0, /* sq_inplace_concat */
8571     0, /* sq_inplace_repeat */
8572 };
8573
8574 static PyMappingMethods DB_mapping = {
8575         DB_length,                   /*mp_length*/
8576         (binaryfunc)DB_subscript,    /*mp_subscript*/
8577         (objobjargproc)DB_ass_sub,   /*mp_ass_subscript*/
8578 };
8579
8580
8581 static PyMethodDef DBCursor_methods[] = {
8582     {"close",           (PyCFunction)DBC_close,         METH_NOARGS},
8583     {"count",           (PyCFunction)DBC_count,         METH_VARARGS},
8584     {"current",         (PyCFunction)DBC_current,       METH_VARARGS|METH_KEYWORDS},
8585     {"delete",          (PyCFunction)DBC_delete,        METH_VARARGS},
8586     {"dup",             (PyCFunction)DBC_dup,           METH_VARARGS},
8587     {"first",           (PyCFunction)DBC_first,         METH_VARARGS|METH_KEYWORDS},
8588     {"get",             (PyCFunction)DBC_get,           METH_VARARGS|METH_KEYWORDS},
8589     {"pget",            (PyCFunction)DBC_pget,          METH_VARARGS|METH_KEYWORDS},
8590     {"get_recno",       (PyCFunction)DBC_get_recno,     METH_NOARGS},
8591     {"last",            (PyCFunction)DBC_last,          METH_VARARGS|METH_KEYWORDS},
8592     {"next",            (PyCFunction)DBC_next,          METH_VARARGS|METH_KEYWORDS},
8593     {"prev",            (PyCFunction)DBC_prev,          METH_VARARGS|METH_KEYWORDS},
8594     {"put",             (PyCFunction)DBC_put,           METH_VARARGS|METH_KEYWORDS},
8595     {"set",             (PyCFunction)DBC_set,           METH_VARARGS|METH_KEYWORDS},
8596     {"set_range",       (PyCFunction)DBC_set_range,     METH_VARARGS|METH_KEYWORDS},
8597     {"get_both",        (PyCFunction)DBC_get_both,      METH_VARARGS},
8598     {"get_current_size",(PyCFunction)DBC_get_current_size, METH_NOARGS},
8599     {"set_both",        (PyCFunction)DBC_set_both,      METH_VARARGS},
8600     {"set_recno",       (PyCFunction)DBC_set_recno,     METH_VARARGS|METH_KEYWORDS},
8601     {"consume",         (PyCFunction)DBC_consume,       METH_VARARGS|METH_KEYWORDS},
8602     {"next_dup",        (PyCFunction)DBC_next_dup,      METH_VARARGS|METH_KEYWORDS},
8603     {"next_nodup",      (PyCFunction)DBC_next_nodup,    METH_VARARGS|METH_KEYWORDS},
8604 #if (DBVER >= 46)
8605     {"prev_dup",        (PyCFunction)DBC_prev_dup,
8606         METH_VARARGS|METH_KEYWORDS},
8607 #endif
8608     {"prev_nodup",      (PyCFunction)DBC_prev_nodup,    METH_VARARGS|METH_KEYWORDS},
8609     {"join_item",       (PyCFunction)DBC_join_item,     METH_VARARGS},
8610 #if (DBVER >= 46)
8611     {"set_priority",    (PyCFunction)DBC_set_priority,
8612         METH_VARARGS|METH_KEYWORDS},
8613     {"get_priority",    (PyCFunction)DBC_get_priority, METH_NOARGS},
8614 #endif
8615     {NULL,      NULL}       /* sentinel */
8616 };
8617
8618
8619 static PyMethodDef DBLogCursor_methods[] = {
8620     {"close",   (PyCFunction)DBLogCursor_close,     METH_NOARGS},
8621     {"current", (PyCFunction)DBLogCursor_current,   METH_NOARGS},
8622     {"first",   (PyCFunction)DBLogCursor_first,     METH_NOARGS},
8623     {"last",    (PyCFunction)DBLogCursor_last,      METH_NOARGS},
8624     {"next",    (PyCFunction)DBLogCursor_next,      METH_NOARGS},
8625     {"prev",    (PyCFunction)DBLogCursor_prev,      METH_NOARGS},
8626     {"set",     (PyCFunction)DBLogCursor_set,       METH_VARARGS},
8627     {NULL,      NULL}       /* sentinel */
8628 };
8629
8630
8631 static PyMethodDef DBEnv_methods[] = {
8632     {"close",           (PyCFunction)DBEnv_close,            METH_VARARGS},
8633     {"open",            (PyCFunction)DBEnv_open,             METH_VARARGS},
8634     {"remove",          (PyCFunction)DBEnv_remove,           METH_VARARGS},
8635     {"dbremove",        (PyCFunction)DBEnv_dbremove,         METH_VARARGS|METH_KEYWORDS},
8636     {"dbrename",        (PyCFunction)DBEnv_dbrename,         METH_VARARGS|METH_KEYWORDS},
8637 #if (DBVER >= 46)
8638     {"set_thread_count", (PyCFunction)DBEnv_set_thread_count, METH_VARARGS},
8639     {"get_thread_count", (PyCFunction)DBEnv_get_thread_count, METH_NOARGS},
8640 #endif
8641     {"set_encrypt",     (PyCFunction)DBEnv_set_encrypt,      METH_VARARGS|METH_KEYWORDS},
8642 #if (DBVER >= 42)
8643     {"get_encrypt_flags", (PyCFunction)DBEnv_get_encrypt_flags, METH_NOARGS},
8644     {"get_timeout",     (PyCFunction)DBEnv_get_timeout,
8645         METH_VARARGS|METH_KEYWORDS},
8646 #endif
8647     {"set_timeout",     (PyCFunction)DBEnv_set_timeout,     METH_VARARGS|METH_KEYWORDS},
8648     {"set_shm_key",     (PyCFunction)DBEnv_set_shm_key,     METH_VARARGS},
8649 #if (DBVER >= 42)
8650     {"get_shm_key",     (PyCFunction)DBEnv_get_shm_key,     METH_NOARGS},
8651 #endif
8652 #if (DBVER >= 46)
8653     {"set_cache_max",   (PyCFunction)DBEnv_set_cache_max,   METH_VARARGS},
8654     {"get_cache_max",   (PyCFunction)DBEnv_get_cache_max,   METH_NOARGS},
8655 #endif
8656     {"set_cachesize",   (PyCFunction)DBEnv_set_cachesize,   METH_VARARGS},
8657 #if (DBVER >= 42)
8658     {"get_cachesize",   (PyCFunction)DBEnv_get_cachesize,   METH_NOARGS},
8659 #endif
8660     {"memp_trickle",    (PyCFunction)DBEnv_memp_trickle,    METH_VARARGS},
8661     {"memp_sync",       (PyCFunction)DBEnv_memp_sync,       METH_VARARGS},
8662     {"memp_stat",       (PyCFunction)DBEnv_memp_stat,
8663         METH_VARARGS|METH_KEYWORDS},
8664 #if (DBVER >= 43)
8665     {"memp_stat_print", (PyCFunction)DBEnv_memp_stat_print,
8666         METH_VARARGS|METH_KEYWORDS},
8667 #endif
8668 #if (DBVER >= 44)
8669     {"mutex_set_max",   (PyCFunction)DBEnv_mutex_set_max,   METH_VARARGS},
8670     {"mutex_get_max",   (PyCFunction)DBEnv_mutex_get_max,   METH_NOARGS},
8671     {"mutex_set_align", (PyCFunction)DBEnv_mutex_set_align, METH_VARARGS},
8672     {"mutex_get_align", (PyCFunction)DBEnv_mutex_get_align, METH_NOARGS},
8673     {"mutex_set_increment", (PyCFunction)DBEnv_mutex_set_increment,
8674         METH_VARARGS},
8675     {"mutex_get_increment", (PyCFunction)DBEnv_mutex_get_increment,
8676         METH_NOARGS},
8677     {"mutex_set_tas_spins", (PyCFunction)DBEnv_mutex_set_tas_spins,
8678         METH_VARARGS},
8679     {"mutex_get_tas_spins", (PyCFunction)DBEnv_mutex_get_tas_spins,
8680         METH_NOARGS},
8681     {"mutex_stat",      (PyCFunction)DBEnv_mutex_stat,      METH_VARARGS},
8682 #if (DBVER >= 44)
8683     {"mutex_stat_print", (PyCFunction)DBEnv_mutex_stat_print,
8684                                          METH_VARARGS|METH_KEYWORDS},
8685 #endif
8686 #endif
8687     {"set_data_dir",    (PyCFunction)DBEnv_set_data_dir,    METH_VARARGS},
8688 #if (DBVER >= 42)
8689     {"get_data_dirs",   (PyCFunction)DBEnv_get_data_dirs,   METH_NOARGS},
8690 #endif
8691 #if (DBVER >= 42)
8692     {"get_flags",       (PyCFunction)DBEnv_get_flags,       METH_NOARGS},
8693 #endif
8694     {"set_flags",       (PyCFunction)DBEnv_set_flags,       METH_VARARGS},
8695 #if (DBVER >= 47)
8696     {"log_set_config",  (PyCFunction)DBEnv_log_set_config,  METH_VARARGS},
8697     {"log_get_config",  (PyCFunction)DBEnv_log_get_config,  METH_VARARGS},
8698 #endif
8699     {"set_lg_bsize",    (PyCFunction)DBEnv_set_lg_bsize,    METH_VARARGS},
8700 #if (DBVER >= 42)
8701     {"get_lg_bsize",    (PyCFunction)DBEnv_get_lg_bsize,    METH_NOARGS},
8702 #endif
8703     {"set_lg_dir",      (PyCFunction)DBEnv_set_lg_dir,      METH_VARARGS},
8704 #if (DBVER >= 42)
8705     {"get_lg_dir",      (PyCFunction)DBEnv_get_lg_dir,      METH_NOARGS},
8706 #endif
8707     {"set_lg_max",      (PyCFunction)DBEnv_set_lg_max,      METH_VARARGS},
8708 #if (DBVER >= 42)
8709     {"get_lg_max",      (PyCFunction)DBEnv_get_lg_max,      METH_NOARGS},
8710 #endif
8711     {"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS},
8712 #if (DBVER >= 42)
8713     {"get_lg_regionmax",(PyCFunction)DBEnv_get_lg_regionmax, METH_NOARGS},
8714 #endif
8715 #if (DBVER >= 44)
8716     {"set_lg_filemode", (PyCFunction)DBEnv_set_lg_filemode, METH_VARARGS},
8717     {"get_lg_filemode", (PyCFunction)DBEnv_get_lg_filemode, METH_NOARGS},
8718 #endif
8719 #if (DBVER >= 47)
8720     {"set_lk_partitions", (PyCFunction)DBEnv_set_lk_partitions, METH_VARARGS},
8721     {"get_lk_partitions", (PyCFunction)DBEnv_get_lk_partitions, METH_NOARGS},
8722 #endif
8723     {"set_lk_detect",   (PyCFunction)DBEnv_set_lk_detect,   METH_VARARGS},
8724 #if (DBVER >= 42)
8725     {"get_lk_detect",   (PyCFunction)DBEnv_get_lk_detect,   METH_NOARGS},
8726 #endif
8727 #if (DBVER < 45)
8728     {"set_lk_max",      (PyCFunction)DBEnv_set_lk_max,      METH_VARARGS},
8729 #endif
8730     {"set_lk_max_locks", (PyCFunction)DBEnv_set_lk_max_locks, METH_VARARGS},
8731 #if (DBVER >= 42)
8732     {"get_lk_max_locks", (PyCFunction)DBEnv_get_lk_max_locks, METH_NOARGS},
8733 #endif
8734     {"set_lk_max_lockers", (PyCFunction)DBEnv_set_lk_max_lockers, METH_VARARGS},
8735 #if (DBVER >= 42)
8736     {"get_lk_max_lockers", (PyCFunction)DBEnv_get_lk_max_lockers, METH_NOARGS},
8737 #endif
8738     {"set_lk_max_objects", (PyCFunction)DBEnv_set_lk_max_objects, METH_VARARGS},
8739 #if (DBVER >= 42)
8740     {"get_lk_max_objects", (PyCFunction)DBEnv_get_lk_max_objects, METH_NOARGS},
8741 #endif
8742 #if (DBVER >= 43)
8743     {"stat_print",          (PyCFunction)DBEnv_stat_print,
8744         METH_VARARGS|METH_KEYWORDS},
8745 #endif
8746     {"set_mp_mmapsize", (PyCFunction)DBEnv_set_mp_mmapsize, METH_VARARGS},
8747 #if (DBVER >= 42)
8748     {"get_mp_mmapsize", (PyCFunction)DBEnv_get_mp_mmapsize, METH_NOARGS},
8749 #endif
8750     {"set_tmp_dir",     (PyCFunction)DBEnv_set_tmp_dir,     METH_VARARGS},
8751 #if (DBVER >= 42)
8752     {"get_tmp_dir",     (PyCFunction)DBEnv_get_tmp_dir,     METH_NOARGS},
8753 #endif
8754     {"txn_begin",       (PyCFunction)DBEnv_txn_begin,       METH_VARARGS|METH_KEYWORDS},
8755     {"txn_checkpoint",  (PyCFunction)DBEnv_txn_checkpoint,  METH_VARARGS},
8756     {"txn_stat",        (PyCFunction)DBEnv_txn_stat,        METH_VARARGS},
8757 #if (DBVER >= 43)
8758     {"txn_stat_print",  (PyCFunction)DBEnv_txn_stat_print,
8759         METH_VARARGS|METH_KEYWORDS},
8760 #endif
8761 #if (DBVER >= 42)
8762     {"get_tx_max",      (PyCFunction)DBEnv_get_tx_max,      METH_NOARGS},
8763     {"get_tx_timestamp", (PyCFunction)DBEnv_get_tx_timestamp, METH_NOARGS},
8764 #endif
8765     {"set_tx_max",      (PyCFunction)DBEnv_set_tx_max,      METH_VARARGS},
8766     {"set_tx_timestamp", (PyCFunction)DBEnv_set_tx_timestamp, METH_VARARGS},
8767     {"lock_detect",     (PyCFunction)DBEnv_lock_detect,     METH_VARARGS},
8768     {"lock_get",        (PyCFunction)DBEnv_lock_get,        METH_VARARGS},
8769     {"lock_id",         (PyCFunction)DBEnv_lock_id,         METH_NOARGS},
8770     {"lock_id_free",    (PyCFunction)DBEnv_lock_id_free,    METH_VARARGS},
8771     {"lock_put",        (PyCFunction)DBEnv_lock_put,        METH_VARARGS},
8772     {"lock_stat",       (PyCFunction)DBEnv_lock_stat,       METH_VARARGS},
8773 #if (DBVER >= 43)
8774     {"lock_stat_print", (PyCFunction)DBEnv_lock_stat_print,
8775         METH_VARARGS|METH_KEYWORDS},
8776 #endif
8777     {"log_cursor",      (PyCFunction)DBEnv_log_cursor,      METH_NOARGS},
8778     {"log_file",        (PyCFunction)DBEnv_log_file,        METH_VARARGS},
8779 #if (DBVER >= 44)
8780     {"log_printf",      (PyCFunction)DBEnv_log_printf,
8781         METH_VARARGS|METH_KEYWORDS},
8782 #endif
8783     {"log_archive",     (PyCFunction)DBEnv_log_archive,     METH_VARARGS},
8784     {"log_flush",       (PyCFunction)DBEnv_log_flush,       METH_NOARGS},
8785     {"log_stat",        (PyCFunction)DBEnv_log_stat,        METH_VARARGS},
8786 #if (DBVER >= 43)
8787     {"log_stat_print",  (PyCFunction)DBEnv_log_stat_print,
8788         METH_VARARGS|METH_KEYWORDS},
8789 #endif
8790 #if (DBVER >= 44)
8791     {"fileid_reset",    (PyCFunction)DBEnv_fileid_reset,    METH_VARARGS|METH_KEYWORDS},
8792     {"lsn_reset",       (PyCFunction)DBEnv_lsn_reset,       METH_VARARGS|METH_KEYWORDS},
8793 #endif
8794     {"set_get_returns_none",(PyCFunction)DBEnv_set_get_returns_none, METH_VARARGS},
8795     {"txn_recover",     (PyCFunction)DBEnv_txn_recover,     METH_NOARGS},
8796 #if (DBVER < 48)
8797     {"set_rpc_server",  (PyCFunction)DBEnv_set_rpc_server,
8798         METH_VARARGS|METH_KEYWORDS},
8799 #endif
8800 #if (DBVER >= 43)
8801     {"set_mp_max_openfd", (PyCFunction)DBEnv_set_mp_max_openfd, METH_VARARGS},
8802     {"get_mp_max_openfd", (PyCFunction)DBEnv_get_mp_max_openfd, METH_NOARGS},
8803     {"set_mp_max_write", (PyCFunction)DBEnv_set_mp_max_write, METH_VARARGS},
8804     {"get_mp_max_write", (PyCFunction)DBEnv_get_mp_max_write, METH_NOARGS},
8805 #endif
8806     {"set_verbose",     (PyCFunction)DBEnv_set_verbose,     METH_VARARGS},
8807 #if (DBVER >= 42)
8808     {"get_verbose",     (PyCFunction)DBEnv_get_verbose,       METH_VARARGS},
8809 #endif
8810     {"set_private",     (PyCFunction)DBEnv_set_private,       METH_O},
8811     {"get_private",     (PyCFunction)DBEnv_get_private,       METH_NOARGS},
8812     {"rep_start",       (PyCFunction)DBEnv_rep_start,
8813         METH_VARARGS|METH_KEYWORDS},
8814     {"rep_set_transport", (PyCFunction)DBEnv_rep_set_transport, METH_VARARGS},
8815     {"rep_process_message", (PyCFunction)DBEnv_rep_process_message,
8816         METH_VARARGS},
8817 #if (DBVER >= 46)
8818     {"rep_elect",       (PyCFunction)DBEnv_rep_elect,         METH_VARARGS},
8819 #endif
8820 #if (DBVER >= 44)
8821     {"rep_set_config",  (PyCFunction)DBEnv_rep_set_config,    METH_VARARGS},
8822     {"rep_get_config",  (PyCFunction)DBEnv_rep_get_config,    METH_VARARGS},
8823     {"rep_sync",        (PyCFunction)DBEnv_rep_sync,          METH_NOARGS},
8824 #endif
8825 #if (DBVER >= 45)
8826     {"rep_set_limit",   (PyCFunction)DBEnv_rep_set_limit,     METH_VARARGS},
8827     {"rep_get_limit",   (PyCFunction)DBEnv_rep_get_limit,     METH_NOARGS},
8828 #endif
8829 #if (DBVER >= 47)
8830     {"rep_set_request", (PyCFunction)DBEnv_rep_set_request,   METH_VARARGS},
8831     {"rep_get_request", (PyCFunction)DBEnv_rep_get_request,   METH_NOARGS},
8832 #endif
8833 #if (DBVER >= 45)
8834     {"set_event_notify", (PyCFunction)DBEnv_set_event_notify, METH_O},
8835 #endif
8836 #if (DBVER >= 45)
8837     {"rep_set_nsites", (PyCFunction)DBEnv_rep_set_nsites, METH_VARARGS},
8838     {"rep_get_nsites", (PyCFunction)DBEnv_rep_get_nsites, METH_NOARGS},
8839     {"rep_set_priority", (PyCFunction)DBEnv_rep_set_priority, METH_VARARGS},
8840     {"rep_get_priority", (PyCFunction)DBEnv_rep_get_priority, METH_NOARGS},
8841     {"rep_set_timeout", (PyCFunction)DBEnv_rep_set_timeout, METH_VARARGS},
8842     {"rep_get_timeout", (PyCFunction)DBEnv_rep_get_timeout, METH_VARARGS},
8843 #endif
8844 #if (DBVER >= 47)
8845     {"rep_set_clockskew", (PyCFunction)DBEnv_rep_set_clockskew, METH_VARARGS},
8846     {"rep_get_clockskew", (PyCFunction)DBEnv_rep_get_clockskew, METH_VARARGS},
8847 #endif
8848     {"rep_stat", (PyCFunction)DBEnv_rep_stat,
8849         METH_VARARGS|METH_KEYWORDS},
8850 #if (DBVER >= 43)
8851     {"rep_stat_print", (PyCFunction)DBEnv_rep_stat_print,
8852         METH_VARARGS|METH_KEYWORDS},
8853 #endif
8854
8855 #if (DBVER >= 45)
8856     {"repmgr_start", (PyCFunction)DBEnv_repmgr_start,
8857         METH_VARARGS|METH_KEYWORDS},
8858     {"repmgr_set_local_site", (PyCFunction)DBEnv_repmgr_set_local_site,
8859         METH_VARARGS|METH_KEYWORDS},
8860     {"repmgr_add_remote_site", (PyCFunction)DBEnv_repmgr_add_remote_site,
8861         METH_VARARGS|METH_KEYWORDS},
8862     {"repmgr_set_ack_policy", (PyCFunction)DBEnv_repmgr_set_ack_policy,
8863         METH_VARARGS},
8864     {"repmgr_get_ack_policy", (PyCFunction)DBEnv_repmgr_get_ack_policy,
8865         METH_NOARGS},
8866     {"repmgr_site_list", (PyCFunction)DBEnv_repmgr_site_list,
8867         METH_NOARGS},
8868 #endif
8869 #if (DBVER >= 46)
8870     {"repmgr_stat", (PyCFunction)DBEnv_repmgr_stat,
8871         METH_VARARGS|METH_KEYWORDS},
8872     {"repmgr_stat_print", (PyCFunction)DBEnv_repmgr_stat_print,
8873         METH_VARARGS|METH_KEYWORDS},
8874 #endif
8875     {NULL,      NULL}       /* sentinel */
8876 };
8877
8878
8879 static PyMethodDef DBTxn_methods[] = {
8880     {"commit",          (PyCFunction)DBTxn_commit,      METH_VARARGS},
8881     {"prepare",         (PyCFunction)DBTxn_prepare,     METH_VARARGS},
8882     {"discard",         (PyCFunction)DBTxn_discard,     METH_NOARGS},
8883     {"abort",           (PyCFunction)DBTxn_abort,       METH_NOARGS},
8884     {"id",              (PyCFunction)DBTxn_id,          METH_NOARGS},
8885     {"set_timeout",     (PyCFunction)DBTxn_set_timeout,
8886         METH_VARARGS|METH_KEYWORDS},
8887 #if (DBVER >= 44)
8888     {"set_name",        (PyCFunction)DBTxn_set_name, METH_VARARGS},
8889     {"get_name",        (PyCFunction)DBTxn_get_name, METH_NOARGS},
8890 #endif
8891     {NULL,      NULL}       /* sentinel */
8892 };
8893
8894
8895 #if (DBVER >= 43)
8896 static PyMethodDef DBSequence_methods[] = {
8897     {"close",           (PyCFunction)DBSequence_close,          METH_VARARGS},
8898     {"get",             (PyCFunction)DBSequence_get,            METH_VARARGS|METH_KEYWORDS},
8899     {"get_dbp",         (PyCFunction)DBSequence_get_dbp,        METH_NOARGS},
8900     {"get_key",         (PyCFunction)DBSequence_get_key,        METH_NOARGS},
8901     {"initial_value",   (PyCFunction)DBSequence_initial_value,  METH_VARARGS},
8902     {"open",            (PyCFunction)DBSequence_open,           METH_VARARGS|METH_KEYWORDS},
8903     {"remove",          (PyCFunction)DBSequence_remove,         METH_VARARGS|METH_KEYWORDS},
8904     {"set_cachesize",   (PyCFunction)DBSequence_set_cachesize,  METH_VARARGS},
8905     {"get_cachesize",   (PyCFunction)DBSequence_get_cachesize,  METH_NOARGS},
8906     {"set_flags",       (PyCFunction)DBSequence_set_flags,      METH_VARARGS},
8907     {"get_flags",       (PyCFunction)DBSequence_get_flags,      METH_NOARGS},
8908     {"set_range",       (PyCFunction)DBSequence_set_range,      METH_VARARGS},
8909     {"get_range",       (PyCFunction)DBSequence_get_range,      METH_NOARGS},
8910     {"stat",            (PyCFunction)DBSequence_stat,           METH_VARARGS|METH_KEYWORDS},
8911     {"stat_print",      (PyCFunction)DBSequence_stat_print,
8912         METH_VARARGS|METH_KEYWORDS},
8913     {NULL,      NULL}       /* sentinel */
8914 };
8915 #endif
8916
8917
8918 static PyObject*
8919 DBEnv_db_home_get(DBEnvObject* self)
8920 {
8921     const char *home = NULL;
8922
8923     CHECK_ENV_NOT_CLOSED(self);
8924
8925 #if (DBVER >= 42)
8926     MYDB_BEGIN_ALLOW_THREADS;
8927     self->db_env->get_home(self->db_env, &home);
8928     MYDB_END_ALLOW_THREADS;
8929 #else
8930     home=self->db_env->db_home;
8931 #endif
8932
8933     if (home == NULL) {
8934         RETURN_NONE();
8935     }
8936     return PyBytes_FromString(home);
8937 }
8938
8939 static PyGetSetDef DBEnv_getsets[] = {
8940     {"db_home", (getter)DBEnv_db_home_get, NULL,},
8941     {NULL}
8942 };
8943
8944
8945 statichere PyTypeObject DB_Type = {
8946 #if (PY_VERSION_HEX < 0x03000000)
8947     PyObject_HEAD_INIT(NULL)
8948     0,                  /*ob_size*/
8949 #else
8950     PyVarObject_HEAD_INIT(NULL, 0)
8951 #endif
8952     "DB",               /*tp_name*/
8953     sizeof(DBObject),   /*tp_basicsize*/
8954     0,                  /*tp_itemsize*/
8955     /* methods */
8956     (destructor)DB_dealloc, /*tp_dealloc*/
8957     0,          /*tp_print*/
8958     0,          /*tp_getattr*/
8959     0,          /*tp_setattr*/
8960     0,          /*tp_compare*/
8961     0,          /*tp_repr*/
8962     0,          /*tp_as_number*/
8963     &DB_sequence,/*tp_as_sequence*/
8964     &DB_mapping,/*tp_as_mapping*/
8965     0,          /*tp_hash*/
8966     0,                  /* tp_call */
8967     0,                  /* tp_str */
8968     0,                  /* tp_getattro */
8969     0,          /* tp_setattro */
8970     0,                  /* tp_as_buffer */
8971 #if (PY_VERSION_HEX < 0x03000000)
8972     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS,      /* tp_flags */
8973 #else
8974     Py_TPFLAGS_DEFAULT,      /* tp_flags */
8975 #endif
8976     0,          /* tp_doc */
8977     0,              /* tp_traverse */
8978     0,                  /* tp_clear */
8979     0,                  /* tp_richcompare */
8980     offsetof(DBObject, in_weakreflist),   /* tp_weaklistoffset */
8981     0,          /*tp_iter*/
8982     0,          /*tp_iternext*/
8983     DB_methods, /*tp_methods*/
8984     0, /*tp_members*/
8985 };
8986
8987
8988 statichere PyTypeObject DBCursor_Type = {
8989 #if (PY_VERSION_HEX < 0x03000000)
8990     PyObject_HEAD_INIT(NULL)
8991     0,                  /*ob_size*/
8992 #else
8993     PyVarObject_HEAD_INIT(NULL, 0)
8994 #endif
8995     "DBCursor",         /*tp_name*/
8996     sizeof(DBCursorObject),  /*tp_basicsize*/
8997     0,          /*tp_itemsize*/
8998     /* methods */
8999     (destructor)DBCursor_dealloc,/*tp_dealloc*/
9000     0,          /*tp_print*/
9001     0,          /*tp_getattr*/
9002     0,          /*tp_setattr*/
9003     0,          /*tp_compare*/
9004     0,          /*tp_repr*/
9005     0,          /*tp_as_number*/
9006     0,          /*tp_as_sequence*/
9007     0,          /*tp_as_mapping*/
9008     0,          /*tp_hash*/
9009     0,          /*tp_call*/
9010     0,          /*tp_str*/
9011     0,          /*tp_getattro*/
9012     0,          /*tp_setattro*/
9013     0,          /*tp_as_buffer*/
9014 #if (PY_VERSION_HEX < 0x03000000)
9015     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS,      /* tp_flags */
9016 #else
9017     Py_TPFLAGS_DEFAULT,      /* tp_flags */
9018 #endif
9019     0,          /* tp_doc */
9020     0,          /* tp_traverse */
9021     0,          /* tp_clear */
9022     0,          /* tp_richcompare */
9023     offsetof(DBCursorObject, in_weakreflist),   /* tp_weaklistoffset */
9024     0,          /*tp_iter*/
9025     0,          /*tp_iternext*/
9026     DBCursor_methods, /*tp_methods*/
9027     0,          /*tp_members*/
9028 };
9029
9030
9031 statichere PyTypeObject DBLogCursor_Type = {
9032 #if (PY_VERSION_HEX < 0x03000000)
9033     PyObject_HEAD_INIT(NULL)
9034     0,                  /*ob_size*/
9035 #else
9036     PyVarObject_HEAD_INIT(NULL, 0)
9037 #endif
9038     "DBLogCursor",         /*tp_name*/
9039     sizeof(DBLogCursorObject),  /*tp_basicsize*/
9040     0,          /*tp_itemsize*/
9041     /* methods */
9042     (destructor)DBLogCursor_dealloc,/*tp_dealloc*/
9043     0,          /*tp_print*/
9044     0,          /*tp_getattr*/
9045     0,          /*tp_setattr*/
9046     0,          /*tp_compare*/
9047     0,          /*tp_repr*/
9048     0,          /*tp_as_number*/
9049     0,          /*tp_as_sequence*/
9050     0,          /*tp_as_mapping*/
9051     0,          /*tp_hash*/
9052     0,          /*tp_call*/
9053     0,          /*tp_str*/
9054     0,          /*tp_getattro*/
9055     0,          /*tp_setattro*/
9056     0,          /*tp_as_buffer*/
9057 #if (PY_VERSION_HEX < 0x03000000)
9058     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS,      /* tp_flags */
9059 #else
9060     Py_TPFLAGS_DEFAULT,      /* tp_flags */
9061 #endif
9062     0,          /* tp_doc */
9063     0,          /* tp_traverse */
9064     0,          /* tp_clear */
9065     0,          /* tp_richcompare */
9066     offsetof(DBLogCursorObject, in_weakreflist),   /* tp_weaklistoffset */
9067     0,          /*tp_iter*/
9068     0,          /*tp_iternext*/
9069     DBLogCursor_methods, /*tp_methods*/
9070     0,          /*tp_members*/
9071 };
9072
9073
9074 statichere PyTypeObject DBEnv_Type = {
9075 #if (PY_VERSION_HEX < 0x03000000)
9076     PyObject_HEAD_INIT(NULL)
9077     0,                  /*ob_size*/
9078 #else
9079     PyVarObject_HEAD_INIT(NULL, 0)
9080 #endif
9081     "DBEnv",            /*tp_name*/
9082     sizeof(DBEnvObject),    /*tp_basicsize*/
9083     0,          /*tp_itemsize*/
9084     /* methods */
9085     (destructor)DBEnv_dealloc, /*tp_dealloc*/
9086     0,          /*tp_print*/
9087     0,          /*tp_getattr*/
9088     0,          /*tp_setattr*/
9089     0,          /*tp_compare*/
9090     0,          /*tp_repr*/
9091     0,          /*tp_as_number*/
9092     0,          /*tp_as_sequence*/
9093     0,          /*tp_as_mapping*/
9094     0,          /*tp_hash*/
9095     0,                  /* tp_call */
9096     0,                  /* tp_str */
9097     0,                  /* tp_getattro */
9098     0,          /* tp_setattro */
9099     0,                  /* tp_as_buffer */
9100 #if (PY_VERSION_HEX < 0x03000000)
9101     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS,      /* tp_flags */
9102 #else
9103     Py_TPFLAGS_DEFAULT,      /* tp_flags */
9104 #endif
9105     0,          /* tp_doc */
9106     0,              /* tp_traverse */
9107     0,                  /* tp_clear */
9108     0,                  /* tp_richcompare */
9109     offsetof(DBEnvObject, in_weakreflist),   /* tp_weaklistoffset */
9110     0,          /* tp_iter */
9111     0,          /* tp_iternext */
9112     DBEnv_methods,      /* tp_methods */
9113     0,          /* tp_members */
9114     DBEnv_getsets,      /* tp_getsets */
9115 };
9116
9117 statichere PyTypeObject DBTxn_Type = {
9118 #if (PY_VERSION_HEX < 0x03000000)
9119     PyObject_HEAD_INIT(NULL)
9120     0,                  /*ob_size*/
9121 #else
9122     PyVarObject_HEAD_INIT(NULL, 0)
9123 #endif
9124     "DBTxn",    /*tp_name*/
9125     sizeof(DBTxnObject),  /*tp_basicsize*/
9126     0,          /*tp_itemsize*/
9127     /* methods */
9128     (destructor)DBTxn_dealloc, /*tp_dealloc*/
9129     0,          /*tp_print*/
9130     0,          /*tp_getattr*/
9131     0,          /*tp_setattr*/
9132     0,          /*tp_compare*/
9133     0,          /*tp_repr*/
9134     0,          /*tp_as_number*/
9135     0,          /*tp_as_sequence*/
9136     0,          /*tp_as_mapping*/
9137     0,          /*tp_hash*/
9138     0,                  /* tp_call */
9139     0,                  /* tp_str */
9140     0,                  /* tp_getattro */
9141     0,          /* tp_setattro */
9142     0,                  /* tp_as_buffer */
9143 #if (PY_VERSION_HEX < 0x03000000)
9144     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS,      /* tp_flags */
9145 #else
9146     Py_TPFLAGS_DEFAULT,      /* tp_flags */
9147 #endif
9148     0,          /* tp_doc */
9149     0,          /* tp_traverse */
9150     0,                  /* tp_clear */
9151     0,                  /* tp_richcompare */
9152     offsetof(DBTxnObject, in_weakreflist),   /* tp_weaklistoffset */
9153     0,          /*tp_iter*/
9154     0,          /*tp_iternext*/
9155     DBTxn_methods, /*tp_methods*/
9156     0,          /*tp_members*/
9157 };
9158
9159
9160 statichere PyTypeObject DBLock_Type = {
9161 #if (PY_VERSION_HEX < 0x03000000)
9162     PyObject_HEAD_INIT(NULL)
9163     0,                  /*ob_size*/
9164 #else
9165     PyVarObject_HEAD_INIT(NULL, 0)
9166 #endif
9167     "DBLock",   /*tp_name*/
9168     sizeof(DBLockObject),  /*tp_basicsize*/
9169     0,          /*tp_itemsize*/
9170     /* methods */
9171     (destructor)DBLock_dealloc, /*tp_dealloc*/
9172     0,          /*tp_print*/
9173     0,          /*tp_getattr*/
9174     0,          /*tp_setattr*/
9175     0,          /*tp_compare*/
9176     0,          /*tp_repr*/
9177     0,          /*tp_as_number*/
9178     0,          /*tp_as_sequence*/
9179     0,          /*tp_as_mapping*/
9180     0,          /*tp_hash*/
9181     0,                  /* tp_call */
9182     0,                  /* tp_str */
9183     0,                  /* tp_getattro */
9184     0,          /* tp_setattro */
9185     0,                  /* tp_as_buffer */
9186 #if (PY_VERSION_HEX < 0x03000000)
9187     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS,      /* tp_flags */
9188 #else
9189     Py_TPFLAGS_DEFAULT,      /* tp_flags */
9190 #endif
9191     0,          /* tp_doc */
9192     0,              /* tp_traverse */
9193     0,                  /* tp_clear */
9194     0,                  /* tp_richcompare */
9195     offsetof(DBLockObject, in_weakreflist),   /* tp_weaklistoffset */
9196 };
9197
9198 #if (DBVER >= 43)
9199 statichere PyTypeObject DBSequence_Type = {
9200 #if (PY_VERSION_HEX < 0x03000000)
9201     PyObject_HEAD_INIT(NULL)
9202     0,                  /*ob_size*/
9203 #else
9204     PyVarObject_HEAD_INIT(NULL, 0)
9205 #endif
9206     "DBSequence",                   /*tp_name*/
9207     sizeof(DBSequenceObject),       /*tp_basicsize*/
9208     0,          /*tp_itemsize*/
9209     /* methods */
9210     (destructor)DBSequence_dealloc, /*tp_dealloc*/
9211     0,          /*tp_print*/
9212     0,          /*tp_getattr*/
9213     0,          /*tp_setattr*/
9214     0,          /*tp_compare*/
9215     0,          /*tp_repr*/
9216     0,          /*tp_as_number*/
9217     0,          /*tp_as_sequence*/
9218     0,          /*tp_as_mapping*/
9219     0,          /*tp_hash*/
9220     0,                  /* tp_call */
9221     0,                  /* tp_str */
9222     0,                  /* tp_getattro */
9223     0,          /* tp_setattro */
9224     0,                  /* tp_as_buffer */
9225 #if (PY_VERSION_HEX < 0x03000000)
9226     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS,      /* tp_flags */
9227 #else
9228     Py_TPFLAGS_DEFAULT,      /* tp_flags */
9229 #endif
9230     0,          /* tp_doc */
9231     0,              /* tp_traverse */
9232     0,                  /* tp_clear */
9233     0,                  /* tp_richcompare */
9234     offsetof(DBSequenceObject, in_weakreflist),   /* tp_weaklistoffset */
9235     0,          /*tp_iter*/
9236     0,          /*tp_iternext*/
9237     DBSequence_methods, /*tp_methods*/
9238     0,          /*tp_members*/
9239 };
9240 #endif
9241
9242 /* --------------------------------------------------------------------- */
9243 /* Module-level functions */
9244
9245 static PyObject*
9246 DB_construct(PyObject* self, PyObject* args, PyObject* kwargs)
9247 {
9248     PyObject* dbenvobj = NULL;
9249     int flags = 0;
9250     static char* kwnames[] = { "dbEnv", "flags", NULL};
9251
9252     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:DB", kwnames,
9253                                      &dbenvobj, &flags))
9254         return NULL;
9255     if (dbenvobj == Py_None)
9256         dbenvobj = NULL;
9257     else if (dbenvobj && !DBEnvObject_Check(dbenvobj)) {
9258         makeTypeError("DBEnv", dbenvobj);
9259         return NULL;
9260     }
9261
9262     return (PyObject* )newDBObject((DBEnvObject*)dbenvobj, flags);
9263 }
9264
9265
9266 static PyObject*
9267 DBEnv_construct(PyObject* self, PyObject* args)
9268 {
9269     int flags = 0;
9270     if (!PyArg_ParseTuple(args, "|i:DbEnv", &flags)) return NULL;
9271     return (PyObject* )newDBEnvObject(flags);
9272 }
9273
9274 #if (DBVER >= 43)
9275 static PyObject*
9276 DBSequence_construct(PyObject* self, PyObject* args, PyObject* kwargs)
9277 {
9278     PyObject* dbobj;
9279     int flags = 0;
9280     static char* kwnames[] = { "db", "flags", NULL};
9281
9282     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:DBSequence", kwnames, &dbobj, &flags))
9283         return NULL;
9284     if (!DBObject_Check(dbobj)) {
9285         makeTypeError("DB", dbobj);
9286         return NULL;
9287     }
9288     return (PyObject* )newDBSequenceObject((DBObject*)dbobj, flags);
9289 }
9290 #endif
9291
9292 static char bsddb_version_doc[] =
9293 "Returns a tuple of major, minor, and patch release numbers of the\n\
9294 underlying DB library.";
9295
9296 static PyObject*
9297 bsddb_version(PyObject* self)
9298 {
9299     int major, minor, patch;
9300
9301     db_version(&major, &minor, &patch);
9302     return Py_BuildValue("(iii)", major, minor, patch);
9303 }
9304
9305
9306 /* List of functions defined in the module */
9307 static PyMethodDef bsddb_methods[] = {
9308     {"DB",          (PyCFunction)DB_construct,          METH_VARARGS | METH_KEYWORDS },
9309     {"DBEnv",       (PyCFunction)DBEnv_construct,       METH_VARARGS},
9310 #if (DBVER >= 43)
9311     {"DBSequence",  (PyCFunction)DBSequence_construct,  METH_VARARGS | METH_KEYWORDS },
9312 #endif
9313     {"version",     (PyCFunction)bsddb_version,         METH_NOARGS, bsddb_version_doc},
9314     {NULL,      NULL}       /* sentinel */
9315 };
9316
9317
9318 /* API structure */
9319 static BSDDB_api bsddb_api;
9320
9321
9322 /* --------------------------------------------------------------------- */
9323 /* Module initialization */
9324
9325
9326 /* Convenience routine to export an integer value.
9327  * Errors are silently ignored, for better or for worse...
9328  */
9329 #define ADD_INT(dict, NAME)         _addIntToDict(dict, #NAME, NAME)
9330
9331 #define MODULE_NAME_MAX_LEN     11
9332 static char _bsddbModuleName[MODULE_NAME_MAX_LEN+1] = "_bsddb";
9333
9334 #if (PY_VERSION_HEX >= 0x03000000)
9335 static struct PyModuleDef bsddbmodule = {
9336     PyModuleDef_HEAD_INIT,
9337     _bsddbModuleName,   /* Name of module */
9338     NULL,               /* module documentation, may be NULL */
9339     -1,                 /* size of per-interpreter state of the module,
9340                             or -1 if the module keeps state in global variables. */
9341     bsddb_methods,
9342     NULL,   /* Reload */
9343     NULL,   /* Traverse */
9344     NULL,   /* Clear */
9345     NULL    /* Free */
9346 };
9347 #endif
9348
9349
9350 #if (PY_VERSION_HEX < 0x03000000)
9351 DL_EXPORT(void) init_bsddb(void)
9352 #else
9353 PyMODINIT_FUNC  PyInit__bsddb(void)    /* Note the two underscores */
9354 #endif
9355 {
9356     PyObject* m;
9357     PyObject* d;
9358     PyObject* py_api;
9359     PyObject* pybsddb_version_s;
9360     PyObject* db_version_s;
9361     PyObject* cvsid_s;
9362
9363 #if (PY_VERSION_HEX < 0x03000000)
9364     pybsddb_version_s = PyString_FromString(PY_BSDDB_VERSION);
9365     db_version_s = PyString_FromString(DB_VERSION_STRING);
9366     cvsid_s = PyString_FromString(rcs_id);
9367 #else
9368     /* This data should be ascii, so UTF-8 conversion is fine */
9369     pybsddb_version_s = PyUnicode_FromString(PY_BSDDB_VERSION);
9370     db_version_s = PyUnicode_FromString(DB_VERSION_STRING);
9371     cvsid_s = PyUnicode_FromString(rcs_id);
9372 #endif
9373
9374     /* Initialize object types */
9375     if ((PyType_Ready(&DB_Type) < 0)
9376         || (PyType_Ready(&DBCursor_Type) < 0)
9377         || (PyType_Ready(&DBLogCursor_Type) < 0)
9378         || (PyType_Ready(&DBEnv_Type) < 0)
9379         || (PyType_Ready(&DBTxn_Type) < 0)
9380         || (PyType_Ready(&DBLock_Type) < 0)
9381 #if (DBVER >= 43)
9382         || (PyType_Ready(&DBSequence_Type) < 0)
9383 #endif
9384         ) {
9385 #if (PY_VERSION_HEX < 0x03000000)
9386         return;
9387 #else
9388         return NULL;
9389 #endif
9390     }
9391
9392 #if defined(WITH_THREAD) && !defined(MYDB_USE_GILSTATE)
9393     /* Save the current interpreter, so callbacks can do the right thing. */
9394     _db_interpreterState = PyThreadState_GET()->interp;
9395 #endif
9396
9397     /* Create the module and add the functions */
9398 #if (PY_VERSION_HEX < 0x03000000)
9399     m = Py_InitModule(_bsddbModuleName, bsddb_methods);
9400 #else
9401     m=PyModule_Create(&bsddbmodule);
9402 #endif
9403     if (m == NULL) {
9404 #if (PY_VERSION_HEX < 0x03000000)
9405         return;
9406 #else
9407         return NULL;
9408 #endif
9409     }
9410
9411     /* Add some symbolic constants to the module */
9412     d = PyModule_GetDict(m);
9413     PyDict_SetItemString(d, "__version__", pybsddb_version_s);
9414     PyDict_SetItemString(d, "cvsid", cvsid_s);
9415     PyDict_SetItemString(d, "DB_VERSION_STRING", db_version_s);
9416     Py_DECREF(pybsddb_version_s);
9417     pybsddb_version_s = NULL;
9418     Py_DECREF(cvsid_s);
9419     cvsid_s = NULL;
9420     Py_DECREF(db_version_s);
9421     db_version_s = NULL;
9422
9423     ADD_INT(d, DB_VERSION_MAJOR);
9424     ADD_INT(d, DB_VERSION_MINOR);
9425     ADD_INT(d, DB_VERSION_PATCH);
9426
9427     ADD_INT(d, DB_MAX_PAGES);
9428     ADD_INT(d, DB_MAX_RECORDS);
9429
9430 #if (DBVER < 48)
9431 #if (DBVER >= 42)
9432     ADD_INT(d, DB_RPCCLIENT);
9433 #else
9434     ADD_INT(d, DB_CLIENT);
9435     /* allow apps to be written using DB_RPCCLIENT on older Berkeley DB */
9436     _addIntToDict(d, "DB_RPCCLIENT", DB_CLIENT);
9437 #endif
9438 #endif
9439
9440 #if (DBVER < 48)
9441     ADD_INT(d, DB_XA_CREATE);
9442 #endif
9443
9444     ADD_INT(d, DB_CREATE);
9445     ADD_INT(d, DB_NOMMAP);
9446     ADD_INT(d, DB_THREAD);
9447 #if (DBVER >= 45)
9448     ADD_INT(d, DB_MULTIVERSION);
9449 #endif
9450
9451     ADD_INT(d, DB_FORCE);
9452     ADD_INT(d, DB_INIT_CDB);
9453     ADD_INT(d, DB_INIT_LOCK);
9454     ADD_INT(d, DB_INIT_LOG);
9455     ADD_INT(d, DB_INIT_MPOOL);
9456     ADD_INT(d, DB_INIT_TXN);
9457     ADD_INT(d, DB_JOINENV);
9458
9459 #if (DBVER >= 48)
9460     ADD_INT(d, DB_GID_SIZE);
9461 #else
9462     ADD_INT(d, DB_XIDDATASIZE);
9463     /* Allow new code to work in old BDB releases */
9464     _addIntToDict(d, "DB_GID_SIZE", DB_XIDDATASIZE);
9465 #endif
9466
9467     ADD_INT(d, DB_RECOVER);
9468     ADD_INT(d, DB_RECOVER_FATAL);
9469     ADD_INT(d, DB_TXN_NOSYNC);
9470     ADD_INT(d, DB_USE_ENVIRON);
9471     ADD_INT(d, DB_USE_ENVIRON_ROOT);
9472
9473     ADD_INT(d, DB_LOCKDOWN);
9474     ADD_INT(d, DB_PRIVATE);
9475     ADD_INT(d, DB_SYSTEM_MEM);
9476
9477     ADD_INT(d, DB_TXN_SYNC);
9478     ADD_INT(d, DB_TXN_NOWAIT);
9479
9480 #if (DBVER >= 46)
9481     ADD_INT(d, DB_TXN_WAIT);
9482 #endif
9483
9484     ADD_INT(d, DB_EXCL);
9485     ADD_INT(d, DB_FCNTL_LOCKING);
9486     ADD_INT(d, DB_ODDFILESIZE);
9487     ADD_INT(d, DB_RDWRMASTER);
9488     ADD_INT(d, DB_RDONLY);
9489     ADD_INT(d, DB_TRUNCATE);
9490     ADD_INT(d, DB_EXTENT);
9491     ADD_INT(d, DB_CDB_ALLDB);
9492     ADD_INT(d, DB_VERIFY);
9493     ADD_INT(d, DB_UPGRADE);
9494
9495     ADD_INT(d, DB_PRINTABLE);
9496     ADD_INT(d, DB_AGGRESSIVE);
9497     ADD_INT(d, DB_NOORDERCHK);
9498     ADD_INT(d, DB_ORDERCHKONLY);
9499     ADD_INT(d, DB_PR_PAGE);
9500
9501     ADD_INT(d, DB_PR_RECOVERYTEST);
9502     ADD_INT(d, DB_SALVAGE);
9503
9504     ADD_INT(d, DB_LOCK_NORUN);
9505     ADD_INT(d, DB_LOCK_DEFAULT);
9506     ADD_INT(d, DB_LOCK_OLDEST);
9507     ADD_INT(d, DB_LOCK_RANDOM);
9508     ADD_INT(d, DB_LOCK_YOUNGEST);
9509     ADD_INT(d, DB_LOCK_MAXLOCKS);
9510     ADD_INT(d, DB_LOCK_MINLOCKS);
9511     ADD_INT(d, DB_LOCK_MINWRITE);
9512
9513     ADD_INT(d, DB_LOCK_EXPIRE);
9514 #if (DBVER >= 43)
9515     ADD_INT(d, DB_LOCK_MAXWRITE);
9516 #endif
9517
9518     _addIntToDict(d, "DB_LOCK_CONFLICT", 0);
9519
9520     ADD_INT(d, DB_LOCK_DUMP);
9521     ADD_INT(d, DB_LOCK_GET);
9522     ADD_INT(d, DB_LOCK_INHERIT);
9523     ADD_INT(d, DB_LOCK_PUT);
9524     ADD_INT(d, DB_LOCK_PUT_ALL);
9525     ADD_INT(d, DB_LOCK_PUT_OBJ);
9526
9527     ADD_INT(d, DB_LOCK_NG);
9528     ADD_INT(d, DB_LOCK_READ);
9529     ADD_INT(d, DB_LOCK_WRITE);
9530     ADD_INT(d, DB_LOCK_NOWAIT);
9531     ADD_INT(d, DB_LOCK_WAIT);
9532     ADD_INT(d, DB_LOCK_IWRITE);
9533     ADD_INT(d, DB_LOCK_IREAD);
9534     ADD_INT(d, DB_LOCK_IWR);
9535 #if (DBVER < 44)
9536     ADD_INT(d, DB_LOCK_DIRTY);
9537 #else
9538     ADD_INT(d, DB_LOCK_READ_UNCOMMITTED);  /* renamed in 4.4 */
9539 #endif
9540     ADD_INT(d, DB_LOCK_WWRITE);
9541
9542     ADD_INT(d, DB_LOCK_RECORD);
9543     ADD_INT(d, DB_LOCK_UPGRADE);
9544     ADD_INT(d, DB_LOCK_SWITCH);
9545     ADD_INT(d, DB_LOCK_UPGRADE_WRITE);
9546
9547     ADD_INT(d, DB_LOCK_NOWAIT);
9548     ADD_INT(d, DB_LOCK_RECORD);
9549     ADD_INT(d, DB_LOCK_UPGRADE);
9550
9551     ADD_INT(d, DB_LSTAT_ABORTED);
9552 #if (DBVER < 43)
9553     ADD_INT(d, DB_LSTAT_ERR);
9554 #endif
9555     ADD_INT(d, DB_LSTAT_FREE);
9556     ADD_INT(d, DB_LSTAT_HELD);
9557
9558     ADD_INT(d, DB_LSTAT_PENDING);
9559     ADD_INT(d, DB_LSTAT_WAITING);
9560
9561     ADD_INT(d, DB_ARCH_ABS);
9562     ADD_INT(d, DB_ARCH_DATA);
9563     ADD_INT(d, DB_ARCH_LOG);
9564 #if (DBVER >= 42)
9565     ADD_INT(d, DB_ARCH_REMOVE);
9566 #endif
9567
9568     ADD_INT(d, DB_BTREE);
9569     ADD_INT(d, DB_HASH);
9570     ADD_INT(d, DB_RECNO);
9571     ADD_INT(d, DB_QUEUE);
9572     ADD_INT(d, DB_UNKNOWN);
9573
9574     ADD_INT(d, DB_DUP);
9575     ADD_INT(d, DB_DUPSORT);
9576     ADD_INT(d, DB_RECNUM);
9577     ADD_INT(d, DB_RENUMBER);
9578     ADD_INT(d, DB_REVSPLITOFF);
9579     ADD_INT(d, DB_SNAPSHOT);
9580
9581 #if (DBVER >= 43)
9582     ADD_INT(d, DB_INORDER);
9583 #endif
9584
9585     ADD_INT(d, DB_JOIN_NOSORT);
9586
9587     ADD_INT(d, DB_AFTER);
9588     ADD_INT(d, DB_APPEND);
9589     ADD_INT(d, DB_BEFORE);
9590 #if (DBVER < 45)
9591     ADD_INT(d, DB_CACHED_COUNTS);
9592 #endif
9593
9594 #if (DBVER <= 41)
9595     ADD_INT(d, DB_COMMIT);
9596 #endif
9597     ADD_INT(d, DB_CONSUME);
9598     ADD_INT(d, DB_CONSUME_WAIT);
9599     ADD_INT(d, DB_CURRENT);
9600     ADD_INT(d, DB_FAST_STAT);
9601     ADD_INT(d, DB_FIRST);
9602     ADD_INT(d, DB_FLUSH);
9603     ADD_INT(d, DB_GET_BOTH);
9604     ADD_INT(d, DB_GET_BOTH_RANGE);
9605     ADD_INT(d, DB_GET_RECNO);
9606     ADD_INT(d, DB_JOIN_ITEM);
9607     ADD_INT(d, DB_KEYFIRST);
9608     ADD_INT(d, DB_KEYLAST);
9609     ADD_INT(d, DB_LAST);
9610     ADD_INT(d, DB_NEXT);
9611     ADD_INT(d, DB_NEXT_DUP);
9612     ADD_INT(d, DB_NEXT_NODUP);
9613     ADD_INT(d, DB_NODUPDATA);
9614     ADD_INT(d, DB_NOOVERWRITE);
9615     ADD_INT(d, DB_NOSYNC);
9616     ADD_INT(d, DB_POSITION);
9617     ADD_INT(d, DB_PREV);
9618     ADD_INT(d, DB_PREV_NODUP);
9619 #if (DBVER >= 46)
9620     ADD_INT(d, DB_PREV_DUP);
9621 #endif
9622 #if (DBVER < 45)
9623     ADD_INT(d, DB_RECORDCOUNT);
9624 #endif
9625     ADD_INT(d, DB_SET);
9626     ADD_INT(d, DB_SET_RANGE);
9627     ADD_INT(d, DB_SET_RECNO);
9628     ADD_INT(d, DB_WRITECURSOR);
9629
9630     ADD_INT(d, DB_OPFLAGS_MASK);
9631     ADD_INT(d, DB_RMW);
9632     ADD_INT(d, DB_DIRTY_READ);
9633     ADD_INT(d, DB_MULTIPLE);
9634     ADD_INT(d, DB_MULTIPLE_KEY);
9635
9636 #if (DBVER >= 44)
9637     ADD_INT(d, DB_IMMUTABLE_KEY);
9638     ADD_INT(d, DB_READ_UNCOMMITTED);    /* replaces DB_DIRTY_READ in 4.4 */
9639     ADD_INT(d, DB_READ_COMMITTED);
9640 #endif
9641
9642 #if (DBVER >= 44)
9643     ADD_INT(d, DB_FREELIST_ONLY);
9644     ADD_INT(d, DB_FREE_SPACE);
9645 #endif
9646
9647     ADD_INT(d, DB_DONOTINDEX);
9648
9649     ADD_INT(d, DB_KEYEMPTY);
9650     ADD_INT(d, DB_KEYEXIST);
9651     ADD_INT(d, DB_LOCK_DEADLOCK);
9652     ADD_INT(d, DB_LOCK_NOTGRANTED);
9653     ADD_INT(d, DB_NOSERVER);
9654     ADD_INT(d, DB_NOSERVER_HOME);
9655     ADD_INT(d, DB_NOSERVER_ID);
9656     ADD_INT(d, DB_NOTFOUND);
9657     ADD_INT(d, DB_OLD_VERSION);
9658     ADD_INT(d, DB_RUNRECOVERY);
9659     ADD_INT(d, DB_VERIFY_BAD);
9660     ADD_INT(d, DB_PAGE_NOTFOUND);
9661     ADD_INT(d, DB_SECONDARY_BAD);
9662     ADD_INT(d, DB_STAT_CLEAR);
9663     ADD_INT(d, DB_REGION_INIT);
9664     ADD_INT(d, DB_NOLOCKING);
9665     ADD_INT(d, DB_YIELDCPU);
9666     ADD_INT(d, DB_PANIC_ENVIRONMENT);
9667     ADD_INT(d, DB_NOPANIC);
9668
9669     ADD_INT(d, DB_OVERWRITE);
9670
9671 #if (DBVER >= 43)
9672     ADD_INT(d, DB_STAT_SUBSYSTEM);
9673     ADD_INT(d, DB_STAT_MEMP_HASH);
9674 #endif
9675
9676 #if (DBVER >= 48)
9677     ADD_INT(d, DB_OVERWRITE_DUP);
9678 #endif
9679
9680 #if (DBVER >= 47)
9681     ADD_INT(d, DB_FOREIGN_ABORT);
9682     ADD_INT(d, DB_FOREIGN_CASCADE);
9683     ADD_INT(d, DB_FOREIGN_NULLIFY);
9684 #endif
9685
9686 #if (DBVER >= 44)
9687     ADD_INT(d, DB_REGISTER);
9688 #endif
9689
9690     ADD_INT(d, DB_EID_INVALID);
9691     ADD_INT(d, DB_EID_BROADCAST);
9692
9693 #if (DBVER >= 42)
9694     ADD_INT(d, DB_TIME_NOTGRANTED);
9695     ADD_INT(d, DB_TXN_NOT_DURABLE);
9696     ADD_INT(d, DB_TXN_WRITE_NOSYNC);
9697     ADD_INT(d, DB_DIRECT_DB);
9698     ADD_INT(d, DB_INIT_REP);
9699     ADD_INT(d, DB_ENCRYPT);
9700     ADD_INT(d, DB_CHKSUM);
9701 #endif
9702
9703 #if (DBVER >= 42) && (DBVER < 47)
9704     ADD_INT(d, DB_LOG_AUTOREMOVE);
9705     ADD_INT(d, DB_DIRECT_LOG);
9706 #endif
9707
9708 #if (DBVER >= 47)
9709     ADD_INT(d, DB_LOG_DIRECT);
9710     ADD_INT(d, DB_LOG_DSYNC);
9711     ADD_INT(d, DB_LOG_IN_MEMORY);
9712     ADD_INT(d, DB_LOG_AUTO_REMOVE);
9713     ADD_INT(d, DB_LOG_ZERO);
9714 #endif
9715
9716 #if (DBVER >= 44)
9717     ADD_INT(d, DB_DSYNC_DB);
9718 #endif
9719
9720 #if (DBVER >= 45)
9721     ADD_INT(d, DB_TXN_SNAPSHOT);
9722 #endif
9723
9724     ADD_INT(d, DB_VERB_DEADLOCK);
9725 #if (DBVER >= 46)
9726     ADD_INT(d, DB_VERB_FILEOPS);
9727     ADD_INT(d, DB_VERB_FILEOPS_ALL);
9728 #endif
9729     ADD_INT(d, DB_VERB_RECOVERY);
9730 #if (DBVER >= 44)
9731     ADD_INT(d, DB_VERB_REGISTER);
9732 #endif
9733     ADD_INT(d, DB_VERB_REPLICATION);
9734     ADD_INT(d, DB_VERB_WAITSFOR);
9735
9736 #if (DBVER >= 45)
9737     ADD_INT(d, DB_EVENT_PANIC);
9738     ADD_INT(d, DB_EVENT_REP_CLIENT);
9739 #if (DBVER >= 46)
9740     ADD_INT(d, DB_EVENT_REP_ELECTED);
9741 #endif
9742     ADD_INT(d, DB_EVENT_REP_MASTER);
9743     ADD_INT(d, DB_EVENT_REP_NEWMASTER);
9744 #if (DBVER >= 46)
9745     ADD_INT(d, DB_EVENT_REP_PERM_FAILED);
9746 #endif
9747     ADD_INT(d, DB_EVENT_REP_STARTUPDONE);
9748     ADD_INT(d, DB_EVENT_WRITE_FAILED);
9749 #endif
9750
9751     ADD_INT(d, DB_REP_DUPMASTER);
9752     ADD_INT(d, DB_REP_HOLDELECTION);
9753 #if (DBVER >= 44)
9754     ADD_INT(d, DB_REP_IGNORE);
9755     ADD_INT(d, DB_REP_JOIN_FAILURE);
9756 #endif
9757 #if (DBVER >= 42)
9758     ADD_INT(d, DB_REP_ISPERM);
9759     ADD_INT(d, DB_REP_NOTPERM);
9760 #endif
9761     ADD_INT(d, DB_REP_NEWSITE);
9762
9763     ADD_INT(d, DB_REP_MASTER);
9764     ADD_INT(d, DB_REP_CLIENT);
9765
9766     ADD_INT(d, DB_REP_PERMANENT);
9767
9768 #if (DBVER >= 44)
9769     ADD_INT(d, DB_REP_CONF_NOAUTOINIT);
9770     ADD_INT(d, DB_REP_CONF_DELAYCLIENT);
9771     ADD_INT(d, DB_REP_CONF_BULK);
9772     ADD_INT(d, DB_REP_CONF_NOWAIT);
9773     ADD_INT(d, DB_REP_ANYWHERE);
9774     ADD_INT(d, DB_REP_REREQUEST);
9775 #endif
9776
9777 #if (DBVER >= 42)
9778     ADD_INT(d, DB_REP_NOBUFFER);
9779 #endif
9780
9781 #if (DBVER >= 46)
9782     ADD_INT(d, DB_REP_LEASE_EXPIRED);
9783     ADD_INT(d, DB_IGNORE_LEASE);
9784 #endif
9785
9786 #if (DBVER >= 47)
9787     ADD_INT(d, DB_REP_CONF_LEASE);
9788     ADD_INT(d, DB_REPMGR_CONF_2SITE_STRICT);
9789 #endif
9790
9791 #if (DBVER >= 45)
9792     ADD_INT(d, DB_REP_ELECTION);
9793
9794     ADD_INT(d, DB_REP_ACK_TIMEOUT);
9795     ADD_INT(d, DB_REP_CONNECTION_RETRY);
9796     ADD_INT(d, DB_REP_ELECTION_TIMEOUT);
9797     ADD_INT(d, DB_REP_ELECTION_RETRY);
9798 #endif
9799 #if (DBVER >= 46)
9800     ADD_INT(d, DB_REP_CHECKPOINT_DELAY);
9801     ADD_INT(d, DB_REP_FULL_ELECTION_TIMEOUT);
9802     ADD_INT(d, DB_REP_LEASE_TIMEOUT);
9803 #endif
9804 #if (DBVER >= 47)
9805     ADD_INT(d, DB_REP_HEARTBEAT_MONITOR);
9806     ADD_INT(d, DB_REP_HEARTBEAT_SEND);
9807 #endif
9808
9809 #if (DBVER >= 45)
9810     ADD_INT(d, DB_REPMGR_PEER);
9811     ADD_INT(d, DB_REPMGR_ACKS_ALL);
9812     ADD_INT(d, DB_REPMGR_ACKS_ALL_PEERS);
9813     ADD_INT(d, DB_REPMGR_ACKS_NONE);
9814     ADD_INT(d, DB_REPMGR_ACKS_ONE);
9815     ADD_INT(d, DB_REPMGR_ACKS_ONE_PEER);
9816     ADD_INT(d, DB_REPMGR_ACKS_QUORUM);
9817     ADD_INT(d, DB_REPMGR_CONNECTED);
9818     ADD_INT(d, DB_REPMGR_DISCONNECTED);
9819     ADD_INT(d, DB_STAT_ALL);
9820 #endif
9821
9822 #if (DBVER >= 43)
9823     ADD_INT(d, DB_BUFFER_SMALL);
9824     ADD_INT(d, DB_SEQ_DEC);
9825     ADD_INT(d, DB_SEQ_INC);
9826     ADD_INT(d, DB_SEQ_WRAP);
9827 #endif
9828
9829 #if (DBVER >= 43) && (DBVER < 47)
9830     ADD_INT(d, DB_LOG_INMEMORY);
9831     ADD_INT(d, DB_DSYNC_LOG);
9832 #endif
9833
9834     ADD_INT(d, DB_ENCRYPT_AES);
9835     ADD_INT(d, DB_AUTO_COMMIT);
9836     ADD_INT(d, DB_PRIORITY_VERY_LOW);
9837     ADD_INT(d, DB_PRIORITY_LOW);
9838     ADD_INT(d, DB_PRIORITY_DEFAULT);
9839     ADD_INT(d, DB_PRIORITY_HIGH);
9840     ADD_INT(d, DB_PRIORITY_VERY_HIGH);
9841
9842 #if (DBVER >= 46)
9843     ADD_INT(d, DB_PRIORITY_UNCHANGED);
9844 #endif
9845
9846     ADD_INT(d, EINVAL);
9847     ADD_INT(d, EACCES);
9848     ADD_INT(d, ENOSPC);
9849     ADD_INT(d, ENOMEM);
9850     ADD_INT(d, EAGAIN);
9851     ADD_INT(d, EBUSY);
9852     ADD_INT(d, EEXIST);
9853     ADD_INT(d, ENOENT);
9854     ADD_INT(d, EPERM);
9855
9856     ADD_INT(d, DB_SET_LOCK_TIMEOUT);
9857     ADD_INT(d, DB_SET_TXN_TIMEOUT);
9858
9859     /* The exception name must be correct for pickled exception *
9860      * objects to unpickle properly.                            */
9861 #ifdef PYBSDDB_STANDALONE  /* different value needed for standalone pybsddb */
9862 #define PYBSDDB_EXCEPTION_BASE  "bsddb3.db."
9863 #else
9864 #define PYBSDDB_EXCEPTION_BASE  "bsddb.db."
9865 #endif
9866
9867     /* All the rest of the exceptions derive only from DBError */
9868 #define MAKE_EX(name)   name = PyErr_NewException(PYBSDDB_EXCEPTION_BASE #name, DBError, NULL); \
9869                         PyDict_SetItemString(d, #name, name)
9870
9871     /* The base exception class is DBError */
9872     DBError = NULL;     /* used in MAKE_EX so that it derives from nothing */
9873     MAKE_EX(DBError);
9874
9875 #if (PY_VERSION_HEX < 0x03000000)
9876     /* Some magic to make DBNotFoundError and DBKeyEmptyError derive
9877      * from both DBError and KeyError, since the API only supports
9878      * using one base class. */
9879     PyDict_SetItemString(d, "KeyError", PyExc_KeyError);
9880     PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n"
9881                  "class DBKeyEmptyError(DBError, KeyError): pass",
9882                  Py_file_input, d, d);
9883     DBNotFoundError = PyDict_GetItemString(d, "DBNotFoundError");
9884     DBKeyEmptyError = PyDict_GetItemString(d, "DBKeyEmptyError");
9885     PyDict_DelItemString(d, "KeyError");
9886 #else
9887     /* Since Python 2.5, PyErr_NewException() accepts a tuple, to be able to
9888     ** derive from several classes. We use this new API only for Python 3.0,
9889     ** though.
9890     */
9891     {
9892         PyObject* bases;
9893
9894         bases = PyTuple_Pack(2, DBError, PyExc_KeyError);
9895
9896 #define MAKE_EX2(name)   name = PyErr_NewException(PYBSDDB_EXCEPTION_BASE #name, bases, NULL); \
9897                          PyDict_SetItemString(d, #name, name)
9898         MAKE_EX2(DBNotFoundError);
9899         MAKE_EX2(DBKeyEmptyError);
9900
9901 #undef MAKE_EX2
9902
9903         Py_XDECREF(bases);
9904     }
9905 #endif
9906
9907     MAKE_EX(DBCursorClosedError);
9908     MAKE_EX(DBKeyExistError);
9909     MAKE_EX(DBLockDeadlockError);
9910     MAKE_EX(DBLockNotGrantedError);
9911     MAKE_EX(DBOldVersionError);
9912     MAKE_EX(DBRunRecoveryError);
9913     MAKE_EX(DBVerifyBadError);
9914     MAKE_EX(DBNoServerError);
9915     MAKE_EX(DBNoServerHomeError);
9916     MAKE_EX(DBNoServerIDError);
9917     MAKE_EX(DBPageNotFoundError);
9918     MAKE_EX(DBSecondaryBadError);
9919
9920     MAKE_EX(DBInvalidArgError);
9921     MAKE_EX(DBAccessError);
9922     MAKE_EX(DBNoSpaceError);
9923     MAKE_EX(DBNoMemoryError);
9924     MAKE_EX(DBAgainError);
9925     MAKE_EX(DBBusyError);
9926     MAKE_EX(DBFileExistsError);
9927     MAKE_EX(DBNoSuchFileError);
9928     MAKE_EX(DBPermissionsError);
9929
9930 #if (DBVER >= 42)
9931     MAKE_EX(DBRepHandleDeadError);
9932 #endif
9933 #if (DBVER >= 44)
9934     MAKE_EX(DBRepLockoutError);
9935 #endif
9936
9937     MAKE_EX(DBRepUnavailError);
9938
9939 #if (DBVER >= 46)
9940     MAKE_EX(DBRepLeaseExpiredError);
9941 #endif
9942
9943 #if (DBVER >= 47)
9944         MAKE_EX(DBForeignConflictError);
9945 #endif
9946
9947 #undef MAKE_EX
9948
9949     /* Initialise the C API structure and add it to the module */
9950     bsddb_api.db_type          = &DB_Type;
9951     bsddb_api.dbcursor_type    = &DBCursor_Type;
9952     bsddb_api.dblogcursor_type = &DBLogCursor_Type;
9953     bsddb_api.dbenv_type       = &DBEnv_Type;
9954     bsddb_api.dbtxn_type       = &DBTxn_Type;
9955     bsddb_api.dblock_type      = &DBLock_Type;
9956 #if (DBVER >= 43)
9957     bsddb_api.dbsequence_type  = &DBSequence_Type;
9958 #endif
9959     bsddb_api.makeDBError      = makeDBError;
9960
9961     /*
9962     ** Capsules exist from Python 3.1, but I
9963     ** don't want to break the API compatibility
9964     ** for already published Python versions.
9965     */
9966 #if (PY_VERSION_HEX < 0x03020000)
9967     py_api = PyCObject_FromVoidPtr((void*)&bsddb_api, NULL);
9968 #else
9969     {
9970         char py_api_name[250];
9971
9972         strcpy(py_api_name, _bsddbModuleName);
9973         strcat(py_api_name, ".api");
9974
9975         py_api = PyCapsule_New((void*)&bsddb_api, py_api_name, NULL);
9976     }
9977 #endif
9978
9979     /* Check error control */
9980     /*
9981     ** PyErr_NoMemory();
9982     ** py_api = NULL;
9983     */
9984
9985     if (py_api) {
9986         PyDict_SetItemString(d, "api", py_api);
9987         Py_DECREF(py_api);
9988     } else { /* Something bad happened */
9989         PyErr_WriteUnraisable(m);
9990         if(PyErr_Warn(PyExc_RuntimeWarning,
9991                 "_bsddb/_pybsddb C API will be not available")) {
9992             PyErr_WriteUnraisable(m);
9993         }
9994         PyErr_Clear();
9995     }
9996
9997     /* Check for errors */
9998     if (PyErr_Occurred()) {
9999         PyErr_Print();
10000         Py_FatalError("can't initialize module _bsddb/_pybsddb");
10001         Py_DECREF(m);
10002         m = NULL;
10003     }
10004 #if (PY_VERSION_HEX < 0x03000000)
10005     return;
10006 #else
10007     return m;
10008 #endif
10009 }
10010
10011 /* allow this module to be named _pybsddb so that it can be installed
10012  * and imported on top of python >= 2.3 that includes its own older
10013  * copy of the library named _bsddb without importing the old version. */
10014 #if (PY_VERSION_HEX < 0x03000000)
10015 DL_EXPORT(void) init_pybsddb(void)
10016 #else
10017 PyMODINIT_FUNC PyInit__pybsddb(void)  /* Note the two underscores */
10018 #endif
10019 {
10020     strncpy(_bsddbModuleName, "_pybsddb", MODULE_NAME_MAX_LEN);
10021 #if (PY_VERSION_HEX < 0x03000000)
10022     init_bsddb();
10023 #else
10024     return PyInit__bsddb();   /* Note the two underscores */
10025 #endif
10026 }