TransactionStatus,
Ping,
)
+from .pq_encodings import py_codecs
from . import _pq_ctypes as impl
return TransactionStatus(rv)
def parameter_status(self, name):
- rv = impl.PQparameterStatus(self.pgconn_ptr, self._encode(name))
- return self._decode(rv)
+ rv = impl.PQparameterStatus(
+ self.pgconn_ptr, self._encode(name, "utf8")
+ )
+ return self._decode(rv, "utf8")
@property
def protocol_version(self):
raise MemoryError("couldn't allocate PGresult")
return PGresult(rv)
- def _encode(self, s):
+ def _encode(self, s, py_enc=None):
if isinstance(s, bytes):
return s
elif isinstance(s, str):
- # TODO: encode in client encoding
- return s.encode("utf8")
+ if py_enc is None:
+ pg_enc = self.parameter_status("client_encoding")
+ py_enc = py_codecs[pg_enc]
+ if py_enc is None:
+ raise PQerror(
+ f"PostgreSQL encoding {pg_enc} doesn't have a Python codec."
+ f" Please use bytes instead of str"
+ )
+ return s.encode(py_enc)
else:
raise TypeError(f"expected bytes or str, got {s!r} instead")
- def _decode(self, b):
+ def _decode(self, b, py_enc=None):
if b is None:
return None
- # TODO: decode in client encoding
- return b.decode("utf8", "replace")
+
+ if py_enc is None:
+ pg_enc = self.parameter_status("client_encoding")
+ py_enc = py_codecs[pg_enc]
+
+ if py_enc is not None:
+ return b.decode(py_enc)
+ else:
+ # pretty much a punt, but this is only for communication, no data
+ return b.decode("utf8", "replace")
class PGresult:
--- /dev/null
+py_codecs = {
+ "BIG5": "big5",
+ "EUC_CN": "gb2312",
+ "EUC_JIS_2004": "euc_jis_2004",
+ "EUC_JP": "euc_jp",
+ "EUC_KR": "euc_kr",
+ "EUC_TW": None, # not available in Python
+ "GB18030": "gb18030",
+ "GBK": "gbk",
+ "ISO_8859_5": "iso8859-5",
+ "ISO_8859_6": "iso8859-6",
+ "ISO_8859_7": "iso8859-7",
+ "ISO_8859_8": "iso8859-8",
+ "JOHAB": "johab",
+ "KOI8R": "koi8-r",
+ "KOI8U": "koi8-u",
+ "LATIN1": "iso8859-1",
+ "LATIN10": "iso8859-16",
+ "LATIN2": "iso8859-2",
+ "LATIN3": "iso8859-3",
+ "LATIN4": "iso8859-4",
+ "LATIN5": "iso8859-9",
+ "LATIN6": "iso8859-10",
+ "LATIN7": "iso8859-13",
+ "LATIN8": "iso8859-14",
+ "LATIN9": "iso8859-15",
+ "MULE_INTERNAL": None, # not available in Python
+ "SHIFT_JIS_2004": "shift_jis_2004",
+ "SJIS": "shift_jis",
+ "SQL_ASCII": None, # means no encoding, see PostgreSQL docs
+ "UHC": "cp949",
+ "UTF8": "utf-8",
+ "WIN1250": "cp1250",
+ "WIN1251": "cp1251",
+ "WIN1252": "cp1252",
+ "WIN1253": "cp1253",
+ "WIN1254": "cp1254",
+ "WIN1255": "cp1255",
+ "WIN1256": "cp1256",
+ "WIN1257": "cp1257",
+ "WIN1258": "cp1258",
+ "WIN866": "cp866",
+ "WIN874": "cp874",
+}
def test_exec_command(pq, pgconn):
res = pgconn.exec_("set timezone to utc")
assert res.status == pq.ExecStatus.PGRES_COMMAND_OK
+
+
+def test_exec_error(pq, pgconn):
+ res = pgconn.exec_("wat")
+ assert res.status == pq.ExecStatus.PGRES_FATAL_ERROR
assert pgconn.parameter_status("wat") is None
+def test_encoding(pq, pgconn):
+ res = pgconn.exec_("set client_encoding to latin1")
+ assert res.status == pq.ExecStatus.PGRES_COMMAND_OK
+ assert pgconn.parameter_status("client_encoding") == "LATIN1"
+
+ res = pgconn.exec_("set client_encoding to 'utf-8'")
+ assert res.status == pq.ExecStatus.PGRES_COMMAND_OK
+ assert pgconn.parameter_status("client_encoding") == "UTF8"
+
+ res = pgconn.exec_("set client_encoding to wat")
+ assert res.status == pq.ExecStatus.PGRES_FATAL_ERROR
+ assert pgconn.parameter_status("client_encoding") == "UTF8"
+
+
def test_protocol_version(pgconn):
assert pgconn.protocol_version == 3
assert pgconn.server_version >= 90400
+def test_error_message(pq, pgconn):
+ res = pgconn.exec_("set client_encoding to latin9")
+ assert res.status == pq.ExecStatus.PGRES_COMMAND_OK
+ res = pgconn.exec_(b"set client_encoding to '\xa4'") # euro sign in latin9
+ msg = pgconn.error_message
+ assert isinstance(msg, str) # decoded
+ assert "\u20ac" in msg # decoded ok
+
+
def test_backend_pid(pgconn):
assert 2 <= pgconn.backend_pid <= 65535 # Unless increased in kernel?