| From: | PG Bug reporting form <noreply(at)postgresql(dot)org> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Cc: | 303677365(at)qq(dot)com |
| Subject: | BUG #19822: DEFAULT boolean expressions in SQL/JSON functions are re-encoded as JSON booleans and always yield f |
| Date: | 2026-11-01 07:56:47 |
| Message-ID: | 19822-8bdbbe6b7cdc9048@postgresql.org |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
The following bug has been logged on the website:
Bug reference: 19822
Logged by: chunling qin
Email address: 303677365(at)qq(dot)com
PostgreSQL version: 18.6
Operating system: Linux (TencentOS 4.4, x86_64)
Description:
Hello,
In transformJsonBehavior() (src/backend/parser/parse_expr.c), the
"coerce at runtime" branch replaces a boolean DEFAULT expression with a
JSON boolean constant using the *clause behavior type* instead of the
expression's actual value:
char *val = btype == JSON_BEHAVIOR_TRUE ? "true" : "false";
For a DEFAULT clause, btype is JSON_BEHAVIOR_DEFAULT, so the constant is
always "false", regardless of whether the expression evaluates to true,
false, or NULL. The replacement is also not guarded by !isnull, so a
NULL boolean constant becomes false as well.
The trigger is: the DEFAULT expression's type is boolean, and the
RETURNING type's base type is not int4 (the ordinary bool->int4 cast
path is unaffected).
Reproducer (self-contained, on 18.6 and on 20devel):
-- G1: DEFAULT true must yield 'true ' (padded to char(5))
SELECT JSON_VALUE(jsonb '"xyzzy!"', '$'
RETURNING char(5) DEFAULT true ON ERROR);
-- actual: false <- the boolean true was replaced by JSON false
-- expected: 'true ' (SQL boolean cast to bpchar(5))
-- G4: same with a domain over bool
CREATE DOMAIN dbool AS bool;
SELECT JSON_VALUE(jsonb '"xyzzy!"', '$'
RETURNING dbool DEFAULT true ON ERROR);
-- actual: f -- expected: t
-- H1: a NULL boolean constant is also replaced (no !isnull guard)
SELECT JSON_VALUE(jsonb '"xyzzy!"', '$'
RETURNING char(5) DEFAULT NULL::bool ON ERROR);
-- actual: false -- expected: NULL
-- Controls that show the normal paths are fine:
SELECT JSON_VALUE(jsonb '"xyzzy!"', '$'
RETURNING char(5) DEFAULT false ON ERROR); -- false (correct by
accident)
SELECT JSON_VALUE(jsonb '"xyzzy!"', '$'
RETURNING int DEFAULT true ON ERROR); -- 1 (bool->int4 path,
correct)
Expected: the value of a DEFAULT expression should be determined by the
expression itself (true -> "true", NULL -> NULL), not by the clause
behavior type; JSON boolean encoding should only apply to an explicit
FORMAT JSON.
Actual: DEFAULT true/false/NULL all come back as JSON false whenever the
runtime-coercion path is taken, silently and with no warning. A common
use of DEFAULT true is a fallback flag (feature switch, approval marker);
getting false there instead of true produces wrong business decisions
with no error anywhere.
Reproduced on:
- PostgreSQL 18.6 (REL_18_STABLE, self-built, snapshot 2026-10-26)
- PostgreSQL 20devel (snapshot of 2026-10-29)
A draft fix location would be transformJsonBehavior()
(src/backend/parser/parse_expr.c): use the actual constant value for
boolean DEFAULT expressions (and guard the replacement with !isnull).
Regards,
Chunling Qin
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Michael Paquier | 2026-11-01 08:00:31 | Re: BUG #19795: pgoutput: walsender crashes on START_REPLICATION option without a value |
| Previous Message | Rajesh Kumar Thandapani | 2026-11-01 07:32:17 | Re: BUG #19776: pg_combinebackup ignores the truncation_block_length of an intermediate incremental backup |