# 22004 — null_value_not_allowed

> PostgreSQL SQLSTATE 22004 的源码与诊断参考。
---

# 22004

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

22004 是 `null_value_not_allowed`。固定 table-function 路径报告 `namespace URI must not be null`；其他扩展和核心函数可能有不同的 NULL 契约。

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

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

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

共享案例向 XMLTABLE 提供 NULL namespace URI，然后使用 URI `u` 和匹配的 XML 行重做表函数调用。应分开发送两条 SELECT；第一条预期失败，之后再执行修复调用。会话和清理由运行器负责。

<!-- BEGIN SQLSTATE SNIPPET: xmltable_null_namespace -->
```sql
SELECT * FROM XMLTABLE(XMLNAMESPACES (NULL AS p), '/p:row' PASSING '<p:row xmlns:p="u"/>' COLUMNS x text PATH 'p:x');
SELECT count(*) FROM XMLTABLE(XMLNAMESPACES ('u' AS p), '/p:row' PASSING '<p:row xmlns:p="u"><p:x>ok</p:x></p:row>' COLUMNS x text PATH 'p:x');
```
<!-- END SQLSTATE SNIPPET -->

校准实测了表函数 namespace URI 路径：NULL namespace 报告 `namespace URI must not be null`；有效 URI 返回一行 XMLTABLE 结果，运行器的两条自动提交会话均回到 `IDLE`。

## 报文 {#messages}

namespace guard 以 `ERROR` 严重性报告 primary：`namespace URI must not be null`，没有独立 DETAIL 或 HINT。table-function executor 模块还分别检查 NULL row-filter 表达式和 NULL column-filter 表达式（DETAIL 会包含列名）。输出列 guard 的范围更窄：XMLTABLE 输出列标记为 NOT NULL 后，先取得值并应用 DEFAULT；只有仍为 NULL 时才报告 `null is not allowed in column "%s"`。这个条件不同于普通 NULL 结果或单独的 `23502` 约束错误；本次运行只观察了 namespace 报文。

## 含义 {#meaning}

`22004` 是 NULL 契约失败。固定 `nodeTableFuncscan.c` 路径拒绝 table function 使用的 namespace URI，消息为 `namespace URI must not be null`。同名条件也可能由其他函数选择，因此 NULL 函数参数、STRICT 函数返回的 NULL 和声明了 NOT NULL 的表列属于不同调查。普通 SQL NULL 结果本身不是 22004 的证据，应以实际 SQLSTATE 和诊断字段为准。

## 诊断 {#diagnosis}

用完整 message、routine、context 和对象字段确认哪个参数或 descriptor 为 NULL。已确认的 table-function 路径要检查 namespace URI 表达式，以及提供它的 XML/行描述。普通 NULL 输入或 STRICT 函数返回 NULL 本身并不表示该条件。如果响应指向列约束，应使用实际 SQLSTATE 和 constraint 字段；不要把列 NOT NULL 错误重新标成 22004。

## 处置 {#response}

修正消息所指的函数参数或 descriptor，或修改 table-function 定义以满足 namespace URI 契约。API 允许时应保留有意的 SQL NULL；把所有 NULL 换成空字符串可能改变 XML 或查询语义。本次固定案例使用自动提交，失败语句结束后会话仍为 `IDLE`；显式事务中应先回滚整个事务，或回滚到失败语句前已有的保存点，再继续执行。确认调用已修正后再重复写入。

## 版本 {#versions}

锁定目录从 7.4 记录该条件，并在列出的正式快照及 19beta3 中出现；固定源码覆盖为 PostgreSQL 18.6。

## 相关条件 {#related}

[`22000`](../22000/) 是其他 Data Exception 路径，[`22002`](../22002/) 是 ECPG 指示变量条件；若实际响应是 NOT NULL 约束错误，应按 [`23502`](../23502/) 调查。

## 来源 {#sources}

已确认的 table-function 检查见 [`nodeTableFuncscan.c#L368-L370`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/nodeTableFuncscan.c#L368-L370)；相邻的 filter/output guard 见 [`nodeTableFuncscan.c#L380-L419`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/nodeTableFuncscan.c#L380-L419) 和 [`nodeTableFuncscan.c#L494-L508`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/nodeTableFuncscan.c#L494-L508)。结构化[证据记录](../../data/evidence/22004.json)固定了这些路径，并把其他 NULL 契约保持为条件性说明。
