Silence SyntaxWarning and DeprecationWarning in pydoc triggered by tuple
[python.git] / Modules / _bsddb.c
blob104962fa892e99e138f444be672273391741cec1
1 /*----------------------------------------------------------------------
2 Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA
3 and Andrew Kuchling. All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 o Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the disclaimer that follows.
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.
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.
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 ------------------------------------------------------------------------*/
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.
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.
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).
51 * Gregory P. Smith <greg@krypto.org> was once again the maintainer.
53 * Since January 2008, new maintainer is Jesus Cea <jcea@jcea.es>.
54 * Jesus Cea licenses this code to PSF under a Contributor Agreement.
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:
60 * http://pybsddb.sf.net
62 * This file should remain backward compatible with Python 2.1, but see PEP
63 * 291 for the most current backward compatibility requirements:
65 * http://www.python.org/peps/pep-0291.html
67 * This module contains 6 types:
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)
78 /* --------------------------------------------------------------------- */
81 * Portions of this module, associated unit tests and build scripts are the
82 * result of a contract with The Written Word (http://thewrittenword.com/)
83 * Many thanks go out to them for causing me to raise the bar on quality and
84 * functionality, resulting in a better bsddb3 package for all of us to use.
86 * --Robin
89 /* --------------------------------------------------------------------- */
91 #include <stddef.h> /* for offsetof() */
92 #include <Python.h>
94 #define COMPILING_BSDDB_C
95 #include "bsddb.h"
96 #undef COMPILING_BSDDB_C
98 static char *rcs_id = "$Id$";
100 /* --------------------------------------------------------------------- */
101 /* Various macro definitions */
103 #if (PY_VERSION_HEX < 0x02050000)
104 typedef int Py_ssize_t;
105 #endif
107 #if (PY_VERSION_HEX < 0x02060000) /* really: before python trunk r63675 */
108 /* This code now uses PyBytes* API function names instead of PyString*.
109 * These #defines map to their equivalent on earlier python versions. */
110 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
111 #define PyBytes_FromString PyString_FromString
112 #define PyBytes_AsStringAndSize PyString_AsStringAndSize
113 #define PyBytes_Check PyString_Check
114 #define PyBytes_GET_SIZE PyString_GET_SIZE
115 #define PyBytes_AS_STRING PyString_AS_STRING
116 #endif
118 #if (PY_VERSION_HEX >= 0x03000000)
119 #define NUMBER_Check PyLong_Check
120 #define NUMBER_AsLong PyLong_AsLong
121 #define NUMBER_FromLong PyLong_FromLong
122 #else
123 #define NUMBER_Check PyInt_Check
124 #define NUMBER_AsLong PyInt_AsLong
125 #define NUMBER_FromLong PyInt_FromLong
126 #endif
128 #ifdef WITH_THREAD
130 /* These are for when calling Python --> C */
131 #define MYDB_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS;
132 #define MYDB_END_ALLOW_THREADS Py_END_ALLOW_THREADS;
134 /* For 2.3, use the PyGILState_ calls */
135 #if (PY_VERSION_HEX >= 0x02030000)
136 #define MYDB_USE_GILSTATE
137 #endif
139 /* and these are for calling C --> Python */
140 #if defined(MYDB_USE_GILSTATE)
141 #define MYDB_BEGIN_BLOCK_THREADS \
142 PyGILState_STATE __savestate = PyGILState_Ensure();
143 #define MYDB_END_BLOCK_THREADS \
144 PyGILState_Release(__savestate);
145 #else /* MYDB_USE_GILSTATE */
146 /* Pre GILState API - do it the long old way */
147 static PyInterpreterState* _db_interpreterState = NULL;
148 #define MYDB_BEGIN_BLOCK_THREADS { \
149 PyThreadState* prevState; \
150 PyThreadState* newState; \
151 PyEval_AcquireLock(); \
152 newState = PyThreadState_New(_db_interpreterState); \
153 prevState = PyThreadState_Swap(newState);
155 #define MYDB_END_BLOCK_THREADS \
156 newState = PyThreadState_Swap(prevState); \
157 PyThreadState_Clear(newState); \
158 PyEval_ReleaseLock(); \
159 PyThreadState_Delete(newState); \
161 #endif /* MYDB_USE_GILSTATE */
163 #else
164 /* Compiled without threads - avoid all this cruft */
165 #define MYDB_BEGIN_ALLOW_THREADS
166 #define MYDB_END_ALLOW_THREADS
167 #define MYDB_BEGIN_BLOCK_THREADS
168 #define MYDB_END_BLOCK_THREADS
170 #endif
172 /* Should DB_INCOMPLETE be turned into a warning or an exception? */
173 #define INCOMPLETE_IS_WARNING 1
175 /* --------------------------------------------------------------------- */
176 /* Exceptions */
178 static PyObject* DBError; /* Base class, all others derive from this */
179 static PyObject* DBCursorClosedError; /* raised when trying to use a closed cursor object */
180 static PyObject* DBKeyEmptyError; /* DB_KEYEMPTY: also derives from KeyError */
181 static PyObject* DBKeyExistError; /* DB_KEYEXIST */
182 static PyObject* DBLockDeadlockError; /* DB_LOCK_DEADLOCK */
183 static PyObject* DBLockNotGrantedError; /* DB_LOCK_NOTGRANTED */
184 static PyObject* DBNotFoundError; /* DB_NOTFOUND: also derives from KeyError */
185 static PyObject* DBOldVersionError; /* DB_OLD_VERSION */
186 static PyObject* DBRunRecoveryError; /* DB_RUNRECOVERY */
187 static PyObject* DBVerifyBadError; /* DB_VERIFY_BAD */
188 static PyObject* DBNoServerError; /* DB_NOSERVER */
189 static PyObject* DBNoServerHomeError; /* DB_NOSERVER_HOME */
190 static PyObject* DBNoServerIDError; /* DB_NOSERVER_ID */
191 static PyObject* DBPageNotFoundError; /* DB_PAGE_NOTFOUND */
192 static PyObject* DBSecondaryBadError; /* DB_SECONDARY_BAD */
194 #if !INCOMPLETE_IS_WARNING
195 static PyObject* DBIncompleteError; /* DB_INCOMPLETE */
196 #endif
198 static PyObject* DBInvalidArgError; /* EINVAL */
199 static PyObject* DBAccessError; /* EACCES */
200 static PyObject* DBNoSpaceError; /* ENOSPC */
201 static PyObject* DBNoMemoryError; /* DB_BUFFER_SMALL (ENOMEM when < 4.3) */
202 static PyObject* DBAgainError; /* EAGAIN */
203 static PyObject* DBBusyError; /* EBUSY */
204 static PyObject* DBFileExistsError; /* EEXIST */
205 static PyObject* DBNoSuchFileError; /* ENOENT */
206 static PyObject* DBPermissionsError; /* EPERM */
208 #if (DBVER >= 42)
209 static PyObject* DBRepHandleDeadError; /* DB_REP_HANDLE_DEAD */
210 #endif
212 static PyObject* DBRepUnavailError; /* DB_REP_UNAVAIL */
214 #if (DBVER < 43)
215 #define DB_BUFFER_SMALL ENOMEM
216 #endif
219 /* --------------------------------------------------------------------- */
220 /* Structure definitions */
222 #if PYTHON_API_VERSION < 1010
223 #error "Python 2.1 or later required"
224 #endif
227 /* Defaults for moduleFlags in DBEnvObject and DBObject. */
228 #define DEFAULT_GET_RETURNS_NONE 1
229 #define DEFAULT_CURSOR_SET_RETURNS_NONE 1 /* 0 in pybsddb < 4.2, python < 2.4 */
232 /* See comment in Python 2.6 "object.h" */
233 #ifndef staticforward
234 #define staticforward static
235 #endif
236 #ifndef statichere
237 #define statichere static
238 #endif
240 staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type,
241 DBLock_Type;
242 #if (DBVER >= 43)
243 staticforward PyTypeObject DBSequence_Type;
244 #endif
246 #ifndef Py_TYPE
247 /* for compatibility with Python 2.5 and earlier */
248 #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
249 #endif
251 #define DBObject_Check(v) (Py_TYPE(v) == &DB_Type)
252 #define DBCursorObject_Check(v) (Py_TYPE(v) == &DBCursor_Type)
253 #define DBEnvObject_Check(v) (Py_TYPE(v) == &DBEnv_Type)
254 #define DBTxnObject_Check(v) (Py_TYPE(v) == &DBTxn_Type)
255 #define DBLockObject_Check(v) (Py_TYPE(v) == &DBLock_Type)
256 #if (DBVER >= 43)
257 #define DBSequenceObject_Check(v) (Py_TYPE(v) == &DBSequence_Type)
258 #endif
260 #if (DBVER < 46)
261 #define _DBC_close(dbc) dbc->c_close(dbc)
262 #define _DBC_count(dbc,a,b) dbc->c_count(dbc,a,b)
263 #define _DBC_del(dbc,a) dbc->c_del(dbc,a)
264 #define _DBC_dup(dbc,a,b) dbc->c_dup(dbc,a,b)
265 #define _DBC_get(dbc,a,b,c) dbc->c_get(dbc,a,b,c)
266 #define _DBC_pget(dbc,a,b,c,d) dbc->c_pget(dbc,a,b,c,d)
267 #define _DBC_put(dbc,a,b,c) dbc->c_put(dbc,a,b,c)
268 #else
269 #define _DBC_close(dbc) dbc->close(dbc)
270 #define _DBC_count(dbc,a,b) dbc->count(dbc,a,b)
271 #define _DBC_del(dbc,a) dbc->del(dbc,a)
272 #define _DBC_dup(dbc,a,b) dbc->dup(dbc,a,b)
273 #define _DBC_get(dbc,a,b,c) dbc->get(dbc,a,b,c)
274 #define _DBC_pget(dbc,a,b,c,d) dbc->pget(dbc,a,b,c,d)
275 #define _DBC_put(dbc,a,b,c) dbc->put(dbc,a,b,c)
276 #endif
279 /* --------------------------------------------------------------------- */
280 /* Utility macros and functions */
282 #define INSERT_IN_DOUBLE_LINKED_LIST(backlink,object) \
284 object->sibling_next=backlink; \
285 object->sibling_prev_p=&(backlink); \
286 backlink=object; \
287 if (object->sibling_next) { \
288 object->sibling_next->sibling_prev_p=&(object->sibling_next); \
292 #define EXTRACT_FROM_DOUBLE_LINKED_LIST(object) \
294 if (object->sibling_next) { \
295 object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
297 *(object->sibling_prev_p)=object->sibling_next; \
300 #define EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(object) \
302 if (object->sibling_next) { \
303 object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
305 if (object->sibling_prev_p) { \
306 *(object->sibling_prev_p)=object->sibling_next; \
310 #define INSERT_IN_DOUBLE_LINKED_LIST_TXN(backlink,object) \
312 object->sibling_next_txn=backlink; \
313 object->sibling_prev_p_txn=&(backlink); \
314 backlink=object; \
315 if (object->sibling_next_txn) { \
316 object->sibling_next_txn->sibling_prev_p_txn= \
317 &(object->sibling_next_txn); \
321 #define EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(object) \
323 if (object->sibling_next_txn) { \
324 object->sibling_next_txn->sibling_prev_p_txn= \
325 object->sibling_prev_p_txn; \
327 *(object->sibling_prev_p_txn)=object->sibling_next_txn; \
331 #define RETURN_IF_ERR() \
332 if (makeDBError(err)) { \
333 return NULL; \
336 #define RETURN_NONE() Py_INCREF(Py_None); return Py_None;
338 #define _CHECK_OBJECT_NOT_CLOSED(nonNull, pyErrObj, name) \
339 if ((nonNull) == NULL) { \
340 PyObject *errTuple = NULL; \
341 errTuple = Py_BuildValue("(is)", 0, #name " object has been closed"); \
342 if (errTuple) { \
343 PyErr_SetObject((pyErrObj), errTuple); \
344 Py_DECREF(errTuple); \
346 return NULL; \
349 #define CHECK_DB_NOT_CLOSED(dbobj) \
350 _CHECK_OBJECT_NOT_CLOSED(dbobj->db, DBError, DB)
352 #define CHECK_ENV_NOT_CLOSED(env) \
353 _CHECK_OBJECT_NOT_CLOSED(env->db_env, DBError, DBEnv)
355 #define CHECK_CURSOR_NOT_CLOSED(curs) \
356 _CHECK_OBJECT_NOT_CLOSED(curs->dbc, DBCursorClosedError, DBCursor)
358 #if (DBVER >= 43)
359 #define CHECK_SEQUENCE_NOT_CLOSED(curs) \
360 _CHECK_OBJECT_NOT_CLOSED(curs->sequence, DBError, DBSequence)
361 #endif
363 #define CHECK_DBFLAG(mydb, flag) (((mydb)->flags & (flag)) || \
364 (((mydb)->myenvobj != NULL) && ((mydb)->myenvobj->flags & (flag))))
366 #define CLEAR_DBT(dbt) (memset(&(dbt), 0, sizeof(dbt)))
368 #define FREE_DBT(dbt) if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \
369 dbt.data != NULL) { free(dbt.data); dbt.data = NULL; }
372 static int makeDBError(int err);
375 /* Return the access method type of the DBObject */
376 static int _DB_get_type(DBObject* self)
378 DBTYPE type;
379 int err;
381 err = self->db->get_type(self->db, &type);
382 if (makeDBError(err)) {
383 return -1;
385 return type;
389 /* Create a DBT structure (containing key and data values) from Python
390 strings. Returns 1 on success, 0 on an error. */
391 static int make_dbt(PyObject* obj, DBT* dbt)
393 CLEAR_DBT(*dbt);
394 if (obj == Py_None) {
395 /* no need to do anything, the structure has already been zeroed */
397 else if (!PyArg_Parse(obj, "s#", &dbt->data, &dbt->size)) {
398 PyErr_SetString(PyExc_TypeError,
399 "Data values must be of type string or None.");
400 return 0;
402 return 1;
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.
409 Caller MUST call FREE_DBT(key) when done. */
410 static int
411 make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags)
413 db_recno_t recno;
414 int type;
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;
427 /* no need to do anything, the structure has already been zeroed */
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 "String keys not allowed for Recno and Queue DB's");
439 return 0;
443 * NOTE(gps): I don't like doing a data copy here, it seems
444 * wasteful. But without a clean way to tell FREE_DBT if it
445 * should free key->data or not we have to. Other places in
446 * the code check for DB_THREAD and forceably set DBT_MALLOC
447 * when we otherwise would leave flags 0 to indicate that.
449 key->data = malloc(PyBytes_GET_SIZE(keyobj));
450 if (key->data == NULL) {
451 PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
452 return 0;
454 memcpy(key->data, PyBytes_AS_STRING(keyobj),
455 PyBytes_GET_SIZE(keyobj));
456 key->flags = DB_DBT_REALLOC;
457 key->size = PyBytes_GET_SIZE(keyobj);
460 else if (NUMBER_Check(keyobj)) {
461 /* verify access method type */
462 type = _DB_get_type(self);
463 if (type == -1)
464 return 0;
465 if (type == DB_BTREE && pflags != NULL) {
466 /* if BTREE then an Integer key is allowed with the
467 * DB_SET_RECNO flag */
468 *pflags |= DB_SET_RECNO;
470 else if (type != DB_RECNO && type != DB_QUEUE) {
471 PyErr_SetString(
472 PyExc_TypeError,
473 "Integer keys only allowed for Recno and Queue DB's");
474 return 0;
477 /* Make a key out of the requested recno, use allocated space so DB
478 * will be able to realloc room for the real key if needed. */
479 recno = NUMBER_AsLong(keyobj);
480 key->data = malloc(sizeof(db_recno_t));
481 if (key->data == NULL) {
482 PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
483 return 0;
485 key->ulen = key->size = sizeof(db_recno_t);
486 memcpy(key->data, &recno, sizeof(db_recno_t));
487 key->flags = DB_DBT_REALLOC;
489 else {
490 PyErr_Format(PyExc_TypeError,
491 "String or Integer object expected for key, %s found",
492 Py_TYPE(keyobj)->tp_name);
493 return 0;
496 return 1;
500 /* Add partial record access to an existing DBT data struct.
501 If dlen and doff are set, then the DB_DBT_PARTIAL flag will be set
502 and the data storage/retrieval will be done using dlen and doff. */
503 static int add_partial_dbt(DBT* d, int dlen, int doff) {
504 /* if neither were set we do nothing (-1 is the default value) */
505 if ((dlen == -1) && (doff == -1)) {
506 return 1;
509 if ((dlen < 0) || (doff < 0)) {
510 PyErr_SetString(PyExc_TypeError, "dlen and doff must both be >= 0");
511 return 0;
514 d->flags = d->flags | DB_DBT_PARTIAL;
515 d->dlen = (unsigned int) dlen;
516 d->doff = (unsigned int) doff;
517 return 1;
520 /* a safe strcpy() without the zeroing behaviour and semantics of strncpy. */
521 /* TODO: make this use the native libc strlcpy() when available (BSD) */
522 unsigned int our_strlcpy(char* dest, const char* src, unsigned int n)
524 unsigned int srclen, copylen;
526 srclen = strlen(src);
527 if (n <= 0)
528 return srclen;
529 copylen = (srclen > n-1) ? n-1 : srclen;
530 /* populate dest[0] thru dest[copylen-1] */
531 memcpy(dest, src, copylen);
532 /* guarantee null termination */
533 dest[copylen] = 0;
535 return srclen;
538 /* Callback used to save away more information about errors from the DB
539 * library. */
540 static char _db_errmsg[1024];
541 #if (DBVER <= 42)
542 static void _db_errorCallback(const char* prefix, char* msg)
543 #else
544 static void _db_errorCallback(const DB_ENV *db_env,
545 const char* prefix, const char* msg)
546 #endif
548 our_strlcpy(_db_errmsg, msg, sizeof(_db_errmsg));
553 ** We need these functions because some results
554 ** are undefined if pointer is NULL. Some other
555 ** give None instead of "".
557 ** This functions are static and will be
558 ** -I hope- inlined.
560 static const char *DummyString = "This string is a simple placeholder";
561 static PyObject *Build_PyString(const char *p,int s)
563 if (!p) {
564 p=DummyString;
565 assert(s==0);
567 return PyBytes_FromStringAndSize(p,s);
570 static PyObject *BuildValue_S(const void *p,int s)
572 if (!p) {
573 p=DummyString;
574 assert(s==0);
576 return Py_BuildValue("s#",p,s);
579 static PyObject *BuildValue_SS(const void *p1,int s1,const void *p2,int s2)
581 if (!p1) {
582 p1=DummyString;
583 assert(s1==0);
585 if (!p2) {
586 p2=DummyString;
587 assert(s2==0);
589 return Py_BuildValue("s#s#",p1,s1,p2,s2);
592 static PyObject *BuildValue_IS(int i,const void *p,int s)
594 if (!p) {
595 p=DummyString;
596 assert(s==0);
598 return Py_BuildValue("is#",i,p,s);
601 static PyObject *BuildValue_LS(long i,const void *p,int s)
603 if (!p) {
604 p=DummyString;
605 assert(s==0);
607 return Py_BuildValue("ls#",i,p,s);
612 /* make a nice exception object to raise for errors. */
613 static int makeDBError(int err)
615 char errTxt[2048]; /* really big, just in case... */
616 PyObject *errObj = NULL;
617 PyObject *errTuple = NULL;
618 int exceptionRaised = 0;
619 unsigned int bytes_left;
621 switch (err) {
622 case 0: /* successful, no error */ break;
624 #if (DBVER < 41)
625 case DB_INCOMPLETE:
626 #if INCOMPLETE_IS_WARNING
627 bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt));
628 /* Ensure that bytes_left never goes negative */
629 if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) {
630 bytes_left = sizeof(errTxt) - bytes_left - 4 - 1;
631 assert(bytes_left >= 0);
632 strcat(errTxt, " -- ");
633 strncat(errTxt, _db_errmsg, bytes_left);
635 _db_errmsg[0] = 0;
636 exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt);
638 #else /* do an exception instead */
639 errObj = DBIncompleteError;
640 #endif
641 break;
642 #endif /* DBVER < 41 */
644 case DB_KEYEMPTY: errObj = DBKeyEmptyError; break;
645 case DB_KEYEXIST: errObj = DBKeyExistError; break;
646 case DB_LOCK_DEADLOCK: errObj = DBLockDeadlockError; break;
647 case DB_LOCK_NOTGRANTED: errObj = DBLockNotGrantedError; break;
648 case DB_NOTFOUND: errObj = DBNotFoundError; break;
649 case DB_OLD_VERSION: errObj = DBOldVersionError; break;
650 case DB_RUNRECOVERY: errObj = DBRunRecoveryError; break;
651 case DB_VERIFY_BAD: errObj = DBVerifyBadError; break;
652 case DB_NOSERVER: errObj = DBNoServerError; break;
653 case DB_NOSERVER_HOME: errObj = DBNoServerHomeError; break;
654 case DB_NOSERVER_ID: errObj = DBNoServerIDError; break;
655 case DB_PAGE_NOTFOUND: errObj = DBPageNotFoundError; break;
656 case DB_SECONDARY_BAD: errObj = DBSecondaryBadError; break;
657 case DB_BUFFER_SMALL: errObj = DBNoMemoryError; break;
659 #if (DBVER >= 43)
660 /* ENOMEM and DB_BUFFER_SMALL were one and the same until 4.3 */
661 case ENOMEM: errObj = PyExc_MemoryError; break;
662 #endif
663 case EINVAL: errObj = DBInvalidArgError; break;
664 case EACCES: errObj = DBAccessError; break;
665 case ENOSPC: errObj = DBNoSpaceError; break;
666 case EAGAIN: errObj = DBAgainError; break;
667 case EBUSY : errObj = DBBusyError; break;
668 case EEXIST: errObj = DBFileExistsError; break;
669 case ENOENT: errObj = DBNoSuchFileError; break;
670 case EPERM : errObj = DBPermissionsError; break;
672 #if (DBVER >= 42)
673 case DB_REP_HANDLE_DEAD : errObj = DBRepHandleDeadError; break;
674 #endif
676 case DB_REP_UNAVAIL : errObj = DBRepUnavailError; break;
678 default: errObj = DBError; break;
681 if (errObj != NULL) {
682 bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt));
683 /* Ensure that bytes_left never goes negative */
684 if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) {
685 bytes_left = sizeof(errTxt) - bytes_left - 4 - 1;
686 assert(bytes_left >= 0);
687 strcat(errTxt, " -- ");
688 strncat(errTxt, _db_errmsg, bytes_left);
690 _db_errmsg[0] = 0;
692 errTuple = Py_BuildValue("(is)", err, errTxt);
693 if (errTuple == NULL) {
694 Py_DECREF(errObj);
695 return !0;
697 PyErr_SetObject(errObj, errTuple);
698 Py_DECREF(errTuple);
701 return ((errObj != NULL) || exceptionRaised);
706 /* set a type exception */
707 static void makeTypeError(char* expected, PyObject* found)
709 PyErr_Format(PyExc_TypeError, "Expected %s argument, %s found.",
710 expected, Py_TYPE(found)->tp_name);
714 /* verify that an obj is either None or a DBTxn, and set the txn pointer */
715 static int checkTxnObj(PyObject* txnobj, DB_TXN** txn)
717 if (txnobj == Py_None || txnobj == NULL) {
718 *txn = NULL;
719 return 1;
721 if (DBTxnObject_Check(txnobj)) {
722 *txn = ((DBTxnObject*)txnobj)->txn;
723 return 1;
725 else
726 makeTypeError("DBTxn", txnobj);
727 return 0;
731 /* Delete a key from a database
732 Returns 0 on success, -1 on an error. */
733 static int _DB_delete(DBObject* self, DB_TXN *txn, DBT *key, int flags)
735 int err;
737 MYDB_BEGIN_ALLOW_THREADS;
738 err = self->db->del(self->db, txn, key, 0);
739 MYDB_END_ALLOW_THREADS;
740 if (makeDBError(err)) {
741 return -1;
743 self->haveStat = 0;
744 return 0;
748 /* Store a key into a database
749 Returns 0 on success, -1 on an error. */
750 static int _DB_put(DBObject* self, DB_TXN *txn, DBT *key, DBT *data, int flags)
752 int err;
754 MYDB_BEGIN_ALLOW_THREADS;
755 err = self->db->put(self->db, txn, key, data, flags);
756 MYDB_END_ALLOW_THREADS;
757 if (makeDBError(err)) {
758 return -1;
760 self->haveStat = 0;
761 return 0;
764 /* Get a key/data pair from a cursor */
765 static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
766 PyObject *args, PyObject *kwargs, char *format)
768 int err;
769 PyObject* retval = NULL;
770 DBT key, data;
771 int dlen = -1;
772 int doff = -1;
773 int flags = 0;
774 static char* kwnames[] = { "flags", "dlen", "doff", NULL };
776 if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, kwnames,
777 &flags, &dlen, &doff))
778 return NULL;
780 CHECK_CURSOR_NOT_CLOSED(self);
782 flags |= extra_flags;
783 CLEAR_DBT(key);
784 CLEAR_DBT(data);
785 if (!add_partial_dbt(&data, dlen, doff))
786 return NULL;
788 MYDB_BEGIN_ALLOW_THREADS;
789 err = _DBC_get(self->dbc, &key, &data, flags);
790 MYDB_END_ALLOW_THREADS;
792 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
793 && self->mydb->moduleFlags.getReturnsNone) {
794 Py_INCREF(Py_None);
795 retval = Py_None;
797 else if (makeDBError(err)) {
798 retval = NULL;
800 else { /* otherwise, success! */
802 /* if Recno or Queue, return the key as an Int */
803 switch (_DB_get_type(self->mydb)) {
804 case -1:
805 retval = NULL;
806 break;
808 case DB_RECNO:
809 case DB_QUEUE:
810 retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
811 break;
812 case DB_HASH:
813 case DB_BTREE:
814 default:
815 retval = BuildValue_SS(key.data, key.size, data.data, data.size);
816 break;
819 return retval;
823 /* add an integer to a dictionary using the given name as a key */
824 static void _addIntToDict(PyObject* dict, char *name, int value)
826 PyObject* v = NUMBER_FromLong((long) value);
827 if (!v || PyDict_SetItemString(dict, name, v))
828 PyErr_Clear();
830 Py_XDECREF(v);
833 /* The same, when the value is a time_t */
834 static void _addTimeTToDict(PyObject* dict, char *name, time_t value)
836 PyObject* v;
837 /* if the value fits in regular int, use that. */
838 #ifdef PY_LONG_LONG
839 if (sizeof(time_t) > sizeof(long))
840 v = PyLong_FromLongLong((PY_LONG_LONG) value);
841 else
842 #endif
843 v = NUMBER_FromLong((long) value);
844 if (!v || PyDict_SetItemString(dict, name, v))
845 PyErr_Clear();
847 Py_XDECREF(v);
850 #if (DBVER >= 43)
851 /* add an db_seq_t to a dictionary using the given name as a key */
852 static void _addDb_seq_tToDict(PyObject* dict, char *name, db_seq_t value)
854 PyObject* v = PyLong_FromLongLong(value);
855 if (!v || PyDict_SetItemString(dict, name, v))
856 PyErr_Clear();
858 Py_XDECREF(v);
860 #endif
862 static void _addDB_lsnToDict(PyObject* dict, char *name, DB_LSN value)
864 PyObject *v = Py_BuildValue("(ll)",value.file,value.offset);
865 if (!v || PyDict_SetItemString(dict, name, v))
866 PyErr_Clear();
868 Py_XDECREF(v);
871 /* --------------------------------------------------------------------- */
872 /* Allocators and deallocators */
874 static DBObject*
875 newDBObject(DBEnvObject* arg, int flags)
877 DBObject* self;
878 DB_ENV* db_env = NULL;
879 int err;
881 self = PyObject_New(DBObject, &DB_Type);
882 if (self == NULL)
883 return NULL;
885 self->haveStat = 0;
886 self->flags = 0;
887 self->setflags = 0;
888 self->myenvobj = NULL;
889 self->db = NULL;
890 self->children_cursors = NULL;
891 #if (DBVER >=43)
892 self->children_sequences = NULL;
893 #endif
894 self->associateCallback = NULL;
895 self->btCompareCallback = NULL;
896 self->primaryDBType = 0;
897 Py_INCREF(Py_None);
898 self->private = Py_None;
899 self->in_weakreflist = NULL;
901 /* keep a reference to our python DBEnv object */
902 if (arg) {
903 Py_INCREF(arg);
904 self->myenvobj = arg;
905 db_env = arg->db_env;
906 INSERT_IN_DOUBLE_LINKED_LIST(self->myenvobj->children_dbs,self);
907 } else {
908 self->sibling_prev_p=NULL;
909 self->sibling_next=NULL;
911 self->txn=NULL;
912 self->sibling_prev_p_txn=NULL;
913 self->sibling_next_txn=NULL;
915 if (self->myenvobj)
916 self->moduleFlags = self->myenvobj->moduleFlags;
917 else
918 self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
919 self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
921 MYDB_BEGIN_ALLOW_THREADS;
922 err = db_create(&self->db, db_env, flags);
923 if (self->db != NULL) {
924 self->db->set_errcall(self->db, _db_errorCallback);
925 self->db->app_private = (void*)self;
927 MYDB_END_ALLOW_THREADS;
928 /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs
929 * list so that a DBEnv can refuse to close without aborting any open
930 * DBTxns and closing any open DBs first. */
931 if (makeDBError(err)) {
932 if (self->myenvobj) {
933 Py_DECREF(self->myenvobj);
934 self->myenvobj = NULL;
936 Py_DECREF(self);
937 self = NULL;
939 return self;
943 /* Forward declaration */
944 static PyObject *DB_close_internal(DBObject* self, int flags);
946 static void
947 DB_dealloc(DBObject* self)
949 PyObject *dummy;
951 if (self->db != NULL) {
952 dummy=DB_close_internal(self,0);
953 Py_XDECREF(dummy);
955 if (self->in_weakreflist != NULL) {
956 PyObject_ClearWeakRefs((PyObject *) self);
958 if (self->myenvobj) {
959 Py_DECREF(self->myenvobj);
960 self->myenvobj = NULL;
962 if (self->associateCallback != NULL) {
963 Py_DECREF(self->associateCallback);
964 self->associateCallback = NULL;
966 if (self->btCompareCallback != NULL) {
967 Py_DECREF(self->btCompareCallback);
968 self->btCompareCallback = NULL;
970 Py_DECREF(self->private);
971 PyObject_Del(self);
974 static DBCursorObject*
975 newDBCursorObject(DBC* dbc, DBTxnObject *txn, DBObject* db)
977 DBCursorObject* self = PyObject_New(DBCursorObject, &DBCursor_Type);
978 if (self == NULL)
979 return NULL;
981 self->dbc = dbc;
982 self->mydb = db;
984 INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_cursors,self);
985 if (txn && ((PyObject *)txn!=Py_None)) {
986 INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->children_cursors,self);
987 self->txn=txn;
988 } else {
989 self->txn=NULL;
992 self->in_weakreflist = NULL;
993 Py_INCREF(self->mydb);
994 return self;
998 /* Forward declaration */
999 static PyObject *DBC_close_internal(DBCursorObject* self);
1001 static void
1002 DBCursor_dealloc(DBCursorObject* self)
1004 PyObject *dummy;
1006 if (self->dbc != NULL) {
1007 dummy=DBC_close_internal(self);
1008 Py_XDECREF(dummy);
1010 if (self->in_weakreflist != NULL) {
1011 PyObject_ClearWeakRefs((PyObject *) self);
1013 Py_DECREF(self->mydb);
1014 PyObject_Del(self);
1018 static DBEnvObject*
1019 newDBEnvObject(int flags)
1021 int err;
1022 DBEnvObject* self = PyObject_New(DBEnvObject, &DBEnv_Type);
1023 if (self == NULL)
1024 return NULL;
1026 self->closed = 1;
1027 self->flags = flags;
1028 self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
1029 self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
1030 self->children_dbs = NULL;
1031 self->children_txns = NULL;
1032 Py_INCREF(Py_None);
1033 self->private = Py_None;
1034 Py_INCREF(Py_None);
1035 self->rep_transport = Py_None;
1036 self->in_weakreflist = NULL;
1037 self->event_notifyCallback = NULL;
1039 MYDB_BEGIN_ALLOW_THREADS;
1040 err = db_env_create(&self->db_env, flags);
1041 MYDB_END_ALLOW_THREADS;
1042 if (makeDBError(err)) {
1043 Py_DECREF(self);
1044 self = NULL;
1046 else {
1047 self->db_env->set_errcall(self->db_env, _db_errorCallback);
1048 self->db_env->app_private=self;
1050 return self;
1053 /* Forward declaration */
1054 static PyObject *DBEnv_close_internal(DBEnvObject* self, int flags);
1056 static void
1057 DBEnv_dealloc(DBEnvObject* self)
1059 PyObject *dummy;
1061 if (self->db_env && !self->closed) {
1062 dummy=DBEnv_close_internal(self,0);
1063 Py_XDECREF(dummy);
1066 Py_XDECREF(self->event_notifyCallback);
1067 self->event_notifyCallback = NULL;
1069 if (self->in_weakreflist != NULL) {
1070 PyObject_ClearWeakRefs((PyObject *) self);
1072 Py_DECREF(self->private);
1073 Py_DECREF(self->rep_transport);
1074 PyObject_Del(self);
1078 static DBTxnObject*
1079 newDBTxnObject(DBEnvObject* myenv, DBTxnObject *parent, DB_TXN *txn, int flags)
1081 int err;
1082 DB_TXN *parent_txn = NULL;
1084 DBTxnObject* self = PyObject_New(DBTxnObject, &DBTxn_Type);
1085 if (self == NULL)
1086 return NULL;
1088 self->in_weakreflist = NULL;
1089 self->children_txns = NULL;
1090 self->children_dbs = NULL;
1091 self->children_cursors = NULL;
1092 self->children_sequences = NULL;
1093 self->flag_prepare = 0;
1094 self->parent_txn = NULL;
1095 self->env = NULL;
1097 if (parent && ((PyObject *)parent!=Py_None)) {
1098 parent_txn = parent->txn;
1101 if (txn) {
1102 self->txn = txn;
1103 } else {
1104 MYDB_BEGIN_ALLOW_THREADS;
1105 err = myenv->db_env->txn_begin(myenv->db_env, parent_txn, &(self->txn), flags);
1106 MYDB_END_ALLOW_THREADS;
1108 if (makeDBError(err)) {
1109 Py_DECREF(self);
1110 return NULL;
1114 /* Can't use 'parent' because could be 'parent==Py_None' */
1115 if (parent_txn) {
1116 self->parent_txn = parent;
1117 Py_INCREF(parent);
1118 self->env = NULL;
1119 INSERT_IN_DOUBLE_LINKED_LIST(parent->children_txns, self);
1120 } else {
1121 self->parent_txn = NULL;
1122 Py_INCREF(myenv);
1123 self->env = myenv;
1124 INSERT_IN_DOUBLE_LINKED_LIST(myenv->children_txns, self);
1127 return self;
1130 /* Forward declaration */
1131 static PyObject *
1132 DBTxn_abort_discard_internal(DBTxnObject* self, int discard);
1134 static void
1135 DBTxn_dealloc(DBTxnObject* self)
1137 PyObject *dummy;
1139 if (self->txn) {
1140 int flag_prepare = self->flag_prepare;
1141 dummy=DBTxn_abort_discard_internal(self,0);
1142 Py_XDECREF(dummy);
1143 if (!flag_prepare) {
1144 PyErr_Warn(PyExc_RuntimeWarning,
1145 "DBTxn aborted in destructor. No prior commit() or abort().");
1149 if (self->in_weakreflist != NULL) {
1150 PyObject_ClearWeakRefs((PyObject *) self);
1153 if (self->env) {
1154 Py_DECREF(self->env);
1155 } else {
1156 Py_DECREF(self->parent_txn);
1158 PyObject_Del(self);
1162 static DBLockObject*
1163 newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj,
1164 db_lockmode_t lock_mode, int flags)
1166 int err;
1167 DBLockObject* self = PyObject_New(DBLockObject, &DBLock_Type);
1168 if (self == NULL)
1169 return NULL;
1170 self->in_weakreflist = NULL;
1172 MYDB_BEGIN_ALLOW_THREADS;
1173 err = myenv->db_env->lock_get(myenv->db_env, locker, flags, obj, lock_mode,
1174 &self->lock);
1175 MYDB_END_ALLOW_THREADS;
1176 if (makeDBError(err)) {
1177 Py_DECREF(self);
1178 self = NULL;
1181 return self;
1185 static void
1186 DBLock_dealloc(DBLockObject* self)
1188 if (self->in_weakreflist != NULL) {
1189 PyObject_ClearWeakRefs((PyObject *) self);
1191 /* TODO: is this lock held? should we release it? */
1193 PyObject_Del(self);
1197 #if (DBVER >= 43)
1198 static DBSequenceObject*
1199 newDBSequenceObject(DBObject* mydb, int flags)
1201 int err;
1202 DBSequenceObject* self = PyObject_New(DBSequenceObject, &DBSequence_Type);
1203 if (self == NULL)
1204 return NULL;
1205 Py_INCREF(mydb);
1206 self->mydb = mydb;
1208 INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_sequences,self);
1209 self->txn = NULL;
1211 self->in_weakreflist = NULL;
1213 MYDB_BEGIN_ALLOW_THREADS;
1214 err = db_sequence_create(&self->sequence, self->mydb->db, flags);
1215 MYDB_END_ALLOW_THREADS;
1216 if (makeDBError(err)) {
1217 Py_DECREF(self);
1218 self = NULL;
1221 return self;
1224 /* Forward declaration */
1225 static PyObject
1226 *DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close);
1228 static void
1229 DBSequence_dealloc(DBSequenceObject* self)
1231 PyObject *dummy;
1233 if (self->sequence != NULL) {
1234 dummy=DBSequence_close_internal(self,0,0);
1235 Py_XDECREF(dummy);
1238 if (self->in_weakreflist != NULL) {
1239 PyObject_ClearWeakRefs((PyObject *) self);
1242 Py_DECREF(self->mydb);
1243 PyObject_Del(self);
1245 #endif
1247 /* --------------------------------------------------------------------- */
1248 /* DB methods */
1250 static PyObject*
1251 DB_append(DBObject* self, PyObject* args)
1253 PyObject* txnobj = NULL;
1254 PyObject* dataobj;
1255 db_recno_t recno;
1256 DBT key, data;
1257 DB_TXN *txn = NULL;
1259 if (!PyArg_UnpackTuple(args, "append", 1, 2, &dataobj, &txnobj))
1260 return NULL;
1262 CHECK_DB_NOT_CLOSED(self);
1264 /* make a dummy key out of a recno */
1265 recno = 0;
1266 CLEAR_DBT(key);
1267 key.data = &recno;
1268 key.size = sizeof(recno);
1269 key.ulen = key.size;
1270 key.flags = DB_DBT_USERMEM;
1272 if (!make_dbt(dataobj, &data)) return NULL;
1273 if (!checkTxnObj(txnobj, &txn)) return NULL;
1275 if (-1 == _DB_put(self, txn, &key, &data, DB_APPEND))
1276 return NULL;
1278 return NUMBER_FromLong(recno);
1282 static int
1283 _db_associateCallback(DB* db, const DBT* priKey, const DBT* priData,
1284 DBT* secKey)
1286 int retval = DB_DONOTINDEX;
1287 DBObject* secondaryDB = (DBObject*)db->app_private;
1288 PyObject* callback = secondaryDB->associateCallback;
1289 int type = secondaryDB->primaryDBType;
1290 PyObject* args;
1291 PyObject* result = NULL;
1294 if (callback != NULL) {
1295 MYDB_BEGIN_BLOCK_THREADS;
1297 if (type == DB_RECNO || type == DB_QUEUE)
1298 args = BuildValue_LS(*((db_recno_t*)priKey->data), priData->data, priData->size);
1299 else
1300 args = BuildValue_SS(priKey->data, priKey->size, priData->data, priData->size);
1301 if (args != NULL) {
1302 result = PyEval_CallObject(callback, args);
1304 if (args == NULL || result == NULL) {
1305 PyErr_Print();
1307 else if (result == Py_None) {
1308 retval = DB_DONOTINDEX;
1310 else if (NUMBER_Check(result)) {
1311 retval = NUMBER_AsLong(result);
1313 else if (PyBytes_Check(result)) {
1314 char* data;
1315 Py_ssize_t size;
1317 CLEAR_DBT(*secKey);
1318 PyBytes_AsStringAndSize(result, &data, &size);
1319 secKey->flags = DB_DBT_APPMALLOC; /* DB will free */
1320 secKey->data = malloc(size); /* TODO, check this */
1321 if (secKey->data) {
1322 memcpy(secKey->data, data, size);
1323 secKey->size = size;
1324 retval = 0;
1326 else {
1327 PyErr_SetString(PyExc_MemoryError,
1328 "malloc failed in _db_associateCallback");
1329 PyErr_Print();
1332 else {
1333 PyErr_SetString(
1334 PyExc_TypeError,
1335 "DB associate callback should return DB_DONOTINDEX or string.");
1336 PyErr_Print();
1339 Py_XDECREF(args);
1340 Py_XDECREF(result);
1342 MYDB_END_BLOCK_THREADS;
1344 return retval;
1348 static PyObject*
1349 DB_associate(DBObject* self, PyObject* args, PyObject* kwargs)
1351 int err, flags=0;
1352 DBObject* secondaryDB;
1353 PyObject* callback;
1354 #if (DBVER >= 41)
1355 PyObject *txnobj = NULL;
1356 DB_TXN *txn = NULL;
1357 static char* kwnames[] = {"secondaryDB", "callback", "flags", "txn",
1358 NULL};
1359 #else
1360 static char* kwnames[] = {"secondaryDB", "callback", "flags", NULL};
1361 #endif
1363 #if (DBVER >= 41)
1364 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iO:associate", kwnames,
1365 &secondaryDB, &callback, &flags,
1366 &txnobj)) {
1367 #else
1368 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:associate", kwnames,
1369 &secondaryDB, &callback, &flags)) {
1370 #endif
1371 return NULL;
1374 #if (DBVER >= 41)
1375 if (!checkTxnObj(txnobj, &txn)) return NULL;
1376 #endif
1378 CHECK_DB_NOT_CLOSED(self);
1379 if (!DBObject_Check(secondaryDB)) {
1380 makeTypeError("DB", (PyObject*)secondaryDB);
1381 return NULL;
1383 CHECK_DB_NOT_CLOSED(secondaryDB);
1384 if (callback == Py_None) {
1385 callback = NULL;
1387 else if (!PyCallable_Check(callback)) {
1388 makeTypeError("Callable", callback);
1389 return NULL;
1392 /* Save a reference to the callback in the secondary DB. */
1393 Py_XDECREF(secondaryDB->associateCallback);
1394 Py_XINCREF(callback);
1395 secondaryDB->associateCallback = callback;
1396 secondaryDB->primaryDBType = _DB_get_type(self);
1398 /* PyEval_InitThreads is called here due to a quirk in python 1.5
1399 * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>:
1400 * The global interepreter lock is not initialized until the first
1401 * thread is created using thread.start_new_thread() or fork() is
1402 * called. that would cause the ALLOW_THREADS here to segfault due
1403 * to a null pointer reference if no threads or child processes
1404 * have been created. This works around that and is a no-op if
1405 * threads have already been initialized.
1406 * (see pybsddb-users mailing list post on 2002-08-07)
1408 #ifdef WITH_THREAD
1409 PyEval_InitThreads();
1410 #endif
1411 MYDB_BEGIN_ALLOW_THREADS;
1412 #if (DBVER >= 41)
1413 err = self->db->associate(self->db,
1414 txn,
1415 secondaryDB->db,
1416 _db_associateCallback,
1417 flags);
1418 #else
1419 err = self->db->associate(self->db,
1420 secondaryDB->db,
1421 _db_associateCallback,
1422 flags);
1423 #endif
1424 MYDB_END_ALLOW_THREADS;
1426 if (err) {
1427 Py_XDECREF(secondaryDB->associateCallback);
1428 secondaryDB->associateCallback = NULL;
1429 secondaryDB->primaryDBType = 0;
1432 RETURN_IF_ERR();
1433 RETURN_NONE();
1437 static PyObject*
1438 DB_close_internal(DBObject* self, int flags)
1440 PyObject *dummy;
1441 int err;
1443 if (self->db != NULL) {
1444 /* Can be NULL if db is not in an environment */
1445 EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(self);
1446 if (self->txn) {
1447 EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
1448 self->txn=NULL;
1451 while(self->children_cursors) {
1452 dummy=DBC_close_internal(self->children_cursors);
1453 Py_XDECREF(dummy);
1456 #if (DBVER >= 43)
1457 while(self->children_sequences) {
1458 dummy=DBSequence_close_internal(self->children_sequences,0,0);
1459 Py_XDECREF(dummy);
1461 #endif
1463 MYDB_BEGIN_ALLOW_THREADS;
1464 err = self->db->close(self->db, flags);
1465 MYDB_END_ALLOW_THREADS;
1466 self->db = NULL;
1467 RETURN_IF_ERR();
1469 RETURN_NONE();
1472 static PyObject*
1473 DB_close(DBObject* self, PyObject* args)
1475 int flags=0;
1476 if (!PyArg_ParseTuple(args,"|i:close", &flags))
1477 return NULL;
1478 return DB_close_internal(self,flags);
1482 static PyObject*
1483 _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
1485 int err, flags=0, type;
1486 PyObject* txnobj = NULL;
1487 PyObject* retval = NULL;
1488 DBT key, data;
1489 DB_TXN *txn = NULL;
1490 static char* kwnames[] = { "txn", "flags", NULL };
1492 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:consume", kwnames,
1493 &txnobj, &flags))
1494 return NULL;
1496 CHECK_DB_NOT_CLOSED(self);
1497 type = _DB_get_type(self);
1498 if (type == -1)
1499 return NULL;
1500 if (type != DB_QUEUE) {
1501 PyErr_SetString(PyExc_TypeError,
1502 "Consume methods only allowed for Queue DB's");
1503 return NULL;
1505 if (!checkTxnObj(txnobj, &txn))
1506 return NULL;
1508 CLEAR_DBT(key);
1509 CLEAR_DBT(data);
1510 if (CHECK_DBFLAG(self, DB_THREAD)) {
1511 /* Tell Berkeley DB to malloc the return value (thread safe) */
1512 data.flags = DB_DBT_MALLOC;
1513 key.flags = DB_DBT_MALLOC;
1516 MYDB_BEGIN_ALLOW_THREADS;
1517 err = self->db->get(self->db, txn, &key, &data, flags|consume_flag);
1518 MYDB_END_ALLOW_THREADS;
1520 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1521 && self->moduleFlags.getReturnsNone) {
1522 err = 0;
1523 Py_INCREF(Py_None);
1524 retval = Py_None;
1526 else if (!err) {
1527 retval = BuildValue_SS(key.data, key.size, data.data, data.size);
1528 FREE_DBT(key);
1529 FREE_DBT(data);
1532 RETURN_IF_ERR();
1533 return retval;
1536 static PyObject*
1537 DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
1539 return _DB_consume(self, args, kwargs, DB_CONSUME);
1542 static PyObject*
1543 DB_consume_wait(DBObject* self, PyObject* args, PyObject* kwargs,
1544 int consume_flag)
1546 return _DB_consume(self, args, kwargs, DB_CONSUME_WAIT);
1550 static PyObject*
1551 DB_cursor(DBObject* self, PyObject* args, PyObject* kwargs)
1553 int err, flags=0;
1554 DBC* dbc;
1555 PyObject* txnobj = NULL;
1556 DB_TXN *txn = NULL;
1557 static char* kwnames[] = { "txn", "flags", NULL };
1559 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames,
1560 &txnobj, &flags))
1561 return NULL;
1562 CHECK_DB_NOT_CLOSED(self);
1563 if (!checkTxnObj(txnobj, &txn))
1564 return NULL;
1566 MYDB_BEGIN_ALLOW_THREADS;
1567 err = self->db->cursor(self->db, txn, &dbc, flags);
1568 MYDB_END_ALLOW_THREADS;
1569 RETURN_IF_ERR();
1570 return (PyObject*) newDBCursorObject(dbc, (DBTxnObject *)txnobj, self);
1574 static PyObject*
1575 DB_delete(DBObject* self, PyObject* args, PyObject* kwargs)
1577 PyObject* txnobj = NULL;
1578 int flags = 0;
1579 PyObject* keyobj;
1580 DBT key;
1581 DB_TXN *txn = NULL;
1582 static char* kwnames[] = { "key", "txn", "flags", NULL };
1584 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:delete", kwnames,
1585 &keyobj, &txnobj, &flags))
1586 return NULL;
1587 CHECK_DB_NOT_CLOSED(self);
1588 if (!make_key_dbt(self, keyobj, &key, NULL))
1589 return NULL;
1590 if (!checkTxnObj(txnobj, &txn)) {
1591 FREE_DBT(key);
1592 return NULL;
1595 if (-1 == _DB_delete(self, txn, &key, 0)) {
1596 FREE_DBT(key);
1597 return NULL;
1600 FREE_DBT(key);
1601 RETURN_NONE();
1605 static PyObject*
1606 DB_fd(DBObject* self)
1608 int err, the_fd;
1610 CHECK_DB_NOT_CLOSED(self);
1612 MYDB_BEGIN_ALLOW_THREADS;
1613 err = self->db->fd(self->db, &the_fd);
1614 MYDB_END_ALLOW_THREADS;
1615 RETURN_IF_ERR();
1616 return NUMBER_FromLong(the_fd);
1620 static PyObject*
1621 DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
1623 int err, flags=0;
1624 PyObject* txnobj = NULL;
1625 PyObject* keyobj;
1626 PyObject* dfltobj = NULL;
1627 PyObject* retval = NULL;
1628 int dlen = -1;
1629 int doff = -1;
1630 DBT key, data;
1631 DB_TXN *txn = NULL;
1632 static char* kwnames[] = {"key", "default", "txn", "flags", "dlen",
1633 "doff", NULL};
1635 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:get", kwnames,
1636 &keyobj, &dfltobj, &txnobj, &flags, &dlen,
1637 &doff))
1638 return NULL;
1640 CHECK_DB_NOT_CLOSED(self);
1641 if (!make_key_dbt(self, keyobj, &key, &flags))
1642 return NULL;
1643 if (!checkTxnObj(txnobj, &txn)) {
1644 FREE_DBT(key);
1645 return NULL;
1648 CLEAR_DBT(data);
1649 if (CHECK_DBFLAG(self, DB_THREAD)) {
1650 /* Tell Berkeley DB to malloc the return value (thread safe) */
1651 data.flags = DB_DBT_MALLOC;
1653 if (!add_partial_dbt(&data, dlen, doff)) {
1654 FREE_DBT(key);
1655 return NULL;
1658 MYDB_BEGIN_ALLOW_THREADS;
1659 err = self->db->get(self->db, txn, &key, &data, flags);
1660 MYDB_END_ALLOW_THREADS;
1662 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) {
1663 err = 0;
1664 Py_INCREF(dfltobj);
1665 retval = dfltobj;
1667 else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1668 && self->moduleFlags.getReturnsNone) {
1669 err = 0;
1670 Py_INCREF(Py_None);
1671 retval = Py_None;
1673 else if (!err) {
1674 if (flags & DB_SET_RECNO) /* return both key and data */
1675 retval = BuildValue_SS(key.data, key.size, data.data, data.size);
1676 else /* return just the data */
1677 retval = Build_PyString(data.data, data.size);
1678 FREE_DBT(data);
1680 FREE_DBT(key);
1682 RETURN_IF_ERR();
1683 return retval;
1686 static PyObject*
1687 DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
1689 int err, flags=0;
1690 PyObject* txnobj = NULL;
1691 PyObject* keyobj;
1692 PyObject* dfltobj = NULL;
1693 PyObject* retval = NULL;
1694 int dlen = -1;
1695 int doff = -1;
1696 DBT key, pkey, data;
1697 DB_TXN *txn = NULL;
1698 static char* kwnames[] = {"key", "default", "txn", "flags", "dlen",
1699 "doff", NULL};
1701 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:pget", kwnames,
1702 &keyobj, &dfltobj, &txnobj, &flags, &dlen,
1703 &doff))
1704 return NULL;
1706 CHECK_DB_NOT_CLOSED(self);
1707 if (!make_key_dbt(self, keyobj, &key, &flags))
1708 return NULL;
1709 if (!checkTxnObj(txnobj, &txn)) {
1710 FREE_DBT(key);
1711 return NULL;
1714 CLEAR_DBT(data);
1715 if (CHECK_DBFLAG(self, DB_THREAD)) {
1716 /* Tell Berkeley DB to malloc the return value (thread safe) */
1717 data.flags = DB_DBT_MALLOC;
1719 if (!add_partial_dbt(&data, dlen, doff)) {
1720 FREE_DBT(key);
1721 return NULL;
1724 CLEAR_DBT(pkey);
1725 pkey.flags = DB_DBT_MALLOC;
1727 MYDB_BEGIN_ALLOW_THREADS;
1728 err = self->db->pget(self->db, txn, &key, &pkey, &data, flags);
1729 MYDB_END_ALLOW_THREADS;
1731 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) {
1732 err = 0;
1733 Py_INCREF(dfltobj);
1734 retval = dfltobj;
1736 else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1737 && self->moduleFlags.getReturnsNone) {
1738 err = 0;
1739 Py_INCREF(Py_None);
1740 retval = Py_None;
1742 else if (!err) {
1743 PyObject *pkeyObj;
1744 PyObject *dataObj;
1745 dataObj = Build_PyString(data.data, data.size);
1747 if (self->primaryDBType == DB_RECNO ||
1748 self->primaryDBType == DB_QUEUE)
1749 pkeyObj = NUMBER_FromLong(*(int *)pkey.data);
1750 else
1751 pkeyObj = Build_PyString(pkey.data, pkey.size);
1753 if (flags & DB_SET_RECNO) /* return key , pkey and data */
1755 PyObject *keyObj;
1756 int type = _DB_get_type(self);
1757 if (type == DB_RECNO || type == DB_QUEUE)
1758 keyObj = NUMBER_FromLong(*(int *)key.data);
1759 else
1760 keyObj = Build_PyString(key.data, key.size);
1761 #if (PY_VERSION_HEX >= 0x02040000)
1762 retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
1763 #else
1764 retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj);
1765 #endif
1766 Py_DECREF(keyObj);
1768 else /* return just the pkey and data */
1770 #if (PY_VERSION_HEX >= 0x02040000)
1771 retval = PyTuple_Pack(2, pkeyObj, dataObj);
1772 #else
1773 retval = Py_BuildValue("OO", pkeyObj, dataObj);
1774 #endif
1776 Py_DECREF(dataObj);
1777 Py_DECREF(pkeyObj);
1778 FREE_DBT(pkey);
1779 FREE_DBT(data);
1781 FREE_DBT(key);
1783 RETURN_IF_ERR();
1784 return retval;
1788 /* Return size of entry */
1789 static PyObject*
1790 DB_get_size(DBObject* self, PyObject* args, PyObject* kwargs)
1792 int err, flags=0;
1793 PyObject* txnobj = NULL;
1794 PyObject* keyobj;
1795 PyObject* retval = NULL;
1796 DBT key, data;
1797 DB_TXN *txn = NULL;
1798 static char* kwnames[] = { "key", "txn", NULL };
1800 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:get_size", kwnames,
1801 &keyobj, &txnobj))
1802 return NULL;
1803 CHECK_DB_NOT_CLOSED(self);
1804 if (!make_key_dbt(self, keyobj, &key, &flags))
1805 return NULL;
1806 if (!checkTxnObj(txnobj, &txn)) {
1807 FREE_DBT(key);
1808 return NULL;
1810 CLEAR_DBT(data);
1812 /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and
1813 thus getting the record size. */
1814 data.flags = DB_DBT_USERMEM;
1815 data.ulen = 0;
1816 MYDB_BEGIN_ALLOW_THREADS;
1817 err = self->db->get(self->db, txn, &key, &data, flags);
1818 MYDB_END_ALLOW_THREADS;
1819 if (err == DB_BUFFER_SMALL) {
1820 retval = NUMBER_FromLong((long)data.size);
1821 err = 0;
1824 FREE_DBT(key);
1825 FREE_DBT(data);
1826 RETURN_IF_ERR();
1827 return retval;
1831 static PyObject*
1832 DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
1834 int err, flags=0;
1835 PyObject* txnobj = NULL;
1836 PyObject* keyobj;
1837 PyObject* dataobj;
1838 PyObject* retval = NULL;
1839 DBT key, data;
1840 void *orig_data;
1841 DB_TXN *txn = NULL;
1842 static char* kwnames[] = { "key", "data", "txn", "flags", NULL };
1844 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oi:get_both", kwnames,
1845 &keyobj, &dataobj, &txnobj, &flags))
1846 return NULL;
1848 CHECK_DB_NOT_CLOSED(self);
1849 if (!make_key_dbt(self, keyobj, &key, NULL))
1850 return NULL;
1851 if ( !make_dbt(dataobj, &data) ||
1852 !checkTxnObj(txnobj, &txn) )
1854 FREE_DBT(key);
1855 return NULL;
1858 flags |= DB_GET_BOTH;
1859 orig_data = data.data;
1861 if (CHECK_DBFLAG(self, DB_THREAD)) {
1862 /* Tell Berkeley DB to malloc the return value (thread safe) */
1863 /* XXX(nnorwitz): At least 4.4.20 and 4.5.20 require this flag. */
1864 data.flags = DB_DBT_MALLOC;
1867 MYDB_BEGIN_ALLOW_THREADS;
1868 err = self->db->get(self->db, txn, &key, &data, flags);
1869 MYDB_END_ALLOW_THREADS;
1871 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1872 && self->moduleFlags.getReturnsNone) {
1873 err = 0;
1874 Py_INCREF(Py_None);
1875 retval = Py_None;
1877 else if (!err) {
1878 /* XXX(nnorwitz): can we do: retval = dataobj; Py_INCREF(retval); */
1879 retval = Build_PyString(data.data, data.size);
1881 /* Even though the flags require DB_DBT_MALLOC, data is not always
1882 allocated. 4.4: allocated, 4.5: *not* allocated. :-( */
1883 if (data.data != orig_data)
1884 FREE_DBT(data);
1887 FREE_DBT(key);
1888 RETURN_IF_ERR();
1889 return retval;
1893 static PyObject*
1894 DB_get_byteswapped(DBObject* self)
1896 int err = 0;
1897 int retval = -1;
1899 CHECK_DB_NOT_CLOSED(self);
1901 MYDB_BEGIN_ALLOW_THREADS;
1902 err = self->db->get_byteswapped(self->db, &retval);
1903 MYDB_END_ALLOW_THREADS;
1904 RETURN_IF_ERR();
1905 return NUMBER_FromLong(retval);
1909 static PyObject*
1910 DB_get_type(DBObject* self)
1912 int type;
1914 CHECK_DB_NOT_CLOSED(self);
1916 type = _DB_get_type(self);
1917 if (type == -1)
1918 return NULL;
1919 return NUMBER_FromLong(type);
1923 static PyObject*
1924 DB_join(DBObject* self, PyObject* args)
1926 int err, flags=0;
1927 int length, x;
1928 PyObject* cursorsObj;
1929 DBC** cursors;
1930 DBC* dbc;
1932 if (!PyArg_ParseTuple(args,"O|i:join", &cursorsObj, &flags))
1933 return NULL;
1935 CHECK_DB_NOT_CLOSED(self);
1937 if (!PySequence_Check(cursorsObj)) {
1938 PyErr_SetString(PyExc_TypeError,
1939 "Sequence of DBCursor objects expected");
1940 return NULL;
1943 length = PyObject_Length(cursorsObj);
1944 cursors = malloc((length+1) * sizeof(DBC*));
1945 if (!cursors) {
1946 PyErr_NoMemory();
1947 return NULL;
1950 cursors[length] = NULL;
1951 for (x=0; x<length; x++) {
1952 PyObject* item = PySequence_GetItem(cursorsObj, x);
1953 if (item == NULL) {
1954 free(cursors);
1955 return NULL;
1957 if (!DBCursorObject_Check(item)) {
1958 PyErr_SetString(PyExc_TypeError,
1959 "Sequence of DBCursor objects expected");
1960 free(cursors);
1961 return NULL;
1963 cursors[x] = ((DBCursorObject*)item)->dbc;
1964 Py_DECREF(item);
1967 MYDB_BEGIN_ALLOW_THREADS;
1968 err = self->db->join(self->db, cursors, &dbc, flags);
1969 MYDB_END_ALLOW_THREADS;
1970 free(cursors);
1971 RETURN_IF_ERR();
1973 /* FIXME: this is a buggy interface. The returned cursor
1974 contains internal references to the passed in cursors
1975 but does not hold python references to them or prevent
1976 them from being closed prematurely. This can cause
1977 python to crash when things are done in the wrong order. */
1978 return (PyObject*) newDBCursorObject(dbc, NULL, self);
1982 static PyObject*
1983 DB_key_range(DBObject* self, PyObject* args, PyObject* kwargs)
1985 int err, flags=0;
1986 PyObject* txnobj = NULL;
1987 PyObject* keyobj;
1988 DBT key;
1989 DB_TXN *txn = NULL;
1990 DB_KEY_RANGE range;
1991 static char* kwnames[] = { "key", "txn", "flags", NULL };
1993 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:key_range", kwnames,
1994 &keyobj, &txnobj, &flags))
1995 return NULL;
1996 CHECK_DB_NOT_CLOSED(self);
1997 if (!make_dbt(keyobj, &key))
1998 /* BTree only, don't need to allow for an int key */
1999 return NULL;
2000 if (!checkTxnObj(txnobj, &txn))
2001 return NULL;
2003 MYDB_BEGIN_ALLOW_THREADS;
2004 err = self->db->key_range(self->db, txn, &key, &range, flags);
2005 MYDB_END_ALLOW_THREADS;
2007 RETURN_IF_ERR();
2008 return Py_BuildValue("ddd", range.less, range.equal, range.greater);
2012 static PyObject*
2013 DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
2015 int err, type = DB_UNKNOWN, flags=0, mode=0660;
2016 char* filename = NULL;
2017 char* dbname = NULL;
2018 #if (DBVER >= 41)
2019 PyObject *txnobj = NULL;
2020 DB_TXN *txn = NULL;
2021 /* with dbname */
2022 static char* kwnames[] = {
2023 "filename", "dbname", "dbtype", "flags", "mode", "txn", NULL};
2024 /* without dbname */
2025 static char* kwnames_basic[] = {
2026 "filename", "dbtype", "flags", "mode", "txn", NULL};
2027 #else
2028 /* with dbname */
2029 static char* kwnames[] = {
2030 "filename", "dbname", "dbtype", "flags", "mode", NULL};
2031 /* without dbname */
2032 static char* kwnames_basic[] = {
2033 "filename", "dbtype", "flags", "mode", NULL};
2034 #endif
2036 #if (DBVER >= 41)
2037 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziiiO:open", kwnames,
2038 &filename, &dbname, &type, &flags, &mode,
2039 &txnobj))
2040 #else
2041 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziii:open", kwnames,
2042 &filename, &dbname, &type, &flags,
2043 &mode))
2044 #endif
2046 PyErr_Clear();
2047 type = DB_UNKNOWN; flags = 0; mode = 0660;
2048 filename = NULL; dbname = NULL;
2049 #if (DBVER >= 41)
2050 if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iiiO:open",
2051 kwnames_basic,
2052 &filename, &type, &flags, &mode,
2053 &txnobj))
2054 return NULL;
2055 #else
2056 if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iii:open",
2057 kwnames_basic,
2058 &filename, &type, &flags, &mode))
2059 return NULL;
2060 #endif
2063 #if (DBVER >= 41)
2064 if (!checkTxnObj(txnobj, &txn)) return NULL;
2065 #endif
2067 if (NULL == self->db) {
2068 PyObject *t = Py_BuildValue("(is)", 0,
2069 "Cannot call open() twice for DB object");
2070 if (t) {
2071 PyErr_SetObject(DBError, t);
2072 Py_DECREF(t);
2074 return NULL;
2077 #if (DBVER >= 41)
2078 if (txn) { /* Can't use 'txnobj' because could be 'txnobj==Py_None' */
2079 INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_dbs,self);
2080 self->txn=(DBTxnObject *)txnobj;
2081 } else {
2082 self->txn=NULL;
2084 #else
2085 self->txn=NULL;
2086 #endif
2088 MYDB_BEGIN_ALLOW_THREADS;
2089 #if (DBVER >= 41)
2090 err = self->db->open(self->db, txn, filename, dbname, type, flags, mode);
2091 #else
2092 err = self->db->open(self->db, filename, dbname, type, flags, mode);
2093 #endif
2094 MYDB_END_ALLOW_THREADS;
2095 if (makeDBError(err)) {
2096 PyObject *dummy;
2098 dummy=DB_close_internal(self,0);
2099 Py_XDECREF(dummy);
2100 return NULL;
2103 #if (DBVER >= 42)
2104 self->db->get_flags(self->db, &self->setflags);
2105 #endif
2107 self->flags = flags;
2109 RETURN_NONE();
2113 static PyObject*
2114 DB_put(DBObject* self, PyObject* args, PyObject* kwargs)
2116 int flags=0;
2117 PyObject* txnobj = NULL;
2118 int dlen = -1;
2119 int doff = -1;
2120 PyObject* keyobj, *dataobj, *retval;
2121 DBT key, data;
2122 DB_TXN *txn = NULL;
2123 static char* kwnames[] = { "key", "data", "txn", "flags", "dlen",
2124 "doff", NULL };
2126 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oiii:put", kwnames,
2127 &keyobj, &dataobj, &txnobj, &flags, &dlen, &doff))
2128 return NULL;
2130 CHECK_DB_NOT_CLOSED(self);
2131 if (!make_key_dbt(self, keyobj, &key, NULL))
2132 return NULL;
2133 if ( !make_dbt(dataobj, &data) ||
2134 !add_partial_dbt(&data, dlen, doff) ||
2135 !checkTxnObj(txnobj, &txn) )
2137 FREE_DBT(key);
2138 return NULL;
2141 if (-1 == _DB_put(self, txn, &key, &data, flags)) {
2142 FREE_DBT(key);
2143 return NULL;
2146 if (flags & DB_APPEND)
2147 retval = NUMBER_FromLong(*((db_recno_t*)key.data));
2148 else {
2149 retval = Py_None;
2150 Py_INCREF(retval);
2152 FREE_DBT(key);
2153 return retval;
2158 static PyObject*
2159 DB_remove(DBObject* self, PyObject* args, PyObject* kwargs)
2161 char* filename;
2162 char* database = NULL;
2163 int err, flags=0;
2164 static char* kwnames[] = { "filename", "dbname", "flags", NULL};
2166 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zi:remove", kwnames,
2167 &filename, &database, &flags))
2168 return NULL;
2169 CHECK_DB_NOT_CLOSED(self);
2171 err = self->db->remove(self->db, filename, database, flags);
2172 self->db = NULL;
2173 RETURN_IF_ERR();
2174 RETURN_NONE();
2179 static PyObject*
2180 DB_rename(DBObject* self, PyObject* args)
2182 char* filename;
2183 char* database;
2184 char* newname;
2185 int err, flags=0;
2187 if (!PyArg_ParseTuple(args, "sss|i:rename", &filename, &database, &newname,
2188 &flags))
2189 return NULL;
2190 CHECK_DB_NOT_CLOSED(self);
2192 MYDB_BEGIN_ALLOW_THREADS;
2193 err = self->db->rename(self->db, filename, database, newname, flags);
2194 MYDB_END_ALLOW_THREADS;
2195 RETURN_IF_ERR();
2196 RETURN_NONE();
2200 static PyObject*
2201 DB_get_private(DBObject* self)
2203 /* We can give out the private field even if db is closed */
2204 Py_INCREF(self->private);
2205 return self->private;
2208 static PyObject*
2209 DB_set_private(DBObject* self, PyObject* private)
2211 /* We can set the private field even if db is closed */
2212 Py_DECREF(self->private);
2213 Py_INCREF(private);
2214 self->private = private;
2215 RETURN_NONE();
2219 static PyObject*
2220 DB_set_bt_minkey(DBObject* self, PyObject* args)
2222 int err, minkey;
2224 if (!PyArg_ParseTuple(args,"i:set_bt_minkey", &minkey ))
2225 return NULL;
2226 CHECK_DB_NOT_CLOSED(self);
2228 MYDB_BEGIN_ALLOW_THREADS;
2229 err = self->db->set_bt_minkey(self->db, minkey);
2230 MYDB_END_ALLOW_THREADS;
2231 RETURN_IF_ERR();
2232 RETURN_NONE();
2235 static int
2236 _default_cmp(const DBT *leftKey,
2237 const DBT *rightKey)
2239 int res;
2240 int lsize = leftKey->size, rsize = rightKey->size;
2242 res = memcmp(leftKey->data, rightKey->data,
2243 lsize < rsize ? lsize : rsize);
2245 if (res == 0) {
2246 if (lsize < rsize) {
2247 res = -1;
2249 else if (lsize > rsize) {
2250 res = 1;
2253 return res;
2256 static int
2257 _db_compareCallback(DB* db,
2258 const DBT *leftKey,
2259 const DBT *rightKey)
2261 int res = 0;
2262 PyObject *args;
2263 PyObject *result = NULL;
2264 DBObject *self = (DBObject *)db->app_private;
2266 if (self == NULL || self->btCompareCallback == NULL) {
2267 MYDB_BEGIN_BLOCK_THREADS;
2268 PyErr_SetString(PyExc_TypeError,
2269 (self == 0
2270 ? "DB_bt_compare db is NULL."
2271 : "DB_bt_compare callback is NULL."));
2272 /* we're in a callback within the DB code, we can't raise */
2273 PyErr_Print();
2274 res = _default_cmp(leftKey, rightKey);
2275 MYDB_END_BLOCK_THREADS;
2276 } else {
2277 MYDB_BEGIN_BLOCK_THREADS;
2279 args = BuildValue_SS(leftKey->data, leftKey->size, rightKey->data, rightKey->size);
2280 if (args != NULL) {
2281 /* XXX(twouters) I highly doubt this INCREF is correct */
2282 Py_INCREF(self);
2283 result = PyEval_CallObject(self->btCompareCallback, args);
2285 if (args == NULL || result == NULL) {
2286 /* we're in a callback within the DB code, we can't raise */
2287 PyErr_Print();
2288 res = _default_cmp(leftKey, rightKey);
2289 } else if (NUMBER_Check(result)) {
2290 res = NUMBER_AsLong(result);
2291 } else {
2292 PyErr_SetString(PyExc_TypeError,
2293 "DB_bt_compare callback MUST return an int.");
2294 /* we're in a callback within the DB code, we can't raise */
2295 PyErr_Print();
2296 res = _default_cmp(leftKey, rightKey);
2299 Py_XDECREF(args);
2300 Py_XDECREF(result);
2302 MYDB_END_BLOCK_THREADS;
2304 return res;
2307 static PyObject*
2308 DB_set_bt_compare(DBObject* self, PyObject* comparator)
2310 int err;
2311 PyObject *tuple, *result;
2313 CHECK_DB_NOT_CLOSED(self);
2315 if (!PyCallable_Check(comparator)) {
2316 makeTypeError("Callable", comparator);
2317 return NULL;
2321 * Perform a test call of the comparator function with two empty
2322 * string objects here. verify that it returns an int (0).
2323 * err if not.
2325 tuple = Py_BuildValue("(ss)", "", "");
2326 result = PyEval_CallObject(comparator, tuple);
2327 Py_DECREF(tuple);
2328 if (result == NULL)
2329 return NULL;
2330 if (!NUMBER_Check(result)) {
2331 PyErr_SetString(PyExc_TypeError,
2332 "callback MUST return an int");
2333 return NULL;
2334 } else if (NUMBER_AsLong(result) != 0) {
2335 PyErr_SetString(PyExc_TypeError,
2336 "callback failed to return 0 on two empty strings");
2337 return NULL;
2339 Py_DECREF(result);
2341 /* We don't accept multiple set_bt_compare operations, in order to
2342 * simplify the code. This would have no real use, as one cannot
2343 * change the function once the db is opened anyway */
2344 if (self->btCompareCallback != NULL) {
2345 PyErr_SetString(PyExc_RuntimeError, "set_bt_compare() cannot be called more than once");
2346 return NULL;
2349 Py_INCREF(comparator);
2350 self->btCompareCallback = comparator;
2352 /* This is to workaround a problem with un-initialized threads (see
2353 comment in DB_associate) */
2354 #ifdef WITH_THREAD
2355 PyEval_InitThreads();
2356 #endif
2358 err = self->db->set_bt_compare(self->db, _db_compareCallback);
2360 if (err) {
2361 /* restore the old state in case of error */
2362 Py_DECREF(comparator);
2363 self->btCompareCallback = NULL;
2366 RETURN_IF_ERR();
2367 RETURN_NONE();
2371 static PyObject*
2372 DB_set_cachesize(DBObject* self, PyObject* args)
2374 int err;
2375 int gbytes = 0, bytes = 0, ncache = 0;
2377 if (!PyArg_ParseTuple(args,"ii|i:set_cachesize",
2378 &gbytes,&bytes,&ncache))
2379 return NULL;
2380 CHECK_DB_NOT_CLOSED(self);
2382 MYDB_BEGIN_ALLOW_THREADS;
2383 err = self->db->set_cachesize(self->db, gbytes, bytes, ncache);
2384 MYDB_END_ALLOW_THREADS;
2385 RETURN_IF_ERR();
2386 RETURN_NONE();
2390 static PyObject*
2391 DB_set_flags(DBObject* self, PyObject* args)
2393 int err, flags;
2395 if (!PyArg_ParseTuple(args,"i:set_flags", &flags))
2396 return NULL;
2397 CHECK_DB_NOT_CLOSED(self);
2399 MYDB_BEGIN_ALLOW_THREADS;
2400 err = self->db->set_flags(self->db, flags);
2401 MYDB_END_ALLOW_THREADS;
2402 RETURN_IF_ERR();
2404 self->setflags |= flags;
2405 RETURN_NONE();
2409 static PyObject*
2410 DB_set_h_ffactor(DBObject* self, PyObject* args)
2412 int err, ffactor;
2414 if (!PyArg_ParseTuple(args,"i:set_h_ffactor", &ffactor))
2415 return NULL;
2416 CHECK_DB_NOT_CLOSED(self);
2418 MYDB_BEGIN_ALLOW_THREADS;
2419 err = self->db->set_h_ffactor(self->db, ffactor);
2420 MYDB_END_ALLOW_THREADS;
2421 RETURN_IF_ERR();
2422 RETURN_NONE();
2426 static PyObject*
2427 DB_set_h_nelem(DBObject* self, PyObject* args)
2429 int err, nelem;
2431 if (!PyArg_ParseTuple(args,"i:set_h_nelem", &nelem))
2432 return NULL;
2433 CHECK_DB_NOT_CLOSED(self);
2435 MYDB_BEGIN_ALLOW_THREADS;
2436 err = self->db->set_h_nelem(self->db, nelem);
2437 MYDB_END_ALLOW_THREADS;
2438 RETURN_IF_ERR();
2439 RETURN_NONE();
2443 static PyObject*
2444 DB_set_lorder(DBObject* self, PyObject* args)
2446 int err, lorder;
2448 if (!PyArg_ParseTuple(args,"i:set_lorder", &lorder))
2449 return NULL;
2450 CHECK_DB_NOT_CLOSED(self);
2452 MYDB_BEGIN_ALLOW_THREADS;
2453 err = self->db->set_lorder(self->db, lorder);
2454 MYDB_END_ALLOW_THREADS;
2455 RETURN_IF_ERR();
2456 RETURN_NONE();
2460 static PyObject*
2461 DB_set_pagesize(DBObject* self, PyObject* args)
2463 int err, pagesize;
2465 if (!PyArg_ParseTuple(args,"i:set_pagesize", &pagesize))
2466 return NULL;
2467 CHECK_DB_NOT_CLOSED(self);
2469 MYDB_BEGIN_ALLOW_THREADS;
2470 err = self->db->set_pagesize(self->db, pagesize);
2471 MYDB_END_ALLOW_THREADS;
2472 RETURN_IF_ERR();
2473 RETURN_NONE();
2477 static PyObject*
2478 DB_set_re_delim(DBObject* self, PyObject* args)
2480 int err;
2481 char delim;
2483 if (!PyArg_ParseTuple(args,"b:set_re_delim", &delim)) {
2484 PyErr_Clear();
2485 if (!PyArg_ParseTuple(args,"c:set_re_delim", &delim))
2486 return NULL;
2489 CHECK_DB_NOT_CLOSED(self);
2491 MYDB_BEGIN_ALLOW_THREADS;
2492 err = self->db->set_re_delim(self->db, delim);
2493 MYDB_END_ALLOW_THREADS;
2494 RETURN_IF_ERR();
2495 RETURN_NONE();
2498 static PyObject*
2499 DB_set_re_len(DBObject* self, PyObject* args)
2501 int err, len;
2503 if (!PyArg_ParseTuple(args,"i:set_re_len", &len))
2504 return NULL;
2505 CHECK_DB_NOT_CLOSED(self);
2507 MYDB_BEGIN_ALLOW_THREADS;
2508 err = self->db->set_re_len(self->db, len);
2509 MYDB_END_ALLOW_THREADS;
2510 RETURN_IF_ERR();
2511 RETURN_NONE();
2515 static PyObject*
2516 DB_set_re_pad(DBObject* self, PyObject* args)
2518 int err;
2519 char pad;
2521 if (!PyArg_ParseTuple(args,"b:set_re_pad", &pad)) {
2522 PyErr_Clear();
2523 if (!PyArg_ParseTuple(args,"c:set_re_pad", &pad))
2524 return NULL;
2526 CHECK_DB_NOT_CLOSED(self);
2528 MYDB_BEGIN_ALLOW_THREADS;
2529 err = self->db->set_re_pad(self->db, pad);
2530 MYDB_END_ALLOW_THREADS;
2531 RETURN_IF_ERR();
2532 RETURN_NONE();
2536 static PyObject*
2537 DB_set_re_source(DBObject* self, PyObject* args)
2539 int err;
2540 char *re_source;
2542 if (!PyArg_ParseTuple(args,"s:set_re_source", &re_source))
2543 return NULL;
2544 CHECK_DB_NOT_CLOSED(self);
2546 MYDB_BEGIN_ALLOW_THREADS;
2547 err = self->db->set_re_source(self->db, re_source);
2548 MYDB_END_ALLOW_THREADS;
2549 RETURN_IF_ERR();
2550 RETURN_NONE();
2554 static PyObject*
2555 DB_set_q_extentsize(DBObject* self, PyObject* args)
2557 int err;
2558 int extentsize;
2560 if (!PyArg_ParseTuple(args,"i:set_q_extentsize", &extentsize))
2561 return NULL;
2562 CHECK_DB_NOT_CLOSED(self);
2564 MYDB_BEGIN_ALLOW_THREADS;
2565 err = self->db->set_q_extentsize(self->db, extentsize);
2566 MYDB_END_ALLOW_THREADS;
2567 RETURN_IF_ERR();
2568 RETURN_NONE();
2571 static PyObject*
2572 DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
2574 int err, flags = 0, type;
2575 void* sp;
2576 PyObject* d;
2577 #if (DBVER >= 43)
2578 PyObject* txnobj = NULL;
2579 DB_TXN *txn = NULL;
2580 static char* kwnames[] = { "flags", "txn", NULL };
2581 #else
2582 static char* kwnames[] = { "flags", NULL };
2583 #endif
2585 #if (DBVER >= 43)
2586 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO:stat", kwnames,
2587 &flags, &txnobj))
2588 return NULL;
2589 if (!checkTxnObj(txnobj, &txn))
2590 return NULL;
2591 #else
2592 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags))
2593 return NULL;
2594 #endif
2595 CHECK_DB_NOT_CLOSED(self);
2597 MYDB_BEGIN_ALLOW_THREADS;
2598 #if (DBVER >= 43)
2599 err = self->db->stat(self->db, txn, &sp, flags);
2600 #else
2601 err = self->db->stat(self->db, &sp, flags);
2602 #endif
2603 MYDB_END_ALLOW_THREADS;
2604 RETURN_IF_ERR();
2606 self->haveStat = 1;
2608 /* Turn the stat structure into a dictionary */
2609 type = _DB_get_type(self);
2610 if ((type == -1) || ((d = PyDict_New()) == NULL)) {
2611 free(sp);
2612 return NULL;
2615 #define MAKE_HASH_ENTRY(name) _addIntToDict(d, #name, ((DB_HASH_STAT*)sp)->hash_##name)
2616 #define MAKE_BT_ENTRY(name) _addIntToDict(d, #name, ((DB_BTREE_STAT*)sp)->bt_##name)
2617 #define MAKE_QUEUE_ENTRY(name) _addIntToDict(d, #name, ((DB_QUEUE_STAT*)sp)->qs_##name)
2619 switch (type) {
2620 case DB_HASH:
2621 MAKE_HASH_ENTRY(magic);
2622 MAKE_HASH_ENTRY(version);
2623 MAKE_HASH_ENTRY(nkeys);
2624 MAKE_HASH_ENTRY(ndata);
2625 #if (DBVER >= 46)
2626 MAKE_HASH_ENTRY(pagecnt);
2627 #endif
2628 MAKE_HASH_ENTRY(pagesize);
2629 #if (DBVER < 41)
2630 MAKE_HASH_ENTRY(nelem);
2631 #endif
2632 MAKE_HASH_ENTRY(ffactor);
2633 MAKE_HASH_ENTRY(buckets);
2634 MAKE_HASH_ENTRY(free);
2635 MAKE_HASH_ENTRY(bfree);
2636 MAKE_HASH_ENTRY(bigpages);
2637 MAKE_HASH_ENTRY(big_bfree);
2638 MAKE_HASH_ENTRY(overflows);
2639 MAKE_HASH_ENTRY(ovfl_free);
2640 MAKE_HASH_ENTRY(dup);
2641 MAKE_HASH_ENTRY(dup_free);
2642 break;
2644 case DB_BTREE:
2645 case DB_RECNO:
2646 MAKE_BT_ENTRY(magic);
2647 MAKE_BT_ENTRY(version);
2648 MAKE_BT_ENTRY(nkeys);
2649 MAKE_BT_ENTRY(ndata);
2650 #if (DBVER >= 46)
2651 MAKE_BT_ENTRY(pagecnt);
2652 #endif
2653 MAKE_BT_ENTRY(pagesize);
2654 MAKE_BT_ENTRY(minkey);
2655 MAKE_BT_ENTRY(re_len);
2656 MAKE_BT_ENTRY(re_pad);
2657 MAKE_BT_ENTRY(levels);
2658 MAKE_BT_ENTRY(int_pg);
2659 MAKE_BT_ENTRY(leaf_pg);
2660 MAKE_BT_ENTRY(dup_pg);
2661 MAKE_BT_ENTRY(over_pg);
2662 #if (DBVER >= 43)
2663 MAKE_BT_ENTRY(empty_pg);
2664 #endif
2665 MAKE_BT_ENTRY(free);
2666 MAKE_BT_ENTRY(int_pgfree);
2667 MAKE_BT_ENTRY(leaf_pgfree);
2668 MAKE_BT_ENTRY(dup_pgfree);
2669 MAKE_BT_ENTRY(over_pgfree);
2670 break;
2672 case DB_QUEUE:
2673 MAKE_QUEUE_ENTRY(magic);
2674 MAKE_QUEUE_ENTRY(version);
2675 MAKE_QUEUE_ENTRY(nkeys);
2676 MAKE_QUEUE_ENTRY(ndata);
2677 MAKE_QUEUE_ENTRY(pagesize);
2678 #if (DBVER >= 41)
2679 MAKE_QUEUE_ENTRY(extentsize);
2680 #endif
2681 MAKE_QUEUE_ENTRY(pages);
2682 MAKE_QUEUE_ENTRY(re_len);
2683 MAKE_QUEUE_ENTRY(re_pad);
2684 MAKE_QUEUE_ENTRY(pgfree);
2685 #if (DBVER == 31)
2686 MAKE_QUEUE_ENTRY(start);
2687 #endif
2688 MAKE_QUEUE_ENTRY(first_recno);
2689 MAKE_QUEUE_ENTRY(cur_recno);
2690 break;
2692 default:
2693 PyErr_SetString(PyExc_TypeError, "Unknown DB type, unable to stat");
2694 Py_DECREF(d);
2695 d = NULL;
2698 #undef MAKE_HASH_ENTRY
2699 #undef MAKE_BT_ENTRY
2700 #undef MAKE_QUEUE_ENTRY
2702 free(sp);
2703 return d;
2706 static PyObject*
2707 DB_sync(DBObject* self, PyObject* args)
2709 int err;
2710 int flags = 0;
2712 if (!PyArg_ParseTuple(args,"|i:sync", &flags ))
2713 return NULL;
2714 CHECK_DB_NOT_CLOSED(self);
2716 MYDB_BEGIN_ALLOW_THREADS;
2717 err = self->db->sync(self->db, flags);
2718 MYDB_END_ALLOW_THREADS;
2719 RETURN_IF_ERR();
2720 RETURN_NONE();
2724 static PyObject*
2725 DB_truncate(DBObject* self, PyObject* args, PyObject* kwargs)
2727 int err, flags=0;
2728 u_int32_t count=0;
2729 PyObject* txnobj = NULL;
2730 DB_TXN *txn = NULL;
2731 static char* kwnames[] = { "txn", "flags", NULL };
2733 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames,
2734 &txnobj, &flags))
2735 return NULL;
2736 CHECK_DB_NOT_CLOSED(self);
2737 if (!checkTxnObj(txnobj, &txn))
2738 return NULL;
2740 MYDB_BEGIN_ALLOW_THREADS;
2741 err = self->db->truncate(self->db, txn, &count, flags);
2742 MYDB_END_ALLOW_THREADS;
2743 RETURN_IF_ERR();
2744 return NUMBER_FromLong(count);
2748 static PyObject*
2749 DB_upgrade(DBObject* self, PyObject* args)
2751 int err, flags=0;
2752 char *filename;
2754 if (!PyArg_ParseTuple(args,"s|i:upgrade", &filename, &flags))
2755 return NULL;
2756 CHECK_DB_NOT_CLOSED(self);
2758 MYDB_BEGIN_ALLOW_THREADS;
2759 err = self->db->upgrade(self->db, filename, flags);
2760 MYDB_END_ALLOW_THREADS;
2761 RETURN_IF_ERR();
2762 RETURN_NONE();
2766 static PyObject*
2767 DB_verify(DBObject* self, PyObject* args, PyObject* kwargs)
2769 int err, flags=0;
2770 char* fileName;
2771 char* dbName=NULL;
2772 char* outFileName=NULL;
2773 FILE* outFile=NULL;
2774 static char* kwnames[] = { "filename", "dbname", "outfile", "flags",
2775 NULL };
2777 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzi:verify", kwnames,
2778 &fileName, &dbName, &outFileName, &flags))
2779 return NULL;
2781 CHECK_DB_NOT_CLOSED(self);
2782 if (outFileName)
2783 outFile = fopen(outFileName, "w");
2784 /* XXX(nnorwitz): it should probably be an exception if outFile
2785 can't be opened. */
2787 MYDB_BEGIN_ALLOW_THREADS;
2788 err = self->db->verify(self->db, fileName, dbName, outFile, flags);
2789 MYDB_END_ALLOW_THREADS;
2790 if (outFile)
2791 fclose(outFile);
2793 { /* DB.verify acts as a DB handle destructor (like close) */
2794 PyObject *error;
2796 error=DB_close_internal(self,0);
2797 if (error ) {
2798 return error;
2802 RETURN_IF_ERR();
2803 RETURN_NONE();
2807 static PyObject*
2808 DB_set_get_returns_none(DBObject* self, PyObject* args)
2810 int flags=0;
2811 int oldValue=0;
2813 if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
2814 return NULL;
2815 CHECK_DB_NOT_CLOSED(self);
2817 if (self->moduleFlags.getReturnsNone)
2818 ++oldValue;
2819 if (self->moduleFlags.cursorSetReturnsNone)
2820 ++oldValue;
2821 self->moduleFlags.getReturnsNone = (flags >= 1);
2822 self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
2823 return NUMBER_FromLong(oldValue);
2826 #if (DBVER >= 41)
2827 static PyObject*
2828 DB_set_encrypt(DBObject* self, PyObject* args, PyObject* kwargs)
2830 int err;
2831 u_int32_t flags=0;
2832 char *passwd = NULL;
2833 static char* kwnames[] = { "passwd", "flags", NULL };
2835 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames,
2836 &passwd, &flags)) {
2837 return NULL;
2840 MYDB_BEGIN_ALLOW_THREADS;
2841 err = self->db->set_encrypt(self->db, passwd, flags);
2842 MYDB_END_ALLOW_THREADS;
2844 RETURN_IF_ERR();
2845 RETURN_NONE();
2847 #endif /* DBVER >= 41 */
2850 /*-------------------------------------------------------------- */
2851 /* Mapping and Dictionary-like access routines */
2853 Py_ssize_t DB_length(PyObject* _self)
2855 int err;
2856 Py_ssize_t size = 0;
2857 int flags = 0;
2858 void* sp;
2859 DBObject* self = (DBObject*)_self;
2861 if (self->db == NULL) {
2862 PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed");
2863 if (t) {
2864 PyErr_SetObject(DBError, t);
2865 Py_DECREF(t);
2867 return -1;
2870 if (self->haveStat) { /* Has the stat function been called recently? If
2871 so, we can use the cached value. */
2872 flags = DB_FAST_STAT;
2875 MYDB_BEGIN_ALLOW_THREADS;
2876 redo_stat_for_length:
2877 #if (DBVER >= 43)
2878 err = self->db->stat(self->db, /*txnid*/ NULL, &sp, flags);
2879 #else
2880 err = self->db->stat(self->db, &sp, flags);
2881 #endif
2883 /* All the stat structures have matching fields upto the ndata field,
2884 so we can use any of them for the type cast */
2885 size = ((DB_BTREE_STAT*)sp)->bt_ndata;
2887 /* A size of 0 could mean that Berkeley DB no longer had the stat values cached.
2888 * redo a full stat to make sure.
2889 * Fixes SF python bug 1493322, pybsddb bug 1184012
2891 if (size == 0 && (flags & DB_FAST_STAT)) {
2892 flags = 0;
2893 if (!err)
2894 free(sp);
2895 goto redo_stat_for_length;
2898 MYDB_END_ALLOW_THREADS;
2900 if (err)
2901 return -1;
2903 self->haveStat = 1;
2905 free(sp);
2906 return size;
2910 PyObject* DB_subscript(DBObject* self, PyObject* keyobj)
2912 int err;
2913 PyObject* retval;
2914 DBT key;
2915 DBT data;
2917 CHECK_DB_NOT_CLOSED(self);
2918 if (!make_key_dbt(self, keyobj, &key, NULL))
2919 return NULL;
2921 CLEAR_DBT(data);
2922 if (CHECK_DBFLAG(self, DB_THREAD)) {
2923 /* Tell Berkeley DB to malloc the return value (thread safe) */
2924 data.flags = DB_DBT_MALLOC;
2926 MYDB_BEGIN_ALLOW_THREADS;
2927 err = self->db->get(self->db, NULL, &key, &data, 0);
2928 MYDB_END_ALLOW_THREADS;
2929 if (err == DB_NOTFOUND || err == DB_KEYEMPTY) {
2930 PyErr_SetObject(PyExc_KeyError, keyobj);
2931 retval = NULL;
2933 else if (makeDBError(err)) {
2934 retval = NULL;
2936 else {
2937 retval = Build_PyString(data.data, data.size);
2938 FREE_DBT(data);
2941 FREE_DBT(key);
2942 return retval;
2946 static int
2947 DB_ass_sub(DBObject* self, PyObject* keyobj, PyObject* dataobj)
2949 DBT key, data;
2950 int retval;
2951 int flags = 0;
2953 if (self->db == NULL) {
2954 PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed");
2955 if (t) {
2956 PyErr_SetObject(DBError, t);
2957 Py_DECREF(t);
2959 return -1;
2962 if (!make_key_dbt(self, keyobj, &key, NULL))
2963 return -1;
2965 if (dataobj != NULL) {
2966 if (!make_dbt(dataobj, &data))
2967 retval = -1;
2968 else {
2969 if (self->setflags & (DB_DUP|DB_DUPSORT))
2970 /* dictionaries shouldn't have duplicate keys */
2971 flags = DB_NOOVERWRITE;
2972 retval = _DB_put(self, NULL, &key, &data, flags);
2974 if ((retval == -1) && (self->setflags & (DB_DUP|DB_DUPSORT))) {
2975 /* try deleting any old record that matches and then PUT it
2976 * again... */
2977 _DB_delete(self, NULL, &key, 0);
2978 PyErr_Clear();
2979 retval = _DB_put(self, NULL, &key, &data, flags);
2983 else {
2984 /* dataobj == NULL, so delete the key */
2985 retval = _DB_delete(self, NULL, &key, 0);
2987 FREE_DBT(key);
2988 return retval;
2992 static PyObject*
2993 DB_has_key(DBObject* self, PyObject* args)
2995 int err;
2996 PyObject* keyobj;
2997 DBT key, data;
2998 PyObject* txnobj = NULL;
2999 DB_TXN *txn = NULL;
3001 if (!PyArg_UnpackTuple(args,"has_key", 1, 2, &keyobj, &txnobj))
3002 return NULL;
3003 CHECK_DB_NOT_CLOSED(self);
3004 if (!make_key_dbt(self, keyobj, &key, NULL))
3005 return NULL;
3006 if (!checkTxnObj(txnobj, &txn)) {
3007 FREE_DBT(key);
3008 return NULL;
3011 /* This causes DB_BUFFER_SMALL to be returned when the db has the key because
3012 it has a record but can't allocate a buffer for the data. This saves
3013 having to deal with data we won't be using.
3015 CLEAR_DBT(data);
3016 data.flags = DB_DBT_USERMEM;
3018 MYDB_BEGIN_ALLOW_THREADS;
3019 err = self->db->get(self->db, txn, &key, &data, 0);
3020 MYDB_END_ALLOW_THREADS;
3021 FREE_DBT(key);
3023 if (err == DB_BUFFER_SMALL || err == 0) {
3024 return NUMBER_FromLong(1);
3025 } else if (err == DB_NOTFOUND || err == DB_KEYEMPTY) {
3026 return NUMBER_FromLong(0);
3029 makeDBError(err);
3030 return NULL;
3034 #define _KEYS_LIST 1
3035 #define _VALUES_LIST 2
3036 #define _ITEMS_LIST 3
3038 static PyObject*
3039 _DB_make_list(DBObject* self, DB_TXN* txn, int type)
3041 int err, dbtype;
3042 DBT key;
3043 DBT data;
3044 DBC *cursor;
3045 PyObject* list;
3046 PyObject* item = NULL;
3048 CHECK_DB_NOT_CLOSED(self);
3049 CLEAR_DBT(key);
3050 CLEAR_DBT(data);
3052 dbtype = _DB_get_type(self);
3053 if (dbtype == -1)
3054 return NULL;
3056 list = PyList_New(0);
3057 if (list == NULL)
3058 return NULL;
3060 /* get a cursor */
3061 MYDB_BEGIN_ALLOW_THREADS;
3062 err = self->db->cursor(self->db, txn, &cursor, 0);
3063 MYDB_END_ALLOW_THREADS;
3064 if (makeDBError(err)) {
3065 Py_DECREF(list);
3066 return NULL;
3069 while (1) { /* use the cursor to traverse the DB, collecting items */
3070 MYDB_BEGIN_ALLOW_THREADS;
3071 err = _DBC_get(cursor, &key, &data, DB_NEXT);
3072 MYDB_END_ALLOW_THREADS;
3074 if (err) {
3075 /* for any error, break out of the loop */
3076 break;
3079 switch (type) {
3080 case _KEYS_LIST:
3081 switch(dbtype) {
3082 case DB_BTREE:
3083 case DB_HASH:
3084 default:
3085 item = Build_PyString(key.data, key.size);
3086 break;
3087 case DB_RECNO:
3088 case DB_QUEUE:
3089 item = NUMBER_FromLong(*((db_recno_t*)key.data));
3090 break;
3092 break;
3094 case _VALUES_LIST:
3095 item = Build_PyString(data.data, data.size);
3096 break;
3098 case _ITEMS_LIST:
3099 switch(dbtype) {
3100 case DB_BTREE:
3101 case DB_HASH:
3102 default:
3103 item = BuildValue_SS(key.data, key.size, data.data, data.size);
3104 break;
3105 case DB_RECNO:
3106 case DB_QUEUE:
3107 item = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3108 break;
3110 break;
3111 default:
3112 PyErr_Format(PyExc_ValueError, "Unknown key type 0x%x", type);
3113 item = NULL;
3114 break;
3116 if (item == NULL) {
3117 Py_DECREF(list);
3118 list = NULL;
3119 goto done;
3121 if (PyList_Append(list, item)) {
3122 Py_DECREF(list);
3123 Py_DECREF(item);
3124 list = NULL;
3125 goto done;
3127 Py_DECREF(item);
3130 /* DB_NOTFOUND || DB_KEYEMPTY is okay, it means we got to the end */
3131 if (err != DB_NOTFOUND && err != DB_KEYEMPTY && makeDBError(err)) {
3132 Py_DECREF(list);
3133 list = NULL;
3136 done:
3137 MYDB_BEGIN_ALLOW_THREADS;
3138 _DBC_close(cursor);
3139 MYDB_END_ALLOW_THREADS;
3140 return list;
3144 static PyObject*
3145 DB_keys(DBObject* self, PyObject* args)
3147 PyObject* txnobj = NULL;
3148 DB_TXN *txn = NULL;
3150 if (!PyArg_UnpackTuple(args, "keys", 0, 1, &txnobj))
3151 return NULL;
3152 if (!checkTxnObj(txnobj, &txn))
3153 return NULL;
3154 return _DB_make_list(self, txn, _KEYS_LIST);
3158 static PyObject*
3159 DB_items(DBObject* self, PyObject* args)
3161 PyObject* txnobj = NULL;
3162 DB_TXN *txn = NULL;
3164 if (!PyArg_UnpackTuple(args, "items", 0, 1, &txnobj))
3165 return NULL;
3166 if (!checkTxnObj(txnobj, &txn))
3167 return NULL;
3168 return _DB_make_list(self, txn, _ITEMS_LIST);
3172 static PyObject*
3173 DB_values(DBObject* self, PyObject* args)
3175 PyObject* txnobj = NULL;
3176 DB_TXN *txn = NULL;
3178 if (!PyArg_UnpackTuple(args, "values", 0, 1, &txnobj))
3179 return NULL;
3180 if (!checkTxnObj(txnobj, &txn))
3181 return NULL;
3182 return _DB_make_list(self, txn, _VALUES_LIST);
3185 /* --------------------------------------------------------------------- */
3186 /* DBCursor methods */
3189 static PyObject*
3190 DBC_close_internal(DBCursorObject* self)
3192 int err = 0;
3194 if (self->dbc != NULL) {
3195 EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
3196 if (self->txn) {
3197 EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
3198 self->txn=NULL;
3201 MYDB_BEGIN_ALLOW_THREADS;
3202 err = _DBC_close(self->dbc);
3203 MYDB_END_ALLOW_THREADS;
3204 self->dbc = NULL;
3206 RETURN_IF_ERR();
3207 RETURN_NONE();
3210 static PyObject*
3211 DBC_close(DBCursorObject* self)
3213 return DBC_close_internal(self);
3217 static PyObject*
3218 DBC_count(DBCursorObject* self, PyObject* args)
3220 int err = 0;
3221 db_recno_t count;
3222 int flags = 0;
3224 if (!PyArg_ParseTuple(args, "|i:count", &flags))
3225 return NULL;
3227 CHECK_CURSOR_NOT_CLOSED(self);
3229 MYDB_BEGIN_ALLOW_THREADS;
3230 err = _DBC_count(self->dbc, &count, flags);
3231 MYDB_END_ALLOW_THREADS;
3232 RETURN_IF_ERR();
3234 return NUMBER_FromLong(count);
3238 static PyObject*
3239 DBC_current(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3241 return _DBCursor_get(self,DB_CURRENT,args,kwargs,"|iii:current");
3245 static PyObject*
3246 DBC_delete(DBCursorObject* self, PyObject* args)
3248 int err, flags=0;
3250 if (!PyArg_ParseTuple(args, "|i:delete", &flags))
3251 return NULL;
3253 CHECK_CURSOR_NOT_CLOSED(self);
3255 MYDB_BEGIN_ALLOW_THREADS;
3256 err = _DBC_del(self->dbc, flags);
3257 MYDB_END_ALLOW_THREADS;
3258 RETURN_IF_ERR();
3260 self->mydb->haveStat = 0;
3261 RETURN_NONE();
3265 static PyObject*
3266 DBC_dup(DBCursorObject* self, PyObject* args)
3268 int err, flags =0;
3269 DBC* dbc = NULL;
3271 if (!PyArg_ParseTuple(args, "|i:dup", &flags))
3272 return NULL;
3274 CHECK_CURSOR_NOT_CLOSED(self);
3276 MYDB_BEGIN_ALLOW_THREADS;
3277 err = _DBC_dup(self->dbc, &dbc, flags);
3278 MYDB_END_ALLOW_THREADS;
3279 RETURN_IF_ERR();
3281 return (PyObject*) newDBCursorObject(dbc, self->txn, self->mydb);
3284 static PyObject*
3285 DBC_first(DBCursorObject* self, PyObject* args, PyObject* kwargs)
3287 return _DBCursor_get(self,DB_FIRST,args,kwargs,"|iii:first");
3291 static PyObject*
3292 DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3294 int err, flags=0;
3295 PyObject* keyobj = NULL;
3296 PyObject* dataobj = NULL;
3297 PyObject* retval = NULL;
3298 int dlen = -1;
3299 int doff = -1;
3300 DBT key, data;
3301 static char* kwnames[] = { "key","data", "flags", "dlen", "doff",
3302 NULL };
3304 CLEAR_DBT(key);
3305 CLEAR_DBT(data);
3306 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:get", &kwnames[2],
3307 &flags, &dlen, &doff))
3309 PyErr_Clear();
3310 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:get",
3311 &kwnames[1],
3312 &keyobj, &flags, &dlen, &doff))
3314 PyErr_Clear();
3315 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:get",
3316 kwnames, &keyobj, &dataobj,
3317 &flags, &dlen, &doff))
3319 return NULL;
3324 CHECK_CURSOR_NOT_CLOSED(self);
3326 if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
3327 return NULL;
3328 if ( (dataobj && !make_dbt(dataobj, &data)) ||
3329 (!add_partial_dbt(&data, dlen, doff)) )
3331 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3332 return NULL;
3335 MYDB_BEGIN_ALLOW_THREADS;
3336 err = _DBC_get(self->dbc, &key, &data, flags);
3337 MYDB_END_ALLOW_THREADS;
3339 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3340 && self->mydb->moduleFlags.getReturnsNone) {
3341 Py_INCREF(Py_None);
3342 retval = Py_None;
3344 else if (makeDBError(err)) {
3345 retval = NULL;
3347 else {
3348 switch (_DB_get_type(self->mydb)) {
3349 case -1:
3350 retval = NULL;
3351 break;
3352 case DB_BTREE:
3353 case DB_HASH:
3354 default:
3355 retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3356 break;
3357 case DB_RECNO:
3358 case DB_QUEUE:
3359 retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3360 break;
3363 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3364 return retval;
3367 static PyObject*
3368 DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3370 int err, flags=0;
3371 PyObject* keyobj = NULL;
3372 PyObject* dataobj = NULL;
3373 PyObject* retval = NULL;
3374 int dlen = -1;
3375 int doff = -1;
3376 DBT key, pkey, data;
3377 static char* kwnames_keyOnly[] = { "key", "flags", "dlen", "doff", NULL };
3378 static char* kwnames[] = { "key", "data", "flags", "dlen", "doff", NULL };
3380 CLEAR_DBT(key);
3381 CLEAR_DBT(data);
3382 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:pget", &kwnames[2],
3383 &flags, &dlen, &doff))
3385 PyErr_Clear();
3386 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:pget",
3387 kwnames_keyOnly,
3388 &keyobj, &flags, &dlen, &doff))
3390 PyErr_Clear();
3391 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:pget",
3392 kwnames, &keyobj, &dataobj,
3393 &flags, &dlen, &doff))
3395 return NULL;
3400 CHECK_CURSOR_NOT_CLOSED(self);
3402 if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
3403 return NULL;
3404 if ( (dataobj && !make_dbt(dataobj, &data)) ||
3405 (!add_partial_dbt(&data, dlen, doff)) ) {
3406 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3407 return NULL;
3410 CLEAR_DBT(pkey);
3411 pkey.flags = DB_DBT_MALLOC;
3413 MYDB_BEGIN_ALLOW_THREADS;
3414 err = _DBC_pget(self->dbc, &key, &pkey, &data, flags);
3415 MYDB_END_ALLOW_THREADS;
3417 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3418 && self->mydb->moduleFlags.getReturnsNone) {
3419 Py_INCREF(Py_None);
3420 retval = Py_None;
3422 else if (makeDBError(err)) {
3423 retval = NULL;
3425 else {
3426 PyObject *pkeyObj;
3427 PyObject *dataObj;
3428 dataObj = Build_PyString(data.data, data.size);
3430 if (self->mydb->primaryDBType == DB_RECNO ||
3431 self->mydb->primaryDBType == DB_QUEUE)
3432 pkeyObj = NUMBER_FromLong(*(int *)pkey.data);
3433 else
3434 pkeyObj = Build_PyString(pkey.data, pkey.size);
3436 if (key.data && key.size) /* return key, pkey and data */
3438 PyObject *keyObj;
3439 int type = _DB_get_type(self->mydb);
3440 if (type == DB_RECNO || type == DB_QUEUE)
3441 keyObj = NUMBER_FromLong(*(int *)key.data);
3442 else
3443 keyObj = Build_PyString(key.data, key.size);
3444 #if (PY_VERSION_HEX >= 0x02040000)
3445 retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
3446 #else
3447 retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj);
3448 #endif
3449 Py_DECREF(keyObj);
3450 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3452 else /* return just the pkey and data */
3454 #if (PY_VERSION_HEX >= 0x02040000)
3455 retval = PyTuple_Pack(2, pkeyObj, dataObj);
3456 #else
3457 retval = Py_BuildValue("OO", pkeyObj, dataObj);
3458 #endif
3460 Py_DECREF(dataObj);
3461 Py_DECREF(pkeyObj);
3462 FREE_DBT(pkey);
3464 /* the only time REALLOC should be set is if we used an integer
3465 * key that make_key_dbt malloc'd for us. always free these. */
3466 if (key.flags & DB_DBT_REALLOC) { /* 'make_key_dbt' could do a 'malloc' */
3467 FREE_DBT(key);
3469 return retval;
3473 static PyObject*
3474 DBC_get_recno(DBCursorObject* self)
3476 int err;
3477 db_recno_t recno;
3478 DBT key;
3479 DBT data;
3481 CHECK_CURSOR_NOT_CLOSED(self);
3483 CLEAR_DBT(key);
3484 CLEAR_DBT(data);
3486 MYDB_BEGIN_ALLOW_THREADS;
3487 err = _DBC_get(self->dbc, &key, &data, DB_GET_RECNO);
3488 MYDB_END_ALLOW_THREADS;
3489 RETURN_IF_ERR();
3491 recno = *((db_recno_t*)data.data);
3492 return NUMBER_FromLong(recno);
3496 static PyObject*
3497 DBC_last(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3499 return _DBCursor_get(self,DB_LAST,args,kwargs,"|iii:last");
3503 static PyObject*
3504 DBC_next(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3506 return _DBCursor_get(self,DB_NEXT,args,kwargs,"|iii:next");
3510 static PyObject*
3511 DBC_prev(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3513 return _DBCursor_get(self,DB_PREV,args,kwargs,"|iii:prev");
3517 static PyObject*
3518 DBC_put(DBCursorObject* self, PyObject* args, PyObject* kwargs)
3520 int err, flags = 0;
3521 PyObject* keyobj, *dataobj;
3522 DBT key, data;
3523 static char* kwnames[] = { "key", "data", "flags", "dlen", "doff",
3524 NULL };
3525 int dlen = -1;
3526 int doff = -1;
3528 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iii:put", kwnames,
3529 &keyobj, &dataobj, &flags, &dlen, &doff))
3530 return NULL;
3532 CHECK_CURSOR_NOT_CLOSED(self);
3534 if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
3535 return NULL;
3536 if (!make_dbt(dataobj, &data) ||
3537 !add_partial_dbt(&data, dlen, doff) )
3539 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3540 return NULL;
3543 MYDB_BEGIN_ALLOW_THREADS;
3544 err = _DBC_put(self->dbc, &key, &data, flags);
3545 MYDB_END_ALLOW_THREADS;
3546 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3547 RETURN_IF_ERR();
3548 self->mydb->haveStat = 0;
3549 RETURN_NONE();
3553 static PyObject*
3554 DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3556 int err, flags = 0;
3557 DBT key, data;
3558 PyObject* retval, *keyobj;
3559 static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL };
3560 int dlen = -1;
3561 int doff = -1;
3563 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set", kwnames,
3564 &keyobj, &flags, &dlen, &doff))
3565 return NULL;
3567 CHECK_CURSOR_NOT_CLOSED(self);
3569 if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
3570 return NULL;
3572 CLEAR_DBT(data);
3573 if (!add_partial_dbt(&data, dlen, doff)) {
3574 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3575 return NULL;
3578 MYDB_BEGIN_ALLOW_THREADS;
3579 err = _DBC_get(self->dbc, &key, &data, flags|DB_SET);
3580 MYDB_END_ALLOW_THREADS;
3581 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3582 && self->mydb->moduleFlags.cursorSetReturnsNone) {
3583 Py_INCREF(Py_None);
3584 retval = Py_None;
3586 else if (makeDBError(err)) {
3587 retval = NULL;
3589 else {
3590 switch (_DB_get_type(self->mydb)) {
3591 case -1:
3592 retval = NULL;
3593 break;
3594 case DB_BTREE:
3595 case DB_HASH:
3596 default:
3597 retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3598 break;
3599 case DB_RECNO:
3600 case DB_QUEUE:
3601 retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3602 break;
3604 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3606 /* the only time REALLOC should be set is if we used an integer
3607 * key that make_key_dbt malloc'd for us. always free these. */
3608 if (key.flags & DB_DBT_REALLOC) {
3609 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3612 return retval;
3616 static PyObject*
3617 DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
3619 int err, flags = 0;
3620 DBT key, data;
3621 PyObject* retval, *keyobj;
3622 static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL };
3623 int dlen = -1;
3624 int doff = -1;
3626 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set_range", kwnames,
3627 &keyobj, &flags, &dlen, &doff))
3628 return NULL;
3630 CHECK_CURSOR_NOT_CLOSED(self);
3632 if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
3633 return NULL;
3635 CLEAR_DBT(data);
3636 if (!add_partial_dbt(&data, dlen, doff)) {
3637 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3638 return NULL;
3640 MYDB_BEGIN_ALLOW_THREADS;
3641 err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
3642 MYDB_END_ALLOW_THREADS;
3643 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3644 && self->mydb->moduleFlags.cursorSetReturnsNone) {
3645 Py_INCREF(Py_None);
3646 retval = Py_None;
3648 else if (makeDBError(err)) {
3649 retval = NULL;
3651 else {
3652 switch (_DB_get_type(self->mydb)) {
3653 case -1:
3654 retval = NULL;
3655 break;
3656 case DB_BTREE:
3657 case DB_HASH:
3658 default:
3659 retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3660 break;
3661 case DB_RECNO:
3662 case DB_QUEUE:
3663 retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3664 break;
3666 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3668 /* the only time REALLOC should be set is if we used an integer
3669 * key that make_key_dbt malloc'd for us. always free these. */
3670 if (key.flags & DB_DBT_REALLOC) {
3671 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3674 return retval;
3677 static PyObject*
3678 _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
3679 int flags, unsigned int returnsNone)
3681 int err;
3682 DBT key, data;
3683 PyObject* retval;
3685 /* the caller did this: CHECK_CURSOR_NOT_CLOSED(self); */
3686 if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
3687 return NULL;
3688 if (!make_dbt(dataobj, &data)) {
3689 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3690 return NULL;
3693 MYDB_BEGIN_ALLOW_THREADS;
3694 err = _DBC_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
3695 MYDB_END_ALLOW_THREADS;
3696 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && returnsNone) {
3697 Py_INCREF(Py_None);
3698 retval = Py_None;
3700 else if (makeDBError(err)) {
3701 retval = NULL;
3703 else {
3704 switch (_DB_get_type(self->mydb)) {
3705 case -1:
3706 retval = NULL;
3707 break;
3708 case DB_BTREE:
3709 case DB_HASH:
3710 default:
3711 retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3712 break;
3713 case DB_RECNO:
3714 case DB_QUEUE:
3715 retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
3716 break;
3720 FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
3721 return retval;
3724 static PyObject*
3725 DBC_get_both(DBCursorObject* self, PyObject* args)
3727 int flags=0;
3728 PyObject *keyobj, *dataobj;
3730 if (!PyArg_ParseTuple(args, "OO|i:get_both", &keyobj, &dataobj, &flags))
3731 return NULL;
3733 /* if the cursor is closed, self->mydb may be invalid */
3734 CHECK_CURSOR_NOT_CLOSED(self);
3736 return _DBC_get_set_both(self, keyobj, dataobj, flags,
3737 self->mydb->moduleFlags.getReturnsNone);
3740 /* Return size of entry */
3741 static PyObject*
3742 DBC_get_current_size(DBCursorObject* self)
3744 int err, flags=DB_CURRENT;
3745 PyObject* retval = NULL;
3746 DBT key, data;
3748 CHECK_CURSOR_NOT_CLOSED(self);
3749 CLEAR_DBT(key);
3750 CLEAR_DBT(data);
3752 /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and thus
3753 getting the record size. */
3754 data.flags = DB_DBT_USERMEM;
3755 data.ulen = 0;
3756 MYDB_BEGIN_ALLOW_THREADS;
3757 err = _DBC_get(self->dbc, &key, &data, flags);
3758 MYDB_END_ALLOW_THREADS;
3759 if (err == DB_BUFFER_SMALL || !err) {
3760 /* DB_BUFFER_SMALL means positive size, !err means zero length value */
3761 retval = NUMBER_FromLong((long)data.size);
3762 err = 0;
3765 RETURN_IF_ERR();
3766 return retval;
3769 static PyObject*
3770 DBC_set_both(DBCursorObject* self, PyObject* args)
3772 int flags=0;
3773 PyObject *keyobj, *dataobj;
3775 if (!PyArg_ParseTuple(args, "OO|i:set_both", &keyobj, &dataobj, &flags))
3776 return NULL;
3778 /* if the cursor is closed, self->mydb may be invalid */
3779 CHECK_CURSOR_NOT_CLOSED(self);
3781 return _DBC_get_set_both(self, keyobj, dataobj, flags,
3782 self->mydb->moduleFlags.cursorSetReturnsNone);
3786 static PyObject*
3787 DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3789 int err, irecno, flags=0;
3790 db_recno_t recno;
3791 DBT key, data;
3792 PyObject* retval;
3793 int dlen = -1;
3794 int doff = -1;
3795 static char* kwnames[] = { "recno","flags", "dlen", "doff", NULL };
3797 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii:set_recno", kwnames,
3798 &irecno, &flags, &dlen, &doff))
3799 return NULL;
3801 CHECK_CURSOR_NOT_CLOSED(self);
3803 CLEAR_DBT(key);
3804 recno = (db_recno_t) irecno;
3805 /* use allocated space so DB will be able to realloc room for the real
3806 * key */
3807 key.data = malloc(sizeof(db_recno_t));
3808 if (key.data == NULL) {
3809 PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
3810 return NULL;
3812 key.size = sizeof(db_recno_t);
3813 key.ulen = key.size;
3814 memcpy(key.data, &recno, sizeof(db_recno_t));
3815 key.flags = DB_DBT_REALLOC;
3817 CLEAR_DBT(data);
3818 if (!add_partial_dbt(&data, dlen, doff)) {
3819 FREE_DBT(key);
3820 return NULL;
3823 MYDB_BEGIN_ALLOW_THREADS;
3824 err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
3825 MYDB_END_ALLOW_THREADS;
3826 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3827 && self->mydb->moduleFlags.cursorSetReturnsNone) {
3828 Py_INCREF(Py_None);
3829 retval = Py_None;
3831 else if (makeDBError(err)) {
3832 retval = NULL;
3834 else { /* Can only be used for BTrees, so no need to return int key */
3835 retval = BuildValue_SS(key.data, key.size, data.data, data.size);
3837 FREE_DBT(key);
3839 return retval;
3843 static PyObject*
3844 DBC_consume(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3846 return _DBCursor_get(self,DB_CONSUME,args,kwargs,"|iii:consume");
3850 static PyObject*
3851 DBC_next_dup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3853 return _DBCursor_get(self,DB_NEXT_DUP,args,kwargs,"|iii:next_dup");
3857 static PyObject*
3858 DBC_next_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3860 return _DBCursor_get(self,DB_NEXT_NODUP,args,kwargs,"|iii:next_nodup");
3864 static PyObject*
3865 DBC_prev_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
3867 return _DBCursor_get(self,DB_PREV_NODUP,args,kwargs,"|iii:prev_nodup");
3871 static PyObject*
3872 DBC_join_item(DBCursorObject* self, PyObject* args)
3874 int err, flags=0;
3875 DBT key, data;
3876 PyObject* retval;
3878 if (!PyArg_ParseTuple(args, "|i:join_item", &flags))
3879 return NULL;
3881 CHECK_CURSOR_NOT_CLOSED(self);
3883 CLEAR_DBT(key);
3884 CLEAR_DBT(data);
3886 MYDB_BEGIN_ALLOW_THREADS;
3887 err = _DBC_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
3888 MYDB_END_ALLOW_THREADS;
3889 if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3890 && self->mydb->moduleFlags.getReturnsNone) {
3891 Py_INCREF(Py_None);
3892 retval = Py_None;
3894 else if (makeDBError(err)) {
3895 retval = NULL;
3897 else {
3898 retval = BuildValue_S(key.data, key.size);
3901 return retval;
3906 /* --------------------------------------------------------------------- */
3907 /* DBEnv methods */
3910 static PyObject*
3911 DBEnv_close_internal(DBEnvObject* self, int flags)
3913 PyObject *dummy;
3914 int err;
3916 if (!self->closed) { /* Don't close more than once */
3917 while(self->children_txns) {
3918 dummy=DBTxn_abort_discard_internal(self->children_txns,0);
3919 Py_XDECREF(dummy);
3921 while(self->children_dbs) {
3922 dummy=DB_close_internal(self->children_dbs,0);
3923 Py_XDECREF(dummy);
3926 MYDB_BEGIN_ALLOW_THREADS;
3927 err = self->db_env->close(self->db_env, flags);
3928 MYDB_END_ALLOW_THREADS;
3929 /* after calling DBEnv->close, regardless of error, this DBEnv
3930 * may not be accessed again (Berkeley DB docs). */
3931 self->closed = 1;
3932 self->db_env = NULL;
3933 RETURN_IF_ERR();
3935 RETURN_NONE();
3938 static PyObject*
3939 DBEnv_close(DBEnvObject* self, PyObject* args)
3941 int flags = 0;
3943 if (!PyArg_ParseTuple(args, "|i:close", &flags))
3944 return NULL;
3945 return DBEnv_close_internal(self,flags);
3949 static PyObject*
3950 DBEnv_open(DBEnvObject* self, PyObject* args)
3952 int err, flags=0, mode=0660;
3953 char *db_home;
3955 if (!PyArg_ParseTuple(args, "z|ii:open", &db_home, &flags, &mode))
3956 return NULL;
3958 CHECK_ENV_NOT_CLOSED(self);
3960 MYDB_BEGIN_ALLOW_THREADS;
3961 err = self->db_env->open(self->db_env, db_home, flags, mode);
3962 MYDB_END_ALLOW_THREADS;
3963 RETURN_IF_ERR();
3964 self->closed = 0;
3965 self->flags = flags;
3966 RETURN_NONE();
3970 static PyObject*
3971 DBEnv_remove(DBEnvObject* self, PyObject* args)
3973 int err, flags=0;
3974 char *db_home;
3976 if (!PyArg_ParseTuple(args, "s|i:remove", &db_home, &flags))
3977 return NULL;
3978 CHECK_ENV_NOT_CLOSED(self);
3979 MYDB_BEGIN_ALLOW_THREADS;
3980 err = self->db_env->remove(self->db_env, db_home, flags);
3981 MYDB_END_ALLOW_THREADS;
3982 RETURN_IF_ERR();
3983 RETURN_NONE();
3986 #if (DBVER >= 41)
3987 static PyObject*
3988 DBEnv_dbremove(DBEnvObject* self, PyObject* args, PyObject* kwargs)
3990 int err;
3991 u_int32_t flags=0;
3992 char *file = NULL;
3993 char *database = NULL;
3994 PyObject *txnobj = NULL;
3995 DB_TXN *txn = NULL;
3996 static char* kwnames[] = { "file", "database", "txn", "flags",
3997 NULL };
3999 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zOi:dbremove", kwnames,
4000 &file, &database, &txnobj, &flags)) {
4001 return NULL;
4003 if (!checkTxnObj(txnobj, &txn)) {
4004 return NULL;
4006 CHECK_ENV_NOT_CLOSED(self);
4007 MYDB_BEGIN_ALLOW_THREADS;
4008 err = self->db_env->dbremove(self->db_env, txn, file, database, flags);
4009 MYDB_END_ALLOW_THREADS;
4010 RETURN_IF_ERR();
4011 RETURN_NONE();
4014 static PyObject*
4015 DBEnv_dbrename(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4017 int err;
4018 u_int32_t flags=0;
4019 char *file = NULL;
4020 char *database = NULL;
4021 char *newname = NULL;
4022 PyObject *txnobj = NULL;
4023 DB_TXN *txn = NULL;
4024 static char* kwnames[] = { "file", "database", "newname", "txn",
4025 "flags", NULL };
4027 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "szs|Oi:dbrename", kwnames,
4028 &file, &database, &newname, &txnobj, &flags)) {
4029 return NULL;
4031 if (!checkTxnObj(txnobj, &txn)) {
4032 return NULL;
4034 CHECK_ENV_NOT_CLOSED(self);
4035 MYDB_BEGIN_ALLOW_THREADS;
4036 err = self->db_env->dbrename(self->db_env, txn, file, database, newname,
4037 flags);
4038 MYDB_END_ALLOW_THREADS;
4039 RETURN_IF_ERR();
4040 RETURN_NONE();
4043 static PyObject*
4044 DBEnv_set_encrypt(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4046 int err;
4047 u_int32_t flags=0;
4048 char *passwd = NULL;
4049 static char* kwnames[] = { "passwd", "flags", NULL };
4051 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames,
4052 &passwd, &flags)) {
4053 return NULL;
4056 MYDB_BEGIN_ALLOW_THREADS;
4057 err = self->db_env->set_encrypt(self->db_env, passwd, flags);
4058 MYDB_END_ALLOW_THREADS;
4060 RETURN_IF_ERR();
4061 RETURN_NONE();
4063 #endif /* DBVER >= 41 */
4065 static PyObject*
4066 DBEnv_set_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4068 int err;
4069 u_int32_t flags=0;
4070 u_int32_t timeout = 0;
4071 static char* kwnames[] = { "timeout", "flags", NULL };
4073 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames,
4074 &timeout, &flags)) {
4075 return NULL;
4078 MYDB_BEGIN_ALLOW_THREADS;
4079 err = self->db_env->set_timeout(self->db_env, (db_timeout_t)timeout, flags);
4080 MYDB_END_ALLOW_THREADS;
4082 RETURN_IF_ERR();
4083 RETURN_NONE();
4086 static PyObject*
4087 DBEnv_set_shm_key(DBEnvObject* self, PyObject* args)
4089 int err;
4090 long shm_key = 0;
4092 if (!PyArg_ParseTuple(args, "l:set_shm_key", &shm_key))
4093 return NULL;
4094 CHECK_ENV_NOT_CLOSED(self);
4096 err = self->db_env->set_shm_key(self->db_env, shm_key);
4097 RETURN_IF_ERR();
4098 RETURN_NONE();
4101 static PyObject*
4102 DBEnv_set_cachesize(DBEnvObject* self, PyObject* args)
4104 int err, gbytes=0, bytes=0, ncache=0;
4106 if (!PyArg_ParseTuple(args, "ii|i:set_cachesize",
4107 &gbytes, &bytes, &ncache))
4108 return NULL;
4109 CHECK_ENV_NOT_CLOSED(self);
4111 MYDB_BEGIN_ALLOW_THREADS;
4112 err = self->db_env->set_cachesize(self->db_env, gbytes, bytes, ncache);
4113 MYDB_END_ALLOW_THREADS;
4114 RETURN_IF_ERR();
4115 RETURN_NONE();
4119 static PyObject*
4120 DBEnv_set_flags(DBEnvObject* self, PyObject* args)
4122 int err, flags=0, onoff=0;
4124 if (!PyArg_ParseTuple(args, "ii:set_flags",
4125 &flags, &onoff))
4126 return NULL;
4127 CHECK_ENV_NOT_CLOSED(self);
4129 MYDB_BEGIN_ALLOW_THREADS;
4130 err = self->db_env->set_flags(self->db_env, flags, onoff);
4131 MYDB_END_ALLOW_THREADS;
4132 RETURN_IF_ERR();
4133 RETURN_NONE();
4137 #if (DBVER >= 47)
4138 static PyObject*
4139 DBEnv_log_set_config(DBEnvObject* self, PyObject* args)
4141 int err, flags, onoff;
4143 if (!PyArg_ParseTuple(args, "ii:log_set_config",
4144 &flags, &onoff))
4145 return NULL;
4146 CHECK_ENV_NOT_CLOSED(self);
4148 MYDB_BEGIN_ALLOW_THREADS;
4149 err = self->db_env->log_set_config(self->db_env, flags, onoff);
4150 MYDB_END_ALLOW_THREADS;
4151 RETURN_IF_ERR();
4152 RETURN_NONE();
4154 #endif /* DBVER >= 47 */
4157 static PyObject*
4158 DBEnv_set_data_dir(DBEnvObject* self, PyObject* args)
4160 int err;
4161 char *dir;
4163 if (!PyArg_ParseTuple(args, "s:set_data_dir", &dir))
4164 return NULL;
4165 CHECK_ENV_NOT_CLOSED(self);
4167 MYDB_BEGIN_ALLOW_THREADS;
4168 err = self->db_env->set_data_dir(self->db_env, dir);
4169 MYDB_END_ALLOW_THREADS;
4170 RETURN_IF_ERR();
4171 RETURN_NONE();
4175 static PyObject*
4176 DBEnv_set_lg_bsize(DBEnvObject* self, PyObject* args)
4178 int err, lg_bsize;
4180 if (!PyArg_ParseTuple(args, "i:set_lg_bsize", &lg_bsize))
4181 return NULL;
4182 CHECK_ENV_NOT_CLOSED(self);
4184 MYDB_BEGIN_ALLOW_THREADS;
4185 err = self->db_env->set_lg_bsize(self->db_env, lg_bsize);
4186 MYDB_END_ALLOW_THREADS;
4187 RETURN_IF_ERR();
4188 RETURN_NONE();
4192 static PyObject*
4193 DBEnv_set_lg_dir(DBEnvObject* self, PyObject* args)
4195 int err;
4196 char *dir;
4198 if (!PyArg_ParseTuple(args, "s:set_lg_dir", &dir))
4199 return NULL;
4200 CHECK_ENV_NOT_CLOSED(self);
4202 MYDB_BEGIN_ALLOW_THREADS;
4203 err = self->db_env->set_lg_dir(self->db_env, dir);
4204 MYDB_END_ALLOW_THREADS;
4205 RETURN_IF_ERR();
4206 RETURN_NONE();
4209 static PyObject*
4210 DBEnv_set_lg_max(DBEnvObject* self, PyObject* args)
4212 int err, lg_max;
4214 if (!PyArg_ParseTuple(args, "i:set_lg_max", &lg_max))
4215 return NULL;
4216 CHECK_ENV_NOT_CLOSED(self);
4218 MYDB_BEGIN_ALLOW_THREADS;
4219 err = self->db_env->set_lg_max(self->db_env, lg_max);
4220 MYDB_END_ALLOW_THREADS;
4221 RETURN_IF_ERR();
4222 RETURN_NONE();
4225 #if (DBVER >= 42)
4226 static PyObject*
4227 DBEnv_get_lg_max(DBEnvObject* self)
4229 int err;
4230 u_int32_t lg_max;
4232 CHECK_ENV_NOT_CLOSED(self);
4234 MYDB_BEGIN_ALLOW_THREADS;
4235 err = self->db_env->get_lg_max(self->db_env, &lg_max);
4236 MYDB_END_ALLOW_THREADS;
4237 RETURN_IF_ERR();
4238 return NUMBER_FromLong(lg_max);
4240 #endif
4243 static PyObject*
4244 DBEnv_set_lg_regionmax(DBEnvObject* self, PyObject* args)
4246 int err, lg_max;
4248 if (!PyArg_ParseTuple(args, "i:set_lg_regionmax", &lg_max))
4249 return NULL;
4250 CHECK_ENV_NOT_CLOSED(self);
4252 MYDB_BEGIN_ALLOW_THREADS;
4253 err = self->db_env->set_lg_regionmax(self->db_env, lg_max);
4254 MYDB_END_ALLOW_THREADS;
4255 RETURN_IF_ERR();
4256 RETURN_NONE();
4260 static PyObject*
4261 DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args)
4263 int err, lk_detect;
4265 if (!PyArg_ParseTuple(args, "i:set_lk_detect", &lk_detect))
4266 return NULL;
4267 CHECK_ENV_NOT_CLOSED(self);
4269 MYDB_BEGIN_ALLOW_THREADS;
4270 err = self->db_env->set_lk_detect(self->db_env, lk_detect);
4271 MYDB_END_ALLOW_THREADS;
4272 RETURN_IF_ERR();
4273 RETURN_NONE();
4277 #if (DBVER < 45)
4278 static PyObject*
4279 DBEnv_set_lk_max(DBEnvObject* self, PyObject* args)
4281 int err, max;
4283 if (!PyArg_ParseTuple(args, "i:set_lk_max", &max))
4284 return NULL;
4285 CHECK_ENV_NOT_CLOSED(self);
4287 MYDB_BEGIN_ALLOW_THREADS;
4288 err = self->db_env->set_lk_max(self->db_env, max);
4289 MYDB_END_ALLOW_THREADS;
4290 RETURN_IF_ERR();
4291 RETURN_NONE();
4293 #endif
4297 static PyObject*
4298 DBEnv_set_lk_max_locks(DBEnvObject* self, PyObject* args)
4300 int err, max;
4302 if (!PyArg_ParseTuple(args, "i:set_lk_max_locks", &max))
4303 return NULL;
4304 CHECK_ENV_NOT_CLOSED(self);
4306 MYDB_BEGIN_ALLOW_THREADS;
4307 err = self->db_env->set_lk_max_locks(self->db_env, max);
4308 MYDB_END_ALLOW_THREADS;
4309 RETURN_IF_ERR();
4310 RETURN_NONE();
4314 static PyObject*
4315 DBEnv_set_lk_max_lockers(DBEnvObject* self, PyObject* args)
4317 int err, max;
4319 if (!PyArg_ParseTuple(args, "i:set_lk_max_lockers", &max))
4320 return NULL;
4321 CHECK_ENV_NOT_CLOSED(self);
4323 MYDB_BEGIN_ALLOW_THREADS;
4324 err = self->db_env->set_lk_max_lockers(self->db_env, max);
4325 MYDB_END_ALLOW_THREADS;
4326 RETURN_IF_ERR();
4327 RETURN_NONE();
4331 static PyObject*
4332 DBEnv_set_lk_max_objects(DBEnvObject* self, PyObject* args)
4334 int err, max;
4336 if (!PyArg_ParseTuple(args, "i:set_lk_max_objects", &max))
4337 return NULL;
4338 CHECK_ENV_NOT_CLOSED(self);
4340 MYDB_BEGIN_ALLOW_THREADS;
4341 err = self->db_env->set_lk_max_objects(self->db_env, max);
4342 MYDB_END_ALLOW_THREADS;
4343 RETURN_IF_ERR();
4344 RETURN_NONE();
4348 static PyObject*
4349 DBEnv_set_mp_mmapsize(DBEnvObject* self, PyObject* args)
4351 int err, mp_mmapsize;
4353 if (!PyArg_ParseTuple(args, "i:set_mp_mmapsize", &mp_mmapsize))
4354 return NULL;
4355 CHECK_ENV_NOT_CLOSED(self);
4357 MYDB_BEGIN_ALLOW_THREADS;
4358 err = self->db_env->set_mp_mmapsize(self->db_env, mp_mmapsize);
4359 MYDB_END_ALLOW_THREADS;
4360 RETURN_IF_ERR();
4361 RETURN_NONE();
4365 static PyObject*
4366 DBEnv_set_tmp_dir(DBEnvObject* self, PyObject* args)
4368 int err;
4369 char *dir;
4371 if (!PyArg_ParseTuple(args, "s:set_tmp_dir", &dir))
4372 return NULL;
4373 CHECK_ENV_NOT_CLOSED(self);
4375 MYDB_BEGIN_ALLOW_THREADS;
4376 err = self->db_env->set_tmp_dir(self->db_env, dir);
4377 MYDB_END_ALLOW_THREADS;
4378 RETURN_IF_ERR();
4379 RETURN_NONE();
4383 static PyObject*
4384 DBEnv_txn_recover(DBEnvObject* self)
4386 int flags = DB_FIRST;
4387 int err, i;
4388 PyObject *list, *tuple, *gid;
4389 DBTxnObject *txn;
4390 #define PREPLIST_LEN 16
4391 DB_PREPLIST preplist[PREPLIST_LEN];
4392 long retp;
4394 CHECK_ENV_NOT_CLOSED(self);
4396 list=PyList_New(0);
4397 if (!list)
4398 return NULL;
4399 while (!0) {
4400 MYDB_BEGIN_ALLOW_THREADS
4401 err=self->db_env->txn_recover(self->db_env,
4402 preplist, PREPLIST_LEN, &retp, flags);
4403 #undef PREPLIST_LEN
4404 MYDB_END_ALLOW_THREADS
4405 if (err) {
4406 Py_DECREF(list);
4407 RETURN_IF_ERR();
4409 if (!retp) break;
4410 flags=DB_NEXT; /* Prepare for next loop pass */
4411 for (i=0; i<retp; i++) {
4412 gid=PyBytes_FromStringAndSize((char *)(preplist[i].gid),
4413 DB_XIDDATASIZE);
4414 if (!gid) {
4415 Py_DECREF(list);
4416 return NULL;
4418 txn=newDBTxnObject(self, NULL, preplist[i].txn, flags);
4419 if (!txn) {
4420 Py_DECREF(list);
4421 Py_DECREF(gid);
4422 return NULL;
4424 txn->flag_prepare=1; /* Recover state */
4425 tuple=PyTuple_New(2);
4426 if (!tuple) {
4427 Py_DECREF(list);
4428 Py_DECREF(gid);
4429 Py_DECREF(txn);
4430 return NULL;
4432 if (PyTuple_SetItem(tuple, 0, gid)) {
4433 Py_DECREF(list);
4434 Py_DECREF(gid);
4435 Py_DECREF(txn);
4436 Py_DECREF(tuple);
4437 return NULL;
4439 if (PyTuple_SetItem(tuple, 1, (PyObject *)txn)) {
4440 Py_DECREF(list);
4441 Py_DECREF(txn);
4442 Py_DECREF(tuple); /* This delete the "gid" also */
4443 return NULL;
4445 if (PyList_Append(list, tuple)) {
4446 Py_DECREF(list);
4447 Py_DECREF(tuple);/* This delete the "gid" and the "txn" also */
4448 return NULL;
4450 Py_DECREF(tuple);
4453 return list;
4456 static PyObject*
4457 DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4459 int flags = 0;
4460 PyObject* txnobj = NULL;
4461 DB_TXN *txn = NULL;
4462 static char* kwnames[] = { "parent", "flags", NULL };
4464 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:txn_begin", kwnames,
4465 &txnobj, &flags))
4466 return NULL;
4468 if (!checkTxnObj(txnobj, &txn))
4469 return NULL;
4470 CHECK_ENV_NOT_CLOSED(self);
4472 return (PyObject*)newDBTxnObject(self, (DBTxnObject *)txnobj, NULL, flags);
4476 static PyObject*
4477 DBEnv_txn_checkpoint(DBEnvObject* self, PyObject* args)
4479 int err, kbyte=0, min=0, flags=0;
4481 if (!PyArg_ParseTuple(args, "|iii:txn_checkpoint", &kbyte, &min, &flags))
4482 return NULL;
4483 CHECK_ENV_NOT_CLOSED(self);
4485 MYDB_BEGIN_ALLOW_THREADS;
4486 err = self->db_env->txn_checkpoint(self->db_env, kbyte, min, flags);
4487 MYDB_END_ALLOW_THREADS;
4488 RETURN_IF_ERR();
4489 RETURN_NONE();
4493 static PyObject*
4494 DBEnv_set_tx_max(DBEnvObject* self, PyObject* args)
4496 int err, max;
4498 if (!PyArg_ParseTuple(args, "i:set_tx_max", &max))
4499 return NULL;
4500 CHECK_ENV_NOT_CLOSED(self);
4502 err = self->db_env->set_tx_max(self->db_env, max);
4503 RETURN_IF_ERR();
4504 RETURN_NONE();
4508 static PyObject*
4509 DBEnv_set_tx_timestamp(DBEnvObject* self, PyObject* args)
4511 int err;
4512 long stamp;
4513 time_t timestamp;
4515 if (!PyArg_ParseTuple(args, "l:set_tx_timestamp", &stamp))
4516 return NULL;
4517 CHECK_ENV_NOT_CLOSED(self);
4518 timestamp = (time_t)stamp;
4519 err = self->db_env->set_tx_timestamp(self->db_env, &timestamp);
4520 RETURN_IF_ERR();
4521 RETURN_NONE();
4525 static PyObject*
4526 DBEnv_lock_detect(DBEnvObject* self, PyObject* args)
4528 int err, atype, flags=0;
4529 int aborted = 0;
4531 if (!PyArg_ParseTuple(args, "i|i:lock_detect", &atype, &flags))
4532 return NULL;
4533 CHECK_ENV_NOT_CLOSED(self);
4535 MYDB_BEGIN_ALLOW_THREADS;
4536 err = self->db_env->lock_detect(self->db_env, flags, atype, &aborted);
4537 MYDB_END_ALLOW_THREADS;
4538 RETURN_IF_ERR();
4539 return NUMBER_FromLong(aborted);
4543 static PyObject*
4544 DBEnv_lock_get(DBEnvObject* self, PyObject* args)
4546 int flags=0;
4547 int locker, lock_mode;
4548 DBT obj;
4549 PyObject* objobj;
4551 if (!PyArg_ParseTuple(args, "iOi|i:lock_get", &locker, &objobj, &lock_mode, &flags))
4552 return NULL;
4555 if (!make_dbt(objobj, &obj))
4556 return NULL;
4558 return (PyObject*)newDBLockObject(self, locker, &obj, lock_mode, flags);
4562 static PyObject*
4563 DBEnv_lock_id(DBEnvObject* self)
4565 int err;
4566 u_int32_t theID;
4568 CHECK_ENV_NOT_CLOSED(self);
4569 MYDB_BEGIN_ALLOW_THREADS;
4570 err = self->db_env->lock_id(self->db_env, &theID);
4571 MYDB_END_ALLOW_THREADS;
4572 RETURN_IF_ERR();
4574 return NUMBER_FromLong((long)theID);
4577 static PyObject*
4578 DBEnv_lock_id_free(DBEnvObject* self, PyObject* args)
4580 int err;
4581 u_int32_t theID;
4583 if (!PyArg_ParseTuple(args, "I:lock_id_free", &theID))
4584 return NULL;
4586 CHECK_ENV_NOT_CLOSED(self);
4587 MYDB_BEGIN_ALLOW_THREADS;
4588 err = self->db_env->lock_id_free(self->db_env, theID);
4589 MYDB_END_ALLOW_THREADS;
4590 RETURN_IF_ERR();
4591 RETURN_NONE();
4594 static PyObject*
4595 DBEnv_lock_put(DBEnvObject* self, PyObject* args)
4597 int err;
4598 DBLockObject* dblockobj;
4600 if (!PyArg_ParseTuple(args, "O!:lock_put", &DBLock_Type, &dblockobj))
4601 return NULL;
4603 CHECK_ENV_NOT_CLOSED(self);
4604 MYDB_BEGIN_ALLOW_THREADS;
4605 err = self->db_env->lock_put(self->db_env, &dblockobj->lock);
4606 MYDB_END_ALLOW_THREADS;
4607 RETURN_IF_ERR();
4608 RETURN_NONE();
4611 #if (DBVER >= 44)
4612 static PyObject*
4613 DBEnv_lsn_reset(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4615 int err;
4616 char *file;
4617 u_int32_t flags = 0;
4618 static char* kwnames[] = { "file", "flags", NULL};
4620 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|i:lsn_reset", kwnames,
4621 &file, &flags))
4622 return NULL;
4623 CHECK_ENV_NOT_CLOSED(self);
4625 MYDB_BEGIN_ALLOW_THREADS;
4626 err = self->db_env->lsn_reset(self->db_env, file, flags);
4627 MYDB_END_ALLOW_THREADS;
4628 RETURN_IF_ERR();
4629 RETURN_NONE();
4631 #endif /* DBVER >= 4.4 */
4633 static PyObject*
4634 DBEnv_log_stat(DBEnvObject* self, PyObject* args)
4636 int err;
4637 DB_LOG_STAT* statp = NULL;
4638 PyObject* d = NULL;
4639 u_int32_t flags = 0;
4641 if (!PyArg_ParseTuple(args, "|i:log_stat", &flags))
4642 return NULL;
4643 CHECK_ENV_NOT_CLOSED(self);
4645 MYDB_BEGIN_ALLOW_THREADS;
4646 err = self->db_env->log_stat(self->db_env, &statp, flags);
4647 MYDB_END_ALLOW_THREADS;
4648 RETURN_IF_ERR();
4650 /* Turn the stat structure into a dictionary */
4651 d = PyDict_New();
4652 if (d == NULL) {
4653 if (statp)
4654 free(statp);
4655 return NULL;
4658 #define MAKE_ENTRY(name) _addIntToDict(d, #name, statp->st_##name)
4660 MAKE_ENTRY(magic);
4661 MAKE_ENTRY(version);
4662 MAKE_ENTRY(mode);
4663 MAKE_ENTRY(lg_bsize);
4664 #if (DBVER >= 44)
4665 MAKE_ENTRY(lg_size);
4666 MAKE_ENTRY(record);
4667 #endif
4668 #if (DBVER < 41)
4669 MAKE_ENTRY(lg_max);
4670 #endif
4671 MAKE_ENTRY(w_mbytes);
4672 MAKE_ENTRY(w_bytes);
4673 MAKE_ENTRY(wc_mbytes);
4674 MAKE_ENTRY(wc_bytes);
4675 MAKE_ENTRY(wcount);
4676 MAKE_ENTRY(wcount_fill);
4677 #if (DBVER >= 44)
4678 MAKE_ENTRY(rcount);
4679 #endif
4680 MAKE_ENTRY(scount);
4681 MAKE_ENTRY(cur_file);
4682 MAKE_ENTRY(cur_offset);
4683 MAKE_ENTRY(disk_file);
4684 MAKE_ENTRY(disk_offset);
4685 MAKE_ENTRY(maxcommitperflush);
4686 MAKE_ENTRY(mincommitperflush);
4687 MAKE_ENTRY(regsize);
4688 MAKE_ENTRY(region_wait);
4689 MAKE_ENTRY(region_nowait);
4691 #undef MAKE_ENTRY
4692 free(statp);
4693 return d;
4694 } /* DBEnv_log_stat */
4697 static PyObject*
4698 DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
4700 int err;
4701 DB_LOCK_STAT* sp;
4702 PyObject* d = NULL;
4703 u_int32_t flags = 0;
4705 if (!PyArg_ParseTuple(args, "|i:lock_stat", &flags))
4706 return NULL;
4707 CHECK_ENV_NOT_CLOSED(self);
4709 MYDB_BEGIN_ALLOW_THREADS;
4710 err = self->db_env->lock_stat(self->db_env, &sp, flags);
4711 MYDB_END_ALLOW_THREADS;
4712 RETURN_IF_ERR();
4714 /* Turn the stat structure into a dictionary */
4715 d = PyDict_New();
4716 if (d == NULL) {
4717 free(sp);
4718 return NULL;
4721 #define MAKE_ENTRY(name) _addIntToDict(d, #name, sp->st_##name)
4723 #if (DBVER < 41)
4724 MAKE_ENTRY(lastid);
4725 #endif
4726 #if (DBVER >=41)
4727 MAKE_ENTRY(id);
4728 MAKE_ENTRY(cur_maxid);
4729 #endif
4730 MAKE_ENTRY(nmodes);
4731 MAKE_ENTRY(maxlocks);
4732 MAKE_ENTRY(maxlockers);
4733 MAKE_ENTRY(maxobjects);
4734 MAKE_ENTRY(nlocks);
4735 MAKE_ENTRY(maxnlocks);
4736 MAKE_ENTRY(nlockers);
4737 MAKE_ENTRY(maxnlockers);
4738 MAKE_ENTRY(nobjects);
4739 MAKE_ENTRY(maxnobjects);
4740 MAKE_ENTRY(nrequests);
4741 MAKE_ENTRY(nreleases);
4742 #if (DBVER >= 44)
4743 MAKE_ENTRY(nupgrade);
4744 MAKE_ENTRY(ndowngrade);
4745 #endif
4746 #if (DBVER < 44)
4747 MAKE_ENTRY(nnowaits); /* these were renamed in 4.4 */
4748 MAKE_ENTRY(nconflicts);
4749 #else
4750 MAKE_ENTRY(lock_nowait);
4751 MAKE_ENTRY(lock_wait);
4752 #endif
4753 MAKE_ENTRY(ndeadlocks);
4754 #if (DBVER >= 41)
4755 MAKE_ENTRY(locktimeout);
4756 MAKE_ENTRY(txntimeout);
4757 #endif
4758 MAKE_ENTRY(nlocktimeouts);
4759 MAKE_ENTRY(ntxntimeouts);
4760 #if (DBVER >= 46)
4761 MAKE_ENTRY(objs_wait);
4762 MAKE_ENTRY(objs_nowait);
4763 MAKE_ENTRY(lockers_wait);
4764 MAKE_ENTRY(lockers_nowait);
4765 #if (DBVER >= 47)
4766 MAKE_ENTRY(lock_wait);
4767 MAKE_ENTRY(lock_nowait);
4768 #else
4769 MAKE_ENTRY(locks_wait);
4770 MAKE_ENTRY(locks_nowait);
4771 #endif
4772 MAKE_ENTRY(hash_len);
4773 #endif
4774 MAKE_ENTRY(regsize);
4775 MAKE_ENTRY(region_wait);
4776 MAKE_ENTRY(region_nowait);
4778 #undef MAKE_ENTRY
4779 free(sp);
4780 return d;
4783 static PyObject*
4784 DBEnv_log_flush(DBEnvObject* self)
4786 int err;
4788 CHECK_ENV_NOT_CLOSED(self);
4790 MYDB_BEGIN_ALLOW_THREADS
4791 err = self->db_env->log_flush(self->db_env, NULL);
4792 MYDB_END_ALLOW_THREADS
4794 RETURN_IF_ERR();
4795 RETURN_NONE();
4798 static PyObject*
4799 DBEnv_log_archive(DBEnvObject* self, PyObject* args)
4801 int flags=0;
4802 int err;
4803 char **log_list = NULL;
4804 PyObject* list;
4805 PyObject* item = NULL;
4807 if (!PyArg_ParseTuple(args, "|i:log_archive", &flags))
4808 return NULL;
4810 CHECK_ENV_NOT_CLOSED(self);
4811 MYDB_BEGIN_ALLOW_THREADS;
4812 err = self->db_env->log_archive(self->db_env, &log_list, flags);
4813 MYDB_END_ALLOW_THREADS;
4814 RETURN_IF_ERR();
4816 list = PyList_New(0);
4817 if (list == NULL) {
4818 if (log_list)
4819 free(log_list);
4820 return NULL;
4823 if (log_list) {
4824 char **log_list_start;
4825 for (log_list_start = log_list; *log_list != NULL; ++log_list) {
4826 item = PyBytes_FromString (*log_list);
4827 if (item == NULL) {
4828 Py_DECREF(list);
4829 list = NULL;
4830 break;
4832 if (PyList_Append(list, item)) {
4833 Py_DECREF(list);
4834 list = NULL;
4835 Py_DECREF(item);
4836 break;
4838 Py_DECREF(item);
4840 free(log_list_start);
4842 return list;
4846 static PyObject*
4847 DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
4849 int err;
4850 DB_TXN_STAT* sp;
4851 PyObject* d = NULL;
4852 u_int32_t flags=0;
4854 if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
4855 return NULL;
4856 CHECK_ENV_NOT_CLOSED(self);
4858 MYDB_BEGIN_ALLOW_THREADS;
4859 err = self->db_env->txn_stat(self->db_env, &sp, flags);
4860 MYDB_END_ALLOW_THREADS;
4861 RETURN_IF_ERR();
4863 /* Turn the stat structure into a dictionary */
4864 d = PyDict_New();
4865 if (d == NULL) {
4866 free(sp);
4867 return NULL;
4870 #define MAKE_ENTRY(name) _addIntToDict(d, #name, sp->st_##name)
4871 #define MAKE_TIME_T_ENTRY(name) _addTimeTToDict(d, #name, sp->st_##name)
4872 #define MAKE_DB_LSN_ENTRY(name) _addDB_lsnToDict(d, #name, sp->st_##name)
4874 MAKE_DB_LSN_ENTRY(last_ckp);
4875 MAKE_TIME_T_ENTRY(time_ckp);
4876 MAKE_ENTRY(last_txnid);
4877 MAKE_ENTRY(maxtxns);
4878 MAKE_ENTRY(nactive);
4879 MAKE_ENTRY(maxnactive);
4880 #if (DBVER >= 45)
4881 MAKE_ENTRY(nsnapshot);
4882 MAKE_ENTRY(maxnsnapshot);
4883 #endif
4884 MAKE_ENTRY(nbegins);
4885 MAKE_ENTRY(naborts);
4886 MAKE_ENTRY(ncommits);
4887 MAKE_ENTRY(nrestores);
4888 MAKE_ENTRY(regsize);
4889 MAKE_ENTRY(region_wait);
4890 MAKE_ENTRY(region_nowait);
4892 #undef MAKE_DB_LSN_ENTRY
4893 #undef MAKE_ENTRY
4894 #undef MAKE_TIME_T_ENTRY
4895 free(sp);
4896 return d;
4900 static PyObject*
4901 DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
4903 int flags=0;
4904 int oldValue=0;
4906 if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
4907 return NULL;
4908 CHECK_ENV_NOT_CLOSED(self);
4910 if (self->moduleFlags.getReturnsNone)
4911 ++oldValue;
4912 if (self->moduleFlags.cursorSetReturnsNone)
4913 ++oldValue;
4914 self->moduleFlags.getReturnsNone = (flags >= 1);
4915 self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
4916 return NUMBER_FromLong(oldValue);
4919 static PyObject*
4920 DBEnv_get_private(DBEnvObject* self)
4922 /* We can give out the private field even if dbenv is closed */
4923 Py_INCREF(self->private);
4924 return self->private;
4927 static PyObject*
4928 DBEnv_set_private(DBEnvObject* self, PyObject* private)
4930 /* We can set the private field even if dbenv is closed */
4931 Py_DECREF(self->private);
4932 Py_INCREF(private);
4933 self->private = private;
4934 RETURN_NONE();
4938 static PyObject*
4939 DBEnv_set_rpc_server(DBEnvObject* self, PyObject* args, PyObject* kwargs)
4941 int err;
4942 char *host;
4943 long cl_timeout=0, sv_timeout=0;
4945 static char* kwnames[] = { "host", "cl_timeout", "sv_timeout", NULL};
4947 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ll:set_rpc_server", kwnames,
4948 &host, &cl_timeout, &sv_timeout))
4949 return NULL;
4950 CHECK_ENV_NOT_CLOSED(self);
4952 MYDB_BEGIN_ALLOW_THREADS;
4953 err = self->db_env->set_rpc_server(self->db_env, NULL, host, cl_timeout,
4954 sv_timeout, 0);
4955 MYDB_END_ALLOW_THREADS;
4956 RETURN_IF_ERR();
4957 RETURN_NONE();
4960 static PyObject*
4961 DBEnv_set_verbose(DBEnvObject* self, PyObject* args)
4963 int err;
4964 int which, onoff;
4966 if (!PyArg_ParseTuple(args, "ii:set_verbose", &which, &onoff)) {
4967 return NULL;
4969 CHECK_ENV_NOT_CLOSED(self);
4970 MYDB_BEGIN_ALLOW_THREADS;
4971 err = self->db_env->set_verbose(self->db_env, which, onoff);
4972 MYDB_END_ALLOW_THREADS;
4973 RETURN_IF_ERR();
4974 RETURN_NONE();
4977 #if (DBVER >= 42)
4978 static PyObject*
4979 DBEnv_get_verbose(DBEnvObject* self, PyObject* args)
4981 int err;
4982 int which;
4983 int verbose;
4985 if (!PyArg_ParseTuple(args, "i:get_verbose", &which)) {
4986 return NULL;
4988 CHECK_ENV_NOT_CLOSED(self);
4989 MYDB_BEGIN_ALLOW_THREADS;
4990 err = self->db_env->get_verbose(self->db_env, which, &verbose);
4991 MYDB_END_ALLOW_THREADS;
4992 RETURN_IF_ERR();
4993 return PyBool_FromLong(verbose);
4995 #endif
4997 #if (DBVER >= 45)
4998 static void
4999 _dbenv_event_notifyCallback(DB_ENV* db_env, u_int32_t event, void *event_info)
5001 DBEnvObject *dbenv;
5002 PyObject* callback;
5003 PyObject* args;
5004 PyObject* result = NULL;
5006 MYDB_BEGIN_BLOCK_THREADS;
5007 dbenv = (DBEnvObject *)db_env->app_private;
5008 callback = dbenv->event_notifyCallback;
5009 if (callback) {
5010 if (event == DB_EVENT_REP_NEWMASTER) {
5011 args = Py_BuildValue("(Oii)", dbenv, event, *((int *)event_info));
5012 } else {
5013 args = Py_BuildValue("(OiO)", dbenv, event, Py_None);
5015 if (args) {
5016 result = PyEval_CallObject(callback, args);
5018 if ((!args) || (!result)) {
5019 PyErr_Print();
5021 Py_XDECREF(args);
5022 Py_XDECREF(result);
5024 MYDB_END_BLOCK_THREADS;
5026 #endif
5028 #if (DBVER >= 45)
5029 static PyObject*
5030 DBEnv_set_event_notify(DBEnvObject* self, PyObject* notifyFunc)
5032 int err;
5034 CHECK_ENV_NOT_CLOSED(self);
5036 if (!PyCallable_Check(notifyFunc)) {
5037 makeTypeError("Callable", notifyFunc);
5038 return NULL;
5041 Py_XDECREF(self->event_notifyCallback);
5042 Py_INCREF(notifyFunc);
5043 self->event_notifyCallback = notifyFunc;
5045 /* This is to workaround a problem with un-initialized threads (see
5046 comment in DB_associate) */
5047 #ifdef WITH_THREAD
5048 PyEval_InitThreads();
5049 #endif
5051 MYDB_BEGIN_ALLOW_THREADS;
5052 err = self->db_env->set_event_notify(self->db_env, _dbenv_event_notifyCallback);
5053 MYDB_END_ALLOW_THREADS;
5055 if (err) {
5056 Py_DECREF(notifyFunc);
5057 self->event_notifyCallback = NULL;
5060 RETURN_IF_ERR();
5061 RETURN_NONE();
5063 #endif
5066 /* --------------------------------------------------------------------- */
5067 /* REPLICATION METHODS: Base Replication */
5070 static PyObject*
5071 DBEnv_rep_process_message(DBEnvObject* self, PyObject* args)
5073 int err;
5074 PyObject *control_py, *rec_py;
5075 DBT control, rec;
5076 int envid;
5077 #if (DBVER >= 42)
5078 DB_LSN lsn;
5079 #endif
5081 if (!PyArg_ParseTuple(args, "OOi:rep_process_message", &control_py,
5082 &rec_py, &envid))
5083 return NULL;
5084 CHECK_ENV_NOT_CLOSED(self);
5086 if (!make_dbt(control_py, &control))
5087 return NULL;
5088 if (!make_dbt(rec_py, &rec))
5089 return NULL;
5091 MYDB_BEGIN_ALLOW_THREADS;
5092 #if (DBVER >= 46)
5093 err = self->db_env->rep_process_message(self->db_env, &control, &rec,
5094 envid, &lsn);
5095 #else
5096 #if (DBVER >= 42)
5097 err = self->db_env->rep_process_message(self->db_env, &control, &rec,
5098 &envid, &lsn);
5099 #else
5100 err = self->db_env->rep_process_message(self->db_env, &control, &rec,
5101 &envid);
5102 #endif
5103 #endif
5104 MYDB_END_ALLOW_THREADS;
5105 switch (err) {
5106 case DB_REP_NEWMASTER :
5107 return Py_BuildValue("(iO)", envid, Py_None);
5108 break;
5110 case DB_REP_DUPMASTER :
5111 case DB_REP_HOLDELECTION :
5112 #if (DBVER >= 44)
5113 case DB_REP_IGNORE :
5114 case DB_REP_JOIN_FAILURE :
5115 #endif
5116 return Py_BuildValue("(iO)", err, Py_None);
5117 break;
5118 case DB_REP_NEWSITE :
5119 return Py_BuildValue("(is#)", err, rec.data, rec.size);
5120 break;
5121 #if (DBVER >= 42)
5122 case DB_REP_NOTPERM :
5123 case DB_REP_ISPERM :
5124 return Py_BuildValue("(i(ll))", err, lsn.file, lsn.offset);
5125 break;
5126 #endif
5128 RETURN_IF_ERR();
5129 return Py_BuildValue("(OO)", Py_None, Py_None);
5132 static int
5133 _DBEnv_rep_transportCallback(DB_ENV* db_env, const DBT* control, const DBT* rec,
5134 const DB_LSN *lsn, int envid, u_int32_t flags)
5136 DBEnvObject *dbenv;
5137 PyObject* rep_transport;
5138 PyObject* args;
5139 PyObject* result = NULL;
5140 int ret=0;
5142 MYDB_BEGIN_BLOCK_THREADS;
5143 dbenv = (DBEnvObject *)db_env->app_private;
5144 rep_transport = dbenv->rep_transport;
5146 args = Py_BuildValue(
5147 #if (PY_VERSION_HEX >= 0x02040000)
5148 "(Os#s#(ll)iI)",
5149 #else
5150 "(Os#s#(ll)ii)",
5151 #endif
5152 dbenv,
5153 control->data, control->size,
5154 rec->data, rec->size, lsn->file, lsn->offset, envid, flags);
5155 if (args) {
5156 result = PyEval_CallObject(rep_transport, args);
5159 if ((!args) || (!result)) {
5160 PyErr_Print();
5161 ret = -1;
5163 Py_XDECREF(args);
5164 Py_XDECREF(result);
5165 MYDB_END_BLOCK_THREADS;
5166 return ret;
5169 #if (DBVER <= 41)
5170 static int
5171 _DBEnv_rep_transportCallbackOLD(DB_ENV* db_env, const DBT* control, const DBT* rec,
5172 int envid, u_int32_t flags)
5174 DB_LSN lsn;
5176 lsn.file = -1; /* Dummy values */
5177 lsn.offset = -1;
5178 return _DBEnv_rep_transportCallback(db_env, control, rec, &lsn, envid,
5179 flags);
5181 #endif
5183 static PyObject*
5184 DBEnv_rep_set_transport(DBEnvObject* self, PyObject* args)
5186 int err;
5187 int envid;
5188 PyObject *rep_transport;
5190 if (!PyArg_ParseTuple(args, "iO:rep_set_transport", &envid, &rep_transport))
5191 return NULL;
5192 CHECK_ENV_NOT_CLOSED(self);
5193 if (!PyCallable_Check(rep_transport)) {
5194 makeTypeError("Callable", rep_transport);
5195 return NULL;
5198 MYDB_BEGIN_ALLOW_THREADS;
5199 #if (DBVER >=45)
5200 err = self->db_env->rep_set_transport(self->db_env, envid,
5201 &_DBEnv_rep_transportCallback);
5202 #else
5203 #if (DBVER >= 42)
5204 err = self->db_env->set_rep_transport(self->db_env, envid,
5205 &_DBEnv_rep_transportCallback);
5206 #else
5207 err = self->db_env->set_rep_transport(self->db_env, envid,
5208 &_DBEnv_rep_transportCallbackOLD);
5209 #endif
5210 #endif
5211 MYDB_END_ALLOW_THREADS;
5212 RETURN_IF_ERR();
5214 Py_DECREF(self->rep_transport);
5215 Py_INCREF(rep_transport);
5216 self->rep_transport = rep_transport;
5217 RETURN_NONE();
5220 #if (DBVER >= 47)
5221 static PyObject*
5222 DBEnv_rep_set_request(DBEnvObject* self, PyObject* args)
5224 int err;
5225 unsigned int minimum, maximum;
5227 if (!PyArg_ParseTuple(args,"II:rep_set_request", &minimum, &maximum))
5228 return NULL;
5229 CHECK_ENV_NOT_CLOSED(self);
5231 MYDB_BEGIN_ALLOW_THREADS;
5232 err = self->db_env->rep_set_request(self->db_env, minimum, maximum);
5233 MYDB_END_ALLOW_THREADS;
5234 RETURN_IF_ERR();
5235 RETURN_NONE();
5238 static PyObject*
5239 DBEnv_rep_get_request(DBEnvObject* self)
5241 int err;
5242 u_int32_t minimum, maximum;
5244 CHECK_ENV_NOT_CLOSED(self);
5245 MYDB_BEGIN_ALLOW_THREADS;
5246 err = self->db_env->rep_get_request(self->db_env, &minimum, &maximum);
5247 MYDB_END_ALLOW_THREADS;
5248 RETURN_IF_ERR();
5249 #if (PY_VERSION_HEX >= 0x02040000)
5250 return Py_BuildValue("II", minimum, maximum);
5251 #else
5252 return Py_BuildValue("ii", minimum, maximum);
5253 #endif
5255 #endif
5257 #if (DBVER >= 45)
5258 static PyObject*
5259 DBEnv_rep_set_limit(DBEnvObject* self, PyObject* args)
5261 int err;
5262 int limit;
5264 if (!PyArg_ParseTuple(args,"i:rep_set_limit", &limit))
5265 return NULL;
5266 CHECK_ENV_NOT_CLOSED(self);
5268 MYDB_BEGIN_ALLOW_THREADS;
5269 err = self->db_env->rep_set_limit(self->db_env, 0, limit);
5270 MYDB_END_ALLOW_THREADS;
5271 RETURN_IF_ERR();
5272 RETURN_NONE();
5275 static PyObject*
5276 DBEnv_rep_get_limit(DBEnvObject* self)
5278 int err;
5279 u_int32_t gbytes, bytes;
5281 CHECK_ENV_NOT_CLOSED(self);
5282 MYDB_BEGIN_ALLOW_THREADS;
5283 err = self->db_env->rep_get_limit(self->db_env, &gbytes, &bytes);
5284 MYDB_END_ALLOW_THREADS;
5285 RETURN_IF_ERR();
5286 return NUMBER_FromLong(bytes);
5288 #endif
5290 #if (DBVER >= 44)
5291 static PyObject*
5292 DBEnv_rep_set_config(DBEnvObject* self, PyObject* args)
5294 int err;
5295 int which;
5296 int onoff;
5298 if (!PyArg_ParseTuple(args,"ii:rep_set_config", &which, &onoff))
5299 return NULL;
5300 CHECK_ENV_NOT_CLOSED(self);
5302 MYDB_BEGIN_ALLOW_THREADS;
5303 err = self->db_env->rep_set_config(self->db_env, which, onoff);
5304 MYDB_END_ALLOW_THREADS;
5305 RETURN_IF_ERR();
5306 RETURN_NONE();
5309 static PyObject*
5310 DBEnv_rep_get_config(DBEnvObject* self, PyObject* args)
5312 int err;
5313 int which;
5314 int onoff;
5316 if (!PyArg_ParseTuple(args, "i:rep_get_config", &which)) {
5317 return NULL;
5319 CHECK_ENV_NOT_CLOSED(self);
5320 MYDB_BEGIN_ALLOW_THREADS;
5321 err = self->db_env->rep_get_config(self->db_env, which, &onoff);
5322 MYDB_END_ALLOW_THREADS;
5323 RETURN_IF_ERR();
5324 return PyBool_FromLong(onoff);
5326 #endif
5328 #if (DBVER >= 46)
5329 static PyObject*
5330 DBEnv_rep_elect(DBEnvObject* self, PyObject* args)
5332 int err;
5333 u_int32_t nsites, nvotes;
5335 if (!PyArg_ParseTuple(args, "II:rep_elect", &nsites, &nvotes)) {
5336 return NULL;
5338 CHECK_ENV_NOT_CLOSED(self);
5339 MYDB_BEGIN_ALLOW_THREADS;
5340 err = self->db_env->rep_elect(self->db_env, nvotes, nvotes, 0);
5341 MYDB_END_ALLOW_THREADS;
5342 RETURN_IF_ERR();
5343 RETURN_NONE();
5345 #endif
5347 static PyObject*
5348 DBEnv_rep_start(DBEnvObject* self, PyObject* args, PyObject* kwargs)
5350 int err;
5351 PyObject *cdata_py = Py_None;
5352 DBT cdata;
5353 int flags;
5354 static char* kwnames[] = {"flags","cdata", NULL};
5356 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
5357 "i|O:rep_start", kwnames, &flags, &cdata_py))
5359 return NULL;
5361 CHECK_ENV_NOT_CLOSED(self);
5363 if (!make_dbt(cdata_py, &cdata))
5364 return NULL;
5366 MYDB_BEGIN_ALLOW_THREADS;
5367 err = self->db_env->rep_start(self->db_env, cdata.size ? &cdata : NULL,
5368 flags);
5369 MYDB_END_ALLOW_THREADS;
5370 RETURN_IF_ERR();
5371 RETURN_NONE();
5374 #if (DBVER >= 44)
5375 static PyObject*
5376 DBEnv_rep_sync(DBEnvObject* self)
5378 int err;
5380 CHECK_ENV_NOT_CLOSED(self);
5381 MYDB_BEGIN_ALLOW_THREADS;
5382 err = self->db_env->rep_sync(self->db_env, 0);
5383 MYDB_END_ALLOW_THREADS;
5384 RETURN_IF_ERR();
5385 RETURN_NONE();
5387 #endif
5390 #if (DBVER >= 45)
5391 static PyObject*
5392 DBEnv_rep_set_nsites(DBEnvObject* self, PyObject* args)
5394 int err;
5395 int nsites;
5397 if (!PyArg_ParseTuple(args, "i:rep_set_nsites", &nsites)) {
5398 return NULL;
5400 CHECK_ENV_NOT_CLOSED(self);
5401 MYDB_BEGIN_ALLOW_THREADS;
5402 err = self->db_env->rep_set_nsites(self->db_env, nsites);
5403 MYDB_END_ALLOW_THREADS;
5404 RETURN_IF_ERR();
5405 RETURN_NONE();
5408 static PyObject*
5409 DBEnv_rep_get_nsites(DBEnvObject* self)
5411 int err;
5412 #if (DBVER >= 47)
5413 u_int32_t nsites;
5414 #else
5415 int nsites;
5416 #endif
5418 CHECK_ENV_NOT_CLOSED(self);
5419 MYDB_BEGIN_ALLOW_THREADS;
5420 err = self->db_env->rep_get_nsites(self->db_env, &nsites);
5421 MYDB_END_ALLOW_THREADS;
5422 RETURN_IF_ERR();
5423 return NUMBER_FromLong(nsites);
5426 static PyObject*
5427 DBEnv_rep_set_priority(DBEnvObject* self, PyObject* args)
5429 int err;
5430 int priority;
5432 if (!PyArg_ParseTuple(args, "i:rep_set_priority", &priority)) {
5433 return NULL;
5435 CHECK_ENV_NOT_CLOSED(self);
5436 MYDB_BEGIN_ALLOW_THREADS;
5437 err = self->db_env->rep_set_priority(self->db_env, priority);
5438 MYDB_END_ALLOW_THREADS;
5439 RETURN_IF_ERR();
5440 RETURN_NONE();
5443 static PyObject*
5444 DBEnv_rep_get_priority(DBEnvObject* self)
5446 int err;
5447 #if (DBVER >= 47)
5448 u_int32_t priority;
5449 #else
5450 int priority;
5451 #endif
5453 CHECK_ENV_NOT_CLOSED(self);
5454 MYDB_BEGIN_ALLOW_THREADS;
5455 err = self->db_env->rep_get_priority(self->db_env, &priority);
5456 MYDB_END_ALLOW_THREADS;
5457 RETURN_IF_ERR();
5458 return NUMBER_FromLong(priority);
5461 static PyObject*
5462 DBEnv_rep_set_timeout(DBEnvObject* self, PyObject* args)
5464 int err;
5465 int which, timeout;
5467 if (!PyArg_ParseTuple(args, "ii:rep_set_timeout", &which, &timeout)) {
5468 return NULL;
5470 CHECK_ENV_NOT_CLOSED(self);
5471 MYDB_BEGIN_ALLOW_THREADS;
5472 err = self->db_env->rep_set_timeout(self->db_env, which, timeout);
5473 MYDB_END_ALLOW_THREADS;
5474 RETURN_IF_ERR();
5475 RETURN_NONE();
5478 static PyObject*
5479 DBEnv_rep_get_timeout(DBEnvObject* self, PyObject* args)
5481 int err;
5482 int which;
5483 u_int32_t timeout;
5485 if (!PyArg_ParseTuple(args, "i:rep_get_timeout", &which)) {
5486 return NULL;
5488 CHECK_ENV_NOT_CLOSED(self);
5489 MYDB_BEGIN_ALLOW_THREADS;
5490 err = self->db_env->rep_get_timeout(self->db_env, which, &timeout);
5491 MYDB_END_ALLOW_THREADS;
5492 RETURN_IF_ERR();
5493 return NUMBER_FromLong(timeout);
5495 #endif
5497 /* --------------------------------------------------------------------- */
5498 /* REPLICATION METHODS: Replication Manager */
5500 #if (DBVER >= 45)
5501 static PyObject*
5502 DBEnv_repmgr_start(DBEnvObject* self, PyObject* args, PyObject*
5503 kwargs)
5505 int err;
5506 int nthreads, flags;
5507 static char* kwnames[] = {"nthreads","flags", NULL};
5509 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
5510 "ii:repmgr_start", kwnames, &nthreads, &flags))
5512 return NULL;
5514 CHECK_ENV_NOT_CLOSED(self);
5515 MYDB_BEGIN_ALLOW_THREADS;
5516 err = self->db_env->repmgr_start(self->db_env, nthreads, flags);
5517 MYDB_END_ALLOW_THREADS;
5518 RETURN_IF_ERR();
5519 RETURN_NONE();
5522 static PyObject*
5523 DBEnv_repmgr_set_local_site(DBEnvObject* self, PyObject* args, PyObject*
5524 kwargs)
5526 int err;
5527 char *host;
5528 int port;
5529 int flags = 0;
5530 static char* kwnames[] = {"host", "port", "flags", NULL};
5532 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
5533 "si|i:repmgr_set_local_site", kwnames, &host, &port, &flags))
5535 return NULL;
5537 CHECK_ENV_NOT_CLOSED(self);
5538 MYDB_BEGIN_ALLOW_THREADS;
5539 err = self->db_env->repmgr_set_local_site(self->db_env, host, port, flags);
5540 MYDB_END_ALLOW_THREADS;
5541 RETURN_IF_ERR();
5542 RETURN_NONE();
5545 static PyObject*
5546 DBEnv_repmgr_add_remote_site(DBEnvObject* self, PyObject* args, PyObject*
5547 kwargs)
5549 int err;
5550 char *host;
5551 int port;
5552 int flags = 0;
5553 int eidp;
5554 static char* kwnames[] = {"host", "port", "flags", NULL};
5556 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
5557 "si|i:repmgr_add_remote_site", kwnames, &host, &port, &flags))
5559 return NULL;
5561 CHECK_ENV_NOT_CLOSED(self);
5562 MYDB_BEGIN_ALLOW_THREADS;
5563 err = self->db_env->repmgr_add_remote_site(self->db_env, host, port, &eidp, flags);
5564 MYDB_END_ALLOW_THREADS;
5565 RETURN_IF_ERR();
5566 return NUMBER_FromLong(eidp);
5569 static PyObject*
5570 DBEnv_repmgr_set_ack_policy(DBEnvObject* self, PyObject* args)
5572 int err;
5573 int ack_policy;
5575 if (!PyArg_ParseTuple(args, "i:repmgr_set_ack_policy", &ack_policy))
5577 return NULL;
5579 CHECK_ENV_NOT_CLOSED(self);
5580 MYDB_BEGIN_ALLOW_THREADS;
5581 err = self->db_env->repmgr_set_ack_policy(self->db_env, ack_policy);
5582 MYDB_END_ALLOW_THREADS;
5583 RETURN_IF_ERR();
5584 RETURN_NONE();
5587 static PyObject*
5588 DBEnv_repmgr_get_ack_policy(DBEnvObject* self)
5590 int err;
5591 int ack_policy;
5593 CHECK_ENV_NOT_CLOSED(self);
5594 MYDB_BEGIN_ALLOW_THREADS;
5595 err = self->db_env->repmgr_get_ack_policy(self->db_env, &ack_policy);
5596 MYDB_END_ALLOW_THREADS;
5597 RETURN_IF_ERR();
5598 return NUMBER_FromLong(ack_policy);
5601 static PyObject*
5602 DBEnv_repmgr_site_list(DBEnvObject* self)
5604 int err;
5605 unsigned int countp;
5606 DB_REPMGR_SITE *listp;
5607 PyObject *stats, *key, *tuple;
5609 CHECK_ENV_NOT_CLOSED(self);
5610 MYDB_BEGIN_ALLOW_THREADS;
5611 err = self->db_env->repmgr_site_list(self->db_env, &countp, &listp);
5612 MYDB_END_ALLOW_THREADS;
5613 RETURN_IF_ERR();
5615 stats=PyDict_New();
5616 if (stats == NULL) {
5617 free(listp);
5618 return NULL;
5621 for(;countp--;) {
5622 key=NUMBER_FromLong(listp[countp].eid);
5623 if(!key) {
5624 Py_DECREF(stats);
5625 free(listp);
5626 return NULL;
5628 #if (PY_VERSION_HEX >= 0x02040000)
5629 tuple=Py_BuildValue("(sII)", listp[countp].host,
5630 listp[countp].port, listp[countp].status);
5631 #else
5632 tuple=Py_BuildValue("(sii)", listp[countp].host,
5633 listp[countp].port, listp[countp].status);
5634 #endif
5635 if(!tuple) {
5636 Py_DECREF(key);
5637 Py_DECREF(stats);
5638 free(listp);
5639 return NULL;
5641 if(PyDict_SetItem(stats, key, tuple)) {
5642 Py_DECREF(key);
5643 Py_DECREF(tuple);
5644 Py_DECREF(stats);
5645 free(listp);
5646 return NULL;
5649 free(listp);
5650 return stats;
5652 #endif
5654 #if (DBVER >= 46)
5655 static PyObject*
5656 DBEnv_repmgr_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
5658 int err;
5659 int flags=0;
5660 static char* kwnames[] = { "flags", NULL };
5662 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat_print",
5663 kwnames, &flags))
5665 return NULL;
5667 CHECK_ENV_NOT_CLOSED(self);
5668 MYDB_BEGIN_ALLOW_THREADS;
5669 err = self->db_env->repmgr_stat_print(self->db_env, flags);
5670 MYDB_END_ALLOW_THREADS;
5671 RETURN_IF_ERR();
5672 RETURN_NONE();
5675 static PyObject*
5676 DBEnv_repmgr_stat(DBEnvObject* self, PyObject* args, PyObject *kwargs)
5678 int err;
5679 int flags=0;
5680 DB_REPMGR_STAT *statp;
5681 PyObject *stats;
5682 static char* kwnames[] = { "flags", NULL };
5684 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat",
5685 kwnames, &flags))
5687 return NULL;
5689 CHECK_ENV_NOT_CLOSED(self);
5690 MYDB_BEGIN_ALLOW_THREADS;
5691 err = self->db_env->repmgr_stat(self->db_env, &statp, flags);
5692 MYDB_END_ALLOW_THREADS;
5693 RETURN_IF_ERR();
5695 stats=PyDict_New();
5696 if (stats == NULL) {
5697 free(statp);
5698 return NULL;
5701 #define MAKE_ENTRY(name) _addIntToDict(stats, #name, statp->st_##name)
5703 MAKE_ENTRY(perm_failed);
5704 MAKE_ENTRY(msgs_queued);
5705 MAKE_ENTRY(msgs_dropped);
5706 MAKE_ENTRY(connection_drop);
5707 MAKE_ENTRY(connect_fail);
5709 #undef MAKE_ENTRY
5711 free(statp);
5712 return stats;
5714 #endif
5717 /* --------------------------------------------------------------------- */
5718 /* DBTxn methods */
5721 static void _close_transaction_cursors(DBTxnObject* txn)
5723 PyObject *dummy;
5725 while(txn->children_cursors) {
5726 PyErr_Warn(PyExc_RuntimeWarning,
5727 "Must close cursors before resolving a transaction.");
5728 dummy=DBC_close_internal(txn->children_cursors);
5729 Py_XDECREF(dummy);
5733 static void _promote_transaction_dbs_and_sequences(DBTxnObject *txn)
5735 DBObject *db;
5736 #if (DBVER >= 43)
5737 DBSequenceObject *dbs;
5738 #endif
5740 while (txn->children_dbs) {
5741 db=txn->children_dbs;
5742 EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(db);
5743 if (txn->parent_txn) {
5744 INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_dbs,db);
5745 db->txn=txn->parent_txn;
5746 } else {
5747 /* The db is already linked to its environment,
5748 ** so nothing to do.
5750 db->txn=NULL;
5754 #if (DBVER >= 43)
5755 while (txn->children_sequences) {
5756 dbs=txn->children_sequences;
5757 EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(dbs);
5758 if (txn->parent_txn) {
5759 INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_sequences,dbs);
5760 dbs->txn=txn->parent_txn;
5761 } else {
5762 /* The sequence is already linked to its
5763 ** parent db. Nothing to do.
5765 dbs->txn=NULL;
5768 #endif
5772 static PyObject*
5773 DBTxn_commit(DBTxnObject* self, PyObject* args)
5775 int flags=0, err;
5776 DB_TXN *txn;
5778 if (!PyArg_ParseTuple(args, "|i:commit", &flags))
5779 return NULL;
5781 _close_transaction_cursors(self);
5783 if (!self->txn) {
5784 PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
5785 "after txn_commit, txn_abort "
5786 "or txn_discard");
5787 if (t) {
5788 PyErr_SetObject(DBError, t);
5789 Py_DECREF(t);
5791 return NULL;
5793 self->flag_prepare=0;
5794 txn = self->txn;
5795 self->txn = NULL; /* this DB_TXN is no longer valid after this call */
5797 EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
5799 MYDB_BEGIN_ALLOW_THREADS;
5800 err = txn->commit(txn, flags);
5801 MYDB_END_ALLOW_THREADS;
5803 _promote_transaction_dbs_and_sequences(self);
5805 RETURN_IF_ERR();
5806 RETURN_NONE();
5809 static PyObject*
5810 DBTxn_prepare(DBTxnObject* self, PyObject* args)
5812 int err;
5813 char* gid=NULL;
5814 int gid_size=0;
5816 if (!PyArg_ParseTuple(args, "s#:prepare", &gid, &gid_size))
5817 return NULL;
5819 if (gid_size != DB_XIDDATASIZE) {
5820 PyErr_SetString(PyExc_TypeError,
5821 "gid must be DB_XIDDATASIZE bytes long");
5822 return NULL;
5825 if (!self->txn) {
5826 PyObject *t = Py_BuildValue("(is)", 0,"DBTxn must not be used "
5827 "after txn_commit, txn_abort "
5828 "or txn_discard");
5829 if (t) {
5830 PyErr_SetObject(DBError, t);
5831 Py_DECREF(t);
5833 return NULL;
5835 self->flag_prepare=1; /* Prepare state */
5836 MYDB_BEGIN_ALLOW_THREADS;
5837 err = self->txn->prepare(self->txn, (u_int8_t*)gid);
5838 MYDB_END_ALLOW_THREADS;
5839 RETURN_IF_ERR();
5840 RETURN_NONE();
5844 static PyObject*
5845 DBTxn_abort_discard_internal(DBTxnObject* self, int discard)
5847 PyObject *dummy;
5848 int err=0;
5849 DB_TXN *txn;
5851 if (!self->txn) {
5852 PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
5853 "after txn_commit, txn_abort "
5854 "or txn_discard");
5855 if (t) {
5856 PyErr_SetObject(DBError, t);
5857 Py_DECREF(t);
5859 return NULL;
5861 txn = self->txn;
5862 self->txn = NULL; /* this DB_TXN is no longer valid after this call */
5864 _close_transaction_cursors(self);
5865 #if (DBVER >= 43)
5866 while (self->children_sequences) {
5867 dummy=DBSequence_close_internal(self->children_sequences,0,0);
5868 Py_XDECREF(dummy);
5870 #endif
5871 while (self->children_dbs) {
5872 dummy=DB_close_internal(self->children_dbs,0);
5873 Py_XDECREF(dummy);
5876 EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
5878 MYDB_BEGIN_ALLOW_THREADS;
5879 if (discard) {
5880 assert(!self->flag_prepare);
5881 err = txn->discard(txn,0);
5882 } else {
5884 ** If the transaction is in the "prepare" or "recover" state,
5885 ** we better do not implicitly abort it.
5887 if (!self->flag_prepare) {
5888 err = txn->abort(txn);
5891 MYDB_END_ALLOW_THREADS;
5892 RETURN_IF_ERR();
5893 RETURN_NONE();
5896 static PyObject*
5897 DBTxn_abort(DBTxnObject* self)
5899 self->flag_prepare=0;
5900 _close_transaction_cursors(self);
5902 return DBTxn_abort_discard_internal(self,0);
5905 static PyObject*
5906 DBTxn_discard(DBTxnObject* self)
5908 self->flag_prepare=0;
5909 _close_transaction_cursors(self);
5911 return DBTxn_abort_discard_internal(self,1);
5915 static PyObject*
5916 DBTxn_id(DBTxnObject* self)
5918 int id;
5920 if (!self->txn) {
5921 PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
5922 "after txn_commit, txn_abort "
5923 "or txn_discard");
5924 if (t) {
5925 PyErr_SetObject(DBError, t);
5926 Py_DECREF(t);
5928 return NULL;
5930 MYDB_BEGIN_ALLOW_THREADS;
5931 id = self->txn->id(self->txn);
5932 MYDB_END_ALLOW_THREADS;
5933 return NUMBER_FromLong(id);
5936 #if (DBVER >= 43)
5937 /* --------------------------------------------------------------------- */
5938 /* DBSequence methods */
5941 static PyObject*
5942 DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close)
5944 int err=0;
5946 if (self->sequence!=NULL) {
5947 EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
5948 if (self->txn) {
5949 EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
5950 self->txn=NULL;
5953 if (!do_not_close) {
5954 MYDB_BEGIN_ALLOW_THREADS
5955 err = self->sequence->close(self->sequence, flags);
5956 MYDB_END_ALLOW_THREADS
5958 self->sequence = NULL;
5960 RETURN_IF_ERR();
5963 RETURN_NONE();
5966 static PyObject*
5967 DBSequence_close(DBSequenceObject* self, PyObject* args)
5969 int flags=0;
5970 if (!PyArg_ParseTuple(args,"|i:close", &flags))
5971 return NULL;
5973 return DBSequence_close_internal(self,flags,0);
5976 static PyObject*
5977 DBSequence_get(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
5979 int err, flags = 0;
5980 int delta = 1;
5981 db_seq_t value;
5982 PyObject *txnobj = NULL;
5983 DB_TXN *txn = NULL;
5984 static char* kwnames[] = {"delta", "txn", "flags", NULL };
5985 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iOi:get", kwnames, &delta, &txnobj, &flags))
5986 return NULL;
5987 CHECK_SEQUENCE_NOT_CLOSED(self)
5989 if (!checkTxnObj(txnobj, &txn))
5990 return NULL;
5992 MYDB_BEGIN_ALLOW_THREADS
5993 err = self->sequence->get(self->sequence, txn, delta, &value, flags);
5994 MYDB_END_ALLOW_THREADS
5996 RETURN_IF_ERR();
5997 return PyLong_FromLongLong(value);
6000 static PyObject*
6001 DBSequence_get_dbp(DBSequenceObject* self)
6003 CHECK_SEQUENCE_NOT_CLOSED(self)
6004 Py_INCREF(self->mydb);
6005 return (PyObject* )self->mydb;
6008 static PyObject*
6009 DBSequence_get_key(DBSequenceObject* self)
6011 int err;
6012 DBT key;
6013 PyObject *retval = NULL;
6015 key.flags = DB_DBT_MALLOC;
6016 CHECK_SEQUENCE_NOT_CLOSED(self)
6017 MYDB_BEGIN_ALLOW_THREADS
6018 err = self->sequence->get_key(self->sequence, &key);
6019 MYDB_END_ALLOW_THREADS
6021 if (!err)
6022 retval = Build_PyString(key.data, key.size);
6024 FREE_DBT(key);
6025 RETURN_IF_ERR();
6027 return retval;
6030 static PyObject*
6031 DBSequence_init_value(DBSequenceObject* self, PyObject* args)
6033 int err;
6034 PY_LONG_LONG value;
6035 db_seq_t value2;
6036 if (!PyArg_ParseTuple(args,"L:init_value", &value))
6037 return NULL;
6038 CHECK_SEQUENCE_NOT_CLOSED(self)
6040 value2=value; /* If truncation, compiler should show a warning */
6041 MYDB_BEGIN_ALLOW_THREADS
6042 err = self->sequence->initial_value(self->sequence, value2);
6043 MYDB_END_ALLOW_THREADS
6045 RETURN_IF_ERR();
6047 RETURN_NONE();
6050 static PyObject*
6051 DBSequence_open(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
6053 int err, flags = 0;
6054 PyObject* keyobj;
6055 PyObject *txnobj = NULL;
6056 DB_TXN *txn = NULL;
6057 DBT key;
6059 static char* kwnames[] = {"key", "txn", "flags", NULL };
6060 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:open", kwnames, &keyobj, &txnobj, &flags))
6061 return NULL;
6063 if (!checkTxnObj(txnobj, &txn))
6064 return NULL;
6066 if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
6067 return NULL;
6069 MYDB_BEGIN_ALLOW_THREADS
6070 err = self->sequence->open(self->sequence, txn, &key, flags);
6071 MYDB_END_ALLOW_THREADS
6073 CLEAR_DBT(key);
6074 RETURN_IF_ERR();
6076 if (txn) {
6077 INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_sequences,self);
6078 self->txn=(DBTxnObject *)txnobj;
6081 RETURN_NONE();
6084 static PyObject*
6085 DBSequence_remove(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
6087 PyObject *dummy;
6088 int err, flags = 0;
6089 PyObject *txnobj = NULL;
6090 DB_TXN *txn = NULL;
6092 static char* kwnames[] = {"txn", "flags", NULL };
6093 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:remove", kwnames, &txnobj, &flags))
6094 return NULL;
6096 if (!checkTxnObj(txnobj, &txn))
6097 return NULL;
6099 CHECK_SEQUENCE_NOT_CLOSED(self)
6101 MYDB_BEGIN_ALLOW_THREADS
6102 err = self->sequence->remove(self->sequence, txn, flags);
6103 MYDB_END_ALLOW_THREADS
6105 dummy=DBSequence_close_internal(self,flags,1);
6106 Py_XDECREF(dummy);
6108 RETURN_IF_ERR();
6109 RETURN_NONE();
6112 static PyObject*
6113 DBSequence_set_cachesize(DBSequenceObject* self, PyObject* args)
6115 int err, size;
6116 if (!PyArg_ParseTuple(args,"i:set_cachesize", &size))
6117 return NULL;
6118 CHECK_SEQUENCE_NOT_CLOSED(self)
6120 MYDB_BEGIN_ALLOW_THREADS
6121 err = self->sequence->set_cachesize(self->sequence, size);
6122 MYDB_END_ALLOW_THREADS
6124 RETURN_IF_ERR();
6125 RETURN_NONE();
6128 static PyObject*
6129 DBSequence_get_cachesize(DBSequenceObject* self)
6131 int err, size;
6133 CHECK_SEQUENCE_NOT_CLOSED(self)
6135 MYDB_BEGIN_ALLOW_THREADS
6136 err = self->sequence->get_cachesize(self->sequence, &size);
6137 MYDB_END_ALLOW_THREADS
6139 RETURN_IF_ERR();
6140 return NUMBER_FromLong(size);
6143 static PyObject*
6144 DBSequence_set_flags(DBSequenceObject* self, PyObject* args)
6146 int err, flags = 0;
6147 if (!PyArg_ParseTuple(args,"i:set_flags", &flags))
6148 return NULL;
6149 CHECK_SEQUENCE_NOT_CLOSED(self)
6151 MYDB_BEGIN_ALLOW_THREADS
6152 err = self->sequence->set_flags(self->sequence, flags);
6153 MYDB_END_ALLOW_THREADS
6155 RETURN_IF_ERR();
6156 RETURN_NONE();
6159 static PyObject*
6160 DBSequence_get_flags(DBSequenceObject* self)
6162 unsigned int flags;
6163 int err;
6165 CHECK_SEQUENCE_NOT_CLOSED(self)
6167 MYDB_BEGIN_ALLOW_THREADS
6168 err = self->sequence->get_flags(self->sequence, &flags);
6169 MYDB_END_ALLOW_THREADS
6171 RETURN_IF_ERR();
6172 return NUMBER_FromLong((int)flags);
6175 static PyObject*
6176 DBSequence_set_range(DBSequenceObject* self, PyObject* args)
6178 int err;
6179 PY_LONG_LONG min, max;
6180 db_seq_t min2, max2;
6181 if (!PyArg_ParseTuple(args,"(LL):set_range", &min, &max))
6182 return NULL;
6183 CHECK_SEQUENCE_NOT_CLOSED(self)
6185 min2=min; /* If truncation, compiler should show a warning */
6186 max2=max;
6187 MYDB_BEGIN_ALLOW_THREADS
6188 err = self->sequence->set_range(self->sequence, min2, max2);
6189 MYDB_END_ALLOW_THREADS
6191 RETURN_IF_ERR();
6192 RETURN_NONE();
6195 static PyObject*
6196 DBSequence_get_range(DBSequenceObject* self)
6198 int err;
6199 PY_LONG_LONG min, max;
6200 db_seq_t min2, max2;
6202 CHECK_SEQUENCE_NOT_CLOSED(self)
6204 MYDB_BEGIN_ALLOW_THREADS
6205 err = self->sequence->get_range(self->sequence, &min2, &max2);
6206 MYDB_END_ALLOW_THREADS
6208 RETURN_IF_ERR();
6209 min=min2; /* If truncation, compiler should show a warning */
6210 max=max2;
6211 return Py_BuildValue("(LL)", min, max);
6214 static PyObject*
6215 DBSequence_stat(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
6217 int err, flags = 0;
6218 DB_SEQUENCE_STAT* sp = NULL;
6219 PyObject* dict_stat;
6220 static char* kwnames[] = {"flags", NULL };
6221 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags))
6222 return NULL;
6223 CHECK_SEQUENCE_NOT_CLOSED(self);
6225 MYDB_BEGIN_ALLOW_THREADS;
6226 err = self->sequence->stat(self->sequence, &sp, flags);
6227 MYDB_END_ALLOW_THREADS;
6228 RETURN_IF_ERR();
6230 if ((dict_stat = PyDict_New()) == NULL) {
6231 free(sp);
6232 return NULL;
6236 #define MAKE_INT_ENTRY(name) _addIntToDict(dict_stat, #name, sp->st_##name)
6237 #define MAKE_LONG_LONG_ENTRY(name) _addDb_seq_tToDict(dict_stat, #name, sp->st_##name)
6239 MAKE_INT_ENTRY(wait);
6240 MAKE_INT_ENTRY(nowait);
6241 MAKE_LONG_LONG_ENTRY(current);
6242 MAKE_LONG_LONG_ENTRY(value);
6243 MAKE_LONG_LONG_ENTRY(last_value);
6244 MAKE_LONG_LONG_ENTRY(min);
6245 MAKE_LONG_LONG_ENTRY(max);
6246 MAKE_INT_ENTRY(cache_size);
6247 MAKE_INT_ENTRY(flags);
6249 #undef MAKE_INT_ENTRY
6250 #undef MAKE_LONG_LONG_ENTRY
6252 free(sp);
6253 return dict_stat;
6255 #endif
6258 /* --------------------------------------------------------------------- */
6259 /* Method definition tables and type objects */
6261 static PyMethodDef DB_methods[] = {
6262 {"append", (PyCFunction)DB_append, METH_VARARGS},
6263 {"associate", (PyCFunction)DB_associate, METH_VARARGS|METH_KEYWORDS},
6264 {"close", (PyCFunction)DB_close, METH_VARARGS},
6265 {"consume", (PyCFunction)DB_consume, METH_VARARGS|METH_KEYWORDS},
6266 {"consume_wait", (PyCFunction)DB_consume_wait, METH_VARARGS|METH_KEYWORDS},
6267 {"cursor", (PyCFunction)DB_cursor, METH_VARARGS|METH_KEYWORDS},
6268 {"delete", (PyCFunction)DB_delete, METH_VARARGS|METH_KEYWORDS},
6269 {"fd", (PyCFunction)DB_fd, METH_NOARGS},
6270 {"get", (PyCFunction)DB_get, METH_VARARGS|METH_KEYWORDS},
6271 {"pget", (PyCFunction)DB_pget, METH_VARARGS|METH_KEYWORDS},
6272 {"get_both", (PyCFunction)DB_get_both, METH_VARARGS|METH_KEYWORDS},
6273 {"get_byteswapped", (PyCFunction)DB_get_byteswapped,METH_NOARGS},
6274 {"get_size", (PyCFunction)DB_get_size, METH_VARARGS|METH_KEYWORDS},
6275 {"get_type", (PyCFunction)DB_get_type, METH_NOARGS},
6276 {"join", (PyCFunction)DB_join, METH_VARARGS},
6277 {"key_range", (PyCFunction)DB_key_range, METH_VARARGS|METH_KEYWORDS},
6278 {"has_key", (PyCFunction)DB_has_key, METH_VARARGS},
6279 {"items", (PyCFunction)DB_items, METH_VARARGS},
6280 {"keys", (PyCFunction)DB_keys, METH_VARARGS},
6281 {"open", (PyCFunction)DB_open, METH_VARARGS|METH_KEYWORDS},
6282 {"put", (PyCFunction)DB_put, METH_VARARGS|METH_KEYWORDS},
6283 {"remove", (PyCFunction)DB_remove, METH_VARARGS|METH_KEYWORDS},
6284 {"rename", (PyCFunction)DB_rename, METH_VARARGS},
6285 {"set_bt_minkey", (PyCFunction)DB_set_bt_minkey, METH_VARARGS},
6286 {"set_bt_compare", (PyCFunction)DB_set_bt_compare, METH_O},
6287 {"set_cachesize", (PyCFunction)DB_set_cachesize, METH_VARARGS},
6288 #if (DBVER >= 41)
6289 {"set_encrypt", (PyCFunction)DB_set_encrypt, METH_VARARGS|METH_KEYWORDS},
6290 #endif
6291 {"set_flags", (PyCFunction)DB_set_flags, METH_VARARGS},
6292 {"set_h_ffactor", (PyCFunction)DB_set_h_ffactor, METH_VARARGS},
6293 {"set_h_nelem", (PyCFunction)DB_set_h_nelem, METH_VARARGS},
6294 {"set_lorder", (PyCFunction)DB_set_lorder, METH_VARARGS},
6295 {"set_pagesize", (PyCFunction)DB_set_pagesize, METH_VARARGS},
6296 {"set_re_delim", (PyCFunction)DB_set_re_delim, METH_VARARGS},
6297 {"set_re_len", (PyCFunction)DB_set_re_len, METH_VARARGS},
6298 {"set_re_pad", (PyCFunction)DB_set_re_pad, METH_VARARGS},
6299 {"set_re_source", (PyCFunction)DB_set_re_source, METH_VARARGS},
6300 {"set_q_extentsize",(PyCFunction)DB_set_q_extentsize, METH_VARARGS},
6301 {"set_private", (PyCFunction)DB_set_private, METH_O},
6302 {"get_private", (PyCFunction)DB_get_private, METH_NOARGS},
6303 {"stat", (PyCFunction)DB_stat, METH_VARARGS|METH_KEYWORDS},
6304 {"sync", (PyCFunction)DB_sync, METH_VARARGS},
6305 {"truncate", (PyCFunction)DB_truncate, METH_VARARGS|METH_KEYWORDS},
6306 {"type", (PyCFunction)DB_get_type, METH_NOARGS},
6307 {"upgrade", (PyCFunction)DB_upgrade, METH_VARARGS},
6308 {"values", (PyCFunction)DB_values, METH_VARARGS},
6309 {"verify", (PyCFunction)DB_verify, METH_VARARGS|METH_KEYWORDS},
6310 {"set_get_returns_none",(PyCFunction)DB_set_get_returns_none, METH_VARARGS},
6311 {NULL, NULL} /* sentinel */
6315 static PyMappingMethods DB_mapping = {
6316 DB_length, /*mp_length*/
6317 (binaryfunc)DB_subscript, /*mp_subscript*/
6318 (objobjargproc)DB_ass_sub, /*mp_ass_subscript*/
6322 static PyMethodDef DBCursor_methods[] = {
6323 {"close", (PyCFunction)DBC_close, METH_NOARGS},
6324 {"count", (PyCFunction)DBC_count, METH_VARARGS},
6325 {"current", (PyCFunction)DBC_current, METH_VARARGS|METH_KEYWORDS},
6326 {"delete", (PyCFunction)DBC_delete, METH_VARARGS},
6327 {"dup", (PyCFunction)DBC_dup, METH_VARARGS},
6328 {"first", (PyCFunction)DBC_first, METH_VARARGS|METH_KEYWORDS},
6329 {"get", (PyCFunction)DBC_get, METH_VARARGS|METH_KEYWORDS},
6330 {"pget", (PyCFunction)DBC_pget, METH_VARARGS|METH_KEYWORDS},
6331 {"get_recno", (PyCFunction)DBC_get_recno, METH_NOARGS},
6332 {"last", (PyCFunction)DBC_last, METH_VARARGS|METH_KEYWORDS},
6333 {"next", (PyCFunction)DBC_next, METH_VARARGS|METH_KEYWORDS},
6334 {"prev", (PyCFunction)DBC_prev, METH_VARARGS|METH_KEYWORDS},
6335 {"put", (PyCFunction)DBC_put, METH_VARARGS|METH_KEYWORDS},
6336 {"set", (PyCFunction)DBC_set, METH_VARARGS|METH_KEYWORDS},
6337 {"set_range", (PyCFunction)DBC_set_range, METH_VARARGS|METH_KEYWORDS},
6338 {"get_both", (PyCFunction)DBC_get_both, METH_VARARGS},
6339 {"get_current_size",(PyCFunction)DBC_get_current_size, METH_NOARGS},
6340 {"set_both", (PyCFunction)DBC_set_both, METH_VARARGS},
6341 {"set_recno", (PyCFunction)DBC_set_recno, METH_VARARGS|METH_KEYWORDS},
6342 {"consume", (PyCFunction)DBC_consume, METH_VARARGS|METH_KEYWORDS},
6343 {"next_dup", (PyCFunction)DBC_next_dup, METH_VARARGS|METH_KEYWORDS},
6344 {"next_nodup", (PyCFunction)DBC_next_nodup, METH_VARARGS|METH_KEYWORDS},
6345 {"prev_nodup", (PyCFunction)DBC_prev_nodup, METH_VARARGS|METH_KEYWORDS},
6346 {"join_item", (PyCFunction)DBC_join_item, METH_VARARGS},
6347 {NULL, NULL} /* sentinel */
6351 static PyMethodDef DBEnv_methods[] = {
6352 {"close", (PyCFunction)DBEnv_close, METH_VARARGS},
6353 {"open", (PyCFunction)DBEnv_open, METH_VARARGS},
6354 {"remove", (PyCFunction)DBEnv_remove, METH_VARARGS},
6355 #if (DBVER >= 41)
6356 {"dbremove", (PyCFunction)DBEnv_dbremove, METH_VARARGS|METH_KEYWORDS},
6357 {"dbrename", (PyCFunction)DBEnv_dbrename, METH_VARARGS|METH_KEYWORDS},
6358 {"set_encrypt", (PyCFunction)DBEnv_set_encrypt, METH_VARARGS|METH_KEYWORDS},
6359 #endif
6360 {"set_timeout", (PyCFunction)DBEnv_set_timeout, METH_VARARGS|METH_KEYWORDS},
6361 {"set_shm_key", (PyCFunction)DBEnv_set_shm_key, METH_VARARGS},
6362 {"set_cachesize", (PyCFunction)DBEnv_set_cachesize, METH_VARARGS},
6363 {"set_data_dir", (PyCFunction)DBEnv_set_data_dir, METH_VARARGS},
6364 {"set_flags", (PyCFunction)DBEnv_set_flags, METH_VARARGS},
6365 #if (DBVER >= 47)
6366 {"log_set_config", (PyCFunction)DBEnv_log_set_config, METH_VARARGS},
6367 #endif
6368 {"set_lg_bsize", (PyCFunction)DBEnv_set_lg_bsize, METH_VARARGS},
6369 {"set_lg_dir", (PyCFunction)DBEnv_set_lg_dir, METH_VARARGS},
6370 {"set_lg_max", (PyCFunction)DBEnv_set_lg_max, METH_VARARGS},
6371 #if (DBVER >= 42)
6372 {"get_lg_max", (PyCFunction)DBEnv_get_lg_max, METH_NOARGS},
6373 #endif
6374 {"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS},
6375 {"set_lk_detect", (PyCFunction)DBEnv_set_lk_detect, METH_VARARGS},
6376 #if (DBVER < 45)
6377 {"set_lk_max", (PyCFunction)DBEnv_set_lk_max, METH_VARARGS},
6378 #endif
6379 {"set_lk_max_locks", (PyCFunction)DBEnv_set_lk_max_locks, METH_VARARGS},
6380 {"set_lk_max_lockers", (PyCFunction)DBEnv_set_lk_max_lockers, METH_VARARGS},
6381 {"set_lk_max_objects", (PyCFunction)DBEnv_set_lk_max_objects, METH_VARARGS},
6382 {"set_mp_mmapsize", (PyCFunction)DBEnv_set_mp_mmapsize, METH_VARARGS},
6383 {"set_tmp_dir", (PyCFunction)DBEnv_set_tmp_dir, METH_VARARGS},
6384 {"txn_begin", (PyCFunction)DBEnv_txn_begin, METH_VARARGS|METH_KEYWORDS},
6385 {"txn_checkpoint", (PyCFunction)DBEnv_txn_checkpoint, METH_VARARGS},
6386 {"txn_stat", (PyCFunction)DBEnv_txn_stat, METH_VARARGS},
6387 {"set_tx_max", (PyCFunction)DBEnv_set_tx_max, METH_VARARGS},
6388 {"set_tx_timestamp", (PyCFunction)DBEnv_set_tx_timestamp, METH_VARARGS},
6389 {"lock_detect", (PyCFunction)DBEnv_lock_detect, METH_VARARGS},
6390 {"lock_get", (PyCFunction)DBEnv_lock_get, METH_VARARGS},
6391 {"lock_id", (PyCFunction)DBEnv_lock_id, METH_NOARGS},
6392 {"lock_id_free", (PyCFunction)DBEnv_lock_id_free, METH_VARARGS},
6393 {"lock_put", (PyCFunction)DBEnv_lock_put, METH_VARARGS},
6394 {"lock_stat", (PyCFunction)DBEnv_lock_stat, METH_VARARGS},
6395 {"log_archive", (PyCFunction)DBEnv_log_archive, METH_VARARGS},
6396 {"log_flush", (PyCFunction)DBEnv_log_flush, METH_NOARGS},
6397 {"log_stat", (PyCFunction)DBEnv_log_stat, METH_VARARGS},
6398 #if (DBVER >= 44)
6399 {"lsn_reset", (PyCFunction)DBEnv_lsn_reset, METH_VARARGS|METH_KEYWORDS},
6400 #endif
6401 {"set_get_returns_none",(PyCFunction)DBEnv_set_get_returns_none, METH_VARARGS},
6402 {"txn_recover", (PyCFunction)DBEnv_txn_recover, METH_NOARGS},
6403 {"set_rpc_server", (PyCFunction)DBEnv_set_rpc_server,
6404 METH_VARARGS||METH_KEYWORDS},
6405 {"set_verbose", (PyCFunction)DBEnv_set_verbose, METH_VARARGS},
6406 #if (DBVER >= 42)
6407 {"get_verbose", (PyCFunction)DBEnv_get_verbose, METH_VARARGS},
6408 #endif
6409 {"set_private", (PyCFunction)DBEnv_set_private, METH_O},
6410 {"get_private", (PyCFunction)DBEnv_get_private, METH_NOARGS},
6411 {"rep_start", (PyCFunction)DBEnv_rep_start,
6412 METH_VARARGS|METH_KEYWORDS},
6413 {"rep_set_transport", (PyCFunction)DBEnv_rep_set_transport, METH_VARARGS},
6414 {"rep_process_message", (PyCFunction)DBEnv_rep_process_message,
6415 METH_VARARGS},
6416 #if (DBVER >= 46)
6417 {"rep_elect", (PyCFunction)DBEnv_rep_elect, METH_VARARGS},
6418 #endif
6419 #if (DBVER >= 44)
6420 {"rep_set_config", (PyCFunction)DBEnv_rep_set_config, METH_VARARGS},
6421 {"rep_get_config", (PyCFunction)DBEnv_rep_get_config, METH_VARARGS},
6422 {"rep_sync", (PyCFunction)DBEnv_rep_sync, METH_NOARGS},
6423 #endif
6424 #if (DBVER >= 45)
6425 {"rep_set_limit", (PyCFunction)DBEnv_rep_set_limit, METH_VARARGS},
6426 {"rep_get_limit", (PyCFunction)DBEnv_rep_get_limit, METH_NOARGS},
6427 #endif
6428 #if (DBVER >= 47)
6429 {"rep_set_request", (PyCFunction)DBEnv_rep_set_request, METH_VARARGS},
6430 {"rep_get_request", (PyCFunction)DBEnv_rep_get_request, METH_NOARGS},
6431 #endif
6432 #if (DBVER >= 45)
6433 {"set_event_notify", (PyCFunction)DBEnv_set_event_notify, METH_O},
6434 #endif
6435 #if (DBVER >= 45)
6436 {"rep_set_nsites", (PyCFunction)DBEnv_rep_set_nsites, METH_VARARGS},
6437 {"rep_get_nsites", (PyCFunction)DBEnv_rep_get_nsites, METH_NOARGS},
6438 {"rep_set_priority", (PyCFunction)DBEnv_rep_set_priority, METH_VARARGS},
6439 {"rep_get_priority", (PyCFunction)DBEnv_rep_get_priority, METH_NOARGS},
6440 {"rep_set_timeout", (PyCFunction)DBEnv_rep_set_timeout, METH_VARARGS},
6441 {"rep_get_timeout", (PyCFunction)DBEnv_rep_get_timeout, METH_VARARGS},
6442 #endif
6443 #if (DBVER >= 45)
6444 {"repmgr_start", (PyCFunction)DBEnv_repmgr_start,
6445 METH_VARARGS|METH_KEYWORDS},
6446 {"repmgr_set_local_site", (PyCFunction)DBEnv_repmgr_set_local_site,
6447 METH_VARARGS|METH_KEYWORDS},
6448 {"repmgr_add_remote_site", (PyCFunction)DBEnv_repmgr_add_remote_site,
6449 METH_VARARGS|METH_KEYWORDS},
6450 {"repmgr_set_ack_policy", (PyCFunction)DBEnv_repmgr_set_ack_policy,
6451 METH_VARARGS},
6452 {"repmgr_get_ack_policy", (PyCFunction)DBEnv_repmgr_get_ack_policy,
6453 METH_NOARGS},
6454 {"repmgr_site_list", (PyCFunction)DBEnv_repmgr_site_list,
6455 METH_NOARGS},
6456 #endif
6457 #if (DBVER >= 46)
6458 {"repmgr_stat", (PyCFunction)DBEnv_repmgr_stat,
6459 METH_VARARGS|METH_KEYWORDS},
6460 {"repmgr_stat_print", (PyCFunction)DBEnv_repmgr_stat_print,
6461 METH_VARARGS|METH_KEYWORDS},
6462 #endif
6463 {NULL, NULL} /* sentinel */
6467 static PyMethodDef DBTxn_methods[] = {
6468 {"commit", (PyCFunction)DBTxn_commit, METH_VARARGS},
6469 {"prepare", (PyCFunction)DBTxn_prepare, METH_VARARGS},
6470 {"discard", (PyCFunction)DBTxn_discard, METH_NOARGS},
6471 {"abort", (PyCFunction)DBTxn_abort, METH_NOARGS},
6472 {"id", (PyCFunction)DBTxn_id, METH_NOARGS},
6473 {NULL, NULL} /* sentinel */
6477 #if (DBVER >= 43)
6478 static PyMethodDef DBSequence_methods[] = {
6479 {"close", (PyCFunction)DBSequence_close, METH_VARARGS},
6480 {"get", (PyCFunction)DBSequence_get, METH_VARARGS|METH_KEYWORDS},
6481 {"get_dbp", (PyCFunction)DBSequence_get_dbp, METH_NOARGS},
6482 {"get_key", (PyCFunction)DBSequence_get_key, METH_NOARGS},
6483 {"init_value", (PyCFunction)DBSequence_init_value, METH_VARARGS},
6484 {"open", (PyCFunction)DBSequence_open, METH_VARARGS|METH_KEYWORDS},
6485 {"remove", (PyCFunction)DBSequence_remove, METH_VARARGS|METH_KEYWORDS},
6486 {"set_cachesize", (PyCFunction)DBSequence_set_cachesize, METH_VARARGS},
6487 {"get_cachesize", (PyCFunction)DBSequence_get_cachesize, METH_NOARGS},
6488 {"set_flags", (PyCFunction)DBSequence_set_flags, METH_VARARGS},
6489 {"get_flags", (PyCFunction)DBSequence_get_flags, METH_NOARGS},
6490 {"set_range", (PyCFunction)DBSequence_set_range, METH_VARARGS},
6491 {"get_range", (PyCFunction)DBSequence_get_range, METH_NOARGS},
6492 {"stat", (PyCFunction)DBSequence_stat, METH_VARARGS|METH_KEYWORDS},
6493 {NULL, NULL} /* sentinel */
6495 #endif
6498 static PyObject*
6499 DBEnv_db_home_get(DBEnvObject* self)
6501 const char *home = NULL;
6503 CHECK_ENV_NOT_CLOSED(self);
6505 #if (DBVER >= 42)
6506 self->db_env->get_home(self->db_env, &home);
6507 #else
6508 home=self->db_env->db_home;
6509 #endif
6511 if (home == NULL) {
6512 RETURN_NONE();
6514 return PyBytes_FromString(home);
6517 static PyGetSetDef DBEnv_getsets[] = {
6518 {"db_home", (getter)DBEnv_db_home_get, NULL,},
6519 {NULL}
6523 statichere PyTypeObject DB_Type = {
6524 #if (PY_VERSION_HEX < 0x03000000)
6525 PyObject_HEAD_INIT(NULL)
6526 0, /*ob_size*/
6527 #else
6528 PyVarObject_HEAD_INIT(NULL, 0)
6529 #endif
6530 "DB", /*tp_name*/
6531 sizeof(DBObject), /*tp_basicsize*/
6532 0, /*tp_itemsize*/
6533 /* methods */
6534 (destructor)DB_dealloc, /*tp_dealloc*/
6535 0, /*tp_print*/
6536 0, /*tp_getattr*/
6537 0, /*tp_setattr*/
6538 0, /*tp_compare*/
6539 0, /*tp_repr*/
6540 0, /*tp_as_number*/
6541 0, /*tp_as_sequence*/
6542 &DB_mapping,/*tp_as_mapping*/
6543 0, /*tp_hash*/
6544 0, /* tp_call */
6545 0, /* tp_str */
6546 0, /* tp_getattro */
6547 0, /* tp_setattro */
6548 0, /* tp_as_buffer */
6549 #if (PY_VERSION_HEX < 0x03000000)
6550 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
6551 #else
6552 Py_TPFLAGS_DEFAULT, /* tp_flags */
6553 #endif
6554 0, /* tp_doc */
6555 0, /* tp_traverse */
6556 0, /* tp_clear */
6557 0, /* tp_richcompare */
6558 offsetof(DBObject, in_weakreflist), /* tp_weaklistoffset */
6559 0, /*tp_iter*/
6560 0, /*tp_iternext*/
6561 DB_methods, /*tp_methods*/
6562 0, /*tp_members*/
6566 statichere PyTypeObject DBCursor_Type = {
6567 #if (PY_VERSION_HEX < 0x03000000)
6568 PyObject_HEAD_INIT(NULL)
6569 0, /*ob_size*/
6570 #else
6571 PyVarObject_HEAD_INIT(NULL, 0)
6572 #endif
6573 "DBCursor", /*tp_name*/
6574 sizeof(DBCursorObject), /*tp_basicsize*/
6575 0, /*tp_itemsize*/
6576 /* methods */
6577 (destructor)DBCursor_dealloc,/*tp_dealloc*/
6578 0, /*tp_print*/
6579 0, /*tp_getattr*/
6580 0, /*tp_setattr*/
6581 0, /*tp_compare*/
6582 0, /*tp_repr*/
6583 0, /*tp_as_number*/
6584 0, /*tp_as_sequence*/
6585 0, /*tp_as_mapping*/
6586 0, /*tp_hash*/
6587 0, /*tp_call*/
6588 0, /*tp_str*/
6589 0, /*tp_getattro*/
6590 0, /*tp_setattro*/
6591 0, /*tp_as_buffer*/
6592 #if (PY_VERSION_HEX < 0x03000000)
6593 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
6594 #else
6595 Py_TPFLAGS_DEFAULT, /* tp_flags */
6596 #endif
6597 0, /* tp_doc */
6598 0, /* tp_traverse */
6599 0, /* tp_clear */
6600 0, /* tp_richcompare */
6601 offsetof(DBCursorObject, in_weakreflist), /* tp_weaklistoffset */
6602 0, /*tp_iter*/
6603 0, /*tp_iternext*/
6604 DBCursor_methods, /*tp_methods*/
6605 0, /*tp_members*/
6609 statichere PyTypeObject DBEnv_Type = {
6610 #if (PY_VERSION_HEX < 0x03000000)
6611 PyObject_HEAD_INIT(NULL)
6612 0, /*ob_size*/
6613 #else
6614 PyVarObject_HEAD_INIT(NULL, 0)
6615 #endif
6616 "DBEnv", /*tp_name*/
6617 sizeof(DBEnvObject), /*tp_basicsize*/
6618 0, /*tp_itemsize*/
6619 /* methods */
6620 (destructor)DBEnv_dealloc, /*tp_dealloc*/
6621 0, /*tp_print*/
6622 0, /*tp_getattr*/
6623 0, /*tp_setattr*/
6624 0, /*tp_compare*/
6625 0, /*tp_repr*/
6626 0, /*tp_as_number*/
6627 0, /*tp_as_sequence*/
6628 0, /*tp_as_mapping*/
6629 0, /*tp_hash*/
6630 0, /* tp_call */
6631 0, /* tp_str */
6632 0, /* tp_getattro */
6633 0, /* tp_setattro */
6634 0, /* tp_as_buffer */
6635 #if (PY_VERSION_HEX < 0x03000000)
6636 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
6637 #else
6638 Py_TPFLAGS_DEFAULT, /* tp_flags */
6639 #endif
6640 0, /* tp_doc */
6641 0, /* tp_traverse */
6642 0, /* tp_clear */
6643 0, /* tp_richcompare */
6644 offsetof(DBEnvObject, in_weakreflist), /* tp_weaklistoffset */
6645 0, /* tp_iter */
6646 0, /* tp_iternext */
6647 DBEnv_methods, /* tp_methods */
6648 0, /* tp_members */
6649 DBEnv_getsets, /* tp_getsets */
6652 statichere PyTypeObject DBTxn_Type = {
6653 #if (PY_VERSION_HEX < 0x03000000)
6654 PyObject_HEAD_INIT(NULL)
6655 0, /*ob_size*/
6656 #else
6657 PyVarObject_HEAD_INIT(NULL, 0)
6658 #endif
6659 "DBTxn", /*tp_name*/
6660 sizeof(DBTxnObject), /*tp_basicsize*/
6661 0, /*tp_itemsize*/
6662 /* methods */
6663 (destructor)DBTxn_dealloc, /*tp_dealloc*/
6664 0, /*tp_print*/
6665 0, /*tp_getattr*/
6666 0, /*tp_setattr*/
6667 0, /*tp_compare*/
6668 0, /*tp_repr*/
6669 0, /*tp_as_number*/
6670 0, /*tp_as_sequence*/
6671 0, /*tp_as_mapping*/
6672 0, /*tp_hash*/
6673 0, /* tp_call */
6674 0, /* tp_str */
6675 0, /* tp_getattro */
6676 0, /* tp_setattro */
6677 0, /* tp_as_buffer */
6678 #if (PY_VERSION_HEX < 0x03000000)
6679 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
6680 #else
6681 Py_TPFLAGS_DEFAULT, /* tp_flags */
6682 #endif
6683 0, /* tp_doc */
6684 0, /* tp_traverse */
6685 0, /* tp_clear */
6686 0, /* tp_richcompare */
6687 offsetof(DBTxnObject, in_weakreflist), /* tp_weaklistoffset */
6688 0, /*tp_iter*/
6689 0, /*tp_iternext*/
6690 DBTxn_methods, /*tp_methods*/
6691 0, /*tp_members*/
6695 statichere PyTypeObject DBLock_Type = {
6696 #if (PY_VERSION_HEX < 0x03000000)
6697 PyObject_HEAD_INIT(NULL)
6698 0, /*ob_size*/
6699 #else
6700 PyVarObject_HEAD_INIT(NULL, 0)
6701 #endif
6702 "DBLock", /*tp_name*/
6703 sizeof(DBLockObject), /*tp_basicsize*/
6704 0, /*tp_itemsize*/
6705 /* methods */
6706 (destructor)DBLock_dealloc, /*tp_dealloc*/
6707 0, /*tp_print*/
6708 0, /*tp_getattr*/
6709 0, /*tp_setattr*/
6710 0, /*tp_compare*/
6711 0, /*tp_repr*/
6712 0, /*tp_as_number*/
6713 0, /*tp_as_sequence*/
6714 0, /*tp_as_mapping*/
6715 0, /*tp_hash*/
6716 0, /* tp_call */
6717 0, /* tp_str */
6718 0, /* tp_getattro */
6719 0, /* tp_setattro */
6720 0, /* tp_as_buffer */
6721 #if (PY_VERSION_HEX < 0x03000000)
6722 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
6723 #else
6724 Py_TPFLAGS_DEFAULT, /* tp_flags */
6725 #endif
6726 0, /* tp_doc */
6727 0, /* tp_traverse */
6728 0, /* tp_clear */
6729 0, /* tp_richcompare */
6730 offsetof(DBLockObject, in_weakreflist), /* tp_weaklistoffset */
6733 #if (DBVER >= 43)
6734 statichere PyTypeObject DBSequence_Type = {
6735 #if (PY_VERSION_HEX < 0x03000000)
6736 PyObject_HEAD_INIT(NULL)
6737 0, /*ob_size*/
6738 #else
6739 PyVarObject_HEAD_INIT(NULL, 0)
6740 #endif
6741 "DBSequence", /*tp_name*/
6742 sizeof(DBSequenceObject), /*tp_basicsize*/
6743 0, /*tp_itemsize*/
6744 /* methods */
6745 (destructor)DBSequence_dealloc, /*tp_dealloc*/
6746 0, /*tp_print*/
6747 0, /*tp_getattr*/
6748 0, /*tp_setattr*/
6749 0, /*tp_compare*/
6750 0, /*tp_repr*/
6751 0, /*tp_as_number*/
6752 0, /*tp_as_sequence*/
6753 0, /*tp_as_mapping*/
6754 0, /*tp_hash*/
6755 0, /* tp_call */
6756 0, /* tp_str */
6757 0, /* tp_getattro */
6758 0, /* tp_setattro */
6759 0, /* tp_as_buffer */
6760 #if (PY_VERSION_HEX < 0x03000000)
6761 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
6762 #else
6763 Py_TPFLAGS_DEFAULT, /* tp_flags */
6764 #endif
6765 0, /* tp_doc */
6766 0, /* tp_traverse */
6767 0, /* tp_clear */
6768 0, /* tp_richcompare */
6769 offsetof(DBSequenceObject, in_weakreflist), /* tp_weaklistoffset */
6770 0, /*tp_iter*/
6771 0, /*tp_iternext*/
6772 DBSequence_methods, /*tp_methods*/
6773 0, /*tp_members*/
6775 #endif
6777 /* --------------------------------------------------------------------- */
6778 /* Module-level functions */
6780 static PyObject*
6781 DB_construct(PyObject* self, PyObject* args, PyObject* kwargs)
6783 PyObject* dbenvobj = NULL;
6784 int flags = 0;
6785 static char* kwnames[] = { "dbEnv", "flags", NULL};
6787 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:DB", kwnames,
6788 &dbenvobj, &flags))
6789 return NULL;
6790 if (dbenvobj == Py_None)
6791 dbenvobj = NULL;
6792 else if (dbenvobj && !DBEnvObject_Check(dbenvobj)) {
6793 makeTypeError("DBEnv", dbenvobj);
6794 return NULL;
6797 return (PyObject* )newDBObject((DBEnvObject*)dbenvobj, flags);
6801 static PyObject*
6802 DBEnv_construct(PyObject* self, PyObject* args)
6804 int flags = 0;
6805 if (!PyArg_ParseTuple(args, "|i:DbEnv", &flags)) return NULL;
6806 return (PyObject* )newDBEnvObject(flags);
6809 #if (DBVER >= 43)
6810 static PyObject*
6811 DBSequence_construct(PyObject* self, PyObject* args, PyObject* kwargs)
6813 PyObject* dbobj;
6814 int flags = 0;
6815 static char* kwnames[] = { "db", "flags", NULL};
6817 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:DBSequence", kwnames, &dbobj, &flags))
6818 return NULL;
6819 if (!DBObject_Check(dbobj)) {
6820 makeTypeError("DB", dbobj);
6821 return NULL;
6823 return (PyObject* )newDBSequenceObject((DBObject*)dbobj, flags);
6825 #endif
6827 static char bsddb_version_doc[] =
6828 "Returns a tuple of major, minor, and patch release numbers of the\n\
6829 underlying DB library.";
6831 static PyObject*
6832 bsddb_version(PyObject* self)
6834 int major, minor, patch;
6836 db_version(&major, &minor, &patch);
6837 return Py_BuildValue("(iii)", major, minor, patch);
6841 /* List of functions defined in the module */
6842 static PyMethodDef bsddb_methods[] = {
6843 {"DB", (PyCFunction)DB_construct, METH_VARARGS | METH_KEYWORDS },
6844 {"DBEnv", (PyCFunction)DBEnv_construct, METH_VARARGS},
6845 #if (DBVER >= 43)
6846 {"DBSequence", (PyCFunction)DBSequence_construct, METH_VARARGS | METH_KEYWORDS },
6847 #endif
6848 {"version", (PyCFunction)bsddb_version, METH_NOARGS, bsddb_version_doc},
6849 {NULL, NULL} /* sentinel */
6853 /* API structure */
6854 static BSDDB_api bsddb_api;
6857 /* --------------------------------------------------------------------- */
6858 /* Module initialization */
6861 /* Convenience routine to export an integer value.
6862 * Errors are silently ignored, for better or for worse...
6864 #define ADD_INT(dict, NAME) _addIntToDict(dict, #NAME, NAME)
6866 #define MODULE_NAME_MAX_LEN 11
6867 static char _bsddbModuleName[MODULE_NAME_MAX_LEN+1] = "_bsddb";
6869 #if (PY_VERSION_HEX >= 0x03000000)
6870 static struct PyModuleDef bsddbmodule = {
6871 PyModuleDef_HEAD_INIT,
6872 _bsddbModuleName, /* Name of module */
6873 NULL, /* module documentation, may be NULL */
6874 -1, /* size of per-interpreter state of the module,
6875 or -1 if the module keeps state in global variables. */
6876 bsddb_methods,
6877 NULL, /* Reload */
6878 NULL, /* Traverse */
6879 NULL, /* Clear */
6880 NULL /* Free */
6882 #endif
6885 #if (PY_VERSION_HEX < 0x03000000)
6886 DL_EXPORT(void) init_bsddb(void)
6887 #else
6888 PyMODINIT_FUNC PyInit__bsddb(void) /* Note the two underscores */
6889 #endif
6891 PyObject* m;
6892 PyObject* d;
6893 PyObject* pybsddb_version_s = PyBytes_FromString( PY_BSDDB_VERSION );
6894 PyObject* db_version_s = PyBytes_FromString( DB_VERSION_STRING );
6895 PyObject* cvsid_s = PyBytes_FromString( rcs_id );
6896 PyObject* py_api;
6898 /* Initialize object types */
6899 if ((PyType_Ready(&DB_Type) < 0)
6900 || (PyType_Ready(&DBCursor_Type) < 0)
6901 || (PyType_Ready(&DBEnv_Type) < 0)
6902 || (PyType_Ready(&DBTxn_Type) < 0)
6903 || (PyType_Ready(&DBLock_Type) < 0)
6904 #if (DBVER >= 43)
6905 || (PyType_Ready(&DBSequence_Type) < 0)
6906 #endif
6908 #if (PY_VERSION_HEX < 0x03000000)
6909 return;
6910 #else
6911 return NULL;
6912 #endif
6915 #if defined(WITH_THREAD) && !defined(MYDB_USE_GILSTATE)
6916 /* Save the current interpreter, so callbacks can do the right thing. */
6917 _db_interpreterState = PyThreadState_GET()->interp;
6918 #endif
6920 /* Create the module and add the functions */
6921 #if (PY_VERSION_HEX < 0x03000000)
6922 m = Py_InitModule(_bsddbModuleName, bsddb_methods);
6923 #else
6924 m=PyModule_Create(&bsddbmodule);
6925 #endif
6926 if (m == NULL) {
6927 #if (PY_VERSION_HEX < 0x03000000)
6928 return;
6929 #else
6930 return NULL;
6931 #endif
6934 /* Add some symbolic constants to the module */
6935 d = PyModule_GetDict(m);
6936 PyDict_SetItemString(d, "__version__", pybsddb_version_s);
6937 PyDict_SetItemString(d, "cvsid", cvsid_s);
6938 PyDict_SetItemString(d, "DB_VERSION_STRING", db_version_s);
6939 Py_DECREF(pybsddb_version_s);
6940 pybsddb_version_s = NULL;
6941 Py_DECREF(cvsid_s);
6942 cvsid_s = NULL;
6943 Py_DECREF(db_version_s);
6944 db_version_s = NULL;
6946 ADD_INT(d, DB_VERSION_MAJOR);
6947 ADD_INT(d, DB_VERSION_MINOR);
6948 ADD_INT(d, DB_VERSION_PATCH);
6950 ADD_INT(d, DB_MAX_PAGES);
6951 ADD_INT(d, DB_MAX_RECORDS);
6953 #if (DBVER >= 42)
6954 ADD_INT(d, DB_RPCCLIENT);
6955 #else
6956 ADD_INT(d, DB_CLIENT);
6957 /* allow apps to be written using DB_RPCCLIENT on older Berkeley DB */
6958 _addIntToDict(d, "DB_RPCCLIENT", DB_CLIENT);
6959 #endif
6960 ADD_INT(d, DB_XA_CREATE);
6962 ADD_INT(d, DB_CREATE);
6963 ADD_INT(d, DB_NOMMAP);
6964 ADD_INT(d, DB_THREAD);
6965 #if (DBVER >= 45)
6966 ADD_INT(d, DB_MULTIVERSION);
6967 #endif
6969 ADD_INT(d, DB_FORCE);
6970 ADD_INT(d, DB_INIT_CDB);
6971 ADD_INT(d, DB_INIT_LOCK);
6972 ADD_INT(d, DB_INIT_LOG);
6973 ADD_INT(d, DB_INIT_MPOOL);
6974 ADD_INT(d, DB_INIT_TXN);
6975 ADD_INT(d, DB_JOINENV);
6977 ADD_INT(d, DB_XIDDATASIZE);
6979 ADD_INT(d, DB_RECOVER);
6980 ADD_INT(d, DB_RECOVER_FATAL);
6981 ADD_INT(d, DB_TXN_NOSYNC);
6982 ADD_INT(d, DB_USE_ENVIRON);
6983 ADD_INT(d, DB_USE_ENVIRON_ROOT);
6985 ADD_INT(d, DB_LOCKDOWN);
6986 ADD_INT(d, DB_PRIVATE);
6987 ADD_INT(d, DB_SYSTEM_MEM);
6989 ADD_INT(d, DB_TXN_SYNC);
6990 ADD_INT(d, DB_TXN_NOWAIT);
6992 ADD_INT(d, DB_EXCL);
6993 ADD_INT(d, DB_FCNTL_LOCKING);
6994 ADD_INT(d, DB_ODDFILESIZE);
6995 ADD_INT(d, DB_RDWRMASTER);
6996 ADD_INT(d, DB_RDONLY);
6997 ADD_INT(d, DB_TRUNCATE);
6998 ADD_INT(d, DB_EXTENT);
6999 ADD_INT(d, DB_CDB_ALLDB);
7000 ADD_INT(d, DB_VERIFY);
7001 ADD_INT(d, DB_UPGRADE);
7003 ADD_INT(d, DB_AGGRESSIVE);
7004 ADD_INT(d, DB_NOORDERCHK);
7005 ADD_INT(d, DB_ORDERCHKONLY);
7006 ADD_INT(d, DB_PR_PAGE);
7008 ADD_INT(d, DB_PR_RECOVERYTEST);
7009 ADD_INT(d, DB_SALVAGE);
7011 ADD_INT(d, DB_LOCK_NORUN);
7012 ADD_INT(d, DB_LOCK_DEFAULT);
7013 ADD_INT(d, DB_LOCK_OLDEST);
7014 ADD_INT(d, DB_LOCK_RANDOM);
7015 ADD_INT(d, DB_LOCK_YOUNGEST);
7016 ADD_INT(d, DB_LOCK_MAXLOCKS);
7017 ADD_INT(d, DB_LOCK_MINLOCKS);
7018 ADD_INT(d, DB_LOCK_MINWRITE);
7020 ADD_INT(d, DB_LOCK_EXPIRE);
7021 #if (DBVER >= 43)
7022 ADD_INT(d, DB_LOCK_MAXWRITE);
7023 #endif
7025 _addIntToDict(d, "DB_LOCK_CONFLICT", 0);
7027 ADD_INT(d, DB_LOCK_DUMP);
7028 ADD_INT(d, DB_LOCK_GET);
7029 ADD_INT(d, DB_LOCK_INHERIT);
7030 ADD_INT(d, DB_LOCK_PUT);
7031 ADD_INT(d, DB_LOCK_PUT_ALL);
7032 ADD_INT(d, DB_LOCK_PUT_OBJ);
7034 ADD_INT(d, DB_LOCK_NG);
7035 ADD_INT(d, DB_LOCK_READ);
7036 ADD_INT(d, DB_LOCK_WRITE);
7037 ADD_INT(d, DB_LOCK_NOWAIT);
7038 ADD_INT(d, DB_LOCK_WAIT);
7039 ADD_INT(d, DB_LOCK_IWRITE);
7040 ADD_INT(d, DB_LOCK_IREAD);
7041 ADD_INT(d, DB_LOCK_IWR);
7042 #if (DBVER < 44)
7043 ADD_INT(d, DB_LOCK_DIRTY);
7044 #else
7045 ADD_INT(d, DB_LOCK_READ_UNCOMMITTED); /* renamed in 4.4 */
7046 #endif
7047 ADD_INT(d, DB_LOCK_WWRITE);
7049 ADD_INT(d, DB_LOCK_RECORD);
7050 ADD_INT(d, DB_LOCK_UPGRADE);
7051 ADD_INT(d, DB_LOCK_SWITCH);
7052 ADD_INT(d, DB_LOCK_UPGRADE_WRITE);
7054 ADD_INT(d, DB_LOCK_NOWAIT);
7055 ADD_INT(d, DB_LOCK_RECORD);
7056 ADD_INT(d, DB_LOCK_UPGRADE);
7058 ADD_INT(d, DB_LSTAT_ABORTED);
7059 #if (DBVER < 43)
7060 ADD_INT(d, DB_LSTAT_ERR);
7061 #endif
7062 ADD_INT(d, DB_LSTAT_FREE);
7063 ADD_INT(d, DB_LSTAT_HELD);
7065 ADD_INT(d, DB_LSTAT_PENDING);
7066 ADD_INT(d, DB_LSTAT_WAITING);
7068 ADD_INT(d, DB_ARCH_ABS);
7069 ADD_INT(d, DB_ARCH_DATA);
7070 ADD_INT(d, DB_ARCH_LOG);
7071 #if (DBVER >= 42)
7072 ADD_INT(d, DB_ARCH_REMOVE);
7073 #endif
7075 ADD_INT(d, DB_BTREE);
7076 ADD_INT(d, DB_HASH);
7077 ADD_INT(d, DB_RECNO);
7078 ADD_INT(d, DB_QUEUE);
7079 ADD_INT(d, DB_UNKNOWN);
7081 ADD_INT(d, DB_DUP);
7082 ADD_INT(d, DB_DUPSORT);
7083 ADD_INT(d, DB_RECNUM);
7084 ADD_INT(d, DB_RENUMBER);
7085 ADD_INT(d, DB_REVSPLITOFF);
7086 ADD_INT(d, DB_SNAPSHOT);
7088 ADD_INT(d, DB_JOIN_NOSORT);
7090 ADD_INT(d, DB_AFTER);
7091 ADD_INT(d, DB_APPEND);
7092 ADD_INT(d, DB_BEFORE);
7093 #if (DBVER < 45)
7094 ADD_INT(d, DB_CACHED_COUNTS);
7095 #endif
7097 #if (DBVER >= 41)
7098 _addIntToDict(d, "DB_CHECKPOINT", 0);
7099 #else
7100 ADD_INT(d, DB_CHECKPOINT);
7101 ADD_INT(d, DB_CURLSN);
7102 #endif
7103 #if (DBVER <= 41)
7104 ADD_INT(d, DB_COMMIT);
7105 #endif
7106 ADD_INT(d, DB_CONSUME);
7107 ADD_INT(d, DB_CONSUME_WAIT);
7108 ADD_INT(d, DB_CURRENT);
7109 ADD_INT(d, DB_FAST_STAT);
7110 ADD_INT(d, DB_FIRST);
7111 ADD_INT(d, DB_FLUSH);
7112 ADD_INT(d, DB_GET_BOTH);
7113 ADD_INT(d, DB_GET_RECNO);
7114 ADD_INT(d, DB_JOIN_ITEM);
7115 ADD_INT(d, DB_KEYFIRST);
7116 ADD_INT(d, DB_KEYLAST);
7117 ADD_INT(d, DB_LAST);
7118 ADD_INT(d, DB_NEXT);
7119 ADD_INT(d, DB_NEXT_DUP);
7120 ADD_INT(d, DB_NEXT_NODUP);
7121 ADD_INT(d, DB_NODUPDATA);
7122 ADD_INT(d, DB_NOOVERWRITE);
7123 ADD_INT(d, DB_NOSYNC);
7124 ADD_INT(d, DB_POSITION);
7125 ADD_INT(d, DB_PREV);
7126 ADD_INT(d, DB_PREV_NODUP);
7127 #if (DBVER < 45)
7128 ADD_INT(d, DB_RECORDCOUNT);
7129 #endif
7130 ADD_INT(d, DB_SET);
7131 ADD_INT(d, DB_SET_RANGE);
7132 ADD_INT(d, DB_SET_RECNO);
7133 ADD_INT(d, DB_WRITECURSOR);
7135 ADD_INT(d, DB_OPFLAGS_MASK);
7136 ADD_INT(d, DB_RMW);
7137 ADD_INT(d, DB_DIRTY_READ);
7138 ADD_INT(d, DB_MULTIPLE);
7139 ADD_INT(d, DB_MULTIPLE_KEY);
7141 #if (DBVER >= 44)
7142 ADD_INT(d, DB_READ_UNCOMMITTED); /* replaces DB_DIRTY_READ in 4.4 */
7143 ADD_INT(d, DB_READ_COMMITTED);
7144 #endif
7146 ADD_INT(d, DB_DONOTINDEX);
7148 #if (DBVER >= 41)
7149 _addIntToDict(d, "DB_INCOMPLETE", 0);
7150 #else
7151 ADD_INT(d, DB_INCOMPLETE);
7152 #endif
7153 ADD_INT(d, DB_KEYEMPTY);
7154 ADD_INT(d, DB_KEYEXIST);
7155 ADD_INT(d, DB_LOCK_DEADLOCK);
7156 ADD_INT(d, DB_LOCK_NOTGRANTED);
7157 ADD_INT(d, DB_NOSERVER);
7158 ADD_INT(d, DB_NOSERVER_HOME);
7159 ADD_INT(d, DB_NOSERVER_ID);
7160 ADD_INT(d, DB_NOTFOUND);
7161 ADD_INT(d, DB_OLD_VERSION);
7162 ADD_INT(d, DB_RUNRECOVERY);
7163 ADD_INT(d, DB_VERIFY_BAD);
7164 ADD_INT(d, DB_PAGE_NOTFOUND);
7165 ADD_INT(d, DB_SECONDARY_BAD);
7166 ADD_INT(d, DB_STAT_CLEAR);
7167 ADD_INT(d, DB_REGION_INIT);
7168 ADD_INT(d, DB_NOLOCKING);
7169 ADD_INT(d, DB_YIELDCPU);
7170 ADD_INT(d, DB_PANIC_ENVIRONMENT);
7171 ADD_INT(d, DB_NOPANIC);
7173 #if (DBVER >= 41)
7174 ADD_INT(d, DB_OVERWRITE);
7175 #endif
7177 #ifdef DB_REGISTER
7178 ADD_INT(d, DB_REGISTER);
7179 #endif
7181 #if (DBVER >= 42)
7182 ADD_INT(d, DB_TIME_NOTGRANTED);
7183 ADD_INT(d, DB_TXN_NOT_DURABLE);
7184 ADD_INT(d, DB_TXN_WRITE_NOSYNC);
7185 ADD_INT(d, DB_DIRECT_DB);
7186 ADD_INT(d, DB_INIT_REP);
7187 ADD_INT(d, DB_ENCRYPT);
7188 ADD_INT(d, DB_CHKSUM);
7189 #endif
7191 #if (DBVER >= 42) && (DBVER < 47)
7192 ADD_INT(d, DB_LOG_AUTOREMOVE);
7193 ADD_INT(d, DB_DIRECT_LOG);
7194 #endif
7196 #if (DBVER >= 47)
7197 ADD_INT(d, DB_LOG_DIRECT);
7198 ADD_INT(d, DB_LOG_DSYNC);
7199 ADD_INT(d, DB_LOG_IN_MEMORY);
7200 ADD_INT(d, DB_LOG_AUTO_REMOVE);
7201 ADD_INT(d, DB_LOG_ZERO);
7202 #endif
7204 #if (DBVER >= 44)
7205 ADD_INT(d, DB_DSYNC_DB);
7206 #endif
7208 #if (DBVER >= 45)
7209 ADD_INT(d, DB_TXN_SNAPSHOT);
7210 #endif
7212 ADD_INT(d, DB_VERB_DEADLOCK);
7213 #if (DBVER >= 46)
7214 ADD_INT(d, DB_VERB_FILEOPS);
7215 ADD_INT(d, DB_VERB_FILEOPS_ALL);
7216 #endif
7217 ADD_INT(d, DB_VERB_RECOVERY);
7218 #if (DBVER >= 44)
7219 ADD_INT(d, DB_VERB_REGISTER);
7220 #endif
7221 ADD_INT(d, DB_VERB_REPLICATION);
7222 ADD_INT(d, DB_VERB_WAITSFOR);
7224 #if (DBVER >= 45)
7225 ADD_INT(d, DB_EVENT_PANIC);
7226 ADD_INT(d, DB_EVENT_REP_CLIENT);
7227 #if (DBVER >= 46)
7228 ADD_INT(d, DB_EVENT_REP_ELECTED);
7229 #endif
7230 ADD_INT(d, DB_EVENT_REP_MASTER);
7231 ADD_INT(d, DB_EVENT_REP_NEWMASTER);
7232 #if (DBVER >= 46)
7233 ADD_INT(d, DB_EVENT_REP_PERM_FAILED);
7234 #endif
7235 ADD_INT(d, DB_EVENT_REP_STARTUPDONE);
7236 ADD_INT(d, DB_EVENT_WRITE_FAILED);
7237 #endif
7239 ADD_INT(d, DB_REP_DUPMASTER);
7240 ADD_INT(d, DB_REP_HOLDELECTION);
7241 #if (DBVER >= 44)
7242 ADD_INT(d, DB_REP_IGNORE);
7243 ADD_INT(d, DB_REP_JOIN_FAILURE);
7244 #endif
7245 #if (DBVER >= 42)
7246 ADD_INT(d, DB_REP_ISPERM);
7247 ADD_INT(d, DB_REP_NOTPERM);
7248 #endif
7249 ADD_INT(d, DB_REP_NEWSITE);
7251 ADD_INT(d, DB_REP_MASTER);
7252 ADD_INT(d, DB_REP_CLIENT);
7253 #if (DBVER >= 45)
7254 ADD_INT(d, DB_REP_ELECTION);
7256 ADD_INT(d, DB_REP_ACK_TIMEOUT);
7257 ADD_INT(d, DB_REP_CONNECTION_RETRY);
7258 ADD_INT(d, DB_REP_ELECTION_TIMEOUT);
7259 ADD_INT(d, DB_REP_ELECTION_RETRY);
7260 #endif
7261 #if (DBVER >= 46)
7262 ADD_INT(d, DB_REP_CHECKPOINT_DELAY);
7263 ADD_INT(d, DB_REP_FULL_ELECTION_TIMEOUT);
7264 #endif
7266 #if (DBVER >= 45)
7267 ADD_INT(d, DB_REPMGR_PEER);
7268 ADD_INT(d, DB_REPMGR_ACKS_ALL);
7269 ADD_INT(d, DB_REPMGR_ACKS_ALL_PEERS);
7270 ADD_INT(d, DB_REPMGR_ACKS_NONE);
7271 ADD_INT(d, DB_REPMGR_ACKS_ONE);
7272 ADD_INT(d, DB_REPMGR_ACKS_ONE_PEER);
7273 ADD_INT(d, DB_REPMGR_ACKS_QUORUM);
7274 ADD_INT(d, DB_REPMGR_CONNECTED);
7275 ADD_INT(d, DB_REPMGR_DISCONNECTED);
7276 ADD_INT(d, DB_STAT_CLEAR);
7277 ADD_INT(d, DB_STAT_ALL);
7278 #endif
7280 #if (DBVER >= 43)
7281 ADD_INT(d, DB_BUFFER_SMALL);
7282 ADD_INT(d, DB_SEQ_DEC);
7283 ADD_INT(d, DB_SEQ_INC);
7284 ADD_INT(d, DB_SEQ_WRAP);
7285 #endif
7287 #if (DBVER >= 43) && (DBVER < 47)
7288 ADD_INT(d, DB_LOG_INMEMORY);
7289 ADD_INT(d, DB_DSYNC_LOG);
7290 #endif
7292 #if (DBVER >= 41)
7293 ADD_INT(d, DB_ENCRYPT_AES);
7294 ADD_INT(d, DB_AUTO_COMMIT);
7295 #else
7296 /* allow Berkeley DB 4.1 aware apps to run on older versions */
7297 _addIntToDict(d, "DB_AUTO_COMMIT", 0);
7298 #endif
7300 ADD_INT(d, EINVAL);
7301 ADD_INT(d, EACCES);
7302 ADD_INT(d, ENOSPC);
7303 ADD_INT(d, ENOMEM);
7304 ADD_INT(d, EAGAIN);
7305 ADD_INT(d, EBUSY);
7306 ADD_INT(d, EEXIST);
7307 ADD_INT(d, ENOENT);
7308 ADD_INT(d, EPERM);
7310 ADD_INT(d, DB_SET_LOCK_TIMEOUT);
7311 ADD_INT(d, DB_SET_TXN_TIMEOUT);
7313 /* The exception name must be correct for pickled exception *
7314 * objects to unpickle properly. */
7315 #ifdef PYBSDDB_STANDALONE /* different value needed for standalone pybsddb */
7316 #define PYBSDDB_EXCEPTION_BASE "bsddb3.db."
7317 #else
7318 #define PYBSDDB_EXCEPTION_BASE "bsddb.db."
7319 #endif
7321 /* All the rest of the exceptions derive only from DBError */
7322 #define MAKE_EX(name) name = PyErr_NewException(PYBSDDB_EXCEPTION_BASE #name, DBError, NULL); \
7323 PyDict_SetItemString(d, #name, name)
7325 /* The base exception class is DBError */
7326 DBError = NULL; /* used in MAKE_EX so that it derives from nothing */
7327 MAKE_EX(DBError);
7329 #if (PY_VERSION_HEX < 0x03000000)
7330 /* Some magic to make DBNotFoundError and DBKeyEmptyError derive
7331 * from both DBError and KeyError, since the API only supports
7332 * using one base class. */
7333 PyDict_SetItemString(d, "KeyError", PyExc_KeyError);
7334 PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n"
7335 "class DBKeyEmptyError(DBError, KeyError): pass",
7336 Py_file_input, d, d);
7337 DBNotFoundError = PyDict_GetItemString(d, "DBNotFoundError");
7338 DBKeyEmptyError = PyDict_GetItemString(d, "DBKeyEmptyError");
7339 PyDict_DelItemString(d, "KeyError");
7340 #else
7341 /* Since Python 2.5, PyErr_NewException() accepts a tuple, to be able to
7342 ** derive from several classes. We use this new API only for Python 3.0,
7343 ** though.
7346 PyObject* bases;
7348 bases = PyTuple_Pack(2, DBError, PyExc_KeyError);
7350 #define MAKE_EX2(name) name = PyErr_NewException(PYBSDDB_EXCEPTION_BASE #name, bases, NULL); \
7351 PyDict_SetItemString(d, #name, name)
7352 MAKE_EX2(DBNotFoundError);
7353 MAKE_EX2(DBKeyEmptyError);
7355 #undef MAKE_EX2
7357 Py_XDECREF(bases);
7359 #endif
7362 #if !INCOMPLETE_IS_WARNING
7363 MAKE_EX(DBIncompleteError);
7364 #endif
7365 MAKE_EX(DBCursorClosedError);
7366 MAKE_EX(DBKeyEmptyError);
7367 MAKE_EX(DBKeyExistError);
7368 MAKE_EX(DBLockDeadlockError);
7369 MAKE_EX(DBLockNotGrantedError);
7370 MAKE_EX(DBOldVersionError);
7371 MAKE_EX(DBRunRecoveryError);
7372 MAKE_EX(DBVerifyBadError);
7373 MAKE_EX(DBNoServerError);
7374 MAKE_EX(DBNoServerHomeError);
7375 MAKE_EX(DBNoServerIDError);
7376 MAKE_EX(DBPageNotFoundError);
7377 MAKE_EX(DBSecondaryBadError);
7379 MAKE_EX(DBInvalidArgError);
7380 MAKE_EX(DBAccessError);
7381 MAKE_EX(DBNoSpaceError);
7382 MAKE_EX(DBNoMemoryError);
7383 MAKE_EX(DBAgainError);
7384 MAKE_EX(DBBusyError);
7385 MAKE_EX(DBFileExistsError);
7386 MAKE_EX(DBNoSuchFileError);
7387 MAKE_EX(DBPermissionsError);
7389 #if (DBVER >= 42)
7390 MAKE_EX(DBRepHandleDeadError);
7391 #endif
7393 MAKE_EX(DBRepUnavailError);
7395 #undef MAKE_EX
7397 /* Initiliase the C API structure and add it to the module */
7398 bsddb_api.db_type = &DB_Type;
7399 bsddb_api.dbcursor_type = &DBCursor_Type;
7400 bsddb_api.dbenv_type = &DBEnv_Type;
7401 bsddb_api.dbtxn_type = &DBTxn_Type;
7402 bsddb_api.dblock_type = &DBLock_Type;
7403 #if (DBVER >= 43)
7404 bsddb_api.dbsequence_type = &DBSequence_Type;
7405 #endif
7406 bsddb_api.makeDBError = makeDBError;
7408 py_api = PyCObject_FromVoidPtr((void*)&bsddb_api, NULL);
7409 PyDict_SetItemString(d, "api", py_api);
7410 Py_DECREF(py_api);
7412 /* Check for errors */
7413 if (PyErr_Occurred()) {
7414 PyErr_Print();
7415 Py_FatalError("can't initialize module _bsddb/_pybsddb");
7416 Py_DECREF(m);
7417 m = NULL;
7419 #if (PY_VERSION_HEX < 0x03000000)
7420 return;
7421 #else
7422 return m;
7423 #endif
7426 /* allow this module to be named _pybsddb so that it can be installed
7427 * and imported on top of python >= 2.3 that includes its own older
7428 * copy of the library named _bsddb without importing the old version. */
7429 #if (PY_VERSION_HEX < 0x03000000)
7430 DL_EXPORT(void) init_pybsddb(void)
7431 #else
7432 PyMODINIT_FUNC PyInit__pybsddb(void) /* Note the two underscores */
7433 #endif
7435 strncpy(_bsddbModuleName, "_pybsddb", MODULE_NAME_MAX_LEN);
7436 #if (PY_VERSION_HEX < 0x03000000)
7437 init_bsddb();
7438 #else
7439 return PyInit__bsddb(); /* Note the two underscores */
7440 #endif