# Buggy code
async def set_type_codec(
    self, typename, *, schema="public", encoder, decoder, binary=None, format="text"
):
    """Set an encoder/decoder pair for the specified data type.

    :param typename:
        Name of the data type the codec is for.

    :param schema:
        Schema name of the data type the codec is for
        (defaults to ``'public'``)

    :param format:
        The type of the argument received by the *decoder* callback,
        and the type of the *encoder* callback return value.

        If *format* is ``'text'`` (the default), the exchange datum is a
        ``str`` instance containing valid text representation of the
        data type.

        If *format* is ``'binary'``, the exchange datum is a ``bytes``
        instance containing valid _binary_ representation of the
        data type.

        If *format* is ``'tuple'``, the exchange datum is a type-specific
        ``tuple`` of values.  The table below lists supported data
        types and their format for this mode.

        +-----------------+---------------------------------------------+
        |  Type           |                Tuple layout                 |
        +=================+=============================================+
        | ``interval``    | (``months``, ``days``, ``microseconds``)    |
        +-----------------+---------------------------------------------+
        | ``date``        | (``date ordinal relative to Jan 1 2000``,)  |
        |                 | ``-2^31`` for negative infinity timestamp   |
        |                 | ``2^31-1`` for positive infinity timestamp. |
        +-----------------+---------------------------------------------+
        | ``timestamp``   | (``microseconds relative to Jan 1 2000``,)  |
        |                 | ``-2^63`` for negative infinity timestamp   |
        |                 | ``2^63-1`` for positive infinity timestamp. |
        +-----------------+---------------------------------------------+
        | ``timestamp     | (``microseconds relative to Jan 1 2000      |
        | with time zone``| UTC``,)                                     |
        |                 | ``-2^63`` for negative infinity timestamp   |
        |                 | ``2^63-1`` for positive infinity timestamp. |
        +-----------------+---------------------------------------------+
        | ``time``        | (``microseconds``,)                         |
        +-----------------+---------------------------------------------+
        | ``time with     | (``microseconds``,                          |
        | time zone``     | ``time zone offset in seconds``)            |
        +-----------------+---------------------------------------------+

    :param encoder:
        Callable accepting a Python object as a single argument and
        returning a value encoded according to *format*.

    :param decoder:
        Callable accepting a single argument encoded according to *format*
        and returning a decoded Python object.

    :param binary:
        **Deprecated**.  Use *format* instead.

    Example:

    .. code-block:: pycon

        >>> import asyncpg
        >>> import asyncio
        >>> import datetime
        >>> from dateutil.relativedelta import relativedelta
        >>> async def run():
        ...     con = await asyncpg.connect(user='postgres')
        ...     def encoder(delta):
        ...         ndelta = delta.normalized()
        ...         return (ndelta.years * 12 + ndelta.months,
        ...                 ndelta.days,
        ...                 ((ndelta.hours * 3600 +
        ...                    ndelta.minutes * 60 +
        ...                    ndelta.seconds) * 1000000 +
        ...                  ndelta.microseconds))
        ...     def decoder(tup):
        ...         return relativedelta(months=tup[0], days=tup[1],
        ...                              microseconds=tup[2])
        ...     await con.set_type_codec(
        ...         'interval', schema='pg_catalog', encoder=encoder,
        ...         decoder=decoder, format='tuple')
        ...     result = await con.fetchval(
        ...         "SELECT '2 years 3 mons 1 day'::interval")
        ...     print(result)
        ...     print(datetime.datetime(2002, 1, 1) + result)
        >>> asyncio.get_event_loop().run_until_complete(run())
        relativedelta(years=+2, months=+3, days=+1)
        2004-04-02 00:00:00

    .. versionadded:: 0.12.0
        Added the ``format`` keyword argument and support for 'tuple'
        format.

    .. versionchanged:: 0.12.0
        The ``binary`` keyword argument is deprecated in favor of
        ``format``.

    """
    self._check_open()

    if binary is not None:
        format = "binary" if binary else "text"
        warnings.warn(
            "The `binary` keyword argument to "
            "set_type_codec() is deprecated and will be removed in "
            "asyncpg 0.13.0.  Use the `format` keyword argument instead.",
            DeprecationWarning,
            stacklevel=2,
        )

    if self._type_by_name_stmt is None:
        self._type_by_name_stmt = await self.prepare(introspection.TYPE_BY_NAME)

    typeinfo = await self._type_by_name_stmt.fetchrow(typename, schema)
    if not typeinfo:
        raise ValueError("unknown type: {}.{}".format(schema, typename))

    oid = typeinfo["oid"]
    if typeinfo["kind"] != b"b" or typeinfo["elemtype"]:
        raise ValueError(
            "cannot use custom codec on non-scalar type {}.{}".format(schema, typename)
        )

    self._protocol.get_settings().add_python_codec(
        oid, typename, schema, "scalar", encoder, decoder, format
    )

    # Statement cache is no longer valid due to codec changes.
    self._drop_local_statement_cache()


