# 39P02 — srf_protocol_violated

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

# 39P02

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

39P02 是 `srf_protocol_violated`。固定 executor 源码确认它检查 set-returning function 的 value-per-call、materialize 以及 `returnMode` 契约。

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

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `39P02` |
| 条件名 | `srf_protocol_violated` |
| 状态 | `有效` |
| 已知存在于 | `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_E_R_I_E_SRF_PROTOCOL_VIOLATED` |
| 别名 | `—` |

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

## 含义 {#meaning}

SQL 执行器收到的 `ReturnSetInfo` 状态与函数声明/实现不一致时，会报告此条件：报文可能是 `table-function protocol for value-per-call mode was not followed`、`table-function protocol for materialize mode was not followed` 或 `unrecognized table-function returnMode: %d`。它描述 SRF 协议，不是普通 SELECT 的行数结果。

## 诊断 {#diagnosis}

从完整消息判断是哪一类模式，再检查扩展或 C 函数如何设置 `rsinfo.returnMode`、`isDone`、`returnSet` 以及结果存储。优先定位提供该 set-returning function 的函数体和部署版本；不要把客户端收到的空结果误判成 39P02。

## 处置 {#response}

修正 SRF 实现以遵守所选 value-per-call 或 materialize 协议，并重新验证其 `ReturnSetInfo` 字段与返回声明。修复函数契约后再重试调用；仅改变 SQL 的 LIMIT、事务或客户端重试策略不能修复该 executor 协议错误。

## 版本 {#versions}

锁定目录从 7.4 记录该条件，并在正式快照及 19beta3 中出现；固定报告该码的路径 为 PostgreSQL 18.6 `execSRF.c`。

## 相关条件 {#related}

[`39P01`](../39p01/), [`39P03`](../39p03/), [`2F002`](../2f002/)

## 来源 {#sources}

可直接阅读固定的 [execSRF.c](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/execSRF.c#L363-L381) 以及 materialize 路径（665-686 行）；完整范围见结构化[证据记录](../../data/evidence/39p02.json)。
