19
19
from . import protocol
20
20
from . import serverversion
21
21
from . import transaction
22
+ from . import types
22
23
23
24
24
25
class Connection :
@@ -31,7 +32,8 @@ class Connection:
31
32
'_type_by_name_stmt' , '_top_xact' , '_uid' , '_aborted' ,
32
33
'_stmt_cache_max_size' , '_stmt_cache' , '_stmts_to_close' ,
33
34
'_addr' , '_opts' , '_command_timeout' , '_listeners' ,
34
- '_server_version' , '_intro_query' )
35
+ '_server_version' , '_server_caps' , '_intro_query' ,
36
+ '_reset_query' )
35
37
36
38
def __init__ (self , protocol , transport , loop , addr , opts , * ,
37
39
statement_cache_size , command_timeout ):
@@ -55,15 +57,21 @@ def __init__(self, protocol, transport, loop, addr, opts, *,
55
57
56
58
self ._listeners = {}
57
59
58
- ver_string = self ._protocol .get_settings ().server_version
60
+ settings = self ._protocol .get_settings ()
61
+ ver_string = settings .server_version
59
62
self ._server_version = \
60
63
serverversion .split_server_version_string (ver_string )
61
64
65
+ self ._server_caps = _detect_server_capabilities (
66
+ self ._server_version , settings )
67
+
62
68
if self ._server_version < (9 , 2 ):
63
69
self ._intro_query = introspection .INTRO_LOOKUP_TYPES_91
64
70
else :
65
71
self ._intro_query = introspection .INTRO_LOOKUP_TYPES
66
72
73
+ self ._reset_query = None
74
+
67
75
async def add_listener (self , channel , callback ):
68
76
"""Add a listener for Postgres notifications.
69
77
@@ -107,9 +115,26 @@ def get_server_version(self):
107
115
ServerVersion(major=9, minor=6, micro=1,
108
116
releaselevel='final', serial=0)
109
117
118
+ .. versionadded:: 0.8.0
110
119
"""
111
120
return self ._server_version
112
121
122
+ def get_server_capabilities (self ):
123
+ """Return the capabilities supported by the server as detected.
124
+
125
+ The returned value is a named tuple:
126
+
127
+ .. code-block:: pycon
128
+
129
+ >>> con.get_server_capabilities()
130
+ ServerCapabilities(advisory_locks=True, cursors=True,
131
+ notifications=True, plpgsql=True,
132
+ sql_reset=True)
133
+
134
+ .. versionadded:: 0.10.0
135
+ """
136
+ return self ._server_caps
137
+
113
138
def get_settings (self ):
114
139
"""Return connection settings.
115
140
@@ -394,22 +419,10 @@ def terminate(self):
394
419
self ._protocol .abort ()
395
420
396
421
async def reset (self ):
397
- self ._listeners = {}
398
-
399
- await self .execute ('''
400
- DO $$
401
- BEGIN
402
- PERFORM * FROM pg_listening_channels() LIMIT 1;
403
- IF FOUND THEN
404
- UNLISTEN *;
405
- END IF;
406
- END;
407
- $$;
408
- SET SESSION AUTHORIZATION DEFAULT;
409
- RESET ALL;
410
- CLOSE ALL;
411
- SELECT pg_advisory_unlock_all();
412
- ''' )
422
+ self ._listeners .clear ()
423
+ reset_query = self ._get_reset_query ()
424
+ if reset_query :
425
+ await self .execute (reset_query )
413
426
414
427
def _get_unique_id (self ):
415
428
self ._uid += 1
@@ -492,6 +505,35 @@ def _notify(self, pid, channel, payload):
492
505
'exception' : ex
493
506
})
494
507
508
+ def _get_reset_query (self ):
509
+ if self ._reset_query is not None :
510
+ return self ._reset_query
511
+
512
+ caps = self .get_server_capabilities ()
513
+
514
+ _reset_query = ''
515
+ if caps .advisory_locks :
516
+ _reset_query += 'SELECT pg_advisory_unlock_all();\n '
517
+ if caps .cursors :
518
+ _reset_query += 'CLOSE ALL;\n '
519
+ if caps .notifications and caps .plpgsql :
520
+ _reset_query += '''
521
+ DO $$
522
+ BEGIN
523
+ PERFORM * FROM pg_listening_channels() LIMIT 1;
524
+ IF FOUND THEN
525
+ UNLISTEN *;
526
+ END IF;
527
+ END;
528
+ $$;
529
+ '''
530
+ if caps .sql_reset :
531
+ _reset_query += 'RESET ALL;\n '
532
+
533
+ self ._reset_query = _reset_query
534
+
535
+ return _reset_query
536
+
495
537
496
538
async def connect (dsn = None , * ,
497
539
host = None , port = None ,
@@ -730,3 +772,20 @@ def _create_future(loop):
730
772
return asyncio .Future (loop = loop )
731
773
else :
732
774
return create_future ()
775
+
776
+
777
+ def _detect_server_capabilities (server_version , connection_settings ):
778
+ if hasattr (connection_settings , 'crdb_version' ):
779
+ # CocroachDB detected.
780
+ advisory_locks = cursors = notifications = plpgsql = sql_reset = False
781
+ else :
782
+ # Standard PostgreSQL server assumed.
783
+ advisory_locks = cursors = notifications = plpgsql = sql_reset = True
784
+
785
+ return types .ServerCapabilities (
786
+ advisory_locks = advisory_locks ,
787
+ cursors = cursors ,
788
+ notifications = notifications ,
789
+ plpgsql = plpgsql ,
790
+ sql_reset = sql_reset
791
+ )
0 commit comments