# Traceback (InvalidSQLStatementNameError)
In [1]: import os, asyncpg, asyncio

In [2]: loop = asyncio.get_event_loop()

In [3]: conn = loop.run_until_complete(asyncpg.connect(
...:     host = 'pgaas.mail.yandex.net',
...:     port = 12000,
...:     user = 'statinfra_api',
...:     database = 'statinfra_api_beta',
...:     password=os.environ['DB_PASSWORD'],
...:     ssl=True,
...:     statement_cache_size=0
...: ))

In [4]: loop.run_until_complete(conn.fetch('SELECT * FROM tasks'))
---------------------------------------------------------------------------
InvalidSQLStatementNameError              Traceback (most recent call last)
<ipython-input-5-8a44237acb87> in <module>()
----> 1 loop.run_until_complete(conn.fetch('SELECT * FROM tasks'))

/usr/lib/python3.6/asyncio/base_events.py in run_until_complete(self, future)
465             raise RuntimeError('Event loop stopped before Future completed.')
466
--> 467         return future.result()
468
469     def stop(self):

~/.virtualenvs/statbox-abt-backend/lib/python3.6/site-packages/asyncpg/connection.py in fetch(self, query, timeout, *args)
339         """
340         self._check_open()
--> 341         return await self._execute(query, args, 0, timeout)
342
343     async def fetchval(self, query, *args, column=0, timeout=None):

~/.virtualenvs/statbox-abt-backend/lib/python3.6/site-packages/asyncpg/connection.py in _execute(self, query, args, limit, timeout, return_status)
1186         timeout = self._protocol._get_timeout(timeout)
1187         with self._stmt_exclusive_section:
-> 1188             return await self._do_execute(query, executor, timeout)
1189
1190     async def _executemany(self, query, args, timeout):

~/.virtualenvs/statbox-abt-backend/lib/python3.6/site-packages/asyncpg/connection.py in _do_execute(self, query, executor, timeout, retry)
1197     async def _do_execute(self, query, executor, timeout, retry=True):
1198         if timeout is None:
-> 1199             stmt = await self._get_statement(query, None)
1200         else:
1201             before = time.monotonic()

~/.virtualenvs/statbox-abt-backend/lib/python3.6/site-packages/asyncpg/connection.py in _get_statement(self, query, timeout, named)
290                 self._types_stmt = await self.prepare(self._intro_query)
291
--> 292             types = await self._types_stmt.fetch(list(ready))
293             self._protocol.get_settings().register_data_types(types)
294

~/.virtualenvs/statbox-abt-backend/lib/python3.6/site-packages/asyncpg/prepared_stmt.py in fetch(self, timeout, *args)
155         :return: A list of :class:`Record` instances.
156         """
--> 157         data = await self.__bind_execute(args, 0, timeout)
158         return data
159

~/.virtualenvs/statbox-abt-backend/lib/python3.6/site-packages/asyncpg/prepared_stmt.py in __bind_execute(self, args, limit, timeout)
194         protocol = self._connection._protocol
195         data, status, _ = await protocol.bind_execute(
--> 196             self._state, args, '', limit, True, timeout)
197         self._last_status = status
198         return data

~/.virtualenvs/statbox-abt-backend/lib/python3.6/site-packages/asyncpg/protocol/protocol.pyx in bind_execute (asyncpg/protocol/protocol.c:66799)()

InvalidSQLStatementNameError: prepared statement "__asyncpg_stmt_1__" does not exist

# Fixed code
async def set_type_codec(
    self, typename, *, schema="public", encoder, decoder, binary=None, format="text"
):
    """Set an encoder/decoder pair for the specified data type.

    :param typename:
        Name of the data type the codec is for.

    :param schema:
        Schema name of the data type the codec is for
        (defaults to ``'public'``)

    :param format:
        The type of the argument received by the *decoder* callback,
        and the type of the *encoder* callback return value.

        If *format* is ``'text'`` (the default), the exchange datum is a
        ``str`` instance containing valid text representation of the
        data type.

        If *format* is ``'binary'``, the exchange datum is a ``bytes``
        instance containing valid _binary_ representation of the
        data type.

        If *format* is ``'tuple'``, the exchange datum is a type-specific
        ``tuple`` of values.  The table below lists supported data
        types and their format for this mode.

        +-----------------+---------------------------------------------+
        |  Type           |                Tuple layout                 |
        +=================+=============================================+
        | ``interval``    | (``months``, ``days``, ``microseconds``)    |
        +-----------------+---------------------------------------------+
        | ``date``        | (``date ordinal relative to Jan 1 2000``,)  |
        |                 | ``-2^31`` for negative infinity timestamp   |
        |                 | ``2^31-1`` for positive infinity timestamp. |
        +-----------------+---------------------------------------------+
        | ``timestamp``   | (``microseconds relative to Jan 1 2000``,)  |
        |                 | ``-2^63`` for negative infinity timestamp   |
        |                 | ``2^63-1`` for positive infinity timestamp. |
        +-----------------+---------------------------------------------+
        | ``timestamp     | (``microseconds relative to Jan 1 2000      |
        | with time zone``| UTC``,)                                     |
        |                 | ``-2^63`` for negative infinity timestamp   |
        |                 | ``2^63-1`` for positive infinity timestamp. |
        +-----------------+---------------------------------------------+
        | ``time``        | (``microseconds``,)                         |
        +-----------------+---------------------------------------------+
        | ``time with     | (``microseconds``,                          |
        | time zone``     | ``time zone offset in seconds``)            |
        +-----------------+---------------------------------------------+

    :param encoder:
        Callable accepting a Python object as a single argument and
        returning a value encoded according to *format*.

    :param decoder:
        Callable accepting a single argument encoded according to *format*
        and returning a decoded Python object.

    :param binary:
        **Deprecated**.  Use *format* instead.

    Example:

    .. code-block:: pycon

        >>> import asyncpg
        >>> import asyncio
        >>> import datetime
        >>> from dateutil.relativedelta import relativedelta
        >>> async def run():
        ...     con = await asyncpg.connect(user='postgres')
        ...     def encoder(delta):
        ...         ndelta = delta.normalized()
        ...         return (ndelta.years * 12 + ndelta.months,
        ...                 ndelta.days,
        ...                 ((ndelta.hours * 3600 +
        ...                    ndelta.minutes * 60 +
        ...                    ndelta.seconds) * 1000000 +
        ...                  ndelta.microseconds))
        ...     def decoder(tup):
        ...         return relativedelta(months=tup[0], days=tup[1],
        ...                              microseconds=tup[2])
        ...     await con.set_type_codec(
        ...         'interval', schema='pg_catalog', encoder=encoder,
        ...         decoder=decoder, format='tuple')
        ...     result = await con.fetchval(
        ...         "SELECT '2 years 3 mons 1 day'::interval")
        ...     print(result)
        ...     print(datetime.datetime(2002, 1, 1) + result)
        >>> asyncio.get_event_loop().run_until_complete(run())
        relativedelta(years=+2, months=+3, days=+1)
        2004-04-02 00:00:00

    .. versionadded:: 0.12.0
        Added the ``format`` keyword argument and support for 'tuple'
        format.

    .. versionchanged:: 0.12.0
        The ``binary`` keyword argument is deprecated in favor of
        ``format``.

    """
    self._check_open()

    if binary is not None:
        format = "binary" if binary else "text"
        warnings.warn(
            "The `binary` keyword argument to "
            "set_type_codec() is deprecated and will be removed in "
            "asyncpg 0.13.0.  Use the `format` keyword argument instead.",
            DeprecationWarning,
            stacklevel=2,
        )

    typeinfo = await self.fetchrow(introspection.TYPE_BY_NAME, typename, schema)
    if not typeinfo:
        raise ValueError("unknown type: {}.{}".format(schema, typename))

    oid = typeinfo["oid"]
    if typeinfo["kind"] != b"b" or typeinfo["elemtype"]:
        raise ValueError(
            "cannot use custom codec on non-scalar type {}.{}".format(schema, typename)
        )

    self._protocol.get_settings().add_python_codec(
        oid, typename, schema, "scalar", encoder, decoder, format
    )

    # Statement cache is no longer valid due to codec changes.
    self._drop_local_statement_cache()