
    >|hj+                     p    d Z ddlmZ ddlmZ ddlmZ  G d de      Z	 G d d	e	      Z
e
Z G d
 d      Zy)a.
  SteadyPg - hardened classic PyGreSQL connections.

Implements steady connections to a PostgreSQL database
using the classic (not DB-API 2 compliant) PyGreSQL API.

The connections are transparently reopened when they are
closed or the database connection has been lost or when
they are used more often than an optional usage limit.
Only connections which have been marked as being in a database
transaction with a begin() call will not be silently replaced.

A typical situation where database connections are lost
is when the database server or an intervening firewall is
shutdown and restarted for maintenance reasons.  In such a
case, all database connections would become unusable, even
though the database service may be already available again.

The "hardened" connections provided by this module will
make the database connections immediately available again.

This results in a steady PostgreSQL connection that can be used
by PooledPg or PersistentPg to create pooled or persistent
connections to a PostgreSQL database in a threaded environment
such as the application server of "Webware for Python."
Note, however, that the connections themselves are not thread-safe.

For more information on PostgreSQL, see:
    https://www.postgresql.org/
For more information on PyGreSQL, see:
    http://www.pygresql.org
For more information on Webware for Python, see:
    https://webwareforpython.github.io/w4py/


Usage:

You can use the class SteadyPgConnection in the same way as you
would use the class DB from the classic PyGreSQL API module db.
The only difference is that you may specify a usage limit as the
first parameter when you open a connection (set it to None
if you prefer unlimited usage), and an optional list of commands
that may serve to prepare the session as the second parameter,
and you can specify whether is is allowed to close the connection
(by default this is true).  When the connection to the PostgreSQL
database is lost or has been used too often, it will be automatically
reset, without further notice.

    from dbutils.steady_pg import SteadyPgConnection
    db = SteadyPgConnection(10000, ["set datestyle to german"],
        host=..., dbname=..., user=..., ...)
    ...
    result = db.query('...')
    ...
    db.close()


Ideas for improvement:

* Alternatively to the maximum number of uses,
  implement a maximum time to live for connections.
* Optionally log usage and loss of connection.


Copyright, credits and license:

* Contributed as supplement for Webware for Python and PyGreSQL
  by Christoph Zwerschke in September 2005

Licensed under the MIT license.
    )suppress)DB   )__version__c                       e Zd ZdZy)SteadyPgErrorzGeneral SteadyPg error.N__name__
__module____qualname____doc__     P/var/www/html/test/engine/venv/lib/python3.12/site-packages/dbutils/steady_pg.pyr   r   O   s    !r   r   c                       e Zd ZdZy)InvalidConnectionErrorzDatabase connection is invalid.Nr	   r   r   r   r   r   S   s    )r   r   c                   z    e Zd ZdZeZ	 ddZd Zd Zd Z	d Z
d Zd	 Zd
 ZddZddZddZddZd Zd Zd Zy)SteadyPgConnectiona  Class representing steady connections to a PostgreSQL database.

    Underlying the connection is a classic PyGreSQL pg API database
    connection which is reset if the connection is lost or used too often.
    Thus the resulting connection is steadier ("tough and self-healing").

    If you want the connection to be persistent in a threaded environment,
    then you should not deal with this class directly, but use either the
    PooledPg module or the PersistentPg module to get the connections.
    Nc                     d| _         d| _        |d}t        |t              st	        d      || _        || _        || _        t        |i || _         d| _	        d| _        | j                          d| _        y)a  Create a "tough" PostgreSQL connection.

        A hardened version of the DB wrapper class of PyGreSQL.

        maxusage: maximum usage limit for the underlying PyGreSQL connection
            (number of uses, 0 or None means unlimited usage)
            When this limit is reached, the connection is automatically reset.
        setsession: optional list of SQL commands that may serve to prepare
            the session, e.g. ["set datestyle to ...", "set time zone ..."]
        closeable: if this is set to false, then closing the connection will
            be silently ignored, but by default the connection can be closed
        args, kwargs: the parameters that shall be used to establish
            the PostgreSQL connections with PyGreSQL using pg.DB()
        NTr   z$'maxusage' must be an integer value.F)_con_closed
