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