pgsql: SQL/JSON: fix error handling when coercing to a domain fails sof

From: Amit Langote <amitlan(at)postgresql(dot)org>
To: pgsql-committers(at)lists(dot)postgresql(dot)org
Subject: pgsql: SQL/JSON: fix error handling when coercing to a domain fails sof
Date: 2026-10-29 01:01:17
Message-ID: E1xMEW5-00000001Bab-1h95@gemulon.postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-committers

SQL/JSON: fix error handling when coercing to a domain fails softly

SQL/JSON query functions could throw an error, or report the wrong one,
in cases where the ON ERROR or ON EMPTY clause said what to do instead.
This happened when the RETURNING type, or a DEFAULT expression,
involved a domain: if the value failed to convert to the domain's base
type, that failure was saved to be handled by the ON ERROR behavior,
but the domain's constraints were then checked anyway, against the
dummy NULL left behind by the failed conversion. A CHECK expression
can throw a hard error on that NULL, which ON ERROR cannot catch, and
a NOT NULL constraint reports a violation that overwrites the saved
error, so the error message ends up describing the wrong problem.

For example, this failed with "division by zero" instead of returning
11:

CREATE DOMAIN d AS int CHECK (1 / coalesce(VALUE, 0) = 0);
SELECT JSON_VALUE(jsonb '"x"', '$' RETURNING d DEFAULT 11 ON ERROR);

Fix by stopping as soon as a soft error has been saved, in each of the
places that kept going:

* The domain constraint checks of a CoerceToDomain in an ON ERROR or ON
EMPTY DEFAULT expression, which is the only case where they are
evaluated softly. ExecInitCoerceToDomain now emits a jump before each
constraint check that skips the remaining checks if an error has
already been saved.

* populate_domain, called from json_populate_type when coercing to a
domain. Return as soon as the conversion to the base type fails,
instead of going on to check the domain's constraints.

* populate_record, likewise. Stop populating the remaining columns as
soon as one of them fails.

* ExecEvalJsonCoercion. Return at once if the DEFAULT expression whose
result it would coerce has already failed, and leave throwing the
error to the COERCION_FINISH step that follows.

Reported-by: jian he <jian(dot)universality(at)gmail(dot)com>
Author: jian he <jian(dot)universality(at)gmail(dot)com>
Discussion: https://postgr.es/m/CACJufxHDK39zF+1zZF6prH_wtn1SDt74_mrqYk1Oo82cCu44ng@mail.gmail.com
Backpatch-through: 17

Branch
------
REL_17_STABLE

Details
-------
https://git.postgresql.org/pg/commitdiff/46798ab1adf34bf57b7585019033db89fb0641e2

Modified Files
--------------
src/backend/executor/execExpr.c | 23 ++++++++++
src/backend/executor/execExprInterp.c | 14 ++++++
src/backend/utils/adt/jsonfuncs.c | 19 +++++++++
src/test/regress/expected/sqljson_queryfuncs.out | 54 ++++++++++++++++++++++++
src/test/regress/sql/sqljson_queryfuncs.sql | 18 ++++++++
5 files changed, 128 insertions(+)

Browse pgsql-committers by date

  From Date Subject
Next Message Amit Langote 2026-10-29 01:01:31 pgsql: SQL/JSON: fix error handling when coercing to a domain fails sof
Previous Message Michael Paquier 2026-10-29 00:44:55 pgsql: Work around failure with SPARC in base backup code