22012 — division_by_zero
除法或取模运算遇到零除数。
英文手册覆盖始于 PostgreSQL 8.1. 来源历史与运行验证各自保留独立版本边界。
当前阅读 PG 18·选择有来源记录的版本
- aliases
- 未知
- class name
- Data Exception
- condition name
- division_by_zero
- lang
- en
- sqlstate
- 22012
版本定义 PG 18
速览 {#at-a-glance}
除法或取模操作遇到零除数。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 除法案例;它不是对下面所有生产路径的运行时比较。
含义 {#meaning}
直接的 numeric_div 和 numeric_mod 会检查 numeric 零除数;内部 *_opt_error 形式也可以设置 have_error 标志并返回 NULL,由调用者自行处理。整数除法和取模函数在使用 / 或 % 前检查第二个操作数是否为零。float4/float8 除法经过 float*_div,当分子不是 NaN 且除数为零时抛错。money 除法检查整数或 money 除数,interval 除法检查浮点因子。这些路径共享 SQLSTATE 和 primary 文本,但实际解析出的运算符及特殊值仍决定结果。
诊断 {#diagnosis}
在运算符和类型解析完成后定位除数或取模除数;不要把 int4 规则推广到全部数值类型。检查零是否来自输入、连接、聚合或业务规则,并阅读完整 primary。NULL 操作数通常在严格算术函数调用前得到 NULL;NULLIF(denominator, 0) 则是有意把零情况变为 NULL。CASE 可以选择 NULL、替代值或跳过分支,因此应选择符合业务结果的分支,不要静默地把错误改成另一个值。
还要区分规划期和执行期:PostgreSQL 18.6 的条件表达式文档警告,常量 1/0 子表达式即使位于运行时不会进入的 CASE 分支,也可能在规划期失败。规划器源码会递归简化常量参数并计算不可变的常量表达式。若必须延迟到执行期,应使用非恒定值,或在实际除数处使用 NULLIF/合适的 CASE;这不能让无效常量表达式变安全,也不能替应用决定 NULL 或替代值哪一种语义正确。
处理 {#response}
修正产生零除数的来源,或明确选择零值策略。只有 NULL 结果符合业务含义时才使用 NULLIF;应用确有替代值或跳过规则时使用 CASE,然后检查下游聚合和过滤将看到的新结果。不要重放未改变的操作。普通固定路径抛出 ERROR;显式事务需先 ROLLBACK 或 ROLLBACK TO SAVEPOINT 再重试,自动提交只重试修正后的动作。保留的 18.6/10.21 numeric 实测仅覆盖这个案例。
报文 {#messages}
- Primary,
ERROR:division by zero。 - 引用的 numeric、整数、浮点、money 和 interval 除法 guard 没有固定 DETAIL 或 HINT。内部 numeric
have_error调用是软处理路径,不能据此声称直接 SQL 运算成功返回。
版本 {#versions}
锁定目录从 7.4 起记录该条件;固定源码覆盖 PostgreSQL 18.6。保留的 numeric 运行记录是 PostgreSQL 18.6 和 10.21,仅覆盖 10::numeric / 0::numeric 后接 10::numeric / 2::numeric。
相关 {#related}
来源 {#sources}
src/backend/utils/adt/numeric.c#L3243-L3375展示 numeric 除法、特殊值、直接ERROR和内部have_error分支;#L3467-L3553展示 numeric 取模。src/backend/utils/adt/int.c#L861-L875和#L1158-L1184展示整数除法和取模;int8.c有对应的 bigint guard。src/include/utils/float.h#L222-L250与src/backend/utils/adt/float.c#L101-L106展示 float4/float8 零除数分派及 primary。src/backend/utils/adt/cash.c#L155-L161和#L728-L744展示 money 除法 guard;src/backend/utils/adt/timestamp.c#L3759-L3776展示 interval 除以零因子。src/backend/optimizer/util/clauses.c#L2437-L2462展示常量简化/计算;同版条件表达式文档说明不可达CASE中1/0的规划期边界。
结构化证据记录保留两份运行摘要/原始摘要哈希和固定源码声明。
比较版本
SQLSTATE 证据与已记录的运行版本
cases · division_by_zero_numeric
{
"assertions": [
"SQLSTATE is 22012 with primary division by zero",
"The failed autocommit session remains IDLE",
"A nonzero denominator returns the defined numeric result"
],
"case_id": "division_by_zero_numeric",
"cleanup": "Close the runner connection and drop the case schema with an owner connection.",
"has_snippet": true,
"position": 0,
"preconditions": [
"A runner-owned disposable target is provisioned."
],
"repair": "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.",
"trigger": "Evaluate a numeric expression with a zero denominator.",
"versions": [
"10",
"18"
]
}claims · identity
{
"claim_id": "identity",
"limits": "",
"method": "Read the fixed errcodes row and macro.",
"position": 0,
"runtime": [],
"sources": [
"src.errcodes.18.6"
],
"statement": "22012 is division_by_zero in SQLSTATE Class 22."
}claims · numeric-divmod
{
"claim_id": "numeric-divmod",
"limits": "",
"method": "Read the complete numeric division and modulo functions.",
"position": 1,
"runtime": [],
"sources": [
"src.numeric-div.18.6",
"src.numeric-mod.18.6"
],
"statement": "Numeric division and modulo guard zero divisors; direct SQL calls raise, while internal opt-error forms can report through a have_error soft path."
}claims · integer-divmod
{
"claim_id": "integer-divmod",
"limits": "",
"method": "Read the representative integer and bigint guards.",
"position": 2,
"runtime": [],
"sources": [
"src.int-div.18.6",
"src.int-mod.18.6",
"src.int8-div.18.6",
"src.int8-mod.18.6"
],
"statement": "The int4 and int8 division and modulo functions check their second operand before using the arithmetic operator."
}claims · float-guard
{
"claim_id": "float-guard",
"limits": "",
"method": "Read the exact val2==0 and !isnan(val1) guard.",
"position": 3,
"runtime": [],
"sources": [
"src.float-inline.18.6",
"src.float-error.18.6"
],
"statement": "float4/float8 division raises for a zero divisor only when the numerator is not NaN, through the inline zero-divide helper."
}claims · money-and-interval
{
"claim_id": "money-and-interval",
"limits": "",
"method": "Read the type-specific division guards.",
"position": 4,
"runtime": [],
"sources": [
"src.cash-int.18.6",
"src.cash-money.18.6",
"src.interval-div.18.6"
],
"statement": "Money division checks its divisor and interval division rejects a zero factor with the same condition."
}claims · planner-boundary
{
"claim_id": "planner-boundary",
"limits": "This is a planning/execution boundary, not an assertion that every CASE expression is evaluated early.",
"method": "Read the planner evaluation path and same-tag documentation.",
"position": 5,
"runtime": [],
"sources": [
"src.planner-const.18.6",
"src.docs-conditional.18.6"
],
"statement": "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."
}claims · runtime.observation
{
"claim_id": "runtime.observation",
"limits": "The observation covers this numeric case and does not generalize to every producer.",
"method": "Read both retained summaries, raw digests, and the fixed snippet registry.",
"position": 6,
"runtime": [],
"sources": [
"runtime.22012-data-runtime-latest.latest",
"runtime.22012-data-runtime-pg10.pg10",
"snippet-registry.22012"
],
"statement": "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."
}claims · history
{
"claim_id": "history",
"limits": "",
"method": "Use catalogue presence and history boundaries.",
"position": 7,
"runtime": [],
"sources": [
"src.errcodes.18.6"
],
"statement": "The locked catalogue records 22012 from 7.4 without proving an exact implementation introduction date."
}messages · message.division-by-zero
{
"limits": "Direct cited guards; special values and internal numeric soft callers are type/context dependent.",
"message_id": "message.division-by-zero",
"path": "",
"position": 0,
"raw": {
"id": "message.division-by-zero",
"limits": "Direct cited guards; special values and internal numeric soft callers are type/context dependent.",
"primary_template": "division by zero",
"severity_source": "ERROR",
"sources": [
"src.numeric-div.18.6",
"src.numeric-mod.18.6",
"src.int-div.18.6",
"src.int-mod.18.6",
"src.int8-div.18.6",
"src.int8-mod.18.6",
"src.float-inline.18.6",
"src.float-error.18.6",
"src.cash-int.18.6",
"src.cash-money.18.6",
"src.interval-div.18.6"
],
"sqlstate": "22012"
},
"severity": "ERROR",
"sources": [
"src.numeric-div.18.6",
"src.numeric-mod.18.6",
"src.int-div.18.6",
"src.int-mod.18.6",
"src.int8-div.18.6",
"src.int8-mod.18.6",
"src.float-inline.18.6",
"src.float-error.18.6",
"src.cash-int.18.6",
"src.cash-money.18.6",
"src.interval-div.18.6"
],
"templates": [
{
"kind": "primary",
"literal": "division by zero",
"position": 0,
"role": "",
"template": "division by zero"
}
]
}runtimes · runtime.22012-data-runtime-latest.latest · 18.6 (Homebrew) · passed
{
"cases": [
"division_by_zero_numeric"
],
"limits": "",
"position": 0,
"raw": {
"cases": [
"division_by_zero_numeric"
],
"id": "runtime.22012-data-runtime-latest.latest",
"observed": {
"sqlstate": "22012",
"status_after_repair": "IDLE"
},
"raw": "verify/results/22012-data-runtime-latest/latest/raw.jsonl",
"raw_sha256": "9d7035f924444adf1fa68308787310083c584343376d7b041e803a3bd2e1b539",
"run_id": "22012-data-runtime-latest",
"server_version": "18.6 (Homebrew)",
"server_version_num": 180006,
"snippet_registry": {
"path": "verify/cases/22012/snippets.json",
"sha256": "d070ef39a492c0411c3fc2cf9cc841321cae85cbd8a2f8d169f49ecbadbd3be7"
},
"status": "passed",
"summary": "verify/results/22012-data-runtime-latest/latest/summary.json",
"summary_sha256": "a92ed17a37d32b0a6dc3f30c2b900f4d643fa0dea2736110b1d6170ccba4157c",
"target": "latest"
},
"run_id": "22012-data-runtime-latest",
"runtime_id": "runtime.22012-data-runtime-latest.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.22012-data-runtime-pg10.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"division_by_zero_numeric"
],
"limits": "",
"position": 1,
"raw": {
"cases": [
"division_by_zero_numeric"
],
"id": "runtime.22012-data-runtime-pg10.pg10",
"observed": {
"sqlstate": "22012",
"status_after_repair": "IDLE"
},
"raw": "verify/results/22012-data-runtime-pg10/pg10/raw.jsonl",
"raw_sha256": "e8b465904879a89b453d291d4cabddcfe8920ea8c9752f83213644e84f6510f2",
"run_id": "22012-data-runtime-pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"server_version_num": 100021,
"snippet_registry": {
"path": "verify/cases/22012/snippets.json",
"sha256": "d070ef39a492c0411c3fc2cf9cc841321cae85cbd8a2f8d169f49ecbadbd3be7"
},
"status": "passed",
"summary": "verify/results/22012-data-runtime-pg10/pg10/summary.json",
"summary_sha256": "60991b51352ba0c2294f65719ada02e39aba969e7467755b138febedcd548e50",
"target": "pg10"
},
"run_id": "22012-data-runtime-pg10",
"runtime_id": "runtime.22012-data-runtime-pg10.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}sources · src.errcodes.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/errcodes.txt",
"position": 0,
"sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
"source_id": "src.errcodes.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L182"
}sources · src.numeric-div.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/numeric.c",
"position": 1,
"sha256": "6cde7cd60b3330b83be35d1f014045f5fb5fe737f3c5db4c8ed4080b99f2b666",
"source_id": "src.numeric-div.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/numeric.c#L3243-3375"
}sources · src.numeric-mod.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/numeric.c",
"position": 2,
"sha256": "6cde7cd60b3330b83be35d1f014045f5fb5fe737f3c5db4c8ed4080b99f2b666",
"source_id": "src.numeric-mod.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/numeric.c#L3467-3553"
}sources · src.int-div.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/int.c",
"position": 3,
"sha256": "ed5a4718016a9acaf68eb08d97bb5c8973c450444dca57e0b953d11c99695e77",
"source_id": "src.int-div.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/int.c#L861-875"
}sources · src.int-mod.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/int.c",
"position": 4,
"sha256": "ed5a4718016a9acaf68eb08d97bb5c8973c450444dca57e0b953d11c99695e77",
"source_id": "src.int-mod.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/int.c#L1158-1184"
}sources · src.int8-div.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/int8.c",
"position": 5,
"sha256": "da4d3688c0b037346f25419ea31020af9fec54021f182370234dcbf70b748f36",
"source_id": "src.int8-div.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/int8.c#L503-517"
}sources · src.int8-mod.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/int8.c",
"position": 6,
"sha256": "da4d3688c0b037346f25419ea31020af9fec54021f182370234dcbf70b748f36",
"source_id": "src.int8-mod.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/int8.c#L559-588"
}sources · src.float-inline.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/include/utils/float.h",
"position": 7,
"sha256": "e41d97d3eff1ee8447f56562cdf649733330b56f07ee3d81325ee096ff5fd446",
"source_id": "src.float-inline.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/include/utils/float.h#L222-250"
}sources · src.float-error.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/float.c",
"position": 8,
"sha256": "58914ae93c06c281e581a4bb2dcf2280e4ae1619f3ceb8f801f50beca87eecd8",
"source_id": "src.float-error.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/float.c#L101-106"
}sources · src.cash-int.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/cash.c",
"position": 9,
"sha256": "a6b9d7af9e8d697b737a5ed5ae98226ed317ec75c06f3fb2dcb057a6bd6a92b3",
"source_id": "src.cash-int.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/cash.c#L155-161"
}sources · src.cash-money.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/cash.c",
"position": 10,
"sha256": "a6b9d7af9e8d697b737a5ed5ae98226ed317ec75c06f3fb2dcb057a6bd6a92b3",
"source_id": "src.cash-money.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/cash.c#L728-744"
}sources · src.interval-div.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/adt/timestamp.c",
"position": 11,
"sha256": "2614ccd2182fa904b4cac9bef43039e90a1af578d2d1c6803d49a07420d168f2",
"source_id": "src.interval-div.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/timestamp.c#L3759-3776"
}sources · src.planner-const.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/optimizer/util/clauses.c",
"position": 12,
"sha256": "7268380af5eccec9e3bf90179f0a2753a7f50426d62af143a451b7f0fb542732",
"source_id": "src.planner-const.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/optimizer/util/clauses.c#L2437-2462"
}sources · src.docs-conditional.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "doc/src/sgml/func.sgml",
"position": 13,
"sha256": "05d03f505dc3c3b4fb2b3a6e8ed3275c425306a8ff20dd9548e838c26bbb968a",
"source_id": "src.docs-conditional.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/func.sgml#L20143-20150"
}sources · snippet-registry.22012
{
"commit": "",
"docs_url": "",
"kind": "local_artifact",
"location": "",
"path": "verify/cases/22012/snippets.json",
"position": 14,
"sha256": "d070ef39a492c0411c3fc2cf9cc841321cae85cbd8a2f8d169f49ecbadbd3be7",
"source_id": "snippet-registry.22012",
"tag": "",
"url": ""
}来源引用
定义来源
center · PostgreSQL 18 · english-manuals:a0197ca4c78bba14db70bfeb414095e7f3af9c62c7e232f47480d9ca02d3ef24
正文语言: zh-Hans · english-manuals:a0197ca4c78bba14db70bfeb414095e7f3af9c62c7e232f47480d9ca02d3ef24