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