about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/asyncpg/protocol/codecs/base.pyx
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/asyncpg/protocol/codecs/base.pyx
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/asyncpg/protocol/codecs/base.pyx')
-rw-r--r--.venv/lib/python3.12/site-packages/asyncpg/protocol/codecs/base.pyx895
1 files changed, 895 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/asyncpg/protocol/codecs/base.pyx b/.venv/lib/python3.12/site-packages/asyncpg/protocol/codecs/base.pyx
new file mode 100644
index 00000000..c269e374
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/asyncpg/protocol/codecs/base.pyx
@@ -0,0 +1,895 @@
+# Copyright (C) 2016-present the asyncpg authors and contributors
+# <see AUTHORS file>
+#
+# This module is part of asyncpg and is released under
+# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
+
+
+from collections.abc import Mapping as MappingABC
+
+import asyncpg
+from asyncpg import exceptions
+
+
+cdef void* binary_codec_map[(MAXSUPPORTEDOID + 1) * 2]
+cdef void* text_codec_map[(MAXSUPPORTEDOID + 1) * 2]
+cdef dict EXTRA_CODECS = {}
+
+
+@cython.final
+cdef class Codec:
+
+    def __cinit__(self, uint32_t oid):
+        self.oid = oid
+        self.type = CODEC_UNDEFINED
+
+    cdef init(
+        self,
+        str name,
+        str schema,
+        str kind,
+        CodecType type,
+        ServerDataFormat format,
+        ClientExchangeFormat xformat,
+        encode_func c_encoder,
+        decode_func c_decoder,
+        Codec base_codec,
+        object py_encoder,
+        object py_decoder,
+        Codec element_codec,
+        tuple element_type_oids,
+        object element_names,
+        list element_codecs,
+        Py_UCS4 element_delimiter,
+    ):
+
+        self.name = name
+        self.schema = schema
+        self.kind = kind
+        self.type = type
+        self.format = format
+        self.xformat = xformat
+        self.c_encoder = c_encoder
+        self.c_decoder = c_decoder
+        self.base_codec = base_codec
+        self.py_encoder = py_encoder
+        self.py_decoder = py_decoder
+        self.element_codec = element_codec
+        self.element_type_oids = element_type_oids
+        self.element_codecs = element_codecs
+        self.element_delimiter = element_delimiter
+        self.element_names = element_names
+
+        if base_codec is not None:
+            if c_encoder != NULL or c_decoder != NULL:
+                raise exceptions.InternalClientError(
+                    'base_codec is mutually exclusive with c_encoder/c_decoder'
+                )
+
+        if element_names is not None:
+            self.record_desc = record.ApgRecordDesc_New(
+                element_names, tuple(element_names))
+        else:
+            self.record_desc = None
+
+        if type == CODEC_C:
+            self.encoder = <codec_encode_func>&self.encode_scalar
+            self.decoder = <codec_decode_func>&self.decode_scalar
+        elif type == CODEC_ARRAY:
+            if format == PG_FORMAT_BINARY:
+                self.encoder = <codec_encode_func>&self.encode_array
+                self.decoder = <codec_decode_func>&self.decode_array
+            else:
+                self.encoder = <codec_encode_func>&self.encode_array_text
+                self.decoder = <codec_decode_func>&self.decode_array_text
+        elif type == CODEC_RANGE:
+            if format != PG_FORMAT_BINARY:
+                raise exceptions.UnsupportedClientFeatureError(
+                    'cannot decode type "{}"."{}": text encoding of '
+                    'range types is not supported'.format(schema, name))
+            self.encoder = <codec_encode_func>&self.encode_range
+            self.decoder = <codec_decode_func>&self.decode_range
+        elif type == CODEC_MULTIRANGE:
+            if format != PG_FORMAT_BINARY:
+                raise exceptions.UnsupportedClientFeatureError(
+                    'cannot decode type "{}"."{}": text encoding of '
+                    'range types is not supported'.format(schema, name))
+            self.encoder = <codec_encode_func>&self.encode_multirange
+            self.decoder = <codec_decode_func>&self.decode_multirange
+        elif type == CODEC_COMPOSITE:
+            if format != PG_FORMAT_BINARY:
+                raise exceptions.UnsupportedClientFeatureError(
+                    'cannot decode type "{}"."{}": text encoding of '
+                    'composite types is not supported'.format(schema, name))
+            self.encoder = <codec_encode_func>&self.encode_composite
+            self.decoder = <codec_decode_func>&self.decode_composite
+        elif type == CODEC_PY:
+            self.encoder = <codec_encode_func>&self.encode_in_python
+            self.decoder = <codec_decode_func>&self.decode_in_python
+        else:
+            raise exceptions.InternalClientError(
+                'unexpected codec type: {}'.format(type))
+
+    cdef Codec copy(self):
+        cdef Codec codec
+
+        codec = Codec(self.oid)
+        codec.init(self.name, self.schema, self.kind,
+                   self.type, self.format, self.xformat,
+                   self.c_encoder, self.c_decoder, self.base_codec,
+                   self.py_encoder, self.py_decoder,
+                   self.element_codec,
+                   self.element_type_oids, self.element_names,
+                   self.element_codecs, self.element_delimiter)
+
+        return codec
+
+    cdef encode_scalar(self, ConnectionSettings settings, WriteBuffer buf,
+                       object obj):
+        self.c_encoder(settings, buf, obj)
+
+    cdef encode_array(self, ConnectionSettings settings, WriteBuffer buf,
+                      object obj):
+        array_encode(settings, buf, obj, self.element_codec.oid,
+                     codec_encode_func_ex,
+                     <void*>(<cpython.PyObject>self.element_codec))
+
+    cdef encode_array_text(self, ConnectionSettings settings, WriteBuffer buf,
+                           object obj):
+        return textarray_encode(settings, buf, obj,
+                                codec_encode_func_ex,
+                                <void*>(<cpython.PyObject>self.element_codec),
+                                self.element_delimiter)
+
+    cdef encode_range(self, ConnectionSettings settings, WriteBuffer buf,
+                      object obj):
+        range_encode(settings, buf, obj, self.element_codec.oid,
+                     codec_encode_func_ex,
+                     <void*>(<cpython.PyObject>self.element_codec))
+
+    cdef encode_multirange(self, ConnectionSettings settings, WriteBuffer buf,
+                           object obj):
+        multirange_encode(settings, buf, obj, self.element_codec.oid,
+                          codec_encode_func_ex,
+                          <void*>(<cpython.PyObject>self.element_codec))
+
+    cdef encode_composite(self, ConnectionSettings settings, WriteBuffer buf,
+                          object obj):
+        cdef:
+            WriteBuffer elem_data
+            int i
+            list elem_codecs = self.element_codecs
+            ssize_t count
+            ssize_t composite_size
+            tuple rec
+
+        if isinstance(obj, MappingABC):
+            # Input is dict-like, form a tuple
+            composite_size = len(self.element_type_oids)
+            rec = cpython.PyTuple_New(composite_size)
+
+            for i in range(composite_size):
+                cpython.Py_INCREF(None)
+                cpython.PyTuple_SET_ITEM(rec, i, None)
+
+            for field in obj:
+                try:
+                    i = self.element_names[field]
+                except KeyError:
+                    raise ValueError(
+                        '{!r} is not a valid element of composite '
+                        'type {}'.format(field, self.name)) from None
+
+                item = obj[field]
+                cpython.Py_INCREF(item)
+                cpython.PyTuple_SET_ITEM(rec, i, item)
+
+            obj = rec
+
+        count = len(obj)
+        if count > _MAXINT32:
+            raise ValueError('too many elements in composite type record')
+
+        elem_data = WriteBuffer.new()
+        i = 0
+        for item in obj:
+            elem_data.write_int32(<int32_t>self.element_type_oids[i])
+            if item is None:
+                elem_data.write_int32(-1)
+            else:
+                (<Codec>elem_codecs[i]).encode(settings, elem_data, item)
+            i += 1
+
+        record_encode_frame(settings, buf, elem_data, <int32_t>count)
+
+    cdef encode_in_python(self, ConnectionSettings settings, WriteBuffer buf,
+                          object obj):
+        data = self.py_encoder(obj)
+        if self.xformat == PG_XFORMAT_OBJECT:
+            if self.format == PG_FORMAT_BINARY:
+                pgproto.bytea_encode(settings, buf, data)
+            elif self.format == PG_FORMAT_TEXT:
+                pgproto.text_encode(settings, buf, data)
+            else:
+                raise exceptions.InternalClientError(
+                    'unexpected data format: {}'.format(self.format))
+        elif self.xformat == PG_XFORMAT_TUPLE:
+            if self.base_codec is not None:
+                self.base_codec.encode(settings, buf, data)
+            else:
+                self.c_encoder(settings, buf, data)
+        else:
+            raise exceptions.InternalClientError(
+                'unexpected exchange format: {}'.format(self.xformat))
+
+    cdef encode(self, ConnectionSettings settings, WriteBuffer buf,
+                object obj):
+        return self.encoder(self, settings, buf, obj)
+
+    cdef decode_scalar(self, ConnectionSettings settings, FRBuffer *buf):
+        return self.c_decoder(settings, buf)
+
+    cdef decode_array(self, ConnectionSettings settings, FRBuffer *buf):
+        return array_decode(settings, buf, codec_decode_func_ex,
+                            <void*>(<cpython.PyObject>self.element_codec))
+
+    cdef decode_array_text(self, ConnectionSettings settings,
+                           FRBuffer *buf):
+        return textarray_decode(settings, buf, codec_decode_func_ex,
+                                <void*>(<cpython.PyObject>self.element_codec),
+                                self.element_delimiter)
+
+    cdef decode_range(self, ConnectionSettings settings, FRBuffer *buf):
+        return range_decode(settings, buf, codec_decode_func_ex,
+                            <void*>(<cpython.PyObject>self.element_codec))
+
+    cdef decode_multirange(self, ConnectionSettings settings, FRBuffer *buf):
+        return multirange_decode(settings, buf, codec_decode_func_ex,
+                                 <void*>(<cpython.PyObject>self.element_codec))
+
+    cdef decode_composite(self, ConnectionSettings settings,
+                          FRBuffer *buf):
+        cdef:
+            object result
+            ssize_t elem_count
+            ssize_t i
+            int32_t elem_len
+            uint32_t elem_typ
+            uint32_t received_elem_typ
+            Codec elem_codec
+            FRBuffer elem_buf
+
+        elem_count = <ssize_t><uint32_t>hton.unpack_int32(frb_read(buf, 4))
+        if elem_count != len(self.element_type_oids):
+            raise exceptions.OutdatedSchemaCacheError(
+                'unexpected number of attributes of composite type: '
+                '{}, expected {}'
+                    .format(
+                        elem_count,
+                        len(self.element_type_oids),
+                    ),
+                schema=self.schema,
+                data_type=self.name,
+            )
+        result = record.ApgRecord_New(asyncpg.Record, self.record_desc, elem_count)
+        for i in range(elem_count):
+            elem_typ = self.element_type_oids[i]
+            received_elem_typ = <uint32_t>hton.unpack_int32(frb_read(buf, 4))
+
+            if received_elem_typ != elem_typ:
+                raise exceptions.OutdatedSchemaCacheError(
+                    'unexpected data type of composite type attribute {}: '
+                    '{!r}, expected {!r}'
+                        .format(
+                            i,
+                            BUILTIN_TYPE_OID_MAP.get(
+                                received_elem_typ, received_elem_typ),
+                            BUILTIN_TYPE_OID_MAP.get(
+                                elem_typ, elem_typ)
+                        ),
+                    schema=self.schema,
+                    data_type=self.name,
+                    position=i,
+                )
+
+            elem_len = hton.unpack_int32(frb_read(buf, 4))
+            if elem_len == -1:
+                elem = None
+            else:
+                elem_codec = self.element_codecs[i]
+                elem = elem_codec.decode(
+                    settings, frb_slice_from(&elem_buf, buf, elem_len))
+
+            cpython.Py_INCREF(elem)
+            record.ApgRecord_SET_ITEM(result, i, elem)
+
+        return result
+
+    cdef decode_in_python(self, ConnectionSettings settings,
+                          FRBuffer *buf):
+        if self.xformat == PG_XFORMAT_OBJECT:
+            if self.format == PG_FORMAT_BINARY:
+                data = pgproto.bytea_decode(settings, buf)
+            elif self.format == PG_FORMAT_TEXT:
+                data = pgproto.text_decode(settings, buf)
+            else:
+                raise exceptions.InternalClientError(
+                    'unexpected data format: {}'.format(self.format))
+        elif self.xformat == PG_XFORMAT_TUPLE:
+            if self.base_codec is not None:
+                data = self.base_codec.decode(settings, buf)
+            else:
+                data = self.c_decoder(settings, buf)
+        else:
+            raise exceptions.InternalClientError(
+                'unexpected exchange format: {}'.format(self.xformat))
+
+        return self.py_decoder(data)
+
+    cdef inline decode(self, ConnectionSettings settings, FRBuffer *buf):
+        return self.decoder(self, settings, buf)
+
+    cdef inline has_encoder(self):
+        cdef Codec elem_codec
+
+        if self.c_encoder is not NULL or self.py_encoder is not None:
+            return True
+
+        elif (
+            self.type == CODEC_ARRAY
+            or self.type == CODEC_RANGE
+            or self.type == CODEC_MULTIRANGE
+        ):
+            return self.element_codec.has_encoder()
+
+        elif self.type == CODEC_COMPOSITE:
+            for elem_codec in self.element_codecs:
+                if not elem_codec.has_encoder():
+                    return False
+            return True
+
+        else:
+            return False
+
+    cdef has_decoder(self):
+        cdef Codec elem_codec
+
+        if self.c_decoder is not NULL or self.py_decoder is not None:
+            return True
+
+        elif (
+            self.type == CODEC_ARRAY
+            or self.type == CODEC_RANGE
+            or self.type == CODEC_MULTIRANGE
+        ):
+            return self.element_codec.has_decoder()
+
+        elif self.type == CODEC_COMPOSITE:
+            for elem_codec in self.element_codecs:
+                if not elem_codec.has_decoder():
+                    return False
+            return True
+
+        else:
+            return False
+
+    cdef is_binary(self):
+        return self.format == PG_FORMAT_BINARY
+
+    def __repr__(self):
+        return '<Codec oid={} elem_oid={} core={}>'.format(
+            self.oid,
+            'NA' if self.element_codec is None else self.element_codec.oid,
+            has_core_codec(self.oid))
+
+    @staticmethod
+    cdef Codec new_array_codec(uint32_t oid,
+                               str name,
+                               str schema,
+                               Codec element_codec,
+                               Py_UCS4 element_delimiter):
+        cdef Codec codec
+        codec = Codec(oid)
+        codec.init(name, schema, 'array', CODEC_ARRAY, element_codec.format,
+                   PG_XFORMAT_OBJECT, NULL, NULL, None, None, None,
+                   element_codec, None, None, None, element_delimiter)
+        return codec
+
+    @staticmethod
+    cdef Codec new_range_codec(uint32_t oid,
+                               str name,
+                               str schema,
+                               Codec element_codec):
+        cdef Codec codec
+        codec = Codec(oid)
+        codec.init(name, schema, 'range', CODEC_RANGE, element_codec.format,
+                   PG_XFORMAT_OBJECT, NULL, NULL, None, None, None,
+                   element_codec, None, None, None, 0)
+        return codec
+
+    @staticmethod
+    cdef Codec new_multirange_codec(uint32_t oid,
+                                    str name,
+                                    str schema,
+                                    Codec element_codec):
+        cdef Codec codec
+        codec = Codec(oid)
+        codec.init(name, schema, 'multirange', CODEC_MULTIRANGE,
+                   element_codec.format, PG_XFORMAT_OBJECT, NULL, NULL, None,
+                   None, None, element_codec, None, None, None, 0)
+        return codec
+
+    @staticmethod
+    cdef Codec new_composite_codec(uint32_t oid,
+                                   str name,
+                                   str schema,
+                                   ServerDataFormat format,
+                                   list element_codecs,
+                                   tuple element_type_oids,
+                                   object element_names):
+        cdef Codec codec
+        codec = Codec(oid)
+        codec.init(name, schema, 'composite', CODEC_COMPOSITE,
+                   format, PG_XFORMAT_OBJECT, NULL, NULL, None, None, None,
+                   None, element_type_oids, element_names, element_codecs, 0)
+        return codec
+
+    @staticmethod
+    cdef Codec new_python_codec(uint32_t oid,
+                                str name,
+                                str schema,
+                                str kind,
+                                object encoder,
+                                object decoder,
+                                encode_func c_encoder,
+                                decode_func c_decoder,
+                                Codec base_codec,
+                                ServerDataFormat format,
+                                ClientExchangeFormat xformat):
+        cdef Codec codec
+        codec = Codec(oid)
+        codec.init(name, schema, kind, CODEC_PY, format, xformat,
+                   c_encoder, c_decoder, base_codec, encoder, decoder,
+                   None, None, None, None, 0)
+        return codec
+
+
+# Encode callback for arrays
+cdef codec_encode_func_ex(ConnectionSettings settings, WriteBuffer buf,
+                          object obj, const void *arg):
+    return (<Codec>arg).encode(settings, buf, obj)
+
+
+# Decode callback for arrays
+cdef codec_decode_func_ex(ConnectionSettings settings, FRBuffer *buf,
+                          const void *arg):
+    return (<Codec>arg).decode(settings, buf)
+
+
+cdef uint32_t pylong_as_oid(val) except? 0xFFFFFFFFl:
+    cdef:
+        int64_t oid = 0
+        bint overflow = False
+
+    try:
+        oid = cpython.PyLong_AsLongLong(val)
+    except OverflowError:
+        overflow = True
+
+    if overflow or (oid < 0 or oid > UINT32_MAX):
+        raise OverflowError('OID value too large: {!r}'.format(val))
+
+    return <uint32_t>val
+
+
+cdef class DataCodecConfig:
+    def __init__(self, cache_key):
+        # Codec instance cache for derived types:
+        # composites, arrays, ranges, domains and their combinations.
+        self._derived_type_codecs = {}
+        # Codec instances set up by the user for the connection.
+        self._custom_type_codecs = {}
+
+    def add_types(self, types):
+        cdef:
+            Codec elem_codec
+            list comp_elem_codecs
+            ServerDataFormat format
+            ServerDataFormat elem_format
+            bint has_text_elements
+            Py_UCS4 elem_delim
+
+        for ti in types:
+            oid = ti['oid']
+
+            if self.get_codec(oid, PG_FORMAT_ANY) is not None:
+                continue
+
+            name = ti['name']
+            schema = ti['ns']
+            array_element_oid = ti['elemtype']
+            range_subtype_oid = ti['range_subtype']
+            if ti['attrtypoids']:
+                comp_type_attrs = tuple(ti['attrtypoids'])
+            else:
+                comp_type_attrs = None
+            base_type = ti['basetype']
+
+            if array_element_oid:
+                # Array type (note, there is no separate 'kind' for arrays)
+
+                # Canonicalize type name to "elemtype[]"
+                if name.startswith('_'):
+                    name = name[1:]
+                name = '{}[]'.format(name)
+
+                elem_codec = self.get_codec(array_element_oid, PG_FORMAT_ANY)
+                if elem_codec is None:
+                    elem_codec = self.declare_fallback_codec(
+                        array_element_oid, ti['elemtype_name'], schema)
+
+                elem_delim = <Py_UCS4>ti['elemdelim'][0]
+
+                self._derived_type_codecs[oid, elem_codec.format] = \
+                    Codec.new_array_codec(
+                        oid, name, schema, elem_codec, elem_delim)
+
+            elif ti['kind'] == b'c':
+                # Composite type
+
+                if not comp_type_attrs:
+                    raise exceptions.InternalClientError(
+                        f'type record missing field types for composite {oid}')
+
+                comp_elem_codecs = []
+                has_text_elements = False
+
+                for typoid in comp_type_attrs:
+                    elem_codec = self.get_codec(typoid, PG_FORMAT_ANY)
+                    if elem_codec is None:
+                        raise exceptions.InternalClientError(
+                            f'no codec for composite attribute type {typoid}')
+                    if elem_codec.format is PG_FORMAT_TEXT:
+                        has_text_elements = True
+                    comp_elem_codecs.append(elem_codec)
+
+                element_names = collections.OrderedDict()
+                for i, attrname in enumerate(ti['attrnames']):
+                    element_names[attrname] = i
+
+                # If at least one element is text-encoded, we must
+                # encode the whole composite as text.
+                if has_text_elements:
+                    elem_format = PG_FORMAT_TEXT
+                else:
+                    elem_format = PG_FORMAT_BINARY
+
+                self._derived_type_codecs[oid, elem_format] = \
+                    Codec.new_composite_codec(
+                        oid, name, schema, elem_format, comp_elem_codecs,
+                        comp_type_attrs, element_names)
+
+            elif ti['kind'] == b'd':
+                # Domain type
+
+                if not base_type:
+                    raise exceptions.InternalClientError(
+                        f'type record missing base type for domain {oid}')
+
+                elem_codec = self.get_codec(base_type, PG_FORMAT_ANY)
+                if elem_codec is None:
+                    elem_codec = self.declare_fallback_codec(
+                        base_type, ti['basetype_name'], schema)
+
+                self._derived_type_codecs[oid, elem_codec.format] = elem_codec
+
+            elif ti['kind'] == b'r':
+                # Range type
+
+                if not range_subtype_oid:
+                    raise exceptions.InternalClientError(
+                        f'type record missing base type for range {oid}')
+
+                elem_codec = self.get_codec(range_subtype_oid, PG_FORMAT_ANY)
+                if elem_codec is None:
+                    elem_codec = self.declare_fallback_codec(
+                        range_subtype_oid, ti['range_subtype_name'], schema)
+
+                self._derived_type_codecs[oid, elem_codec.format] = \
+                    Codec.new_range_codec(oid, name, schema, elem_codec)
+
+            elif ti['kind'] == b'm':
+                # Multirange type
+
+                if not range_subtype_oid:
+                    raise exceptions.InternalClientError(
+                        f'type record missing base type for multirange {oid}')
+
+                elem_codec = self.get_codec(range_subtype_oid, PG_FORMAT_ANY)
+                if elem_codec is None:
+                    elem_codec = self.declare_fallback_codec(
+                        range_subtype_oid, ti['range_subtype_name'], schema)
+
+                self._derived_type_codecs[oid, elem_codec.format] = \
+                    Codec.new_multirange_codec(oid, name, schema, elem_codec)
+
+            elif ti['kind'] == b'e':
+                # Enum types are essentially text
+                self._set_builtin_type_codec(oid, name, schema, 'scalar',
+                                             TEXTOID, PG_FORMAT_ANY)
+            else:
+                self.declare_fallback_codec(oid, name, schema)
+
+    def add_python_codec(self, typeoid, typename, typeschema, typekind,
+                         typeinfos, encoder, decoder, format, xformat):
+        cdef:
+            Codec core_codec = None
+            encode_func c_encoder = NULL
+            decode_func c_decoder = NULL
+            Codec base_codec = None
+            uint32_t oid = pylong_as_oid(typeoid)
+            bint codec_set = False
+
+        # Clear all previous overrides (this also clears type cache).
+        self.remove_python_codec(typeoid, typename, typeschema)
+
+        if typeinfos:
+            self.add_types(typeinfos)
+
+        if format == PG_FORMAT_ANY:
+            formats = (PG_FORMAT_TEXT, PG_FORMAT_BINARY)
+        else:
+            formats = (format,)
+
+        for fmt in formats:
+            if xformat == PG_XFORMAT_TUPLE:
+                if typekind == "scalar":
+                    core_codec = get_core_codec(oid, fmt, xformat)
+                    if core_codec is None:
+                        continue
+                    c_encoder = core_codec.c_encoder
+                    c_decoder = core_codec.c_decoder
+                elif typekind == "composite":
+                    base_codec = self.get_codec(oid, fmt)
+                    if base_codec is None:
+                        continue
+
+            self._custom_type_codecs[typeoid, fmt] = \
+                Codec.new_python_codec(oid, typename, typeschema, typekind,
+                                       encoder, decoder, c_encoder, c_decoder,
+                                       base_codec, fmt, xformat)
+            codec_set = True
+
+        if not codec_set:
+            raise exceptions.InterfaceError(
+                "{} type does not support the 'tuple' exchange format".format(
+                    typename))
+
+    def remove_python_codec(self, typeoid, typename, typeschema):
+        for fmt in (PG_FORMAT_BINARY, PG_FORMAT_TEXT):
+            self._custom_type_codecs.pop((typeoid, fmt), None)
+        self.clear_type_cache()
+
+    def _set_builtin_type_codec(self, typeoid, typename, typeschema, typekind,
+                                alias_to, format=PG_FORMAT_ANY):
+        cdef:
+            Codec codec
+            Codec target_codec
+            uint32_t oid = pylong_as_oid(typeoid)
+            uint32_t alias_oid = 0
+            bint codec_set = False
+
+        if format == PG_FORMAT_ANY:
+            formats = (PG_FORMAT_BINARY, PG_FORMAT_TEXT)
+        else:
+            formats = (format,)
+
+        if isinstance(alias_to, int):
+            alias_oid = pylong_as_oid(alias_to)
+        else:
+            alias_oid = BUILTIN_TYPE_NAME_MAP.get(alias_to, 0)
+
+        for format in formats:
+            if alias_oid != 0:
+                target_codec = self.get_codec(alias_oid, format)
+            else:
+                target_codec = get_extra_codec(alias_to, format)
+
+            if target_codec is None:
+                continue
+
+            codec = target_codec.copy()
+            codec.oid = typeoid
+            codec.name = typename
+            codec.schema = typeschema
+            codec.kind = typekind
+
+            self._custom_type_codecs[typeoid, format] = codec
+            codec_set = True
+
+        if not codec_set:
+            if format == PG_FORMAT_BINARY:
+                codec_str = 'binary'
+            elif format == PG_FORMAT_TEXT:
+                codec_str = 'text'
+            else:
+                codec_str = 'text or binary'
+
+            raise exceptions.InterfaceError(
+                f'cannot alias {typename} to {alias_to}: '
+                f'there is no {codec_str} codec for {alias_to}')
+
+    def set_builtin_type_codec(self, typeoid, typename, typeschema, typekind,
+                               alias_to, format=PG_FORMAT_ANY):
+        self._set_builtin_type_codec(typeoid, typename, typeschema, typekind,
+                                     alias_to, format)
+        self.clear_type_cache()
+
+    def clear_type_cache(self):
+        self._derived_type_codecs.clear()
+
+    def declare_fallback_codec(self, uint32_t oid, str name, str schema):
+        cdef Codec codec
+
+        if oid <= MAXBUILTINOID:
+            # This is a BKI type, for which asyncpg has no
+            # defined codec.  This should only happen for newly
+            # added builtin types, for which this version of
+            # asyncpg is lacking support.
+            #
+            raise exceptions.UnsupportedClientFeatureError(
+                f'unhandled standard data type {name!r} (OID {oid})')
+        else:
+            # This is a non-BKI type, and as such, has no
+            # stable OID, so no possibility of a builtin codec.
+            # In this case, fallback to text format.  Applications
+            # can avoid this by specifying a codec for this type
+            # using Connection.set_type_codec().
+            #
+            self._set_builtin_type_codec(oid, name, schema, 'scalar',
+                                         TEXTOID, PG_FORMAT_TEXT)
+
+            codec = self.get_codec(oid, PG_FORMAT_TEXT)
+
+        return codec
+
+    cdef inline Codec get_codec(self, uint32_t oid, ServerDataFormat format,
+                                bint ignore_custom_codec=False):
+        cdef Codec codec
+
+        if format == PG_FORMAT_ANY:
+            codec = self.get_codec(
+                oid, PG_FORMAT_BINARY, ignore_custom_codec)
+            if codec is None:
+                codec = self.get_codec(
+                    oid, PG_FORMAT_TEXT, ignore_custom_codec)
+            return codec
+        else:
+            if not ignore_custom_codec:
+                codec = self.get_custom_codec(oid, PG_FORMAT_ANY)
+                if codec is not None:
+                    if codec.format != format:
+                        # The codec for this OID has been overridden by
+                        # set_{builtin}_type_codec with a different format.
+                        # We must respect that and not return a core codec.
+                        return None
+                    else:
+                        return codec
+
+            codec = get_core_codec(oid, format)
+            if codec is not None:
+                return codec
+            else:
+                try:
+                    return self._derived_type_codecs[oid, format]
+                except KeyError:
+                    return None
+
+    cdef inline Codec get_custom_codec(
+        self,
+        uint32_t oid,
+        ServerDataFormat format
+    ):
+        cdef Codec codec
+
+        if format == PG_FORMAT_ANY:
+            codec = self.get_custom_codec(oid, PG_FORMAT_BINARY)
+            if codec is None:
+                codec = self.get_custom_codec(oid, PG_FORMAT_TEXT)
+        else:
+            codec = self._custom_type_codecs.get((oid, format))
+
+        return codec
+
+
+cdef inline Codec get_core_codec(
+        uint32_t oid, ServerDataFormat format,
+        ClientExchangeFormat xformat=PG_XFORMAT_OBJECT):
+    cdef:
+        void *ptr = NULL
+
+    if oid > MAXSUPPORTEDOID:
+        return None
+    if format == PG_FORMAT_BINARY:
+        ptr = binary_codec_map[oid * xformat]
+    elif format == PG_FORMAT_TEXT:
+        ptr = text_codec_map[oid * xformat]
+
+    if ptr is NULL:
+        return None
+    else:
+        return <Codec>ptr
+
+
+cdef inline Codec get_any_core_codec(
+        uint32_t oid, ServerDataFormat format,
+        ClientExchangeFormat xformat=PG_XFORMAT_OBJECT):
+    """A version of get_core_codec that accepts PG_FORMAT_ANY."""
+    cdef:
+        Codec codec
+
+    if format == PG_FORMAT_ANY:
+        codec = get_core_codec(oid, PG_FORMAT_BINARY, xformat)
+        if codec is None:
+            codec = get_core_codec(oid, PG_FORMAT_TEXT, xformat)
+    else:
+        codec = get_core_codec(oid, format, xformat)
+
+    return codec
+
+
+cdef inline int has_core_codec(uint32_t oid):
+    return binary_codec_map[oid] != NULL or text_codec_map[oid] != NULL
+
+
+cdef register_core_codec(uint32_t oid,
+                         encode_func encode,
+                         decode_func decode,
+                         ServerDataFormat format,
+                         ClientExchangeFormat xformat=PG_XFORMAT_OBJECT):
+
+    if oid > MAXSUPPORTEDOID:
+        raise exceptions.InternalClientError(
+            'cannot register core codec for OID {}: it is greater '
+            'than MAXSUPPORTEDOID ({})'.format(oid, MAXSUPPORTEDOID))
+
+    cdef:
+        Codec codec
+        str name
+        str kind
+
+    name = BUILTIN_TYPE_OID_MAP[oid]
+    kind = 'array' if oid in ARRAY_TYPES else 'scalar'
+
+    codec = Codec(oid)
+    codec.init(name, 'pg_catalog', kind, CODEC_C, format, xformat,
+               encode, decode, None, None, None, None, None, None, None, 0)
+    cpython.Py_INCREF(codec)  # immortalize
+
+    if format == PG_FORMAT_BINARY:
+        binary_codec_map[oid * xformat] = <void*>codec
+    elif format == PG_FORMAT_TEXT:
+        text_codec_map[oid * xformat] = <void*>codec
+    else:
+        raise exceptions.InternalClientError(
+            'invalid data format: {}'.format(format))
+
+
+cdef register_extra_codec(str name,
+                          encode_func encode,
+                          decode_func decode,
+                          ServerDataFormat format):
+    cdef:
+        Codec codec
+        str kind
+
+    kind = 'scalar'
+
+    codec = Codec(INVALIDOID)
+    codec.init(name, None, kind, CODEC_C, format, PG_XFORMAT_OBJECT,
+               encode, decode, None, None, None, None, None, None, None, 0)
+    EXTRA_CODECS[name, format] = codec
+
+
+cdef inline Codec get_extra_codec(str name, ServerDataFormat format):
+    return EXTRA_CODECS.get((name, format))