# 44000 — with_check_option_violation（WITH CHECK OPTION 违规）

> PostgreSQL SQLSTATE 44000：视图 WITH CHECK OPTION 的诊断与修复。
---

# 44000 — with_check_option_violation（WITH CHECK OPTION 违规）

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

`44000` 表示通过视图写入的行不满足该视图的 `WITH CHECK OPTION` 谓词。它保护的是视图写入不变量，不是表级 `CHECK` 对应的 `23514`。

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

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

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

## 含义 {#meaning}

可自动更新的视图声明 `WITH CHECK OPTION` 后，PostgreSQL 会检查插入或更新后的行是否仍能通过该视图看到。执行器把视图谓词的 `FALSE` 和 `NULL` 都视为失败，因此可空谓词列的未知结果也不能通过。`ExecWithCheckOptions` 报告 `new row violates check option for view "%s"`；只有权限允许描述该行时才附带动态失败行 DETAIL。`LOCAL` 只检查当前视图直接定义的条件；底层视图条件不会检查，除非那些底层视图也指定了 `CHECK OPTION`。`CASCADED` 检查当前视图以及所有底层视图条件。`CHECK OPTION` 只支持没有 `INSTEAD OF` 触发器或规则的自动可更新视图；底层可由触发器更新的视图和 `INSTEAD` 重写都是独立边界，级联检查可能在这些边界停止或全部被忽略。选定自然案例使用的是直接可更新视图。

## 诊断 {#diagnosis}

保存 SQLSTATE、视图名称、存在时的 DETAIL，以及通过视图发送的实际行值。用 `pg_get_viewdef()` 查看定义，并按 SQL 三值逻辑计算谓词：只有 `TRUE` 可见，`FALSE` 和 `NULL` 都会失败。确认视图是否自动可更新、使用的是 `LOCAL` 还是 `CASCADED`，以及底层视图是否有 `INSTEAD OF` 触发器或 `INSTEAD` 重写。不要只搜索表 CHECK 约束：`LOCAL` 不检查普通底层视图谓词，而 `CASCADED` 会检查这些谓词，除非遇到可由触发器更新或被重写的边界。缺少 DETAIL 可能是权限边界，不能据此判断没有进行行检查。

## 处理 {#response}

让行的谓词结果为 `TRUE`；只有确认模式契约和 `LOCAL`/`CASCADED` 范围后才修改视图定义。如果视图是受保护的过滤写入接口，应保留 check option。如果涉及底层触发器可更新的视图或 `INSTEAD` 重写，应检查该边界及其实际生效的检查，不要假定级联检查已经到达那里。选定自动提交案例的错误后连接仍为 `IDLE`；若在显式事务中发生，则先回滚失败块，再用合法行重试。

## 报文 {#messages}

固定源码模板是 `new row violates check option for view "%s"` 和 `Failing row contains %s.`。视图名称和行渲染都是动态值。DETAIL 是诊断数据，解析器必须考虑用户值和格式变化。

## 代表案例 {#case}

共享 registry `verify/cases/44000/snippets.json`（SHA-256 `7b227bca904c860388c6cf1f5b7f551412b4d67832fb91aaa682f4126072e41c`）创建过滤视图，先尝试谓词外的行，再插入合法行。见[公开案例导出](../../data/cases/44000.json)和[结构化证据](../../data/evidence/44000.json)。

<!-- BEGIN SQLSTATE SNIPPET: view_check_option_recovery -->

```sql
CREATE TABLE items(id integer PRIMARY KEY, visible boolean NOT NULL, note text NOT NULL);
CREATE VIEW visible_items AS SELECT id, visible, note FROM items WHERE visible WITH CHECK OPTION;
INSERT INTO visible_items VALUES (1, false, 'hidden');
INSERT INTO visible_items VALUES (1, true, 'visible');
SELECT id, visible, note FROM visible_items ORDER BY id;
```
<!-- END SQLSTATE SNIPPET -->

运行器会在私有 schema 中限定 registry 的表名。它断言服务器自然产生的 SQLSTATE 和视图诊断，并核对只有可见行被接受。

选定案例在 PostgreSQL 18.6 和 10.21 通过带 `WITH CHECK OPTION` 的视图插入 `visible = false` 行时观察到 `44000`。DETAIL 给出失败行；自动提交连接保持 `IDLE`，满足谓词的行随后插入成功。

## 版本 {#versions}

锁定目录从早期历史边界到正式快照都记录了该条件。固定源码在 18.6 和 10.23 都包含同一机制；选定运行只覆盖 18.6 与 10.21 的简单视图插入，不涵盖所有视图规则组合。

## 相关 {#related}

可对照表 CHECK 的[23514 检查约束违规](../23514/)和触发器驱动的[27000 触发的数据更改违规](../27000/)。

## 来源 {#sources}

- [`src.errcodes.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt)（SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba`）
- [`src.execMain.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/execMain.c#L2322-L2327)（SHA-256 `33b97337fa23a649c5e7a092e1bd405a54e8503529236c62c9d5bb93a1774a8d`）
- [`CREATE VIEW 官方文档`](https://www.postgresql.org/docs/18/sql-createview.html) · 本地调用扫描 `src.calls.REL_18_6`（SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf`）
