pybsddb 4.3.2:
* the has_key() method was not raising a DBError when a database error had occurred. [SF patch id 1212590] * added a wrapper for the DBEnv.set_lg_regionmax method [SF patch id 1212590] * DBKeyEmptyError now derives from KeyError just like DBNotFoundError. * internally everywhere DB_NOTFOUND was checked for has been updated to also check for DB_KEYEMPTY. This fixes the semantics of a couple operations on recno and queue databases to be more intuitive and results in less unexpected DBKeyEmptyError exceptions being raised.
This commit is contained in:
parent
5d36a55eaa
commit
e947706b10
|
@ -397,10 +397,14 @@ class BasicTestCase(unittest.TestCase):
|
|||
try:
|
||||
rec = c.current()
|
||||
except db.DBKeyEmptyError, val:
|
||||
assert val[0] == db.DB_KEYEMPTY
|
||||
if verbose: print val
|
||||
if get_raises_error:
|
||||
assert val[0] == db.DB_KEYEMPTY
|
||||
if verbose: print val
|
||||
else:
|
||||
self.fail("unexpected DBKeyEmptyError")
|
||||
else:
|
||||
self.fail('exception expected')
|
||||
if get_raises_error:
|
||||
self.fail('DBKeyEmptyError exception expected')
|
||||
|
||||
c.next()
|
||||
c2 = c.dup(db.DB_POSITION)
|
||||
|
@ -612,7 +616,6 @@ class BasicTransactionTestCase(BasicTestCase):
|
|||
self.txn = self.env.txn_begin()
|
||||
|
||||
|
||||
|
||||
def test06_Transactions(self):
|
||||
d = self.d
|
||||
if verbose:
|
||||
|
|
|
@ -34,6 +34,10 @@ class SimpleRecnoTestCase(unittest.TestCase):
|
|||
|
||||
def test01_basic(self):
|
||||
d = db.DB()
|
||||
|
||||
get_returns_none = d.set_get_returns_none(2)
|
||||
d.set_get_returns_none(get_returns_none)
|
||||
|
||||
d.open(self.filename, db.DB_RECNO, db.DB_CREATE)
|
||||
|
||||
for x in letters:
|
||||
|
@ -65,6 +69,14 @@ class SimpleRecnoTestCase(unittest.TestCase):
|
|||
else:
|
||||
self.fail("expected exception")
|
||||
|
||||
# test that has_key raises DB exceptions (fixed in pybsddb 4.3.2)
|
||||
try:
|
||||
d.has_key(0)
|
||||
except db.DBError, val:
|
||||
pass
|
||||
else:
|
||||
self.fail("has_key did not raise a proper exception")
|
||||
|
||||
try:
|
||||
data = d[100]
|
||||
except KeyError:
|
||||
|
@ -72,8 +84,13 @@ class SimpleRecnoTestCase(unittest.TestCase):
|
|||
else:
|
||||
self.fail("expected exception")
|
||||
|
||||
data = d.get(100)
|
||||
assert data == None
|
||||
try:
|
||||
data = d.get(100)
|
||||
except db.DBNotFoundError, val:
|
||||
if get_returns_none:
|
||||
self.fail("unexpected exception")
|
||||
else:
|
||||
assert data == None
|
||||
|
||||
keys = d.keys()
|
||||
if verbose:
|
||||
|
@ -161,10 +178,14 @@ class SimpleRecnoTestCase(unittest.TestCase):
|
|||
try:
|
||||
d.get(99)
|
||||
except db.DBKeyEmptyError, val:
|
||||
assert val[0] == db.DB_KEYEMPTY
|
||||
if verbose: print val
|
||||
if get_returns_none:
|
||||
self.fail("unexpected DBKeyEmptyError exception")
|
||||
else:
|
||||
assert val[0] == db.DB_KEYEMPTY
|
||||
if verbose: print val
|
||||
else:
|
||||
self.fail("expected exception")
|
||||
if not get_returns_none:
|
||||
self.fail("expected exception")
|
||||
|
||||
rec = c.set(40)
|
||||
while rec:
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
#error "eek! DBVER can't handle minor versions > 9"
|
||||
#endif
|
||||
|
||||
#define PY_BSDDB_VERSION "4.3.1"
|
||||
#define PY_BSDDB_VERSION "4.3.2"
|
||||
static char *rcs_id = "$Id$";
|
||||
|
||||
|
||||
|
@ -153,7 +153,7 @@ static PyInterpreterState* _db_interpreterState = NULL;
|
|||
|
||||
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 @@ static PyObject* DBPermissionsError; /* EPERM */
|
|||
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -673,7 +673,8 @@ 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->moduleFlags.getReturnsNone) {
|
||||
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
|
||||
&& self->mydb->moduleFlags.getReturnsNone) {
|
||||
Py_INCREF(Py_None);
|
||||
retval = Py_None;
|
||||
}
|
||||
|
@ -1285,7 +1286,8 @@ _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->moduleFlags.getReturnsNone) {
|
||||
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
|
||||
&& self->moduleFlags.getReturnsNone) {
|
||||
err = 0;
|
||||
Py_INCREF(Py_None);
|
||||
retval = Py_None;
|
||||
|
@ -1430,12 +1432,13 @@ DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
|
|||
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;
|
||||
|
@ -1499,12 +1502,13 @@ DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
|
|||
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;
|
||||
|
@ -1629,7 +1633,8 @@ 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->moduleFlags.getReturnsNone) {
|
||||
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
|
||||
&& self->moduleFlags.getReturnsNone) {
|
||||
err = 0;
|
||||
Py_INCREF(Py_None);
|
||||
retval = Py_None;
|
||||
|
@ -2745,7 +2750,15 @@ DB_has_key(DBObject* self, PyObject* args)
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2843,8 +2856,8 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
|
|||
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;
|
||||
}
|
||||
|
@ -3051,7 +3064,8 @@ DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
|
|||
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;
|
||||
}
|
||||
|
@ -3138,7 +3152,8 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
|
|||
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;
|
||||
}
|
||||
|
@ -3305,7 +3320,8 @@ 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 ((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;
|
||||
}
|
||||
|
@ -3377,7 +3393,8 @@ 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 ((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;
|
||||
}
|
||||
|
@ -3432,7 +3449,7 @@ _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
|
|||
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;
|
||||
}
|
||||
|
@ -3572,7 +3589,8 @@ 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 ((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;
|
||||
}
|
||||
|
@ -3640,7 +3658,8 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
|
|||
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;
|
||||
}
|
||||
|
@ -3941,6 +3960,23 @@ DBEnv_set_lg_max(DBEnvObject* self, PyObject* args)
|
|||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args)
|
||||
{
|
||||
|
@ -4651,6 +4687,7 @@ static PyMethodDef DBEnv_methods[] = {
|
|||
{"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},
|
||||
{"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS},
|
||||
{"set_lk_detect", (PyCFunction)DBEnv_set_lk_detect, METH_VARARGS},
|
||||
{"set_lk_max", (PyCFunction)DBEnv_set_lk_max, METH_VARARGS},
|
||||
#if (DBVER >= 32)
|
||||
|
@ -5279,12 +5316,15 @@ DL_EXPORT(void) init_bsddb(void)
|
|||
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");
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue