dbapi.py
branchstable
changeset 5813 0b250d72fcfa
parent 5812 d970049d7cfd
child 5815 282194aa43f3
child 5859 3da3574fe397
equal deleted inserted replaced
5812:d970049d7cfd 5813:0b250d72fcfa
    18 """DB-API 2.0 compliant module
    18 """DB-API 2.0 compliant module
    19 
    19 
    20 Take a look at http://www.python.org/peps/pep-0249.html
    20 Take a look at http://www.python.org/peps/pep-0249.html
    21 
    21 
    22 (most parts of this document are reported here in docstrings)
    22 (most parts of this document are reported here in docstrings)
    23 
       
    24 """
    23 """
       
    24 
    25 __docformat__ = "restructuredtext en"
    25 __docformat__ = "restructuredtext en"
    26 
    26 
       
    27 from threading import currentThread
    27 from logging import getLogger
    28 from logging import getLogger
    28 from time import time, clock
    29 from time import time, clock
    29 from itertools import count
    30 from itertools import count
    30 from warnings import warn
    31 from warnings import warn
    31 from os.path import join
    32 from os.path import join
   401 
   402 
   402     def close(self):
   403     def close(self):
   403         """no effect"""
   404         """no effect"""
   404         pass
   405         pass
   405 
   406 
       
   407     def _txid(self):
       
   408         return self.connection._txid(self)
       
   409 
   406     def execute(self, rql, args=None, eid_key=None, build_descr=True):
   410     def execute(self, rql, args=None, eid_key=None, build_descr=True):
   407         """execute a rql query, return resulting rows and their description in
   411         """execute a rql query, return resulting rows and their description in
   408         a :class:`~cubicweb.rset.ResultSet` object
   412         a :class:`~cubicweb.rset.ResultSet` object
   409 
   413 
   410         * `rql` should be an Unicode string or a plain ASCII string, containing
   414         * `rql` should be an Unicode string or a plain ASCII string, containing
   436         """
   440         """
   437         if eid_key is not None:
   441         if eid_key is not None:
   438             warn('[3.8] eid_key is deprecated, you can safely remove this argument',
   442             warn('[3.8] eid_key is deprecated, you can safely remove this argument',
   439                  DeprecationWarning, stacklevel=2)
   443                  DeprecationWarning, stacklevel=2)
   440         # XXX use named argument for build_descr in case repo is < 3.8
   444         # XXX use named argument for build_descr in case repo is < 3.8
   441         rset = self._repo.execute(self._sessid, rql, args, build_descr=build_descr)
   445         rset = self._repo.execute(self._sessid, rql, args,
       
   446                                   build_descr=build_descr, txid=self._txid())
   442         rset.req = self.req
   447         rset.req = self.req
   443         return rset
   448         return rset
   444 
   449 
   445 
   450 
   446 class LogCursor(Cursor):
   451 class LogCursor(Cursor):
   490         if exc_type is None:
   495         if exc_type is None:
   491             self.commit()
   496             self.commit()
   492         else:
   497         else:
   493             self.rollback()
   498             self.rollback()
   494             return False #propagate the exception
   499             return False #propagate the exception
       
   500 
       
   501     def _txid(self, cursor=None): # XXX could now handle various isolation level!
       
   502         return currentThread().getName()
   495 
   503 
   496     def request(self):
   504     def request(self):
   497         return DBAPIRequest(self.vreg, DBAPISession(self))
   505         return DBAPIRequest(self.vreg, DBAPISession(self))
   498 
   506 
   499     def check(self):
   507     def check(self):
   626                 pass
   634                 pass
   627 
   635 
   628     def describe(self, eid):
   636     def describe(self, eid):
   629         if self._closed is not None:
   637         if self._closed is not None:
   630             raise ProgrammingError('Closed connection')
   638             raise ProgrammingError('Closed connection')
   631         return self._repo.describe(self.sessionid, eid)
   639         return self._repo.describe(self.sessionid, eid, txid=self._txid())
   632 
   640 
   633     def close(self):
   641     def close(self):
   634         """Close the connection now (rather than whenever __del__ is called).
   642         """Close the connection now (rather than whenever __del__ is called).
   635 
   643 
   636         The connection will be unusable from this point forward; an Error (or
   644         The connection will be unusable from this point forward; an Error (or
   639         connection.  Note that closing a connection without committing the
   647         connection.  Note that closing a connection without committing the
   640         changes first will cause an implicit rollback to be performed.
   648         changes first will cause an implicit rollback to be performed.
   641         """
   649         """
   642         if self._closed:
   650         if self._closed:
   643             raise ProgrammingError('Connection is already closed')
   651             raise ProgrammingError('Connection is already closed')
   644         self._repo.close(self.sessionid)
   652         self._repo.close(self.sessionid, txid=self._txid())
   645         del self._repo # necessary for proper garbage collection
   653         del self._repo # necessary for proper garbage collection
   646         self._closed = 1
   654         self._closed = 1
   647 
   655 
   648     def commit(self):
   656     def commit(self):
   649         """Commit pending transaction for this connection to the repository.
   657         """Commit pending transaction for this connection to the repository.
   653 
   661 
   654         If the transaction is undoable, a transaction id will be returned.
   662         If the transaction is undoable, a transaction id will be returned.
   655         """
   663         """
   656         if not self._closed is None:
   664         if not self._closed is None:
   657             raise ProgrammingError('Connection is already closed')
   665             raise ProgrammingError('Connection is already closed')
   658         return self._repo.commit(self.sessionid)
   666         return self._repo.commit(self.sessionid, txid=self._txid())
   659 
   667 
   660     def rollback(self):
   668     def rollback(self):
   661         """This method is optional since not all databases provide transaction
   669         """This method is optional since not all databases provide transaction
   662         support.
   670         support.
   663 
   671 
   666         a connection without committing the changes first will cause an implicit
   674         a connection without committing the changes first will cause an implicit
   667         rollback to be performed.
   675         rollback to be performed.
   668         """
   676         """
   669         if not self._closed is None:
   677         if not self._closed is None:
   670             raise ProgrammingError('Connection is already closed')
   678             raise ProgrammingError('Connection is already closed')
   671         self._repo.rollback(self.sessionid)
   679         self._repo.rollback(self.sessionid, txid=self._txid())
   672 
   680 
   673     def cursor(self, req=None):
   681     def cursor(self, req=None):
   674         """Return a new Cursor Object using the connection.
   682         """Return a new Cursor Object using the connection.
   675 
   683 
   676         On pyro connection, you should get cursor after calling if
   684         On pyro connection, you should get cursor after calling if
   707         * `public`: when additional filtering is provided, their are by default
   715         * `public`: when additional filtering is provided, their are by default
   708           only searched in 'public' actions, unless a `public` argument is given
   716           only searched in 'public' actions, unless a `public` argument is given
   709           and set to false.
   717           and set to false.
   710         """
   718         """
   711         txinfos = self._repo.undoable_transactions(self.sessionid, ueid,
   719         txinfos = self._repo.undoable_transactions(self.sessionid, ueid,
       
   720                                                    txid=self._txid(),
   712                                                    **actionfilters)
   721                                                    **actionfilters)
   713         if req is None:
   722         if req is None:
   714             req = self.request()
   723             req = self.request()
   715         for txinfo in txinfos:
   724         for txinfo in txinfos:
   716             txinfo.req = req
   725             txinfo.req = req
   721 
   730 
   722         raise `NoSuchTransaction` if not found or if session's user is not
   731         raise `NoSuchTransaction` if not found or if session's user is not
   723         allowed (eg not in managers group and the transaction doesn't belong to
   732         allowed (eg not in managers group and the transaction doesn't belong to
   724         him).
   733         him).
   725         """
   734         """
   726         txinfo = self._repo.transaction_info(self.sessionid, txuuid)
   735         txinfo = self._repo.transaction_info(self.sessionid, txuuid,
       
   736                                              txid=self._txid())
   727         if req is None:
   737         if req is None:
   728             req = self.request()
   738             req = self.request()
   729         txinfo.req = req
   739         txinfo.req = req
   730         return txinfo
   740         return txinfo
   731 
   741 
   737 
   747 
   738         raise `NoSuchTransaction` if the transaction is not found or if
   748         raise `NoSuchTransaction` if the transaction is not found or if
   739         session's user is not allowed (eg not in managers group and the
   749         session's user is not allowed (eg not in managers group and the
   740         transaction doesn't belong to him).
   750         transaction doesn't belong to him).
   741         """
   751         """
   742         return self._repo.transaction_actions(self.sessionid, txuuid, public)
   752         return self._repo.transaction_actions(self.sessionid, txuuid, public,
       
   753                                               txid=self._txid())
   743 
   754 
   744     def undo_transaction(self, txuuid):
   755     def undo_transaction(self, txuuid):
   745         """Undo the given transaction. Return potential restoration errors.
   756         """Undo the given transaction. Return potential restoration errors.
   746 
   757 
   747         raise `NoSuchTransaction` if not found or if session's user is not
   758         raise `NoSuchTransaction` if not found or if session's user is not
   748         allowed (eg not in managers group and the transaction doesn't belong to
   759         allowed (eg not in managers group and the transaction doesn't belong to
   749         him).
   760         him).
   750         """
   761         """
   751         return self._repo.undo_transaction(self.sessionid, txuuid)
   762         return self._repo.undo_transaction(self.sessionid, txuuid,
       
   763                                            txid=self._txid())