Re: Savepoint or subtransaction support
Markus Schiltknecht <[email protected]> Fri, 06 Oct 2006 12:56:13 +0200
| Newsgroups | gmane.comp.python.db.pypgsql.user |
|---|---|
| Message-ID | <[email protected]> |
This is a MIME-formatted message. If you see this text it means that your
E-mail software does not support MIME-formatted messages.
--=_molabola.bugaboo.mu-24216-1160132174-0001-2
Content-Type: text/plain; charset=iso-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Hi,
Our patches were very similar, I like the single rollback() method with
added support for savepoints. Adding a rollback_savepoint method (as I
did) is not that elegant.
I've modified my patch to support multiple savepoints. I'm now using the
same methods as the original patch (i.e. savepoint, release and rollback)
The original patch from [1] did release a savepoint if it already
existed. I think that's dangerous. In fact, PostgreSQL even allows to
define multiple savepoints with the very same name.
Also, if you rollback to a savepoint, the savepoint is not released. So
you can rollback to a savepoint several times. This also allows you to
call rollback() and then release() on the same savepoint.
If you define multiple savepoints A, B, C (in that order), rolling back
to savepoint A obviously releases the savepoints B and C. My patch takes
that into accont. Please note that savepoint A still remains and does
not get released when rolling back to it.
(I've tried to upload the page to the 'patches' page on SourceForge, but
didn't succeed, I've only added a useless comment, sorry. Please bear
with a SF-first-timer.)
Regards
Markus
[1]: the original patch:
https://sourceforge.net/tracker/?func=detail&atid=316528&aid=1511984&group_id=16528
Markus Schiltknecht wrote:
> Hi,
>
> as I really urgently need savepoints, I have written a small patch to
> add support for one savepoint. Only to find out that I should have
> looked in the SF 'patches' page where someone else did exactly the same...
>
> I'm comparing our patches just now.
>
> Regards
>
> Markus
--=_molabola.bugaboo.mu-24216-1160132174-0001-2
Content-Type: text/plain; name=diff; charset=iso-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="diff"
Index: pyPgSQL/PgSQL.py
===================================================================
RCS file: /cvsroot/pypgsql/pypgsql/pyPgSQL/PgSQL.py,v
retrieving revision 1.50
diff -c -r1.50 PgSQL.py
*** pyPgSQL/PgSQL.py 1 Jun 2006 14:42:51 -0000 1.50
--- pyPgSQL/PgSQL.py 6 Oct 2006 10:37:52 -0000
***************
*** 2368,2373 ****
--- 2368,2374 ----
self.__dict__["TransactionLevel"] = ""
self.__dict__["notices"] = self.conn.notices
self.__dict__["inTransaction"] = 0
+ self.__dict__["savepoints"] = None
self.__dict__["version"] = self.conn.version
self.__dict__["_isOpen"] = 1
self.__dict__["_cache"] = TypeCache(self)
***************
*** 2515,2520 ****
--- 2516,2522 ----
if len(self.notices) != _nl:
raise Warning, self.notices.pop()
self.__dict__["inTransaction"] = 1
+ self.__dict__["savepoints"] = []
def close(self):
***************
*** 2542,2547 ****
--- 2544,2550 ----
self.__dict__["conn"] = None
self.__dict__["cursors"] = None
self.__dict__["inTransaction"] = 0
+ self.__dict__["savepoints"] = None
self.__dict__["TransactionLevel"] = None
self.__dict__["version"] = None
self.__dict__["notices"] = None
***************
*** 2559,2564 ****
--- 2562,2568 ----
if self.__closeCursors():
self.__dict__["inTransaction"] = 0
+ self.__dict__["savepoints"] = None
_nl = len(self.conn.notices)
res = self.conn.query("COMMIT WORK")
if len(self.notices) != _nl:
***************
*** 2566,2575 ****
if res.resultStatus != COMMAND_OK:
raise InternalError, "Commit failed - reason unknown."
! def rollback(self):
"""
rollback()
! Rollback to the start of any pending transactions.\n"""
if not self._isOpen:
raise InterfaceError, "Rollback failed - Connection is not open."
--- 2570,2605 ----
if res.resultStatus != COMMAND_OK:
raise InternalError, "Commit failed - reason unknown."
! def savepoint(self, name):
! """
! savepoint()
! Set a savepoint in the current connection, to which the connection
! gets rolled back to on error or on request.\n"""
!
! if not self._isOpen:
! raise InterfaceError, "Savepoint failed - Connection is not open."
!
! if self.autocommit:
! raise InterfaceError, "Savepoint failed - autocommit is on."
!
! if not self.inTransaction:
! raise InterfaceError, "Savepoint failed - not in a transaction."
!
! _nl = len(self.conn.notices)
! res = self.conn.query("SAVEPOINT %s" % name)
! if len(self.notices) != _nl:
! raise Warning, self.notices.pop()
! if res.resultStatus != COMMAND_OK:
! raise InternalError, \
! "Savepoint failed - %s" % res.resultErrorMessage
!
! self.__dict__["savepoints"].append(name)
!
! def rollback(self, toSavepoint=None):
"""
rollback()
! Rollback to the start of any pending transactions on to a
! savepoint.\n"""
if not self._isOpen:
raise InterfaceError, "Rollback failed - Connection is not open."
***************
*** 2578,2592 ****
raise InterfaceError, "Rollback failed - autocommit is on."
if self.__closeCursors():
- self.__dict__["inTransaction"] = 0
_nl = len(self.conn.notices)
! res = self.conn.query("ROLLBACK WORK")
if len(self.notices) != _nl:
raise Warning, self.notices.pop()
if res.resultStatus != COMMAND_OK:
raise InternalError, \
"Rollback failed - %s" % res.resultErrorMessage
def cursor(self, name=None, isRefCursor=PG_False):
"""
cursor([name])
--- 2608,2660 ----
raise InterfaceError, "Rollback failed - autocommit is on."
if self.__closeCursors():
_nl = len(self.conn.notices)
! if toSavepoint:
! try:
! idx = self.savepoints.index(toSavepoint)
! self.__dict__["savepoints"] = self.savepoints[:idx+1]
! except:
! raise InterfaceError, "Rollback failed - no such savepoint."
!
! res = self.conn.query("ROLLBACK TO SAVEPOINT %s" % toSavepoint)
!
! else:
! self.__dict__["inTransaction"] = 0
! res = self.conn.query("ROLLBACK WORK")
!
if len(self.notices) != _nl:
raise Warning, self.notices.pop()
if res.resultStatus != COMMAND_OK:
raise InternalError, \
"Rollback failed - %s" % res.resultErrorMessage
+ def release(self, name=None):
+ if not self._isOpen:
+ raise InterfaceError, "Release failed - Connection is not open."
+
+ if self.autocommit:
+ raise InterfaceError, "Release failed - autocommit is on."
+
+ if not self.inTransaction:
+ raise InterfaceError, "Release failed - not in a transaction."
+
+ if not name:
+ name = self.savepoints[-1]
+ else:
+ try:
+ idx = self.savepoints.index(name)
+ self.__dict__["savepoints"] = self.savepoints[:idx+1]
+ except:
+ raise InterfaceError, "Rollback failed - no savepoint named %s." % name
+
+ _nl = len(self.conn.notices)
+ res = self.conn.query("RELEASE SAVEPOINT %s" % name)
+ if len(self.notices) != _nl:
+ raise Warning, self.notices.pop()
+ if res.resultStatus != COMMAND_OK:
+ raise InternalError, \
+ "Release savepoint failed - %s" % res.resultErrorMessage
+
def cursor(self, name=None, isRefCursor=PG_False):
"""
cursor([name])
***************
*** 2982,2989 ****
# Uh-oh. A fatal error occurred. This means the current trans-
# action has been aborted. Try to recover to a sane state.
if self.conn.inTransaction:
! self.conn.conn.query('END WORK')
! self.conn.__dict__["inTransaction"] = 0
self.conn._Connection__closeCursors()
raise OperationalError, msg
except InternalError, msg:
--- 3050,3060 ----
# Uh-oh. A fatal error occurred. This means the current trans-
# action has been aborted. Try to recover to a sane state.
if self.conn.inTransaction:
! if len(self.conn.savepoints) > 0:
! self.conn.conn.query('ROLLBACK TO SAVEPOINT %s' % self.conn.savepoints[-1])
! else:
! self.conn.conn.query('END WORK')
! self.conn.__dict__["inTransaction"] = 0
self.conn._Connection__closeCursors()
raise OperationalError, msg
except InternalError, msg:
***************
*** 3103,3113 ****
# action has been aborted. Try to recover to a sane state.
if self.conn.inTransaction:
_n = len(self.conn.notices)
! self.conn.conn.query('ROLLBACK WORK')
if len(self.conn.notices) != _n:
raise Warning, self.conn.notices.pop()
- self.conn.__dict__["inTransaction"] = 0
- self.conn._Connection__closeCursors()
raise OperationalError, msg
except InternalError, msg:
# An internal error occured. Try to get to a sane state.
--- 3174,3187 ----
# action has been aborted. Try to recover to a sane state.
if self.conn.inTransaction:
_n = len(self.conn.notices)
! if len(self.conn.savepoints) > 0:
! self.conn.conn.query('ROLLBACK TO SAVEPOINT %s' % self.conn.savepoints[-1])
! else:
! self.conn.conn.query('ROLLBACK WORK')
! self.conn.__dict__["inTransaction"] = 0
! self.conn._Connection__closeCursors()
if len(self.conn.notices) != _n:
raise Warning, self.conn.notices.pop()
raise OperationalError, msg
except InternalError, msg:
# An internal error occured. Try to get to a sane state.
--=_molabola.bugaboo.mu-24216-1160132174-0001-2
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
--=_molabola.bugaboo.mu-24216-1160132174-0001-2
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
Pypgsql-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/pypgsql-users
--=_molabola.bugaboo.mu-24216-1160132174-0001-2--