/* worker functions for populate_record, to_record, populate_recordset and to_recordset */
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
- bool have_record_arg);
+ bool is_json, bool have_record_arg);
static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
- bool have_record_arg);
+ bool is_json, bool have_record_arg);
/* helper functions for populate_record[set] */
static HeapTupleHeader populate_record(TupleDesc tupdesc, RecordIOData **record_p,
Datum
jsonb_populate_record(PG_FUNCTION_ARGS)
{
- return populate_record_worker(fcinfo, "jsonb_populate_record", true);
+ return populate_record_worker(fcinfo, "jsonb_populate_record",
+ false, true);
}
Datum
jsonb_to_record(PG_FUNCTION_ARGS)
{
- return populate_record_worker(fcinfo, "jsonb_to_record", false);
+ return populate_record_worker(fcinfo, "jsonb_to_record",
+ false, false);
}
Datum
json_populate_record(PG_FUNCTION_ARGS)
{
- return populate_record_worker(fcinfo, "json_populate_record", true);
+ return populate_record_worker(fcinfo, "json_populate_record",
+ true, true);
}
Datum
json_to_record(PG_FUNCTION_ARGS)
{
- return populate_record_worker(fcinfo, "json_to_record", false);
+ return populate_record_worker(fcinfo, "json_to_record",
+ true, false);
}
/* helper function for diagnostics */
return res->t_data;
}
+/*
+ * common worker for json{b}_populate_record() and json{b}_to_record()
+ * is_json and have_record_arg identify the specific function
+ */
static Datum
populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
- bool have_record_arg)
+ bool is_json, bool have_record_arg)
{
int json_arg_num = have_record_arg ? 1 : 0;
- Oid jtype = get_fn_expr_argtype(fcinfo->flinfo, json_arg_num);
JsValue jsv = {0};
HeapTupleHeader rec;
Datum rettuple;
MemoryContext fnmcxt = fcinfo->flinfo->fn_mcxt;
PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
- Assert(jtype == JSONOID || jtype == JSONBOID);
-
/*
* If first time through, identify input/result record type. Note that
* this stanza looks only at fcinfo context, which can't change during the
PG_RETURN_NULL();
}
- jsv.is_json = jtype == JSONOID;
+ jsv.is_json = is_json;
- if (jsv.is_json)
+ if (is_json)
{
text *json = PG_GETARG_TEXT_PP(json_arg_num);
Datum
jsonb_populate_recordset(PG_FUNCTION_ARGS)
{
- return populate_recordset_worker(fcinfo, "jsonb_populate_recordset", true);
+ return populate_recordset_worker(fcinfo, "jsonb_populate_recordset",
+ false, true);
}
Datum
jsonb_to_recordset(PG_FUNCTION_ARGS)
{
- return populate_recordset_worker(fcinfo, "jsonb_to_recordset", false);
+ return populate_recordset_worker(fcinfo, "jsonb_to_recordset",
+ false, false);
}
Datum
json_populate_recordset(PG_FUNCTION_ARGS)
{
- return populate_recordset_worker(fcinfo, "json_populate_recordset", true);
+ return populate_recordset_worker(fcinfo, "json_populate_recordset",
+ true, true);
}
Datum
json_to_recordset(PG_FUNCTION_ARGS)
{
- return populate_recordset_worker(fcinfo, "json_to_recordset", false);
+ return populate_recordset_worker(fcinfo, "json_to_recordset",
+ true, false);
}
static void
}
/*
- * common worker for json_populate_recordset() and json_to_recordset()
+ * common worker for json{b}_populate_recordset() and json{b}_to_recordset()
+ * is_json and have_record_arg identify the specific function
*/
static Datum
populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
- bool have_record_arg)
+ bool is_json, bool have_record_arg)
{
int json_arg_num = have_record_arg ? 1 : 0;
- Oid jtype = get_fn_expr_argtype(fcinfo->flinfo, json_arg_num);
ReturnSetInfo *rsi;
MemoryContext old_cxt;
HeapTupleHeader rec;
state->cache = cache;
state->rec = rec;
- if (jtype == JSONOID)
+ if (is_json)
{
text *json = PG_GETARG_TEXT_PP(json_arg_num);
JsonLexContext *lex;
bool skipNested = false;
JsonbIteratorToken r;
- Assert(jtype == JSONBOID);
-
if (JB_ROOT_IS_SCALAR(jb) || !JB_ROOT_IS_ARRAY(jb))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
}
}
+ /*
+ * Note: we must copy the cached tupdesc because the executor will free
+ * the passed-back setDesc, but we want to hang onto the cache in case
+ * we're called again in the same query.
+ */
rsi->setResult = state->tuple_store;
- rsi->setDesc = cache->c.io.composite.tupdesc;
+ rsi->setDesc = CreateTupleDescCopy(cache->c.io.composite.tupdesc);
PG_RETURN_NULL();
}