文档 / SQL 状态码 / Class 25 事务状态无效
25006 read_only_sql_transaction
只读 SQL 事务
ERROR 已实测 详解 实测通过
- 条件名
read_only_sql_transaction- 宏名称
ERRCODE_READ_ONLY_SQL_TRANSACTION- 启用版本
- 7.4
- 状态
- 活跃
版本覆盖
速览
25006 表示命令试图在只读事务中写入。选定案例在 SET TRANSACTION READ ONLY 后执行 CREATE TABLE,观察到 INERROR,回滚后离开只读事务再建表。
含义
该码覆盖多个保护点。PreventCommandIfReadOnly 把命令名填入 cannot execute %s in a read-only transaction;固定源码还包含恢复期间临时表和复制原点的专用报文。选定案例覆盖普通显式只读事务路径,而备用机或恢复路径可能使用不同的命令相关报文。
诊断
记录精确命令、SQLSTATE、严重级别和事务状态。重试前检查有效的 SHOW transaction_read_only,并在需要判断服务器边界时检查 pg_is_in_recovery();同时确认连接池是否把连接路由到了备用机。选定运行中 CREATE TABLE 返回 25006,使显式事务块进入 INERROR;复用会话前必须 ROLLBACK。离开只读事务后再次 CREATE TABLE 成功。
处理
先判断操作是否应放在只读事务中。若必须写入,应在主库的可写事务中执行或移出只读块;失败块先回滚,再把连接归还连接池。备用机或恢复期间的 25006 需要把操作路由到主库;在同一只读目标上重试写入不会改变访问模式。
可复现案例
在一次性实例上执行过的场景。其中 1 个附有可执行 SQL,正文相应小节里给出。
read_only_transaction PG 10 / 18 有 SQL
前置条件
- A runner-owned disposable target is provisioned.
触发
Run CREATE TABLE after SET TRANSACTION READ ONLY.
断言
- SQLSTATE is 25006
- The CREATE TABLE read-only diagnostic is exact
- The failed transaction is INERROR, ROLLBACK restores IDLE
- The table can be created after leaving read-only mode
处置
Follow the explicit transaction or source boundary described by the case.
清理
Drop the case schema with an owner connection.
源码报文
核心 utility 路径的源码模板是 cannot execute %s in a read-only transaction;在恢复目标上,同一 utility 保护会使用 cannot execute %s during recovery,恢复期间临时表和复制原点也有各自的固定文本。%s 是实际命令名,不能脱离路径当作一条静态报文。
报文模板
源码里的格式串,不是某一次运行的输出。%s 之类是占位符,实际报文会填入对象名与取值。适用范围一栏是核验时留下的原始英文记录,未经翻译。
cannot execute %s in a read-only transaction
来源:src/backend/tcop/utility.c @ REL_18_6
适用范围:The %s substitution is the command name.
cannot execute %s during recovery
来源:src/backend/tcop/utility.c @ REL_18_6
适用范围:Recovery-only utility path; %s is the command name and this was not the selected ordinary read-only case.
cannot create temporary tables during recovery
来源:src/backend/catalog/namespace.c @ REL_18_6
适用范围:A recovery-only path; not the selected case.
cannot manipulate replication origins during recovery
来源:src/backend/replication/logical/origin.c @ REL_18_6
适用范围:A recovery-only path; not the selected case.
实测诊断
18.6 (Homebrew) / latest:SQLSTATE 25006;主报文 cannot execute CREATE TABLE in a read-only transaction;状态 INERROR → IDLE;修复后关系行数 0;最终状态 IDLE。
10.21 (Debian 10.21-1.pgdg90+1) / pg10:SQLSTATE 25006;主报文 cannot execute CREATE TABLE in a read-only transaction;状态 INERROR → IDLE;修复后关系行数 0;最终状态 IDLE。
代表案例
运行器从共享语句清单(registry)读取下列 setup、只读事务、回滚和事务块外修复语句;完整断言、环境和清理见 案例导出。
-- create
CREATE TABLE items(id integer PRIMARY KEY, note text NOT NULL);
-- begin
BEGIN;
-- read_only
SET TRANSACTION READ ONLY;
-- trigger
CREATE TABLE blocked(id integer PRIMARY KEY);
-- rollback
ROLLBACK;
-- repair
CREATE TABLE blocked(id integer PRIMARY KEY);
-- verify
SELECT count(*) FROM blocked;
上述片段的 SQLSTATE、诊断、状态和修复断言来自共享语句清单(registry)(SHA-256 62db30e401b1f72fa50958d0ac612b2b1eb636299532dd1ad246c167e4f9fadf);结构化证据。
作者证据 ID:identity, utility-path, other-paths, runtime。选定运行记录:runtime.25006-batch2-latest-20260909.latest, runtime.25006-batch2-pg10-20260909.pg10。
版本与边界
选定的 CREATE TABLE 案例在 PostgreSQL 18.6 与 10.21 通过,主报文相同,并完成 INERROR → IDLE 恢复和修复后建表。其他 25006 源码路径不在本运行案例范围内。
来源
- 上游源码 doc/src/sgml/ref/set_transaction.sgml 第 131–145 行
- 上游源码 src/backend/utils/errcodes.txt
- 上游源码 src/backend/catalog/namespace.c 第 4418–4437 行
- 上游源码 src/backend/replication/logical/origin.c 第 189–200 行
- 上游源码 src/backend/tcop/utility.c 第 397–448 行
- 核验材料 raw/calls/REL_18_6.jsonl
证据
断言
每条断言都写明了是怎么核实的,以及它不覆盖什么。这一层是核验时留下的原始英文记录,照原样呈现,未经翻译。
-
25006 is read_only_sql_transaction in Class 25.
-
PreventCommandIfReadOnly formats the SQL command name into “cannot execute %s in a read-only transaction”; CREATE TABLE is one ordinary utility path.
-
The fixed source also uses 25006 for temporary-table creation during recovery and replication-origin manipulation during recovery.
-
The selected read-only CREATE TABLE case returned 25006 on PostgreSQL 18.6 and 10.21, entered INERROR, recovered after ROLLBACK, and created the relation outside the read-only transaction.
-
The same fixed utility source uses 25006 during recovery with the command-specific message "cannot execute %s during recovery"; this is separate from the selected ordinary read-only transaction path.
运行记录
| 目标 | 服务器版本 | 结果 | 覆盖案例 |
|---|---|---|---|
| latest | 18.6 (Homebrew) | passed | read_only_transaction |
| pg10 | 10.21 (Debian 10.21-1.pgdg90+1) | passed | read_only_transaction |
同类 SQL 状态码
| 状态码 | 条件名 | 宏名称 | 严重等级 | 版本 |
|---|---|---|---|---|
| 25000 | invalid_transaction_state | ERRCODE_INVALID_TRANSACTION_STATE |
ERROR | 7.4 |
| 事务状态无效的类别码,多见于内部状态检查。 | 活跃 | |||
| 25001 | active_sql_transaction | ERRCODE_ACTIVE_SQL_TRANSACTION |
ERROR | 7.4 |
| 命令不能在活动事务块中执行,如 VACUUM。 | 活跃 | |||
| 25002 | branch_transaction_already_active | ERRCODE_BRANCH_TRANSACTION_ALREADY_ACTIVE |
ERROR | 7.4 |
| 分支事务已经活动,范围窄于 25001。 | 活跃 | |||
| 25003 | inappropriate_access_mode_for_branch_transaction | ERRCODE_INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION |
ERROR | 7.4 |
| 分支事务使用了不适用的访问模式。 | 活跃 | |||
| 25004 | inappropriate_isolation_level_for_branch_transaction | ERRCODE_INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION |
ERROR | 7.4 |
| 分支事务使用了不适用的隔离级别。 | 活跃 | |||
| 25005 | no_active_sql_transaction_for_branch_transaction | ERRCODE_NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION |
ERROR | 7.4 |
| 分支事务缺少活动的 SQL 事务。 | 活跃 | |||
| 25006 | read_only_sql_transaction | ERRCODE_READ_ONLY_SQL_TRANSACTION |
ERROR | 7.4 |
| 命令试图在只读事务中写入数据。 | 活跃 | |||
| 25007 | schema_and_data_statement_mixing_not_supported | ERRCODE_SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED |
ERROR | 7.4 |
| 事务中不支持混合模式语句与数据语句。 | 活跃 | |||
| 25008 | held_cursor_requires_same_isolation_level | ERRCODE_HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL |
ERROR | 7.4 |
| 持有游标要求与操作相同的事务隔离级别。 | 活跃 | |||
| 25P01 | no_active_sql_transaction | ERRCODE_NO_ACTIVE_SQL_TRANSACTION |
ERROR | 7.4 |
| 操作需要活动事务块,如自动提交下的 SAVEPOINT。 | 活跃 | |||
| 25P02 | in_failed_sql_transaction | ERRCODE_IN_FAILED_SQL_TRANSACTION |
ERROR | 7.4 |
| 事务已失败,后续语句被拒绝直到 ROLLBACK。 | 活跃 | |||
| 25P03 | idle_in_transaction_session_timeout | ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT |
ERROR | 9.6 |
| 会话在开放事务中空闲超时,被服务器终止。 | 活跃 | |||
| 25P04 | transaction_timeout | ERRCODE_TRANSACTION_TIMEOUT |
ERROR | 17 |
| 事务运行超过 transaction_timeout 被终止。 | 活跃 | |||