From be0db8b125951adb475fc388de9aebabcabbf6e3 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Wed, 1 Oct 2003 06:48:51 +0000 Subject: [PATCH] bsddb3 4.2.2, adds DBCursor.get_current_size() method to return the length of the current value without reading the value itself. --- Lib/bsddb/test/test_basics.py | 74 +++++++++++++++++------------------ Modules/_bsddb.c | 36 ++++++++++++++++- 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/Lib/bsddb/test/test_basics.py b/Lib/bsddb/test/test_basics.py index 2e6b922b4db..93a7fb75916 100644 --- a/Lib/bsddb/test/test_basics.py +++ b/Lib/bsddb/test/test_basics.py @@ -49,6 +49,8 @@ class BasicTestCase(unittest.TestCase): envflags = 0 envsetflags = 0 + _numKeys = 1002 # PRIVATE. NOTE: must be an even value + def setUp(self): if self.useEnv: homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home') @@ -106,17 +108,23 @@ class BasicTestCase(unittest.TestCase): - def populateDB(self): + def populateDB(self, _txn=None): d = self.d - for x in range(500): - key = '%04d' % (1000 - x) # insert keys in reverse order - data = self.makeData(key) - d.put(key, data) - for x in range(500): + for x in range(self._numKeys/2): + key = '%04d' % (self._numKeys - x) # insert keys in reverse order + data = self.makeData(key) + d.put(key, data, _txn) + + d.put('empty value', '', _txn) + + for x in range(self._numKeys/2-1): key = '%04d' % x # and now some in forward order data = self.makeData(key) - d.put(key, data) + d.put(key, data, _txn) + + if _txn: + _txn.commit() num = len(d) if verbose: @@ -236,20 +244,20 @@ class BasicTestCase(unittest.TestCase): if verbose: print data - assert len(d) == 1000 + assert len(d) == self._numKeys keys = d.keys() - assert len(keys) == 1000 + assert len(keys) == self._numKeys assert type(keys) == type([]) d['new record'] = 'a new record' - assert len(d) == 1001 + assert len(d) == self._numKeys+1 keys = d.keys() - assert len(keys) == 1001 + assert len(keys) == self._numKeys+1 d['new record'] = 'a replacement record' - assert len(d) == 1001 + assert len(d) == self._numKeys+1 keys = d.keys() - assert len(keys) == 1001 + assert len(keys) == self._numKeys+1 if verbose: print "the first 10 keys are:" @@ -261,7 +269,7 @@ class BasicTestCase(unittest.TestCase): assert d.has_key('spam') == 0 items = d.items() - assert len(items) == 1001 + assert len(items) == self._numKeys+1 assert type(items) == type([]) assert type(items[0]) == type(()) assert len(items[0]) == 2 @@ -271,7 +279,7 @@ class BasicTestCase(unittest.TestCase): pprint(items[:10]) values = d.values() - assert len(values) == 1001 + assert len(values) == self._numKeys+1 assert type(values) == type([]) if verbose: @@ -293,7 +301,7 @@ class BasicTestCase(unittest.TestCase): else: txn = None c = self.d.cursor(txn=txn) - + rec = c.first() count = 0 while rec is not None: @@ -309,8 +317,9 @@ class BasicTestCase(unittest.TestCase): rec = None else: self.fail("unexpected DBNotFoundError") - - assert count == 1000 + assert c.get_current_size() == len(c.current()[1]), "%s != len(%r)" % (c.get_current_size(), c.current()[1]) + + assert count == self._numKeys rec = c.last() @@ -329,14 +338,20 @@ class BasicTestCase(unittest.TestCase): else: self.fail("unexpected DBNotFoundError") - assert count == 1000 + assert count == self._numKeys rec = c.set('0505') rec2 = c.current() assert rec == rec2 assert rec[0] == '0505' assert rec[1] == self.makeData('0505') + assert c.get_current_size() == len(rec[1]) + # make sure we get empty values properly + rec = c.set('empty value') + assert rec[1] == '' + assert c.get_current_size() == 0 + try: n = c.set('bad key') except db.DBNotFoundError, val: @@ -575,23 +590,8 @@ class BasicTransactionTestCase(BasicTestCase): def populateDB(self): - d = self.d txn = self.env.txn_begin() - for x in range(500): - key = '%04d' % (1000 - x) # insert keys in reverse order - data = self.makeData(key) - d.put(key, data, txn) - - for x in range(500): - key = '%04d' % x # and now some in forward order - data = self.makeData(key) - d.put(key, data, txn) - - txn.commit() - - num = len(d) - if verbose: - print "created %d records" % num + BasicTestCase.populateDB(self, _txn=txn) self.txn = self.env.txn_begin() @@ -626,7 +626,7 @@ class BasicTransactionTestCase(BasicTestCase): if verbose and count % 100 == 0: print rec rec = c.next() - assert count == 1001 + assert count == self._numKeys+1 c.close() # Cursors *MUST* be closed before commit! self.txn.commit() @@ -855,7 +855,7 @@ class BasicMultiDBTestCase(BasicTestCase): if verbose and (count % 50) == 0: print rec rec = c1.next() - assert count == 1000 + assert count == self._numKeys count = 0 rec = c2.first() diff --git a/Modules/_bsddb.c b/Modules/_bsddb.c index c6b569cbe39..e70552646e6 100644 --- a/Modules/_bsddb.c +++ b/Modules/_bsddb.c @@ -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.2.1" +#define PY_BSDDB_VERSION "4.2.2" static char *rcs_id = "$Id$"; @@ -2981,6 +2981,39 @@ DBC_get_both(DBCursorObject* self, PyObject* args) self->mydb->moduleFlags.getReturnsNone); } +/* Return size of entry */ +static PyObject* +DBC_get_current_size(DBCursorObject* self, PyObject* args) +{ + int err, flags=DB_CURRENT; + PyObject* retval = NULL; + DBT key, data; + + if (!PyArg_ParseTuple(args, ":get_current_size")) + return NULL; + CHECK_CURSOR_NOT_CLOSED(self); + CLEAR_DBT(key); + CLEAR_DBT(data); + + /* We don't allocate any memory, forcing a ENOMEM error and thus + getting the record size. */ + data.flags = DB_DBT_USERMEM; + data.ulen = 0; + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags); + MYDB_END_ALLOW_THREADS; + if (err == ENOMEM || !err) { + /* ENOMEM means positive size, !err means zero length value */ + retval = PyInt_FromLong((long)data.size); + err = 0; + } + + FREE_DBT(key); + FREE_DBT(data); + RETURN_IF_ERR(); + return retval; +} + static PyObject* DBC_set_both(DBCursorObject* self, PyObject* args) { @@ -4079,6 +4112,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}, + {"get_current_size",(PyCFunction)DBC_get_current_size, 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},