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