From: Daniele Varrazzo Date: Sun, 20 Mar 2022 15:02:12 +0000 (+0100) Subject: fix(composite): fix fetching composite info with invalid name or field names X-Git-Tag: 3.1~109^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=280a6a7f410c3c80d2034d053f5665c98d5437be;p=thirdparty%2Fpsycopg.git fix(composite): fix fetching composite info with invalid name or field names --- diff --git a/psycopg/psycopg/types/composite.py b/psycopg/psycopg/types/composite.py index 4174854b1..9093f66e8 100644 --- a/psycopg/psycopg/types/composite.py +++ b/psycopg/psycopg/types/composite.py @@ -17,6 +17,7 @@ from ..adapt import Transformer, PyFormat, RecursiveDumper, Loader from .._struct import pack_len, unpack_len from ..postgres import TEXT_OID from .._typeinfo import CompositeInfo as CompositeInfo # exported here +from .._encodings import _as_python_identifier _struct_oidlen = struct.Struct("!Ii") _pack_oidlen = cast(Callable[[int, int], bytes], _struct_oidlen.pack) @@ -240,7 +241,10 @@ def register_composite( info.register(context) if not factory: - factory = namedtuple(info.name, info.field_names) # type: ignore + factory = namedtuple( # type: ignore + _as_python_identifier(info.name), + [_as_python_identifier(n) for n in info.field_names], + ) adapters = context.adapters if context else postgres.adapters diff --git a/tests/types/test_composite.py b/tests/types/test_composite.py index a3f7d5284..aee61c8db 100644 --- a/tests/types/test_composite.py +++ b/tests/types/test_composite.py @@ -8,6 +8,8 @@ from psycopg.types.range import Range from psycopg.types.composite import CompositeInfo, register_composite from psycopg.types.composite import TupleDumper, TupleBinaryDumper +eur = "\u20ac" + tests_str = [ ("", ()), # Funnily enough there's no way to represent (None,) in Postgres @@ -324,3 +326,22 @@ def test_callable_dumper_not_registered(conn, testcomp): def test_no_info_error(conn): with pytest.raises(TypeError, match="composite"): register_composite(None, conn) # type: ignore[arg-type] + + +def test_invalid_fields_names(conn): + conn.execute("set client_encoding to utf8") + conn.execute( + f""" + create type "a-b" as ("c-d" text, "{eur}" int); + create type "-x-{eur}" as ("w-ww" "a-b", "0" int); + """ + ) + ab = CompositeInfo.fetch(conn, '"a-b"') + x = CompositeInfo.fetch(conn, f'"-x-{eur}"') + register_composite(ab, conn) + register_composite(x, conn) + obj = x.python_type(ab.python_type("foo", 10), 20) + conn.execute(f"""create table meh (wat "-x-{eur}")""") + conn.execute("insert into meh values (%s)", [obj]) + got = conn.execute("select wat from meh").fetchone()[0] + assert obj == got