#----------------------------------------
+ def test07_verify(self):
+ # Verify bug solved in 4.7.3pre8
+ self.d.close()
+ d = db.DB(self.env)
+ d.verify(self.filename)
+
+
+ #----------------------------------------
+
#----------------------------------------------------------------------
#----------------------------------------
- def test07_EnvRemoveAndRename(self):
+ def test08_EnvRemoveAndRename(self):
if not self.env:
return
if verbose:
print '\n', '-=' * 30
- print "Running %s.test07_EnvRemoveAndRename..." % self.__class__.__name__
+ print "Running %s.test08_EnvRemoveAndRename..." % self.__class__.__name__
# can't rename or remove an open DB
self.d.close()
# dbremove and dbrename are in 4.1 and later
if db.version() < (4,1):
- del test07_EnvRemoveAndRename
+ del test08_EnvRemoveAndRename
#----------------------------------------
#----------------------------------------
- def test07_TxnTruncate(self):
+ def test08_TxnTruncate(self):
d = self.d
if verbose:
print '\n', '-=' * 30
- print "Running %s.test07_TxnTruncate..." % self.__class__.__name__
+ print "Running %s.test08_TxnTruncate..." % self.__class__.__name__
d.put("abcde", "ABCDE");
txn = self.env.txn_begin()
#----------------------------------------
- def test08_TxnLateUse(self):
+ def test09_TxnLateUse(self):
txn = self.env.txn_begin()
txn.abort()
try:
dbtype = db.DB_BTREE
dbsetflags = db.DB_RECNUM
- def test07_RecnoInBTree(self):
+ def test08_RecnoInBTree(self):
d = self.d
if verbose:
print '\n', '-=' * 30
- print "Running %s.test07_RecnoInBTree..." % self.__class__.__name__
+ print "Running %s.test08_RecnoInBTree..." % self.__class__.__name__
rec = d.get(200)
self.assertEqual(type(rec), type(()))
class BasicDUPTestCase(BasicTestCase):
dbsetflags = db.DB_DUP
- def test08_DuplicateKeys(self):
+ def test09_DuplicateKeys(self):
d = self.d
if verbose:
print '\n', '-=' * 30
- print "Running %s.test08_DuplicateKeys..." % \
+ print "Running %s.test09_DuplicateKeys..." % \
self.__class__.__name__
d.put("dup0", "before")
else:
return db.DB_BTREE
- def test09_MultiDB(self):
+ def test10_MultiDB(self):
d1 = self.d
if verbose:
print '\n', '-=' * 30
- print "Running %s.test09_MultiDB..." % self.__class__.__name__
+ print "Running %s.test10_MultiDB..." % self.__class__.__name__
d2 = db.DB(self.env)
d2.open(self.filename, "second", self.dbtype,
self.obj = db.DB()
class CrashAndBurn(unittest.TestCase) :
- def test01_OpenCrash(self) :
- # See http://bugs.python.org/issue3307
- self.assertRaises(db.DBInvalidArgError, db.DB, None, 65535)
+ import sys
+ if sys.version_info[:3] < (2, 4, 0):
+ def assertTrue(self, expr, msg=None):
+ self.failUnless(expr,msg=msg)
+
+ #def test01_OpenCrash(self) :
+ # # See http://bugs.python.org/issue3307
+ # self.assertRaises(db.DBInvalidArgError, db.DB, None, 65535)
+
+ def test02_DBEnv_dealloc(self):
+ # http://bugs.python.org/issue3885
+ import gc
+ self.assertRaises(db.DBInvalidArgError, db.DBEnv, ~db.DB_RPCCLIENT)
+ gc.collect()
#----------------------------------------------------------------------
suite.addTest(unittest.makeSuite(HashMultiDBTestCase))
suite.addTest(unittest.makeSuite(DBEnvPrivateObject))
suite.addTest(unittest.makeSuite(DBPrivateObject))
- #suite.addTest(unittest.makeSuite(CrashAndBurn))
+ suite.addTest(unittest.makeSuite(CrashAndBurn))
return suite
/* Forward declaration */
-static PyObject *DB_close_internal(DBObject* self, int flags);
+static PyObject *DB_close_internal(DBObject* self, int flags, int do_not_close);
static void
DB_dealloc(DBObject* self)
PyObject *dummy;
if (self->db != NULL) {
- dummy=DB_close_internal(self,0);
- Py_XDECREF(dummy);
+ dummy=DB_close_internal(self, 0, 0);
+ /*
+ ** Raising exceptions while doing
+ ** garbage collection is a fatal error.
+ */
+ if (dummy)
+ Py_DECREF(dummy);
+ else
+ PyErr_Clear();
}
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
PyObject *dummy;
if (self->dbc != NULL) {
- dummy=DBC_close_internal(self);
- Py_XDECREF(dummy);
+ dummy=DBC_close_internal(self);
+ /*
+ ** Raising exceptions while doing
+ ** garbage collection is a fatal error.
+ */
+ if (dummy)
+ Py_DECREF(dummy);
+ else
+ PyErr_Clear();
}
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
if (self == NULL)
return NULL;
+ self->db_env = NULL;
self->closed = 1;
self->flags = flags;
self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
PyObject *dummy;
if (self->db_env) {
- dummy=DBEnv_close_internal(self,0);
- Py_XDECREF(dummy);
+ dummy=DBEnv_close_internal(self, 0);
+ /*
+ ** Raising exceptions while doing
+ ** garbage collection is a fatal error.
+ */
+ if (dummy)
+ Py_DECREF(dummy);
+ else
+ PyErr_Clear();
}
Py_XDECREF(self->event_notifyCallback);
if (self->txn) {
int flag_prepare = self->flag_prepare;
+
dummy=DBTxn_abort_discard_internal(self,0);
- Py_XDECREF(dummy);
+ /*
+ ** Raising exceptions while doing
+ ** garbage collection is a fatal error.
+ */
+ if (dummy)
+ Py_DECREF(dummy);
+ else
+ PyErr_Clear();
+
if (!flag_prepare) {
PyErr_Warn(PyExc_RuntimeWarning,
"DBTxn aborted in destructor. No prior commit() or abort().");
if (self->sequence != NULL) {
dummy=DBSequence_close_internal(self,0,0);
- Py_XDECREF(dummy);
+ /*
+ ** Raising exceptions while doing
+ ** garbage collection is a fatal error.
+ */
+ if (dummy)
+ Py_DECREF(dummy);
+ else
+ PyErr_Clear();
}
if (self->in_weakreflist != NULL) {
static PyObject*
-DB_close_internal(DBObject* self, int flags)
+DB_close_internal(DBObject* self, int flags, int do_not_close)
{
PyObject *dummy;
- int err;
+ int err = 0;
if (self->db != NULL) {
/* Can be NULL if db is not in an environment */
}
#endif
- MYDB_BEGIN_ALLOW_THREADS;
- err = self->db->close(self->db, flags);
- MYDB_END_ALLOW_THREADS;
- self->db = NULL;
+ /*
+ ** "do_not_close" is used to dispose all related objects in the
+ ** tree, without actually releasing the "root" object.
+ ** This is done, for example, because function calls like
+ ** "DB.verify()" implicitly close the underlying handle. So
+ ** the handle doesn't need to be closed, but related objects
+ ** must be cleaned up.
+ */
+ if (!do_not_close) {
+ MYDB_BEGIN_ALLOW_THREADS;
+ err = self->db->close(self->db, flags);
+ MYDB_END_ALLOW_THREADS;
+ self->db = NULL;
+ }
RETURN_IF_ERR();
}
RETURN_NONE();
int flags=0;
if (!PyArg_ParseTuple(args,"|i:close", &flags))
return NULL;
- return DB_close_internal(self,flags);
+ return DB_close_internal(self, flags, 0);
}
if (makeDBError(err)) {
PyObject *dummy;
- dummy=DB_close_internal(self,0);
+ dummy=DB_close_internal(self, 0, 0);
Py_XDECREF(dummy);
return NULL;
}
/* XXX(nnorwitz): it should probably be an exception if outFile
can't be opened. */
- MYDB_BEGIN_ALLOW_THREADS;
- err = self->db->verify(self->db, fileName, dbName, outFile, flags);
- MYDB_END_ALLOW_THREADS;
- if (outFile)
- fclose(outFile);
-
{ /* DB.verify acts as a DB handle destructor (like close) */
PyObject *error;
- error=DB_close_internal(self,0);
+ error=DB_close_internal(self, 0, 1);
if (error ) {
return error;
}
}
+ MYDB_BEGIN_ALLOW_THREADS;
+ err = self->db->verify(self->db, fileName, dbName, outFile, flags);
+ MYDB_END_ALLOW_THREADS;
+
+ self->db = NULL; /* Implicit close; related objects already released */
+
+ if (outFile)
+ fclose(outFile);
+
RETURN_IF_ERR();
RETURN_NONE();
}
Py_XDECREF(dummy);
}
while(self->children_dbs) {
- dummy=DB_close_internal(self->children_dbs,0);
+ dummy=DB_close_internal(self->children_dbs, 0, 0);
Py_XDECREF(dummy);
}
}
if (!PyArg_ParseTuple(args, "|i:close", &flags))
return NULL;
- return DBEnv_close_internal(self,flags);
+ return DBEnv_close_internal(self, flags);
}
}
#endif
while (self->children_dbs) {
- dummy=DB_close_internal(self->children_dbs,0);
+ dummy=DB_close_internal(self->children_dbs, 0, 0);
Py_XDECREF(dummy);
}
self->txn=NULL;
}
+ /*
+ ** "do_not_close" is used to dispose all related objects in the
+ ** tree, without actually releasing the "root" object.
+ ** This is done, for example, because function calls like
+ ** "DBSequence.remove()" implicitly close the underlying handle. So
+ ** the handle doesn't need to be closed, but related objects
+ ** must be cleaned up.
+ */
if (!do_not_close) {
MYDB_BEGIN_ALLOW_THREADS
err = self->sequence->close(self->sequence, flags);