bsddb 4.1.6:

* Extended DB & DBEnv set_get_returns_none functionality to take a
   "level" instead of a boolean flag.  The boolean 0 and 1 values still
   have the same effect.  A value of 2 extends the "return None instead
   of raising an exception" behaviour to the DBCursor set methods.
   This will become the default behaviour in pybsddb 4.2.
 * Fixed a typo in DBCursor.join_item method that made it crash instead
   of returning a value.  Obviously nobody uses it.  Wrote a test case
   for join and join_item.
This commit is contained in:
Gregory P. Smith 2003-07-09 04:45:59 +00:00
parent bea57c6c35
commit 455d46f0d9
6 changed files with 284 additions and 51 deletions

View file

@ -93,7 +93,7 @@
/* 40 = 4.0, 33 = 3.3; this will break if the second number is > 9 */
#define DBVER (DB_VERSION_MAJOR * 10 + DB_VERSION_MINOR)
#define PY_BSDDB_VERSION "4.1.5"
#define PY_BSDDB_VERSION "4.1.6"
static char *rcs_id = "$Id$";
@ -141,12 +141,6 @@ static PyInterpreterState* _db_interpreterState = NULL;
#endif
/* What is the default behaviour when DB->get or DBCursor->get returns a
DB_NOTFOUND error? Return None or raise an exception? */
#define GET_RETURNS_NONE_DEFAULT 1
/* Should DB_INCOMPLETE be turned into a warning or an exception? */
#define INCOMPLETE_IS_WARNING 1
@ -189,12 +183,24 @@ static PyObject* DBPermissionsError; /* EPERM */
/* --------------------------------------------------------------------- */
/* Structure definitions */
struct behaviourFlags {
/* What is the default behaviour when DB->get or DBCursor->get returns a
DB_NOTFOUND 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? */
unsigned int cursorSetReturnsNone : 1;
};
#define DEFAULT_GET_RETURNS_NONE 1
#define DEFAULT_CURSOR_SET_RETURNS_NONE 0 /* 0 in pybsddb < 4.2, python < 2.4 */
typedef struct {
PyObject_HEAD
DB_ENV* db_env;
u_int32_t flags; /* saved flags from open() */
int closed;
int getReturnsNone;
struct behaviourFlags moduleFlags;
} DBEnvObject;
@ -205,7 +211,7 @@ typedef struct {
u_int32_t flags; /* saved flags from open() */
u_int32_t setflags; /* saved flags from set_flags() */
int haveStat;
int getReturnsNone;
struct behaviourFlags moduleFlags;
#if (DBVER >= 33)
PyObject* associateCallback;
int primaryDBType;
@ -595,7 +601,7 @@ static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
err = self->dbc->c_get(self->dbc, &key, &data, flags);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND) && self->mydb->getReturnsNone) {
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
Py_INCREF(Py_None);
retval = Py_None;
}
@ -681,9 +687,10 @@ newDBObject(DBEnvObject* arg, int flags)
}
if (self->myenvobj)
self->getReturnsNone = self->myenvobj->getReturnsNone;
self->moduleFlags = self->myenvobj->moduleFlags;
else
self->getReturnsNone = GET_RETURNS_NONE_DEFAULT;
self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
MYDB_BEGIN_ALLOW_THREADS;
err = db_create(&self->db, db_env, flags);
@ -797,7 +804,8 @@ newDBEnvObject(int flags)
self->closed = 1;
self->flags = flags;
self->getReturnsNone = GET_RETURNS_NONE_DEFAULT;
self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
MYDB_BEGIN_ALLOW_THREADS;
err = db_env_create(&self->db_env, flags);
@ -1182,7 +1190,7 @@ _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
err = self->db->get(self->db, txn, &key, &data, flags|consume_flag);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND) && self->getReturnsNone) {
if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
err = 0;
Py_INCREF(Py_None);
retval = Py_None;
@ -1324,7 +1332,7 @@ DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
Py_INCREF(dfltobj);
retval = dfltobj;
}
else if ((err == DB_NOTFOUND) && self->getReturnsNone) {
else if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
err = 0;
Py_INCREF(Py_None);
retval = Py_None;
@ -1424,7 +1432,7 @@ DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
err = self->db->get(self->db, txn, &key, &data, flags);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND) && self->getReturnsNone) {
if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
err = 0;
Py_INCREF(Py_None);
retval = Py_None;
@ -1525,6 +1533,11 @@ DB_join(DBObject* self, PyObject* args)
free(cursors);
RETURN_IF_ERR();
// FIXME: this is a buggy interface. The returned cursor
// contains internal references to the passed in cursors
// but does not hold python references to them or prevent
// them from being closed prematurely. This can cause
// python to crash when things are done in the wrong order.
return (PyObject*) newDBCursorObject(dbc, self);
}
@ -2156,14 +2169,18 @@ static PyObject*
DB_set_get_returns_none(DBObject* self, PyObject* args)
{
int flags=0;
int oldValue;
int oldValue=0;
if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
return NULL;
CHECK_DB_NOT_CLOSED(self);
oldValue = self->getReturnsNone;
self->getReturnsNone = flags;
if (self->moduleFlags.getReturnsNone)
++oldValue;
if (self->moduleFlags.cursorSetReturnsNone)
++oldValue;
self->moduleFlags.getReturnsNone = (flags >= 1);
self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
return PyInt_FromLong(oldValue);
}
@ -2643,7 +2660,7 @@ DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND) && self->mydb->getReturnsNone) {
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
Py_INCREF(Py_None);
retval = Py_None;
}
@ -2790,7 +2807,11 @@ DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET);
MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) {
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
Py_INCREF(Py_None);
retval = Py_None;
}
else if (makeDBError(err)) {
retval = NULL;
}
else {
@ -2848,7 +2869,11 @@ DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) {
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
Py_INCREF(Py_None);
retval = Py_None;
}
else if (makeDBError(err)) {
retval = NULL;
}
else {
@ -2875,19 +2900,15 @@ DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
return retval;
}
static PyObject*
DBC_get_both(DBCursorObject* self, PyObject* args)
_DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
int flags, unsigned int returnsNone)
{
int err, flags=0;
int err;
DBT key, data;
PyObject* retval, *keyobj, *dataobj;
if (!PyArg_ParseTuple(args, "OO|i:get_both", &keyobj, &dataobj, &flags))
return NULL;
CHECK_CURSOR_NOT_CLOSED(self);
PyObject* retval;
// the caller did this: CHECK_CURSOR_NOT_CLOSED(self);
if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
return NULL;
if (!make_dbt(dataobj, &data))
@ -2896,7 +2917,11 @@ DBC_get_both(DBCursorObject* self, PyObject* args)
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) {
if ((err == DB_NOTFOUND) && returnsNone) {
Py_INCREF(Py_None);
retval = Py_None;
}
else if (makeDBError(err)) {
retval = NULL;
}
else {
@ -2922,6 +2947,38 @@ DBC_get_both(DBCursorObject* self, PyObject* args)
return retval;
}
static PyObject*
DBC_get_both(DBCursorObject* self, PyObject* args)
{
int flags=0;
PyObject *keyobj, *dataobj;
if (!PyArg_ParseTuple(args, "OO|i:get_both", &keyobj, &dataobj, &flags))
return NULL;
// if the cursor is closed, self->mydb may be invalid
CHECK_CURSOR_NOT_CLOSED(self);
return _DBC_get_set_both(self, keyobj, dataobj, flags,
self->mydb->moduleFlags.getReturnsNone);
}
static PyObject*
DBC_set_both(DBCursorObject* self, PyObject* args)
{
int flags=0;
PyObject *keyobj, *dataobj;
if (!PyArg_ParseTuple(args, "OO|i:set_both", &keyobj, &dataobj, &flags))
return NULL;
// if the cursor is closed, self->mydb may be invalid
CHECK_CURSOR_NOT_CLOSED(self);
return _DBC_get_set_both(self, keyobj, dataobj, flags,
self->mydb->moduleFlags.cursorSetReturnsNone);
}
static PyObject*
DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
@ -2965,7 +3022,11 @@ DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) {
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
Py_INCREF(Py_None);
retval = Py_None;
}
else if (makeDBError(err)) {
retval = NULL;
}
else { /* Can only be used for BTrees, so no need to return int key */
@ -3010,11 +3071,11 @@ DBC_prev_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs)
static PyObject*
DBC_join_item(DBCursorObject* self, PyObject* args)
{
int err;
int err, flags=0;
DBT key, data;
PyObject* retval;
if (!PyArg_ParseTuple(args, ":join_item"))
if (!PyArg_ParseTuple(args, "|i:join_item", &flags))
return NULL;
CHECK_CURSOR_NOT_CLOSED(self);
@ -3027,9 +3088,13 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, DB_JOIN_ITEM);
err = self->dbc->c_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) {
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
Py_INCREF(Py_None);
retval = Py_None;
}
else if (makeDBError(err)) {
retval = NULL;
}
else {
@ -3748,14 +3813,18 @@ static PyObject*
DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
{
int flags=0;
int oldValue;
int oldValue=0;
if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
return NULL;
CHECK_ENV_NOT_CLOSED(self);
oldValue = self->getReturnsNone;
self->getReturnsNone = flags;
if (self->moduleFlags.getReturnsNone)
++oldValue;
if (self->moduleFlags.cursorSetReturnsNone)
++oldValue;
self->moduleFlags.getReturnsNone = (flags >= 1);
self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
return PyInt_FromLong(oldValue);
}
@ -3977,7 +4046,7 @@ static PyMethodDef DBCursor_methods[] = {
{"set", (PyCFunction)DBC_set, METH_VARARGS|METH_KEYWORDS},
{"set_range", (PyCFunction)DBC_set_range, METH_VARARGS|METH_KEYWORDS},
{"get_both", (PyCFunction)DBC_get_both, METH_VARARGS},
{"set_both", (PyCFunction)DBC_get_both, METH_VARARGS},
{"set_both", (PyCFunction)DBC_set_both, METH_VARARGS},
{"set_recno", (PyCFunction)DBC_set_recno, METH_VARARGS|METH_KEYWORDS},
{"consume", (PyCFunction)DBC_consume, METH_VARARGS|METH_KEYWORDS},
{"next_dup", (PyCFunction)DBC_next_dup, METH_VARARGS|METH_KEYWORDS},