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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions