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