文档 / SQL 状态码 / Class 22 数据异常
22012 division_by_zero
ERROR 已实测 详解 实测通过
- 条件名
division_by_zero- 宏名称
ERRCODE_DIVISION_BY_ZERO- 启用版本
- 7.4
- 状态
- 活跃
版本覆盖
速览
除法或取模操作遇到零除数。PostgreSQL 18.6 在 numeric、整数、浮点、money 和 interval 除法路径中使用 SQLSTATE 22012,但每条路径仍有自己的操作数和特殊值规则。
SELECT 10::numeric / 0::numeric;
SELECT 10::numeric / 2::numeric;
保留的 PostgreSQL 18.6 和 10.21 实测显示,第一条语句返回 primary division by zero 与 SQLSTATE 22012,随后修正语句返回 5.0000000000000000;修复动作后两个后端均为 IDLE。公开案例 JSON 说明了这个 numeric 除法案例;它不是对下面所有生产路径的运行时比较。
含义
直接的 numeric_div 和 numeric_mod 会检查 numeric 零除数;内部 *_opt_error 形式也可以设置 have_error 标志并返回 NULL,由调用者自行处理。整数除法和取模函数在使用 / 或 % 前检查第二个操作数是否为零。float4/float8 除法经过 float*_div,当分子不是 NaN 且除数为零时抛错。money 除法检查整数或 money 除数,interval 除法检查浮点因子。这些路径共享 SQLSTATE 和 primary 文本,但实际解析出的运算符及特殊值仍决定结果。
诊断
在运算符和类型解析完成后定位除数或取模除数;不要把 int4 规则推广到全部数值类型。检查零是否来自输入、连接、聚合或业务规则,并阅读完整 primary。NULL 操作数通常在严格算术函数调用前得到 NULL;NULLIF(denominator, 0) 则是有意把零情况变为 NULL。CASE 可以选择 NULL、替代值或跳过分支,因此应选择符合业务结果的分支,不要静默地把错误改成另一个值。
还要区分规划期和执行期:PostgreSQL 18.6 的条件表达式文档警告,常量 1/0 子表达式即使位于运行时不会进入的 CASE 分支,也可能在规划期失败。规划器源码会递归简化常量参数并计算不可变的常量表达式。若必须延迟到执行期,应使用非恒定值,或在实际除数处使用 NULLIF/合适的 CASE;这不能让无效常量表达式变安全,也不能替应用决定 NULL 或替代值哪一种语义正确。
处理
修正产生零除数的来源,或明确选择零值策略。只有 NULL 结果符合业务含义时才使用 NULLIF;应用确有替代值或跳过规则时使用 CASE,然后检查下游聚合和过滤将看到的新结果。不要重放未改变的操作。普通固定路径抛出 ERROR;显式事务需先 ROLLBACK 或 ROLLBACK TO SAVEPOINT 再重试,自动提交只重试修正后的动作。保留的 18.6/10.21 numeric 实测仅覆盖这个案例。
可复现案例
在一次性实例上执行过的场景。其中 1 个附有可执行 SQL,正文相应小节里给出。
division_by_zero_numeric PG 10 / 18 有 SQL
前置条件
- A runner-owned disposable target is provisioned.
触发
Evaluate a numeric expression with a zero denominator.
断言
- SQLSTATE is 22012 with primary division by zero
- The failed autocommit session remains IDLE
- A nonzero denominator returns the defined numeric result
处置
Validate the denominator or apply an explicitly chosen domain policy; do not silently turn a calculation into NULL with NULLIF unless that is the intended business result.
清理
Close the runner connection and drop the case schema with an owner connection.
报文
- Primary,
ERROR:division by zero。 - 引用的 numeric、整数、浮点、money 和 interval 除法 guard 没有固定 DETAIL 或 HINT。内部 numeric
have_error调用是软处理路径,不能据此声称直接 SQL 运算成功返回。
报文模板
源码里的格式串,不是某一次运行的输出。%s 之类是占位符,实际报文会填入对象名与取值。适用范围一栏是核验时留下的原始英文记录,未经翻译。
division by zero
来源:src/backend/utils/adt/numeric.c @ REL_18_6 · src/backend/utils/adt/numeric.c @ REL_18_6 · src/backend/utils/adt/int.c @ REL_18_6 · src/backend/utils/adt/int.c @ REL_18_6 · src/backend/utils/adt/int8.c @ REL_18_6 · src/backend/utils/adt/int8.c @ REL_18_6 · src/include/utils/float.h @ REL_18_6 · src/backend/utils/adt/float.c @ REL_18_6 · src/backend/utils/adt/cash.c @ REL_18_6 · src/backend/utils/adt/cash.c @ REL_18_6 · src/backend/utils/adt/timestamp.c @ REL_18_6
适用范围:Direct cited guards; special values and internal numeric soft callers are type/context dependent.
版本
锁定目录从 7.4 起记录该条件;固定源码覆盖 PostgreSQL 18.6。保留的 numeric 运行记录是 PostgreSQL 18.6 和 10.21,仅覆盖 10::numeric / 0::numeric 后接 10::numeric / 2::numeric。
来源
- 上游源码 src/backend/utils/adt/cash.c
- 上游源码 src/backend/utils/adt/cash.c
- 上游源码 doc/src/sgml/func.sgml
- 上游源码 src/backend/utils/errcodes.txt 第 182 行
- 上游源码 src/backend/utils/adt/float.c
- 上游源码 src/include/utils/float.h
- 上游源码 src/backend/utils/adt/int.c
- 上游源码 src/backend/utils/adt/int.c
- 上游源码 src/backend/utils/adt/int8.c
- 上游源码 src/backend/utils/adt/int8.c
- 上游源码 src/backend/utils/adt/timestamp.c
- 上游源码 src/backend/utils/adt/numeric.c
- 上游源码 src/backend/utils/adt/numeric.c
- 上游源码 src/backend/optimizer/util/clauses.c
- 核验材料 verify/cases/22012/snippets.json
证据
断言
每条断言都写明了是怎么核实的,以及它不覆盖什么。这一层是核验时留下的原始英文记录,照原样呈现,未经翻译。
-
22012 is division_by_zero in SQLSTATE Class 22.
-
Numeric division and modulo guard zero divisors; direct SQL calls raise, while internal opt-error forms can report through a have_error soft path.
-
The int4 and int8 division and modulo functions check their second operand before using the arithmetic operator.
-
float4/float8 division raises for a zero divisor only when the numerator is not NaN, through the inline zero-divide helper.
-
Money division checks its divisor and interval division rejects a zero factor with the same condition.
-
The planner can evaluate an immutable constant division while simplifying expressions; same-tag conditional-expression documentation calls out unreachable CASE 1/0 as a planning-time failure boundary.
-
The retained numeric division case observed 22012 for 10::numeric / 0::numeric and 5.0000000000000000 after 10::numeric / 2::numeric on PostgreSQL 18.6 and 10.21; both repaired sessions were IDLE.
-
The locked catalogue records 22012 from 7.4 without proving an exact implementation introduction date.
运行记录
| 目标 | 服务器版本 | 结果 | 覆盖案例 |
|---|---|---|---|
| latest | 18.6 (Homebrew) | passed | division_by_zero_numeric |
| pg10 | 10.21 (Debian 10.21-1.pgdg90+1) | passed | division_by_zero_numeric |
同类 SQL 状态码
| 状态码 | 条件名 | 宏名称 | 严重等级 | 版本 |
|---|---|---|---|---|
| 22000 | data_exception | ERRCODE_DATA_EXCEPTION |
ERROR | 7.4 |
| 数据异常的通用类别,具体原因见成员码。 | 活跃 | |||
| 22001 | string_data_right_truncation | ERRCODE_STRING_DATA_RIGHT_TRUNCATION |
ERROR | 7.4 |
| 值超过目标类型长度而被右截断。 | 活跃 | |||
| 22002 | null_value_no_indicator_parameter | ERRCODE_NULL_VALUE_NO_INDICATOR_PARAMETER |
ERROR | 7.4 |
| 返回 NULL 但没有提供指示变量,见于 ECPG。 | 活跃 | |||
| 22003 | numeric_value_out_of_range | ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE |
ERROR | 7.4 |
| 数值超出目标类型范围,如整数溢出。 | 活跃 | |||
| 22004 | null_value_not_allowed | ERRCODE_NULL_VALUE_NOT_ALLOWED |
ERROR | 7.4 |
| 参数或值不允许为 NULL。 | 活跃 | |||
| 22005 | error_in_assignment | ERRCODE_ERROR_IN_ASSIGNMENT |
ERROR | 7.4 |
| 赋值违反目标变量契约,如变量声明为 CONSTANT。 | 活跃 | |||
| 22007 | invalid_datetime_format | ERRCODE_INVALID_DATETIME_FORMAT |
ERROR | 7.4 |
| 日期时间格式串无效,如 interval 格式错误。 | 活跃 | |||
| 22008 | datetime_field_overflow | ERRCODE_DATETIME_FIELD_OVERFLOW |
ERROR | 7.4 |
| 日期或时间字段取值越界。 | 活跃 | |||
| 22009 | invalid_time_zone_displacement_value | ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE |
ERROR | 7.4 |
| 时区偏移量超出支持范围。 | 活跃 | |||
| 2200B | escape_character_conflict | ERRCODE_ESCAPE_CHARACTER_CONFLICT |
ERROR | 7.4 |
| 转义字符与其他字符冲突。 | 活跃 | |||
| 2200C | invalid_use_of_escape_character | ERRCODE_INVALID_USE_OF_ESCAPE_CHARACTER |
ERROR | 7.4 |
| 转义字符用法无效,如 SIMILAR TO 模式错误。 | 活跃 | |||
| 2200D | invalid_escape_octet | ERRCODE_INVALID_ESCAPE_OCTET |
ERROR | 7.4 |
| 转义八位组无效的数据异常条件。 | 活跃 | |||
| 2200F | zero_length_character_string | ERRCODE_ZERO_LENGTH_CHARACTER_STRING |
ERROR | 7.4 |
| 操作拒绝了零长度字符串。 | 活跃 | |||
| 2200G | most_specific_type_mismatch | ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH |
ERROR | 7.4 |
| 无法确定值的最具体类型,类型不匹配。 | 活跃 | |||
| 2200H | sequence_generator_limit_exceeded | ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED |
ERROR | 10 |
| nextval 触及序列的最大值或最小值。 | 活跃 | |||
| 2200L | not_an_xml_document | ERRCODE_NOT_AN_XML_DOCUMENT |
ERROR | 8.3 |
| 输入不满足 XML DOCUMENT 形式要求。 | 活跃 | |||
| 2200M | invalid_xml_document | ERRCODE_INVALID_XML_DOCUMENT |
ERROR | 8.3 |
| XML 文档解析失败,文档无效。 | 活跃 | |||
| 2200N | invalid_xml_content | ERRCODE_INVALID_XML_CONTENT |
ERROR | 8.3 |
| XML 内容无效,未通过 CONTENT 模式解析。 | 活跃 | |||
| 2200S | invalid_xml_comment | ERRCODE_INVALID_XML_COMMENT |
ERROR | 8.3 |
| XML 注释无效,含 -- 或以 - 结尾。 | 活跃 | |||
| 2200T | invalid_xml_processing_instruction | ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION |
ERROR | 8.3 |
| XML 处理指令无效,目标名或内容非法。 | 活跃 | |||
| 22010 | invalid_indicator_parameter_value | ERRCODE_INVALID_INDICATOR_PARAMETER_VALUE |
ERROR | 7.4 |
| 指示参数取值不符合规则。 | 活跃 | |||
| 22011 | substring_error | ERRCODE_SUBSTRING_ERROR |
ERROR | 7.4 |
| substring 长度参数为负等取子串错误。 | 活跃 | |||
| 22012 | division_by_zero | ERRCODE_DIVISION_BY_ZERO |
ERROR | 7.4 |
| 除法或取模运算遇到零除数。 | 活跃 | |||
| 22013 | invalid_preceding_or_following_size | ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE |
ERROR | 11 |
| 窗口帧的 PRECEDING/FOLLOWING 偏移为负。 | 活跃 | |||
| 22014 | invalid_argument_for_ntile_function | ERRCODE_INVALID_ARGUMENT_FOR_NTILE |
ERROR | 8.4 |
| ntile 的桶数量必须大于零。 | 活跃 | |||
| 22015 | interval_field_overflow | ERRCODE_INTERVAL_FIELD_OVERFLOW |
ERROR | 7.4 |
| interval 输入字段超出可接受范围。 | 活跃 | |||
| 22016 | invalid_argument_for_nth_value_function | ERRCODE_INVALID_ARGUMENT_FOR_NTH_VALUE |
ERROR | 8.4 |
| nth_value 的序号必须大于零。 | 活跃 | |||
| 22018 | invalid_character_value_for_cast | ERRCODE_INVALID_CHARACTER_VALUE_FOR_CAST |
ERROR | 7.4 |
| 字符值无法通过所要求的类型转换。 | 活跃 | |||
| 22019 | invalid_escape_character | ERRCODE_INVALID_ESCAPE_CHARACTER |
ERROR | 7.4 |
| 操作拒绝了给定的转义字符。 | 活跃 | |||
| 2201B | invalid_regular_expression | ERRCODE_INVALID_REGULAR_EXPRESSION |
ERROR | 7.4 |
| 正则表达式无效,编译或执行阶段被拒绝。 | 活跃 | |||
| 2201E | invalid_argument_for_logarithm | ERRCODE_INVALID_ARGUMENT_FOR_LOG |
ERROR | 8.0 |
| 对数函数参数为零或负数。 | 活跃 | |||
| 2201F | invalid_argument_for_power_function | ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION |
ERROR | 8.0 |
| 幂运算参数使实数结果无定义。 | 活跃 | |||
| 2201G | invalid_argument_for_width_bucket_function | ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION |
ERROR | 8.0 |
| width_bucket 参数无效,如桶数非正。 | 活跃 | |||
| 2201W | invalid_row_count_in_limit_clause | ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE |
ERROR | 8.4 |
| LIMIT 行数无效,不能为负。 | 活跃 | |||
| 2201X | invalid_row_count_in_result_offset_clause | ERRCODE_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE |
ERROR | 8.4 |
| OFFSET 行数无效,不能为负。 | 活跃 | |||
| 22021 | character_not_in_repertoire | ERRCODE_CHARACTER_NOT_IN_REPERTOIRE |
ERROR | 7.4 |
| 字节序列对目标编码无效。 | 活跃 | |||
| 22022 | indicator_overflow | ERRCODE_INDICATOR_OVERFLOW |
ERROR | 7.4 |
| 指示变量容纳不下接口返回的结果。 | 活跃 | |||
| 22023 | invalid_parameter_value | ERRCODE_INVALID_PARAMETER_VALUE |
ERROR | 7.4 |
| 参数或选项取值超出允许范围。 | 活跃 | |||
| 22024 | unterminated_c_string | ERRCODE_UNTERMINATED_C_STRING |
ERROR | 7.4 |
| C 风格字符串缺少终止符。 | 活跃 | |||
| 22025 | invalid_escape_sequence | ERRCODE_INVALID_ESCAPE_SEQUENCE |
ERROR | 7.4 |
| 转义序列无效,如 ESCAPE 参数非单字符。 | 活跃 | |||
| 22026 | string_data_length_mismatch | ERRCODE_STRING_DATA_LENGTH_MISMATCH |
ERROR | 7.4 |
| 位串长度与声明的类型长度不一致。 | 活跃 | |||
| 22027 | trim_error | ERRCODE_TRIM_ERROR |
ERROR | 7.4 |
| trim 操作的参数或裁剪规格无效。 | 活跃 | |||
| 2202E | array_subscript_error | ERRCODE_ARRAY_SUBSCRIPT_ERROR |
ERROR | 7.4 |
| 数组下标或维度错误,如拼接维度不兼容。 | 活跃 | |||
| 2202G | invalid_tablesample_repeat | ERRCODE_INVALID_TABLESAMPLE_REPEAT |
ERROR | 9.5 |
| TABLESAMPLE 的 REPEATABLE 种子不能为空。 | 活跃 | |||
| 2202H | invalid_tablesample_argument | ERRCODE_INVALID_TABLESAMPLE_ARGUMENT |
ERROR | 9.5 |
| TABLESAMPLE 方法收到越界的采样参数。 | 活跃 | |||
| 22030 | duplicate_json_object_key_value | ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE |
ERROR | 12 |
| 构造 JSON 对象时出现重复键。 | 活跃 | |||
| 22031 | invalid_argument_for_sql_json_datetime_function | ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION |
ERROR | 13 |
| SQL/JSON datetime 方法的参数或格式无效。 | 活跃 | |||
| 22032 | invalid_json_text | ERRCODE_INVALID_JSON_TEXT |
ERROR | 12 |
| JSON 文本无效,无法被消费方解析。 | 活跃 | |||
| 22033 | invalid_sql_json_subscript | ERRCODE_INVALID_SQL_JSON_SUBSCRIPT |
ERROR | 12 |
| SQL/JSON 数组下标无效,如越界或非数值。 | 活跃 | |||
| 22034 | more_than_one_sql_json_item | ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM |
ERROR | 12 |
| SQL/JSON 结果多于一项,需要单项。 | 活跃 | |||
| 22035 | no_sql_json_item | ERRCODE_NO_SQL_JSON_ITEM |
ERROR | 12 |
| 指定 SQL/JSON path 没有找到任何项。 | 活跃 | |||
| 22036 | non_numeric_sql_json_item | ERRCODE_NON_NUMERIC_SQL_JSON_ITEM |
ERROR | 12 |
| JSON 路径项方法收到非数值的项。 | 活跃 | |||
| 22037 | non_unique_keys_in_a_json_object | ERRCODE_NON_UNIQUE_KEYS_IN_A_JSON_OBJECT |
ERROR | 12 |
| JSON 对象中的键不唯一。 | 活跃 | |||
| 22038 | singleton_sql_json_item_required | ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED |
ERROR | 12 |
| SQL/JSON 路径要求单一指定类型的结果。 | 活跃 | |||
| 22039 | sql_json_array_not_found | ERRCODE_SQL_JSON_ARRAY_NOT_FOUND |
ERROR | 12 |
| JSON 路径访问器要求数组却收到非数组项。 | 活跃 | |||
| 2203A | sql_json_member_not_found | ERRCODE_SQL_JSON_MEMBER_NOT_FOUND |
ERROR | 12 |
| JSON 对象成员不存在或当前项不是对象。 | 活跃 | |||
| 2203B | sql_json_number_not_found | ERRCODE_SQL_JSON_NUMBER_NOT_FOUND |
ERROR | 12 |
| jsonpath 一元运算收到非数值的项。 | 活跃 | |||
| 2203C | sql_json_object_not_found | ERRCODE_SQL_JSON_OBJECT_NOT_FOUND |
ERROR | 12 |
| JSON 路径访问器要求对象却收到非对象项。 | 活跃 | |||
| 2203D | too_many_json_array_elements | ERRCODE_TOO_MANY_JSON_ARRAY_ELEMENTS |
ERROR | 12 |
| JSON 数组元素数量过多。 | 活跃 | |||
| 2203E | too_many_json_object_members | ERRCODE_TOO_MANY_JSON_OBJECT_MEMBERS |
ERROR | 12 |
| JSON 对象成员数量过多。 | 活跃 | |||
| 2203F | sql_json_scalar_required | ERRCODE_SQL_JSON_SCALAR_REQUIRED |
ERROR | 12 |
| JSON_VALUE 要求标量,收到的项不是标量。 | 活跃 | |||
| 2203G | sql_json_item_cannot_be_cast_to_target_type | ERRCODE_SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE |
ERROR | 15 |
| SQL/JSON 项无法转换为目标类型。 | 活跃 | |||
| 22P01 | floating_point_exception | ERRCODE_FLOATING_POINT_EXCEPTION |
ERROR | 7.4 |
| 浮点异常,进程收到 SIGFPE 信号。 | 活跃 | |||
| 22P02 | invalid_text_representation | ERRCODE_INVALID_TEXT_REPRESENTATION |
ERROR | 7.4 |
| 文本无法解析为目标类型,如整数输入非法。 | 活跃 | |||
| 22P03 | invalid_binary_representation | ERRCODE_INVALID_BINARY_REPRESENTATION |
ERROR | 7.4 |
| 二进制数据格式无效,如 Bind 参数或二进制 COPY。 | 活跃 | |||
| 22P04 | bad_copy_file_format | ERRCODE_BAD_COPY_FILE_FORMAT |
ERROR | 7.4 |
| COPY 文件结构错误,如字段数或头部不符。 | 活跃 | |||
| 22P05 | untranslatable_character | ERRCODE_UNTRANSLATABLE_CHARACTER |
ERROR | 7.4 |
| 字符在目标编码中没有对应表示。 | 活跃 | |||
| 22P06 | nonstandard_use_of_escape_character | ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER |
ERROR | 8.1 |
| 字符串字面量中反斜杠转义用法非标准。 | 活跃 | |||