@@ -4541,6 +4541,7 @@ def from_timestamp(self, date_field):
45414541
45424542class _BasePsycopgAdapter (object ):
45434543 isolation_levels = {} # Map int -> str.
4544+ txn_idle = txn_inerror = txn_unknown = None # Driver constants.
45444545
45454546 def __init__ (self ):
45464547 self .isolation_levels_inv = {
@@ -4556,6 +4557,37 @@ def isolation_level_str(self, isolation_level):
45564557 return self .isolation_levels [isolation_level ]
45574558 return isolation_level
45584559
4560+ def is_connection_usable (self , conn ):
4561+ return self .txn_status (conn ) < self .txn_inerror
4562+
4563+ def is_connection_reusable (self , conn ):
4564+ # If the status is unknown then we lost the connection to the server
4565+ # and the connection should not be re-used.
4566+ status = self .txn_status (conn )
4567+ if status == self .txn_unknown :
4568+ return False
4569+ elif status != self .txn_idle :
4570+ try :
4571+ self .rollback (conn )
4572+ except Exception :
4573+ return False
4574+ return True
4575+
4576+ def is_connection_closed (self , conn ):
4577+ status = self .txn_status (conn )
4578+ if status == self .txn_unknown :
4579+ return True
4580+ try :
4581+ if status != self .txn_idle :
4582+ self .rollback (conn )
4583+ else :
4584+ # status flag is local, have to round trip.
4585+ conn .cursor ().execute ('SELECT 1' )
4586+ except Exception :
4587+ return True
4588+ return False
4589+
4590+
45594591class Psycopg2Adapter (_BasePsycopgAdapter ):
45604592 isolation_levels = {
45614593 1 : 'READ COMMITTED' ,
@@ -4564,6 +4596,11 @@ class Psycopg2Adapter(_BasePsycopgAdapter):
45644596 4 : 'READ UNCOMMITTED' ,
45654597 }
45664598
4599+ if psycopg2 is not None :
4600+ txn_idle = pg_extensions .TRANSACTION_STATUS_IDLE
4601+ txn_inerror = pg_extensions .TRANSACTION_STATUS_INERROR
4602+ txn_unknown = pg_extensions .TRANSACTION_STATUS_UNKNOWN
4603+
45674604 def __init__ (self ):
45684605 super (Psycopg2Adapter , self ).__init__ ()
45694606 self .json_type = Json_pg2
@@ -4594,44 +4631,17 @@ def connect(self, db, **params):
45944631 def get_server_version (self , conn ):
45954632 return conn .server_version
45964633
4597- def is_connection_usable (self , conn ):
4598- txn_status = conn .get_transaction_status ()
4599- return txn_status < pg_extensions .TRANSACTION_STATUS_INERROR
4634+ def txn_status (self , conn ):
4635+ return conn .get_transaction_status ()
46004636
4601- def is_connection_reusable (self , conn ):
4602- # If the status is unknown then we lost the connection to the server
4603- # and the connection should not be re-used.
4604- txn_status = conn .get_transaction_status ()
4605- if txn_status == pg_extensions .TRANSACTION_STATUS_UNKNOWN :
4606- return False
4607- elif txn_status != pg_extensions .TRANSACTION_STATUS_IDLE :
4608- # rollback() no-ops and reset() raises under autocommit, send a
4609- # raw ROLLBACK (clears both in-txn and error states).
4610- try :
4611- conn .cursor ().execute ('ROLLBACK' )
4612- except Exception :
4613- return False
4614- return True
4615-
4616- def is_connection_closed (self , conn ):
4617- txn_status = conn .get_transaction_status ()
4618- if txn_status == pg_extensions .TRANSACTION_STATUS_UNKNOWN :
4619- return True
4620- try :
4621- if txn_status != pg_extensions .TRANSACTION_STATUS_IDLE :
4622- # rollback() no-ops under autocommit, send a raw ROLLBACK.
4623- conn .cursor ().execute ('ROLLBACK' )
4624- else :
4625- # The status flag is local, only a round trip can detect a
4626- # server-side disconnect.
4627- conn .cursor ().execute ('SELECT 1' )
4628- except Exception :
4629- return True
4630- return False
4637+ def rollback (self , conn ):
4638+ # rollback() no-ops and reset() raises under autocommit, send a raw
4639+ # ROLLBACK (clears both in-txn and error states).
4640+ conn .cursor ().execute ('ROLLBACK' )
46314641
46324642 def server_side_cursor (self , conn ):
46334643 # psycopg2 does not allow named cursors in autocommit, even if we ARE
4634- # inside a transaction - so specify withhold (not desirable!).
4644+ # inside a transaction. Specify withhold (not desirable!).
46354645 return conn .cursor (name = str (uuid .uuid1 ()), withhold = True )
46364646
46374647
@@ -4642,6 +4652,10 @@ class Psycopg3Adapter(_BasePsycopgAdapter):
46424652 3 : 'REPEATABLE READ' ,
46434653 4 : 'SERIALIZABLE' ,
46444654 }
4655+ if psycopg is not None :
4656+ txn_idle = TransactionStatus .IDLE
4657+ txn_inerror = TransactionStatus .INERROR
4658+ txn_unknown = TransactionStatus .UNKNOWN
46454659
46464660 def __init__ (self ):
46474661 super (Psycopg3Adapter , self ).__init__ ()
@@ -4668,43 +4682,17 @@ def connect(self, db, **params):
46684682 def get_server_version (self , conn ):
46694683 return conn .pgconn .server_version
46704684
4671- def is_connection_usable (self , conn ):
4672- return conn .pgconn .transaction_status < TransactionStatus .INERROR
4673-
4674- def is_connection_reusable (self , conn ):
4675- # If the status is unknown then we lost the connection to the server
4676- # and the connection should not be re-used.
4677- txn_status = conn .pgconn .transaction_status
4678- if txn_status == TransactionStatus .UNKNOWN :
4679- return False
4680- elif txn_status != TransactionStatus .IDLE :
4681- # rollback() clears both in-txn and error states (psycopg3 has
4682- # no Connection.reset()).
4683- try :
4684- conn .rollback ()
4685- except Exception :
4686- return False
4687- return True
4685+ def txn_status (self , conn ):
4686+ return conn .pgconn .transaction_status
46884687
4689- def is_connection_closed (self , conn ):
4690- txn_status = conn .pgconn .transaction_status
4691- if txn_status == TransactionStatus .UNKNOWN :
4692- return True
4693- try :
4694- if txn_status != TransactionStatus .IDLE :
4695- conn .rollback ()
4696- else :
4697- # The status flag is local, only a round trip can detect a
4698- # server-side disconnect.
4699- conn .execute ('SELECT 1' )
4700- except Exception :
4701- return True
4702- return False
4688+ def rollback (self , conn ):
4689+ # rollback() clears both in-txn and error states.
4690+ conn .rollback ()
47034691
47044692 def server_side_cursor (self , conn ):
47054693 # In a transaction a plain named cursor streams and is scoped to it.
47064694 # Otherwise the server requires withhold, which spools at declare.
4707- in_txn = conn . pgconn . transaction_status == TransactionStatus .INTRANS
4695+ in_txn = self . txn_status ( conn ) == TransactionStatus .INTRANS
47084696 return conn .cursor (name = str (uuid .uuid1 ()), withhold = not in_txn )
47094697
47104698
0 commit comments