# 25001 — 活动 SQL 事务（active_sql_transaction）

> PostgreSQL SQLSTATE 25001：活动 SQL 事务的来源与诊断参考。
---

# 25001 — 活动 SQL 事务

## 速览 {#at-a-glance}

`25001` 表示当前活动 SQL 事务违反了命令要求的事务边界。本案例在 `BEGIN` 后执行 `VACUUM`，得到精确错误；回滚后在事务块外执行 `VACUUM` 成功且连接保持 `IDLE`。

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `25001` |
| 条件名 | `active_sql_transaction` |
| 状态 | `有效` |
| 已知存在于 | `7.4` |
| 锁定快照 | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| 宏 | `ERRCODE_ACTIVE_SQL_TRANSACTION` |
| 别名 | `—` |

<!-- source facts: data/errcodes/25001.json -->
<!-- END SQLSTATE FACTS -->

## 含义 {#meaning}

该码覆盖多条路径：`PreventInTransactionBlock` 会拒绝事务块、子事务或函数中的禁用 utility，源码分别格式化为 `%s cannot run inside a transaction block`、`%s cannot run inside a subtransaction` 和 `%s cannot be executed from a function`。其他路径会拒绝写入后的逻辑复制槽、子事务中的快照导出，或查询开始后的导入快照设置。在已经活动的事务中再次 `BEGIN` 是独立的 `WARNING`，因此严重级别和恢复方式取决于具体源码路径。

## 诊断 {#diagnosis}

记录 SQLSTATE、严重级别、主报文、事务状态和命令。本案例的 `VACUUM` ERROR 后显式会话进入 `INERROR`，只有 `ROLLBACK` 恢复 `IDLE`。函数或子事务报错时，应先结束该上下文，再把命令作为位于任何显式事务块之外的一条独立顶层 utility 命令发出（例如驱动自动提交的单条命令）；在同一 wrapper 内重试仍不满足 `PreventInTransactionBlock`。逻辑复制槽和快照报错则要检查是否已有写入、子事务或查询；“事务已在进行中”的 `WARNING` 不是 VACUUM 的 ERROR，本身不要求回滚。随后选定修复在事务块外执行 VACUUM，并断言成功和 `IDLE`。

## 处理 {#response}

禁用 utility 若位于不合适的事务块、函数或子事务中，应移到位于任何显式事务块之外的一条独立顶层命令（通常在自动提交连接上执行）；不要把“顶层”理解为另一个 `BEGIN`。显式事务中的 ERROR 后先执行 `ROLLBACK`，再执行该命令。逻辑复制槽必须在此前没有写入的事务中创建；快照导出不能位于子事务，`SET TRANSACTION SNAPSHOT` 必须早于任何查询。重复 `BEGIN` 的 `WARNING` 应保留已有事务，不要仅因警告就回滚。应按精确源码路径处理，不能机械套用 VACUUM 修复。

## 实测诊断 {#messages}

`18.6 (Homebrew) / latest`：SQLSTATE `25001`；primary `VACUUM cannot run inside a transaction block`；after_error `INERROR`；after_rollback `IDLE`；status_after_vacuum `IDLE`。
`10.21 (Debian 10.21-1.pgdg90+1) / pg10`：SQLSTATE `25001`；primary `VACUUM cannot run inside a transaction block`；after_error `INERROR`；after_rollback `IDLE`；status_after_vacuum `IDLE`。

## 源码报文模板 {#source-templates}

选定的 VACUUM 运行没有覆盖以下源码分支：

- ERROR `%s cannot run inside a subtransaction`（`%s` 替换为命令名）。
- ERROR `%s cannot be executed from a function`（`%s` 替换为命令名）。
- ERROR `cannot create logical replication slot in transaction that has performed writes`。
- ERROR `cannot export a snapshot from a subtransaction`。
- ERROR `SET TRANSACTION SNAPSHOT must be called before any query`。
- WARNING `there is already a transaction in progress`。

这些是源码证据，不是本案例新增的运行结论。

## 代表案例 {#case}

本例中，`VACUUM` 在显式 `BEGIN` 块内被拒绝；`ROLLBACK` 后，同一 utility 作为事务块外的独立命令成功。完整 setup、断言与清理见[案例导出](../../data/cases/25001.json)：

<!-- BEGIN SQLSTATE SNIPPET: vacuum_inside_transaction -->
```sql
-- create
CREATE TABLE items(id integer PRIMARY KEY, note text NOT NULL);
-- seed
INSERT INTO items VALUES (1, 'seed');
-- begin
BEGIN;
-- trigger
VACUUM items;
-- rollback
ROLLBACK;
-- followup
SELECT 1 AS usable;
-- repair
VACUUM items;
```
<!-- END SQLSTATE SNIPPET -->

本案例对应的 SQLSTATE、诊断、事务状态和修复断言均来自经核对的案例 registry；见[结构化证据](../../data/evidence/25001.json)和[案例导出](../../data/cases/25001.json)。

作者证据 ID：`identity`, `utility-path`, `other-paths`, `runtime`。选定运行记录：`runtime.25001-batch1-latest2-20260909.latest`, `runtime.25001-batch1-pg10b-20260909.pg10`。

## 版本与边界 {#versions}

锁定目录在 `7.4` 已观察到该条件，并在列出的正式快照中均存在。选定的 VACUUM 案例在 18.6 与 10.21 通过，包含回滚恢复和事务块外成功修复；其他 25001 路径仅有源码证据。

## 相关 {#related}

对比 [25000 事务状态无效](../25000/)、[25P02 失败 SQL 事务](../25p02/) 和 [24000 游标状态无效](../24000/)。

## 来源 {#sources}

- [`src.errcodes.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt) (SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba`)
- `src.calls.REL_18_6` (SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf`)
- [`src.xact.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/access/transam/xact.c#L3654-L3677) (SHA-256 `75b012c0b047d1dc905a30975c244beec366e45eac0dbf109fd21bcd611a8e39`)
- [`src.logical.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/replication/logical/logical.c#L444-L446) (SHA-256 `3f1bd4c3e627fe78522c4dc9bacf9fa8200e6c82c2d01f7670706eee102b76d1`)
- [`src.snapmgr-export.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/time/snapmgr.c#L1152-L1154) (SHA-256 `b605b69e77a026c143f4cabca079de364b9a8732bfc40f7595be44fb0971ee8`)
- [`src.snapmgr-set-snapshot.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/time/snapmgr.c#L1409-L1411) (SHA-256 `b605b69e77a026c143f4cabca079de364b9a8732bfc40f7595be44fb0971ee8`)
- [`doc.vacuum.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ref/vacuum.sgml) (SHA-256 `80ca5592cda7b74938385f84f09faac33574374c1a05d605a2d55982e4cf1bbf`) · [官方文档](https://www.postgresql.org/docs/18/sql-vacuum.html)