isinstanceint	TypeError	_maxusage_setsession_sql
_closeablePgConnection_transaction_setsession_usage)selfmaxusage
setsession	closeableargskwargss         r   __init__zSteadyPgConnection.__init__i   s|    $ 	H(C(BCC!)# $1&1	!r   c                 &    | j                          | S )z9Enter the runtime context. This will start a transaction.)beginr"   s    r   	__enter__zSteadyPgConnection.__enter__   s    

r   c                 d    |d   |d   |d   | j                          y| j                          y)z8Exit the runtime context. This will end the transaction.r   Nr      )commitrollback)r"   excs     r   __exit__zSteadyPgConnection.__exit__   s-    q6>c!fnQKKMMMOr   c                 v    | j                   r-| j                   D ]  }| j                  j                  |        yy)z1Execute the SQL commands for session preparation.N)r   r   query)r"   sqls     r   r    zSteadyPgConnection._setsession   s5    ++ %		$%  r   c                     | j                   sAt        t              5  | j                  j	                          ddd       d| _        d| _         yy# 1 sw Y   xY w)zClose the tough connection.

        You can always close a tough connection with this method,
        and it will not complain if you close it more than once.
        NFT)r   r   	Exceptionr   closer   r+   s    r   _closezSteadyPgConnection._close   sJ     ||)$ "		!" %DDL	 " "s   AAc                 x    | j                   r| j                          y| j                  r| j                          yy)a^  Close the tough connection.

        You are allowed to close a tough connection by default,
        and it will not complain if you close it more than once.

        You can disallow closing connections by setting
        the closeable parameter to something false.  In this case,
        closing tough connections will be silently ignored.
        N)r   r9   r   resetr+   s    r   r8   zSteadyPgConnection.close   s+     ??KKMJJL r   c                 L   	 | j                   j                          d| _        d| _        | j	                          d| _        y# t        $ rX | j                  rId| _        t        t              5  | j                   j                  d       ddd       Y y# 1 sw Y   Y yxY wY yw xY w)ziReopen the tough connection.

        It will not complain if the connection cannot be reopened.
        Fr   r0   N)	r   reopenr   r   r    r!   r7   r   r4   r+   s    r   r=   zSteadyPgConnection.reopen   s    
	II !&D DLDK  	0  $)!i( 0IIOOJ/0 0 0 !	0s/   A +B#-B	B#B	B#B#"B#c                 F   	 | j                   j                          d| _        | j                          d| _        y# t
        $ r\ 	 | j                          Y y# t
        $ r< t        t
              5  | j                          ddd       n# 1 sw Y   nxY wY Y yY Y yw xY ww xY w)zReset the tough connection.

        If a reset is not possible, tries to reopen the connection.
        It will not complain if the connection is already closed.
        Fr   N)	r   r;   r   r    r!   r7   r=   r   r0   r+   s    r   r;   zSteadyPgConnection.reset   s    
	$IIOO %DDK 	$$ $i( $MMO$ $ $ $$	$sE   8; 	B AB/B	 	B	BBB B BB c                     d| _         	 | j                  j                  }|r	 ||      S  |       S # t        $ r" | j                  j	                  |xs d      cY S w xY w)zBegin a transaction.Tr5   r*   )r   r   r*   AttributeErrorr4   )r"   r5   r*   s      r   r*   zSteadyPgConnection.begin   sY     	6IIOOE
 &)5S>5eg5	  	399??3>'22	3   1 (AAc                     d| _         	 | j                  j                  }|r	 ||      S  |       S # t        $ r" | j                  j	                  |xs d      cY S w xY w)Commit the current transaction.Fr@   end)r   r   rE   rA   r4   )r"   r5   rE   s      r   rE   zSteadyPgConnection.end   sY    !	2))--C $'33<1CE1  	199??3<%00	1rB   c                     d| _         	 | j                  j                  }|r	 ||      S  |       S # t        $ r" | j                  j	                  |xs d      cY S w xY w)rD   Fr@   r/   )r   r   r/   rA   r4   )r"   r5   r/   s      r   r/   zSteadyPgConnection.commit   s[    !	8YY%%F '*6c?7vx7  	499??3?(33	4rB   c                     d| _         	 | j                  j                  }|r	 ||      S  |       S # t        $ r" | j                  j	                  |xs d      cY S w xY w)z!Rollback the current transaction.Fr@   r0   )r   r   r0   rA   r4   )r"   r5   r0   s      r   r0   zSteadyPgConnection.rollback   s]    !	<yy))H ),8$;;  	699??3#4*55	6rB   c                       fd}|S )a  Return a "tough" version of a connection class method.

        The tough version checks whether the connection is bad (lost)
        and automatically and transparently tries to reset the connection
        if this is the case (for instance, the database has been restarted).
        c                     j                   }|sL	 j                  j                  j                  r%j                  rj
                  j                  k\  rt        	  | i |}xj
                  dz  c_        |S # t        $ r j                          Y ;w xY w# t        $ rF |rd_          j                  j                  j                  r j                           | i |}Y w xY w)NFr   )	r   r   dbstatusr   r!   rA   r7   r;   )r&   r'   transactionresultmethodr"   s       r   tough_methodz:SteadyPgConnection._get_tough_method.<locals>.tough_method  s    ++K!  99<<.. NNt{{dnn/L,,	100 KK1KM ! !JJL!  1(-D%99<<&&

001s%   AA< B <BBAC*)C*r   )r"   rN   rO   s   `` r   _get_tough_methodz$SteadyPgConnection._get_tough_method  s    	. r   c                     | j                   r>t        | j                   |      }|dv s|j                  d      r| j                  |      }|S t        )zInherit the members of the standard connection class.

        Some methods are made "tougher" than in the standard version.
        )r4   getinsertupdatedeleteget_)r   getattr
startswithrP   r   )r"   nameattrs      r   __getattr__zSteadyPgConnection.__getattr__%  sK    
 99499d+DFFv.--d3K$$r   c                 4    	 | j                          y#  Y yxY w)zDelete the steady connection.N)r9   r+   s    r   __del__zSteadyPgConnection.__del__2  s    	KKM	s    )NNT)N)r
   r   r   r   r   versionr(   r,   r2   r    r9   r8   r=   r;   r*   rE   r/   r0   rP   r[   r]   r   r   r   r   r   [   sa    	 G =A D
%
 $$$	628<@%r   r   N)r   
contextlibr   pgr   r    r   r7   r   r   InvalidConnectionr   r   r   r   <module>rc      sC   EN   ! "I "*] *
 + ] ]r   