Skip to content

Binary protocol transform failed in load_sequence for query returning both RecordArray and Record  #545

@exrok

Description

@exrok

Getting psycopg.ProgrammingError: cannot load sequence of 1 items: 2 loaders registered
when using the binary protocol with query returning both RecordArray and Record.

See minimal reproduction and error traceback logs included below.

Observations

  • Changing the query to either of the following resolves the problem:
    • SELECT ARRAY[ROW('e656b0f5-fa8e-4cbe-98db-525f9ab1cacc'::uuid, 32)]
    • SELECT ROW('abc')
  • The bug seems to exist in both psycopg_binary and the native python implementation.
  • The rust crate tokio-postgres doesn't have this issue using the binary protocol, with the same setup.
  • The problem only occurs with the binary protocol.

My hypothesis is that it is using the same type info from the first Record to parse the second Record.

Env

  • Python: v3.10
  • OS: Arch Linux
  • DB: Postgres 15.2
  • psycopg 3.1.8 both with and without binary extra
  • Don't know if it is used but I have libpq.so.5.15 on my system.

Minimal Reproduction

Running Postgres v15.2

docker run -d -p 5432:5432 --name testdb -e POSTGRES_PASSWORD=postgres postgres:15.2

Python script to trigger failure.

import psycopg

with psycopg.connect("host=localhost user=postgres password=postgres") as conn:
    conn.execute(
        "SELECT ARRAY[ROW('e656b0f5-fa8e-4cbe-98db-525f9ab1cacc'::uuid, 32)], ROW('abc')",
        binary=True,
    ).fetchall()

Error Traceback Logs

Traceback when using only psycopg[binary,pool] version 3.1.8
Traceback (most recent call last):
  File "/home/user/code/bug/src/repro.py", line 22, in <module>
    rows = cursor.fetchall()
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/cursor.py", line 851, in fetchall
    records = self._tx.load_rows(self._pos, self.pgresult.ntuples, self._make_row)
  File "psycopg_binary/_psycopg/transform.pyx", line 481, in psycopg_binary._psycopg.Transformer.load_rows
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/types/composite.py", line 159, in load
    return self._tx.load_sequence(
  File "psycopg_binary/_psycopg/transform.pyx", line 541, in psycopg_binary._psycopg.Transformer.load_sequence
  File "psycopg_binary/_psycopg/transform.pyx", line 551, in psycopg_binary._psycopg.Transformer.load_sequence
psycopg.ProgrammingError: cannot load sequence of 1 items: 2 loaders registered
Traceback when using only psycopg[pool] version 3.1.8
Traceback (most recent call last):
  File "/home/user/code/bug/src/repro.py", line 22, in <module>
    rows = cursor.fetchall()
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/cursor.py", line 851, in fetchall
    records = self._tx.load_rows(self._pos, self.pgresult.ntuples, self._make_row)
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/_transform.py", line 305, in load_rows
    record[col] = self._row_loaders[col](val)
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/types/composite.py", line 159, in load
    return self._tx.load_sequence(
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/_transform.py", line 328, in load_sequence
    raise e.ProgrammingError(
psycopg.ProgrammingError: cannot load sequence of 1 items: 2 loaders registered
Traceback of different error when the column containing 32 was removed from the record in the array
cursor = conn.execute(
    "SELECT ARRAY[ROW('e656b0f5-fa8e-4cbe-98db-525f9ab1cacc'::uuid)], ROW('abc')",
    binary=True,
).fetchall()
Traceback (most recent call last):
  File "/home/user/code/bug/src/repro.py", line 22, in <module>
    rows = cursor.fetchall()
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/cursor.py", line 851, in fetchall
    records = self._tx.load_rows(self._pos, self.pgresult.ntuples, self._make_row)
  File "psycopg_binary/_psycopg/transform.pyx", line 481, in psycopg_binary._psycopg.Transformer.load_rows
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/types/composite.py", line 159, in load
    return self._tx.load_sequence(
  File "psycopg_binary/_psycopg/transform.pyx", line 541, in psycopg_binary._psycopg.Transformer.load_sequence
  File "psycopg_binary/_psycopg/transform.pyx", line 567, in psycopg_binary._psycopg.Transformer.load_sequence
  File "/home/user/code/bug/.venv/lib/python3.10/site-packages/psycopg/types/uuid.py", line 57, in load
    return UUID(bytes=data)
  File "/usr/lib/python3.10/uuid.py", line 186, in __init__
    raise ValueError('bytes is not a 16-char string')
ValueError: bytes is not a 16-char string

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