mirror of
https://github.com/postgres/postgres.git
synced 2025-12-12 02:37:31 +03:00
Revise APIs for pushJsonbValue() and associated routines.
Instead of passing "JsonbParseState **" to pushJsonbValue(), pass a pointer to a JsonbInState, which will contain the parseState stack pointer as well as other useful fields. Also, instead of returning a JsonbValue pointer that is often meaningless/ignored, return the top-level JsonbValue pointer in the "result" field of the JsonbInState. This involves a lot of (mostly mechanical) edits, but I think the results are notationally cleaner and easier to understand. Certainly the business with sometimes capturing the result of pushJsonbValue() and sometimes not was bug-prone and incapable of mechanical verification. In the new arrangement, JsonbInState.result remains null until we've completed a valid sequence of pushes, so that an incorrect sequence will result in a null-pointer dereference, not mistaken use of a partial result. However, this isn't simply an exercise in prettier notation. The real reason for doing it is to provide a mechanism whereby pushJsonbValue() can be told to construct the JsonbValue tree in a context that is not CurrentMemoryContext. That happens when a non-null "outcontext" is specified in the JsonbInState. No callers exercise that option in this patch, but the next patch in the series will make use of it. I tried to improve the comments in this area too. Author: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: jian he <jian.universality@gmail.com> Reviewed-by: Chao Li <li.evan.chao@gmail.com> Discussion: https://postgr.es/m/1060917.1753202222@sss.pgh.pa.us
This commit is contained in:
@@ -13,7 +13,7 @@ PG_MODULE_MAGIC_EXT(
|
||||
);
|
||||
|
||||
static SV *Jsonb_to_SV(JsonbContainer *jsonb);
|
||||
static JsonbValue *SV_to_JsonbValue(SV *obj, JsonbParseState **ps, bool is_elem);
|
||||
static void SV_to_JsonbValue(SV *obj, JsonbInState *ps, bool is_elem);
|
||||
|
||||
|
||||
static SV *
|
||||
@@ -127,8 +127,8 @@ Jsonb_to_SV(JsonbContainer *jsonb)
|
||||
}
|
||||
}
|
||||
|
||||
static JsonbValue *
|
||||
AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
|
||||
static void
|
||||
AV_to_JsonbValue(AV *in, JsonbInState *jsonb_state)
|
||||
{
|
||||
dTHX;
|
||||
SSize_t pcount = av_len(in) + 1;
|
||||
@@ -141,14 +141,14 @@ AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
|
||||
SV **value = av_fetch(in, i, FALSE);
|
||||
|
||||
if (value)
|
||||
(void) SV_to_JsonbValue(*value, jsonb_state, true);
|
||||
SV_to_JsonbValue(*value, jsonb_state, true);
|
||||
}
|
||||
|
||||
return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
|
||||
pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
|
||||
}
|
||||
|
||||
static JsonbValue *
|
||||
HV_to_JsonbValue(HV *obj, JsonbParseState **jsonb_state)
|
||||
static void
|
||||
HV_to_JsonbValue(HV *obj, JsonbInState *jsonb_state)
|
||||
{
|
||||
dTHX;
|
||||
JsonbValue key;
|
||||
@@ -167,14 +167,14 @@ HV_to_JsonbValue(HV *obj, JsonbParseState **jsonb_state)
|
||||
key.val.string.val = pnstrdup(kstr, klen);
|
||||
key.val.string.len = klen;
|
||||
pushJsonbValue(jsonb_state, WJB_KEY, &key);
|
||||
(void) SV_to_JsonbValue(val, jsonb_state, false);
|
||||
SV_to_JsonbValue(val, jsonb_state, false);
|
||||
}
|
||||
|
||||
return pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
|
||||
pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
|
||||
}
|
||||
|
||||
static JsonbValue *
|
||||
SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
|
||||
static void
|
||||
SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem)
|
||||
{
|
||||
dTHX;
|
||||
JsonbValue out; /* result */
|
||||
@@ -186,10 +186,12 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
|
||||
switch (SvTYPE(in))
|
||||
{
|
||||
case SVt_PVAV:
|
||||
return AV_to_JsonbValue((AV *) in, jsonb_state);
|
||||
AV_to_JsonbValue((AV *) in, jsonb_state);
|
||||
return;
|
||||
|
||||
case SVt_PVHV:
|
||||
return HV_to_JsonbValue((HV *) in, jsonb_state);
|
||||
HV_to_JsonbValue((HV *) in, jsonb_state);
|
||||
return;
|
||||
|
||||
default:
|
||||
if (!SvOK(in))
|
||||
@@ -259,14 +261,24 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot transform this Perl type to jsonb")));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Push result into 'jsonb_state' unless it is a raw scalar. */
|
||||
return *jsonb_state
|
||||
? pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out)
|
||||
: memcpy(palloc_object(JsonbValue), &out, sizeof(JsonbValue));
|
||||
if (jsonb_state->parseState)
|
||||
{
|
||||
/* We're in an array or object, so push value as element or field. */
|
||||
pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* We are at top level, so it's a raw scalar. If we just shove the
|
||||
* scalar value into jsonb_state->result, JsonbValueToJsonb will take
|
||||
* care of wrapping it into a dummy array.
|
||||
*/
|
||||
jsonb_state->result = palloc_object(JsonbValue);
|
||||
memcpy(jsonb_state->result, &out, sizeof(JsonbValue));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -289,10 +301,9 @@ Datum
|
||||
plperl_to_jsonb(PG_FUNCTION_ARGS)
|
||||
{
|
||||
dTHX;
|
||||
JsonbParseState *jsonb_state = NULL;
|
||||
SV *in = (SV *) PG_GETARG_POINTER(0);
|
||||
JsonbValue *out = SV_to_JsonbValue(in, &jsonb_state, true);
|
||||
Jsonb *result = JsonbValueToJsonb(out);
|
||||
JsonbInState jsonb_state = {0};
|
||||
|
||||
PG_RETURN_JSONB_P(result);
|
||||
SV_to_JsonbValue(in, &jsonb_state, true);
|
||||
PG_RETURN_JSONB_P(JsonbValueToJsonb(jsonb_state.result));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user