Queries with more than 32767 arguments are refused, PostgreSQL accepts 65535
Los mantenedores suelen responder en 1 día
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 18/100
Línea de trabajo
The limit lives in asyncpg/protocol/prepared_stmt.pyx (the check near lines 130-132 and the count handling near 348-353) and its declaration in prepared_stmt.pxd. Run the test named test_prepare_28_max_args to see the current 32767 ceiling. Pull request #1391 already carries this change, so review or build on that rather than starting a parallel fix. Done means the counts are unsigned, the limit is 65535, and the test passes.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
- asyncpg version: 0.32.0, same on master (13b0191)
- PostgreSQL version: 17
- Do you use a PostgreSQL SaaS? If so, which? Can you reproduce
the issue with a local PostgreSQL install?: no, local Dockerpostgres:17 - Python version: 3.12
- Platform: macOS
- Do you use pgbouncer?: no
- Did you install asyncpg with pip?: yes, and built master locally for the check below
- If you built asyncpg locally, which version of Cython did you use?: 3.2.x
- Can the issue be reproduced under both asyncio and
uvloop?: tried asyncio only; the limit is in the protocol code
asyncpg refuses more than 32767 query arguments (prepared_stmt.pyx#L130-L132) and keeps the parameter count in int16_t (prepared_stmt.pxd#L24, prepared_stmt.pyx#L348-L353). The limit comes from #127, where the Int16 in the Bind message was read as signed.
PostgreSQL reads that count as unsigned: exec_bind_message takes it with pq_getmsgint(input_message, 2) (postgres.c#L1725), which returns a uint16 (pqformat.c#L419-L430), and the docs list 65,535 query parameters as the limit (PostgreSQL Limits, listed since 12). libpq allows the same (libpq-fe.h#L490), so psycopg runs the same statements with up to 65535 parameters.
As a result, a multi-row INSERT ... VALUES has to be split at half of what the server accepts.
import asyncio
import importlib.metadata as md
import asyncpg
import psycopg
DSN = "postgresql://postgres@localhost/postgres"
def query(n, mark):
return "SELECT count(*) FROM (VALUES {}) v(x)".format(
", ".join("({}::int)".format(mark(i)) for i in range(1, n + 1))
)
async def main():
print("asyncpg", md.version("asyncpg"), "psycopg", md.version("psycopg"))
conn = await asyncpg.connect(DSN)
for n in (32767, 32768, 65535):
try:
print(f"asyncpg {n}:", await conn.fetchval(query(n, lambda i: f"${i}"), *range(n)))
except asyncpg.InterfaceError as e:
print(f"asyncpg {n}: {e}")
with psycopg.connect(DSN) as pg:
print(f"psycopg {n}:", pg.execute(query(n, lambda i: "%s"), range(n), prepare=True).fetchone()[0])
await conn.close()
asyncio.run(main())
asyncpg 0.33.0.dev0+13b0191 psycopg 3.3.6
asyncpg 32767: 32767
psycopg 32767: 32767
asyncpg 32768: the number of query arguments cannot exceed 32767
psycopg 32768: 32768
asyncpg 65535: the number of query arguments cannot exceed 32767
psycopg 65535: 65535
Keeping the counts as uint16_t and raising the check to 65535 fixes it, and the bytes on the wire stay the same for up to 32767 arguments.
I have that ready with an updated test_prepare_28_max_args and will open a PR.
- Lenguaje dominante
- Python
- Estrellas
- 8.1k
- Forks
- 477
- Merge medio
- 1 d 7 h
- PR fusionados (30 d)
- 23
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de MagicStack/asyncpg
-
Failed BEGIN leaves Connection._top_xact set; every later transaction becomes a SAVEPOINT and fails with NoActiveSQLTransactionErrorPosiblemente ocupada @devtechedge la tomó hace 8 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 35/100
MagicStack/asyncpg#1386 ·
Los mantenedores suelen responder en 1 día
-
Connect call failed error doesn't distinguish port mismatch from "server not running"Posiblemente ocupada @aryansk la tomó hace 61 días. Abierto
Dificultad 3/5 1-2 días Aptitud para principiantes 72/100
MagicStack/asyncpg#1342 ·
Los mantenedores suelen responder en 1 día
-
TypeError in asyncpg.connect() for specific parameters when values are not str enoughPosiblemente ocupada @pranjalm37 la tomó hace 64 días. Abierto
Dificultad 3/5 1-2 días Aptitud para principiantes 56/100
MagicStack/asyncpg#1340 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
setup.py relies on deprecated pkg_resourcesPosiblemente ocupada @jasonwbarnett la tomó hace 92 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 28/100
MagicStack/asyncpg#1337 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 42/100
MagicStack/asyncpg#1330 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de MagicStack/asyncpg
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
common-workflow-language/cwl-utils#477 ·
Los mantenedores suelen responder en 1 día
-
Add dependabotAbiertofeat
Dificultad 2/5 Menos de una hora Aptitud para principiantes 72/100
open-nudge/opentemplate#204 ·
Los mantenedores suelen responder en 1 día
-
github-stale-ci-pr-closer: KV state is double-wrapped, never persists, and hits the depth-32 limitPosiblemente ocupada @VascoSch92 la tomó hoy. Abiertopriority:medium ready-for-dev
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
OpenHands/extensions#781 ·
Los mantenedores suelen responder en 1 día
-
bug good first issue
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
curriculum documentation quality
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
githubnext/gh-aw-workshop#4638 ·
Los mantenedores suelen responder en 1 día