Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e947706

Browse files
committed
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.
1 parent 5d36a55 commit e947706

3 files changed

Lines changed: 97 additions & 33 deletions

File tree

Lib/bsddb/test/test_basics.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,10 +397,14 @@ def test03_SimpleCursorStuff(self, get_raises_error=0, set_raises_error=0):
397397
try:
398398
rec = c.current()
399399
except db.DBKeyEmptyError, val:
400-
assert val[0] == db.DB_KEYEMPTY
401-
if verbose: print val
400+
if get_raises_error:
401+
assert val[0] == db.DB_KEYEMPTY
402+
if verbose: print val
403+
else:
404+
self.fail("unexpected DBKeyEmptyError")
402405
else:
403-
self.fail('exception expected')
406+
if get_raises_error:
407+
self.fail('DBKeyEmptyError exception expected')
404408

405409
c.next()
406410
c2 = c.dup(db.DB_POSITION)
@@ -612,7 +616,6 @@ def populateDB(self):
612616
self.txn = self.env.txn_begin()
613617

614618

615-
616619
def test06_Transactions(self):
617620
d = self.d
618621
if verbose:

Lib/bsddb/test/test_recno.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ def tearDown(self):
3434

3535
def test01_basic(self):
3636
d = db.DB()
37+
38+
get_returns_none = d.set_get_returns_none(2)
39+
d.set_get_returns_none(get_returns_none)
40+
3741
d.open(self.filename, db.DB_RECNO, db.DB_CREATE)
3842

3943
for x in letters:
@@ -65,15 +69,28 @@ def test01_basic(self):
6569
else:
6670
self.fail("expected exception")
6771

72+
# test that has_key raises DB exceptions (fixed in pybsddb 4.3.2)
73+
try:
74+
d.has_key(0)
75+
except db.DBError, val:
76+
pass
77+
else:
78+
self.fail("has_key did not raise a proper exception")
79+
6880
try:
6981
data = d[100]
7082
except KeyError:
7183
pass
7284
else:
7385
self.fail("expected exception")
7486

75-
data = d.get(100)
76-
assert data == None
87+
try:
88+
data = d.get(100)
89+
except db.DBNotFoundError, val:
90+
if get_returns_none:
91+
self.fail("unexpected exception")
92+
else:
93+
assert data == None
7794

7895
keys = d.keys()
7996
if verbose:
@@ -161,10 +178,14 @@ def test01_basic(self):
161178
try:
162179
d.get(99)
163180
except db.DBKeyEmptyError, val:
164-
assert val[0] == db.DB_KEYEMPTY
165-
if verbose: print val
181+
if get_returns_none:
182+
self.fail("unexpected DBKeyEmptyError exception")
183+
else:
184+
assert val[0] == db.DB_KEYEMPTY
185+
if verbose: print val
166186
else:
167-
self.fail("expected exception")
187+
if not get_returns_none:
188+
self.fail("expected exception")
168189

169190
rec = c.set(40)
170191
while rec:

Modules/_bsddb.c

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
#error "eek! DBVER can't handle minor versions > 9"
9898
#endif
9999

100-
#define PY_BSDDB_VERSION "4.3.1"
100+
#define PY_BSDDB_VERSION "4.3.2"
101101
static char *rcs_id = "$Id$";
102102

103103

@@ -153,7 +153,7 @@ static PyInterpreterState* _db_interpreterState = NULL;
153153

154154
static PyObject* DBError; /* Base class, all others derive from this */
155155
static PyObject* DBCursorClosedError; /* raised when trying to use a closed cursor object */
156-
static PyObject* DBKeyEmptyError; /* DB_KEYEMPTY */
156+
static PyObject* DBKeyEmptyError; /* DB_KEYEMPTY: also derives from KeyError */
157157
static PyObject* DBKeyExistError; /* DB_KEYEXIST */
158158
static PyObject* DBLockDeadlockError; /* DB_LOCK_DEADLOCK */
159159
static PyObject* DBLockNotGrantedError; /* DB_LOCK_NOTGRANTED */
@@ -212,10 +212,10 @@ static PyObject* DBPermissionsError; /* EPERM */
212212

213213
struct behaviourFlags {
214214
/* What is the default behaviour when DB->get or DBCursor->get returns a
215-
DB_NOTFOUND error? Return None or raise an exception? */
215+
DB_NOTFOUND || DB_KEYEMPTY error? Return None or raise an exception? */
216216
unsigned int getReturnsNone : 1;
217217
/* What is the default behaviour for DBCursor.set* methods when DBCursor->get
218-
* returns a DB_NOTFOUND error? Return None or raise an exception? */
218+
* returns a DB_NOTFOUND || DB_KEYEMPTY error? Return None or raise? */
219219
unsigned int cursorSetReturnsNone : 1;
220220
};
221221

@@ -673,7 +673,8 @@ static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
673673
err = self->dbc->c_get(self->dbc, &key, &data, flags);
674674
MYDB_END_ALLOW_THREADS;
675675

676-
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
676+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
677+
&& self->mydb->moduleFlags.getReturnsNone) {
677678
Py_INCREF(Py_None);
678679
retval = Py_None;
679680
}
@@ -1285,7 +1286,8 @@ _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
12851286
err = self->db->get(self->db, txn, &key, &data, flags|consume_flag);
12861287
MYDB_END_ALLOW_THREADS;
12871288

1288-
if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
1289+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1290+
&& self->moduleFlags.getReturnsNone) {
12891291
err = 0;
12901292
Py_INCREF(Py_None);
12911293
retval = Py_None;
@@ -1430,12 +1432,13 @@ DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
14301432
err = self->db->get(self->db, txn, &key, &data, flags);
14311433
MYDB_END_ALLOW_THREADS;
14321434

1433-
if ((err == DB_NOTFOUND) && (dfltobj != NULL)) {
1435+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) {
14341436
err = 0;
14351437
Py_INCREF(dfltobj);
14361438
retval = dfltobj;
14371439
}
1438-
else if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
1440+
else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1441+
&& self->moduleFlags.getReturnsNone) {
14391442
err = 0;
14401443
Py_INCREF(Py_None);
14411444
retval = Py_None;
@@ -1499,12 +1502,13 @@ DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
14991502
err = self->db->pget(self->db, txn, &key, &pkey, &data, flags);
15001503
MYDB_END_ALLOW_THREADS;
15011504

1502-
if ((err == DB_NOTFOUND) && (dfltobj != NULL)) {
1505+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) {
15031506
err = 0;
15041507
Py_INCREF(dfltobj);
15051508
retval = dfltobj;
15061509
}
1507-
else if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
1510+
else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1511+
&& self->moduleFlags.getReturnsNone) {
15081512
err = 0;
15091513
Py_INCREF(Py_None);
15101514
retval = Py_None;
@@ -1629,7 +1633,8 @@ DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
16291633
err = self->db->get(self->db, txn, &key, &data, flags);
16301634
MYDB_END_ALLOW_THREADS;
16311635

1632-
if ((err == DB_NOTFOUND) && self->moduleFlags.getReturnsNone) {
1636+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
1637+
&& self->moduleFlags.getReturnsNone) {
16331638
err = 0;
16341639
Py_INCREF(Py_None);
16351640
retval = Py_None;
@@ -2745,7 +2750,15 @@ DB_has_key(DBObject* self, PyObject* args)
27452750
err = self->db->get(self->db, txn, &key, &data, 0);
27462751
MYDB_END_ALLOW_THREADS;
27472752
FREE_DBT(key);
2748-
return PyInt_FromLong((err == DB_BUFFER_SMALL) || (err == 0));
2753+
2754+
if (err == DB_BUFFER_SMALL || err == 0) {
2755+
return PyInt_FromLong(1);
2756+
} else if (err == DB_NOTFOUND || err == DB_KEYEMPTY) {
2757+
return PyInt_FromLong(0);
2758+
}
2759+
2760+
makeDBError(err);
2761+
return NULL;
27492762
}
27502763

27512764

@@ -2843,8 +2856,8 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
28432856
Py_DECREF(item);
28442857
}
28452858

2846-
/* DB_NOTFOUND is okay, it just means we got to the end */
2847-
if (err != DB_NOTFOUND && makeDBError(err)) {
2859+
/* DB_NOTFOUND || DB_KEYEMPTY is okay, it means we got to the end */
2860+
if (err != DB_NOTFOUND && err != DB_KEYEMPTY && makeDBError(err)) {
28482861
Py_DECREF(list);
28492862
list = NULL;
28502863
}
@@ -3051,7 +3064,8 @@ DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
30513064
err = self->dbc->c_get(self->dbc, &key, &data, flags);
30523065
MYDB_END_ALLOW_THREADS;
30533066

3054-
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
3067+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3068+
&& self->mydb->moduleFlags.getReturnsNone) {
30553069
Py_INCREF(Py_None);
30563070
retval = Py_None;
30573071
}
@@ -3138,7 +3152,8 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
31383152
err = self->dbc->c_pget(self->dbc, &key, &pkey, &data, flags);
31393153
MYDB_END_ALLOW_THREADS;
31403154

3141-
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
3155+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3156+
&& self->mydb->moduleFlags.getReturnsNone) {
31423157
Py_INCREF(Py_None);
31433158
retval = Py_None;
31443159
}
@@ -3305,7 +3320,8 @@ DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
33053320
MYDB_BEGIN_ALLOW_THREADS;
33063321
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET);
33073322
MYDB_END_ALLOW_THREADS;
3308-
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
3323+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3324+
&& self->mydb->moduleFlags.cursorSetReturnsNone) {
33093325
Py_INCREF(Py_None);
33103326
retval = Py_None;
33113327
}
@@ -3377,7 +3393,8 @@ DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
33773393
MYDB_BEGIN_ALLOW_THREADS;
33783394
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
33793395
MYDB_END_ALLOW_THREADS;
3380-
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
3396+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3397+
&& self->mydb->moduleFlags.cursorSetReturnsNone) {
33813398
Py_INCREF(Py_None);
33823399
retval = Py_None;
33833400
}
@@ -3432,7 +3449,7 @@ _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
34323449
MYDB_BEGIN_ALLOW_THREADS;
34333450
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
34343451
MYDB_END_ALLOW_THREADS;
3435-
if ((err == DB_NOTFOUND) && returnsNone) {
3452+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && returnsNone) {
34363453
Py_INCREF(Py_None);
34373454
retval = Py_None;
34383455
}
@@ -3572,7 +3589,8 @@ DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
35723589
MYDB_BEGIN_ALLOW_THREADS;
35733590
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
35743591
MYDB_END_ALLOW_THREADS;
3575-
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.cursorSetReturnsNone) {
3592+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3593+
&& self->mydb->moduleFlags.cursorSetReturnsNone) {
35763594
Py_INCREF(Py_None);
35773595
retval = Py_None;
35783596
}
@@ -3640,7 +3658,8 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
36403658
MYDB_BEGIN_ALLOW_THREADS;
36413659
err = self->dbc->c_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
36423660
MYDB_END_ALLOW_THREADS;
3643-
if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
3661+
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
3662+
&& self->mydb->moduleFlags.getReturnsNone) {
36443663
Py_INCREF(Py_None);
36453664
retval = Py_None;
36463665
}
@@ -3941,6 +3960,23 @@ DBEnv_set_lg_max(DBEnvObject* self, PyObject* args)
39413960
}
39423961

39433962

3963+
static PyObject*
3964+
DBEnv_set_lg_regionmax(DBEnvObject* self, PyObject* args)
3965+
{
3966+
int err, lg_max;
3967+
3968+
if (!PyArg_ParseTuple(args, "i:set_lg_regionmax", &lg_max))
3969+
return NULL;
3970+
CHECK_ENV_NOT_CLOSED(self);
3971+
3972+
MYDB_BEGIN_ALLOW_THREADS;
3973+
err = self->db_env->set_lg_regionmax(self->db_env, lg_max);
3974+
MYDB_END_ALLOW_THREADS;
3975+
RETURN_IF_ERR();
3976+
RETURN_NONE();
3977+
}
3978+
3979+
39443980
static PyObject*
39453981
DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args)
39463982
{
@@ -4651,6 +4687,7 @@ static PyMethodDef DBEnv_methods[] = {
46514687
{"set_lg_bsize", (PyCFunction)DBEnv_set_lg_bsize, METH_VARARGS},
46524688
{"set_lg_dir", (PyCFunction)DBEnv_set_lg_dir, METH_VARARGS},
46534689
{"set_lg_max", (PyCFunction)DBEnv_set_lg_max, METH_VARARGS},
4690+
{"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS},
46544691
{"set_lk_detect", (PyCFunction)DBEnv_set_lk_detect, METH_VARARGS},
46554692
{"set_lk_max", (PyCFunction)DBEnv_set_lk_max, METH_VARARGS},
46564693
#if (DBVER >= 32)
@@ -5279,12 +5316,15 @@ DL_EXPORT(void) init_bsddb(void)
52795316
DBError = PyErr_NewException("bsddb._db.DBError", NULL, NULL);
52805317
PyDict_SetItemString(d, "DBError", DBError);
52815318

5282-
/* Some magic to make DBNotFoundError derive from both DBError and
5283-
KeyError, since the API only supports using one base class. */
5319+
/* Some magic to make DBNotFoundError and DBKeyEmptyError derive
5320+
* from both DBError and KeyError, since the API only supports
5321+
* using one base class. */
52845322
PyDict_SetItemString(d, "KeyError", PyExc_KeyError);
5285-
PyRun_String("class DBNotFoundError(DBError, KeyError): pass",
5323+
PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n"
5324+
"class DBKeyEmptyError(DBError, KeyError): pass",
52865325
Py_file_input, d, d);
52875326
DBNotFoundError = PyDict_GetItemString(d, "DBNotFoundError");
5327+
DBKeyEmptyError = PyDict_GetItemString(d, "DBKeyEmptyError");
52885328
PyDict_DelItemString(d, "KeyError");
52895329

52905330

0 commit comments

Comments
 (0)