↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

Wiki / SQLSTATE

24000 — 游标状态无效(invalid_cursor_state)

游标或 portal 状态不满足当前操作要求。

英文手册覆盖始于 PostgreSQL 8.1. 来源历史与运行验证各自保留独立版本边界。

当前阅读 PG 18·选择有来源记录的版本

aliases
未知
class name
Invalid Cursor State
condition name
invalid_cursor_state
lang
en
sqlstate
24000

版本定义 PG 18

24000 — 游标状态无效

速览 {#at-a-glance}

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

含义 {#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、断言与清理见 案例导出。

-- 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;

本案例对应的 SQLSTATE、诊断、事务状态和修复断言均来自上述共享 registry;结构化证据 · 案例导出。

作者证据 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 事务、25P02 失败 SQL 事务 和 34000 无效游标名称。

来源 {#sources}

  • src.errcodes.18.6 (SHA-256 6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)
  • src.calls.REL_18_6 (SHA-256 9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)
  • src.execCurrent.18.6 (SHA-256 45c8e48b3a5dc46f1014482dc88e0a26c25c3a4c403372112474d9171253d8a9)
  • doc.declare.18.6 (SHA-256 f1d72befb9a989aa32123560aea784a8bccfcb3d3930804a101d8245e5a3cc95) · 官方文档
  • doc.update.18.6 (SHA-256 47dd724cd724bd77478215a4853aa1f985996a0e5bba9b2451a1ad1ebb6e51fc) · 官方文档

比较版本

SQLSTATE 证据与已记录的运行版本

cases · current_of_before_fetch
{
  "assertions": [
    "SQLSTATE is 24000",
    "The connection recovers after rollback",
    "A direct update succeeds afterward"
  ],
  "case_id": "current_of_before_fetch",
  "cleanup": "Drop the case schema with an owner connection.",
  "has_snippet": true,
  "position": 0,
  "preconditions": [
    "A cursor is declared for a SELECT ... FOR UPDATE",
    "The cursor has not fetched a row"
  ],
  "repair": "Fetch or otherwise position the cursor before CURRENT OF, or use a key-based update whose concurrency semantics are explicit.",
  "trigger": "Use WHERE CURRENT OF before the cursor is positioned on a row.",
  "versions": [
    "10",
    "18"
  ]
}
claims · identity
{
  "claim_id": "identity",
  "limits": "The class has several cursor/portal states; the observed message is one path.",
  "method": "Read the fixed condition row.",
  "position": 0,
  "runtime": [],
  "sources": [
    "src.errcodes.18.6"
  ],
  "statement": "24000 is invalid_cursor_state in Class 24."
}
claims · current-of
{
  "claim_id": "current-of",
  "limits": "A cursor can be validly declared yet still be unpositioned; declaration alone does not make CURRENT OF usable.",
  "method": "Trace execCurrent and the documented DECLARE/CURRENT OF rules.",
  "position": 1,
  "runtime": [],
  "sources": [
    "src.execCurrent.18.6",
    "doc.declare.18.6",
    "doc.update.18.6",
    "src.calls.REL_18_6"
  ],
  "statement": "UPDATE or DELETE ... WHERE CURRENT OF requires a positioned, updatable cursor row; before FETCH the executor reports 24000."
}
claims · runtime
{
  "claim_id": "runtime",
  "limits": "Only the before-FETCH CURRENT OF path was run; other cursor states use other source templates.",
  "method": "Read the selected summaries and raw diagnostics.",
  "position": 2,
  "runtime": [],
  "sources": [
    "runtime.24000-batch1-latest2-20260909.latest",
    "runtime.24000-batch1-pg10-20260909.pg10"
  ],
  "statement": "The selected explicit transaction case returned 24000 before FETCH, entered INERROR, recovered after ROLLBACK, and then directly repaired the row on PG18.6 and PG10.21."
}
messages · unpositioned
{
  "limits": "The same template is also used by another CURRENT OF path; the cursor name is substituted at runtime.",
  "message_id": "unpositioned",
  "path": "",
  "position": 0,
  "raw": {
    "id": "unpositioned",
    "limits": "The same template is also used by another CURRENT OF path; the cursor name is substituted at runtime.",
    "primary_template": "cursor \"%s\" is not positioned on a row",
    "severity_source": "ERROR",
    "sources": [
      "src.execCurrent.18.6"
    ],
    "sqlstate": "24000"
  },
  "severity": "ERROR",
  "sources": [
    "src.execCurrent.18.6"
  ],
  "templates": [
    {
      "kind": "primary",
      "literal": "cursor \" \" is not positioned on a row",
      "position": 0,
      "role": "",
      "template": "cursor \"%s\" is not positioned on a row"
    }
  ]
}
runtimes · runtime.24000-batch1-latest2-20260909.latest · 18.6 (Homebrew) · passed
{
  "cases": [
    "current_of_before_fetch"
  ],
  "limits": "",
  "position": 0,
  "raw": {
    "case_manifest": {
      "path": "verify/cases/24000/cases.json",
      "sha256": "5a52a1c37d8702961515d9d32e7c5285ca3a9cebe0a16492858864ce933a1b1c"
    },
    "cases": [
      "current_of_before_fetch"
    ],
    "id": "runtime.24000-batch1-latest2-20260909.latest",
    "observed": {
      "after_error": "INERROR",
      "after_rollback": "IDLE",
      "primary": "cursor \"item_cursor\" is not positioned on a row",
      "repaired_row": [
        1,
        "repaired"
      ],
      "sqlstate": "24000"
    },
    "raw": "verify/results/24000-batch1-latest2-20260909/latest/raw.jsonl",
    "raw_sha256": "567d6fb5a4c4f6e881050992aa833c79999d5018cba753b41021483f59e7069c",
    "run_id": "24000-batch1-latest2-20260909",
    "server_version": "18.6 (Homebrew)",
    "server_version_num": 180006,
    "snippet_registry": {
      "path": "verify/cases/24000/snippets.json",
      "sha256": "cafca57825378362df0527384614bf658bf86cd3101e1eb520ea0641819f2789"
    },
    "status": "passed",
    "summary": "verify/results/24000-batch1-latest2-20260909/latest/summary.json",
    "summary_sha256": "d14d912dad21157c8911b7ec6f16eb5b995b4efd387cca830b826a4ff17039d6",
    "target": "latest"
  },
  "run_id": "24000-batch1-latest2-20260909",
  "runtime_id": "runtime.24000-batch1-latest2-20260909.latest",
  "server_version": "18.6 (Homebrew)",
  "status": "passed",
  "target": "latest"
}
runtimes · runtime.24000-batch1-pg10-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
  "cases": [
    "current_of_before_fetch"
  ],
  "limits": "",
  "position": 1,
  "raw": {
    "case_manifest": {
      "path": "verify/cases/24000/cases.json",
      "sha256": "5a52a1c37d8702961515d9d32e7c5285ca3a9cebe0a16492858864ce933a1b1c"
    },
    "cases": [
      "current_of_before_fetch"
    ],
    "id": "runtime.24000-batch1-pg10-20260909.pg10",
    "observed": {
      "after_error": "INERROR",
      "after_rollback": "IDLE",
      "primary": "cursor \"item_cursor\" is not positioned on a row",
      "repaired_row": [
        1,
        "repaired"
      ],
      "sqlstate": "24000"
    },
    "raw": "verify/results/24000-batch1-pg10-20260909/pg10/raw.jsonl",
    "raw_sha256": "cf77c7f96913d2a33315afa186be2fd51eb100f69da7d5540ed708f41b5bde3f",
    "run_id": "24000-batch1-pg10-20260909",
    "server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
    "server_version_num": 100021,
    "snippet_registry": {
      "path": "verify/cases/24000/snippets.json",
      "sha256": "cafca57825378362df0527384614bf658bf86cd3101e1eb520ea0641819f2789"
    },
    "status": "passed",
    "summary": "verify/results/24000-batch1-pg10-20260909/pg10/summary.json",
    "summary_sha256": "9a38d0b3ee7ffa8f3018ceb09045cc78ae4c2bccd004a6c369cf9cbc76089851",
    "target": "pg10"
  },
  "run_id": "24000-batch1-pg10-20260909",
  "runtime_id": "runtime.24000-batch1-pg10-20260909.pg10",
  "server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
  "status": "passed",
  "target": "pg10"
}
sources · src.errcodes.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "upstream_source",
  "location": "",
  "path": "src/backend/utils/errcodes.txt",
  "position": 0,
  "sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
  "source_id": "src.errcodes.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt"
}
sources · src.calls.REL_18_6
{
  "commit": "",
  "docs_url": "",
  "kind": "local_artifact",
  "location": "",
  "path": "raw/calls/REL_18_6.jsonl",
  "position": 1,
  "sha256": "9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf",
  "source_id": "src.calls.REL_18_6",
  "tag": "",
  "url": ""
}
sources · src.execCurrent.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "upstream_source",
  "location": "",
  "path": "src/backend/executor/execCurrent.c",
  "position": 2,
  "sha256": "45c8e48b3a5dc46f1014482dc88e0a26c25c3a4c403372112474d9171253d8a9",
  "source_id": "src.execCurrent.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/execCurrent.c#L135-L138"
}
sources · doc.declare.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "https://www.postgresql.org/docs/18/sql-declare.html",
  "kind": "upstream_source",
  "location": "",
  "path": "doc/src/sgml/ref/declare.sgml",
  "position": 3,
  "sha256": "f1d72befb9a989aa32123560aea784a8bccfcb3d3930804a101d8245e5a3cc95",
  "source_id": "doc.declare.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ref/declare.sgml#L275-L285"
}
sources · doc.update.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "https://www.postgresql.org/docs/18/sql-update.html",
  "kind": "upstream_source",
  "location": "",
  "path": "doc/src/sgml/ref/update.sgml",
  "position": 4,
  "sha256": "47dd724cd724bd77478215a4853aa1f985996a0e5bba9b2451a1ad1ebb6e51fc",
  "source_id": "doc.update.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ref/update.sgml#L203-L211"
}

来源引用

完整定义与证据 JSON

定义来源

center · PostgreSQL 18 · english-manuals:ea437c8357667a89d3001ec920203a65b1f5087d24d2e4eaa5d31bfe0929cc46

正文语言: zh-Hans · english-manuals:ea437c8357667a89d3001ec920203a65b1f5087d24d2e4eaa5d31bfe0929cc46