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

Generated on Wed Sep 4 12:49:54 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002