Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix another crash in json{b}_populate_recordset and json{b}_to_recordset.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Nov 2018 20:14:01 +0000 (15:14 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Nov 2018 20:14:01 +0000 (15:14 -0500)
populate_recordset_worker() failed to consider the possibility that the
supplied JSON data contains no rows, so that update_cached_tupdesc never
got called.  This led to a null-pointer dereference since commit 9a5e8ed28;
before that it led to a bogus "set-valued function called in context that
cannot accept a set" error.  Fix by forcing the update to happen.

Per bug #15514.  Back-patch to v11 as 9a5e8ed28 was.  (If we were excited
about the bogus error, we could perhaps go back further, but it'd take more
work to figure out how to fix it in older branches.  Given the lack of
field complaints about that aspect, I'm not excited.)

Discussion: https://postgr.es/m/15514-59d5b4c4065b178b@postgresql.org

src/backend/utils/adt/jsonfuncs.c
src/test/regress/expected/json.out
src/test/regress/expected/jsonb.out
src/test/regress/sql/json.sql
src/test/regress/sql/jsonb.sql

index 06f8d281685db2c6933d39bac47e6aec794980e2..5c3f2fb9f6ff28cbc95ce398bdfb46d22b21e46d 100644 (file)
@@ -3658,6 +3658,12 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
    if (PG_ARGISNULL(json_arg_num))
        PG_RETURN_NULL();
 
+   /*
+    * Forcibly update the cached tupdesc, to ensure we have the right tupdesc
+    * to return even if the JSON contains no rows.
+    */
+   update_cached_tupdesc(&cache->c.io.composite, cache->fn_mcxt);
+
    state = palloc0(sizeof(PopulateRecordsetState));
 
    /* make tuplestore in a sufficiently long-lived memory context */
index 6020feeea41bfd224e486357eb1e4a65344d4b69..ea1be61effc7b3d0ff1837e0fc1ab9753becbb82 100644 (file)
@@ -1851,6 +1851,19 @@ FROM (VALUES (1),(2)) v(i);
  2 | (2,43)
 (4 rows)
 
+-- empty array is a corner case
+SELECT json_populate_recordset(null::record, '[]');
+ERROR:  record type has not been registered
+SELECT json_populate_recordset(row(1,2), '[]');
+ json_populate_recordset 
+-------------------------
+(0 rows)
+
+SELECT * FROM json_populate_recordset(NULL::jpop,'[]') q;
+ a | b | c 
+---+---+---
+(0 rows)
+
 -- composite domain
 SELECT json_populate_recordset(null::j_ordered_pair, '[{"x": 0, "y": 1}]');
  json_populate_recordset 
index f045e0853843996b944e482bae4c3603272d45d0..4fddd2de140c56f6d9067fe00c0b4141532c3251 100644 (file)
@@ -2533,6 +2533,19 @@ FROM (VALUES (1),(2)) v(i);
  2 | (2,43)
 (4 rows)
 
+-- empty array is a corner case
+SELECT jsonb_populate_recordset(null::record, '[]');
+ERROR:  record type has not been registered
+SELECT jsonb_populate_recordset(row(1,2), '[]');
+ jsonb_populate_recordset 
+--------------------------
+(0 rows)
+
+SELECT * FROM jsonb_populate_recordset(NULL::jbpop,'[]') q;
+ a | b | c 
+---+---+---
+(0 rows)
+
 -- composite domain
 SELECT jsonb_populate_recordset(null::jb_ordered_pair, '[{"x": 0, "y": 1}]');
  jsonb_populate_recordset 
index 97c75420e9c02808ff92f47d38b1227796e6bf09..d1e4008427761da8e5cc950ec92013186ba020fe 100644 (file)
@@ -550,6 +550,11 @@ SELECT json_populate_recordset(row(1,2), '[{"f1": 0, "f2": 1}]');
 SELECT i, json_populate_recordset(row(i,50), '[{"f1":"42"},{"f2":"43"}]')
 FROM (VALUES (1),(2)) v(i);
 
+-- empty array is a corner case
+SELECT json_populate_recordset(null::record, '[]');
+SELECT json_populate_recordset(row(1,2), '[]');
+SELECT * FROM json_populate_recordset(NULL::jpop,'[]') q;
+
 -- composite domain
 SELECT json_populate_recordset(null::j_ordered_pair, '[{"x": 0, "y": 1}]');
 SELECT json_populate_recordset(row(1,2)::j_ordered_pair, '[{"x": 0}, {"y": 3}]');
index bd82fd13f7db8034ad1cb19b7402c6125899fe14..6cbdfe43958901b8c7a6ddfbecd650498e95c85c 100644 (file)
@@ -666,6 +666,11 @@ SELECT jsonb_populate_recordset(row(1,2), '[{"f1": 0, "f2": 1}]');
 SELECT i, jsonb_populate_recordset(row(i,50), '[{"f1":"42"},{"f2":"43"}]')
 FROM (VALUES (1),(2)) v(i);
 
+-- empty array is a corner case
+SELECT jsonb_populate_recordset(null::record, '[]');
+SELECT jsonb_populate_recordset(row(1,2), '[]');
+SELECT * FROM jsonb_populate_recordset(NULL::jbpop,'[]') q;
+
 -- composite domain
 SELECT jsonb_populate_recordset(null::jb_ordered_pair, '[{"x": 0, "y": 1}]');
 SELECT jsonb_populate_recordset(row(1,2)::jb_ordered_pair, '[{"x": 0}, {"y": 3}]');