@@ -421,9 +421,9 @@ static void sn_scalar(void *state, char *token, JsonTokenType tokentype);
421
421
422
422
/* worker functions for populate_record, to_record, populate_recordset and to_recordset */
423
423
static Datum populate_recordset_worker (FunctionCallInfo fcinfo , const char * funcname ,
424
- bool have_record_arg );
424
+ bool is_json , bool have_record_arg );
425
425
static Datum populate_record_worker (FunctionCallInfo fcinfo , const char * funcname ,
426
- bool have_record_arg );
426
+ bool is_json , bool have_record_arg );
427
427
428
428
/* helper functions for populate_record[set] */
429
429
static HeapTupleHeader populate_record (TupleDesc tupdesc , RecordIOData * * record_p ,
@@ -2296,25 +2296,29 @@ elements_scalar(void *state, char *token, JsonTokenType tokentype)
2296
2296
Datum
2297
2297
jsonb_populate_record (PG_FUNCTION_ARGS )
2298
2298
{
2299
- return populate_record_worker (fcinfo , "jsonb_populate_record" , true);
2299
+ return populate_record_worker (fcinfo , "jsonb_populate_record" ,
2300
+ false, true);
2300
2301
}
2301
2302
2302
2303
Datum
2303
2304
jsonb_to_record (PG_FUNCTION_ARGS )
2304
2305
{
2305
- return populate_record_worker (fcinfo , "jsonb_to_record" , false);
2306
+ return populate_record_worker (fcinfo , "jsonb_to_record" ,
2307
+ false, false);
2306
2308
}
2307
2309
2308
2310
Datum
2309
2311
json_populate_record (PG_FUNCTION_ARGS )
2310
2312
{
2311
- return populate_record_worker (fcinfo , "json_populate_record" , true);
2313
+ return populate_record_worker (fcinfo , "json_populate_record" ,
2314
+ true, true);
2312
2315
}
2313
2316
2314
2317
Datum
2315
2318
json_to_record (PG_FUNCTION_ARGS )
2316
2319
{
2317
- return populate_record_worker (fcinfo , "json_to_record" , false);
2320
+ return populate_record_worker (fcinfo , "json_to_record" ,
2321
+ true, false);
2318
2322
}
2319
2323
2320
2324
/* helper function for diagnostics */
@@ -3203,21 +3207,22 @@ populate_record(TupleDesc tupdesc,
3203
3207
return res -> t_data ;
3204
3208
}
3205
3209
3210
+ /*
3211
+ * common worker for json{b}_populate_record() and json{b}_to_record()
3212
+ * is_json and have_record_arg identify the specific function
3213
+ */
3206
3214
static Datum
3207
3215
populate_record_worker (FunctionCallInfo fcinfo , const char * funcname ,
3208
- bool have_record_arg )
3216
+ bool is_json , bool have_record_arg )
3209
3217
{
3210
3218
int json_arg_num = have_record_arg ? 1 : 0 ;
3211
- Oid jtype = get_fn_expr_argtype (fcinfo -> flinfo , json_arg_num );
3212
3219
JsValue jsv = {0 };
3213
3220
HeapTupleHeader rec ;
3214
3221
Datum rettuple ;
3215
3222
JsonbValue jbv ;
3216
3223
MemoryContext fnmcxt = fcinfo -> flinfo -> fn_mcxt ;
3217
3224
PopulateRecordCache * cache = fcinfo -> flinfo -> fn_extra ;
3218
3225
3219
- Assert (jtype == JSONOID || jtype == JSONBOID );
3220
-
3221
3226
/*
3222
3227
* If first time through, identify input/result record type. Note that
3223
3228
* this stanza looks only at fcinfo context, which can't change during the
@@ -3303,9 +3308,9 @@ populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
3303
3308
PG_RETURN_NULL ();
3304
3309
}
3305
3310
3306
- jsv .is_json = jtype == JSONOID ;
3311
+ jsv .is_json = is_json ;
3307
3312
3308
- if (jsv . is_json )
3313
+ if (is_json )
3309
3314
{
3310
3315
text * json = PG_GETARG_TEXT_PP (json_arg_num );
3311
3316
@@ -3489,25 +3494,29 @@ hash_scalar(void *state, char *token, JsonTokenType tokentype)
3489
3494
Datum
3490
3495
jsonb_populate_recordset (PG_FUNCTION_ARGS )
3491
3496
{
3492
- return populate_recordset_worker (fcinfo , "jsonb_populate_recordset" , true);
3497
+ return populate_recordset_worker (fcinfo , "jsonb_populate_recordset" ,
3498
+ false, true);
3493
3499
}
3494
3500
3495
3501
Datum
3496
3502
jsonb_to_recordset (PG_FUNCTION_ARGS )
3497
3503
{
3498
- return populate_recordset_worker (fcinfo , "jsonb_to_recordset" , false);
3504
+ return populate_recordset_worker (fcinfo , "jsonb_to_recordset" ,
3505
+ false, false);
3499
3506
}
3500
3507
3501
3508
Datum
3502
3509
json_populate_recordset (PG_FUNCTION_ARGS )
3503
3510
{
3504
- return populate_recordset_worker (fcinfo , "json_populate_recordset" , true);
3511
+ return populate_recordset_worker (fcinfo , "json_populate_recordset" ,
3512
+ true, true);
3505
3513
}
3506
3514
3507
3515
Datum
3508
3516
json_to_recordset (PG_FUNCTION_ARGS )
3509
3517
{
3510
- return populate_recordset_worker (fcinfo , "json_to_recordset" , false);
3518
+ return populate_recordset_worker (fcinfo , "json_to_recordset" ,
3519
+ true, false);
3511
3520
}
3512
3521
3513
3522
static void
@@ -3544,14 +3553,14 @@ populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
3544
3553
}
3545
3554
3546
3555
/*
3547
- * common worker for json_populate_recordset() and json_to_recordset()
3556
+ * common worker for json{b}_populate_recordset() and json{b}_to_recordset()
3557
+ * is_json and have_record_arg identify the specific function
3548
3558
*/
3549
3559
static Datum
3550
3560
populate_recordset_worker (FunctionCallInfo fcinfo , const char * funcname ,
3551
- bool have_record_arg )
3561
+ bool is_json , bool have_record_arg )
3552
3562
{
3553
3563
int json_arg_num = have_record_arg ? 1 : 0 ;
3554
- Oid jtype = get_fn_expr_argtype (fcinfo -> flinfo , json_arg_num );
3555
3564
ReturnSetInfo * rsi ;
3556
3565
MemoryContext old_cxt ;
3557
3566
HeapTupleHeader rec ;
@@ -3662,7 +3671,7 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
3662
3671
state -> cache = cache ;
3663
3672
state -> rec = rec ;
3664
3673
3665
- if (jtype == JSONOID )
3674
+ if (is_json )
3666
3675
{
3667
3676
text * json = PG_GETARG_TEXT_PP (json_arg_num );
3668
3677
JsonLexContext * lex ;
@@ -3693,8 +3702,6 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
3693
3702
bool skipNested = false;
3694
3703
JsonbIteratorToken r ;
3695
3704
3696
- Assert (jtype == JSONBOID );
3697
-
3698
3705
if (JB_ROOT_IS_SCALAR (jb ) || !JB_ROOT_IS_ARRAY (jb ))
3699
3706
ereport (ERROR ,
3700
3707
(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
@@ -3726,8 +3733,13 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
3726
3733
}
3727
3734
}
3728
3735
3736
+ /*
3737
+ * Note: we must copy the cached tupdesc because the executor will free
3738
+ * the passed-back setDesc, but we want to hang onto the cache in case
3739
+ * we're called again in the same query.
3740
+ */
3729
3741
rsi -> setResult = state -> tuple_store ;
3730
- rsi -> setDesc = cache -> c .io .composite .tupdesc ;
3742
+ rsi -> setDesc = CreateTupleDescCopy ( cache -> c .io .composite .tupdesc ) ;
3731
3743
3732
3744
PG_RETURN_NULL ();
3733
3745
}
0 commit comments