Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Yeeef opened this issue Jan 19, 2025 · 0 comments

Comments

@Yeeef
Copy link

Yeeef commented Jan 19, 2025

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', '[email protected]'),
            (2, 'Bob', '[email protected]'),
            (3, 'Charlie', '[email protected]')
        ]

        # 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())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant