Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

python/_rpmdb.c

Go to the documentation of this file.
00001 
00005 /*----------------------------------------------------------------------
00006   Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA
00007   and Andrew Kuchling. All rights reserved.
00008 
00009   Redistribution and use in source and binary forms, with or without
00010   modification, are permitted provided that the following conditions are
00011   met:
00012 
00013     o Redistributions of source code must retain the above copyright
00014       notice, this list of conditions, and the disclaimer that follows.
00015 
00016     o Redistributions in binary form must reproduce the above copyright
00017       notice, this list of conditions, and the following disclaimer in
00018       the documentation and/or other materials provided with the
00019       distribution.
00020 
00021     o Neither the name of Digital Creations nor the names of its
00022       contributors may be used to endorse or promote products derived
00023       from this software without specific prior written permission.
00024 
00025   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
00026   IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00027   TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00028   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL
00029   CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00030   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00031   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00032   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00033   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
00034   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00035   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00036   DAMAGE.
00037 ------------------------------------------------------------------------*/
00038 
00039 
00040 /*
00041  * Handwritten code to wrap version 3.x of the Berkeley DB library,
00042  * written to replace a SWIG-generated file.  It has since been updated
00043  * to compile with BerkeleyDB versions 3.2 through 4.2.
00044  *
00045  * This module was started by Andrew Kuchling to remove the dependency
00046  * on SWIG in a package by Gregory P. Smith <greg@electricrain.com> who
00047  * based his work on a similar package by Robin Dunn <robin@alldunn.com>
00048  * which wrapped Berkeley DB 2.7.x.
00049  *
00050  * Development of this module then returned full circle back to Robin Dunn
00051  * who worked on behalf of Digital Creations to complete the wrapping of
00052  * the DB 3.x API and to build a solid unit test suite.  Robin has
00053  * since gone onto other projects (wxPython).
00054  *
00055  * Gregory P. Smith <greg@electricrain.com> is once again the maintainer.
00056  *
00057  * Use the pybsddb-users@lists.sf.net mailing list for all questions.
00058  * Things can change faster than the header of this file is updated.  This
00059  * file is shared with the PyBSDDB project at SourceForge:
00060  *
00061  * http://pybsddb.sf.net
00062  *
00063  * This file should remain backward compatible with Python 2.1, but see PEP
00064  * 291 for the most current backward compatibility requirements:
00065  *
00066  * http://www.python.org/peps/pep-0291.html
00067  *
00068  * This module contains 5 types:
00069  *
00070  * DB           (Database)
00071  * DBCursor     (Database Cursor)
00072  * DBEnv        (database environment)
00073  * DBTxn        (An explicit database transaction)
00074  * DBLock       (A lock handle)
00075  *
00076  */
00077 
00078 /* --------------------------------------------------------------------- */
00079 
00080 /*
00081  * Portions of this module, associated unit tests and build scripts are the
00082  * result of a contract with The Written Word (http://thewrittenword.com/)
00083  * Many thanks go out to them for causing me to raise the bar on quality and
00084  * functionality, resulting in a better bsddb3 package for all of us to use.
00085  *
00086  * --Robin
00087  */
00088 
00089 /* --------------------------------------------------------------------- */
00090 
00091 #include <stddef.h>   /* for offsetof() */
00092 #include <Python.h>
00093 #include <db.h>
00094 
00095 /* --------------------------------------------------------------------- */
00096 /* Various macro definitions */
00097 
00098 /* 40 = 4.0, 33 = 3.3; this will break if the second number is > 9 */
00099 #define DBVER (DB_VERSION_MAJOR * 10 + DB_VERSION_MINOR)
00100 #if DB_VERSION_MINOR > 9
00101 #error "eek! DBVER can't handle minor versions > 9"
00102 #endif
00103 
00104 #define PY_BSDDB_VERSION "4.2.4"
00105 static char *rcs_id = "$Id: _rpmdb.c,v 1.7.2.3 2003/12/16 05:00:41 jbj Exp $";
00106 
00107 
00108 #ifdef WITH_THREAD
00109 
00110 /* These are for when calling Python --> C */
00111 #define MYDB_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS;
00112 #define MYDB_END_ALLOW_THREADS Py_END_ALLOW_THREADS;
00113 
00114 /* For 2.3, use the PyGILState_ calls */
00115 #if (PY_VERSION_HEX >= 0x02030000)
00116 #define MYDB_USE_GILSTATE
00117 #endif
00118 
00119 /* and these are for calling C --> Python */
00120 #if defined(MYDB_USE_GILSTATE)
00121 #define MYDB_BEGIN_BLOCK_THREADS \
00122                 PyGILState_STATE __savestate = PyGILState_Ensure();
00123 #define MYDB_END_BLOCK_THREADS \
00124                 PyGILState_Release(__savestate);
00125 #else /* MYDB_USE_GILSTATE */
00126 /* Pre GILState API - do it the long old way */
00127 static PyInterpreterState* _db_interpreterState = NULL;
00128 #define MYDB_BEGIN_BLOCK_THREADS {                              \
00129         PyThreadState* prevState;                               \
00130         PyThreadState* newState;                                \
00131         PyEval_AcquireLock();                                   \
00132         newState  = PyThreadState_New(_db_interpreterState);    \
00133         prevState = PyThreadState_Swap(newState);
00134 
00135 #define MYDB_END_BLOCK_THREADS                                  \
00136         newState = PyThreadState_Swap(prevState);               \
00137         PyThreadState_Clear(newState);                          \
00138         PyEval_ReleaseLock();                                   \
00139         PyThreadState_Delete(newState);                         \
00140         }
00141 #endif /* MYDB_USE_GILSTATE */
00142 
00143 #else
00144 /* Compiled without threads - avoid all this cruft */
00145 #define MYDB_BEGIN_ALLOW_THREADS
00146 #define MYDB_END_ALLOW_THREADS
00147 #define MYDB_BEGIN_BLOCK_THREADS
00148 #define MYDB_END_BLOCK_THREADS
00149 
00150 #endif
00151 
00152 /* Should DB_INCOMPLETE be turned into a warning or an exception? */
00153 #define INCOMPLETE_IS_WARNING 1
00154 
00155 /* --------------------------------------------------------------------- */
00156 /* Exceptions */
00157 
00158 static PyObject* DBError;               /* Base class, all others derive from this */
00159 static PyObject* DBCursorClosedError;   /* raised when trying to use a closed cursor object */
00160 static PyObject* DBKeyEmptyError;       /* DB_KEYEMPTY */
00161 static PyObject* DBKeyExistError;       /* DB_KEYEXIST */
00162 static PyObject* DBLockDeadlockError;   /* DB_LOCK_DEADLOCK */
00163 static PyObject* DBLockNotGrantedError; /* DB_LOCK_NOTGRANTED */
00164 static PyObject* DBNotFoundError;       /* DB_NOTFOUND: also derives from KeyError */
00165 static PyObject* DBOldVersionError;     /* DB_OLD_VERSION */
00166 static PyObject* DBRunRecoveryError;    /* DB_RUNRECOVERY */
00167 static PyObject* DBVerifyBadError;      /* DB_VERIFY_BAD */
00168 static PyObject* DBNoServerError;       /* DB_NOSERVER */
00169 static PyObject* DBNoServerHomeError;   /* DB_NOSERVER_HOME */
00170 static PyObject* DBNoServerIDError;     /* DB_NOSERVER_ID */
00171 #if (DBVER >= 33)
00172 static PyObject* DBPageNotFoundError;   /* DB_PAGE_NOTFOUND */
00173 static PyObject* DBSecondaryBadError;   /* DB_SECONDARY_BAD */
00174 #endif
00175 
00176 #if !INCOMPLETE_IS_WARNING
00177 static PyObject* DBIncompleteError;     /* DB_INCOMPLETE */
00178 #endif
00179 
00180 static PyObject* DBInvalidArgError;     /* EINVAL */
00181 static PyObject* DBAccessError;         /* EACCES */
00182 static PyObject* DBNoSpaceError;        /* ENOSPC */
00183 static PyObject* DBNoMemoryError;       /* ENOMEM */
00184 static PyObject* DBAgainError;          /* EAGAIN */
00185 static PyObject* DBBusyError;           /* EBUSY  */
00186 static PyObject* DBFileExistsError;     /* EEXIST */
00187 static PyObject* DBNoSuchFileError;     /* ENOENT */
00188 static PyObject* DBPermissionsError;    /* EPERM  */
00189 
00190 
00191 
00192 /* --------------------------------------------------------------------- */
00193 /* Structure definitions */
00194 
00195 #if PYTHON_API_VERSION >= 1010       /* python >= 2.1 support weak references */
00196 #define HAVE_WEAKREF
00197 #else
00198 #undef HAVE_WEAKREF
00199 #endif
00200 
00201 struct behaviourFlags {
00202     /* What is the default behaviour when DB->get or DBCursor->get returns a
00203        DB_NOTFOUND error?  Return None or raise an exception? */
00204     unsigned int getReturnsNone : 1;
00205     /* What is the default behaviour for DBCursor.set* methods when DBCursor->get
00206      * returns a DB_NOTFOUND error?  Return None or raise an exception? */
00207     unsigned int cursorSetReturnsNone : 1;
00208 };
00209 
00210 #define DEFAULT_GET_RETURNS_NONE                1
00211 #define DEFAULT_CURSOR_SET_RETURNS_NONE         1   /* 0 in pybsddb < 4.2, python < 2.4 */
00212 
00213 typedef struct {
00214     PyObject_HEAD
00215     DB_ENV*     db_env;
00216     u_int32_t   flags;             /* saved flags from open() */
00217     int         closed;
00218     struct behaviourFlags moduleFlags;
00219 } DBEnvObject;
00220 
00221 
00222 typedef struct {
00223     PyObject_HEAD
00224     DB*             db;
00225     DBEnvObject*    myenvobj;  /* PyObject containing the DB_ENV */
00226     u_int32_t       flags;     /* saved flags from open() */
00227     u_int32_t       setflags;  /* saved flags from set_flags() */
00228     int             haveStat;
00229     struct behaviourFlags moduleFlags;
00230 #if (DBVER >= 33)
00231     PyObject*       associateCallback;
00232     int             primaryDBType;
00233 #endif
00234 } DBObject;
00235 
00236 
00237 typedef struct {
00238     PyObject_HEAD
00239     DBC*            dbc;
00240     DBObject*       mydb;
00241 #ifdef HAVE_WEAKREF
00242     PyObject        *in_weakreflist; /* List of weak references */
00243 #endif
00244 } DBCursorObject;
00245 
00246 
00247 typedef struct {
00248     PyObject_HEAD
00249     DB_TXN*         txn;
00250 } DBTxnObject;
00251 
00252 
00253 typedef struct {
00254     PyObject_HEAD
00255     DB_LOCK         lock;
00256 } DBLockObject;
00257 
00258 
00259 
00260 staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type, DBLock_Type;
00261 
00262 #define DBObject_Check(v)           ((v)->ob_type == &DB_Type)
00263 #define DBCursorObject_Check(v)     ((v)->ob_type == &DBCursor_Type)
00264 #define DBEnvObject_Check(v)        ((v)->ob_type == &DBEnv_Type)
00265 #define DBTxnObject_Check(v)        ((v)->ob_type == &DBTxn_Type)
00266 #define DBLockObject_Check(v)       ((v)->ob_type == &DBLock_Type)
00267 
00268 
00269 /* --------------------------------------------------------------------- */
00270 /* Utility macros and functions */
00271 
00272 #define RETURN_IF_ERR()          \
00273     if (makeDBError(err)) {      \
00274         return NULL;             \
00275     }
00276 
00277 #define RETURN_NONE()  Py_INCREF(Py_None); return Py_None;
00278 
00279 #define _CHECK_OBJECT_NOT_CLOSED(nonNull, pyErrObj, name) \
00280     if ((nonNull) == NULL) {          \
00281         PyObject *errTuple = NULL;    \
00282         errTuple = Py_BuildValue("(is)", 0, #name " object has been closed"); \
00283         PyErr_SetObject((pyErrObj), errTuple);  \
00284         Py_DECREF(errTuple);          \
00285         return NULL;                  \
00286     }
00287 
00288 #define CHECK_DB_NOT_CLOSED(dbobj) \
00289         _CHECK_OBJECT_NOT_CLOSED(dbobj->db, DBError, DB)
00290 
00291 #define CHECK_ENV_NOT_CLOSED(env) \
00292         _CHECK_OBJECT_NOT_CLOSED(env->db_env, DBError, DBEnv)
00293 
00294 #define CHECK_CURSOR_NOT_CLOSED(curs) \
00295         _CHECK_OBJECT_NOT_CLOSED(curs->dbc, DBCursorClosedError, DBCursor)
00296 
00297 
00298 #define CHECK_DBFLAG(mydb, flag)    (((mydb)->flags & (flag)) || \
00299                                      (((mydb)->myenvobj != NULL) && ((mydb)->myenvobj->flags & (flag))))
00300 
00301 #define CLEAR_DBT(dbt)              (memset(&(dbt), 0, sizeof(dbt)))
00302 
00303 #define FREE_DBT(dbt)               if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \
00304                                          dbt.data != NULL) { free(dbt.data); }
00305 
00306 
00307 static int makeDBError(int err);
00308 
00309 
00310 /* Return the access method type of the DBObject */
00311 static int _DB_get_type(DBObject* self)
00312 {
00313 #if (DBVER >= 33)
00314     DBTYPE type;
00315     int err;
00316     err = self->db->get_type(self->db, &type);
00317     if (makeDBError(err)) {
00318         return -1;
00319     }
00320     return type;
00321 #else
00322     return self->db->get_type(self->db);
00323 #endif
00324 }
00325 
00326 
00327 /* Create a DBT structure (containing key and data values) from Python
00328    strings.  Returns 1 on success, 0 on an error. */
00329 static int make_dbt(PyObject* obj, DBT* dbt)
00330 {
00331     CLEAR_DBT(*dbt);
00332     if (obj == Py_None) {
00333         /* no need to do anything, the structure has already been zeroed */
00334     }
00335     else if (!PyArg_Parse(obj, "s#", &dbt->data, &dbt->size)) {
00336         PyErr_SetString(PyExc_TypeError,
00337                         "Key and Data values must be of type string or None.");
00338         return 0;
00339     }
00340     return 1;
00341 }
00342 
00343 
00344 /* Recno and Queue DBs can have integer keys.  This function figures out
00345    what's been given, verifies that it's allowed, and then makes the DBT.
00346 
00347    Caller should call FREE_DBT(key) when done. */
00348 static int
00349 make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags)
00350 {
00351     db_recno_t recno;
00352     int type;
00353 
00354     CLEAR_DBT(*key);
00355     if (keyobj == Py_None) {  /* TODO: is None really okay for keys? */
00356         /* no need to do anything, the structure has already been zeroed */
00357     }
00358 
00359     else if (PyString_Check(keyobj)) {
00360         /* verify access method type */
00361         type = _DB_get_type(self);
00362         if (type == -1)
00363             return 0;
00364         if (type == DB_RECNO || type == DB_QUEUE) {
00365             PyErr_SetString(
00366                 PyExc_TypeError,
00367                 "String keys not allowed for Recno and Queue DB's");
00368             return 0;
00369         }
00370 
00371         key->data = PyString_AS_STRING(keyobj);
00372         key->size = PyString_GET_SIZE(keyobj);
00373     }
00374 
00375     else if (PyInt_Check(keyobj)) {
00376         /* verify access method type */
00377         type = _DB_get_type(self);
00378         if (type == -1)
00379             return 0;
00380         if (type == DB_BTREE && pflags != NULL) {
00381             /* if BTREE then an Integer key is allowed with the
00382              * DB_SET_RECNO flag */
00383             *pflags |= DB_SET_RECNO;
00384         }
00385         else if (type != DB_RECNO && type != DB_QUEUE) {
00386             PyErr_SetString(
00387                 PyExc_TypeError,
00388                 "Integer keys only allowed for Recno and Queue DB's");
00389             return 0;
00390         }
00391 
00392         /* Make a key out of the requested recno, use allocated space so DB
00393          * will be able to realloc room for the real key if needed. */
00394         recno = PyInt_AS_LONG(keyobj);
00395         key->data = malloc(sizeof(db_recno_t));
00396         if (key->data == NULL) {
00397             PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
00398             return 0;
00399         }
00400         key->ulen = key->size = sizeof(db_recno_t);
00401         memcpy(key->data, &recno, sizeof(db_recno_t));
00402         key->flags = DB_DBT_REALLOC;
00403     }
00404     else {
00405         PyErr_Format(PyExc_TypeError,
00406                      "String or Integer object expected for key, %s found",
00407                      keyobj->ob_type->tp_name);
00408         return 0;
00409     }
00410 
00411     return 1;
00412 }
00413 
00414 
00415 /* Add partial record access to an existing DBT data struct.
00416    If dlen and doff are set, then the DB_DBT_PARTIAL flag will be set
00417    and the data storage/retrieval will be done using dlen and doff. */
00418 static int add_partial_dbt(DBT* d, int dlen, int doff) {
00419     /* if neither were set we do nothing (-1 is the default value) */
00420     if ((dlen == -1) && (doff == -1)) {
00421         return 1;
00422     }
00423 
00424     if ((dlen < 0) || (doff < 0)) {
00425         PyErr_SetString(PyExc_TypeError, "dlen and doff must both be >= 0");
00426         return 0;
00427     }
00428 
00429     d->flags = d->flags | DB_DBT_PARTIAL;
00430     d->dlen = (unsigned int) dlen;
00431     d->doff = (unsigned int) doff;
00432     return 1;
00433 }
00434 
00435 
00436 /* Callback used to save away more information about errors from the DB
00437  * library. */
00438 static char _db_errmsg[1024];
00439 static void _db_errorCallback(const char* prefix, char* msg)
00440 {
00441     strcpy(_db_errmsg, msg);
00442 }
00443 
00444 
00445 /* make a nice exception object to raise for errors. */
00446 static int makeDBError(int err)
00447 {
00448     char errTxt[2048];  /* really big, just in case... */
00449     PyObject *errObj = NULL;
00450     PyObject *errTuple = NULL;
00451     int exceptionRaised = 0;
00452 
00453     switch (err) {
00454         case 0:                     /* successful, no error */      break;
00455 
00456 #if (DBVER < 41)
00457         case DB_INCOMPLETE:
00458 #if INCOMPLETE_IS_WARNING
00459             strcpy(errTxt, db_strerror(err));
00460             if (_db_errmsg[0]) {
00461                 strcat(errTxt, " -- ");
00462                 strcat(errTxt, _db_errmsg);
00463                 _db_errmsg[0] = 0;
00464             }
00465 /* if Python 2.1 or better use warning framework */
00466 #if PYTHON_API_VERSION >= 1010
00467             exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt);
00468 #else
00469             fprintf(stderr, errTxt);
00470             fprintf(stderr, "\n");
00471 #endif
00472 
00473 #else  /* do an exception instead */
00474         errObj = DBIncompleteError;
00475 #endif
00476         break;
00477 #endif /* DBVER < 41 */
00478 
00479         case DB_KEYEMPTY:           errObj = DBKeyEmptyError;       break;
00480         case DB_KEYEXIST:           errObj = DBKeyExistError;       break;
00481         case DB_LOCK_DEADLOCK:      errObj = DBLockDeadlockError;   break;
00482         case DB_LOCK_NOTGRANTED:    errObj = DBLockNotGrantedError; break;
00483         case DB_NOTFOUND:           errObj = DBNotFoundError;       break;
00484         case DB_OLD_VERSION:        errObj = DBOldVersionError;     break;
00485         case DB_RUNRECOVERY:        errObj = DBRunRecoveryError;    break;
00486         case DB_VERIFY_BAD:         errObj = DBVerifyBadError;      break;
00487         case DB_NOSERVER:           errObj = DBNoServerError;       break;
00488         case DB_NOSERVER_HOME:      errObj = DBNoServerHomeError;   break;
00489         case DB_NOSERVER_ID:        errObj = DBNoServerIDError;     break;
00490 #if (DBVER >= 33)
00491         case DB_PAGE_NOTFOUND:      errObj = DBPageNotFoundError;   break;
00492         case DB_SECONDARY_BAD:      errObj = DBSecondaryBadError;   break;
00493 #endif
00494 
00495         case EINVAL:  errObj = DBInvalidArgError;   break;
00496         case EACCES:  errObj = DBAccessError;       break;
00497         case ENOSPC:  errObj = DBNoSpaceError;      break;
00498         case ENOMEM:  errObj = DBNoMemoryError;     break;
00499         case EAGAIN:  errObj = DBAgainError;        break;
00500         case EBUSY :  errObj = DBBusyError;         break;
00501         case EEXIST:  errObj = DBFileExistsError;   break;
00502         case ENOENT:  errObj = DBNoSuchFileError;   break;
00503         case EPERM :  errObj = DBPermissionsError;  break;
00504 
00505         default:      errObj = DBError;             break;
00506     }
00507 
00508     if (errObj != NULL) {
00509         /* FIXME this needs proper bounds checking on errTxt */
00510         strcpy(errTxt, db_strerror(err));
00511         if (_db_errmsg[0]) {
00512             strcat(errTxt, " -- ");
00513             strcat(errTxt, _db_errmsg);
00514             _db_errmsg[0] = 0;
00515         }
00516 
00517         errTuple = Py_BuildValue("(is)", err, errTxt);
00518         PyErr_SetObject(errObj, errTuple);
00519         Py_DECREF(errTuple);
00520     }
00521 
00522     return ((errObj != NULL) || exceptionRaised);
00523 }
00524 
00525 
00526 
00527 /* set a type exception */
00528 static void makeTypeError(char* expected, PyObject* found)
00529 {
00530     PyErr_Format(PyExc_TypeError, "Expected %s argument, %s found.",
00531                  expected, found->ob_type->tp_name);
00532 }
00533 
00534 
00535 /* verify that an obj is either None or a DBTxn, and set the txn pointer */
00536 static int checkTxnObj(PyObject* txnobj, DB_TXN** txn)
00537 {
00538     if (txnobj == Py_None || txnobj == NULL) {
00539         *txn = NULL;
00540         return 1;
00541     }
00542     if (DBTxnObject_Check(txnobj)) {
00543         *txn = ((DBTxnObject*)txnobj)->txn;
00544         return 1;
00545     }
00546     else
00547         makeTypeError("DBTxn", txnobj);
00548     return 0;
00549 }
00550 
00551 
00552 /* Delete a key from a database
00553   Returns 0 on success, -1 on an error.  */
00554 static int _DB_delete(DBObject* self, DB_TXN *txn, DBT *key, int flags)
00555 {
00556     int err;
00557 
00558     MYDB_BEGIN_ALLOW_THREADS;
00559     err = self->db->del(self->db, txn, key, 0);
00560     MYDB_END_ALLOW_THREADS;
00561     if (makeDBError(err)) {
00562         return -1;
00563     }
00564     self->haveStat = 0;
00565     return 0;
00566 }
00567 
00568 
00569 /* Store a key into a database
00570    Returns 0 on success, -1 on an error.  */
00571 static int _DB_put(DBObject* self, DB_TXN *txn, DBT *key, DBT *data, int flags)
00572 {
00573     int err;
00574 
00575     MYDB_BEGIN_ALLOW_THREADS;
00576     err = self->db->put(self->db, txn, key, data, flags);
00577     MYDB_END_ALLOW_THREADS;
00578     if (makeDBError(err)) {
00579         return -1;
00580     }
00581     self->haveStat = 0;
00582     return 0;
00583 }
00584 
00585 /* Get a key/data pair from a cursor */
00586 static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
00587                                PyObject *args, PyObject *kwargs, char *format)
00588 {
00589     int err;
00590     PyObject* retval = NULL;
00591     DBT key, data;
00592     int dlen = -1;
00593     int doff = -1;
00594     int flags = 0;
00595     char* kwnames[] = { "flags", "dlen", "doff", NULL };
00596 
00597     if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, kwnames,
00598                                      &flags, &dlen, &doff)) 
00599       return NULL;
00600 
00601     CHECK_CURSOR_NOT_CLOSED(self);
00602 
00603     flags |= extra_flags;
00604     CLEAR_DBT(key);
00605     CLEAR_DBT(data);
00606     if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
00607         /* Tell BerkeleyDB to malloc the return value (thread safe) */
00608         data.flags = DB_DBT_MALLOC;
00609         key.flags = DB_DBT_MALLOC;
00610     }
00611     if (!add_partial_dbt(&data, dlen, doff))
00612         return NULL;
00613 
00614     MYDB_BEGIN_ALLOW_THREADS;
00615     err = self->dbc->c_get(self->dbc, &key, &data, flags);
00616     MYDB_END_ALLOW_THREADS;
00617 
00618     if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
00619         Py_INCREF(Py_None);
00620         retval = Py_None;
00621     }
00622     else if (makeDBError(err)) {
00623         retval = NULL;
00624     }
00625     else {  /* otherwise, success! */
00626 
00627         /* if Recno or Queue, return the key as an Int */
00628         switch (_DB_get_type(self->mydb)) {
00629         case -1:
00630             retval = NULL;
00631             break;
00632 
00633         case DB_RECNO:
00634         case DB_QUEUE:
00635             retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
00636                                    data.data, data.size);
00637             break;
00638         case DB_HASH:
00639         case DB_BTREE:
00640         default:
00641             retval = Py_BuildValue("s#s#", key.data, key.size,
00642                                    data.data, data.size);
00643             break;
00644         }
00645     }
00646     if (!err) {
00647         FREE_DBT(key);
00648         FREE_DBT(data);
00649     }
00650     return retval;
00651 }
00652 
00653 
00654 /* add an integer to a dictionary using the given name as a key */
00655 static void _addIntToDict(PyObject* dict, char *name, int value)
00656 {
00657     PyObject* v = PyInt_FromLong((long) value);
00658     if (!v || PyDict_SetItemString(dict, name, v))
00659         PyErr_Clear();
00660 
00661     Py_XDECREF(v);
00662 }
00663 
00664 
00665 
00666 
00667 /* --------------------------------------------------------------------- */
00668 /* Allocators and deallocators */
00669 
00670 static DBObject*
00671 newDBObject(DBEnvObject* arg, int flags)
00672 {
00673     DBObject* self;
00674     DB_ENV* db_env = NULL;
00675     int err;
00676 
00677 #if PYTHON_API_VERSION <= 1007
00678     /* 1.5 compatibility */
00679     self = PyObject_NEW(DBObject, &DB_Type);
00680 #else
00681     self = PyObject_New(DBObject, &DB_Type);
00682 #endif
00683 
00684     if (self == NULL)
00685         return NULL;
00686 
00687     self->haveStat = 0;
00688     self->flags = 0;
00689     self->setflags = 0;
00690     self->myenvobj = NULL;
00691 #if (DBVER >= 33)
00692     self->associateCallback = NULL;
00693     self->primaryDBType = 0;
00694 #endif
00695 
00696     /* keep a reference to our python DBEnv object */
00697     if (arg) {
00698         Py_INCREF(arg);
00699         self->myenvobj = arg;
00700         db_env = arg->db_env;
00701     }
00702 
00703     if (self->myenvobj)
00704         self->moduleFlags = self->myenvobj->moduleFlags;
00705     else
00706         self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
00707         self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
00708 
00709     MYDB_BEGIN_ALLOW_THREADS;
00710     err = db_create(&self->db, db_env, flags);
00711     self->db->set_errcall(self->db, _db_errorCallback);
00712 #if (DBVER >= 33)
00713     self->db->app_private = (void*)self;
00714 #endif
00715     MYDB_END_ALLOW_THREADS;
00716     if (makeDBError(err)) {
00717         if (self->myenvobj) {
00718             Py_DECREF(self->myenvobj);
00719             self->myenvobj = NULL;
00720         }
00721         self = NULL;
00722     }
00723     return self;
00724 }
00725 
00726 
00727 static void
00728 DB_dealloc(DBObject* self)
00729 {
00730     if (self->db != NULL) {
00731         /* avoid closing a DB when its DBEnv has been closed out from under
00732          * it */
00733         if (!self->myenvobj ||
00734             (self->myenvobj && self->myenvobj->db_env))
00735         {
00736             MYDB_BEGIN_ALLOW_THREADS;
00737             self->db->close(self->db, 0);
00738             MYDB_END_ALLOW_THREADS;
00739  /* if Python 2.1 or better use warning framework */
00740 #if PYTHON_API_VERSION >= 1010
00741         } else {
00742             PyErr_Warn(PyExc_RuntimeWarning,
00743                 "DB could not be closed in destructor: DBEnv already closed");
00744 #endif
00745         }
00746         self->db = NULL;
00747     }
00748     if (self->myenvobj) {
00749         Py_DECREF(self->myenvobj);
00750         self->myenvobj = NULL;
00751     }
00752 #if (DBVER >= 33)
00753     if (self->associateCallback != NULL) {
00754         Py_DECREF(self->associateCallback);
00755         self->associateCallback = NULL;
00756     }
00757 #endif
00758 #if PYTHON_API_VERSION <= 1007
00759     PyMem_DEL(self);
00760 #else
00761     PyObject_Del(self);
00762 #endif
00763 }
00764 
00765 
00766 static DBCursorObject*
00767 newDBCursorObject(DBC* dbc, DBObject* db)
00768 {
00769     DBCursorObject* self;
00770 #if PYTHON_API_VERSION <= 1007
00771     self = PyObject_NEW(DBCursorObject, &DBCursor_Type);
00772 #else
00773     self = PyObject_New(DBCursorObject, &DBCursor_Type);
00774 #endif
00775     if (self == NULL)
00776         return NULL;
00777 
00778     self->dbc = dbc;
00779     self->mydb = db;
00780 #ifdef HAVE_WEAKREF
00781     self->in_weakreflist = NULL;
00782 #endif
00783     Py_INCREF(self->mydb);
00784     return self;
00785 }
00786 
00787 
00788 static void
00789 DBCursor_dealloc(DBCursorObject* self)
00790 {
00791     int err;
00792 
00793 #ifdef HAVE_WEAKREF
00794     if (self->in_weakreflist != NULL) {
00795         PyObject_ClearWeakRefs((PyObject *) self);
00796     }
00797 #endif
00798 
00799     if (self->dbc != NULL) {
00800         MYDB_BEGIN_ALLOW_THREADS;
00801         /* If the underlying database has been closed, we don't
00802            need to do anything. If the environment has been closed
00803            we need to leak, as BerkeleyDB will crash trying to access
00804            the environment. There was an exception when the 
00805            user closed the environment even though there still was
00806            a database open. */
00807         if (self->mydb->db && self->mydb->myenvobj &&
00808             !self->mydb->myenvobj->closed)
00809             err = self->dbc->c_close(self->dbc);
00810         self->dbc = NULL;
00811         MYDB_END_ALLOW_THREADS;
00812     }
00813     Py_XDECREF( self->mydb );
00814 #if PYTHON_API_VERSION <= 1007
00815     PyMem_DEL(self);
00816 #else
00817     PyObject_Del(self);
00818 #endif
00819 }
00820 
00821 
00822 static DBEnvObject*
00823 newDBEnvObject(int flags)
00824 {
00825     int err;
00826     DBEnvObject* self;
00827 #if PYTHON_API_VERSION <= 1007
00828     self = PyObject_NEW(DBEnvObject, &DBEnv_Type);
00829 #else
00830     self = PyObject_New(DBEnvObject, &DBEnv_Type);
00831 #endif
00832 
00833     if (self == NULL)
00834         return NULL;
00835 
00836     self->closed = 1;
00837     self->flags = flags;
00838     self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
00839     self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
00840 
00841     MYDB_BEGIN_ALLOW_THREADS;
00842     err = db_env_create(&self->db_env, flags);
00843     MYDB_END_ALLOW_THREADS;
00844     if (makeDBError(err)) {
00845         self = NULL;
00846     }
00847     else {
00848         self->db_env->set_errcall(self->db_env, _db_errorCallback);
00849     }
00850     return self;
00851 }
00852 
00853 
00854 static void
00855 DBEnv_dealloc(DBEnvObject* self)
00856 {
00857     if (!self->closed) {
00858         MYDB_BEGIN_ALLOW_THREADS;
00859         self->db_env->close(self->db_env, 0);
00860         MYDB_END_ALLOW_THREADS;
00861     }
00862 #if PYTHON_API_VERSION <= 1007
00863     PyMem_DEL(self);
00864 #else
00865     PyObject_Del(self);
00866 #endif
00867 }
00868 
00869 
00870 static DBTxnObject*
00871 newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags)
00872 {
00873     int err;
00874     DBTxnObject* self;
00875 
00876 #if PYTHON_API_VERSION <= 1007
00877     self = PyObject_NEW(DBTxnObject, &DBTxn_Type);
00878 #else
00879     self = PyObject_New(DBTxnObject, &DBTxn_Type);
00880 #endif
00881     if (self == NULL)
00882         return NULL;
00883 
00884     MYDB_BEGIN_ALLOW_THREADS;
00885 #if (DBVER >= 40)
00886     err = myenv->db_env->txn_begin(myenv->db_env, parent, &(self->txn), flags);
00887 #else
00888     err = txn_begin(myenv->db_env, parent, &(self->txn), flags);
00889 #endif
00890     MYDB_END_ALLOW_THREADS;
00891     if (makeDBError(err)) {
00892         self = NULL;
00893     }
00894     return self;
00895 }
00896 
00897 
00898 static void
00899 DBTxn_dealloc(DBTxnObject* self)
00900 {
00901     /* XXX nothing to do for transaction objects?!? */
00902 
00903     /* TODO: if it hasn't been commited, should we abort it? */
00904 
00905 #if PYTHON_API_VERSION <= 1007
00906     PyMem_DEL(self);
00907 #else
00908     PyObject_Del(self);
00909 #endif
00910 }
00911 
00912 
00913 static DBLockObject*
00914 newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj,
00915                 db_lockmode_t lock_mode, int flags)
00916 {
00917     int err;
00918     DBLockObject* self;
00919 
00920 #if PYTHON_API_VERSION <= 1007
00921     self = PyObject_NEW(DBLockObject, &DBLock_Type);
00922 #else
00923     self = PyObject_New(DBLockObject, &DBLock_Type);
00924 #endif
00925     if (self == NULL)
00926         return NULL;
00927 
00928     MYDB_BEGIN_ALLOW_THREADS;
00929 #if (DBVER >= 40)
00930     err = myenv->db_env->lock_get(myenv->db_env, locker, flags, obj, lock_mode,
00931                                   &self->lock);
00932 #else
00933     err = lock_get(myenv->db_env, locker, flags, obj, lock_mode, &self->lock);
00934 #endif
00935     MYDB_END_ALLOW_THREADS;
00936     if (makeDBError(err)) {
00937         self = NULL;
00938     }
00939 
00940     return self;
00941 }
00942 
00943 
00944 static void
00945 DBLock_dealloc(DBLockObject* self)
00946 {
00947     /* TODO: if it hasn't been released, should we do it? */
00948 
00949 #if PYTHON_API_VERSION <= 1007
00950     PyMem_DEL(self);
00951 #else
00952     PyObject_Del(self);
00953 #endif
00954 }
00955 
00956 
00957 /* --------------------------------------------------------------------- */
00958 /* DB methods */
00959 
00960 static PyObject*
00961 DB_append(DBObject* self, PyObject* args)
00962 {
00963     PyObject* txnobj = NULL;
00964     PyObject* dataobj;
00965     db_recno_t recno;
00966     DBT key, data;
00967     DB_TXN *txn = NULL;
00968 
00969     if (!PyArg_ParseTuple(args, "O|O:append", &dataobj, &txnobj))
00970         return NULL;
00971 
00972     CHECK_DB_NOT_CLOSED(self);
00973 
00974     /* make a dummy key out of a recno */
00975     recno = 0;
00976     CLEAR_DBT(key);
00977     key.data = &recno;
00978     key.size = sizeof(recno);
00979     key.ulen = key.size;
00980     key.flags = DB_DBT_USERMEM;
00981 
00982     if (!make_dbt(dataobj, &data)) return NULL;
00983     if (!checkTxnObj(txnobj, &txn)) return NULL;
00984 
00985     if (-1 == _DB_put(self, txn, &key, &data, DB_APPEND))
00986         return NULL;
00987 
00988     return PyInt_FromLong(recno);
00989 }
00990 
00991 
00992 #if (DBVER >= 33)
00993 
00994 static int
00995 _db_associateCallback(DB* db, const DBT* priKey, const DBT* priData,
00996                       DBT* secKey)
00997 {
00998     int       retval = DB_DONOTINDEX;
00999     DBObject* secondaryDB = (DBObject*)db->app_private;
01000     PyObject* callback = secondaryDB->associateCallback;
01001     int       type = secondaryDB->primaryDBType;
01002     PyObject* key;
01003     PyObject* data;
01004     PyObject* args;
01005     PyObject* result;
01006 
01007 
01008     if (callback != NULL) {
01009         MYDB_BEGIN_BLOCK_THREADS;
01010 
01011         if (type == DB_RECNO || type == DB_QUEUE) {
01012             key = PyInt_FromLong( *((db_recno_t*)priKey->data));
01013         }
01014         else {
01015             key  = PyString_FromStringAndSize(priKey->data, priKey->size);
01016         }
01017         data = PyString_FromStringAndSize(priData->data, priData->size);
01018         args = PyTuple_New(2);
01019         PyTuple_SET_ITEM(args, 0, key);  /* steals reference */
01020         PyTuple_SET_ITEM(args, 1, data); /* steals reference */
01021 
01022         result = PyEval_CallObject(callback, args);
01023 
01024         if (result == NULL) {
01025             PyErr_Print();
01026         }
01027         else if (result == Py_None) {
01028             retval = DB_DONOTINDEX;
01029         }
01030         else if (PyInt_Check(result)) {
01031             retval = PyInt_AsLong(result);
01032         }
01033         else if (PyString_Check(result)) {
01034             char* data;
01035             int   size;
01036 
01037             CLEAR_DBT(*secKey);
01038 #if PYTHON_API_VERSION <= 1007
01039             /* 1.5 compatibility */
01040             size = PyString_Size(result);
01041             data = PyString_AsString(result);
01042 #else
01043             PyString_AsStringAndSize(result, &data, &size);
01044 #endif
01045             secKey->flags = DB_DBT_APPMALLOC;   /* DB will free */
01046             secKey->data = malloc(size);        /* TODO, check this */
01047             if (secKey->data) {
01048                 memcpy(secKey->data, data, size);
01049                 secKey->size = size;
01050                 retval = 0;
01051             }
01052             else {
01053                 PyErr_SetString(PyExc_MemoryError,
01054                                 "malloc failed in _db_associateCallback");
01055                 PyErr_Print();
01056             }
01057         }
01058         else {
01059             PyErr_SetString(
01060                PyExc_TypeError,
01061                "DB associate callback should return DB_DONOTINDEX or string.");
01062             PyErr_Print();
01063         }
01064 
01065         Py_DECREF(args);
01066         if (result) {
01067             Py_DECREF(result);
01068         }
01069 
01070         MYDB_END_BLOCK_THREADS;
01071     }
01072     return retval;
01073 }
01074 
01075 
01076 static PyObject*
01077 DB_associate(DBObject* self, PyObject* args, PyObject* kwargs)
01078 {
01079     int err, flags=0;
01080     DBObject* secondaryDB;
01081     PyObject* callback;
01082 #if (DBVER >= 41)
01083     PyObject *txnobj = NULL;
01084     DB_TXN *txn = NULL;
01085     char* kwnames[] = {"secondaryDB", "callback", "flags", "txn", NULL};
01086 #else
01087     char* kwnames[] = {"secondaryDB", "callback", "flags", NULL};
01088 #endif
01089 
01090 #if (DBVER >= 41)
01091     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iO:associate", kwnames,
01092                                      &secondaryDB, &callback, &flags,
01093                                      &txnobj)) {
01094 #else
01095     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:associate", kwnames,
01096                                      &secondaryDB, &callback, &flags)) {
01097 #endif
01098         return NULL;
01099     }
01100 
01101 #if (DBVER >= 41)
01102     if (!checkTxnObj(txnobj, &txn)) return NULL;
01103 #endif
01104 
01105     CHECK_DB_NOT_CLOSED(self);
01106     if (!DBObject_Check(secondaryDB)) {
01107         makeTypeError("DB", (PyObject*)secondaryDB);
01108         return NULL;
01109     }
01110     if (callback == Py_None) {
01111         callback = NULL;
01112     }
01113     else if (!PyCallable_Check(callback)) {
01114         makeTypeError("Callable", callback);
01115         return NULL;
01116     }
01117 
01118     /* Save a reference to the callback in the secondary DB. */
01119     if (self->associateCallback != NULL) {
01120         Py_DECREF(self->associateCallback);
01121     }
01122     Py_INCREF(callback);
01123     secondaryDB->associateCallback = callback;
01124     secondaryDB->primaryDBType = _DB_get_type(self);
01125 
01126     /* PyEval_InitThreads is called here due to a quirk in python 1.5
01127      * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>:
01128      * The global interepreter lock is not initialized until the first
01129      * thread is created using thread.start_new_thread() or fork() is
01130      * called.  that would cause the ALLOW_THREADS here to segfault due
01131      * to a null pointer reference if no threads or child processes
01132      * have been created.  This works around that and is a no-op if
01133      * threads have already been initialized.
01134      *  (see pybsddb-users mailing list post on 2002-08-07)
01135      */
01136 #ifdef WITH_THREAD
01137     PyEval_InitThreads();
01138 #endif
01139     MYDB_BEGIN_ALLOW_THREADS;
01140 #if (DBVER >= 41)
01141     err = self->db->associate(self->db,
01142                               txn,
01143                               secondaryDB->db,
01144                               _db_associateCallback,
01145                               flags);
01146 #else
01147     err = self->db->associate(self->db,
01148                               secondaryDB->db,
01149                               _db_associateCallback,
01150                               flags);
01151 #endif
01152     MYDB_END_ALLOW_THREADS;
01153 
01154     if (err) {
01155         Py_DECREF(self->associateCallback);
01156         self->associateCallback = NULL;
01157         secondaryDB->primaryDBType = 0;
01158     }
01159 
01160     RETURN_IF_ERR();
01161     RETURN_NONE();
01162 }
01163 
01164 
01165 #endif
01166 
01167 
01168 static PyObject*
01169 DB_close(DBObject* self, PyObject* args)
01170 {
01171     int err, flags=0;
01172     if (!PyArg_ParseTuple(args,"|i:close", &flags))
01173         return NULL;
01174     if (self->db != NULL) {
01175         if (self->myenvobj)
01176             CHECK_ENV_NOT_CLOSED(self->myenvobj);
01177         err = self->db->close(self->db, flags);
01178         self->db = NULL;
01179         RETURN_IF_ERR();
01180     }
01181     RETURN_NONE();
01182 }
01183 
01184 
01185 #if (DBVER >= 32)
01186 static PyObject*
01187 _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
01188 {
01189     int err, flags=0, type;
01190     PyObject* txnobj = NULL;
01191     PyObject* retval = NULL;
01192     DBT key, data;
01193     DB_TXN *txn = NULL;
01194     char* kwnames[] = { "txn", "flags", NULL };
01195 
01196     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:consume", kwnames,
01197                                      &txnobj, &flags))
01198         return NULL;
01199 
01200     CHECK_DB_NOT_CLOSED(self);
01201     type = _DB_get_type(self);
01202     if (type == -1)
01203         return NULL;
01204     if (type != DB_QUEUE) {
01205         PyErr_SetString(PyExc_TypeError,
01206                         "Consume methods only allowed for Queue DB's");
01207         return NULL;
01208     }
01209     if (!checkTxnObj(txnobj, &txn))
01210         return NULL;
01211 
01212     CLEAR_DBT(key);
01213     CLEAR_DBT(data);
01214     if (CHECK_DBFLAG(self, DB_THREAD)) {
01215         /* Tell BerkeleyDB to malloc the return value (thread safe) */
01216         data.flags = DB_DBT_MALLOC;
01217         key.flags = DB_DBT_MALLOC;
01218     }
01219 
01220     MYDB_BEGIN_ALLOW_THREADS;
01221     err = self->db->get(self->db, txn, &key, &data, flags|consume_flag);
01222     MYDB_END_ALLOW_THREADS;
01223 
01224     if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
01225         err = 0;
01226         Py_INCREF(Py_None);
01227         retval = Py_None;
01228     }
01229     else if (!err) {
01230         retval = Py_BuildValue("s#s#", key.data, key.size, data.data,
01231                                data.size);
01232         FREE_DBT(key);
01233         FREE_DBT(data);
01234     }
01235 
01236     RETURN_IF_ERR();
01237     return retval;
01238 }
01239 
01240 static PyObject*
01241 DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
01242 {
01243     return _DB_consume(self, args, kwargs, DB_CONSUME);
01244 }
01245 
01246 static PyObject*
01247 DB_consume_wait(DBObject* self, PyObject* args, PyObject* kwargs,
01248                 int consume_flag)
01249 {
01250     return _DB_consume(self, args, kwargs, DB_CONSUME_WAIT);
01251 }
01252 #endif
01253 
01254 
01255 
01256 static PyObject*
01257 DB_cursor(DBObject* self, PyObject* args, PyObject* kwargs)
01258 {
01259     int err, flags=0;
01260     DBC* dbc;
01261     PyObject* txnobj = NULL;
01262     DB_TXN *txn = NULL;
01263     char* kwnames[] = { "txn", "flags", NULL };
01264 
01265     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames,
01266                                      &txnobj, &flags))
01267         return NULL;
01268     CHECK_DB_NOT_CLOSED(self);
01269     if (!checkTxnObj(txnobj, &txn))
01270         return NULL;
01271 
01272     MYDB_BEGIN_ALLOW_THREADS;
01273     err = self->db->cursor(self->db, txn, &dbc, flags);
01274     MYDB_END_ALLOW_THREADS;
01275     RETURN_IF_ERR();
01276     return (PyObject*) newDBCursorObject(dbc, self);
01277 }
01278 
01279 
01280 static PyObject*
01281 DB_delete(DBObject* self, PyObject* args, PyObject* kwargs)
01282 {
01283     PyObject* txnobj = NULL;
01284     int flags = 0;
01285     PyObject* keyobj;
01286     DBT key;
01287     DB_TXN *txn = NULL;
01288     char* kwnames[] = { "key", "txn", "flags", NULL };
01289 
01290     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:delete", kwnames,
01291                                      &keyobj, &txnobj, &flags))
01292         return NULL;
01293     CHECK_DB_NOT_CLOSED(self);
01294     if (!make_key_dbt(self, keyobj, &key, NULL))
01295         return NULL;
01296     if (!checkTxnObj(txnobj, &txn))
01297         return NULL;
01298 
01299     if (-1 == _DB_delete(self, txn, &key, 0))
01300         return NULL;
01301 
01302     FREE_DBT(key);
01303     RETURN_NONE();
01304 }
01305 
01306 
01307 static PyObject*
01308 DB_fd(DBObject* self, PyObject* args)
01309 {
01310     int err, the_fd;
01311 
01312     if (!PyArg_ParseTuple(args,":fd"))
01313         return NULL;
01314     CHECK_DB_NOT_CLOSED(self);
01315 
01316     MYDB_BEGIN_ALLOW_THREADS;
01317     err = self->db->fd(self->db, &the_fd);
01318     MYDB_END_ALLOW_THREADS;
01319     RETURN_IF_ERR();
01320     return PyInt_FromLong(the_fd);
01321 }
01322 
01323 
01324 static PyObject*
01325 DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
01326 {
01327     int err, flags=0;
01328     PyObject* txnobj = NULL;
01329     PyObject* keyobj;
01330     PyObject* dfltobj = NULL;
01331     PyObject* retval = NULL;
01332     int dlen = -1;
01333     int doff = -1;
01334     DBT key, data;
01335     DB_TXN *txn = NULL;
01336     char* kwnames[] = {"key", "default", "txn", "flags", "dlen", "doff", NULL};
01337 
01338     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:get", kwnames,
01339                                      &keyobj, &dfltobj, &txnobj, &flags, &dlen,
01340                                      &doff))
01341         return NULL;
01342 
01343     CHECK_DB_NOT_CLOSED(self);
01344     if (!make_key_dbt(self, keyobj, &key, &flags))
01345         return NULL;
01346     if (!checkTxnObj(txnobj, &txn))
01347         return NULL;
01348 
01349     CLEAR_DBT(data);
01350     if (CHECK_DBFLAG(self, DB_THREAD)) {
01351         /* Tell BerkeleyDB to malloc the return value (thread safe) */
01352         data.flags = DB_DBT_MALLOC;
01353     }
01354     if (!add_partial_dbt(&data, dlen, doff))
01355         return NULL;
01356 
01357     MYDB_BEGIN_ALLOW_THREADS;
01358     err = self->db->get(self->db, txn, &key, &data, flags);
01359     MYDB_END_ALLOW_THREADS;
01360 
01361     if ((err == DB_NOTFOUND) && (dfltobj != NULL)) {
01362         err = 0;
01363         Py_INCREF(dfltobj);
01364         retval = dfltobj;
01365     }
01366     else if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
01367         err = 0;
01368         Py_INCREF(Py_None);
01369         retval = Py_None;
01370     }
01371     else if (!err) {
01372         if (flags & DB_SET_RECNO) /* return both key and data */
01373             retval = Py_BuildValue("s#s#", key.data, key.size, data.data,
01374                                    data.size);
01375         else /* return just the data */
01376             retval = PyString_FromStringAndSize((char*)data.data, data.size);
01377         FREE_DBT(key);
01378         FREE_DBT(data);
01379     }
01380 
01381     RETURN_IF_ERR();
01382     return retval;
01383 }
01384 
01385 
01386 /* Return size of entry */
01387 static PyObject*
01388 DB_get_size(DBObject* self, PyObject* args, PyObject* kwargs)
01389 {
01390     int err, flags=0;
01391     PyObject* txnobj = NULL;
01392     PyObject* keyobj;
01393     PyObject* retval = NULL;
01394     DBT key, data;
01395     DB_TXN *txn = NULL;
01396     char* kwnames[] = { "key", "txn", NULL };
01397 
01398     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:get_size", kwnames,
01399                                      &keyobj, &txnobj))
01400         return NULL;
01401     CHECK_DB_NOT_CLOSED(self);
01402     if (!make_key_dbt(self, keyobj, &key, &flags))
01403         return NULL;
01404     if (!checkTxnObj(txnobj, &txn))
01405         return NULL;
01406     CLEAR_DBT(data);
01407 
01408     /* We don't allocate any memory, forcing a ENOMEM error and thus
01409        getting the record size. */
01410     data.flags = DB_DBT_USERMEM;
01411     data.ulen = 0;
01412     MYDB_BEGIN_ALLOW_THREADS;
01413     err = self->db->get(self->db, txn, &key, &data, flags);
01414     MYDB_END_ALLOW_THREADS;
01415     if (err == ENOMEM) {
01416         retval = PyInt_FromLong((long)data.size);
01417         err = 0;
01418     }
01419 
01420     FREE_DBT(key);
01421     FREE_DBT(data);
01422     RETURN_IF_ERR();
01423     return retval;
01424 }
01425 
01426 
01427 static PyObject*
01428 DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
01429 {
01430     int err, flags=0;
01431     PyObject* txnobj = NULL;
01432     PyObject* keyobj;
01433     PyObject* dataobj;
01434     PyObject* retval = NULL;
01435     DBT key, data;
01436     DB_TXN *txn = NULL;
01437     char* kwnames[] = { "key", "data", "txn", "flags", NULL };
01438 
01439 
01440     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oi:get_both", kwnames,
01441                                      &keyobj, &dataobj, &txnobj, &flags))
01442         return NULL;
01443 
01444     CHECK_DB_NOT_CLOSED(self);
01445     if (!make_key_dbt(self, keyobj, &key, NULL))
01446         return NULL;
01447     if (!make_dbt(dataobj, &data))
01448         return NULL;
01449     if (!checkTxnObj(txnobj, &txn))
01450         return NULL;
01451 
01452     flags |= DB_GET_BOTH;
01453 
01454     if (CHECK_DBFLAG(self, DB_THREAD)) {
01455         /* Tell BerkeleyDB to malloc the return value (thread safe) */
01456         data.flags = DB_DBT_MALLOC;
01457         /* TODO: Is this flag needed?  We're passing a data object that should
01458                  match what's in the DB, so there should be no need to malloc.
01459                  We run the risk of freeing something twice!  Check this. */
01460     }
01461 
01462     MYDB_BEGIN_ALLOW_THREADS;
01463     err = self->db->get(self->db, txn, &key, &data, flags);
01464     MYDB_END_ALLOW_THREADS;
01465 
01466     if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
01467         err = 0;
01468         Py_INCREF(Py_None);
01469         retval = Py_None;
01470     }
01471     else if (!err) {
01472         retval = PyString_FromStringAndSize((char*)data.data, data.size);
01473         FREE_DBT(data); /* Only if retrieval was successful */
01474     }
01475 
01476     FREE_DBT(key);
01477     RETURN_IF_ERR();
01478     return retval;
01479 }
01480 
01481 
01482 static PyObject*
01483 DB_get_byteswapped(DBObject* self, PyObject* args)
01484 {
01485 #if (DBVER >= 33)
01486     int err = 0;
01487 #endif
01488     int retval = -1;
01489 
01490     if (!PyArg_ParseTuple(args,":get_byteswapped"))
01491         return NULL;
01492     CHECK_DB_NOT_CLOSED(self);
01493 
01494 #if (DBVER >= 33)
01495     MYDB_BEGIN_ALLOW_THREADS;
01496     err = self->db->get_byteswapped(self->db, &retval);
01497     MYDB_END_ALLOW_THREADS;
01498     RETURN_IF_ERR();
01499 #else
01500     MYDB_BEGIN_ALLOW_THREADS;
01501     retval = self->db->get_byteswapped(self->db);
01502     MYDB_END_ALLOW_THREADS;
01503 #endif
01504     return PyInt_FromLong(retval);
01505 }
01506 
01507 
01508 static PyObject*
01509 DB_get_type(DBObject* self, PyObject* args)
01510 {
01511     int type;
01512 
01513     if (!PyArg_ParseTuple(args,":get_type"))
01514         return NULL;
01515     CHECK_DB_NOT_CLOSED(self);
01516 
01517     MYDB_BEGIN_ALLOW_THREADS;
01518     type = _DB_get_type(self);
01519     MYDB_END_ALLOW_THREADS;
01520     if (type == -1)
01521         return NULL;
01522     return PyInt_FromLong(type);
01523 }
01524 
01525 
01526 static PyObject*
01527 DB_join(DBObject* self, PyObject* args)
01528 {
01529     int err, flags=0;
01530     int length, x;
01531     PyObject* cursorsObj;
01532     DBC** cursors;
01533     DBC*  dbc;
01534 
01535 
01536     if (!PyArg_ParseTuple(args,"O|i:join", &cursorsObj, &flags))
01537         return NULL;
01538 
01539     CHECK_DB_NOT_CLOSED(self);
01540 
01541     if (!PySequence_Check(cursorsObj)) {
01542         PyErr_SetString(PyExc_TypeError,
01543                         "Sequence of DBCursor objects expected");
01544         return NULL;
01545     }
01546 
01547     length = PyObject_Length(cursorsObj);
01548     cursors = malloc((length+1) * sizeof(DBC*));
01549     cursors[length] = NULL;
01550     for (x=0; x<length; x++) {
01551         PyObject* item = PySequence_GetItem(cursorsObj, x);
01552         if (!DBCursorObject_Check(item)) {
01553             PyErr_SetString(PyExc_TypeError,
01554                             "Sequence of DBCursor objects expected");
01555             free(cursors);
01556             return NULL;
01557         }
01558         cursors[x] = ((DBCursorObject*)item)->dbc;
01559     }
01560 
01561     MYDB_BEGIN_ALLOW_THREADS;
01562     err = self->db->join(self->db, cursors, &dbc, flags);
01563     MYDB_END_ALLOW_THREADS;
01564     free(cursors);
01565     RETURN_IF_ERR();
01566 
01567     /* FIXME: this is a buggy interface.  The returned cursor
01568        contains internal references to the passed in cursors
01569        but does not hold python references to them or prevent
01570        them from being closed prematurely.  This can cause
01571        python to crash when things are done in the wrong order. */
01572     return (PyObject*) newDBCursorObject(dbc, self);
01573 }
01574 
01575 
01576 static PyObject*
01577 DB_key_range(DBObject* self, PyObject* args, PyObject* kwargs)
01578 {
01579     int err, flags=0;
01580     PyObject* txnobj = NULL;
01581     PyObject* keyobj;
01582     DBT key;
01583     DB_TXN *txn = NULL;
01584     DB_KEY_RANGE range;
01585     char* kwnames[] = { "key", "txn", "flags", NULL };
01586 
01587     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:key_range", kwnames,
01588                                      &keyobj, &txnobj, &flags))
01589         return NULL;
01590     CHECK_DB_NOT_CLOSED(self);
01591     if (!make_dbt(keyobj, &key))
01592         /* BTree only, don't need to allow for an int key */
01593         return NULL;
01594     if (!checkTxnObj(txnobj, &txn))
01595         return NULL;
01596 
01597     MYDB_BEGIN_ALLOW_THREADS;
01598     err = self->db->key_range(self->db, txn, &key, &range, flags);
01599     MYDB_END_ALLOW_THREADS;
01600 
01601     RETURN_IF_ERR();
01602     return Py_BuildValue("ddd", range.less, range.equal, range.greater);
01603 }
01604 
01605 
01606 static PyObject*
01607 DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
01608 {
01609     int err, type = DB_UNKNOWN, flags=0, mode=0660;
01610     char* filename = NULL;
01611     char* dbname = NULL;
01612 #if (DBVER >= 41)
01613     PyObject *txnobj = NULL;
01614     DB_TXN *txn = NULL;
01615     /* with dbname */
01616     char* kwnames[] = {
01617         "filename", "dbname", "dbtype", "flags", "mode", "txn", NULL};
01618     /* without dbname */
01619     char* kwnames_basic[] = {
01620         "filename", "dbtype", "flags", "mode", "txn", NULL};
01621 #else
01622     /* with dbname */
01623     char* kwnames[] = {
01624         "filename", "dbname", "dbtype", "flags", "mode", NULL};
01625     /* without dbname */
01626     char* kwnames_basic[] = {
01627         "filename", "dbtype", "flags", "mode", NULL};
01628 #endif
01629 
01630 #if (DBVER >= 41)
01631     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziiiO:open", kwnames,
01632                                      &filename, &dbname, &type, &flags, &mode,
01633                                      &txnobj))
01634 #else
01635     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziii:open", kwnames,
01636                                      &filename, &dbname, &type, &flags,
01637                                      &mode))
01638 #endif
01639     {
01640         PyErr_Clear();
01641         type = DB_UNKNOWN; flags = 0; mode = 0660;
01642         filename = NULL; dbname = NULL;
01643 #if (DBVER >= 41)
01644         if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iiiO:open",
01645                                          kwnames_basic,
01646                                          &filename, &type, &flags, &mode,
01647                                          &txnobj))
01648             return NULL;
01649 #else
01650         if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iii:open",
01651                                          kwnames_basic,
01652                                          &filename, &type, &flags, &mode))
01653             return NULL;
01654 #endif
01655     }
01656 
01657 #if (DBVER >= 41)
01658     if (!checkTxnObj(txnobj, &txn)) return NULL;
01659 #endif
01660 
01661     if (NULL == self->db) {
01662         PyErr_SetObject(DBError, Py_BuildValue("(is)", 0,
01663                                  "Cannot call open() twice for DB object"));
01664         return NULL;
01665     }
01666 
01667 #if 0 && (DBVER >= 41)
01668     if ((!txn) && (txnobj != Py_None) && self->myenvobj
01669         && (self->myenvobj->flags & DB_INIT_TXN))
01670     {
01671         /* If no 'txn' parameter was supplied (no DbTxn object and None was not
01672          * explicitly passed) but we are in a transaction ready environment:
01673          *   add DB_AUTO_COMMIT to allow for older pybsddb apps using transactions
01674          *   to work on BerkeleyDB 4.1 without needing to modify their
01675          *   DBEnv or DB open calls. 
01676          * TODO make this behaviour of the library configurable.
01677          */
01678         flags |= DB_AUTO_COMMIT;
01679     }
01680 #endif
01681 
01682     MYDB_BEGIN_ALLOW_THREADS;
01683 #if (DBVER >= 41)
01684     err = self->db->open(self->db, txn, filename, dbname, type, flags, mode);
01685 #else
01686     err = self->db->open(self->db, filename, dbname, type, flags, mode);
01687 #endif
01688     MYDB_END_ALLOW_THREADS;
01689     if (makeDBError(err)) {
01690         self->db->close(self->db, 0);
01691         self->db = NULL;
01692         return NULL;
01693     }
01694 
01695     self->flags = flags;
01696     RETURN_NONE();
01697 }
01698 
01699 
01700 static PyObject*
01701 DB_put(DBObject* self, PyObject* args, PyObject* kwargs)
01702 {
01703     int flags=0;
01704     PyObject* txnobj = NULL;
01705     int dlen = -1;
01706     int doff = -1;
01707     PyObject* keyobj, *dataobj, *retval;
01708     DBT key, data;
01709     DB_TXN *txn = NULL;
01710     char* kwnames[] = { "key", "data", "txn", "flags", "dlen", "doff", NULL };
01711 
01712     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oiii:put", kwnames,
01713                          &keyobj, &dataobj, &txnobj, &flags, &dlen, &doff))
01714         return NULL;
01715 
01716     CHECK_DB_NOT_CLOSED(self);
01717     if (!make_key_dbt(self, keyobj, &key, NULL)) return NULL;
01718     if (!make_dbt(dataobj, &data)) return NULL;
01719     if (!add_partial_dbt(&data, dlen, doff)) return NULL;
01720     if (!checkTxnObj(txnobj, &txn)) return NULL;
01721 
01722     if (-1 == _DB_put(self, txn, &key, &data, flags)) {
01723         FREE_DBT(key);
01724         return NULL;
01725     }
01726 
01727     if (flags & DB_APPEND)
01728         retval = PyInt_FromLong(*((db_recno_t*)key.data));
01729     else {
01730         retval = Py_None;
01731         Py_INCREF(retval);
01732     }
01733     FREE_DBT(key);
01734     return retval;
01735 }
01736 
01737 
01738 
01739 static PyObject*
01740 DB_remove(DBObject* self, PyObject* args, PyObject* kwargs)
01741 {
01742     char* filename;
01743     char* database = NULL;
01744     int err, flags=0;
01745     char* kwnames[] = { "filename", "dbname", "flags", NULL};
01746 
01747     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zi:remove", kwnames,
01748                                      &filename, &database, &flags))
01749         return NULL;
01750     CHECK_DB_NOT_CLOSED(self);
01751 
01752     err = self->db->remove(self->db, filename, database, flags);
01753     self->db = NULL;
01754     RETURN_IF_ERR();
01755     RETURN_NONE();
01756 }
01757 
01758 
01759 
01760 static PyObject*
01761 DB_rename(DBObject* self, PyObject* args)
01762 {
01763     char* filename;
01764     char* database;
01765     char* newname;
01766     int err, flags=0;
01767 
01768     if (!PyArg_ParseTuple(args, "sss|i:rename", &filename, &database, &newname,
01769                           &flags))
01770         return NULL;
01771     CHECK_DB_NOT_CLOSED(self);
01772 
01773     MYDB_BEGIN_ALLOW_THREADS;
01774     err = self->db->rename(self->db, filename, database, newname, flags);
01775     MYDB_END_ALLOW_THREADS;
01776     RETURN_IF_ERR();
01777     RETURN_NONE();
01778 }
01779 
01780 
01781 static PyObject*
01782 DB_set_bt_minkey(DBObject* self, PyObject* args)
01783 {
01784     int err, minkey;
01785 
01786     if (!PyArg_ParseTuple(args,"i:set_bt_minkey", &minkey ))
01787         return NULL;
01788     CHECK_DB_NOT_CLOSED(self);
01789 
01790     MYDB_BEGIN_ALLOW_THREADS;
01791     err = self->db->set_bt_minkey(self->db, minkey);
01792     MYDB_END_ALLOW_THREADS;
01793     RETURN_IF_ERR();
01794     RETURN_NONE();
01795 }
01796 
01797 
01798 static PyObject*
01799 DB_set_cachesize(DBObject* self, PyObject* args)
01800 {
01801     int err;
01802     int gbytes = 0, bytes = 0, ncache = 0;
01803 
01804     if (!PyArg_ParseTuple(args,"ii|i:set_cachesize",
01805                           &gbytes,&bytes,&ncache))
01806         return NULL;
01807     CHECK_DB_NOT_CLOSED(self);
01808 
01809     MYDB_BEGIN_ALLOW_THREADS;
01810     err = self->db->set_cachesize(self->db, gbytes, bytes, ncache);
01811     MYDB_END_ALLOW_THREADS;
01812     RETURN_IF_ERR();
01813     RETURN_NONE();
01814 }
01815 
01816 
01817 static PyObject*
01818 DB_set_flags(DBObject* self, PyObject* args)
01819 {
01820     int err, flags;
01821 
01822     if (!PyArg_ParseTuple(args,"i:set_flags", &flags))
01823         return NULL;
01824     CHECK_DB_NOT_CLOSED(self);
01825 
01826     MYDB_BEGIN_ALLOW_THREADS;
01827     err = self->db->set_flags(self->db, flags);
01828     MYDB_END_ALLOW_THREADS;
01829     RETURN_IF_ERR();
01830 
01831     self->setflags |= flags;
01832     RETURN_NONE();
01833 }
01834 
01835 
01836 static PyObject*
01837 DB_set_h_ffactor(DBObject* self, PyObject* args)
01838 {
01839     int err, ffactor;
01840 
01841     if (!PyArg_ParseTuple(args,"i:set_h_ffactor", &ffactor))
01842         return NULL;
01843     CHECK_DB_NOT_CLOSED(self);
01844 
01845     MYDB_BEGIN_ALLOW_THREADS;
01846     err = self->db->set_h_ffactor(self->db, ffactor);
01847     MYDB_END_ALLOW_THREADS;
01848     RETURN_IF_ERR();
01849     RETURN_NONE();
01850 }
01851 
01852 
01853 static PyObject*
01854 DB_set_h_nelem(DBObject* self, PyObject* args)
01855 {
01856     int err, nelem;
01857 
01858     if (!PyArg_ParseTuple(args,"i:set_h_nelem", &nelem))
01859         return NULL;
01860     CHECK_DB_NOT_CLOSED(self);
01861 
01862     MYDB_BEGIN_ALLOW_THREADS;
01863     err = self->db->set_h_nelem(self->db, nelem);
01864     MYDB_END_ALLOW_THREADS;
01865     RETURN_IF_ERR();
01866     RETURN_NONE();
01867 }
01868 
01869 
01870 static PyObject*
01871 DB_set_lorder(DBObject* self, PyObject* args)
01872 {
01873     int err, lorder;
01874 
01875     if (!PyArg_ParseTuple(args,"i:set_lorder", &lorder))
01876         return NULL;
01877     CHECK_DB_NOT_CLOSED(self);
01878 
01879     MYDB_BEGIN_ALLOW_THREADS;
01880     err = self->db->set_lorder(self->db, lorder);
01881     MYDB_END_ALLOW_THREADS;
01882     RETURN_IF_ERR();
01883     RETURN_NONE();
01884 }
01885 
01886 
01887 static PyObject*
01888 DB_set_pagesize(DBObject* self, PyObject* args)
01889 {
01890     int err, pagesize;
01891 
01892     if (!PyArg_ParseTuple(args,"i:set_pagesize", &pagesize))
01893         return NULL;
01894     CHECK_DB_NOT_CLOSED(self);
01895 
01896     MYDB_BEGIN_ALLOW_THREADS;
01897     err = self->db->set_pagesize(self->db, pagesize);
01898     MYDB_END_ALLOW_THREADS;
01899     RETURN_IF_ERR();
01900     RETURN_NONE();
01901 }
01902 
01903 
01904 static PyObject*
01905 DB_set_re_delim(DBObject* self, PyObject* args)
01906 {
01907     int err;
01908     char delim;
01909 
01910     if (!PyArg_ParseTuple(args,"b:set_re_delim", &delim)) {
01911         PyErr_Clear();
01912         if (!PyArg_ParseTuple(args,"c:set_re_delim", &delim))
01913             return NULL;
01914     }
01915 
01916     CHECK_DB_NOT_CLOSED(self);
01917 
01918     MYDB_BEGIN_ALLOW_THREADS;
01919     err = self->db->set_re_delim(self->db, delim);
01920     MYDB_END_ALLOW_THREADS;
01921     RETURN_IF_ERR();
01922     RETURN_NONE();
01923 }
01924 
01925 static PyObject*
01926 DB_set_re_len(DBObject* self, PyObject* args)
01927 {
01928     int err, len;
01929 
01930     if (!PyArg_ParseTuple(args,"i:set_re_len", &len))
01931         return NULL;
01932     CHECK_DB_NOT_CLOSED(self);
01933 
01934     MYDB_BEGIN_ALLOW_THREADS;
01935     err = self->db->set_re_len(self->db, len);
01936     MYDB_END_ALLOW_THREADS;
01937     RETURN_IF_ERR();
01938     RETURN_NONE();
01939 }
01940 
01941 
01942 static PyObject*
01943 DB_set_re_pad(DBObject* self, PyObject* args)
01944 {
01945     int err;
01946     char pad;
01947 
01948     if (!PyArg_ParseTuple(args,"b:set_re_pad", &pad)) {
01949         PyErr_Clear();
01950         if (!PyArg_ParseTuple(args,"c:set_re_pad", &pad))
01951             return NULL;
01952     }
01953     CHECK_DB_NOT_CLOSED(self);
01954 
01955     MYDB_BEGIN_ALLOW_THREADS;
01956     err = self->db->set_re_pad(self->db, pad);
01957     MYDB_END_ALLOW_THREADS;
01958     RETURN_IF_ERR();
01959     RETURN_NONE();
01960 }
01961 
01962 
01963 static PyObject*
01964 DB_set_re_source(DBObject* self, PyObject* args)
01965 {
01966     int err;
01967     char *re_source;
01968 
01969     if (!PyArg_ParseTuple(args,"s:set_re_source", &re_source))
01970         return NULL;
01971     CHECK_DB_NOT_CLOSED(self);
01972 
01973     MYDB_BEGIN_ALLOW_THREADS;
01974     err = self->db->set_re_source(self->db, re_source);
01975     MYDB_END_ALLOW_THREADS;
01976     RETURN_IF_ERR();
01977     RETURN_NONE();
01978 }
01979 
01980 
01981 #if (DBVER >= 32)
01982 static PyObject*
01983 DB_set_q_extentsize(DBObject* self, PyObject* args)
01984 {
01985     int err;
01986     int extentsize;
01987 
01988     if (!PyArg_ParseTuple(args,"i:set_q_extentsize", &extentsize))
01989         return NULL;
01990     CHECK_DB_NOT_CLOSED(self);
01991 
01992     MYDB_BEGIN_ALLOW_THREADS;
01993     err = self->db->set_q_extentsize(self->db, extentsize);
01994     MYDB_END_ALLOW_THREADS;
01995     RETURN_IF_ERR();
01996     RETURN_NONE();
01997 }
01998 #endif
01999 
02000 static PyObject*
02001 DB_stat(DBObject* self, PyObject* args)
02002 {
02003     int err, flags = 0, type;
02004     void* sp;
02005     PyObject* d;
02006 
02007 
02008     if (!PyArg_ParseTuple(args, "|i:stat", &flags))
02009         return NULL;
02010     CHECK_DB_NOT_CLOSED(self);
02011 
02012     MYDB_BEGIN_ALLOW_THREADS;
02013 #if (DBVER >= 33)
02014     err = self->db->stat(self->db, &sp, flags);
02015 #else
02016     err = self->db->stat(self->db, &sp, NULL, flags);
02017 #endif
02018     MYDB_END_ALLOW_THREADS;
02019     RETURN_IF_ERR();
02020 
02021     self->haveStat = 1;
02022 
02023     /* Turn the stat structure into a dictionary */
02024     type = _DB_get_type(self);
02025     if ((type == -1) || ((d = PyDict_New()) == NULL)) {
02026         free(sp);
02027         return NULL;
02028     }
02029 
02030 #define MAKE_HASH_ENTRY(name)  _addIntToDict(d, #name, ((DB_HASH_STAT*)sp)->hash_##name)
02031 #define MAKE_BT_ENTRY(name)    _addIntToDict(d, #name, ((DB_BTREE_STAT*)sp)->bt_##name)
02032 #define MAKE_QUEUE_ENTRY(name) _addIntToDict(d, #name, ((DB_QUEUE_STAT*)sp)->qs_##name)
02033 
02034     switch (type) {
02035     case DB_HASH:
02036         MAKE_HASH_ENTRY(magic);
02037         MAKE_HASH_ENTRY(version);
02038         MAKE_HASH_ENTRY(nkeys);
02039         MAKE_HASH_ENTRY(ndata);
02040         MAKE_HASH_ENTRY(pagesize);
02041 #if (DBVER < 41)
02042         MAKE_HASH_ENTRY(nelem);
02043 #endif
02044         MAKE_HASH_ENTRY(ffactor);
02045         MAKE_HASH_ENTRY(buckets);
02046         MAKE_HASH_ENTRY(free);
02047         MAKE_HASH_ENTRY(bfree);
02048         MAKE_HASH_ENTRY(bigpages);
02049         MAKE_HASH_ENTRY(big_bfree);
02050         MAKE_HASH_ENTRY(overflows);
02051         MAKE_HASH_ENTRY(ovfl_free);
02052         MAKE_HASH_ENTRY(dup);
02053         MAKE_HASH_ENTRY(dup_free);
02054         break;
02055 
02056     case DB_BTREE:
02057     case DB_RECNO:
02058         MAKE_BT_ENTRY(magic);
02059         MAKE_BT_ENTRY(version);
02060         MAKE_BT_ENTRY(nkeys);
02061         MAKE_BT_ENTRY(ndata);
02062         MAKE_BT_ENTRY(pagesize);
02063         MAKE_BT_ENTRY(minkey);
02064         MAKE_BT_ENTRY(re_len);
02065         MAKE_BT_ENTRY(re_pad);
02066         MAKE_BT_ENTRY(levels);
02067         MAKE_BT_ENTRY(int_pg);
02068         MAKE_BT_ENTRY(leaf_pg);
02069         MAKE_BT_ENTRY(dup_pg);
02070         MAKE_BT_ENTRY(over_pg);
02071         MAKE_BT_ENTRY(free);
02072         MAKE_BT_ENTRY(int_pgfree);
02073         MAKE_BT_ENTRY(leaf_pgfree);
02074         MAKE_BT_ENTRY(dup_pgfree);
02075         MAKE_BT_ENTRY(over_pgfree);
02076         break;
02077 
02078     case DB_QUEUE:
02079         MAKE_QUEUE_ENTRY(magic);
02080         MAKE_QUEUE_ENTRY(version);
02081         MAKE_QUEUE_ENTRY(nkeys);
02082         MAKE_QUEUE_ENTRY(ndata);
02083         MAKE_QUEUE_ENTRY(pagesize);
02084         MAKE_QUEUE_ENTRY(pages);
02085         MAKE_QUEUE_ENTRY(re_len);
02086         MAKE_QUEUE_ENTRY(re_pad);
02087         MAKE_QUEUE_ENTRY(pgfree);
02088 #if (DBVER == 31)
02089         MAKE_QUEUE_ENTRY(start);
02090 #endif
02091         MAKE_QUEUE_ENTRY(first_recno);
02092         MAKE_QUEUE_ENTRY(cur_recno);
02093         break;
02094 
02095     default:
02096         PyErr_SetString(PyExc_TypeError, "Unknown DB type, unable to stat");
02097         Py_DECREF(d);
02098         d = NULL;
02099     }
02100 
02101 #undef MAKE_HASH_ENTRY
02102 #undef MAKE_BT_ENTRY
02103 #undef MAKE_QUEUE_ENTRY
02104 
02105     free(sp);
02106     return d;
02107 }
02108 
02109 static PyObject*
02110 DB_sync(DBObject* self, PyObject* args)
02111 {
02112     int err;
02113     int flags = 0;
02114 
02115     if (!PyArg_ParseTuple(args,"|i:sync", &flags ))
02116         return NULL;
02117     CHECK_DB_NOT_CLOSED(self);
02118 
02119     MYDB_BEGIN_ALLOW_THREADS;
02120     err = self->db->sync(self->db, flags);
02121     MYDB_END_ALLOW_THREADS;
02122     RETURN_IF_ERR();
02123     RETURN_NONE();
02124 }
02125 
02126 
02127 #if (DBVER >= 33)
02128 static PyObject*
02129 DB_truncate(DBObject* self, PyObject* args, PyObject* kwargs)
02130 {
02131     int err, flags=0;
02132     u_int32_t count=0;
02133     PyObject* txnobj = NULL;
02134     DB_TXN *txn = NULL;
02135     char* kwnames[] = { "txn", "flags", NULL };
02136 
02137     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames,
02138                                      &txnobj, &flags))
02139         return NULL;
02140     CHECK_DB_NOT_CLOSED(self);
02141     if (!checkTxnObj(txnobj, &txn))
02142         return NULL;
02143 
02144     MYDB_BEGIN_ALLOW_THREADS;
02145     err = self->db->truncate(self->db, txn, &count, flags);
02146     MYDB_END_ALLOW_THREADS;
02147     RETURN_IF_ERR();
02148     return PyInt_FromLong(count);
02149 }
02150 #endif
02151 
02152 
02153 static PyObject*
02154 DB_upgrade(DBObject* self, PyObject* args)
02155 {
02156     int err, flags=0;
02157     char *filename;
02158 
02159     if (!PyArg_ParseTuple(args,"s|i:upgrade", &filename, &flags))
02160         return NULL;
02161     CHECK_DB_NOT_CLOSED(self);
02162 
02163     MYDB_BEGIN_ALLOW_THREADS;
02164     err = self->db->upgrade(self->db, filename, flags);
02165     MYDB_END_ALLOW_THREADS;
02166     RETURN_IF_ERR();
02167     RETURN_NONE();
02168 }
02169 
02170 
02171 static PyObject*
02172 DB_verify(DBObject* self, PyObject* args, PyObject* kwargs)
02173 {
02174     int err, flags=0;
02175     char* fileName;
02176     char* dbName=NULL;
02177     char* outFileName=NULL;
02178     FILE* outFile=NULL;
02179     char* kwnames[] = { "filename", "dbname", "outfile", "flags", NULL };
02180 
02181     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzi:verify", kwnames,
02182                                      &fileName, &dbName, &outFileName, &flags))
02183         return NULL;
02184 
02185     CHECK_DB_NOT_CLOSED(self);
02186     if (outFileName)
02187         outFile = fopen(outFileName, "w");
02188 
02189     MYDB_BEGIN_ALLOW_THREADS;
02190     err = self->db->verify(self->db, fileName, dbName, outFile, flags);
02191     MYDB_END_ALLOW_THREADS;
02192     if (outFileName)
02193         fclose(outFile);
02194 
02195     /* DB.verify acts as a DB handle destructor (like close); this was
02196      * documented in BerkeleyDB 4.2 but had the undocumented effect
02197      * of not being safe in prior versions while still requiring an explicit
02198      * DB.close call afterwards.  Lets call close for the user to emulate
02199      * the safe 4.2 behaviour. */
02200 #if (DBVER <= 41)
02201     self->db->close(self->db, 0);
02202 #endif
02203     self->db = NULL;
02204 
02205     RETURN_IF_ERR();
02206     RETURN_NONE();
02207 }
02208 
02209 
02210 static PyObject*
02211 DB_set_get_returns_none(DBObject* self, PyObject* args)
02212 {
02213     int flags=0;
02214     int oldValue=0;
02215 
02216     if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
02217         return NULL;
02218     CHECK_DB_NOT_CLOSED(self);
02219 
02220     if (self->moduleFlags.getReturnsNone)
02221         ++oldValue;
02222     if (self->moduleFlags.cursorSetReturnsNone)
02223         ++oldValue;
02224     self->moduleFlags.getReturnsNone = (flags >= 1);
02225     self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
02226     return PyInt_FromLong(oldValue);
02227 }
02228 
02229 #if (DBVER >= 41)
02230 static PyObject*
02231 DB_set_encrypt(DBObject* self, PyObject* args, PyObject* kwargs)
02232 {
02233     int err;
02234     u_int32_t flags=0;
02235     char *passwd = NULL;
02236     char* kwnames[] = { "passwd", "flags", NULL };
02237 
02238     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames,
02239                 &passwd, &flags)) {
02240         return NULL;
02241     }
02242 
02243     MYDB_BEGIN_ALLOW_THREADS;
02244     err = self->db->set_encrypt(self->db, passwd, flags);
02245     MYDB_END_ALLOW_THREADS;
02246 
02247     RETURN_IF_ERR();
02248     RETURN_NONE();
02249 }
02250 #endif /* DBVER >= 41 */
02251 
02252 
02253 /*-------------------------------------------------------------- */
02254 /* Mapping and Dictionary-like access routines */
02255 
02256 int DB_length(DBObject* self)
02257 {
02258     int err;
02259     long size = 0;
02260     int flags = 0;
02261     void* sp;
02262 
02263     if (self->db == NULL) {
02264         PyErr_SetObject(DBError,
02265                         Py_BuildValue("(is)", 0, "DB object has been closed"));
02266         return -1;
02267     }
02268 
02269     if (self->haveStat) {  /* Has the stat function been called recently?  If
02270                               so, we can use the cached value. */
02271         flags = DB_CACHED_COUNTS;
02272     }
02273 
02274     MYDB_BEGIN_ALLOW_THREADS;
02275 #if (DBVER >= 33)
02276     err = self->db->stat(self->db, &sp, flags);
02277 #else
02278     err = self->db->stat(self->db, &sp, NULL, flags);
02279 #endif
02280     MYDB_END_ALLOW_THREADS;
02281 
02282     if (err)
02283         return -1;
02284 
02285     self->haveStat = 1;
02286 
02287     /* All the stat structures have matching fields upto the ndata field,
02288        so we can use any of them for the type cast */
02289     size = ((DB_BTREE_STAT*)sp)->bt_ndata;
02290     free(sp);
02291     return size;
02292 }
02293 
02294 
02295 PyObject* DB_subscript(DBObject* self, PyObject* keyobj)
02296 {
02297     int err;
02298     PyObject* retval;
02299     DBT key;
02300     DBT data;
02301 
02302     CHECK_DB_NOT_CLOSED(self);
02303     if (!make_key_dbt(self, keyobj, &key, NULL))
02304         return NULL;
02305 
02306     CLEAR_DBT(data);
02307     if (CHECK_DBFLAG(self, DB_THREAD)) {
02308         /* Tell BerkeleyDB to malloc the return value (thread safe) */
02309         data.flags = DB_DBT_MALLOC;
02310     }
02311     MYDB_BEGIN_ALLOW_THREADS;
02312     err = self->db->get(self->db, NULL, &key, &data, 0);
02313     MYDB_END_ALLOW_THREADS;
02314     if (err == DB_NOTFOUND || err == DB_KEYEMPTY) {
02315         PyErr_SetObject(PyExc_KeyError, keyobj);
02316         retval = NULL;
02317     }
02318     else if (makeDBError(err)) {
02319         retval = NULL;
02320     }
02321     else {
02322         retval = PyString_FromStringAndSize((char*)data.data, data.size);
02323         FREE_DBT(data);
02324     }
02325 
02326     FREE_DBT(key);
02327     return retval;
02328 }
02329 
02330 
02331 static int
02332 DB_ass_sub(DBObject* self, PyObject* keyobj, PyObject* dataobj)
02333 {
02334     DBT key, data;
02335     int retval;
02336     int flags = 0;
02337 
02338     if (self->db == NULL) {
02339         PyErr_SetObject(DBError,
02340                         Py_BuildValue("(is)", 0, "DB object has been closed"));
02341         return -1;
02342     }
02343 
02344     if (!make_key_dbt(self, keyobj, &key, NULL))
02345         return -1;
02346 
02347     if (dataobj != NULL) {
02348         if (!make_dbt(dataobj, &data))
02349             retval =  -1;
02350         else {
02351             if (self->setflags & (DB_DUP|DB_DUPSORT))
02352                 /* dictionaries shouldn't have duplicate keys */
02353                 flags = DB_NOOVERWRITE;
02354             retval = _DB_put(self, NULL, &key, &data, flags);
02355 
02356             if ((retval == -1) &&  (self->setflags & (DB_DUP|DB_DUPSORT))) {
02357                 /* try deleting any old record that matches and then PUT it
02358                  * again... */
02359                 _DB_delete(self, NULL, &key, 0);
02360                 PyErr_Clear();
02361                 retval = _DB_put(self, NULL, &key, &data, flags);
02362             }
02363         }
02364     }
02365     else {
02366         /* dataobj == NULL, so delete the key */
02367         retval = _DB_delete(self, NULL, &key, 0);
02368     }
02369     FREE_DBT(key);
02370     return retval;
02371 }
02372 
02373 
02374 static PyObject*
02375 DB_has_key(DBObject* self, PyObject* args)
02376 {
02377     int err;
02378     PyObject* keyobj;
02379     DBT key, data;
02380     PyObject* txnobj = NULL;
02381     DB_TXN *txn = NULL;
02382 
02383     if (!PyArg_ParseTuple(args,"O|O:has_key", &keyobj, &txnobj))
02384         return NULL;
02385     CHECK_DB_NOT_CLOSED(self);
02386     if (!make_key_dbt(self, keyobj, &key, NULL))
02387         return NULL;
02388     if (!checkTxnObj(txnobj, &txn))
02389         return NULL;
02390 
02391     /* This causes ENOMEM to be returned when the db has the key because
02392        it has a record but can't allocate a buffer for the data.  This saves
02393        having to deal with data we won't be using.
02394      */
02395     CLEAR_DBT(data);
02396     data.flags = DB_DBT_USERMEM;
02397 
02398     MYDB_BEGIN_ALLOW_THREADS;
02399     err = self->db->get(self->db, NULL, &key, &data, 0);
02400     MYDB_END_ALLOW_THREADS;
02401     FREE_DBT(key);
02402     return PyInt_FromLong((err == ENOMEM) || (err == 0));
02403 }
02404 
02405 
02406 #define _KEYS_LIST      1
02407 #define _VALUES_LIST    2
02408 #define _ITEMS_LIST     3
02409 
02410 static PyObject*
02411 _DB_make_list(DBObject* self, DB_TXN* txn, int type)
02412 {
02413     int err, dbtype;
02414     DBT key;
02415     DBT data;
02416     DBC *cursor;
02417     PyObject* list;
02418     PyObject* item = NULL;
02419 
02420     CHECK_DB_NOT_CLOSED(self);
02421     CLEAR_DBT(key);
02422     CLEAR_DBT(data);
02423 
02424     dbtype = _DB_get_type(self);
02425     if (dbtype == -1)
02426         return NULL;
02427 
02428     list = PyList_New(0);
02429     if (list == NULL) {
02430         PyErr_SetString(PyExc_MemoryError, "PyList_New failed");
02431         return NULL;
02432     }
02433 
02434     /* get a cursor */
02435     MYDB_BEGIN_ALLOW_THREADS;
02436     err = self->db->cursor(self->db, NULL, &cursor, 0);
02437     MYDB_END_ALLOW_THREADS;
02438     RETURN_IF_ERR();
02439 
02440     if (CHECK_DBFLAG(self, DB_THREAD)) {
02441         key.flags = DB_DBT_REALLOC;
02442         data.flags = DB_DBT_REALLOC;
02443     }
02444 
02445     while (1) { /* use the cursor to traverse the DB, collecting items */
02446         MYDB_BEGIN_ALLOW_THREADS;
02447         err = cursor->c_get(cursor, &key, &data, DB_NEXT);
02448         MYDB_END_ALLOW_THREADS;
02449 
02450         if (err) {
02451             /* for any error, break out of the loop */
02452             break;
02453         }
02454 
02455         switch (type) {
02456         case _KEYS_LIST:
02457             switch(dbtype) {
02458             case DB_BTREE:
02459             case DB_HASH:
02460             default:
02461                 item = PyString_FromStringAndSize((char*)key.data, key.size);
02462                 break;
02463             case DB_RECNO:
02464             case DB_QUEUE:
02465                 item = PyInt_FromLong(*((db_recno_t*)key.data));
02466                 break;
02467             }
02468             break;
02469 
02470         case _VALUES_LIST:
02471             item = PyString_FromStringAndSize((char*)data.data, data.size);
02472             break;
02473 
02474         case _ITEMS_LIST:
02475             switch(dbtype) {
02476             case DB_BTREE:
02477             case DB_HASH:
02478             default:
02479                 item = Py_BuildValue("s#s#", key.data, key.size, data.data,
02480                                      data.size);
02481                 break;
02482             case DB_RECNO:
02483             case DB_QUEUE:
02484                 item = Py_BuildValue("is#", *((db_recno_t*)key.data),
02485                                      data.data, data.size);
02486                 break;
02487             }
02488             break;
02489         }
02490         if (item == NULL) {
02491             Py_DECREF(list);
02492             PyErr_SetString(PyExc_MemoryError, "List item creation failed");
02493             list = NULL;
02494             goto done;
02495         }
02496         PyList_Append(list, item);
02497         Py_DECREF(item);
02498     }
02499 
02500     /* DB_NOTFOUND is okay, it just means we got to the end */
02501     if (err != DB_NOTFOUND && makeDBError(err)) {
02502         Py_DECREF(list);
02503         list = NULL;
02504     }
02505 
02506  done:
02507     FREE_DBT(key);
02508     FREE_DBT(data);
02509     MYDB_BEGIN_ALLOW_THREADS;
02510     cursor->c_close(cursor);
02511     MYDB_END_ALLOW_THREADS;
02512     return list;
02513 }
02514 
02515 
02516 static PyObject*
02517 DB_keys(DBObject* self, PyObject* args)
02518 {
02519     PyObject* txnobj = NULL;
02520     DB_TXN *txn = NULL;
02521 
02522     if (!PyArg_ParseTuple(args,"|O:keys", &txnobj))
02523         return NULL;
02524     if (!checkTxnObj(txnobj, &txn))
02525         return NULL;
02526     return _DB_make_list(self, txn, _KEYS_LIST);
02527 }
02528 
02529 
02530 static PyObject*
02531 DB_items(DBObject* self, PyObject* args)
02532 {
02533     PyObject* txnobj = NULL;
02534     DB_TXN *txn = NULL;
02535 
02536     if (!PyArg_ParseTuple(args,"|O:items", &txnobj))
02537         return NULL;
02538     if (!checkTxnObj(txnobj, &txn))
02539         return NULL;
02540     return _DB_make_list(self, txn, _ITEMS_LIST);
02541 }
02542 
02543 
02544 static PyObject*
02545 DB_values(DBObject* self, PyObject* args)
02546 {
02547     PyObject* txnobj = NULL;
02548     DB_TXN *txn = NULL;
02549 
02550     if (!PyArg_ParseTuple(args,"|O:values", &txnobj))
02551         return NULL;
02552     if (!checkTxnObj(txnobj, &txn))
02553         return NULL;
02554     return _DB_make_list(self, txn, _VALUES_LIST);
02555 }
02556 
02557 /* --------------------------------------------------------------------- */
02558 /* DBCursor methods */
02559 
02560 
02561 static PyObject*
02562 DBC_close(DBCursorObject* self, PyObject* args)
02563 {
02564     int err = 0;
02565 
02566     if (!PyArg_ParseTuple(args, ":close"))
02567         return NULL;
02568 
02569     if (self->dbc != NULL) {
02570         MYDB_BEGIN_ALLOW_THREADS;
02571         err = self->dbc->c_close(self->dbc);
02572         self->dbc = NULL;
02573         MYDB_END_ALLOW_THREADS;
02574     }
02575     RETURN_IF_ERR();
02576     RETURN_NONE();
02577 }
02578 
02579 
02580 static PyObject*
02581 DBC_count(DBCursorObject* self, PyObject* args)
02582 {
02583     int err = 0;
02584     db_recno_t count;
02585     int flags = 0;
02586 
02587     if (!PyArg_ParseTuple(args, "|i:count", &flags))
02588         return NULL;
02589 
02590     CHECK_CURSOR_NOT_CLOSED(self);
02591 
02592     MYDB_BEGIN_ALLOW_THREADS;
02593     err = self->dbc->c_count(self->dbc, &count, flags);
02594     MYDB_END_ALLOW_THREADS;
02595     RETURN_IF_ERR();
02596 
02597     return PyInt_FromLong(count);
02598 }
02599 
02600 
02601 static PyObject*
02602 DBC_current(DBCursorObject* self, PyObject* args, PyObject *kwargs)
02603 {
02604     return _DBCursor_get(self,DB_CURRENT,args,kwargs,"|iii:current");
02605 }
02606 
02607 
02608 static PyObject*
02609 DBC_delete(DBCursorObject* self, PyObject* args)
02610 {
02611     int err, flags=0;
02612 
02613     if (!PyArg_ParseTuple(args, "|i:delete", &flags))
02614         return NULL;
02615 
02616     CHECK_CURSOR_NOT_CLOSED(self);
02617 
02618     MYDB_BEGIN_ALLOW_THREADS;
02619     err = self->dbc->c_del(self->dbc, flags);
02620     MYDB_END_ALLOW_THREADS;
02621     RETURN_IF_ERR();
02622 
02623     self->mydb->haveStat = 0;
02624     RETURN_NONE();
02625 }
02626 
02627 
02628 static PyObject*
02629 DBC_dup(DBCursorObject* self, PyObject* args)
02630 {
02631     int err, flags =0;
02632     DBC* dbc = NULL;
02633 
02634     if (!PyArg_ParseTuple(args, "|i:dup", &flags))
02635         return NULL;
02636 
02637     CHECK_CURSOR_NOT_CLOSED(self);
02638 
02639     MYDB_BEGIN_ALLOW_THREADS;
02640     err = self->dbc->c_dup(self->dbc, &dbc, flags);
02641     MYDB_END_ALLOW_THREADS;
02642     RETURN_IF_ERR();
02643 
02644     return (PyObject*) newDBCursorObject(dbc, self->mydb);
02645 }
02646 
02647 static PyObject*
02648 DBC_first(DBCursorObject* self, PyObject* args, PyObject* kwargs)
02649 {
02650     return _DBCursor_get(self,DB_FIRST,args,kwargs,"|iii:first");
02651 }
02652 
02653 
02654 static PyObject*
02655 DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
02656 {
02657     int err, flags=0;
02658     PyObject* keyobj = NULL;
02659     PyObject* dataobj = NULL;
02660     PyObject* retval = NULL;
02661     int dlen = -1;
02662     int doff = -1;
02663     DBT key, data;
02664     char* kwnames[] = { "key","data", "flags", "dlen", "doff", NULL };
02665 
02666     CLEAR_DBT(key);
02667     CLEAR_DBT(data);
02668     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:get", &kwnames[2],
02669                                      &flags, &dlen, &doff))
02670     {
02671         PyErr_Clear();
02672         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:get",
02673                                          &kwnames[1], 
02674                                          &keyobj, &flags, &dlen, &doff))
02675         {
02676             PyErr_Clear();
02677             if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:get",
02678                                              kwnames, &keyobj, &dataobj,
02679                                              &flags, &dlen, &doff))
02680             {
02681                 return NULL;
02682             }
02683         }
02684     }
02685 
02686     CHECK_CURSOR_NOT_CLOSED(self);
02687 
02688     if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
02689         return NULL;
02690     if (dataobj && !make_dbt(dataobj, &data))
02691         return NULL;
02692     if (!add_partial_dbt(&data, dlen, doff))
02693         return NULL;
02694 
02695     if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
02696         data.flags = DB_DBT_MALLOC;
02697         key.flags = DB_DBT_MALLOC;
02698     }
02699 
02700     MYDB_BEGIN_ALLOW_THREADS;
02701     err = self->dbc->c_get(self->dbc, &key, &data, flags);
02702     MYDB_END_ALLOW_THREADS;
02703 
02704 
02705     if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
02706         Py_INCREF(Py_None);
02707         retval = Py_None;
02708     }
02709     else if (makeDBError(err)) {
02710         retval = NULL;
02711     }
02712     else {
02713         switch (_DB_get_type(self->mydb)) {
02714         case -1:
02715             retval = NULL;
02716             break;
02717         case DB_BTREE:
02718         case DB_HASH:
02719         default:
02720             retval = Py_BuildValue("s#s#", key.data, key.size,
02721                                    data.data, data.size);
02722             break;
02723         case DB_RECNO:
02724         case DB_QUEUE:
02725             retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
02726                                    data.data, data.size);
02727             break;
02728         }
02729         FREE_DBT(key);
02730         FREE_DBT(data);
02731     }
02732     return retval;
02733 }
02734 
02735 
02736 static PyObject*
02737 DBC_get_recno(DBCursorObject* self, PyObject* args)
02738 {
02739     int err;
02740     db_recno_t recno;
02741     DBT key;
02742     DBT data;
02743 
02744     if (!PyArg_ParseTuple(args, ":get_recno"))
02745         return NULL;
02746 
02747     CHECK_CURSOR_NOT_CLOSED(self);
02748 
02749     CLEAR_DBT(key);
02750     CLEAR_DBT(data);
02751     if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
02752         /* Tell BerkeleyDB to malloc the return value (thread safe) */
02753         data.flags = DB_DBT_MALLOC;
02754         key.flags = DB_DBT_MALLOC;
02755     }
02756 
02757     MYDB_BEGIN_ALLOW_THREADS;
02758     err = self->dbc->c_get(self->dbc, &key, &data, DB_GET_RECNO);
02759     MYDB_END_ALLOW_THREADS;
02760     RETURN_IF_ERR();
02761 
02762     recno = *((db_recno_t*)data.data);
02763     FREE_DBT(key);
02764     FREE_DBT(data);
02765     return PyInt_FromLong(recno);
02766 }
02767 
02768 
02769 static PyObject*
02770 DBC_last(DBCursorObject* self, PyObject* args, PyObject *kwargs)
02771 {
02772     return _DBCursor_get(self,DB_LAST,args,kwargs,"|iii:last");
02773 }
02774 
02775 
02776 static PyObject*
02777 DBC_next(DBCursorObject* self, PyObject* args, PyObject *kwargs)
02778 {
02779     return _DBCursor_get(self,DB_NEXT,args,kwargs,"|iii:next");
02780 }
02781 
02782 
02783 static PyObject*
02784 DBC_prev(DBCursorObject* self, PyObject* args, PyObject *kwargs)
02785 {
02786     return _DBCursor_get(self,DB_PREV,args,kwargs,"|iii:prev");
02787 }
02788 
02789 
02790 static PyObject*
02791 DBC_put(DBCursorObject* self, PyObject* args, PyObject* kwargs)
02792 {
02793     int err, flags = 0;
02794     PyObject* keyobj, *dataobj;
02795     DBT key, data;
02796     char* kwnames[] = { "key", "data", "flags", "dlen", "doff", NULL };
02797     int dlen = -1;
02798     int doff = -1;
02799 
02800     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iii:put", kwnames,
02801                                      &keyobj, &dataobj, &flags, &dlen, &doff))
02802         return NULL;
02803 
02804     CHECK_CURSOR_NOT_CLOSED(self);
02805 
02806     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
02807         return NULL;
02808     if (!make_dbt(dataobj, &data))
02809         return NULL;
02810     if (!add_partial_dbt(&data, dlen, doff)) return NULL;
02811 
02812     MYDB_BEGIN_ALLOW_THREADS;
02813     err = self->dbc->c_put(self->dbc, &key, &data, flags);
02814     MYDB_END_ALLOW_THREADS;
02815     FREE_DBT(key);
02816     RETURN_IF_ERR();
02817     self->mydb->haveStat = 0;
02818     RETURN_NONE();
02819 }
02820 
02821 
02822 static PyObject*
02823 DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
02824 {
02825     int err, flags = 0;
02826     DBT key, data;
02827     PyObject* retval, *keyobj;
02828     char* kwnames[] = { "key", "flags", "dlen", "doff", NULL };
02829     int dlen = -1;
02830     int doff = -1;
02831 
02832     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set", kwnames,
02833                                      &keyobj, &flags, &dlen, &doff))
02834         return NULL;
02835 
02836     CHECK_CURSOR_NOT_CLOSED(self);
02837 
02838     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
02839         return NULL;
02840 
02841     CLEAR_DBT(data);
02842     if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
02843         /* Tell BerkeleyDB to malloc the return value (thread safe) */
02844         data.flags = DB_DBT_MALLOC;
02845     }
02846     if (!add_partial_dbt(&data, dlen, doff))
02847         return NULL;
02848 
02849     MYDB_BEGIN_ALLOW_THREADS;
02850     err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET);
02851     MYDB_END_ALLOW_THREADS;
02852     if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
02853         Py_INCREF(Py_None);
02854         retval = Py_None;
02855     }
02856     else if (makeDBError(err)) {
02857         retval = NULL;
02858     }
02859     else {
02860         switch (_DB_get_type(self->mydb)) {
02861         case -1:
02862             retval = NULL;
02863             break;
02864         case DB_BTREE:
02865         case DB_HASH:
02866         default:
02867             retval = Py_BuildValue("s#s#", key.data, key.size,
02868                                    data.data, data.size);
02869             break;
02870         case DB_RECNO:
02871         case DB_QUEUE:
02872             retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
02873                                    data.data, data.size);
02874             break;
02875         }
02876         FREE_DBT(key);
02877         FREE_DBT(data);
02878     }
02879 
02880     return retval;
02881 }
02882 
02883 
02884 static PyObject*
02885 DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
02886 {
02887     int err, flags = 0;
02888     DBT key, data;
02889     PyObject* retval, *keyobj;
02890     char* kwnames[] = { "key", "flags", "dlen", "doff", NULL };
02891     int dlen = -1;
02892     int doff = -1;
02893 
02894     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set_range", kwnames,
02895                                      &keyobj, &flags, &dlen, &doff))
02896         return NULL;
02897 
02898     CHECK_CURSOR_NOT_CLOSED(self);
02899 
02900     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
02901         return NULL;
02902 
02903     CLEAR_DBT(data);
02904     if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
02905         /* Tell BerkeleyDB to malloc the return value (thread safe) */
02906         data.flags = DB_DBT_MALLOC;
02907         key.flags = DB_DBT_MALLOC;
02908     }
02909     if (!add_partial_dbt(&data, dlen, doff))
02910         return NULL;
02911     MYDB_BEGIN_ALLOW_THREADS;
02912     err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
02913     MYDB_END_ALLOW_THREADS;
02914     if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
02915         Py_INCREF(Py_None);
02916         retval = Py_None;
02917     }
02918     else if (makeDBError(err)) {
02919         retval = NULL;
02920     }
02921     else {
02922         switch (_DB_get_type(self->mydb)) {
02923         case -1:
02924             retval = NULL;
02925             break;
02926         case DB_BTREE:
02927         case DB_HASH:
02928         default:
02929             retval = Py_BuildValue("s#s#", key.data, key.size,
02930                                    data.data, data.size);
02931             break;
02932         case DB_RECNO:
02933         case DB_QUEUE:
02934             retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
02935                                    data.data, data.size);
02936             break;
02937         }
02938         FREE_DBT(key);
02939         FREE_DBT(data);
02940     }
02941 
02942     return retval;
02943 }
02944 
02945 static PyObject*
02946 _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
02947                   int flags, unsigned int returnsNone)
02948 {
02949     int err;
02950     DBT key, data;
02951     PyObject* retval;
02952 
02953     /* the caller did this:  CHECK_CURSOR_NOT_CLOSED(self); */
02954     if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
02955         return NULL;
02956     if (!make_dbt(dataobj, &data))
02957         return NULL;
02958 
02959     MYDB_BEGIN_ALLOW_THREADS;
02960     err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
02961     MYDB_END_ALLOW_THREADS;
02962     if ((err == DB_NOTFOUND) && returnsNone) {
02963         Py_INCREF(Py_None);
02964         retval = Py_None;
02965     }
02966     else if (makeDBError(err)) {
02967         retval = NULL;
02968     }
02969     else {
02970         switch (_DB_get_type(self->mydb)) {
02971         case -1:
02972             retval = NULL;
02973             break;
02974         case DB_BTREE:
02975         case DB_HASH:
02976         default:
02977             retval = Py_BuildValue("s#s#", key.data, key.size,
02978                                    data.data, data.size);
02979             break;
02980         case DB_RECNO:
02981         case DB_QUEUE:
02982             retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
02983                                    data.data, data.size);
02984             break;
02985         }
02986     }
02987 
02988     FREE_DBT(key);
02989     return retval;
02990 }
02991 
02992 static PyObject*
02993 DBC_get_both(DBCursorObject* self, PyObject* args)
02994 {
02995     int flags=0;
02996     PyObject *keyobj, *dataobj;
02997 
02998     if (!PyArg_ParseTuple(args, "OO|i:get_both", &keyobj, &dataobj, &flags))
02999         return NULL;
03000 
03001     /* if the cursor is closed, self->mydb may be invalid */
03002     CHECK_CURSOR_NOT_CLOSED(self);
03003 
03004     return _DBC_get_set_both(self, keyobj, dataobj, flags,
03005                 self->mydb->moduleFlags.getReturnsNone);
03006 }
03007 
03008 /* Return size of entry */
03009 static PyObject*
03010 DBC_get_current_size(DBCursorObject* self, PyObject* args)
03011 {
03012     int err, flags=DB_CURRENT;
03013     PyObject* retval = NULL;
03014     DBT key, data;
03015 
03016     if (!PyArg_ParseTuple(args, ":get_current_size"))
03017         return NULL;
03018     CHECK_CURSOR_NOT_CLOSED(self);
03019     CLEAR_DBT(key);
03020     CLEAR_DBT(data);
03021 
03022     /* We don't allocate any memory, forcing a ENOMEM error and thus
03023        getting the record size. */
03024     data.flags = DB_DBT_USERMEM;
03025     data.ulen = 0;
03026     MYDB_BEGIN_ALLOW_THREADS;
03027     err = self->dbc->c_get(self->dbc, &key, &data, flags);
03028     MYDB_END_ALLOW_THREADS;
03029     if (err == ENOMEM || !err) {
03030         /* ENOMEM means positive size, !err means zero length value */
03031         retval = PyInt_FromLong((long)data.size);
03032         err = 0;
03033     }
03034 
03035     FREE_DBT(key);
03036     FREE_DBT(data);
03037     RETURN_IF_ERR();
03038     return retval;
03039 }
03040 
03041 static PyObject*
03042 DBC_set_both(DBCursorObject* self, PyObject* args)
03043 {
03044     int flags=0;
03045     PyObject *keyobj, *dataobj;
03046 
03047     if (!PyArg_ParseTuple(args, "OO|i:set_both", &keyobj, &dataobj, &flags))
03048         return NULL;
03049 
03050     /* if the cursor is closed, self->mydb may be invalid */
03051     CHECK_CURSOR_NOT_CLOSED(self);
03052 
03053     return _DBC_get_set_both(self, keyobj, dataobj, flags,
03054                 self->mydb->moduleFlags.cursorSetReturnsNone);
03055 }
03056 
03057 
03058 static PyObject*
03059 DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
03060 {
03061     int err, irecno, flags=0;
03062     db_recno_t recno;
03063     DBT key, data;
03064     PyObject* retval;
03065     int dlen = -1;
03066     int doff = -1;
03067     char* kwnames[] = { "recno","flags", "dlen", "doff", NULL };
03068 
03069     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii:set_recno", kwnames,
03070                                      &irecno, &flags, &dlen, &doff))
03071       return NULL;
03072 
03073     CHECK_CURSOR_NOT_CLOSED(self);
03074 
03075     CLEAR_DBT(key);
03076     recno = (db_recno_t) irecno;
03077     /* use allocated space so DB will be able to realloc room for the real
03078      * key */
03079     key.data = malloc(sizeof(db_recno_t));
03080     if (key.data == NULL) {
03081         PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
03082         return NULL;
03083     }
03084     key.size = sizeof(db_recno_t);
03085     key.ulen = key.size;
03086     memcpy(key.data, &recno, sizeof(db_recno_t));
03087     key.flags = DB_DBT_REALLOC;
03088 
03089     CLEAR_DBT(data);
03090     if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
03091         /* Tell BerkeleyDB to malloc the return value (thread safe) */
03092         data.flags = DB_DBT_MALLOC;
03093     }
03094     if (!add_partial_dbt(&data, dlen, doff))
03095         return NULL;
03096 
03097     MYDB_BEGIN_ALLOW_THREADS;
03098     err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
03099     MYDB_END_ALLOW_THREADS;
03100     if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
03101         Py_INCREF(Py_None);
03102         retval = Py_None;
03103     }
03104     else if (makeDBError(err)) {
03105         retval = NULL;
03106     }
03107     else {  /* Can only be used for BTrees, so no need to return int key */
03108         retval = Py_BuildValue("s#s#", key.data, key.size,
03109                                data.data, data.size);
03110         FREE_DBT(key);
03111         FREE_DBT(data);
03112     }
03113 
03114     return retval;
03115 }
03116 
03117 
03118 static PyObject*
03119 DBC_consume(DBCursorObject* self, PyObject* args, PyObject *kwargs)
03120 {
03121     return _DBCursor_get(self,DB_CONSUME,args,kwargs,"|iii:consume");
03122 }
03123 
03124 
03125 static PyObject*
03126 DBC_next_dup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
03127 {
03128     return _DBCursor_get(self,DB_NEXT_DUP,args,kwargs,"|iii:next_dup");
03129 }
03130 
03131 
03132 static PyObject*
03133 DBC_next_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
03134 {
03135     return _DBCursor_get(self,DB_NEXT_NODUP,args,kwargs,"|iii:next_nodup");
03136 }
03137 
03138 
03139 static PyObject*
03140 DBC_prev_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
03141 {
03142     return _DBCursor_get(self,DB_PREV_NODUP,args,kwargs,"|iii:prev_nodup");
03143 }
03144 
03145 
03146 static PyObject*
03147 DBC_join_item(DBCursorObject* self, PyObject* args)
03148 {
03149     int err, flags=0;
03150     DBT key, data;
03151     PyObject* retval;
03152 
03153     if (!PyArg_ParseTuple(args, "|i:join_item", &flags))
03154         return NULL;
03155 
03156     CHECK_CURSOR_NOT_CLOSED(self);
03157 
03158     CLEAR_DBT(key);
03159     CLEAR_DBT(data);
03160     if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
03161         /* Tell BerkeleyDB to malloc the return value (thread safe) */
03162         key.flags = DB_DBT_MALLOC;
03163     }
03164 
03165     MYDB_BEGIN_ALLOW_THREADS;
03166     err = self->dbc->c_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
03167     MYDB_END_ALLOW_THREADS;
03168     if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
03169         Py_INCREF(Py_None);
03170         retval = Py_None;
03171     }
03172     else if (makeDBError(err)) {
03173         retval = NULL;
03174     }
03175     else {
03176         retval = Py_BuildValue("s#", key.data, key.size);
03177         FREE_DBT(key);
03178     }
03179 
03180     return retval;
03181 }
03182 
03183 
03184 
03185 /* --------------------------------------------------------------------- */
03186 /* DBEnv methods */
03187 
03188 
03189 static PyObject*
03190 DBEnv_close(DBEnvObject* self, PyObject* args)
03191 {
03192     int err, flags = 0;
03193 
03194     if (!PyArg_ParseTuple(args, "|i:close", &flags))
03195         return NULL;
03196     if (!self->closed) {      /* Don't close more than once */
03197         MYDB_BEGIN_ALLOW_THREADS;
03198         err = self->db_env->close(self->db_env, flags);
03199         MYDB_END_ALLOW_THREADS;
03200         /* after calling DBEnv->close, regardless of error, this DBEnv
03201          * may not be accessed again (BerkeleyDB docs). */
03202         self->closed = 1;
03203         self->db_env = NULL;
03204         RETURN_IF_ERR();
03205     }
03206     RETURN_NONE();
03207 }
03208 
03209 
03210 static PyObject*
03211 DBEnv_open(DBEnvObject* self, PyObject* args)
03212 {
03213     int err, flags=0, mode=0660;
03214     char *db_home;
03215 
03216     if (!PyArg_ParseTuple(args, "z|ii:open", &db_home, &flags, &mode))
03217         return NULL;
03218 
03219     CHECK_ENV_NOT_CLOSED(self);
03220 
03221     MYDB_BEGIN_ALLOW_THREADS;
03222     err = self->db_env->open(self->db_env, db_home, flags, mode);
03223     MYDB_END_ALLOW_THREADS;
03224     RETURN_IF_ERR();
03225     self->closed = 0;
03226     self->flags = flags;
03227     RETURN_NONE();
03228 }
03229 
03230 
03231 static PyObject*
03232 DBEnv_remove(DBEnvObject* self, PyObject* args)
03233 {
03234     int err, flags=0;
03235     char *db_home;
03236 
03237     if (!PyArg_ParseTuple(args, "s|i:remove", &db_home, &flags))
03238         return NULL;
03239     CHECK_ENV_NOT_CLOSED(self);
03240     MYDB_BEGIN_ALLOW_THREADS;
03241     err = self->db_env->remove(self->db_env, db_home, flags);
03242     MYDB_END_ALLOW_THREADS;
03243     RETURN_IF_ERR();
03244     RETURN_NONE();
03245 }
03246 
03247 #if (DBVER >= 41)
03248 static PyObject*
03249 DBEnv_dbremove(DBEnvObject* self, PyObject* args, PyObject* kwargs)
03250 {
03251     int err;
03252     u_int32_t flags=0;
03253     char *file = NULL;
03254     char *database = NULL;
03255     PyObject *txnobj = NULL;
03256     DB_TXN *txn = NULL;
03257     char* kwnames[] = { "file", "database", "txn", "flags", NULL };
03258 
03259     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|Oi:dbremove", kwnames,
03260                 &file, &database, &txnobj, &flags)) {
03261         return NULL;
03262     }
03263     if (!checkTxnObj(txnobj, &txn)) {
03264         return NULL;
03265     }
03266     CHECK_ENV_NOT_CLOSED(self);
03267     MYDB_BEGIN_ALLOW_THREADS;
03268     err = self->db_env->dbremove(self->db_env, txn, file, database, flags);
03269     MYDB_END_ALLOW_THREADS;
03270     RETURN_IF_ERR();
03271     RETURN_NONE();
03272 }
03273 
03274 static PyObject*
03275 DBEnv_dbrename(DBEnvObject* self, PyObject* args, PyObject* kwargs)
03276 {
03277     int err;
03278     u_int32_t flags=0;
03279     char *file = NULL;
03280     char *database = NULL;
03281     char *newname = NULL;
03282     PyObject *txnobj = NULL;
03283     DB_TXN *txn = NULL;
03284     char* kwnames[] = { "file", "database", "newname", "txn", "flags", NULL };
03285 
03286     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sss|Oi:dbrename", kwnames,
03287                 &file, &database, &newname, &txnobj, &flags)) {
03288         return NULL;
03289     }
03290     if (!checkTxnObj(txnobj, &txn)) {
03291         return NULL;
03292     }
03293     CHECK_ENV_NOT_CLOSED(self);
03294     MYDB_BEGIN_ALLOW_THREADS;
03295     err = self->db_env->dbrename(self->db_env, txn, file, database, newname,
03296                                  flags);
03297     MYDB_END_ALLOW_THREADS;
03298     RETURN_IF_ERR();
03299     RETURN_NONE();
03300 }
03301 
03302 static PyObject*
03303 DBEnv_set_encrypt(DBEnvObject* self, PyObject* args, PyObject* kwargs)
03304 {
03305     int err;
03306     u_int32_t flags=0;
03307     char *passwd = NULL;
03308     char* kwnames[] = { "passwd", "flags", NULL };
03309 
03310     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames,
03311                 &passwd, &flags)) {
03312         return NULL;
03313     }
03314 
03315     MYDB_BEGIN_ALLOW_THREADS;
03316     err = self->db_env->set_encrypt(self->db_env, passwd, flags);
03317     MYDB_END_ALLOW_THREADS;
03318 
03319     RETURN_IF_ERR();
03320     RETURN_NONE();
03321 }
03322 #endif /* DBVER >= 41 */
03323 
03324 #if (DBVER >= 40)
03325 static PyObject*
03326 DBEnv_set_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs)
03327 {
03328     int err;
03329     u_int32_t flags=0;
03330     u_int32_t timeout = 0;
03331     char* kwnames[] = { "timeout", "flags", NULL };
03332 
03333     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames,
03334                 &timeout, &flags)) {
03335         return NULL;
03336     }
03337 
03338     MYDB_BEGIN_ALLOW_THREADS;
03339     err = self->db_env->set_timeout(self->db_env, (db_timeout_t)timeout, flags);
03340     MYDB_END_ALLOW_THREADS;
03341 
03342     RETURN_IF_ERR();
03343     RETURN_NONE();
03344 }
03345 #endif /* DBVER >= 40 */
03346 
03347 static PyObject*
03348 DBEnv_set_shm_key(DBEnvObject* self, PyObject* args)
03349 {
03350     int err;
03351     long shm_key = 0;
03352 
03353     if (!PyArg_ParseTuple(args, "l:set_shm_key", &shm_key))
03354         return NULL;
03355     CHECK_ENV_NOT_CLOSED(self);
03356 
03357     err = self->db_env->set_shm_key(self->db_env, shm_key);
03358     RETURN_IF_ERR();
03359     RETURN_NONE();
03360 }
03361 
03362 static PyObject*
03363 DBEnv_set_cachesize(DBEnvObject* self, PyObject* args)
03364 {
03365     int err, gbytes=0, bytes=0, ncache=0;
03366 
03367     if (!PyArg_ParseTuple(args, "ii|i:set_cachesize",
03368                           &gbytes, &bytes, &ncache))
03369         return NULL;
03370     CHECK_ENV_NOT_CLOSED(self);
03371 
03372     MYDB_BEGIN_ALLOW_THREADS;
03373     err = self->db_env->set_cachesize(self->db_env, gbytes, bytes, ncache);
03374     MYDB_END_ALLOW_THREADS;
03375     RETURN_IF_ERR();
03376     RETURN_NONE();
03377 }
03378 
03379 
03380 #if (DBVER >= 32)
03381 static PyObject*
03382 DBEnv_set_flags(DBEnvObject* self, PyObject* args)
03383 {
03384     int err, flags=0, onoff=0;
03385 
03386     if (!PyArg_ParseTuple(args, "ii:set_flags",
03387                           &flags, &onoff))
03388         return NULL;
03389     CHECK_ENV_NOT_CLOSED(self);
03390 
03391     MYDB_BEGIN_ALLOW_THREADS;
03392     err = self->db_env->set_flags(self->db_env, flags, onoff);
03393     MYDB_END_ALLOW_THREADS;
03394     RETURN_IF_ERR();
03395     RETURN_NONE();
03396 }
03397 #endif
03398 
03399 
03400 static PyObject*
03401 DBEnv_set_data_dir(DBEnvObject* self, PyObject* args)
03402 {
03403     int err;
03404     char *dir;
03405 
03406     if (!PyArg_ParseTuple(args, "s:set_data_dir", &dir))
03407         return NULL;
03408     CHECK_ENV_NOT_CLOSED(self);
03409 
03410     MYDB_BEGIN_ALLOW_THREADS;
03411     err = self->db_env->set_data_dir(self->db_env, dir);
03412     MYDB_END_ALLOW_THREADS;
03413     RETURN_IF_ERR();
03414     RETURN_NONE();
03415 }
03416 
03417 
03418 static PyObject*
03419 DBEnv_set_lg_bsize(DBEnvObject* self, PyObject* args)
03420 {
03421     int err, lg_bsize;
03422 
03423     if (!PyArg_ParseTuple(args, "i:set_lg_bsize", &lg_bsize))
03424         return NULL;
03425     CHECK_ENV_NOT_CLOSED(self);
03426 
03427     MYDB_BEGIN_ALLOW_THREADS;
03428     err = self->db_env->set_lg_bsize(self->db_env, lg_bsize);
03429     MYDB_END_ALLOW_THREADS;
03430     RETURN_IF_ERR();
03431     RETURN_NONE();
03432 }
03433 
03434 
03435 static PyObject*
03436 DBEnv_set_lg_dir(DBEnvObject* self, PyObject* args)
03437 {
03438     int err;
03439     char *dir;
03440 
03441     if (!PyArg_ParseTuple(args, "s:set_lg_dir", &dir))
03442         return NULL;
03443     CHECK_ENV_NOT_CLOSED(self);
03444 
03445     MYDB_BEGIN_ALLOW_THREADS;
03446     err = self->db_env->set_lg_dir(self->db_env, dir);
03447     MYDB_END_ALLOW_THREADS;
03448     RETURN_IF_ERR();
03449     RETURN_NONE();
03450 }
03451 
03452 static PyObject*
03453 DBEnv_set_lg_max(DBEnvObject* self, PyObject* args)
03454 {
03455     int err, lg_max;
03456 
03457     if (!PyArg_ParseTuple(args, "i:set_lg_max", &lg_max))
03458         return NULL;
03459     CHECK_ENV_NOT_CLOSED(self);
03460 
03461     MYDB_BEGIN_ALLOW_THREADS;
03462     err = self->db_env->set_lg_max(self->db_env, lg_max);
03463     MYDB_END_ALLOW_THREADS;
03464     RETURN_IF_ERR();
03465     RETURN_NONE();
03466 }
03467 
03468 
03469 static PyObject*
03470 DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args)
03471 {
03472     int err, lk_detect;
03473 
03474     if (!PyArg_ParseTuple(args, "i:set_lk_detect", &lk_detect))
03475         return NULL;
03476     CHECK_ENV_NOT_CLOSED(self);
03477 
03478     MYDB_BEGIN_ALLOW_THREADS;
03479     err = self->db_env->set_lk_detect(self->db_env, lk_detect);
03480     MYDB_END_ALLOW_THREADS;
03481     RETURN_IF_ERR();
03482     RETURN_NONE();
03483 }
03484 
03485 
03486 static PyObject*
03487 DBEnv_set_lk_max(DBEnvObject* self, PyObject* args)
03488 {
03489     int err, max;
03490 
03491     if (!PyArg_ParseTuple(args, "i:set_lk_max", &max))
03492         return NULL;
03493     CHECK_ENV_NOT_CLOSED(self);
03494 
03495     MYDB_BEGIN_ALLOW_THREADS;
03496     err = self->db_env->set_lk_max(self->db_env, max);
03497     MYDB_END_ALLOW_THREADS;
03498     RETURN_IF_ERR();
03499     RETURN_NONE();
03500 }
03501 
03502 
03503 #if (DBVER >= 32)
03504 
03505 static PyObject*
03506 DBEnv_set_lk_max_locks(DBEnvObject* self, PyObject* args)
03507 {
03508     int err, max;
03509 
03510     if (!PyArg_ParseTuple(args, "i:set_lk_max_locks", &max))
03511         return NULL;
03512     CHECK_ENV_NOT_CLOSED(self);
03513 
03514     MYDB_BEGIN_ALLOW_THREADS;
03515     err = self->db_env->set_lk_max_locks(self->db_env, max);
03516     MYDB_END_ALLOW_THREADS;
03517     RETURN_IF_ERR();
03518     RETURN_NONE();
03519 }
03520 
03521 
03522 static PyObject*
03523 DBEnv_set_lk_max_lockers(DBEnvObject* self, PyObject* args)
03524 {
03525     int err, max;
03526 
03527     if (!PyArg_ParseTuple(args, "i:set_lk_max_lockers", &max))
03528         return NULL;
03529     CHECK_ENV_NOT_CLOSED(self);
03530 
03531     MYDB_BEGIN_ALLOW_THREADS;
03532     err = self->db_env->set_lk_max_lockers(self->db_env, max);
03533     MYDB_END_ALLOW_THREADS;
03534     RETURN_IF_ERR();
03535     RETURN_NONE();
03536 }
03537 
03538 
03539 static PyObject*
03540 DBEnv_set_lk_max_objects(DBEnvObject* self, PyObject* args)
03541 {
03542     int err, max;
03543 
03544     if (!PyArg_ParseTuple(args, "i:set_lk_max_objects", &max))
03545         return NULL;
03546     CHECK_ENV_NOT_CLOSED(self);
03547 
03548     MYDB_BEGIN_ALLOW_THREADS;
03549     err = self->db_env->set_lk_max_objects(self->db_env, max);
03550     MYDB_END_ALLOW_THREADS;
03551     RETURN_IF_ERR();
03552     RETURN_NONE();
03553 }
03554 
03555 #endif
03556 
03557 
03558 static PyObject*
03559 DBEnv_set_mp_mmapsize(DBEnvObject* self, PyObject* args)
03560 {
03561     int err, mp_mmapsize;
03562 
03563     if (!PyArg_ParseTuple(args, "i:set_mp_mmapsize", &mp_mmapsize))
03564         return NULL;
03565     CHECK_ENV_NOT_CLOSED(self);
03566 
03567     MYDB_BEGIN_ALLOW_THREADS;
03568     err = self->db_env->set_mp_mmapsize(self->db_env, mp_mmapsize);
03569     MYDB_END_ALLOW_THREADS;
03570     RETURN_IF_ERR();
03571     RETURN_NONE();
03572 }
03573 
03574 
03575 static PyObject*
03576 DBEnv_set_tmp_dir(DBEnvObject* self, PyObject* args)
03577 {
03578     int err;
03579     char *dir;
03580 
03581     if (!PyArg_ParseTuple(args, "s:set_tmp_dir", &dir))
03582         return NULL;
03583     CHECK_ENV_NOT_CLOSED(self);
03584 
03585     MYDB_BEGIN_ALLOW_THREADS;
03586     err = self->db_env->set_tmp_dir(self->db_env, dir);
03587     MYDB_END_ALLOW_THREADS;
03588     RETURN_IF_ERR();
03589     RETURN_NONE();
03590 }
03591 
03592 
03593 static PyObject*
03594 DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs)
03595 {
03596     int flags = 0;
03597     PyObject* txnobj = NULL;
03598     DB_TXN *txn = NULL;
03599     char* kwnames[] = { "parent", "flags", NULL };
03600 
03601     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:txn_begin", kwnames,
03602                                      &txnobj, &flags))
03603         return NULL;
03604 
03605     if (!checkTxnObj(txnobj, &txn))
03606         return NULL;
03607     CHECK_ENV_NOT_CLOSED(self);
03608 
03609     return (PyObject*)newDBTxnObject(self, txn, flags);
03610 }
03611 
03612 
03613 static PyObject*
03614 DBEnv_txn_checkpoint(DBEnvObject* self, PyObject* args)
03615 {
03616     int err, kbyte=0, min=0, flags=0;
03617 
03618     if (!PyArg_ParseTuple(args, "|iii:txn_checkpoint", &kbyte, &min, &flags))
03619         return NULL;
03620     CHECK_ENV_NOT_CLOSED(self);
03621 
03622     MYDB_BEGIN_ALLOW_THREADS;
03623 #if (DBVER >= 40)
03624     err = self->db_env->txn_checkpoint(self->db_env, kbyte, min, flags);
03625 #else
03626     err = txn_checkpoint(self->db_env, kbyte, min, flags);
03627 #endif
03628     MYDB_END_ALLOW_THREADS;
03629     RETURN_IF_ERR();
03630     RETURN_NONE();
03631 }
03632 
03633 
03634 static PyObject*
03635 DBEnv_set_tx_max(DBEnvObject* self, PyObject* args)
03636 {
03637     int err, max;
03638 
03639     if (!PyArg_ParseTuple(args, "i:set_tx_max", &max))
03640         return NULL;
03641     CHECK_ENV_NOT_CLOSED(self);
03642 
03643     MYDB_BEGIN_ALLOW_THREADS;
03644     err = self->db_env->set_tx_max(self->db_env, max);
03645     MYDB_END_ALLOW_THREADS;
03646     RETURN_IF_ERR();
03647     RETURN_NONE();
03648 }
03649 
03650 
03651 static PyObject*
03652 DBEnv_lock_detect(DBEnvObject* self, PyObject* args)
03653 {
03654     int err, atype, flags=0;
03655     int aborted = 0;
03656 
03657     if (!PyArg_ParseTuple(args, "i|i:lock_detect", &atype, &flags))
03658         return NULL;
03659     CHECK_ENV_NOT_CLOSED(self);
03660 
03661     MYDB_BEGIN_ALLOW_THREADS;
03662 #if (DBVER >= 40)
03663     err = self->db_env->lock_detect(self->db_env, flags, atype, &aborted);
03664 #else
03665     err = lock_detect(self->db_env, flags, atype, &aborted);
03666 #endif
03667     MYDB_END_ALLOW_THREADS;
03668     RETURN_IF_ERR();
03669     return PyInt_FromLong(aborted);
03670 }
03671 
03672 
03673 static PyObject*
03674 DBEnv_lock_get(DBEnvObject* self, PyObject* args)
03675 {
03676     int flags=0;
03677     int locker, lock_mode;
03678     DBT obj;
03679     PyObject* objobj;
03680 
03681     if (!PyArg_ParseTuple(args, "iOi|i:lock_get", &locker, &objobj, &lock_mode, &flags))
03682         return NULL;
03683 
03684 
03685     if (!make_dbt(objobj, &obj))
03686         return NULL;
03687 
03688     return (PyObject*)newDBLockObject(self, locker, &obj, lock_mode, flags);
03689 }
03690 
03691 
03692 static PyObject*
03693 DBEnv_lock_id(DBEnvObject* self, PyObject* args)
03694 {
03695     int err;
03696     u_int32_t theID;
03697 
03698     if (!PyArg_ParseTuple(args, ":lock_id"))
03699         return NULL;
03700 
03701     CHECK_ENV_NOT_CLOSED(self);
03702     MYDB_BEGIN_ALLOW_THREADS;
03703 #if (DBVER >= 40)
03704     err = self->db_env->lock_id(self->db_env, &theID);
03705 #else
03706     err = lock_id(self->db_env, &theID);
03707 #endif
03708     MYDB_END_ALLOW_THREADS;
03709     RETURN_IF_ERR();
03710 
03711     return PyInt_FromLong((long)theID);
03712 }
03713 
03714 
03715 static PyObject*
03716 DBEnv_lock_put(DBEnvObject* self, PyObject* args)
03717 {
03718     int err;
03719     DBLockObject* dblockobj;
03720 
03721     if (!PyArg_ParseTuple(args, "O!:lock_put", &DBLock_Type, &dblockobj))
03722         return NULL;
03723 
03724     CHECK_ENV_NOT_CLOSED(self);
03725     MYDB_BEGIN_ALLOW_THREADS;
03726 #if (DBVER >= 40)
03727     err = self->db_env->lock_put(self->db_env, &dblockobj->lock);
03728 #else
03729     err = lock_put(self->db_env, &dblockobj->lock);
03730 #endif
03731     MYDB_END_ALLOW_THREADS;
03732     RETURN_IF_ERR();
03733     RETURN_NONE();
03734 }
03735 
03736 
03737 static PyObject*
03738 DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
03739 {
03740     int err;
03741     DB_LOCK_STAT* sp;
03742     PyObject* d = NULL;
03743     u_int32_t flags = 0;
03744 
03745     if (!PyArg_ParseTuple(args, "|i:lock_stat", &flags))
03746         return NULL;
03747     CHECK_ENV_NOT_CLOSED(self);
03748 
03749     MYDB_BEGIN_ALLOW_THREADS;
03750 #if (DBVER >= 40)
03751     err = self->db_env->lock_stat(self->db_env, &sp, flags);
03752 #else
03753 #if (DBVER >= 33)
03754     err = lock_stat(self->db_env, &sp);
03755 #else
03756     err = lock_stat(self->db_env, &sp, NULL);
03757 #endif
03758 #endif
03759     MYDB_END_ALLOW_THREADS;
03760     RETURN_IF_ERR();
03761 
03762     /* Turn the stat structure into a dictionary */
03763     d = PyDict_New();
03764     if (d == NULL) {
03765         free(sp);
03766         return NULL;
03767     }
03768 
03769 #define MAKE_ENTRY(name)  _addIntToDict(d, #name, sp->st_##name)
03770 
03771 #if (DBVER < 41)
03772     MAKE_ENTRY(lastid);
03773 #endif
03774     MAKE_ENTRY(nmodes);
03775 #if (DBVER >= 32)
03776     MAKE_ENTRY(maxlocks);
03777     MAKE_ENTRY(maxlockers);
03778     MAKE_ENTRY(maxobjects);
03779     MAKE_ENTRY(nlocks);
03780     MAKE_ENTRY(maxnlocks);
03781 #endif
03782     MAKE_ENTRY(nlockers);
03783     MAKE_ENTRY(maxnlockers);
03784 #if (DBVER >= 32)
03785     MAKE_ENTRY(nobjects);
03786     MAKE_ENTRY(maxnobjects);
03787 #endif
03788     MAKE_ENTRY(nrequests);
03789     MAKE_ENTRY(nreleases);
03790     MAKE_ENTRY(nnowaits);
03791     MAKE_ENTRY(nconflicts);
03792     MAKE_ENTRY(ndeadlocks);
03793     MAKE_ENTRY(regsize);
03794     MAKE_ENTRY(region_wait);
03795     MAKE_ENTRY(region_nowait);
03796 
03797 #undef MAKE_ENTRY
03798     free(sp);
03799     return d;
03800 }
03801 
03802 
03803 static PyObject*
03804 DBEnv_log_archive(DBEnvObject* self, PyObject* args)
03805 {
03806     int flags=0;
03807     int err;
03808     char **log_list_start, **log_list;
03809     PyObject* list;
03810     PyObject* item = NULL;
03811 
03812     if (!PyArg_ParseTuple(args, "|i:log_archive", &flags))
03813         return NULL;
03814 
03815     CHECK_ENV_NOT_CLOSED(self);
03816     MYDB_BEGIN_ALLOW_THREADS;
03817 #if (DBVER >= 40)
03818     err = self->db_env->log_archive(self->db_env, &log_list, flags);
03819 #elif (DBVER == 33)
03820     err = log_archive(self->db_env, &log_list, flags);
03821 #else
03822     err = log_archive(self->db_env, &log_list, flags, NULL);
03823 #endif
03824     MYDB_END_ALLOW_THREADS;
03825     RETURN_IF_ERR();
03826 
03827     list = PyList_New(0);
03828     if (list == NULL) {
03829         PyErr_SetString(PyExc_MemoryError, "PyList_New failed");
03830         return NULL;
03831     }
03832 
03833     if (log_list) {
03834         for (log_list_start = log_list; *log_list != NULL; ++log_list) {
03835             item = PyString_FromString (*log_list);
03836             if (item == NULL) {
03837                 Py_DECREF(list);
03838                 PyErr_SetString(PyExc_MemoryError,
03839                                 "List item creation failed");
03840                 list = NULL;
03841                 break;
03842             }
03843             PyList_Append(list, item);
03844             Py_DECREF(item);
03845         }
03846         free(log_list_start);
03847     }
03848     return list;
03849 }
03850 
03851 
03852 static PyObject*
03853 DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
03854 {
03855     int err;
03856     DB_TXN_STAT* sp;
03857     PyObject* d = NULL;
03858     u_int32_t flags=0;
03859 
03860     if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
03861         return NULL;
03862     CHECK_ENV_NOT_CLOSED(self);
03863 
03864     MYDB_BEGIN_ALLOW_THREADS;
03865 #if (DBVER >= 40)
03866     err = self->db_env->txn_stat(self->db_env, &sp, flags);
03867 #elif (DBVER == 33)
03868     err = txn_stat(self->db_env, &sp);
03869 #else
03870     err = txn_stat(self->db_env, &sp, NULL);
03871 #endif
03872     MYDB_END_ALLOW_THREADS;
03873     RETURN_IF_ERR();
03874 
03875     /* Turn the stat structure into a dictionary */
03876     d = PyDict_New();
03877     if (d == NULL) {
03878         free(sp);
03879         return NULL;
03880     }
03881 
03882 #define MAKE_ENTRY(name)  _addIntToDict(d, #name, sp->st_##name)
03883 
03884     MAKE_ENTRY(time_ckp);
03885     MAKE_ENTRY(last_txnid);
03886     MAKE_ENTRY(maxtxns);
03887     MAKE_ENTRY(nactive);
03888     MAKE_ENTRY(maxnactive);
03889     MAKE_ENTRY(nbegins);
03890     MAKE_ENTRY(naborts);
03891     MAKE_ENTRY(ncommits);
03892     MAKE_ENTRY(regsize);
03893     MAKE_ENTRY(region_wait);
03894     MAKE_ENTRY(region_nowait);
03895 
03896 #undef MAKE_ENTRY
03897     free(sp);
03898     return d;
03899 }
03900 
03901 
03902 static PyObject*
03903 DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
03904 {
03905     int flags=0;
03906     int oldValue=0;
03907 
03908     if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
03909         return NULL;
03910     CHECK_ENV_NOT_CLOSED(self);
03911 
03912     if (self->moduleFlags.getReturnsNone)
03913         ++oldValue;
03914     if (self->moduleFlags.cursorSetReturnsNone)
03915         ++oldValue;
03916     self->moduleFlags.getReturnsNone = (flags >= 1);
03917     self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
03918     return PyInt_FromLong(oldValue);
03919 }
03920 
03921 
03922 /* --------------------------------------------------------------------- */
03923 /* DBTxn methods */
03924 
03925 
03926 static PyObject*
03927 DBTxn_commit(DBTxnObject* self, PyObject* args)
03928 {
03929     int flags=0, err;
03930     DB_TXN *txn;
03931 
03932     if (!PyArg_ParseTuple(args, "|i:commit", &flags))
03933         return NULL;
03934 
03935     if (!self->txn) {
03936         PyErr_SetObject(DBError, Py_BuildValue("(is)", 0,
03937             "DBTxn must not be used after txn_commit or txn_abort"));
03938         return NULL;
03939     }
03940     txn = self->txn;
03941     self->txn = NULL;   /* this DB_TXN is no longer valid after this call */
03942     MYDB_BEGIN_ALLOW_THREADS;
03943 #if (DBVER >= 40)
03944     err = txn->commit(txn, flags);
03945 #else
03946     err = txn_commit(txn, flags);
03947 #endif
03948     MYDB_END_ALLOW_THREADS;
03949     RETURN_IF_ERR();
03950     RETURN_NONE();
03951 }
03952 
03953 static PyObject*
03954 DBTxn_prepare(DBTxnObject* self, PyObject* args)
03955 {
03956 #if (DBVER >= 33)
03957     int err;
03958     char* gid=NULL;
03959     int   gid_size=0;
03960 
03961     if (!PyArg_ParseTuple(args, "s#:prepare", &gid, &gid_size))
03962         return NULL;
03963 
03964     if (gid_size != DB_XIDDATASIZE) {
03965         PyErr_SetString(PyExc_TypeError,
03966                         "gid must be DB_XIDDATASIZE bytes long");
03967         return NULL;
03968     }
03969 
03970     if (!self->txn) {
03971         PyErr_SetObject(DBError, Py_BuildValue("(is)", 0,
03972             "DBTxn must not be used after txn_commit or txn_abort"));
03973         return NULL;
03974     }
03975     MYDB_BEGIN_ALLOW_THREADS;
03976 #if (DBVER >= 40)
03977     err = self->txn->prepare(self->txn, (u_int8_t*)gid);
03978 #else
03979     err = txn_prepare(self->txn, (u_int8_t*)gid);
03980 #endif
03981     MYDB_END_ALLOW_THREADS;
03982     RETURN_IF_ERR();
03983     RETURN_NONE();
03984 #else
03985     int err;
03986 
03987     if (!PyArg_ParseTuple(args, ":prepare"))
03988         return NULL;
03989 
03990     if (!self->txn) {
03991         PyErr_SetObject(DBError, Py_BuildValue("(is)", 0,
03992             "DBTxn must not be used after txn_commit or txn_abort"));
03993         return NULL;
03994     }
03995     MYDB_BEGIN_ALLOW_THREADS;
03996     err = txn_prepare(self->txn);
03997     MYDB_END_ALLOW_THREADS;
03998     RETURN_IF_ERR();
03999     RETURN_NONE();
04000 #endif
04001 }
04002 
04003 
04004 static PyObject*
04005 DBTxn_abort(DBTxnObject* self, PyObject* args)
04006 {
04007     int err;
04008     DB_TXN *txn;
04009 
04010     if (!PyArg_ParseTuple(args, ":abort"))
04011         return NULL;
04012 
04013     if (!self->txn) {
04014         PyErr_SetObject(DBError, Py_BuildValue("(is)", 0,
04015             "DBTxn must not be used after txn_commit or txn_abort"));
04016         return NULL;
04017     }
04018     txn = self->txn;
04019     self->txn = NULL;   /* this DB_TXN is no longer valid after this call */
04020     MYDB_BEGIN_ALLOW_THREADS;
04021 #if (DBVER >= 40)
04022     err = txn->abort(txn);
04023 #else
04024     err = txn_abort(txn);
04025 #endif
04026     MYDB_END_ALLOW_THREADS;
04027     RETURN_IF_ERR();
04028     RETURN_NONE();
04029 }
04030 
04031 
04032 static PyObject*
04033 DBTxn_id(DBTxnObject* self, PyObject* args)
04034 {
04035     int id;
04036 
04037     if (!PyArg_ParseTuple(args, ":id"))
04038         return NULL;
04039 
04040     if (!self->txn) {
04041         PyErr_SetObject(DBError, Py_BuildValue("(is)", 0,
04042             "DBTxn must not be used after txn_commit or txn_abort"));
04043         return NULL;
04044     }
04045     MYDB_BEGIN_ALLOW_THREADS;
04046 #if (DBVER >= 40)
04047     id = self->txn->id(self->txn);
04048 #else
04049     id = txn_id(self->txn);
04050 #endif
04051     MYDB_END_ALLOW_THREADS;
04052     return PyInt_FromLong(id);
04053 }
04054 
04055 /* --------------------------------------------------------------------- */
04056 /* Method definition tables and type objects */
04057 
04058 static PyMethodDef DB_methods[] = {
04059     {"append",          (PyCFunction)DB_append,         METH_VARARGS},
04060 #if (DBVER >= 33)
04061     {"associate",       (PyCFunction)DB_associate,      METH_VARARGS|METH_KEYWORDS},
04062 #endif
04063     {"close",           (PyCFunction)DB_close,          METH_VARARGS},
04064 #if (DBVER >= 32)
04065     {"consume",         (PyCFunction)DB_consume,        METH_VARARGS|METH_KEYWORDS},
04066     {"consume_wait",    (PyCFunction)DB_consume_wait,   METH_VARARGS|METH_KEYWORDS},
04067 #endif
04068     {"cursor",          (PyCFunction)DB_cursor,         METH_VARARGS|METH_KEYWORDS},
04069     {"delete",          (PyCFunction)DB_delete,         METH_VARARGS|METH_KEYWORDS},
04070     {"fd",              (PyCFunction)DB_fd,             METH_VARARGS},
04071     {"get",             (PyCFunction)DB_get,            METH_VARARGS|METH_KEYWORDS},
04072     {"get_both",        (PyCFunction)DB_get_both,       METH_VARARGS|METH_KEYWORDS},
04073     {"get_byteswapped", (PyCFunction)DB_get_byteswapped,METH_VARARGS},
04074     {"get_size",        (PyCFunction)DB_get_size,       METH_VARARGS|METH_KEYWORDS},
04075     {"get_type",        (PyCFunction)DB_get_type,       METH_VARARGS},
04076     {"join",            (PyCFunction)DB_join,           METH_VARARGS},
04077     {"key_range",       (PyCFunction)DB_key_range,      METH_VARARGS|METH_KEYWORDS},
04078     {"has_key",         (PyCFunction)DB_has_key,        METH_VARARGS},
04079     {"items",           (PyCFunction)DB_items,          METH_VARARGS},
04080     {"keys",            (PyCFunction)DB_keys,           METH_VARARGS},
04081     {"open",            (PyCFunction)DB_open,           METH_VARARGS|METH_KEYWORDS},
04082     {"put",             (PyCFunction)DB_put,            METH_VARARGS|METH_KEYWORDS},
04083     {"remove",          (PyCFunction)DB_remove,         METH_VARARGS|METH_KEYWORDS},
04084     {"rename",          (PyCFunction)DB_rename,         METH_VARARGS},
04085     {"set_bt_minkey",   (PyCFunction)DB_set_bt_minkey,  METH_VARARGS},
04086     {"set_cachesize",   (PyCFunction)DB_set_cachesize,  METH_VARARGS},
04087 #if (DBVER >= 41)
04088     {"set_encrypt",     (PyCFunction)DB_set_encrypt,    METH_VARARGS|METH_KEYWORDS},
04089 #endif
04090     {"set_flags",       (PyCFunction)DB_set_flags,      METH_VARARGS},
04091     {"set_h_ffactor",   (PyCFunction)DB_set_h_ffactor,  METH_VARARGS},
04092     {"set_h_nelem",     (PyCFunction)DB_set_h_nelem,    METH_VARARGS},
04093     {"set_lorder",      (PyCFunction)DB_set_lorder,     METH_VARARGS},
04094     {"set_pagesize",    (PyCFunction)DB_set_pagesize,   METH_VARARGS},
04095     {"set_re_delim",    (PyCFunction)DB_set_re_delim,   METH_VARARGS},
04096     {"set_re_len",      (PyCFunction)DB_set_re_len,     METH_VARARGS},
04097     {"set_re_pad",      (PyCFunction)DB_set_re_pad,     METH_VARARGS},
04098     {"set_re_source",   (PyCFunction)DB_set_re_source,  METH_VARARGS},
04099 #if (DBVER >= 32)
04100     {"set_q_extentsize",(PyCFunction)DB_set_q_extentsize,METH_VARARGS},
04101 #endif
04102     {"stat",            (PyCFunction)DB_stat,           METH_VARARGS},
04103     {"sync",            (PyCFunction)DB_sync,           METH_VARARGS},
04104 #if (DBVER >= 33)
04105     {"truncate",        (PyCFunction)DB_truncate,       METH_VARARGS|METH_KEYWORDS},
04106 #endif
04107     {"type",            (PyCFunction)DB_get_type,       METH_VARARGS},
04108     {"upgrade",         (PyCFunction)DB_upgrade,        METH_VARARGS},
04109     {"values",          (PyCFunction)DB_values,         METH_VARARGS},
04110     {"verify",          (PyCFunction)DB_verify,         METH_VARARGS|METH_KEYWORDS},
04111     {"set_get_returns_none",(PyCFunction)DB_set_get_returns_none,      METH_VARARGS},
04112     {NULL,      NULL}       /* sentinel */
04113 };
04114 
04115 
04116 static PyMappingMethods DB_mapping = {
04117         (inquiry)DB_length,          /*mp_length*/
04118         (binaryfunc)DB_subscript,    /*mp_subscript*/
04119         (objobjargproc)DB_ass_sub,   /*mp_ass_subscript*/
04120 };
04121 
04122 
04123 static PyMethodDef DBCursor_methods[] = {
04124     {"close",           (PyCFunction)DBC_close,         METH_VARARGS},
04125     {"count",           (PyCFunction)DBC_count,         METH_VARARGS},
04126     {"current",         (PyCFunction)DBC_current,       METH_VARARGS|METH_KEYWORDS},
04127     {"delete",          (PyCFunction)DBC_delete,        METH_VARARGS},
04128     {"dup",             (PyCFunction)DBC_dup,           METH_VARARGS},
04129     {"first",           (PyCFunction)DBC_first,         METH_VARARGS|METH_KEYWORDS},
04130     {"get",             (PyCFunction)DBC_get,           METH_VARARGS|METH_KEYWORDS},
04131     {"get_recno",       (PyCFunction)DBC_get_recno,     METH_VARARGS},
04132     {"last",            (PyCFunction)DBC_last,          METH_VARARGS|METH_KEYWORDS},
04133     {"next",            (PyCFunction)DBC_next,          METH_VARARGS|METH_KEYWORDS},
04134     {"prev",            (PyCFunction)DBC_prev,          METH_VARARGS|METH_KEYWORDS},
04135     {"put",             (PyCFunction)DBC_put,           METH_VARARGS|METH_KEYWORDS},
04136     {"set",             (PyCFunction)DBC_set,           METH_VARARGS|METH_KEYWORDS},
04137     {"set_range",       (PyCFunction)DBC_set_range,     METH_VARARGS|METH_KEYWORDS},
04138     {"get_both",        (PyCFunction)DBC_get_both,      METH_VARARGS},
04139     {"get_current_size",(PyCFunction)DBC_get_current_size, METH_VARARGS},
04140     {"set_both",        (PyCFunction)DBC_set_both,      METH_VARARGS},
04141     {"set_recno",       (PyCFunction)DBC_set_recno,     METH_VARARGS|METH_KEYWORDS},
04142     {"consume",         (PyCFunction)DBC_consume,       METH_VARARGS|METH_KEYWORDS},
04143     {"next_dup",        (PyCFunction)DBC_next_dup,      METH_VARARGS|METH_KEYWORDS},
04144     {"next_nodup",      (PyCFunction)DBC_next_nodup,    METH_VARARGS|METH_KEYWORDS},
04145     {"prev_nodup",      (PyCFunction)DBC_prev_nodup,    METH_VARARGS|METH_KEYWORDS},
04146     {"join_item",       (PyCFunction)DBC_join_item,     METH_VARARGS},
04147     {NULL,      NULL}       /* sentinel */
04148 };
04149 
04150 
04151 static PyMethodDef DBEnv_methods[] = {
04152     {"close",           (PyCFunction)DBEnv_close,            METH_VARARGS},
04153     {"open",            (PyCFunction)DBEnv_open,             METH_VARARGS},
04154     {"remove",          (PyCFunction)DBEnv_remove,           METH_VARARGS},
04155 #if (DBVER >= 41)
04156     {"dbremove",        (PyCFunction)DBEnv_dbremove,         METH_VARARGS|METH_KEYWORDS},
04157     {"dbrename",        (PyCFunction)DBEnv_dbrename,         METH_VARARGS|METH_KEYWORDS},
04158     {"set_encrypt",     (PyCFunction)DBEnv_set_encrypt,      METH_VARARGS|METH_KEYWORDS},
04159 #endif
04160 #if (DBVER >= 40)
04161     {"set_timeout",     (PyCFunction)DBEnv_set_timeout,      METH_VARARGS|METH_KEYWORDS},
04162 #endif
04163     {"set_shm_key",     (PyCFunction)DBEnv_set_shm_key,      METH_VARARGS},
04164     {"set_cachesize",   (PyCFunction)DBEnv_set_cachesize,    METH_VARARGS},
04165     {"set_data_dir",    (PyCFunction)DBEnv_set_data_dir,     METH_VARARGS},
04166 #if (DBVER >= 32)
04167     {"set_flags",       (PyCFunction)DBEnv_set_flags,        METH_VARARGS},
04168 #endif
04169     {"set_lg_bsize",    (PyCFunction)DBEnv_set_lg_bsize,     METH_VARARGS},
04170     {"set_lg_dir",      (PyCFunction)DBEnv_set_lg_dir,       METH_VARARGS},
04171     {"set_lg_max",      (PyCFunction)DBEnv_set_lg_max,       METH_VARARGS},
04172     {"set_lk_detect",   (PyCFunction)DBEnv_set_lk_detect,    METH_VARARGS},
04173     {"set_lk_max",      (PyCFunction)DBEnv_set_lk_max,       METH_VARARGS},
04174 #if (DBVER >= 32)
04175     {"set_lk_max_locks", (PyCFunction)DBEnv_set_lk_max_locks, METH_VARARGS},
04176     {"set_lk_max_lockers", (PyCFunction)DBEnv_set_lk_max_lockers, METH_VARARGS},
04177     {"set_lk_max_objects", (PyCFunction)DBEnv_set_lk_max_objects, METH_VARARGS},
04178 #endif
04179     {"set_mp_mmapsize", (PyCFunction)DBEnv_set_mp_mmapsize,  METH_VARARGS},
04180     {"set_tmp_dir",     (PyCFunction)DBEnv_set_tmp_dir,      METH_VARARGS},
04181     {"txn_begin",       (PyCFunction)DBEnv_txn_begin,        METH_VARARGS|METH_KEYWORDS},
04182     {"txn_checkpoint",  (PyCFunction)DBEnv_txn_checkpoint,   METH_VARARGS},
04183     {"txn_stat",        (PyCFunction)DBEnv_txn_stat,         METH_VARARGS},
04184     {"set_tx_max",      (PyCFunction)DBEnv_set_tx_max,       METH_VARARGS},
04185     {"lock_detect",     (PyCFunction)DBEnv_lock_detect,      METH_VARARGS},
04186     {"lock_get",        (PyCFunction)DBEnv_lock_get,         METH_VARARGS},
04187     {"lock_id",         (PyCFunction)DBEnv_lock_id,          METH_VARARGS},
04188     {"lock_put",        (PyCFunction)DBEnv_lock_put,         METH_VARARGS},
04189     {"lock_stat",       (PyCFunction)DBEnv_lock_stat,        METH_VARARGS},
04190     {"log_archive",     (PyCFunction)DBEnv_log_archive,      METH_VARARGS},
04191     {"set_get_returns_none",(PyCFunction)DBEnv_set_get_returns_none, METH_VARARGS},
04192     {NULL,      NULL}       /* sentinel */
04193 };
04194 
04195 
04196 static PyMethodDef DBTxn_methods[] = {
04197     {"commit",          (PyCFunction)DBTxn_commit,      METH_VARARGS},
04198     {"prepare",         (PyCFunction)DBTxn_prepare,     METH_VARARGS},
04199     {"abort",           (PyCFunction)DBTxn_abort,       METH_VARARGS},
04200     {"id",              (PyCFunction)DBTxn_id,          METH_VARARGS},
04201     {NULL,      NULL}       /* sentinel */
04202 };
04203 
04204 
04205 static PyObject*
04206 DB_getattr(DBObject* self, char *name)
04207 {
04208     return Py_FindMethod(DB_methods, (PyObject* )self, name);
04209 }
04210 
04211 
04212 static PyObject*
04213 DBEnv_getattr(DBEnvObject* self, char *name)
04214 {
04215     if (!strcmp(name, "db_home")) {
04216         CHECK_ENV_NOT_CLOSED(self);
04217         if (self->db_env->db_home == NULL) {
04218             RETURN_NONE();
04219         }
04220         return PyString_FromString(self->db_env->db_home);
04221     }
04222 
04223     return Py_FindMethod(DBEnv_methods, (PyObject* )self, name);
04224 }
04225 
04226 
04227 static PyObject*
04228 DBCursor_getattr(DBCursorObject* self, char *name)
04229 {
04230     return Py_FindMethod(DBCursor_methods, (PyObject* )self, name);
04231 }
04232 
04233 static PyObject*
04234 DBTxn_getattr(DBTxnObject* self, char *name)
04235 {
04236     return Py_FindMethod(DBTxn_methods, (PyObject* )self, name);
04237 }
04238 
04239 static PyObject*
04240 DBLock_getattr(DBLockObject* self, char *name)
04241 {
04242     return NULL;
04243 }
04244 
04245 statichere PyTypeObject DB_Type = {
04246     PyObject_HEAD_INIT(NULL)
04247     0,                  /*ob_size*/
04248     "DB",               /*tp_name*/
04249     sizeof(DBObject),   /*tp_basicsize*/
04250     0,                  /*tp_itemsize*/
04251     /* methods */
04252     (destructor)DB_dealloc, /*tp_dealloc*/
04253     0,                  /*tp_print*/
04254     (getattrfunc)DB_getattr, /*tp_getattr*/
04255     0,                      /*tp_setattr*/
04256     0,          /*tp_compare*/
04257     0,          /*tp_repr*/
04258     0,          /*tp_as_number*/
04259     0,          /*tp_as_sequence*/
04260     &DB_mapping,/*tp_as_mapping*/
04261     0,          /*tp_hash*/
04262 };
04263 
04264 
04265 statichere PyTypeObject DBCursor_Type = {
04266     PyObject_HEAD_INIT(NULL)
04267     0,                  /*ob_size*/
04268     "DBCursor",         /*tp_name*/
04269     sizeof(DBCursorObject),  /*tp_basicsize*/
04270     0,                  /*tp_itemsize*/
04271     /* methods */
04272     (destructor)DBCursor_dealloc,/*tp_dealloc*/
04273     0,                  /*tp_print*/
04274     (getattrfunc)DBCursor_getattr, /*tp_getattr*/
04275     0,                  /*tp_setattr*/
04276     0,                  /*tp_compare*/
04277     0,                  /*tp_repr*/
04278     0,                  /*tp_as_number*/
04279     0,                  /*tp_as_sequence*/
04280     0,                  /*tp_as_mapping*/
04281     0,                  /*tp_hash*/
04282 #ifdef HAVE_WEAKREF
04283     0,                  /* tp_call */
04284     0,                  /* tp_str */
04285     0,                  /* tp_getattro */
04286     0,                  /* tp_setattro */
04287     0,                  /* tp_as_buffer */
04288     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS,      /* tp_flags */
04289     0,                  /* tp_doc */
04290     0,                  /* tp_traverse */
04291     0,                  /* tp_clear */
04292     0,                  /* tp_richcompare */
04293     offsetof(DBCursorObject, in_weakreflist),   /* tp_weaklistoffset */
04294 #endif
04295 };
04296 
04297 
04298 statichere PyTypeObject DBEnv_Type = {
04299     PyObject_HEAD_INIT(NULL)
04300     0,          /*ob_size*/
04301     "DBEnv",            /*tp_name*/
04302     sizeof(DBEnvObject),    /*tp_basicsize*/
04303     0,          /*tp_itemsize*/
04304     /* methods */
04305     (destructor)DBEnv_dealloc, /*tp_dealloc*/
04306     0,          /*tp_print*/
04307     (getattrfunc)DBEnv_getattr, /*tp_getattr*/
04308     0,          /*tp_setattr*/
04309     0,          /*tp_compare*/
04310     0,          /*tp_repr*/
04311     0,          /*tp_as_number*/
04312     0,          /*tp_as_sequence*/
04313     0,          /*tp_as_mapping*/
04314     0,          /*tp_hash*/
04315 };
04316 
04317 statichere PyTypeObject DBTxn_Type = {
04318     PyObject_HEAD_INIT(NULL)
04319     0,          /*ob_size*/
04320     "DBTxn",    /*tp_name*/
04321     sizeof(DBTxnObject),  /*tp_basicsize*/
04322     0,          /*tp_itemsize*/
04323     /* methods */
04324     (destructor)DBTxn_dealloc, /*tp_dealloc*/
04325     0,          /*tp_print*/
04326     (getattrfunc)DBTxn_getattr, /*tp_getattr*/
04327     0,                      /*tp_setattr*/
04328     0,          /*tp_compare*/
04329     0,          /*tp_repr*/
04330     0,          /*tp_as_number*/
04331     0,          /*tp_as_sequence*/
04332     0,          /*tp_as_mapping*/
04333     0,          /*tp_hash*/
04334 };
04335 
04336 
04337 statichere PyTypeObject DBLock_Type = {
04338     PyObject_HEAD_INIT(NULL)
04339     0,          /*ob_size*/
04340     "DBLock",   /*tp_name*/
04341     sizeof(DBLockObject),  /*tp_basicsize*/
04342     0,          /*tp_itemsize*/
04343     /* methods */
04344     (destructor)DBLock_dealloc, /*tp_dealloc*/
04345     0,          /*tp_print*/
04346     (getattrfunc)DBLock_getattr, /*tp_getattr*/
04347     0,                      /*tp_setattr*/
04348     0,          /*tp_compare*/
04349     0,          /*tp_repr*/
04350     0,          /*tp_as_number*/
04351     0,          /*tp_as_sequence*/
04352     0,          /*tp_as_mapping*/
04353     0,          /*tp_hash*/
04354 };
04355 
04356 
04357 /* --------------------------------------------------------------------- */
04358 /* Module-level functions */
04359 
04360 static PyObject*
04361 DB_construct(PyObject* self, PyObject* args, PyObject* kwargs)
04362 {
04363     PyObject* dbenvobj = NULL;
04364     int flags = 0;
04365     char* kwnames[] = { "dbEnv", "flags", NULL};
04366 
04367     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:DB", kwnames,
04368                                      &dbenvobj, &flags))
04369         return NULL;
04370     if (dbenvobj == Py_None)
04371         dbenvobj = NULL;
04372     else if (dbenvobj && !DBEnvObject_Check(dbenvobj)) {
04373         makeTypeError("DBEnv", dbenvobj);
04374         return NULL;
04375     }
04376 
04377     return (PyObject* )newDBObject((DBEnvObject*)dbenvobj, flags);
04378 }
04379 
04380 
04381 static PyObject*
04382 DBEnv_construct(PyObject* self, PyObject* args)
04383 {
04384     int flags = 0;
04385     if (!PyArg_ParseTuple(args, "|i:DbEnv", &flags)) return NULL;
04386     return (PyObject* )newDBEnvObject(flags);
04387 }
04388 
04389 
04390 static char bsddb_version_doc[] =
04391 "Returns a tuple of major, minor, and patch release numbers of the\n\
04392 underlying DB library.";
04393 
04394 static PyObject*
04395 bsddb_version(PyObject* self, PyObject* args)
04396 {
04397     int major, minor, patch;
04398 
04399         if (!PyArg_ParseTuple(args, ":version"))
04400         return NULL;
04401         db_version(&major, &minor, &patch);
04402         return Py_BuildValue("(iii)", major, minor, patch);
04403 }
04404 
04405 
04406 /* List of functions defined in the module */
04407 
04408 static PyMethodDef bsddb_methods[] = {
04409     {"DB",      (PyCFunction)DB_construct,      METH_VARARGS | METH_KEYWORDS },
04410     {"DBEnv",   (PyCFunction)DBEnv_construct,   METH_VARARGS},
04411     {"version", (PyCFunction)bsddb_version,     METH_VARARGS, bsddb_version_doc},
04412     {NULL,      NULL}       /* sentinel */
04413 };
04414 
04415 
04416 /* --------------------------------------------------------------------- */
04417 /* Module initialization */
04418 
04419 
04420 /* Convenience routine to export an integer value.
04421  * Errors are silently ignored, for better or for worse...
04422  */
04423 #define ADD_INT(dict, NAME)         _addIntToDict(dict, #NAME, NAME)
04424 
04425 #define MODULE_NAME_MAX_LEN     11
04426 static char _bsddbModuleName[MODULE_NAME_MAX_LEN+1] = "_bsddb";
04427 
04428 DL_EXPORT(void) init_bsddb(void)
04429 {
04430     PyObject* m;
04431     PyObject* d;
04432     PyObject* pybsddb_version_s = PyString_FromString( PY_BSDDB_VERSION );
04433     PyObject* db_version_s = PyString_FromString( DB_VERSION_STRING );
04434     PyObject* cvsid_s = PyString_FromString( rcs_id );
04435 
04436     /* Initialize the type of the new type objects here; doing it here
04437        is required for portability to Windows without requiring C++. */
04438     DB_Type.ob_type = &PyType_Type;
04439     DBCursor_Type.ob_type = &PyType_Type;
04440     DBEnv_Type.ob_type = &PyType_Type;
04441     DBTxn_Type.ob_type = &PyType_Type;
04442     DBLock_Type.ob_type = &PyType_Type;
04443 
04444 
04445 #if defined(WITH_THREAD) && !defined(MYDB_USE_GILSTATE)
04446     /* Save the current interpreter, so callbacks can do the right thing. */
04447     _db_interpreterState = PyThreadState_Get()->interp;
04448 #endif
04449 
04450     /* Create the module and add the functions */
04451     m = Py_InitModule(_bsddbModuleName, bsddb_methods);
04452 
04453     /* Add some symbolic constants to the module */
04454     d = PyModule_GetDict(m);
04455     PyDict_SetItemString(d, "__version__", pybsddb_version_s);
04456     PyDict_SetItemString(d, "cvsid", cvsid_s);
04457     PyDict_SetItemString(d, "DB_VERSION_STRING", db_version_s);
04458     Py_DECREF(pybsddb_version_s);
04459     pybsddb_version_s = NULL;
04460     Py_DECREF(cvsid_s);
04461     cvsid_s = NULL;
04462     Py_DECREF(db_version_s);
04463     db_version_s = NULL;
04464 
04465     ADD_INT(d, DB_VERSION_MAJOR);
04466     ADD_INT(d, DB_VERSION_MINOR);
04467     ADD_INT(d, DB_VERSION_PATCH);
04468 
04469     ADD_INT(d, DB_MAX_PAGES);
04470     ADD_INT(d, DB_MAX_RECORDS);
04471 
04472 #if (DBVER >= 42)
04473     ADD_INT(d, DB_RPCCLIENT);
04474 #else
04475     ADD_INT(d, DB_CLIENT);
04476     /* allow apps to be written using DB_RPCCLIENT on older BerkeleyDB */
04477     _addIntToDict(d, "DB_RPCCLIENT", DB_CLIENT);
04478 #endif
04479     ADD_INT(d, DB_XA_CREATE);
04480 
04481     ADD_INT(d, DB_CREATE);
04482     ADD_INT(d, DB_NOMMAP);
04483     ADD_INT(d, DB_THREAD);
04484 
04485     ADD_INT(d, DB_FORCE);
04486     ADD_INT(d, DB_INIT_CDB);
04487     ADD_INT(d, DB_INIT_LOCK);
04488     ADD_INT(d, DB_INIT_LOG);
04489     ADD_INT(d, DB_INIT_MPOOL);
04490     ADD_INT(d, DB_INIT_TXN);
04491 #if (DBVER >= 32)
04492     ADD_INT(d, DB_JOINENV);
04493 #endif
04494 
04495     ADD_INT(d, DB_RECOVER);
04496     ADD_INT(d, DB_RECOVER_FATAL);
04497     ADD_INT(d, DB_TXN_NOSYNC);
04498     ADD_INT(d, DB_USE_ENVIRON);
04499     ADD_INT(d, DB_USE_ENVIRON_ROOT);
04500 
04501     ADD_INT(d, DB_LOCKDOWN);
04502     ADD_INT(d, DB_PRIVATE);
04503     ADD_INT(d, DB_SYSTEM_MEM);
04504 
04505     ADD_INT(d, DB_TXN_SYNC);
04506     ADD_INT(d, DB_TXN_NOWAIT);
04507 
04508     ADD_INT(d, DB_EXCL);
04509     ADD_INT(d, DB_FCNTL_LOCKING);
04510     ADD_INT(d, DB_ODDFILESIZE);
04511     ADD_INT(d, DB_RDWRMASTER);
04512     ADD_INT(d, DB_RDONLY);
04513     ADD_INT(d, DB_TRUNCATE);
04514 #if (DBVER >= 32)
04515     ADD_INT(d, DB_EXTENT);
04516     ADD_INT(d, DB_CDB_ALLDB);
04517     ADD_INT(d, DB_VERIFY);
04518 #endif
04519     ADD_INT(d, DB_UPGRADE);
04520 
04521     ADD_INT(d, DB_AGGRESSIVE);
04522     ADD_INT(d, DB_NOORDERCHK);
04523     ADD_INT(d, DB_ORDERCHKONLY);
04524     ADD_INT(d, DB_PR_PAGE);
04525 #if ! (DBVER >= 33)
04526     ADD_INT(d, DB_VRFY_FLAGMASK);
04527     ADD_INT(d, DB_PR_HEADERS);
04528 #endif
04529     ADD_INT(d, DB_PR_RECOVERYTEST);
04530     ADD_INT(d, DB_SALVAGE);
04531 
04532     ADD_INT(d, DB_LOCK_NORUN);
04533     ADD_INT(d, DB_LOCK_DEFAULT);
04534     ADD_INT(d, DB_LOCK_OLDEST);
04535     ADD_INT(d, DB_LOCK_RANDOM);
04536     ADD_INT(d, DB_LOCK_YOUNGEST);
04537 #if (DBVER >= 33)
04538     ADD_INT(d, DB_LOCK_MAXLOCKS);
04539     ADD_INT(d, DB_LOCK_MINLOCKS);
04540     ADD_INT(d, DB_LOCK_MINWRITE);
04541 #endif
04542 
04543 
04544 #if (DBVER >= 33)
04545     /* docs say to use zero instead */
04546     _addIntToDict(d, "DB_LOCK_CONFLICT", 0);
04547 #else
04548     ADD_INT(d, DB_LOCK_CONFLICT);
04549 #endif
04550 
04551     ADD_INT(d, DB_LOCK_DUMP);
04552     ADD_INT(d, DB_LOCK_GET);
04553     ADD_INT(d, DB_LOCK_INHERIT);
04554     ADD_INT(d, DB_LOCK_PUT);
04555     ADD_INT(d, DB_LOCK_PUT_ALL);
04556     ADD_INT(d, DB_LOCK_PUT_OBJ);
04557 
04558     ADD_INT(d, DB_LOCK_NG);
04559     ADD_INT(d, DB_LOCK_READ);
04560     ADD_INT(d, DB_LOCK_WRITE);
04561     ADD_INT(d, DB_LOCK_NOWAIT);
04562 #if (DBVER >= 32)
04563     ADD_INT(d, DB_LOCK_WAIT);
04564 #endif
04565     ADD_INT(d, DB_LOCK_IWRITE);
04566     ADD_INT(d, DB_LOCK_IREAD);
04567     ADD_INT(d, DB_LOCK_IWR);
04568 #if (DBVER >= 33)
04569     ADD_INT(d, DB_LOCK_DIRTY);
04570     ADD_INT(d, DB_LOCK_WWRITE);
04571 #endif
04572 
04573     ADD_INT(d, DB_LOCK_RECORD);
04574     ADD_INT(d, DB_LOCK_UPGRADE);
04575 #if (DBVER >= 32)
04576     ADD_INT(d, DB_LOCK_SWITCH);
04577 #endif
04578 #if (DBVER >= 33)
04579     ADD_INT(d, DB_LOCK_UPGRADE_WRITE);
04580 #endif
04581 
04582     ADD_INT(d, DB_LOCK_NOWAIT);
04583     ADD_INT(d, DB_LOCK_RECORD);
04584     ADD_INT(d, DB_LOCK_UPGRADE);
04585 
04586 #if (DBVER >= 33)
04587     ADD_INT(d, DB_LSTAT_ABORTED);
04588     ADD_INT(d, DB_LSTAT_ERR);
04589     ADD_INT(d, DB_LSTAT_FREE);
04590     ADD_INT(d, DB_LSTAT_HELD);
04591 #if (DBVER == 33)
04592     ADD_INT(d, DB_LSTAT_NOGRANT);
04593 #endif
04594     ADD_INT(d, DB_LSTAT_PENDING);
04595     ADD_INT(d, DB_LSTAT_WAITING);
04596 #endif
04597 
04598     ADD_INT(d, DB_ARCH_ABS);
04599     ADD_INT(d, DB_ARCH_DATA);
04600     ADD_INT(d, DB_ARCH_LOG);
04601 
04602     ADD_INT(d, DB_BTREE);
04603     ADD_INT(d, DB_HASH);
04604     ADD_INT(d, DB_RECNO);
04605     ADD_INT(d, DB_QUEUE);
04606     ADD_INT(d, DB_UNKNOWN);
04607 
04608     ADD_INT(d, DB_DUP);
04609     ADD_INT(d, DB_DUPSORT);
04610     ADD_INT(d, DB_RECNUM);
04611     ADD_INT(d, DB_RENUMBER);
04612     ADD_INT(d, DB_REVSPLITOFF);
04613     ADD_INT(d, DB_SNAPSHOT);
04614 
04615     ADD_INT(d, DB_JOIN_NOSORT);
04616 
04617     ADD_INT(d, DB_AFTER);
04618     ADD_INT(d, DB_APPEND);
04619     ADD_INT(d, DB_BEFORE);
04620     ADD_INT(d, DB_CACHED_COUNTS);
04621 #if (DBVER >= 41)
04622     _addIntToDict(d, "DB_CHECKPOINT", 0);
04623 #else
04624     ADD_INT(d, DB_CHECKPOINT);
04625     ADD_INT(d, DB_CURLSN);
04626 #endif
04627 #if ((DBVER >= 33) && (DBVER <= 41))
04628     ADD_INT(d, DB_COMMIT);
04629 #endif
04630     ADD_INT(d, DB_CONSUME);
04631 #if (DBVER >= 32)
04632     ADD_INT(d, DB_CONSUME_WAIT);
04633 #endif
04634     ADD_INT(d, DB_CURRENT);
04635 #if (DBVER >= 33)
04636     ADD_INT(d, DB_FAST_STAT);
04637 #endif
04638     ADD_INT(d, DB_FIRST);
04639     ADD_INT(d, DB_FLUSH);
04640     ADD_INT(d, DB_GET_BOTH);
04641     ADD_INT(d, DB_GET_RECNO);
04642     ADD_INT(d, DB_JOIN_ITEM);
04643     ADD_INT(d, DB_KEYFIRST);
04644     ADD_INT(d, DB_KEYLAST);
04645     ADD_INT(d, DB_LAST);
04646     ADD_INT(d, DB_NEXT);
04647     ADD_INT(d, DB_NEXT_DUP);
04648     ADD_INT(d, DB_NEXT_NODUP);
04649     ADD_INT(d, DB_NODUPDATA);
04650     ADD_INT(d, DB_NOOVERWRITE);
04651     ADD_INT(d, DB_NOSYNC);
04652     ADD_INT(d, DB_POSITION);
04653     ADD_INT(d, DB_PREV);
04654     ADD_INT(d, DB_PREV_NODUP);
04655     ADD_INT(d, DB_RECORDCOUNT);
04656     ADD_INT(d, DB_SET);
04657     ADD_INT(d, DB_SET_RANGE);
04658     ADD_INT(d, DB_SET_RECNO);
04659     ADD_INT(d, DB_WRITECURSOR);
04660 
04661     ADD_INT(d, DB_OPFLAGS_MASK);
04662     ADD_INT(d, DB_RMW);
04663 #if (DBVER >= 33)
04664     ADD_INT(d, DB_DIRTY_READ);
04665     ADD_INT(d, DB_MULTIPLE);
04666     ADD_INT(d, DB_MULTIPLE_KEY);
04667 #endif
04668 
04669 #if (DBVER >= 33)
04670     ADD_INT(d, DB_DONOTINDEX);
04671 #endif
04672 
04673 #if (DBVER >= 41)
04674     _addIntToDict(d, "DB_INCOMPLETE", 0);
04675 #else
04676     ADD_INT(d, DB_INCOMPLETE);
04677 #endif
04678     ADD_INT(d, DB_KEYEMPTY);
04679     ADD_INT(d, DB_KEYEXIST);
04680     ADD_INT(d, DB_LOCK_DEADLOCK);
04681     ADD_INT(d, DB_LOCK_NOTGRANTED);
04682     ADD_INT(d, DB_NOSERVER);
04683     ADD_INT(d, DB_NOSERVER_HOME);
04684     ADD_INT(d, DB_NOSERVER_ID);
04685     ADD_INT(d, DB_NOTFOUND);
04686     ADD_INT(d, DB_OLD_VERSION);
04687     ADD_INT(d, DB_RUNRECOVERY);
04688     ADD_INT(d, DB_VERIFY_BAD);
04689 #if (DBVER >= 33)
04690     ADD_INT(d, DB_PAGE_NOTFOUND);
04691     ADD_INT(d, DB_SECONDARY_BAD);
04692 #endif
04693 #if (DBVER >= 40)
04694     ADD_INT(d, DB_STAT_CLEAR);
04695     ADD_INT(d, DB_REGION_INIT);
04696     ADD_INT(d, DB_NOLOCKING);
04697     ADD_INT(d, DB_YIELDCPU);
04698     ADD_INT(d, DB_PANIC_ENVIRONMENT);
04699     ADD_INT(d, DB_NOPANIC);
04700 #endif
04701 
04702 #if (DBVER >= 42)
04703     ADD_INT(d, DB_TIME_NOTGRANTED);
04704     ADD_INT(d, DB_TXN_NOT_DURABLE);
04705     ADD_INT(d, DB_TXN_WRITE_NOSYNC);
04706     ADD_INT(d, DB_LOG_AUTOREMOVE);
04707     ADD_INT(d, DB_DIRECT_LOG);
04708     ADD_INT(d, DB_DIRECT_DB);
04709     ADD_INT(d, DB_INIT_REP);
04710     ADD_INT(d, DB_ENCRYPT);
04711     ADD_INT(d, DB_CHKSUM);
04712 #endif
04713 
04714 #if (DBVER >= 41)
04715     ADD_INT(d, DB_ENCRYPT_AES);
04716     ADD_INT(d, DB_AUTO_COMMIT);
04717 #else
04718     /* allow berkeleydb 4.1 aware apps to run on older versions */
04719     _addIntToDict(d, "DB_AUTO_COMMIT", 0);
04720 #endif
04721 
04722     ADD_INT(d, EINVAL);
04723     ADD_INT(d, EACCES);
04724     ADD_INT(d, ENOSPC);
04725     ADD_INT(d, ENOMEM);
04726     ADD_INT(d, EAGAIN);
04727     ADD_INT(d, EBUSY);
04728     ADD_INT(d, EEXIST);
04729     ADD_INT(d, ENOENT);
04730     ADD_INT(d, EPERM);
04731 
04732 #if (DBVER >= 40)
04733     ADD_INT(d, DB_SET_LOCK_TIMEOUT);
04734     ADD_INT(d, DB_SET_TXN_TIMEOUT);
04735 #endif
04736 
04737     /* The base exception class is DBError */
04738     DBError = PyErr_NewException("bsddb._db.DBError", NULL, NULL);
04739     PyDict_SetItemString(d, "DBError", DBError);
04740 
04741     /* Some magic to make DBNotFoundError derive from both DBError and
04742        KeyError, since the API only supports using one base class. */
04743     PyDict_SetItemString(d, "KeyError", PyExc_KeyError);
04744     PyRun_String("class DBNotFoundError(DBError, KeyError): pass",
04745                  Py_file_input, d, d);
04746     DBNotFoundError = PyDict_GetItemString(d, "DBNotFoundError");
04747     PyDict_DelItemString(d, "KeyError");
04748 
04749 
04750     /* All the rest of the exceptions derive only from DBError */
04751 #define MAKE_EX(name)   name = PyErr_NewException("bsddb._db." #name, DBError, NULL); \
04752                         PyDict_SetItemString(d, #name, name)
04753 
04754 #if !INCOMPLETE_IS_WARNING
04755     MAKE_EX(DBIncompleteError);
04756 #endif
04757     MAKE_EX(DBCursorClosedError);
04758     MAKE_EX(DBKeyEmptyError);
04759     MAKE_EX(DBKeyExistError);
04760     MAKE_EX(DBLockDeadlockError);
04761     MAKE_EX(DBLockNotGrantedError);
04762     MAKE_EX(DBOldVersionError);
04763     MAKE_EX(DBRunRecoveryError);
04764     MAKE_EX(DBVerifyBadError);
04765     MAKE_EX(DBNoServerError);
04766     MAKE_EX(DBNoServerHomeError);
04767     MAKE_EX(DBNoServerIDError);
04768 #if (DBVER >= 33)
04769     MAKE_EX(DBPageNotFoundError);
04770     MAKE_EX(DBSecondaryBadError);
04771 #endif
04772 
04773     MAKE_EX(DBInvalidArgError);
04774     MAKE_EX(DBAccessError);
04775     MAKE_EX(DBNoSpaceError);
04776     MAKE_EX(DBNoMemoryError);
04777     MAKE_EX(DBAgainError);
04778     MAKE_EX(DBBusyError);
04779     MAKE_EX(DBFileExistsError);
04780     MAKE_EX(DBNoSuchFileError);
04781     MAKE_EX(DBPermissionsError);
04782 
04783 #undef MAKE_EX
04784 
04785     /* Check for errors */
04786     if (PyErr_Occurred()) {
04787         PyErr_Print();
04788         Py_FatalError("can't initialize module _bsddb");
04789     }
04790 }
04791 
04792 /* allow this module to be named _pybsddb so that it can be installed
04793  * and imported on top of python >= 2.3 that includes its own older
04794  * copy of the library named _bsddb without importing the old version. */
04795 DL_EXPORT(void) init_pybsddb(void)
04796 {
04797     strncpy(_bsddbModuleName, "_pybsddb", MODULE_NAME_MAX_LEN);
04798     init_bsddb();
04799 }
04800 
04801 /* allow this module to be named _rpmdb too. */
04802 DL_EXPORT(void) init_rpmdb(void)
04803 {
04804     strncpy(_bsddbModuleName, "_rpmdb", MODULE_NAME_MAX_LEN);
04805     init_bsddb();
04806 }

Generated on Wed Mar 7 07:14:23 2007 for rpm by doxygen 1.3.5