| 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:58 |
| Message-ID: | E1xMEWk-00000001Bcc-1DtI@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
------
master
Details
-------
https://git.postgresql.org/pg/commitdiff/b6e41c16f8ccbfca0d51c94bdb6043b6e8393d6f
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(+)
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Amit Langote | 2026-10-29 01:39:15 | pgsql: Fix JSON_TABLE with sublinks in PASSING arguments |
| Previous Message | Amit Langote | 2026-10-29 01:01:44 | pgsql: SQL/JSON: fix error handling when coercing to a domain fails sof |