diff -Nru Python-2.4.2.orig/Lib/bsddb/__init__.py Python-2.4.2/Lib/bsddb/__init__.py --- Python-2.4.2.orig/Lib/bsddb/__init__.py 2006-02-13 18:18:16.000000000 +0100 +++ Python-2.4.2/Lib/bsddb/__init__.py 2006-01-27 07:17:25.000000000 +0100 @@ -372,6 +372,8 @@ try: import thread del thread + if db.version() < (3, 3, 0): + db.DB_THREAD = 0 except ImportError: db.DB_THREAD = 0 diff -Nru Python-2.4.2.orig/Lib/bsddb/db.py Python-2.4.2/Lib/bsddb/db.py --- Python-2.4.2.orig/Lib/bsddb/db.py 2006-02-13 18:18:16.000000000 +0100 +++ Python-2.4.2/Lib/bsddb/db.py 2006-01-27 07:17:25.000000000 +0100 @@ -37,7 +37,7 @@ # case we ever want to augment the stuff in _db in any way. For now # it just simply imports everything from _db. -if __name__[:len('bsddb3.')] == 'bsddb3.': +if __name__.startswith('bsddb3.'): # import _pybsddb binary as it should be the more recent version from # a standalone pybsddb addon package than the version included with # python as bsddb._bsddb. diff -Nru Python-2.4.2.orig/Lib/bsddb/dbobj.py Python-2.4.2/Lib/bsddb/dbobj.py --- Python-2.4.2.orig/Lib/bsddb/dbobj.py 2006-02-13 18:18:16.000000000 +0100 +++ Python-2.4.2/Lib/bsddb/dbobj.py 2006-01-27 07:28:12.000000000 +0100 @@ -77,6 +77,8 @@ return apply(self._cobj.txn_stat, args, kwargs) def set_tx_max(self, *args, **kwargs): return apply(self._cobj.set_tx_max, args, kwargs) + def set_tx_timestamp(self, *args, **kwargs): + return apply(self._cobj.set_tx_timestamp, args, kwargs) def lock_detect(self, *args, **kwargs): return apply(self._cobj.lock_detect, args, kwargs) def lock_get(self, *args, **kwargs): @@ -164,6 +166,8 @@ return apply(self._cobj.rename, args, kwargs) def set_bt_minkey(self, *args, **kwargs): return apply(self._cobj.set_bt_minkey, args, kwargs) + def set_bt_compare(self, *args, **kwargs): + return apply(self._cobj.set_bt_compare, args, kwargs) def set_cachesize(self, *args, **kwargs): return apply(self._cobj.set_cachesize, args, kwargs) def set_flags(self, *args, **kwargs): diff -Nru Python-2.4.2.orig/Lib/bsddb/dbtables.py Python-2.4.2/Lib/bsddb/dbtables.py --- Python-2.4.2.orig/Lib/bsddb/dbtables.py 2006-02-13 18:18:16.000000000 +0100 +++ Python-2.4.2/Lib/bsddb/dbtables.py 2006-01-27 07:17:25.000000000 +0100 @@ -15,7 +15,7 @@ # This provides a simple database table interface built on top of # the Python BerkeleyDB 3 interface. # -_cvsid = '$Id: dbtables.py,v 1.11 2004/08/08 00:54:20 tim_one Exp $' +_cvsid = '$Id: dbtables.py 36901 2004-08-08 00:54:21Z tim_one $' import re import sys diff -Nru Python-2.4.2.orig/Modules/_bsddb.c Python-2.4.2/Modules/_bsddb.c --- Python-2.4.2.orig/Modules/_bsddb.c 2006-02-13 18:18:17.000000000 +0100 +++ Python-2.4.2/Modules/_bsddb.c 2006-01-30 01:22:16.000000000 +0100 @@ -97,8 +97,8 @@ #error "eek! DBVER can't handle minor versions > 9" #endif -#define PY_BSDDB_VERSION "4.3.0" -static char *rcs_id = "$Id: _bsddb.c,v 1.38.2.1 2004/12/16 09:48:37 greg Exp $"; +#define PY_BSDDB_VERSION "4.4.2" +static char *rcs_id = "$Id: _bsddb.c 42205 2006-01-30 00:22:08Z gregory.p.smith $"; #ifdef WITH_THREAD @@ -153,7 +153,7 @@ static PyObject* DBError; /* Base class, all others derive from this */ static PyObject* DBCursorClosedError; /* raised when trying to use a closed cursor object */ -static PyObject* DBKeyEmptyError; /* DB_KEYEMPTY */ +static PyObject* DBKeyEmptyError; /* DB_KEYEMPTY: also derives from KeyError */ static PyObject* DBKeyExistError; /* DB_KEYEXIST */ static PyObject* DBLockDeadlockError; /* DB_LOCK_DEADLOCK */ static PyObject* DBLockNotGrantedError; /* DB_LOCK_NOTGRANTED */ @@ -212,10 +212,10 @@ struct behaviourFlags { /* What is the default behaviour when DB->get or DBCursor->get returns a - DB_NOTFOUND error? Return None or raise an exception? */ + DB_NOTFOUND || DB_KEYEMPTY error? Return None or raise an exception? */ unsigned int getReturnsNone : 1; /* What is the default behaviour for DBCursor.set* methods when DBCursor->get - * returns a DB_NOTFOUND error? Return None or raise an exception? */ + * returns a DB_NOTFOUND || DB_KEYEMPTY error? Return None or raise? */ unsigned int cursorSetReturnsNone : 1; }; @@ -244,6 +244,7 @@ struct behaviourFlags moduleFlags; #if (DBVER >= 33) PyObject* associateCallback; + PyObject* btCompareCallback; int primaryDBType; #endif #ifdef HAVE_WEAKREF @@ -265,6 +266,7 @@ typedef struct { PyObject_HEAD DB_TXN* txn; + PyObject *env; #ifdef HAVE_WEAKREF PyObject *in_weakreflist; /* List of weak references */ #endif @@ -649,7 +651,7 @@ int dlen = -1; int doff = -1; int flags = 0; - char* kwnames[] = { "flags", "dlen", "doff", NULL }; + static const char* kwnames[] = { "flags", "dlen", "doff", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, kwnames, &flags, &dlen, &doff)) @@ -672,7 +674,8 @@ err = self->dbc->c_get(self->dbc, &key, &data, flags); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.getReturnsNone) { Py_INCREF(Py_None); retval = Py_None; } @@ -741,6 +744,7 @@ self->myenvobj = NULL; #if (DBVER >= 33) self->associateCallback = NULL; + self->btCompareCallback = NULL; self->primaryDBType = 0; #endif #ifdef HAVE_WEAKREF @@ -815,6 +819,10 @@ Py_DECREF(self->associateCallback); self->associateCallback = NULL; } + if (self->btCompareCallback != NULL) { + Py_DECREF(self->btCompareCallback); + self->btCompareCallback = NULL; + } #endif PyObject_Del(self); } @@ -905,7 +913,7 @@ } #endif - if (self->db_env) { + if (self->db_env && !self->closed) { MYDB_BEGIN_ALLOW_THREADS; self->db_env->close(self->db_env, 0); MYDB_END_ALLOW_THREADS; @@ -921,6 +929,8 @@ DBTxnObject* self = PyObject_New(DBTxnObject, &DBTxn_Type); if (self == NULL) return NULL; + Py_INCREF(myenv); + self->env = (PyObject*)myenv; #ifdef HAVE_WEAKREF self->in_weakreflist = NULL; #endif @@ -931,11 +941,10 @@ #else err = txn_begin(myenv->db_env, parent, &(self->txn), flags); #endif - /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs - * list so that a DBEnv can refuse to close without aborting any open - * open DBTxns and closing any open DBs first. */ MYDB_END_ALLOW_THREADS; if (makeDBError(err)) { + Py_DECREF(self->env); + PyObject_Del(self); self = NULL; } return self; @@ -966,6 +975,7 @@ } #endif + Py_DECREF(self->env); PyObject_Del(self); } @@ -1140,9 +1150,10 @@ #if (DBVER >= 41) PyObject *txnobj = NULL; DB_TXN *txn = NULL; - char* kwnames[] = {"secondaryDB", "callback", "flags", "txn", NULL}; + static const char* kwnames[] = {"secondaryDB", "callback", "flags", "txn", + NULL}; #else - char* kwnames[] = {"secondaryDB", "callback", "flags", NULL}; + static const char* kwnames[] = {"secondaryDB", "callback", "flags", NULL}; #endif #if (DBVER >= 41) @@ -1165,6 +1176,7 @@ makeTypeError("DB", (PyObject*)secondaryDB); return NULL; } + CHECK_DB_NOT_CLOSED(secondaryDB); if (callback == Py_None) { callback = NULL; } @@ -1174,9 +1186,7 @@ } /* Save a reference to the callback in the secondary DB. */ - if (self->associateCallback != NULL) { - Py_DECREF(self->associateCallback); - } + Py_XDECREF(secondaryDB->associateCallback); Py_INCREF(callback); secondaryDB->associateCallback = callback; secondaryDB->primaryDBType = _DB_get_type(self); @@ -1210,8 +1220,8 @@ MYDB_END_ALLOW_THREADS; if (err) { - Py_DECREF(self->associateCallback); - self->associateCallback = NULL; + Py_XDECREF(secondaryDB->associateCallback); + secondaryDB->associateCallback = NULL; secondaryDB->primaryDBType = 0; } @@ -1249,7 +1259,7 @@ PyObject* retval = NULL; DBT key, data; DB_TXN *txn = NULL; - char* kwnames[] = { "txn", "flags", NULL }; + static const char* kwnames[] = { "txn", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:consume", kwnames, &txnobj, &flags)) @@ -1279,7 +1289,8 @@ err = self->db->get(self->db, txn, &key, &data, flags|consume_flag); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->moduleFlags.getReturnsNone) { err = 0; Py_INCREF(Py_None); retval = Py_None; @@ -1318,7 +1329,7 @@ DBC* dbc; PyObject* txnobj = NULL; DB_TXN *txn = NULL; - char* kwnames[] = { "txn", "flags", NULL }; + static const char* kwnames[] = { "txn", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames, &txnobj, &flags)) @@ -1343,7 +1354,7 @@ PyObject* keyobj; DBT key; DB_TXN *txn = NULL; - char* kwnames[] = { "key", "txn", "flags", NULL }; + static const char* kwnames[] = { "key", "txn", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:delete", kwnames, &keyobj, &txnobj, &flags)) @@ -1395,7 +1406,8 @@ int doff = -1; DBT key, data; DB_TXN *txn = NULL; - char* kwnames[] = {"key", "default", "txn", "flags", "dlen", "doff", NULL}; + static const char* kwnames[] = {"key", "default", "txn", "flags", "dlen", + "doff", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:get", kwnames, &keyobj, &dfltobj, &txnobj, &flags, &dlen, @@ -1424,12 +1436,13 @@ err = self->db->get(self->db, txn, &key, &data, flags); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && (dfltobj != NULL)) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) { err = 0; Py_INCREF(dfltobj); retval = dfltobj; } - else if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) { + else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->moduleFlags.getReturnsNone) { err = 0; Py_INCREF(Py_None); retval = Py_None; @@ -1461,7 +1474,8 @@ int doff = -1; DBT key, pkey, data; DB_TXN *txn = NULL; - char* kwnames[] = {"key", "default", "txn", "flags", "dlen", "doff", NULL}; + static const char* kwnames[] = {"key", "default", "txn", "flags", "dlen", + "doff", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:pget", kwnames, &keyobj, &dfltobj, &txnobj, &flags, &dlen, @@ -1493,12 +1507,13 @@ err = self->db->pget(self->db, txn, &key, &pkey, &data, flags); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && (dfltobj != NULL)) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) { err = 0; Py_INCREF(dfltobj); retval = dfltobj; } - else if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) { + else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->moduleFlags.getReturnsNone) { err = 0; Py_INCREF(Py_None); retval = Py_None; @@ -1510,7 +1525,7 @@ if (self->primaryDBType == DB_RECNO || self->primaryDBType == DB_QUEUE) - pkeyObj = PyInt_FromLong(*(long *)pkey.data); + pkeyObj = PyInt_FromLong(*(int *)pkey.data); else pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size); @@ -1519,14 +1534,22 @@ PyObject *keyObj; int type = _DB_get_type(self); if (type == DB_RECNO || type == DB_QUEUE) - keyObj = PyInt_FromLong(*(long *)key.data); + keyObj = PyInt_FromLong(*(int *)key.data); else keyObj = PyString_FromStringAndSize(key.data, key.size); +#if (PY_VERSION_HEX >= 0x02040000) + retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj); +#else retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj); +#endif } else /* return just the pkey and data */ { +#if (PY_VERSION_HEX >= 0x02040000) + retval = PyTuple_Pack(2, pkeyObj, dataObj); +#else retval = Py_BuildValue("OO", pkeyObj, dataObj); +#endif } FREE_DBT(pkey); FREE_DBT(data); @@ -1549,7 +1572,7 @@ PyObject* retval = NULL; DBT key, data; DB_TXN *txn = NULL; - char* kwnames[] = { "key", "txn", NULL }; + static const char* kwnames[] = { "key", "txn", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:get_size", kwnames, &keyobj, &txnobj)) @@ -1592,7 +1615,7 @@ PyObject* retval = NULL; DBT key, data; DB_TXN *txn = NULL; - char* kwnames[] = { "key", "data", "txn", "flags", NULL }; + static const char* kwnames[] = { "key", "data", "txn", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oi:get_both", kwnames, @@ -1623,7 +1646,8 @@ err = self->db->get(self->db, txn, &key, &data, flags); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->moduleFlags.getReturnsNone) { err = 0; Py_INCREF(Py_None); retval = Py_None; @@ -1742,7 +1766,7 @@ DBT key; DB_TXN *txn = NULL; DB_KEY_RANGE range; - char* kwnames[] = { "key", "txn", "flags", NULL }; + static const char* kwnames[] = { "key", "txn", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:key_range", kwnames, &keyobj, &txnobj, &flags)) @@ -1773,17 +1797,17 @@ PyObject *txnobj = NULL; DB_TXN *txn = NULL; /* with dbname */ - char* kwnames[] = { + static const char* kwnames[] = { "filename", "dbname", "dbtype", "flags", "mode", "txn", NULL}; /* without dbname */ - char* kwnames_basic[] = { + static const char* kwnames_basic[] = { "filename", "dbtype", "flags", "mode", "txn", NULL}; #else /* with dbname */ - char* kwnames[] = { + static const char* kwnames[] = { "filename", "dbname", "dbtype", "flags", "mode", NULL}; /* without dbname */ - char* kwnames_basic[] = { + static const char* kwnames_basic[] = { "filename", "dbtype", "flags", "mode", NULL}; #endif @@ -1867,7 +1891,8 @@ PyObject* keyobj, *dataobj, *retval; DBT key, data; DB_TXN *txn = NULL; - char* kwnames[] = { "key", "data", "txn", "flags", "dlen", "doff", NULL }; + static const char* kwnames[] = { "key", "data", "txn", "flags", "dlen", + "doff", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oiii:put", kwnames, &keyobj, &dataobj, &txnobj, &flags, &dlen, &doff)) @@ -1907,7 +1932,7 @@ char* filename; char* database = NULL; int err, flags=0; - char* kwnames[] = { "filename", "dbname", "flags", NULL}; + static const char* kwnames[] = { "filename", "dbname", "flags", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zi:remove", kwnames, &filename, &database, &flags)) @@ -1959,6 +1984,160 @@ RETURN_NONE(); } +#if (DBVER >= 33) +static int +_default_cmp (const DBT *leftKey, + const DBT *rightKey) +{ + int res; + int lsize = leftKey->size, rsize = rightKey->size; + + res = memcmp (leftKey->data, rightKey->data, + lsize < rsize ? lsize : rsize); + + if (res == 0) { + if (lsize < rsize) { + res = -1; + } + else if (lsize > rsize) { + res = 1; + } + } + return res; +} + +static int +_db_compareCallback (DB* db, + const DBT *leftKey, + const DBT *rightKey) +{ + int res = 0; + PyObject *args; + PyObject *result; + PyObject *leftObject; + PyObject *rightObject; + DBObject *self = (DBObject *) db->app_private; + + if (self == NULL || self->btCompareCallback == NULL) { + MYDB_BEGIN_BLOCK_THREADS; + PyErr_SetString (PyExc_TypeError, + (self == 0 + ? "DB_bt_compare db is NULL." + : "DB_bt_compare callback is NULL.")); + /* we're in a callback within the DB code, we can't raise */ + PyErr_Print (); + res = _default_cmp (leftKey, rightKey); + MYDB_END_BLOCK_THREADS; + } + else { + MYDB_BEGIN_BLOCK_THREADS; + + leftObject = PyString_FromStringAndSize (leftKey->data, leftKey->size); + rightObject = PyString_FromStringAndSize (rightKey->data, rightKey->size); + + args = PyTuple_New (2); + Py_INCREF (self); + PyTuple_SET_ITEM (args, 0, leftObject); /* steals reference */ + PyTuple_SET_ITEM (args, 1, rightObject); /* steals reference */ + + result = PyEval_CallObject (self->btCompareCallback, args); + if (result == 0) { + /* we're in a callback within the DB code, we can't raise */ + PyErr_Print (); + res = _default_cmp (leftKey, rightKey); + } + else if (PyInt_Check (result)) { + res = PyInt_AsLong (result); + } + else { + PyErr_SetString (PyExc_TypeError, + "DB_bt_compare callback MUST return an int."); + /* we're in a callback within the DB code, we can't raise */ + PyErr_Print (); + res = _default_cmp (leftKey, rightKey); + } + + Py_DECREF (args); + Py_XDECREF (result); + + MYDB_END_BLOCK_THREADS; + } + return res; +} + +static PyObject* +DB_set_bt_compare (DBObject* self, PyObject* args) +{ + int err; + PyObject *comparator; + PyObject *tuple, *emptyStr, *result; + + if (!PyArg_ParseTuple(args,"O:set_bt_compare", &comparator )) + return NULL; + + CHECK_DB_NOT_CLOSED (self); + + if (! PyCallable_Check (comparator)) { + makeTypeError ("Callable", comparator); + return NULL; + } + + /* + * Perform a test call of the comparator function with two empty + * string objects here. verify that it returns an int (0). + * err if not. + */ + tuple = PyTuple_New (2); + + emptyStr = PyString_FromStringAndSize (NULL, 0); + Py_INCREF(emptyStr); + PyTuple_SET_ITEM (tuple, 0, emptyStr); + PyTuple_SET_ITEM (tuple, 1, emptyStr); /* steals reference */ + result = PyEval_CallObject (comparator, tuple); + Py_DECREF (tuple); + if (result == 0 || !PyInt_Check(result)) { + PyErr_SetString (PyExc_TypeError, + "callback MUST return an int"); + return NULL; + } + else if (PyInt_AsLong(result) != 0) { + PyErr_SetString (PyExc_TypeError, + "callback failed to return 0 on two empty strings"); + return NULL; + } + + /* We don't accept multiple set_bt_compare operations, in order to + * simplify the code. This would have no real use, as one cannot + * change the function once the db is opened anyway */ + if (self->btCompareCallback != NULL) { + PyErr_SetString (PyExc_RuntimeError, "set_bt_compare () cannot be called more than once"); + return NULL; + } + + Py_INCREF (comparator); + self->btCompareCallback = comparator; + + /* This is to workaround a problem with un-initialized threads (see + comment in DB_associate) */ +#ifdef WITH_THREAD + PyEval_InitThreads(); +#endif + + err = self->db->set_bt_compare (self->db, + (comparator != NULL ? + _db_compareCallback : NULL)); + + if (err) { + /* restore the old state in case of error */ + Py_DECREF (comparator); + self->btCompareCallback = NULL; + } + + RETURN_IF_ERR (); + RETURN_NONE (); +} +#endif /* DBVER >= 33 */ + static PyObject* DB_set_cachesize(DBObject* self, PyObject* args) @@ -2171,9 +2350,9 @@ #if (DBVER >= 43) PyObject* txnobj = NULL; DB_TXN *txn = NULL; - char* kwnames[] = { "txn", "flags", NULL }; + static const char* kwnames[] = { "txn", "flags", NULL }; #else - char* kwnames[] = { "flags", NULL }; + static const char* kwnames[] = { "flags", NULL }; #endif #if (DBVER >= 43) @@ -2313,7 +2492,7 @@ u_int32_t count=0; PyObject* txnobj = NULL; DB_TXN *txn = NULL; - char* kwnames[] = { "txn", "flags", NULL }; + static const char* kwnames[] = { "txn", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames, &txnobj, &flags)) @@ -2357,7 +2536,8 @@ char* dbName=NULL; char* outFileName=NULL; FILE* outFile=NULL; - char* kwnames[] = { "filename", "dbname", "outfile", "flags", NULL }; + static const char* kwnames[] = { "filename", "dbname", "outfile", "flags", + NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzi:verify", kwnames, &fileName, &dbName, &outFileName, &flags)) @@ -2414,7 +2594,7 @@ int err; u_int32_t flags=0; char *passwd = NULL; - char* kwnames[] = { "passwd", "flags", NULL }; + static const char* kwnames[] = { "passwd", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames, &passwd, &flags)) { @@ -2584,7 +2764,15 @@ err = self->db->get(self->db, txn, &key, &data, 0); MYDB_END_ALLOW_THREADS; FREE_DBT(key); - return PyInt_FromLong((err == DB_BUFFER_SMALL) || (err == 0)); + + if (err == DB_BUFFER_SMALL || err == 0) { + return PyInt_FromLong(1); + } else if (err == DB_NOTFOUND || err == DB_KEYEMPTY) { + return PyInt_FromLong(0); + } + + makeDBError(err); + return NULL; } @@ -2682,8 +2870,8 @@ Py_DECREF(item); } - /* DB_NOTFOUND is okay, it just means we got to the end */ - if (err != DB_NOTFOUND && makeDBError(err)) { + /* DB_NOTFOUND || DB_KEYEMPTY is okay, it means we got to the end */ + if (err != DB_NOTFOUND && err != DB_KEYEMPTY && makeDBError(err)) { Py_DECREF(list); list = NULL; } @@ -2846,7 +3034,8 @@ int dlen = -1; int doff = -1; DBT key, data; - char* kwnames[] = { "key","data", "flags", "dlen", "doff", NULL }; + static const char* kwnames[] = { "key","data", "flags", "dlen", "doff", + NULL }; CLEAR_DBT(key); CLEAR_DBT(data); @@ -2890,7 +3079,8 @@ err = self->dbc->c_get(self->dbc, &key, &data, flags); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.getReturnsNone) { Py_INCREF(Py_None); retval = Py_None; } @@ -2931,7 +3121,8 @@ int dlen = -1; int doff = -1; DBT key, pkey, data; - char* kwnames[] = { "key","data", "flags", "dlen", "doff", NULL }; + static const char* kwnames[] = { "key","data", "flags", "dlen", "doff", + NULL }; CLEAR_DBT(key); CLEAR_DBT(data); @@ -2977,7 +3168,8 @@ err = self->dbc->c_pget(self->dbc, &key, &pkey, &data, flags); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.getReturnsNone) { Py_INCREF(Py_None); retval = Py_None; } @@ -2991,24 +3183,32 @@ if (self->mydb->primaryDBType == DB_RECNO || self->mydb->primaryDBType == DB_QUEUE) - pkeyObj = PyInt_FromLong(*(long *)pkey.data); + pkeyObj = PyInt_FromLong(*(int *)pkey.data); else pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size); - if (flags & DB_SET_RECNO) /* return key, pkey and data */ + if (key.data && key.size) /* return key, pkey and data */ { PyObject *keyObj; int type = _DB_get_type(self->mydb); if (type == DB_RECNO || type == DB_QUEUE) - keyObj = PyInt_FromLong(*(long *)key.data); + keyObj = PyInt_FromLong(*(int *)key.data); else keyObj = PyString_FromStringAndSize(key.data, key.size); +#if (PY_VERSION_HEX >= 0x02040000) + retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj); +#else retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj); +#endif FREE_DBT(key); } else /* return just the pkey and data */ { +#if (PY_VERSION_HEX >= 0x02040000) + retval = PyTuple_Pack(2, pkeyObj, dataObj); +#else retval = Py_BuildValue("OO", pkeyObj, dataObj); +#endif } FREE_DBT(pkey); FREE_DBT(data); @@ -3083,7 +3283,8 @@ int err, flags = 0; PyObject* keyobj, *dataobj; DBT key, data; - char* kwnames[] = { "key", "data", "flags", "dlen", "doff", NULL }; + static const char* kwnames[] = { "key", "data", "flags", "dlen", "doff", + NULL }; int dlen = -1; int doff = -1; @@ -3118,7 +3319,7 @@ int err, flags = 0; DBT key, data; PyObject* retval, *keyobj; - char* kwnames[] = { "key", "flags", "dlen", "doff", NULL }; + static const char* kwnames[] = { "key", "flags", "dlen", "doff", NULL }; int dlen = -1; int doff = -1; @@ -3144,7 +3345,8 @@ MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.cursorSetReturnsNone) { Py_INCREF(Py_None); retval = Py_None; } @@ -3187,7 +3389,7 @@ int err, flags = 0; DBT key, data; PyObject* retval, *keyobj; - char* kwnames[] = { "key", "flags", "dlen", "doff", NULL }; + static const char* kwnames[] = { "key", "flags", "dlen", "doff", NULL }; int dlen = -1; int doff = -1; @@ -3216,7 +3418,8 @@ MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.cursorSetReturnsNone) { Py_INCREF(Py_None); retval = Py_None; } @@ -3271,7 +3474,7 @@ MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_GET_BOTH); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && returnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && returnsNone) { Py_INCREF(Py_None); retval = Py_None; } @@ -3376,7 +3579,7 @@ PyObject* retval; int dlen = -1; int doff = -1; - char* kwnames[] = { "recno","flags", "dlen", "doff", NULL }; + static const char* kwnames[] = { "recno","flags", "dlen", "doff", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii:set_recno", kwnames, &irecno, &flags, &dlen, &doff)) @@ -3411,7 +3614,8 @@ MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RECNO); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.cursorSetReturnsNone) { Py_INCREF(Py_None); retval = Py_None; } @@ -3479,7 +3683,8 @@ MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) { + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.getReturnsNone) { Py_INCREF(Py_None); retval = Py_None; } @@ -3568,7 +3773,8 @@ char *database = NULL; PyObject *txnobj = NULL; DB_TXN *txn = NULL; - char* kwnames[] = { "file", "database", "txn", "flags", NULL }; + static const char* kwnames[] = { "file", "database", "txn", "flags", + NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|Oi:dbremove", kwnames, &file, &database, &txnobj, &flags)) { @@ -3595,7 +3801,8 @@ char *newname = NULL; PyObject *txnobj = NULL; DB_TXN *txn = NULL; - char* kwnames[] = { "file", "database", "newname", "txn", "flags", NULL }; + static const char* kwnames[] = { "file", "database", "newname", "txn", + "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sss|Oi:dbrename", kwnames, &file, &database, &newname, &txnobj, &flags)) { @@ -3619,7 +3826,7 @@ int err; u_int32_t flags=0; char *passwd = NULL; - char* kwnames[] = { "passwd", "flags", NULL }; + static const char* kwnames[] = { "passwd", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames, &passwd, &flags)) { @@ -3642,7 +3849,7 @@ int err; u_int32_t flags=0; u_int32_t timeout = 0; - char* kwnames[] = { "timeout", "flags", NULL }; + static const char* kwnames[] = { "timeout", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames, &timeout, &flags)) { @@ -3780,6 +3987,25 @@ } +#if (DBVER >= 33) +static PyObject* +DBEnv_set_lg_regionmax(DBEnvObject* self, PyObject* args) +{ + int err, lg_max; + + if (!PyArg_ParseTuple(args, "i:set_lg_regionmax", &lg_max)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lg_regionmax(self->db_env, lg_max); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif + + static PyObject* DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args) { @@ -3910,7 +4136,7 @@ int flags = 0; PyObject* txnobj = NULL; DB_TXN *txn = NULL; - char* kwnames[] = { "parent", "flags", NULL }; + static const char* kwnames[] = { "parent", "flags", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:txn_begin", kwnames, &txnobj, &flags)) @@ -3954,9 +4180,23 @@ return NULL; CHECK_ENV_NOT_CLOSED(self); - MYDB_BEGIN_ALLOW_THREADS; err = self->db_env->set_tx_max(self->db_env, max); - MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_set_tx_timestamp(DBEnvObject* self, PyObject* args) +{ + int err; + time_t stamp; + + if (!PyArg_ParseTuple(args, "i:set_tx_timestamp", &stamp)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + err = self->db_env->set_tx_timestamp(self->db_env, &stamp); RETURN_IF_ERR(); RETURN_NONE(); } @@ -4101,8 +4341,13 @@ #endif MAKE_ENTRY(nrequests); MAKE_ENTRY(nreleases); - MAKE_ENTRY(nnowaits); +#if (DBVER < 44) + MAKE_ENTRY(nnowaits); /* these were renamed in 4.4 */ MAKE_ENTRY(nconflicts); +#else + MAKE_ENTRY(lock_nowait); + MAKE_ENTRY(lock_wait); +#endif MAKE_ENTRY(ndeadlocks); MAKE_ENTRY(regsize); MAKE_ENTRY(region_wait); @@ -4400,6 +4645,9 @@ {"remove", (PyCFunction)DB_remove, METH_VARARGS|METH_KEYWORDS}, {"rename", (PyCFunction)DB_rename, METH_VARARGS}, {"set_bt_minkey", (PyCFunction)DB_set_bt_minkey, METH_VARARGS}, +#if (DBVER >= 33) + {"set_bt_compare", (PyCFunction)DB_set_bt_compare, METH_VARARGS}, +#endif {"set_cachesize", (PyCFunction)DB_set_cachesize, METH_VARARGS}, #if (DBVER >= 41) {"set_encrypt", (PyCFunction)DB_set_encrypt, METH_VARARGS|METH_KEYWORDS}, @@ -4489,6 +4737,9 @@ {"set_lg_bsize", (PyCFunction)DBEnv_set_lg_bsize, METH_VARARGS}, {"set_lg_dir", (PyCFunction)DBEnv_set_lg_dir, METH_VARARGS}, {"set_lg_max", (PyCFunction)DBEnv_set_lg_max, METH_VARARGS}, +#if (DBVER >= 33) + {"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS}, +#endif {"set_lk_detect", (PyCFunction)DBEnv_set_lk_detect, METH_VARARGS}, {"set_lk_max", (PyCFunction)DBEnv_set_lk_max, METH_VARARGS}, #if (DBVER >= 32) @@ -4502,6 +4753,7 @@ {"txn_checkpoint", (PyCFunction)DBEnv_txn_checkpoint, METH_VARARGS}, {"txn_stat", (PyCFunction)DBEnv_txn_stat, METH_VARARGS}, {"set_tx_max", (PyCFunction)DBEnv_set_tx_max, METH_VARARGS}, + {"set_tx_timestamp", (PyCFunction)DBEnv_set_tx_timestamp, METH_VARARGS}, {"lock_detect", (PyCFunction)DBEnv_lock_detect, METH_VARARGS}, {"lock_get", (PyCFunction)DBEnv_lock_get, METH_VARARGS}, {"lock_id", (PyCFunction)DBEnv_lock_id, METH_VARARGS}, @@ -4734,7 +4986,7 @@ { PyObject* dbenvobj = NULL; int flags = 0; - char* kwnames[] = { "dbEnv", "flags", NULL}; + static const char* kwnames[] = { "dbEnv", "flags", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:DB", kwnames, &dbenvobj, &flags)) @@ -4821,6 +5073,8 @@ /* Create the module and add the functions */ m = Py_InitModule(_bsddbModuleName, bsddb_methods); + if (m == NULL) + return; /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); @@ -4938,7 +5192,11 @@ ADD_INT(d, DB_LOCK_IREAD); ADD_INT(d, DB_LOCK_IWR); #if (DBVER >= 33) +#if (DBVER < 44) ADD_INT(d, DB_LOCK_DIRTY); +#else + ADD_INT(d, DB_LOCK_READ_UNCOMMITTED); /* renamed in 4.4 */ +#endif ADD_INT(d, DB_LOCK_WWRITE); #endif @@ -5040,6 +5298,11 @@ ADD_INT(d, DB_MULTIPLE_KEY); #endif +#if (DBVER >= 44) + ADD_INT(d, DB_READ_UNCOMMITTED); /* replaces DB_DIRTY_READ in 4.4 */ + ADD_INT(d, DB_READ_COMMITTED); +#endif + #if (DBVER >= 33) ADD_INT(d, DB_DONOTINDEX); #endif @@ -5117,12 +5380,15 @@ DBError = PyErr_NewException("bsddb._db.DBError", NULL, NULL); PyDict_SetItemString(d, "DBError", DBError); - /* Some magic to make DBNotFoundError derive from both DBError and - KeyError, since the API only supports using one base class. */ + /* Some magic to make DBNotFoundError and DBKeyEmptyError derive + * from both DBError and KeyError, since the API only supports + * using one base class. */ PyDict_SetItemString(d, "KeyError", PyExc_KeyError); - PyRun_String("class DBNotFoundError(DBError, KeyError): pass", + PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n" + "class DBKeyEmptyError(DBError, KeyError): pass", Py_file_input, d, d); DBNotFoundError = PyDict_GetItemString(d, "DBNotFoundError"); + DBKeyEmptyError = PyDict_GetItemString(d, "DBKeyEmptyError"); PyDict_DelItemString(d, "KeyError");