Skip to content

copy_records_to_table uses named prepared statement even when statement_cache_size is 0 #1219

Closed
@Yeeef

Description

@Yeeef

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())

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