import ctypes
import ctypes.util
from ctypes import Structure, POINTER
-from ctypes import c_char_p, c_int
+from ctypes import c_char_p, c_int, c_void_p
pq = ctypes.pydll.LoadLibrary(ctypes.util.find_library("pq"))
PQconninfo.argtypes = [PGconn_ptr]
PQconninfo.restype = PQconninfoOption_ptr
+PQconninfoParse = pq.PQconninfoParse
+PQconninfoParse.argtypes = [c_char_p, POINTER(c_char_p)]
+PQconninfoParse.restype = PQconninfoOption_ptr
+
PQfinish = pq.PQfinish
PQfinish.argtypes = [PGconn_ptr]
PQfinish.restype = None
PQsocket = pq.PQsocket
PQsocket.argtypes = [PGconn_ptr]
PQsocket.restype = c_int
+
+
+# 33.11. Miscellaneous Functions
+
+PQfreemem = pq.PQfreemem
+PQfreemem.argtypes = [c_void_p]
+PQfreemem.restype = None
from . import pq_ctypes as pq_module
PGconn = pq_module.PGconn
+PQerror = pq_module.PQerror
-__all__ = ("ConnStatus", "PGconn")
+__all__ = ("ConnStatus", "PGconn", "PQerror")
# Copyright (C) 2020 The Psycopg Team
from collections import namedtuple
+from ctypes import c_char_p, pointer
from .pq_enums import ConnStatus, PostgresPollingStatus, PGPing
from . import _pq_ctypes as impl
def connect_start(cls, conninfo):
if isinstance(conninfo, str):
conninfo = conninfo.encode("utf8")
-
if not isinstance(conninfo, bytes):
raise TypeError("bytes expected, got %r instead" % conninfo)
finally:
impl.PQconninfoFree(opts)
+ @classmethod
+ def parse_conninfo(cls, conninfo):
+ if isinstance(conninfo, str):
+ conninfo = conninfo.encode("utf8")
+ if not isinstance(conninfo, bytes):
+ raise TypeError("bytes expected, got %r instead" % conninfo)
+
+ errmsg = c_char_p()
+ rv = impl.PQconninfoParse(conninfo, pointer(errmsg))
+ if not rv:
+ if not errmsg:
+ raise MemoryError("couldn't allocate on conninfo parse")
+ else:
+ exc = PQerror(errmsg.value.decode("utf8", "replace"))
+ impl.PQfreemem(errmsg)
+ raise exc
+
+ try:
+ return _conninfoopts_from_array(rv)
+ finally:
+ impl.PQconninfoFree(rv)
+
def reset(self):
impl.PQreset(self.pgconn_ptr)
def ping(self, conninfo):
if isinstance(conninfo, str):
conninfo = conninfo.encode("utf8")
+ if not isinstance(conninfo, bytes):
+ raise TypeError("bytes expected, got %r instead" % conninfo)
rv = impl.PQping(conninfo)
return PGPing(rv)
assert dbname.dispsize == 20
+def test_conninfo_parse(pq):
+ info = pq.PGconn.parse_conninfo(
+ "postgresql://host1:123,host2:456/somedb"
+ "?target_session_attrs=any&application_name=myapp"
+ )
+ info = {i.keyword: i.val for i in info if i.val is not None}
+ assert info["host"] == "host1,host2"
+ assert info["port"] == "123,456"
+ assert info["dbname"] == "somedb"
+ assert info["application_name"] == "myapp"
+
+
+def test_conninfo_parse_bad(pq):
+ with pytest.raises(pq.PQerror) as e:
+ pq.PGconn.parse_conninfo("bad_conninfo=")
+ assert "bad_conninfo" in str(e.value)
+
+
def test_reset(pq, dsn):
conn = pq.PGconn.connect(dsn)
assert conn.status == ConnStatus.CONNECTION_OK