| From: | PG Bug reporting form <noreply(at)postgresql(dot)org> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Cc: | zengman(at)halodbtech(dot)com |
| Subject: | BUG #19625: SQL/JSON boolean DEFAULT expression silently replaced with 'false' |
| Date: | 2026-08-17 14:04:21 |
| Message-ID: | 19625-683b498c92087bc8@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: 19625
Logged by: Man Zeng
Email address: zengman(at)halodbtech(dot)com
PostgreSQL version: 19beta3
Operating system: 24.04.1-Ubuntu
Description:
Hi all,
A boolean DEFAULT expression in the SQL/JSON functions can be silently
replaced with 'false', discarding the user's expression at parse time.
For example:
```sql
postgres=# SELECT JSON_VALUE('{"a":"abc"}', 'strict $.b' DEFAULT true ON
ERROR); -- expected true
json_value
------------
false
(1 row)
postgres=# SELECT JSON_VALUE('{"a":"abc"}', 'strict $.b' DEFAULT (1=1) ON
ERROR); -- expected true
json_value
------------
false
(1 row)
postgres=# SELECT JSON_QUERY('{"a":"abc"}', 'strict $.b' DEFAULT false ON
ERROR);
json_query
------------
false
(1 row)
```
The user asked for true, so the result is wrong. A boolean
expression such as DEFAULT (1=1) is affected in the same way, and so
is JSON_QUERY(). Non-boolean DEFAULT expressions (e.g. DEFAULT 'ok')
return the correct value, and so do boolean ones when the RETURNING
type is boolean or integer.
The problem is in transformJsonBehavior() in parse_expr.c. When the
DEFAULT expression is boolean-valued and the RETURNING type is neither
boolean nor integer (or a domain over integer), the code guesses the
jsonb value from the behavior type:
```c
char *val = btype == JSON_BEHAVIOR_TRUE ? "true" : "false";
```
This only works for the canned TRUE/FALSE constants. A user-supplied
DEFAULT clause has btype == JSON_BEHAVIOR_DEFAULT, so the condition is
always false and the expression is replaced with jsonb 'false' without
being evaluated.
I think we can use to_jsonb() to handle all of these cases -- whether a
canned TRUE/FALSE constant or a user-supplied boolean DEFAULT
expression, the value is converted per the expression's actual
evaluation (there is no bool->jsonb cast, hence the explicit function
call). Below is my change:
```c
diff --git a/src/backend/parser/parse_expr.c
b/src/backend/parser/parse_expr.c
index 30c889f505f..175b3d3ee69 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -4956,20 +4956,17 @@ transformJsonBehavior(ParseState *pstate, JsonExpr
*jsexpr,
coerce_at_runtime = true;
/*
- * json_populate_type() expects to be passed a jsonb
value, so gin
- * up a Const containing the appropriate boolean
value represented
- * as jsonb, discarding the original Const
containing a plain
- * boolean.
+ * json_populate_type() only takes a jsonb value, so
convert a
+ * boolean to jsonb by calling to_jsonb() on it.
That way any
+ * boolean-valued expression -- whether a canned
TRUE/FALSE
+ * constant or a user-supplied DEFAULT expression --
is converted
+ * according to the value it actually evaluates to.
*/
if (exprType(expr) == BOOLOID)
- {
- char *val = btype ==
JSON_BEHAVIOR_TRUE ? "true" : "false";
-
- expr = (Node *) makeConst(JSONBOID, -1,
InvalidOid, -1,
-
DirectFunctionCall1(jsonb_in,
-
CStringGetDatum(val)),
-
false, false);
- }
+ expr = (Node *) makeFuncExpr(F_TO_JSONB,
JSONBOID,
+
list_make1(expr),
+
InvalidOid, InvalidOid,
+
COERCE_EXPLICIT_CALL);
}
else
{
```
Thoughts?
--
Regards,
Man Zeng
| From | Date | Subject | |
|---|---|---|---|
| Next Message | zengman | 2026-08-17 14:09:41 | Re:BUG #19625: SQL/JSON boolean DEFAULT expression silently replaced with 'false' |
| Previous Message | Daniel Gustafsson | 2026-08-17 10:35:48 | Re: MERGE/SPLIT PARTITIONS issues/questions |