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