↑↓ select↵ open⌫ change scopeOpen full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

Wiki / SQLSTATE

22012 — division_by_zero

A division or modulo operation reached a zero divisor. PostgreSQL 18.6 uses SQLSTATE 22012 in numeric, integer, floating-point, money, and interval-division paths, while each path keeps its own operand and special-value rules.

English manual coverage begins with PostgreSQL 8.1. Source history and runtime observations have their own recorded version boundaries.

Reading PG 18·Select a recorded version

aliases
Unknown
class name
Data Exception
condition name
division_by_zero
lang
en
sqlstate
22012

Definition PG 18

At a glance {#at-a-glance}

A division or modulo operation reached a zero divisor. PostgreSQL 18.6 uses SQLSTATE 22012 in numeric, integer, floating-point, money, and interval-division paths, while each path keeps its own operand and special-value rules.

SELECT 10::numeric / 0::numeric;
SELECT 10::numeric / 2::numeric;

The retained PostgreSQL 18.6 and 10.21 observations show the first statement returning primary division by zero with SQLSTATE 22012, then the corrected statement returning 5.0000000000000000; both backends were IDLE after the repaired action. The public case JSON identifies this numeric division case; it is not a runtime comparison of every producer listed below.

Meaning {#meaning}

The direct numeric functions numeric_div and numeric_mod guard a zero numeric divisor; their internal *_opt_error forms can instead set a have_error flag and return NULL to a caller that handles the failure. Integer division and modulo functions check their zero second operand before using / or %. Float4/float8 division routes through float*_div, which raises for a zero divisor when the numerator is not NaN. Money division checks its integer or money divisor, and interval division checks its float factor. These paths share the SQLSTATE and primary text, but the resolved operator and special values still determine the result.

Diagnosis {#diagnosis}

Locate the denominator or modulo divisor after operator/type resolution; do not infer an int4 rule for all numeric types. Check whether zero came from input, a join, an aggregate, or a business rule, and inspect the complete primary message. A NULL operand normally produces a NULL result before a strict arithmetic function is called, while NULLIF(denominator, 0) deliberately turns the zero case into NULL. A CASE expression can choose a NULL, substitute, or skip policy, so choose the branch that matches the business result rather than silently changing an error into a value.

The planning boundary matters: the PostgreSQL 18.6 conditional-expression documentation warns that a constant 1/0 subexpression can fail during planning even in an unreachable CASE arm. The planner source recursively simplifies constant arguments and evaluates immutable constant expressions. Use a non-constant value or guard the actual denominator with NULLIF/a suitable CASE when the division must be deferred to execution; this does not make an invalid constant expression safe, and it does not decide whether NULL or a substitute is correct for the application.

Response {#response}

Repair the producer of the zero divisor or select an explicit zero policy. Use NULLIF when a NULL result is meaningful, or a CASE branch when the application has a documented substitute or skip rule; then validate the downstream aggregates and filters that will see that result. Do not replay the unchanged operation. The ordinary fixed paths raise ERROR; in an explicit transaction use ROLLBACK or ROLLBACK TO SAVEPOINT before retrying, while autocommit can retry only the corrected action. The retained 18.6/10.21 numeric observation is limited to this case.

Messages {#messages}

  • Primary, ERROR: division by zero.
  • No fixed DETAIL or HINT is attached to the cited numeric, integer, float, money, or interval-division guards. Internal numeric have_error callers are a soft handling path, not a claim that a direct SQL operator returns successfully.

Versions {#versions}

The locked catalogue records this condition from 7.4; fixed source coverage is PostgreSQL 18.6. The retained numeric runtime records are PostgreSQL 18.6 and 10.21 and cover only 10::numeric / 0::numeric followed by 10::numeric / 2::numeric.

Related {#related}

22003, 22008, 22015

Sources {#sources}

The structured evidence record retains both runtime summaries/raw digests and the fixed source claims.

Compare versions

SQLSTATE evidence and recorded runtime versions

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": ""
}

Source references

Full definition and evidence JSON

Definition sources

center · PostgreSQL 18 · english-manuals:a0197ca4c78bba14db70bfeb414095e7f3af9c62c7e232f47480d9ca02d3ef24

Text language: en · english-manuals:a0197ca4c78bba14db70bfeb414095e7f3af9c62c7e232f47480d9ca02d3ef24