MagicStack / MagicStack/asyncpg

`get_settings()` can get out of sync after a transaction with an error is rolled back

オープン
#1,215 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

主要言語
Python
スター
8.1k
フォーク
468
PR マージ指標
30日以内にマージされた PR はありません

説明

  • asyncpg version: 0.30.0
  • PostgreSQL version: 17.2
  • Do you use a PostgreSQL SaaS? If so, which? Can you reproduce
    the issue with a local PostgreSQL install?
    : No
  • Python version: 3.12.2
  • Platform: Linux
  • Do you use pgbouncer?: No
  • Did you install asyncpg with pip?: Yes
  • If you built asyncpg locally, which version of Cython did you use?:
  • Can the issue be reproduced under both asyncio and
    uvloop?
    : Only checked asyncio but it doesn't seem likely to matter
#!/usr/bin/env python3

import asyncio
import asyncpg

async def _check_encoding(con):
    current_encoding = (await con.fetch(
        "select current_setting('client_encoding')")
    )[0]['current_setting']
    print(current_encoding)
    print(con.get_settings().client_encoding)


async def test(dsn):
    con = await asyncpg.connect(dsn)

    print("Orig")
    await _check_encoding(con)

    tran = con.transaction()
    await tran.start()

    await con.execute("set client_encoding to 'latin1'")
    print("In transaction:")
    await _check_encoding(con)
    try:
        await con.fetch("select 1 + 'a'")
    except Exception:
        pass


    await tran.rollback()
    print("After rollback:")
    await _check_encoding(con)

    res = await con.fetch('select $1::text', '💩')
    print(res)


asyncio.run(test(
    'postgres:///main?user=edgedb&port=5656&host=localhost'
))

In a transaction, if I set client_encoding to something, and then the transaction has an error and is rolled back, the client_encoding that get_settings() returns is never reverted.
If the transaction is rolled back without an error occuring, the right thing happens.

Output:

Orig
UTF8
UTF_8
In transaction:
LATIN1
LATIN1
After rollback:
UTF8
LATIN1
Traceback (most recent call last):
  File "asyncpg/protocol/prepared_stmt.pyx", line 175, in asyncpg.protocol.protocol.PreparedStatementState._encode_bind_msg
  File "asyncpg/protocol/codecs/base.pyx", line 227, in asyncpg.protocol.protocol.Codec.encode
  File "asyncpg/protocol/codecs/base.pyx", line 129, in asyncpg.protocol.protocol.Codec.encode_scalar
  File "asyncpg/pgproto/./codecs/text.pyx", line 29, in asyncpg.pgproto.pgproto.text_encode
  File "asyncpg/pgproto/./codecs/text.pyx", line 17, in asyncpg.pgproto.pgproto.as_pg_string_and_size
UnicodeEncodeError: 'latin-1' codec can't encode character '\U0001f4a9' in position 0: ordinal not in range(256)

I would expect

After rollback:
UTF8
UTF8

and no encoding error.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

提供された Python 再現プログラムから始め、トランザクションのロールバックパスと、接続の get_settings() エントリーポイントに重点を置いてください。トランザクションエラー後のロールバックとクリーンなロールバックの違いを確認し、その後 client_encoding の状態がどのように更新されるかを追跡してください。get_settings() がロールバック後に UTF8 を報告し、その後のテキストパラメータクエリが成功すれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
postgresql, python
領域
backend, databases
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
42/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。