Skip to content

PostgreSQL "char" type (OID 18) cannot be decoded, and custom_decoders does not fix it #165

@Dev-iL

Description

@Dev-iL

Summary

Querying any column of PostgreSQL's internal "char" type (OID 18 — the single-byte character type used extensively in system catalogs) raises a RustToPyValueMappingError. The error message instructs users to use custom_decoders, but passing a decoder for this type to QueryResult.result() has no effect and the exception is still raised.

Environment

  • psqlpy: 0.11.12
  • Python: 3.14.3
  • PostgreSQL: 14.20

Reproduction

import asyncio
import psqlpy

pool = psqlpy.ConnectionPool(
    host="127.0.0.1", port=5432, username="postgres", password="...", db_name="postgres",
    max_db_pool_size=2,
)

async def main():
    async with pool.acquire() as conn:
        # "char" columns appear throughout system catalogs, e.g. pg_type:
        #   typtype, typcategory, typdelim, typalign, typstorage (all OID 18)
        result = await conn.execute(
            "SELECT typname, typtype FROM pg_type LIMIT 5"
        )

        # Attempt 1: call result() without custom_decoders
        # → RustToPyValueMappingError: Cannot convert char into Python type

        # Attempt 2: pass custom_decoders as instructed by the error message
        rows = result.result(
            custom_decoders={"char": lambda b: b.decode("utf-8")}
        )
        # → still raises RustToPyValueMappingError (decoder is never called)

asyncio.run(main())
pool.close()

Actual behaviour

psqlpy.exceptions.RustToPyValueMappingError: Can't convert value from driver to python type: Cannot convert char into Python type, please look at the custom_decoders functionality.

The exception is raised both with and without a custom_decoders entry. All key formats tried — "char", "18", 18, "bpchar", "character" — produce the same error, meaning the custom decoder dispatch never reaches user-supplied code for OID 18.

Expected behaviour

Either:

  1. "char" (OID 18) is decoded natively as a single-character Python str (this is what asyncpg, psycopg2, and psycopg3 all do), or
  2. custom_decoders actually dispatches to user code for this OID so the user can supply their own decoder.

Impact

Any query that touches PostgreSQL system catalogs (pg_type, pg_class, pg_attribute, pg_proc, …) will fail. The "char" type is extremely common in catalog tables — pg_type alone has five "char" columns (typtype, typcategory, typdelim, typalign, typstorage).

Notes

"char" (OID 18) is distinct from character(n) / varchar (OID 1042 / 1043). It is a fixed-width single-byte internal type and should map directly to a one-character Python str.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions