88PG-API
99======
1010
11- ``postgresql.api`` is a Python API to the PostgreSQL RDBMS . It is designed to take
11+ ``postgresql.api`` is a Python API to the PostgreSQL DBMS . It is designed to take
1212full advantage of PostgreSQL's features to provide the Python programmer with
1313substantial convenience.
1414
1515This module is used to define the PG-API. It creates a set of ABCs
1616that makes up the basic interfaces used to work with a PostgreSQL. PG-API is an
17- extension of the ``py-sqlapi`` ABCs .
17+ extension of ``py-database``'s database.api.sql APIs .
1818
1919The `InterfaceElement` is the common ABC, the methods and attributes defined
2020within that class can, should, be mostly ignored while extracting information.
@@ -75,15 +75,14 @@ class InterfaceElement(metaclass = ABCMeta):
7575
7676 <Python Traceback>
7777 postgresql.exceptions.Error: <message>
78- DRIVER: postgresql.driver.pq3
79- CONNECTOR: pq://user@localhost:5432/database
80- CONNECTION: <connection_title> <backend_id> <socket information>
81- <settings, transaction state, connection state>
82- QUERY: <query_title> <statement_id> <parameter info>
83- <query body>
8478 CURSOR: <cursor_id>
8579 <parameters>
86-
80+ QUERY: <statement_id> <parameter info>
81+ <query body>
82+ CONNECTION: <connection_title> <backend_id> <socket information>
83+ <settings, transaction state, connection state>
84+ CONNECTOR: pq://user@localhost:5432/database
85+ DRIVER: postgresql.driver.pq3
8786
8887 Receptors
8988 ---------
@@ -99,8 +98,8 @@ class InterfaceElement(metaclass = ABCMeta):
9998 -------
10099
101100 Many of these APIs are used to support features that users are *not*
102- expected to use. Almost everything on `InterfaceElement` is subject to
103- deprecation.
101+ expected to use directly . Almost everything on `InterfaceElement` is subject
102+ to deprecation.
104103 """
105104 ife_object_title = "<untitled>"
106105
@@ -566,7 +565,7 @@ def statement_id(self) -> str:
566565
567566 @propertydoc
568567 @abstractproperty
569- def string (self ) -> str :
568+ def string (self ) -> object :
570569 """
571570 The SQL string of the prepared statement.
572571
@@ -594,7 +593,7 @@ def __call__(self,
594593
595594 >>> p=db.prepare("SELECT column FROM ttable WHERE key = $1")
596595 >>> p('identifier')
597- <` Cursor` instance >
596+ <postgresql.api. Cursor>
598597 """
599598
600599 @abstractmethod
@@ -679,148 +678,193 @@ def __call__(self, *args, **kw) -> (object, Cursor, collections.Iterable):
679678 SRF returns a composite(OUT parameters), it *should* return a `Cursor`.
680679 """
681680
682- class TransactionManager (
683- InterfaceElement
684- ):
681+ ##
682+ # Arguably, it would be wiser to isolate blocks, prepared transactions, and
683+ # savepoints, but the utility of the separation is not significant. It's really
684+ # more interesting as a formality that the user may explicitly state the
685+ # type of the transaction. However, this capability is not completely absent
686+ # from the current interface as the configuration parameters, or lack thereof,
687+ # help imply the expectations.
688+ class Transaction (InterfaceElement ):
685689 """
686- A `TranactionManager ` is the `Connection`'s transaction manager .
687- `TransactionManager` compliant instances *must* exist on a `Connection`
688- instance's `xact` attribute .
690+ A `Tranaction ` is an element that represents a transaction in the session .
691+ Once created, it's ready to be started, and subsequently committed or
692+ rolled back .
689693
690- Normal usage would entail the use of the with-statement: :
694+ Read-only transaction :
691695
692- with db.xact:
693- ...
694-
695- Or, in cases where two-phase commit is desired::
696+ >>> with db.xact(mode = 'read only'):
697+ ... ...
696698
697- with db.xact(gid = 'gid'):
698- ...
699+ Read committed isolation:
700+
701+ >>> with db.xact(isolation = 'READ COMMITTED'):
702+ ... ...
703+
704+ Savepoints are created if inside a transaction block:
705+
706+ >>> with db.xact():
707+ ... with db.xact():
708+ ... ...
709+
710+ Or, in cases where two-phase commit is desired:
711+
712+ >>> with db.xact(gid = 'gid') as gxact:
713+ ... with gxact:
714+ ... # phase 1 block
715+ ... ...
716+ >>> # fully committed at this point
717+
718+ Considering that transactions decide what's saved and what's not saved, it is
719+ important that they are used properly. In most situations, when an action is
720+ performed where state of the transaction is unexpected, an exception should
721+ occur.
699722 """
700723 ife_label = 'XACT'
701724
702725 @propertydoc
703726 @abstractproperty
704- def failed (self ) -> (bool , None ):
727+ def mode (self ) -> (None , str ):
705728 """
706- bool stating if the current transaction has failed due to an error.
707- `None` if not in a transaction block.
729+ The mode of the transaction block:
730+
731+ START TRANSACTION [ISOLATION] <mode>;
732+
733+ The `mode` property is a string and will be directly interpolated into the
734+ START TRANSACTION statement.
708735 """
709736
710737 @propertydoc
711738 @abstractproperty
712- def depth (self ) -> int :
739+ def isolation (self ) -> ( None , str ) :
713740 """
714- `int` stating the current transaction depth.
741+ The isolation level of the transaction block:
715742
716- The depth starts at zero, indicating no transactions have been started.
717- For each call to `start`, this is incremented by one.
718- For each call to `abort` or `commit`, this is decremented by one.
743+ START TRANSACTION <isolation> [MODE];
719744
720- Implementation must protect against negative levels.
745+ The `isolation` property is a string and will be directly interpolated into
746+ the START TRANSACTION statement.
721747 """
722748
723- @abstractmethod
724- def start (self ) -> None :
725- """
726- Start a transaction block. If a transaction block has already been
727- started, make a savepoint.
728- ``start``, ``begin``, and ``__enter__`` are synonyms.
749+ @propertydoc
750+ @abstractproperty
751+ def gid (self ) -> (None , str ):
729752 """
730- __enter__ = begin = start
753+ The global identifier of the transaction block:
731754
732- def __context__ (self ):
733- return self
755+ PREPARE TRANSACTION <gid>;
756+
757+ The `gid` property is a string that indicates that the block is a prepared
758+ transaction.
759+ """
734760
735761 @abstractmethod
736- def __exit__ (self , typ , obj , tb ) :
762+ def start (self ) -> None :
737763 """
738- Commit the transaction, or abort if the given exception is not `None`.
739- If the transaction level is greater than one, then the savepoint
740- corresponding to the current level will be released or rolled back in
741- cases of an exception.
764+ Start the transaction.
765+
766+ If the database is in a transaction block, the transaction should be
767+ configured as a savepoint. If any transaction block configuration was
768+ applied to the transaction, raise a postgresql.exceptions.OperationError.
742769
743- If an exception was raised, then the return value must indicate the need
744- to further raise the exception, unless the exception is an
745- `postgresql.exceptions.AbortTransaction`. In which case, the transaction
746- will be rolled back accordingly, but the no exception will be raised.
770+ If the database is not in a transaction block, start one using the
771+ configuration where:
772+
773+ `self.isolation` specifies the ``ISOLATION LEVEL``. Normally, ``READ
774+ COMMITTED``, ``SERIALIZABLE``, or ``READ UNCOMMITTED``.
775+
776+ `self.mode` specifies the mode of the transaction. Normally, ``READ
777+ ONLY`` or ``READ WRITE``.
778+
779+ If the transaction is open, do nothing.
747780 """
781+ begin = start
748782
749783 @abstractmethod
750784 def commit (self ) -> None :
751785 """
752- Commit the transaction block, release a savepoint, or prepare the
753- transaction for commit. If the number of running transactions is greater
754- than one, then the corresponding savepoint is released. If no savepoints
755- are set and the transaction is configured with a 'gid', then the
756- transaction is prepared instead of committed, otherwise the transaction
757- is simply committed.
758- """
786+ Commit the transaction.
759787
760- @abstractmethod
761- def rollback (self ) -> None :
762- """
763- Abort the current transaction or rollback to the last started savepoint.
764- `rollback` and `abort` are synonyms.
788+ If the transaction is configured with a `gid` and it has not been
789+ prepared, issue a PREPARE TRANSACTION statement with the configured `gid`.
790+
791+ If the transaction is configured with a `gid` and has already been
792+ prepared, issue a COMMIT PREPARED statement with the configured `gid`.
793+
794+ If the transaction was started inside a transaction block, it should be
795+ identified as a savepoint, and the savepoint should be released.
796+
797+ If the transaction has already been committed, do nothing.
765798 """
766- abort = rollback
767799
768800 @abstractmethod
769- def __call__ (self , gid = None , isolation = None , read_only = None ) :
801+ def rollback (self ) -> None :
770802 """
771- Initialize the transaction using parameters and return self to support a
772- convenient with-statement syntax.
803+ Abort the transaction.
773804
774- The configuration only applies to transaction blocks as savepoints have
775- no parameters to be configured.
805+ If the transaction is configured with a `gid` *and* has been prepared, issue
806+ a ROLLBACK PREPARE statement with the configured `gid` .
776807
777- If the `gid`, the first keyword parameter, is configured, the
778- transaction manager will issue a ``PREPARE TRANSACTION`` with the
779- specified identifier instead of a ``COMMIT``.
808+ If the transaction is a savepoint, ROLLBACK TO the savepoint identifier.
780809
781- If `isolation` is specified, the ``START TRANSACTION`` will include it
782- as the ``ISOLATION LEVEL``. This must be a character string.
810+ If the transaction is a transaction block, issue an ABORT.
783811
784- If the `read_only` parameter is specified, the transaction block will be
785- started in the ``READ ONLY`` mode if True, and ``READ WRITE`` mode if
786- False. If `None`, neither ``READ ONLY`` or ``READ WRITE`` will be
787- specified.
788-
789- Read-only transaction::
812+ If the transaction has already been aborted, do nothing.
813+ """
814+ abort = rollback
790815
791- >>> with db.xact(read_only = True):
792- ...
816+ @abstractmethod
817+ def recover (self ) -> None :
818+ """
819+ If the transaction is assigned a `gid`, recover may be used to identify
820+ the transaction as prepared and ready for committing or aborting.
793821
794- Read committed isolation::
822+ This method is used in recovery procedures where a prepared transaction
823+ needs to be committed or rolled back.
795824
796- >>> with pg_con.xact(isolation = 'READ COMMITTED'):
797- ...
825+ If no prepared transaction with the configured `gid` exists, a
826+ `postgresql.exceptions.UndefinedObjectError` must be raised.
827+ [This is consistent with the error raised by ROLLBACK/COMMIT PREPARED]
798828
799- Database configured defaults apply to all `TransactionManager`
800- operations.
829+ Once this method has been ran, it should identify the transaction as being
830+ prepared so that subsequent invocations to `commit` or `rollback` should
831+ cause the appropriate ROLLBACK PREPARED or COMMIT PREPARED statements to
832+ be executed.
801833 """
802834
803835 @abstractmethod
804- def commit_prepared (self , gid : str ) :
836+ def prepare (self ) -> None :
805837 """
806- Commit the prepared transaction with the given `gid`.
838+ Explicitly prepare the transaction with the configured `gid`.
839+ Commit will automatically call this method if the transaction has a
840+ configured `gid`, so it is primarily provided for isolating the
841+ functionality that will be used by `commit`.
807842 """
808843
809844 @abstractmethod
810- def rollback_prepared (self , * gids : str ):
845+ def __enter__ (self ):
811846 """
812- Rollback the prepared transactions with the given `gid` .
847+ Synonym for `start` returning self .
813848 """
814849
815- @propertydoc
816- @abstractproperty
817- def prepared (self ) -> "sequence of prepared transaction identifiers" :
850+ def __context__ (self ):
851+ 'Return self'
852+ return self
853+
854+ @abstractmethod
855+ def __exit__ (self , typ , obj , tb ):
818856 """
819- A sequence of available prepared transactions for the current user on
820- the current database. This is intended to be more relavent for the
821- current context than selecting the contents of ``pg_prepared_xacts``.
822- So, the view *must* be limited to those of the current database, and
823- those which the user can commit.
857+ If an exception is indicated by the parameters, run the transaction's
858+ `rollback` method iff the database is still available(not closed), and
859+ return a `False` value.
860+
861+ If an exception is not indicated, but the database's transaction state is
862+ in error, run the transaction's `rollback` method and raise a
863+ `postgresql.exceptions.InFailedTransactionError`. If the database is
864+ unavailable, the `rollback` method should cause a
865+ `postgresql.exceptions.ConnectionDoesNotExistError` exception to occur.
866+
867+ Otherwise, run the transaction's `commit` method.
824868 """
825869
826870class Settings (
@@ -994,9 +1038,14 @@ def client_port(self) -> (int, None):
9941038
9951039 @propertydoc
9961040 @abstractproperty
997- def xact (self ) -> TransactionManager :
1041+ def xact (self ,
1042+ gid : "global identifier to configure" = None ,
1043+ isolation : "ISOLATION LEVEL to use with the transaction" = None ,
1044+ mode : "Mode of the transaction, READ ONLY or READ WRITE" = None ,
1045+ ) -> Transaction :
9981046 """
999- A `TransactionManager` instance bound to the `Database`.
1047+ Create a `Transaction` object using the given keyword arguments as its
1048+ configuration.
10001049 """
10011050
10021051 @propertydoc
@@ -1091,14 +1140,12 @@ def reset(self) -> None:
10911140
10921141 Issues a ``RESET ALL`` to the database. If the database supports
10931142 removing temporary tables created in the session, then remove them.
1094- Reapply initial configuration settings such as path. If inside a
1095- transaction block when called, reset the transaction state using the
1096- `reset` method on the connection's transaction manager, `xact`.
1143+ Reapply initial configuration settings such as path.
10971144
10981145 The purpose behind this method is to provide a soft-reconnect method
10991146 that re-initializes the connection into its original state. One
11001147 obvious use of this would be in a connection pool where the connection
1101- is done being used .
1148+ is being recycled .
11021149 """
11031150
11041151class Connector (InterfaceElement ):
@@ -1120,7 +1167,6 @@ class Connector(InterfaceElement):
11201167 def Connection (self ) -> "`Connection`" :
11211168 """
11221169 The default `Connection` class that is used.
1123- This *should* be available on the type object.
11241170 """
11251171
11261172 @propertydoc
0 commit comments