From: Daniele Varrazzo Date: Thu, 8 Dec 2022 14:35:55 +0000 (+0000) Subject: fix: add lookup of dumpers by varchar, name oid X-Git-Tag: 3.1.5~13^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=482f2608815dac6026644c58eddb412a471a0c4b;p=thirdparty%2Fpsycopg.git fix: add lookup of dumpers by varchar, name oid Fix #452 --- diff --git a/docs/news.rst b/docs/news.rst index d29de2da7..d5a99a1dd 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -17,6 +17,7 @@ Psycopg 3.1.5 (unreleased) (:ticket:`#422`). - Fix `Cursor.rownumber` to return `!None` when the result has no row to fetch (:ticket:`#437`). +- Fix `Copy.set_types()` used with `varchar` and `name` types (:ticket:`#452`). Current release diff --git a/psycopg/psycopg/types/string.py b/psycopg/psycopg/types/string.py index c15c3926a..cd5360dba 100644 --- a/psycopg/psycopg/types/string.py +++ b/psycopg/psycopg/types/string.py @@ -24,10 +24,14 @@ class _BaseStrDumper(Dumper): self._encoding = enc if enc != "ascii" else "utf-8" -class StrBinaryDumper(_BaseStrDumper): +class _StrBinaryDumper(_BaseStrDumper): + """ + Base class to dump a Python strings to a Postgres text type, in binary format. + + Subclasses shall specify the oids of real types (text, varchar, name...). + """ format = Format.BINARY - oid = postgres.types["text"].oid def dump(self, obj: str) -> bytes: # the server will raise DataError subclass if the string contains 0x00 @@ -35,6 +39,12 @@ class StrBinaryDumper(_BaseStrDumper): class _StrDumper(_BaseStrDumper): + """ + Base class to dump a Python strings to a Postgres text type, in text format. + + Subclasses shall specify the oids of real types (text, varchar, name...). + """ + def dump(self, obj: str) -> bytes: if "\x00" in obj: raise DataError("PostgreSQL text fields cannot contain NUL (0x00) bytes") @@ -42,6 +52,24 @@ class _StrDumper(_BaseStrDumper): return obj.encode(self._encoding) +# The next are concrete dumpers, each one specifying the oid they dump to. + + +class StrBinaryDumper(_StrBinaryDumper): + + oid = postgres.types["text"].oid + + +class StrBinaryDumperVarchar(_StrBinaryDumper): + + oid = postgres.types["varchar"].oid + + +class StrBinaryDumperName(_StrBinaryDumper): + + oid = postgres.types["name"].oid + + class StrDumper(_StrDumper): """ Dumper for strings in text format to the text oid. @@ -55,6 +83,16 @@ class StrDumper(_StrDumper): oid = postgres.types["text"].oid +class StrDumperVarchar(_StrDumper): + + oid = postgres.types["varchar"].oid + + +class StrDumperName(_StrDumper): + + oid = postgres.types["name"].oid + + class StrDumperUnknown(_StrDumper): """ Dumper for strings in text format to the unknown oid. @@ -62,7 +100,7 @@ class StrDumperUnknown(_StrDumper): This dumper is the default dumper for strings and allows to use Python strings to represent almost every data type. In a few places, however, the unknown oid is not accepted (for instance in variadic functions such as - 'concat()'). In that case either a cast on the placeholder ('%s::text) or + 'concat()'). In that case either a cast on the placeholder ('%s::text') or the StrTextDumper should be used. """ @@ -167,9 +205,13 @@ def register_default_adapters(context: AdaptContext) -> None: # registered becomes the default for each type. Usually, binary is the # default dumper. For text we use the text dumper as default because it # plays the role of unknown, and it can be cast automatically to other - # types. However, before that, we register a dumper with the text oid, - # which will be used when a text dumper is looked up by oid. + # types. However, before that, we register dumper with 'text', 'varchar', + # 'name' oids, which will be used when a text dumper is looked up by oid. + adapters.register_dumper(str, StrBinaryDumperName) + adapters.register_dumper(str, StrBinaryDumperVarchar) adapters.register_dumper(str, StrBinaryDumper) + adapters.register_dumper(str, StrDumperName) + adapters.register_dumper(str, StrDumperVarchar) adapters.register_dumper(str, StrDumper) adapters.register_dumper(str, StrDumperUnknown) diff --git a/psycopg_c/psycopg_c/types/string.pyx b/psycopg_c/psycopg_c/types/string.pyx index cae6a4b5f..da18b015a 100644 --- a/psycopg_c/psycopg_c/types/string.pyx +++ b/psycopg_c/psycopg_c/types/string.pyx @@ -68,13 +68,29 @@ cdef class _BaseStrDumper(CDumper): return size -@cython.final -cdef class StrBinaryDumper(_BaseStrDumper): +cdef class _StrBinaryDumper(_BaseStrDumper): format = PQ_BINARY + + +@cython.final +cdef class StrBinaryDumper(_StrBinaryDumper): + oid = oids.TEXT_OID +@cython.final +cdef class StrBinaryDumperVarchar(_StrBinaryDumper): + + oid = oids.VARCHAR_OID + + +@cython.final +cdef class StrBinaryDumperName(_StrBinaryDumper): + + oid = oids.NAME_OID + + cdef class _StrDumper(_BaseStrDumper): format = PQ_TEXT @@ -97,6 +113,18 @@ cdef class StrDumper(_StrDumper): oid = oids.TEXT_OID +@cython.final +cdef class StrDumperVarchar(_StrDumper): + + oid = oids.VARCHAR_OID + + +@cython.final +cdef class StrDumperName(_StrDumper): + + oid = oids.NAME_OID + + @cython.final cdef class StrDumperUnknown(_StrDumper): pass