1
0
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:
Tom Lane
2025-12-07 11:46:49 -05:00
parent 3628af4210
commit 0986e95161
8 changed files with 528 additions and 422 deletions

View File

@@ -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));
}