]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Added PQconn.get_defaults() wrapping PQconndefault/PQconninfoFree
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 14 Mar 2020 04:44:08 +0000 (17:44 +1300)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 14 Mar 2020 04:44:08 +0000 (17:44 +1300)
psycopg3/_pq_ctypes.py
psycopg3/pq_ctypes.py
tests/test_pq.py

index 04b12e683ee493f20a24f985258fe08ae3e152a2..d2a0f188c3019619f7ae126fa63a9fcfaa16122e 100644 (file)
@@ -22,6 +22,18 @@ class PGconn_struct(Structure):
 PGconn_ptr = POINTER(PGconn_struct)
 
 
+class PQconninfoOption_struct(Structure):
+    _fields_ = [
+        ("keyword", c_char_p),
+        ("envvar", c_char_p),
+        ("compiled", c_char_p),
+        ("val", c_char_p),
+        ("label", c_char_p),
+        ("dispatcher", c_char_p),
+        ("dispsize", c_int),
+    ]
+
+
 # Function definitions as explained in PostgreSQL 12 documentation
 
 # 33.1. Database Connection Control Functions
@@ -45,6 +57,14 @@ PQconnectPoll = pq.PQconnectPoll
 PQconnectPoll.argtypes = [PGconn_ptr]
 PQconnectPoll.restype = c_int
 
+PQconndefaults = pq.PQconndefaults
+PQconndefaults.argtypes = []
+PQconndefaults.restype = POINTER(PQconninfoOption_struct)
+
+PQconninfoFree = pq.PQconninfoFree
+PQconninfoFree.argtypes = [POINTER(PQconninfoOption_struct)]
+PQconninfoFree.restype = None
+
 
 # 33.2. Connection Status Functions
 
index db1abbfac841fc66094a09c7cacc15f4b571ea5b..b85480b425ca36cd0bfe63bcd746ef5debe0a9c2 100644 (file)
@@ -8,8 +8,9 @@ implementation.
 
 # Copyright (C) 2020 The Psycopg Team
 
-from .pq_enums import ConnStatus, PostgresPollingStatus
+from collections import namedtuple
 
+from .pq_enums import ConnStatus, PostgresPollingStatus
 from . import _pq_ctypes as impl
 
 
@@ -45,6 +46,33 @@ class PGconn:
         rv = impl.PQconnectPoll(self.pgconn_ptr)
         return PostgresPollingStatus(rv)
 
+    @classmethod
+    def get_defaults(cls):
+        opts = impl.PQconndefaults()
+        if not opts:
+            raise MemoryError("couldn't allocate connection defaults")
+
+        def gets(opt, kw):
+            rv = getattr(opt, kw)
+            if rv is not None:
+                rv = rv.decode("utf8", "replace")
+            return rv
+
+        try:
+            rv = []
+            skws = "keyword envvar compiled val label dispatcher".split()
+            for opt in opts:
+                if not opt.keyword:
+                    break
+                d = {kw: gets(opt, kw) for kw in skws}
+                d["dispsize"] = opt.dispsize
+                rv.append(ConninfoOption(**d))
+
+        finally:
+            impl.PQconninfoFree(opts)
+
+        return rv
+
     @property
     def status(self):
         rv = impl.PQstatus(self.pgconn_ptr)
@@ -58,3 +86,8 @@ class PGconn:
     @property
     def socket(self):
         return impl.PQsocket(self.pgconn_ptr)
+
+
+ConninfoOption = namedtuple(
+    "ConninfoOption", "keyword envvar compiled val label dispatcher dispsize"
+)
index e6f3169a636ea0cd579a332d2140e0ae538fb0fe..539584a0754a2227725c494a3b7c289b99e23172 100644 (file)
@@ -58,3 +58,14 @@ def test_connect_async_bad(pq, dsn):
             assert False, rv
 
     assert conn.status == ConnStatus.CONNECTION_BAD
+
+
+def test_defaults(pq):
+    defs = pq.PGconn.get_defaults()
+    assert len(defs) > 20
+    port = [d for d in defs if d.keyword == "port"][0]
+    assert port.envvar == "PGPORT"
+    assert port.compiled == "5432"
+    assert port.label == "Database-Port"
+    assert port.dispatcher == ""
+    assert port.dispsize == 6