# 24000 — 游标状态无效（invalid_cursor_state）

> PostgreSQL SQLSTATE 24000：游标状态无效的来源与诊断参考。
---

# 24000 — 游标状态无效

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

`24000` 表示游标或 portal 状态不满足当前操作。本案例声明了有效游标，却在 FETCH 定位前执行 `WHERE CURRENT OF`，因而报“游标未定位到行”。

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

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `24000` |
| 条件名 | `invalid_cursor_state` |
| 状态 | `有效` |
| 已知存在于 | `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_INVALID_CURSOR_STATE` |
| 别名 | `—` |

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

## 含义 {#meaning}

`WHERE CURRENT OF` 要求游标来自可更新查询，并已通过 FETCH 选中当前行；声明本身不会定位。其他非 SELECT、已保持、不可更新或缺少 FOR UPDATE/SHARE 引用的游标也有不同 `24000` 模板。

## 诊断 {#diagnosis}

记录游标名和操作，检查声明、事务生命周期、FETCH 方向及可更新性。显式事务错误后本案例为 `INERROR`，回滚后回到 `IDLE`；本案例用主键直接更新修复，未测试重新 DECLARE/FETCH。

## 处理 {#response}

先 FETCH 定位再使用 CURRENT OF，或者使用确定性的键更新。保持游标和事务生命周期显式，失败事务先回滚。

## 实测诊断 {#messages}

`18.6 (Homebrew) / latest`：SQLSTATE `24000`；primary `cursor "item_cursor" is not positioned on a row`；after_error `INERROR`；after_rollback `IDLE`。
`10.21 (Debian 10.21-1.pgdg90+1) / pg10`：SQLSTATE `24000`；primary `cursor "item_cursor" is not positioned on a row`；after_error `INERROR`；after_rollback `IDLE`。

## 代表案例 {#case}

运行器从 `verify/cases/24000/snippets.json`（SHA-256 `cafca57825378362df0527384614bf658bf86cd3101e1eb520ea0641819f2789`）读取下列片段，并为临时 schema 替换表名；完整 setup、断言与清理见 [案例导出](../../data/cases/24000.json)。

<!-- BEGIN SQLSTATE SNIPPET: current_of_before_fetch -->
```sql
-- create
CREATE TABLE items(id integer PRIMARY KEY, note text NOT NULL);
-- seed
INSERT INTO items VALUES (1, 'seed');
-- begin
BEGIN;
-- declare
DECLARE item_cursor CURSOR FOR SELECT id FROM items FOR UPDATE;
-- trigger
UPDATE items SET note = 'bad' WHERE CURRENT OF item_cursor;
-- rollback
ROLLBACK;
-- repair
UPDATE items SET note = 'repaired' WHERE id = 1;
-- verify
SELECT id, note FROM items;
```
<!-- END SQLSTATE SNIPPET -->

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

作者证据 ID：`identity`, `current-of`, `runtime`。选定运行记录：`runtime.24000-batch1-latest2-20260909.latest`, `runtime.24000-batch1-pg10-20260909.pg10`。

## 版本与边界 {#versions}

锁定目录在 `7.4` 已观察到该条件，并在列出的正式快照中均存在。选定运行覆盖 18.6 与 10.21 的 FETCH 前 `CURRENT OF` 路径；其他游标状态需要独立案例。

## 相关 {#related}

对比 [25001 活动 SQL 事务](../25001/)、[25P02 失败 SQL 事务](../25p02/) 和 [34000 无效游标名称](../34000/)。

## 来源 {#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.execCurrent.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/execCurrent.c#L135-L138) (SHA-256 `45c8e48b3a5dc46f1014482dc88e0a26c25c3a4c403372112474d9171253d8a9`)
- [`doc.declare.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ref/declare.sgml#L275-L285) (SHA-256 `f1d72befb9a989aa32123560aea784a8bccfcb3d3930804a101d8245e5a3cc95`) · [官方文档](https://www.postgresql.org/docs/18/sql-declare.html)
- [`doc.update.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ref/update.sgml#L203-L211) (SHA-256 `47dd724cd724bd77478215a4853aa1f985996a0e5bba9b2451a1ad1ebb6e51fc`) · [官方文档](https://www.postgresql.org/docs/18/sql-update.html)
