Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita1fc364

Browse files
committed
Fix handling of nested JSON objects in json_populate_recordset and friends.
populate_recordset_object_start() improperly created a new hash table(overwriting the link to the existing one) if called at nest levelsgreater than one. This resulted in previous fields not appearing inthe final output, as reported by Matti Hameister in bug #10728.In 9.4 the problem also affects json_to_recordset.This perhaps missed detection earlier because the default behavior is tothrow an error for nested objects: you have to pass use_json_as_text = trueto see the problem.In addition, fix query-lifespan leakage of the hashtable created byjson_populate_record(). This is pretty much the same problem recentlyfixed in dblink: creating an intended-to-be-temporary context underneaththe executor's per-tuple context isn't enough to make it go away at theend of the tuple cycle, because MemoryContextReset is notMemoryContextResetAndDeleteChildren.Michael Paquier and Tom Lane
1 parentcc58418 commita1fc364

File tree

4 files changed

+38
-6
lines changed

4 files changed

+38
-6
lines changed

‎src/backend/utils/adt/jsonfuncs.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,8 +1282,10 @@ json_populate_record(PG_FUNCTION_ARGS)
12821282
* nulls.
12831283
*/
12841284
if (hash_get_num_entries(json_hash)==0&&rec)
1285+
{
1286+
hash_destroy(json_hash);
12851287
PG_RETURN_POINTER(rec);
1286-
1288+
}
12871289

12881290
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
12891291
ncolumns=tupdesc->natts;
@@ -1408,6 +1410,8 @@ json_populate_record(PG_FUNCTION_ARGS)
14081410

14091411
ReleaseTupleDesc(tupdesc);
14101412

1413+
hash_destroy(json_hash);
1414+
14111415
PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
14121416
}
14131417

@@ -1698,16 +1702,23 @@ populate_recordset_object_start(void *state)
16981702
intlex_level=_state->lex->lex_level;
16991703
HASHCTLctl;
17001704

1705+
/* Reject object at top level: we must have an array at level 0 */
17011706
if (lex_level==0)
17021707
ereport(ERROR,
17031708
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
17041709
errmsg("cannot call json_populate_recordset on an object")));
1705-
elseif (lex_level>1&& !_state->use_json_as_text)
1706-
ereport(ERROR,
1707-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1708-
errmsg("cannot call json_populate_recordset with nested objects")));
17091710

1710-
/* set up a new hash for this entry */
1711+
/* Nested objects, if allowed, require no special processing */
1712+
if (lex_level>1)
1713+
{
1714+
if (!_state->use_json_as_text)
1715+
ereport(ERROR,
1716+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1717+
errmsg("cannot call json_populate_recordset with nested objects")));
1718+
return;
1719+
}
1720+
1721+
/* Object at level 1: set up a new hash table for this object */
17111722
memset(&ctl,0,sizeof(ctl));
17121723
ctl.keysize=NAMEDATALEN;
17131724
ctl.entrysize=sizeof(JsonHashEntry);
@@ -1734,9 +1745,11 @@ populate_recordset_object_end(void *state)
17341745
HeapTupleHeaderrec=_state->rec;
17351746
HeapTuplerettuple;
17361747

1748+
/* Nested objects require no special processing */
17371749
if (_state->lex->lex_level>1)
17381750
return;
17391751

1752+
/* Otherwise, construct and return a tuple based on this level-1 object */
17401753
values= (Datum*)palloc(ncolumns*sizeof(Datum));
17411754
nulls= (bool*)palloc(ncolumns*sizeof(bool));
17421755

@@ -1828,7 +1841,9 @@ populate_recordset_object_end(void *state)
18281841

18291842
tuplestore_puttuple(_state->tuple_store,rettuple);
18301843

1844+
/* Done with hash for this object */
18311845
hash_destroy(json_hash);
1846+
_state->json_hash=NULL;
18321847
}
18331848

18341849
staticvoid

‎src/test/regress/expected/json.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,13 @@ select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,3
901901

902902
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
903903
ERROR: invalid input syntax for type timestamp: "[100,200,300]"
904+
create type jpop2 as (a int, b json, c int, d int);
905+
select * from json_populate_recordset(null::jpop2, '[{"a":2,"c":3,"b":{"z":4},"d":6}]',true) q;
906+
a | b | c | d
907+
---+---------+---+---
908+
2 | {"z":4} | 3 | 6
909+
(1 row)
910+
904911
-- using the default use_json_as_text argument
905912
select * from json_populate_recordset(null::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]') q;
906913
a | b | c

‎src/test/regress/expected/json_1.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,13 @@ select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,3
901901

902902
select * from json_populate_recordset(row('def',99,null)::jpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
903903
ERROR: invalid input syntax for type timestamp: "[100,200,300]"
904+
create type jpop2 as (a int, b json, c int, d int);
905+
select * from json_populate_recordset(null::jpop2, '[{"a":2,"c":3,"b":{"z":4},"d":6}]',true) q;
906+
a | b | c | d
907+
---+---------+---+---
908+
2 | {"z":4} | 3 | 6
909+
(1 row)
910+
904911
-- using the default use_json_as_text argument
905912
select * from json_populate_recordset(null::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]') q;
906913
a | b | c

‎src/test/regress/sql/json.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":"blurfl","
290290
select*from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
291291
select*from json_populate_recordset(row('def',99,null)::jpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]',true) q;
292292

293+
createtypejpop2as (aint, b json, cint, dint);
294+
select*from json_populate_recordset(null::jpop2,'[{"a":2,"c":3,"b":{"z":4},"d":6}]',true) q;
295+
293296
-- using the default use_json_as_text argument
294297

295298
select*from json_populate_recordset(null::jpop,'[{"a":"blurfl","x":43.2},{"b":3,"c":"2012-01-20 10:42:53"}]') q;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp