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:
@@ -26,8 +26,8 @@ static PLy_elog_impl_t PLy_elog_impl_p;
|
||||
static PyObject *decimal_constructor;
|
||||
|
||||
static PyObject *PLyObject_FromJsonbContainer(JsonbContainer *jsonb);
|
||||
static JsonbValue *PLyObject_ToJsonbValue(PyObject *obj,
|
||||
JsonbParseState **jsonb_state, bool is_elem);
|
||||
static void PLyObject_ToJsonbValue(PyObject *obj,
|
||||
JsonbInState *jsonb_state, bool is_elem);
|
||||
|
||||
typedef PyObject *(*PLyUnicode_FromStringAndSize_t)
|
||||
(const char *s, Py_ssize_t size);
|
||||
@@ -261,12 +261,11 @@ PLyObject_FromJsonbContainer(JsonbContainer *jsonb)
|
||||
*
|
||||
* Transform Python dict to JsonbValue.
|
||||
*/
|
||||
static JsonbValue *
|
||||
PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
||||
static void
|
||||
PLyMapping_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state)
|
||||
{
|
||||
Py_ssize_t pcount;
|
||||
PyObject *volatile items;
|
||||
JsonbValue *volatile out;
|
||||
|
||||
pcount = PyMapping_Size(obj);
|
||||
items = PyMapping_Items(obj);
|
||||
@@ -297,19 +296,17 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
||||
PLyUnicode_ToJsonbValue(key, &jbvKey);
|
||||
}
|
||||
|
||||
(void) pushJsonbValue(jsonb_state, WJB_KEY, &jbvKey);
|
||||
(void) PLyObject_ToJsonbValue(value, jsonb_state, false);
|
||||
pushJsonbValue(jsonb_state, WJB_KEY, &jbvKey);
|
||||
PLyObject_ToJsonbValue(value, jsonb_state, false);
|
||||
}
|
||||
|
||||
out = pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
|
||||
pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
|
||||
}
|
||||
PG_FINALLY();
|
||||
{
|
||||
Py_DECREF(items);
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -318,8 +315,8 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
||||
* Transform python list to JsonbValue. Expects transformed PyObject and
|
||||
* a state required for jsonb construction.
|
||||
*/
|
||||
static JsonbValue *
|
||||
PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
||||
static void
|
||||
PLySequence_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
Py_ssize_t pcount;
|
||||
@@ -336,7 +333,7 @@ PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
||||
value = PySequence_GetItem(obj, i);
|
||||
Assert(value);
|
||||
|
||||
(void) PLyObject_ToJsonbValue(value, jsonb_state, true);
|
||||
PLyObject_ToJsonbValue(value, jsonb_state, true);
|
||||
Py_XDECREF(value);
|
||||
value = NULL;
|
||||
}
|
||||
@@ -348,7 +345,7 @@ PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
|
||||
pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -406,17 +403,23 @@ PLyNumber_ToJsonbValue(PyObject *obj, JsonbValue *jbvNum)
|
||||
*
|
||||
* Transform python object to JsonbValue.
|
||||
*/
|
||||
static JsonbValue *
|
||||
PLyObject_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state, bool is_elem)
|
||||
static void
|
||||
PLyObject_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state, bool is_elem)
|
||||
{
|
||||
JsonbValue *out;
|
||||
|
||||
if (!PyUnicode_Check(obj))
|
||||
{
|
||||
if (PySequence_Check(obj))
|
||||
return PLySequence_ToJsonbValue(obj, jsonb_state);
|
||||
{
|
||||
PLySequence_ToJsonbValue(obj, jsonb_state);
|
||||
return;
|
||||
}
|
||||
else if (PyMapping_Check(obj))
|
||||
return PLyMapping_ToJsonbValue(obj, jsonb_state);
|
||||
{
|
||||
PLyMapping_ToJsonbValue(obj, jsonb_state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
out = palloc_object(JsonbValue);
|
||||
@@ -443,10 +446,20 @@ PLyObject_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state, bool is_ele
|
||||
errmsg("Python type \"%s\" cannot be transformed to jsonb",
|
||||
PLyObject_AsString((PyObject *) obj->ob_type))));
|
||||
|
||||
/* Push result into 'jsonb_state' unless it is raw scalar value. */
|
||||
return (*jsonb_state ?
|
||||
pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, out) :
|
||||
out);
|
||||
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 = out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -458,13 +471,11 @@ PG_FUNCTION_INFO_V1(plpython_to_jsonb);
|
||||
Datum
|
||||
plpython_to_jsonb(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PyObject *obj;
|
||||
JsonbValue *out;
|
||||
JsonbParseState *jsonb_state = NULL;
|
||||
PyObject *obj = (PyObject *) PG_GETARG_POINTER(0);
|
||||
JsonbInState jsonb_state = {0};
|
||||
|
||||
obj = (PyObject *) PG_GETARG_POINTER(0);
|
||||
out = PLyObject_ToJsonbValue(obj, &jsonb_state, true);
|
||||
PG_RETURN_POINTER(JsonbValueToJsonb(out));
|
||||
PLyObject_ToJsonbValue(obj, &jsonb_state, true);
|
||||
PG_RETURN_POINTER(JsonbValueToJsonb(jsonb_state.result));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user