MagicStack / MagicStack/asyncpg

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

未关闭
#1,215 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

主要语言
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](https://github.com/magicstack/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. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从提供的 Python 复现程序开始,重点关注事务回滚路径和连接的 get_settings() 入口点。确认事务错误后的回滚与干净回滚之间的差异,然后追踪 client_encoding 状态是如何刷新的;当 get_settings() 在回滚后报告 UTF8,且后续的文本参数查询成功时,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
postgresql, python
领域
backend, databases
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
42/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。