# 22001 — string_data_right_truncation

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

# 22001

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

固定 varchar 路径报告 `value too long for type character(%d)`；hstore、varbit 等路径会使用各自的具体变体。

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

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

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

共享案例创建 `varchar_limits(value varchar(3))`，用 `'too-long'` 触发 22001，再插入修复值 `'ok'` 并查询存储值。应在自动提交下逐条发送这些语句：触发语句预期失败，之后再执行修复语句。案例运行器在结束阶段负责清理对象。

<!-- BEGIN SQLSTATE SNIPPET: varchar_width_overflow -->
```sql
CREATE TABLE varchar_limits (value varchar(3));
INSERT INTO varchar_limits VALUES ('too-long');
INSERT INTO varchar_limits VALUES ('ok');
SELECT value FROM varchar_limits;
```
<!-- END SQLSTATE SNIPPET -->

校准实测 `character varying(3)` 拒绝超长值并报告 `value too long for type character varying(3)`；修正值 `ok` 成功，运行器的两条自动提交会话均回到 `IDLE`。

## 报文 {#messages}

固定 character 和 varchar guard 以 `ERROR` 严重性报告 primary 模板 `value too long for type character(%d)` 与 `value too long for type character varying(%d)`。hstore 与 varbit 路径使用各自的 primary：`string too long for hstore key`、`string too long for hstore value` 和 `bit string too long for type bit varying(%d)`。这些源码组没有独立 DETAIL 或 HINT；本次运行只观察了上面的 varchar 模板。

## 含义 {#meaning}

当值无法满足字符串类型的长度契约时会出现 `22001`。PostgreSQL 按字符数而不是字节数计算 `character(n)` 和 `character varying(n)`，因此 `value too long for type character(%d)` 中的 `%d` 指向响应里的 typmod。固定 `varchar.c` 是服务器端检查；hstore 键值和 bit string 有各自的路径和消息。

值进入类型的方式也会改变边界。`varchar()` 和 `bpchar()` 都接收 `isExplicit` 标志：赋值/输入转换遇到超出的非空格字符会报错，而显式 cast 到有界类型可以按 PostgreSQL 字符类型规则截断；超出的尾随空格和非空格字符处理不同。修改存储或校验前应先明确这个选择。

## 诊断 {#diagnosis}

保存 `schema_name`、`table_name`、`column_name`、`datatype_name`、`routine` 和完整 message。先从目录确认目标类型和 typmod，再按字符数而不是字节数测量实际值。区分赋值/插入、显式 cast，以及 hstore/bit 路径，因为它们的截断行为并不完全相同。

常见 varchar 路径要检查超出宽度的后缀是否全是尾随空格。只有尾随空格超出时可能适用字符类型的截断规则；有意义的非空格数据应视为契约被拒绝。固定源码消息说明的是类型宽度问题，不是一般编码或网络错误。

## 处置 {#response}

选择能保留数据契约的修复：校验并拒绝超长输入，有意扩大列/类型，或只在业务明确允许时显式 cast 截断。截断前保存原值和目标 typmod；静默裁剪标识符、键或审计文本可能写入与调用方意图不同的内容。本次固定案例使用自动提交，失败语句结束后会话仍为 `IDLE`；显式事务中应先回滚整个事务，或回滚到语句前建立的保存点，再重试修正值。修正输入或 schema 后重新转换，并核对保存后的字符长度。

## 版本 {#versions}

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

## 相关条件 {#related}

[`22003`](../22003/) 是数值/范围越界，[`22007`](../22007/) 是日期时间格式错误，[`22004`](../22004/) 是独立的 NULL 契约。

## 来源 {#sources}

固定 `character(n)` 检查见 [`varchar.c#L300-L313`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/varchar.c#L300-L313)，`character varying(n)` 检查见 [`varchar.c#L633-L640`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/varchar.c#L633-L640)。PostgreSQL 18 的[字符类型文档](https://www.postgresql.org/docs/18/datatype-character.html)说明了字符数限制、尾随空格和显式 cast。结构化[证据记录](../../data/evidence/22001.json)固定了源码 SHA，并区分 hstore/varbit 变体。
