Changeset 964 for trunk


Ignore:
Timestamp:
Jan 5, 2019, 8:51:23 AM (7 months ago)
Author:
cito
Message:

Graceful exit of DB destructor on closed connection

Also, in the 5.1 branch, the DB wrapper can now be closed
(without closing the underlying connection) and reopened
(reusing the same connection).

This fixed GitHub? issue #11

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/docs/contents/changelog.rst

    r960 r964  
    44Version 5.1 (2019-mm-dd)
    55------------------------
    6 - ...
     6- DB wrapper objects based on existing connections can not be closed and
     7  reopened properly (but the underlying connection will not be affected).
    78
    89Vesion 5.0.7 (2019-mm-dd)
     
    1011- This version officially supports the new PostgreSQL 11.
    1112- Fixed a bug in parsing array subscript ranges (reported by Justin Pryzby).
     13- Fixed an issue when deleting a DB wrapper object with the underlying
     14  connection already closed (bug report by Jacob Champion).
    1215
    1316Vesion 5.0.6 (2018-07-29)
  • trunk/pg.py

    r961 r964  
    15031503        if not db or not hasattr(db, 'db') or not hasattr(db, 'query'):
    15041504            db = connect(*args, **kw)
     1505            self._db_args = args, kw
    15051506            self._closeable = True
    15061507        else:
     1508            self._db_args = db
    15071509            self._closeable = False
    15081510        self.db = db
     
    15121514        self._pkeys = {}
    15131515        self._privileges = {}
    1514         self._args = args, kw
    15151516        self.adapter = Adapter(self)
    15161517        self.dbtypes = DbTypes(self)
     
    15731574            db = None
    15741575        if db:
    1575             db.set_cast_hook(None)
     1576            try:
     1577                db.set_cast_hook(None)
     1578            except TypeError:
     1579                pass  # probably already closed
    15761580            if self._closeable:
    1577                 db.close()
     1581                try:
     1582                    db.close()
     1583                except InternalError:
     1584                    pass  # probably already closed
    15781585
    15791586    # Auxiliary methods
     
    16301637        """Close the database connection."""
    16311638        # Wraps shared library function so we can track state.
    1632         if self._closeable:
    1633             if self.db:
    1634                 self.db.set_cast_hook(None)
    1635                 self.db.close()
    1636                 self.db = None
    1637             else:
    1638                 raise _int_error('Connection already closed')
     1639        db = self.db
     1640        if db:
     1641            try:
     1642                db.set_cast_hook(None)
     1643            except TypeError:
     1644                pass  # probably already closed
     1645            if self._closeable:
     1646                db.close()
     1647            self.db = None
     1648        else:
     1649            raise _int_error('Connection already closed')
    16391650
    16401651    def reset(self):
     
    16591670        # There is no such shared library function.
    16601671        if self._closeable:
    1661             db = connect(*self._args[0], **self._args[1])
     1672            db = connect(*self._db_args[0], **self._db_args[1])
    16621673            if self.db:
    16631674                self.db.set_cast_hook(None)
    16641675                self.db.close()
     1676            db.set_cast_hook(self.dbtypes.typecast)
    16651677            self.db = db
     1678        else:
     1679            self.db = self._db_args
    16661680
    16671681    def begin(self, mode=None):
  • trunk/tests/test_classic_dbwrapper.py

    r961 r964  
    376376    def testExistingConnection(self):
    377377        db = pg.DB(self.db.db)
     378        self.assertIsNotNone(db.db)
    378379        self.assertEqual(self.db.db, db.db)
    379         self.assertTrue(db.db)
    380380        db.close()
    381         self.assertTrue(db.db)
     381        self.assertIsNone(db.db)
     382        self.assertIsNotNone(self.db.db)
    382383        db.reopen()
    383         self.assertTrue(db.db)
     384        self.assertIsNotNone(db.db)
     385        self.assertEqual(self.db.db, db.db)
    384386        db.close()
    385         self.assertTrue(db.db)
     387        self.assertIsNone(db.db)
    386388        db = pg.DB(self.db)
    387389        self.assertEqual(self.db.db, db.db)
     
    389391        self.assertEqual(self.db.db, db.db)
    390392
    391         class DB2:
    392             pass
    393 
    394         db2 = DB2()
    395         db2._cnx = self.db.db
     393    def testExistingDbApi2Connection(self):
     394
     395        class DBApi2Con:
     396
     397            def __init__(self, cnx):
     398                self._cnx = cnx
     399
     400            def close(self):
     401                self._cnx.close()
     402
     403        db2 = DBApi2Con(self.db.db)
    396404        db = pg.DB(db2)
    397405        self.assertEqual(self.db.db, db.db)
     406        db.close()
     407        self.assertIsNone(db.db)
     408        db.reopen()
     409        self.assertIsNotNone(db.db)
     410        self.assertEqual(self.db.db, db.db)
     411        db.close()
     412        self.assertIsNone(db.db)
     413        db2.close()
    398414
    399415
Note: See TracChangeset for help on using the changeset viewer.