Description
We are using asyncpg with pgbouncer statement pooling mode. According to the FAQ https://magicstack.github.io/asyncpg/current/faq.html#why-am-i-getting-prepared-statement-errors , setting statement_cache_size=0
will be enough to disable the usage of named prepared statement. But we are still getting the error prepared statement “__asyncpg_stmt_xx__” already exists
.
After some exploration, we find that copy_records_to_table is calling self._prepare
with name=None
, which eventually instructs self._get_statement
to create a named prepared statement. As a result, a named prepared statement will be created with name __asyncpg_stmt_xx__
, and other client application using asyncpg could try to create something with the same name, leading to the error.
The fix would be straightforward if I am not missing anything: #1218
Test set up:
- asyncpg 0.30.0
- pgbouncer 1.22.0
- postgres 16.6
Simple script to reproduce:
import asyncpg
import asyncio
from asyncpg.connection import Connection
async def main():
conn: Connection = await asyncpg.connect(
host='localhost',
port=6432,
user='postgres',
database='postgres',
statement_cache_size=0,
server_settings={'application_name': 'reproduce'}
)
try:
# Create a sample table
await conn.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER,
name TEXT,
email TEXT
)
''')
# Sample records to copy
records = [
(1, 'Alice', 'alice@example.com'),
(2, 'Bob', 'bob@example.com'),
(3, 'Charlie', 'charlie@example.com')
]
# Copy records to the table
result = await conn.copy_records_to_table(
'users',
records=records,
columns=('id', 'name', 'email')
)
print(f"Copy operation completed: {result}")
finally:
await conn.close()
asyncio.run(main())