Change JsonSemAction to allow non-throw error reporting.

Formerly, semantic action functions for the JSON parser returned void,
so that there was no way for them to affect the parser's behavior.
That means in particular that they can't force an error exit except by
longjmp'ing.  That won't do in the context of our project to make input
functions return errors softly.  Hence, change them to return the same
JsonParseErrorType enum value as the parser itself uses.  If an action
function returns anything besides JSON_SUCCESS, the parse is abandoned
and that error code is returned.

Action functions can thus easily return the same error conditions that
the parser already knows about.  As an escape hatch for expansion, also
invent a code JSON_SEM_ACTION_FAILED that the core parser does not know
the exact meaning of.  When returning this code, an action function
must use some out-of-band mechanism for reporting the error details.

This commit simply makes the API change and causes all the existing
action functions to return JSON_SUCCESS, so that there is no actual
change in behavior here.  This is long enough and boring enough that
it seemed best to commit it separately from the changes that make
real use of the new mechanism.

In passing, remove a duplicate assignment of
transform_string_values_scalar.

Discussion: https://postgr.es/m/1436686.1670701118@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2022-12-11 10:39:05 -05:00
parent d02ef65bce
commit 50428a301d
5 changed files with 342 additions and 168 deletions

View File

@ -63,13 +63,13 @@ typedef struct JsonbAggState
static inline Datum jsonb_from_cstring(char *json, int len);
static size_t checkStringLen(size_t len);
static void jsonb_in_object_start(void *pstate);
static void jsonb_in_object_end(void *pstate);
static void jsonb_in_array_start(void *pstate);
static void jsonb_in_array_end(void *pstate);
static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
static JsonParseErrorType jsonb_in_object_start(void *pstate);
static JsonParseErrorType jsonb_in_object_end(void *pstate);
static JsonParseErrorType jsonb_in_array_start(void *pstate);
static JsonParseErrorType jsonb_in_array_end(void *pstate);
static JsonParseErrorType jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
static JsonParseErrorType jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
static void jsonb_categorize_type(Oid typoid,
JsonbTypeCategory *tcategory,
Oid *outfuncoid);
@ -291,39 +291,47 @@ checkStringLen(size_t len)
return len;
}
static void
static JsonParseErrorType
jsonb_in_object_start(void *pstate)
{
JsonbInState *_state = (JsonbInState *) pstate;
_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL);
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
jsonb_in_object_end(void *pstate)
{
JsonbInState *_state = (JsonbInState *) pstate;
_state->res = pushJsonbValue(&_state->parseState, WJB_END_OBJECT, NULL);
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
jsonb_in_array_start(void *pstate)
{
JsonbInState *_state = (JsonbInState *) pstate;
_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, NULL);
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
jsonb_in_array_end(void *pstate)
{
JsonbInState *_state = (JsonbInState *) pstate;
_state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
{
JsonbInState *_state = (JsonbInState *) pstate;
@ -335,6 +343,8 @@ jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
v.val.string.val = fname;
_state->res = pushJsonbValue(&_state->parseState, WJB_KEY, &v);
return JSON_SUCCESS;
}
static void
@ -367,7 +377,7 @@ jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal)
/*
* For jsonb we always want the de-escaped value - that's what's in token
*/
static void
static JsonParseErrorType
jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
{
JsonbInState *_state = (JsonbInState *) pstate;
@ -443,6 +453,8 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
elog(ERROR, "unexpected parent of nested structure");
}
}
return JSON_SUCCESS;
}
/*

View File

@ -336,20 +336,20 @@ typedef struct JsObject
static int report_json_context(JsonLexContext *lex);
/* semantic action functions for json_object_keys */
static void okeys_object_field_start(void *state, char *fname, bool isnull);
static void okeys_array_start(void *state);
static void okeys_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType okeys_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType okeys_array_start(void *state);
static JsonParseErrorType okeys_scalar(void *state, char *token, JsonTokenType tokentype);
/* semantic action functions for json_get* functions */
static void get_object_start(void *state);
static void get_object_end(void *state);
static void get_object_field_start(void *state, char *fname, bool isnull);
static void get_object_field_end(void *state, char *fname, bool isnull);
static void get_array_start(void *state);
static void get_array_end(void *state);
static void get_array_element_start(void *state, bool isnull);
static void get_array_element_end(void *state, bool isnull);
static void get_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType get_object_start(void *state);
static JsonParseErrorType get_object_end(void *state);
static JsonParseErrorType get_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType get_object_field_end(void *state, char *fname, bool isnull);
static JsonParseErrorType get_array_start(void *state);
static JsonParseErrorType get_array_end(void *state);
static JsonParseErrorType get_array_element_start(void *state, bool isnull);
static JsonParseErrorType get_array_element_end(void *state, bool isnull);
static JsonParseErrorType get_scalar(void *state, char *token, JsonTokenType tokentype);
/* common worker function for json getter functions */
static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text);
@ -359,9 +359,9 @@ static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text);
static text *JsonbValueAsText(JsonbValue *v);
/* semantic action functions for json_array_length */
static void alen_object_start(void *state);
static void alen_scalar(void *state, char *token, JsonTokenType tokentype);
static void alen_array_element_start(void *state, bool isnull);
static JsonParseErrorType alen_object_start(void *state);
static JsonParseErrorType alen_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType alen_array_element_start(void *state, bool isnull);
/* common workers for json{b}_each* functions */
static Datum each_worker(FunctionCallInfo fcinfo, bool as_text);
@ -369,10 +369,10 @@ static Datum each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
bool as_text);
/* semantic action functions for json_each */
static void each_object_field_start(void *state, char *fname, bool isnull);
static void each_object_field_end(void *state, char *fname, bool isnull);
static void each_array_start(void *state);
static void each_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType each_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType each_object_field_end(void *state, char *fname, bool isnull);
static JsonParseErrorType each_array_start(void *state);
static JsonParseErrorType each_scalar(void *state, char *token, JsonTokenType tokentype);
/* common workers for json{b}_array_elements_* functions */
static Datum elements_worker(FunctionCallInfo fcinfo, const char *funcname,
@ -381,44 +381,44 @@ static Datum elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname
bool as_text);
/* semantic action functions for json_array_elements */
static void elements_object_start(void *state);
static void elements_array_element_start(void *state, bool isnull);
static void elements_array_element_end(void *state, bool isnull);
static void elements_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType elements_object_start(void *state);
static JsonParseErrorType elements_array_element_start(void *state, bool isnull);
static JsonParseErrorType elements_array_element_end(void *state, bool isnull);
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype);
/* turn a json object into a hash table */
static HTAB *get_json_object_as_hash(char *json, int len, const char *funcname);
/* semantic actions for populate_array_json */
static void populate_array_object_start(void *_state);
static void populate_array_array_end(void *_state);
static void populate_array_element_start(void *_state, bool isnull);
static void populate_array_element_end(void *_state, bool isnull);
static void populate_array_scalar(void *_state, char *token, JsonTokenType tokentype);
static JsonParseErrorType populate_array_object_start(void *_state);
static JsonParseErrorType populate_array_array_end(void *_state);
static JsonParseErrorType populate_array_element_start(void *_state, bool isnull);
static JsonParseErrorType populate_array_element_end(void *_state, bool isnull);
static JsonParseErrorType populate_array_scalar(void *_state, char *token, JsonTokenType tokentype);
/* semantic action functions for get_json_object_as_hash */
static void hash_object_field_start(void *state, char *fname, bool isnull);
static void hash_object_field_end(void *state, char *fname, bool isnull);
static void hash_array_start(void *state);
static void hash_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType hash_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType hash_object_field_end(void *state, char *fname, bool isnull);
static JsonParseErrorType hash_array_start(void *state);
static JsonParseErrorType hash_scalar(void *state, char *token, JsonTokenType tokentype);
/* semantic action functions for populate_recordset */
static void populate_recordset_object_field_start(void *state, char *fname, bool isnull);
static void populate_recordset_object_field_end(void *state, char *fname, bool isnull);
static void populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype);
static void populate_recordset_object_start(void *state);
static void populate_recordset_object_end(void *state);
static void populate_recordset_array_start(void *state);
static void populate_recordset_array_element_start(void *state, bool isnull);
static JsonParseErrorType populate_recordset_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType populate_recordset_object_field_end(void *state, char *fname, bool isnull);
static JsonParseErrorType populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType populate_recordset_object_start(void *state);
static JsonParseErrorType populate_recordset_object_end(void *state);
static JsonParseErrorType populate_recordset_array_start(void *state);
static JsonParseErrorType populate_recordset_array_element_start(void *state, bool isnull);
/* semantic action functions for json_strip_nulls */
static void sn_object_start(void *state);
static void sn_object_end(void *state);
static void sn_array_start(void *state);
static void sn_array_end(void *state);
static void sn_object_field_start(void *state, char *fname, bool isnull);
static void sn_array_element_start(void *state, bool isnull);
static void sn_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType sn_object_start(void *state);
static JsonParseErrorType sn_object_end(void *state);
static JsonParseErrorType sn_array_start(void *state);
static JsonParseErrorType sn_array_end(void *state);
static JsonParseErrorType sn_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType sn_array_element_start(void *state, bool isnull);
static JsonParseErrorType sn_scalar(void *state, char *token, JsonTokenType tokentype);
/* worker functions for populate_record, to_record, populate_recordset and to_recordset */
static Datum populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
@ -478,17 +478,17 @@ static void setPathArray(JsonbIterator **it, Datum *path_elems,
JsonbValue *newval, uint32 nelems, int op_type);
/* function supporting iterate_json_values */
static void iterate_values_scalar(void *state, char *token, JsonTokenType tokentype);
static void iterate_values_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType iterate_values_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType iterate_values_object_field_start(void *state, char *fname, bool isnull);
/* functions supporting transform_json_string_values */
static void transform_string_values_object_start(void *state);
static void transform_string_values_object_end(void *state);
static void transform_string_values_array_start(void *state);
static void transform_string_values_array_end(void *state);
static void transform_string_values_object_field_start(void *state, char *fname, bool isnull);
static void transform_string_values_array_element_start(void *state, bool isnull);
static void transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype);
static JsonParseErrorType transform_string_values_object_start(void *state);
static JsonParseErrorType transform_string_values_object_end(void *state);
static JsonParseErrorType transform_string_values_array_start(void *state);
static JsonParseErrorType transform_string_values_array_end(void *state);
static JsonParseErrorType transform_string_values_object_field_start(void *state, char *fname, bool isnull);
static JsonParseErrorType transform_string_values_array_element_start(void *state, bool isnull);
static JsonParseErrorType transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype);
/*
* pg_parse_json_or_ereport
@ -745,14 +745,14 @@ json_object_keys(PG_FUNCTION_ARGS)
SRF_RETURN_DONE(funcctx);
}
static void
static JsonParseErrorType
okeys_object_field_start(void *state, char *fname, bool isnull)
{
OkeysState *_state = (OkeysState *) state;
/* only collecting keys for the top level object */
if (_state->lex->lex_level != 1)
return;
return JSON_SUCCESS;
/* enlarge result array if necessary */
if (_state->result_count >= _state->result_size)
@ -764,9 +764,11 @@ okeys_object_field_start(void *state, char *fname, bool isnull)
/* save a copy of the field name */
_state->result[_state->result_count++] = pstrdup(fname);
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
okeys_array_start(void *state)
{
OkeysState *_state = (OkeysState *) state;
@ -777,9 +779,11 @@ okeys_array_start(void *state)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on an array",
"json_object_keys")));
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
okeys_scalar(void *state, char *token, JsonTokenType tokentype)
{
OkeysState *_state = (OkeysState *) state;
@ -790,6 +794,8 @@ okeys_scalar(void *state, char *token, JsonTokenType tokentype)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on a scalar",
"json_object_keys")));
return JSON_SUCCESS;
}
/*
@ -1112,7 +1118,7 @@ get_worker(text *json,
return state->tresult;
}
static void
static JsonParseErrorType
get_object_start(void *state)
{
GetState *_state = (GetState *) state;
@ -1127,9 +1133,11 @@ get_object_start(void *state)
*/
_state->result_start = _state->lex->token_start;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
get_object_end(void *state)
{
GetState *_state = (GetState *) state;
@ -1143,9 +1151,11 @@ get_object_end(void *state)
_state->tresult = cstring_to_text_with_len(start, len);
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
get_object_field_start(void *state, char *fname, bool isnull)
{
GetState *_state = (GetState *) state;
@ -1188,9 +1198,11 @@ get_object_field_start(void *state, char *fname, bool isnull)
_state->result_start = _state->lex->token_start;
}
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
get_object_field_end(void *state, char *fname, bool isnull)
{
GetState *_state = (GetState *) state;
@ -1237,9 +1249,11 @@ get_object_field_end(void *state, char *fname, bool isnull)
/* this should be unnecessary but let's do it for cleanliness: */
_state->result_start = NULL;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
get_array_start(void *state)
{
GetState *_state = (GetState *) state;
@ -1275,9 +1289,11 @@ get_array_start(void *state)
*/
_state->result_start = _state->lex->token_start;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
get_array_end(void *state)
{
GetState *_state = (GetState *) state;
@ -1291,9 +1307,11 @@ get_array_end(void *state)
_state->tresult = cstring_to_text_with_len(start, len);
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
get_array_element_start(void *state, bool isnull)
{
GetState *_state = (GetState *) state;
@ -1337,9 +1355,11 @@ get_array_element_start(void *state, bool isnull)
_state->result_start = _state->lex->token_start;
}
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
get_array_element_end(void *state, bool isnull)
{
GetState *_state = (GetState *) state;
@ -1379,9 +1399,11 @@ get_array_element_end(void *state, bool isnull)
_state->result_start = NULL;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
get_scalar(void *state, char *token, JsonTokenType tokentype)
{
GetState *_state = (GetState *) state;
@ -1420,6 +1442,8 @@ get_scalar(void *state, char *token, JsonTokenType tokentype)
/* make sure the next call to get_scalar doesn't overwrite it */
_state->next_scalar = false;
}
return JSON_SUCCESS;
}
Datum
@ -1834,7 +1858,7 @@ jsonb_array_length(PG_FUNCTION_ARGS)
* a scalar or an object).
*/
static void
static JsonParseErrorType
alen_object_start(void *state)
{
AlenState *_state = (AlenState *) state;
@ -1844,9 +1868,11 @@ alen_object_start(void *state)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot get array length of a non-array")));
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
alen_scalar(void *state, char *token, JsonTokenType tokentype)
{
AlenState *_state = (AlenState *) state;
@ -1856,9 +1882,11 @@ alen_scalar(void *state, char *token, JsonTokenType tokentype)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot get array length of a scalar")));
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
alen_array_element_start(void *state, bool isnull)
{
AlenState *_state = (AlenState *) state;
@ -1866,6 +1894,8 @@ alen_array_element_start(void *state, bool isnull)
/* just count up all the level 1 elements */
if (_state->lex->lex_level == 1)
_state->count++;
return JSON_SUCCESS;
}
/*
@ -2026,7 +2056,7 @@ each_worker(FunctionCallInfo fcinfo, bool as_text)
}
static void
static JsonParseErrorType
each_object_field_start(void *state, char *fname, bool isnull)
{
EachState *_state = (EachState *) state;
@ -2044,9 +2074,11 @@ each_object_field_start(void *state, char *fname, bool isnull)
else
_state->result_start = _state->lex->token_start;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
each_object_field_end(void *state, char *fname, bool isnull)
{
EachState *_state = (EachState *) state;
@ -2059,7 +2091,7 @@ each_object_field_end(void *state, char *fname, bool isnull)
/* skip over nested objects */
if (_state->lex->lex_level != 1)
return;
return JSON_SUCCESS;
/* use the tmp context so we can clean up after each tuple is done */
old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
@ -2090,9 +2122,11 @@ each_object_field_end(void *state, char *fname, bool isnull)
/* clean up and switch back */
MemoryContextSwitchTo(old_cxt);
MemoryContextReset(_state->tmp_cxt);
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
each_array_start(void *state)
{
EachState *_state = (EachState *) state;
@ -2102,9 +2136,11 @@ each_array_start(void *state)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot deconstruct an array as an object")));
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
each_scalar(void *state, char *token, JsonTokenType tokentype)
{
EachState *_state = (EachState *) state;
@ -2118,6 +2154,8 @@ each_scalar(void *state, char *token, JsonTokenType tokentype)
/* supply de-escaped value if required */
if (_state->next_scalar)
_state->normalized_scalar = token;
return JSON_SUCCESS;
}
/*
@ -2268,7 +2306,7 @@ elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
PG_RETURN_NULL();
}
static void
static JsonParseErrorType
elements_array_element_start(void *state, bool isnull)
{
ElementsState *_state = (ElementsState *) state;
@ -2286,9 +2324,11 @@ elements_array_element_start(void *state, bool isnull)
else
_state->result_start = _state->lex->token_start;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
elements_array_element_end(void *state, bool isnull)
{
ElementsState *_state = (ElementsState *) state;
@ -2301,7 +2341,7 @@ elements_array_element_end(void *state, bool isnull)
/* skip over nested objects */
if (_state->lex->lex_level != 1)
return;
return JSON_SUCCESS;
/* use the tmp context so we can clean up after each tuple is done */
old_cxt = MemoryContextSwitchTo(_state->tmp_cxt);
@ -2330,9 +2370,11 @@ elements_array_element_end(void *state, bool isnull)
/* clean up and switch back */
MemoryContextSwitchTo(old_cxt);
MemoryContextReset(_state->tmp_cxt);
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
elements_object_start(void *state)
{
ElementsState *_state = (ElementsState *) state;
@ -2343,9 +2385,11 @@ elements_object_start(void *state)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on a non-array",
_state->function_name)));
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
elements_scalar(void *state, char *token, JsonTokenType tokentype)
{
ElementsState *_state = (ElementsState *) state;
@ -2360,6 +2404,8 @@ elements_scalar(void *state, char *token, JsonTokenType tokentype)
/* supply de-escaped value if required */
if (_state->next_scalar)
_state->normalized_scalar = token;
return JSON_SUCCESS;
}
/*
@ -2508,7 +2554,7 @@ populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
}
/* json object start handler for populate_array_json() */
static void
static JsonParseErrorType
populate_array_object_start(void *_state)
{
PopulateArrayState *state = (PopulateArrayState *) _state;
@ -2518,10 +2564,12 @@ populate_array_object_start(void *_state)
populate_array_assign_ndims(state->ctx, ndim);
else if (ndim < state->ctx->ndims)
populate_array_report_expected_array(state->ctx, ndim);
return JSON_SUCCESS;
}
/* json array end handler for populate_array_json() */
static void
static JsonParseErrorType
populate_array_array_end(void *_state)
{
PopulateArrayState *state = (PopulateArrayState *) _state;
@ -2533,10 +2581,12 @@ populate_array_array_end(void *_state)
if (ndim < ctx->ndims)
populate_array_check_dimension(ctx, ndim);
return JSON_SUCCESS;
}
/* json array element start handler for populate_array_json() */
static void
static JsonParseErrorType
populate_array_element_start(void *_state, bool isnull)
{
PopulateArrayState *state = (PopulateArrayState *) _state;
@ -2549,10 +2599,12 @@ populate_array_element_start(void *_state, bool isnull)
state->element_type = state->lex->token_type;
state->element_scalar = NULL;
}
return JSON_SUCCESS;
}
/* json array element end handler for populate_array_json() */
static void
static JsonParseErrorType
populate_array_element_end(void *_state, bool isnull)
{
PopulateArrayState *state = (PopulateArrayState *) _state;
@ -2588,10 +2640,12 @@ populate_array_element_end(void *_state, bool isnull)
populate_array_element(ctx, ndim, &jsv);
}
return JSON_SUCCESS;
}
/* json scalar handler for populate_array_json() */
static void
static JsonParseErrorType
populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
{
PopulateArrayState *state = (PopulateArrayState *) _state;
@ -2610,6 +2664,8 @@ populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
/* element_type must already be set in populate_array_element_start() */
Assert(state->element_type == tokentype);
}
return JSON_SUCCESS;
}
/* parse a json array and populate array */
@ -3491,13 +3547,13 @@ get_json_object_as_hash(char *json, int len, const char *funcname)
return tab;
}
static void
static JsonParseErrorType
hash_object_field_start(void *state, char *fname, bool isnull)
{
JHashState *_state = (JHashState *) state;
if (_state->lex->lex_level > 1)
return;
return JSON_SUCCESS;
/* remember token type */
_state->saved_token_type = _state->lex->token_type;
@ -3513,9 +3569,11 @@ hash_object_field_start(void *state, char *fname, bool isnull)
/* must be a scalar */
_state->save_json_start = NULL;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
hash_object_field_end(void *state, char *fname, bool isnull)
{
JHashState *_state = (JHashState *) state;
@ -3526,7 +3584,7 @@ hash_object_field_end(void *state, char *fname, bool isnull)
* Ignore nested fields.
*/
if (_state->lex->lex_level > 1)
return;
return JSON_SUCCESS;
/*
* Ignore field names >= NAMEDATALEN - they can't match a record field.
@ -3536,7 +3594,7 @@ hash_object_field_end(void *state, char *fname, bool isnull)
* has previously insisted on exact equality, so we keep this behavior.)
*/
if (strlen(fname) >= NAMEDATALEN)
return;
return JSON_SUCCESS;
hashentry = hash_search(_state->hash, fname, HASH_ENTER, &found);
@ -3562,9 +3620,11 @@ hash_object_field_end(void *state, char *fname, bool isnull)
/* must have had a scalar instead */
hashentry->val = _state->saved_scalar;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
hash_array_start(void *state)
{
JHashState *_state = (JHashState *) state;
@ -3573,9 +3633,11 @@ hash_array_start(void *state)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call %s on an array", _state->function_name)));
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
hash_scalar(void *state, char *token, JsonTokenType tokentype)
{
JHashState *_state = (JHashState *) state;
@ -3591,6 +3653,8 @@ hash_scalar(void *state, char *token, JsonTokenType tokentype)
/* saved_token_type must already be set in hash_object_field_start() */
Assert(_state->saved_token_type == tokentype);
}
return JSON_SUCCESS;
}
@ -3840,7 +3904,7 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
PG_RETURN_NULL();
}
static void
static JsonParseErrorType
populate_recordset_object_start(void *state)
{
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
@ -3856,7 +3920,7 @@ populate_recordset_object_start(void *state)
/* Nested objects require no special processing */
if (lex_level > 1)
return;
return JSON_SUCCESS;
/* Object at level 1: set up a new hash table for this object */
ctl.keysize = NAMEDATALEN;
@ -3866,9 +3930,11 @@ populate_recordset_object_start(void *state)
100,
&ctl,
HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
populate_recordset_object_end(void *state)
{
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
@ -3876,7 +3942,7 @@ populate_recordset_object_end(void *state)
/* Nested objects require no special processing */
if (_state->lex->lex_level > 1)
return;
return JSON_SUCCESS;
obj.is_json = true;
obj.val.json_hash = _state->json_hash;
@ -3887,9 +3953,11 @@ populate_recordset_object_end(void *state)
/* Done with hash for this object */
hash_destroy(_state->json_hash);
_state->json_hash = NULL;
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
populate_recordset_array_element_start(void *state, bool isnull)
{
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
@ -3900,15 +3968,18 @@ populate_recordset_array_element_start(void *state, bool isnull)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument of %s must be an array of objects",
_state->function_name)));
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
populate_recordset_array_start(void *state)
{
/* nothing to do */
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
{
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
@ -3921,15 +3992,17 @@ populate_recordset_scalar(void *state, char *token, JsonTokenType tokentype)
if (_state->lex->lex_level == 2)
_state->saved_scalar = token;
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
populate_recordset_object_field_start(void *state, char *fname, bool isnull)
{
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
if (_state->lex->lex_level > 2)
return;
return JSON_SUCCESS;
_state->saved_token_type = _state->lex->token_type;
@ -3942,9 +4015,11 @@ populate_recordset_object_field_start(void *state, char *fname, bool isnull)
{
_state->save_json_start = NULL;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
populate_recordset_object_field_end(void *state, char *fname, bool isnull)
{
PopulateRecordsetState *_state = (PopulateRecordsetState *) state;
@ -3955,7 +4030,7 @@ populate_recordset_object_field_end(void *state, char *fname, bool isnull)
* Ignore nested fields.
*/
if (_state->lex->lex_level > 2)
return;
return JSON_SUCCESS;
/*
* Ignore field names >= NAMEDATALEN - they can't match a record field.
@ -3965,7 +4040,7 @@ populate_recordset_object_field_end(void *state, char *fname, bool isnull)
* has previously insisted on exact equality, so we keep this behavior.)
*/
if (strlen(fname) >= NAMEDATALEN)
return;
return JSON_SUCCESS;
hashentry = hash_search(_state->json_hash, fname, HASH_ENTER, &found);
@ -3991,6 +4066,8 @@ populate_recordset_object_field_end(void *state, char *fname, bool isnull)
/* must have had a scalar instead */
hashentry->val = _state->saved_scalar;
}
return JSON_SUCCESS;
}
/*
@ -4002,39 +4079,47 @@ populate_recordset_object_field_end(void *state, char *fname, bool isnull)
* is called.
*/
static void
static JsonParseErrorType
sn_object_start(void *state)
{
StripnullState *_state = (StripnullState *) state;
appendStringInfoCharMacro(_state->strval, '{');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
sn_object_end(void *state)
{
StripnullState *_state = (StripnullState *) state;
appendStringInfoCharMacro(_state->strval, '}');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
sn_array_start(void *state)
{
StripnullState *_state = (StripnullState *) state;
appendStringInfoCharMacro(_state->strval, '[');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
sn_array_end(void *state)
{
StripnullState *_state = (StripnullState *) state;
appendStringInfoCharMacro(_state->strval, ']');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
sn_object_field_start(void *state, char *fname, bool isnull)
{
StripnullState *_state = (StripnullState *) state;
@ -4047,7 +4132,7 @@ sn_object_field_start(void *state, char *fname, bool isnull)
* object or array. The flag will be reset in the scalar action.
*/
_state->skip_next_null = true;
return;
return JSON_SUCCESS;
}
if (_state->strval->data[_state->strval->len - 1] != '{')
@ -4060,18 +4145,22 @@ sn_object_field_start(void *state, char *fname, bool isnull)
escape_json(_state->strval, fname);
appendStringInfoCharMacro(_state->strval, ':');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
sn_array_element_start(void *state, bool isnull)
{
StripnullState *_state = (StripnullState *) state;
if (_state->strval->data[_state->strval->len - 1] != '[')
appendStringInfoCharMacro(_state->strval, ',');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
sn_scalar(void *state, char *token, JsonTokenType tokentype)
{
StripnullState *_state = (StripnullState *) state;
@ -4080,13 +4169,15 @@ sn_scalar(void *state, char *token, JsonTokenType tokentype)
{
Assert(tokentype == JSON_TOKEN_NULL);
_state->skip_next_null = false;
return;
return JSON_SUCCESS;
}
if (tokentype == JSON_TOKEN_STRING)
escape_json(_state->strval, token);
else
appendStringInfoString(_state->strval, token);
return JSON_SUCCESS;
}
/*
@ -5326,7 +5417,7 @@ iterate_json_values(text *json, uint32 flags, void *action_state,
* An auxiliary function for iterate_json_values to invoke a specified
* JsonIterateStringValuesAction for specified values.
*/
static void
static JsonParseErrorType
iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
{
IterateJsonStringValuesState *_state = (IterateJsonStringValuesState *) state;
@ -5350,9 +5441,11 @@ iterate_values_scalar(void *state, char *token, JsonTokenType tokentype)
/* do not call callback for any other token */
break;
}
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
iterate_values_object_field_start(void *state, char *fname, bool isnull)
{
IterateJsonStringValuesState *_state = (IterateJsonStringValuesState *) state;
@ -5363,6 +5456,8 @@ iterate_values_object_field_start(void *state, char *fname, bool isnull)
_state->action(_state->action_state, val, strlen(val));
}
return JSON_SUCCESS;
}
/*
@ -5430,7 +5525,6 @@ transform_json_string_values(text *json, void *action_state,
state->action_state = action_state;
sem->semstate = (void *) state;
sem->scalar = transform_string_values_scalar;
sem->object_start = transform_string_values_object_start;
sem->object_end = transform_string_values_object_end;
sem->array_start = transform_string_values_array_start;
@ -5449,39 +5543,47 @@ transform_json_string_values(text *json, void *action_state,
* specified JsonTransformStringValuesAction for all values and left everything
* else untouched.
*/
static void
static JsonParseErrorType
transform_string_values_object_start(void *state)
{
TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
appendStringInfoCharMacro(_state->strval, '{');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
transform_string_values_object_end(void *state)
{
TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
appendStringInfoCharMacro(_state->strval, '}');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
transform_string_values_array_start(void *state)
{
TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
appendStringInfoCharMacro(_state->strval, '[');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
transform_string_values_array_end(void *state)
{
TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
appendStringInfoCharMacro(_state->strval, ']');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
transform_string_values_object_field_start(void *state, char *fname, bool isnull)
{
TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
@ -5495,18 +5597,22 @@ transform_string_values_object_field_start(void *state, char *fname, bool isnull
*/
escape_json(_state->strval, fname);
appendStringInfoCharMacro(_state->strval, ':');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
transform_string_values_array_element_start(void *state, bool isnull)
{
TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
if (_state->strval->data[_state->strval->len - 1] != '[')
appendStringInfoCharMacro(_state->strval, ',');
return JSON_SUCCESS;
}
static void
static JsonParseErrorType
transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype)
{
TransformJsonStringValuesState *_state = (TransformJsonStringValuesState *) state;
@ -5519,4 +5625,6 @@ transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype
}
else
appendStringInfoString(_state->strval, token);
return JSON_SUCCESS;
}

View File

@ -88,14 +88,14 @@ typedef struct
char *manifest_checksum;
} JsonManifestParseState;
static void json_manifest_object_start(void *state);
static void json_manifest_object_end(void *state);
static void json_manifest_array_start(void *state);
static void json_manifest_array_end(void *state);
static void json_manifest_object_field_start(void *state, char *fname,
bool isnull);
static void json_manifest_scalar(void *state, char *token,
JsonTokenType tokentype);
static JsonParseErrorType json_manifest_object_start(void *state);
static JsonParseErrorType json_manifest_object_end(void *state);
static JsonParseErrorType json_manifest_array_start(void *state);
static JsonParseErrorType json_manifest_array_end(void *state);
static JsonParseErrorType json_manifest_object_field_start(void *state, char *fname,
bool isnull);
static JsonParseErrorType json_manifest_scalar(void *state, char *token,
JsonTokenType tokentype);
static void json_manifest_finalize_file(JsonManifestParseState *parse);
static void json_manifest_finalize_wal_range(JsonManifestParseState *parse);
static void verify_manifest_checksum(JsonManifestParseState *parse,
@ -162,7 +162,7 @@ json_parse_manifest(JsonManifestParseContext *context, char *buffer,
* WAL range is also expected to be an object. If we're anywhere else in the
* document, it's an error.
*/
static void
static JsonParseErrorType
json_manifest_object_start(void *state)
{
JsonManifestParseState *parse = state;
@ -191,6 +191,8 @@ json_manifest_object_start(void *state)
"unexpected object start");
break;
}
return JSON_SUCCESS;
}
/*
@ -201,7 +203,7 @@ json_manifest_object_start(void *state)
* reach the end of an object representing a particular file or WAL range,
* we must call json_manifest_finalize_file() to save the associated details.
*/
static void
static JsonParseErrorType
json_manifest_object_end(void *state)
{
JsonManifestParseState *parse = state;
@ -224,6 +226,8 @@ json_manifest_object_end(void *state)
"unexpected object end");
break;
}
return JSON_SUCCESS;
}
/*
@ -233,7 +237,7 @@ json_manifest_object_end(void *state)
* should be an array. Similarly for the "WAL-Ranges" key. No other arrays
* are expected.
*/
static void
static JsonParseErrorType
json_manifest_array_start(void *state)
{
JsonManifestParseState *parse = state;
@ -251,6 +255,8 @@ json_manifest_array_start(void *state)
"unexpected array start");
break;
}
return JSON_SUCCESS;
}
/*
@ -258,7 +264,7 @@ json_manifest_array_start(void *state)
*
* The cases here are analogous to those in json_manifest_array_start.
*/
static void
static JsonParseErrorType
json_manifest_array_end(void *state)
{
JsonManifestParseState *parse = state;
@ -274,12 +280,14 @@ json_manifest_array_end(void *state)
"unexpected array end");
break;
}
return JSON_SUCCESS;
}
/*
* Invoked at the start of each object field in the JSON document.
*/
static void
static JsonParseErrorType
json_manifest_object_field_start(void *state, char *fname, bool isnull)
{
JsonManifestParseState *parse = state;
@ -367,6 +375,8 @@ json_manifest_object_field_start(void *state, char *fname, bool isnull)
"unexpected object field");
break;
}
return JSON_SUCCESS;
}
/*
@ -384,7 +394,7 @@ json_manifest_object_field_start(void *state, char *fname, bool isnull)
* reach either the end of the object representing this file, or the end
* of the manifest, as the case may be.
*/
static void
static JsonParseErrorType
json_manifest_scalar(void *state, char *token, JsonTokenType tokentype)
{
JsonManifestParseState *parse = state;
@ -448,6 +458,8 @@ json_manifest_scalar(void *state, char *token, JsonTokenType tokentype)
json_manifest_parse_failure(parse->context, "unexpected scalar");
break;
}
return JSON_SUCCESS;
}
/*

View File

@ -298,9 +298,9 @@ parse_scalar(JsonLexContext *lex, JsonSemAction *sem)
return result;
/* invoke the callback */
(*sfunc) (sem->semstate, val, tok);
result = (*sfunc) (sem->semstate, val, tok);
return JSON_SUCCESS;
return result;
}
static JsonParseErrorType
@ -335,7 +335,11 @@ parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
isnull = tok == JSON_TOKEN_NULL;
if (ostart != NULL)
(*ostart) (sem->semstate, fname, isnull);
{
result = (*ostart) (sem->semstate, fname, isnull);
if (result != JSON_SUCCESS)
return result;
}
switch (tok)
{
@ -352,7 +356,12 @@ parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
return result;
if (oend != NULL)
(*oend) (sem->semstate, fname, isnull);
{
result = (*oend) (sem->semstate, fname, isnull);
if (result != JSON_SUCCESS)
return result;
}
return JSON_SUCCESS;
}
@ -373,7 +382,11 @@ parse_object(JsonLexContext *lex, JsonSemAction *sem)
#endif
if (ostart != NULL)
(*ostart) (sem->semstate);
{
result = (*ostart) (sem->semstate);
if (result != JSON_SUCCESS)
return result;
}
/*
* Data inside an object is at a higher nesting level than the object
@ -417,7 +430,11 @@ parse_object(JsonLexContext *lex, JsonSemAction *sem)
lex->lex_level--;
if (oend != NULL)
(*oend) (sem->semstate);
{
result = (*oend) (sem->semstate);
if (result != JSON_SUCCESS)
return result;
}
return JSON_SUCCESS;
}
@ -429,13 +446,16 @@ parse_array_element(JsonLexContext *lex, JsonSemAction *sem)
json_aelem_action aend = sem->array_element_end;
JsonTokenType tok = lex_peek(lex);
JsonParseErrorType result;
bool isnull;
isnull = tok == JSON_TOKEN_NULL;
if (astart != NULL)
(*astart) (sem->semstate, isnull);
{
result = (*astart) (sem->semstate, isnull);
if (result != JSON_SUCCESS)
return result;
}
/* an array element is any object, array or scalar */
switch (tok)
@ -454,7 +474,11 @@ parse_array_element(JsonLexContext *lex, JsonSemAction *sem)
return result;
if (aend != NULL)
(*aend) (sem->semstate, isnull);
{
result = (*aend) (sem->semstate, isnull);
if (result != JSON_SUCCESS)
return result;
}
return JSON_SUCCESS;
}
@ -475,7 +499,11 @@ parse_array(JsonLexContext *lex, JsonSemAction *sem)
#endif
if (astart != NULL)
(*astart) (sem->semstate);
{
result = (*astart) (sem->semstate);
if (result != JSON_SUCCESS)
return result;
}
/*
* Data inside an array is at a higher nesting level than the array
@ -508,7 +536,11 @@ parse_array(JsonLexContext *lex, JsonSemAction *sem)
lex->lex_level--;
if (aend != NULL)
(*aend) (sem->semstate);
{
result = (*aend) (sem->semstate);
if (result != JSON_SUCCESS)
return result;
}
return JSON_SUCCESS;
}
@ -1139,6 +1171,9 @@ json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
return _("Unicode high surrogate must not follow a high surrogate.");
case JSON_UNICODE_LOW_SURROGATE:
return _("Unicode low surrogate must follow a high surrogate.");
case JSON_SEM_ACTION_FAILED:
/* fall through to the error code after switch */
break;
}
/*

View File

@ -16,7 +16,7 @@
#include "lib/stringinfo.h"
typedef enum
typedef enum JsonTokenType
{
JSON_TOKEN_INVALID,
JSON_TOKEN_STRING,
@ -33,7 +33,7 @@ typedef enum
JSON_TOKEN_END
} JsonTokenType;
typedef enum
typedef enum JsonParseErrorType
{
JSON_SUCCESS,
JSON_ESCAPING_INVALID,
@ -52,7 +52,8 @@ typedef enum
JSON_UNICODE_ESCAPE_FORMAT,
JSON_UNICODE_HIGH_ESCAPE,
JSON_UNICODE_HIGH_SURROGATE,
JSON_UNICODE_LOW_SURROGATE
JSON_UNICODE_LOW_SURROGATE,
JSON_SEM_ACTION_FAILED /* error should already be reported */
} JsonParseErrorType;
@ -84,14 +85,15 @@ typedef struct JsonLexContext
StringInfo strval;
} JsonLexContext;
typedef void (*json_struct_action) (void *state);
typedef void (*json_ofield_action) (void *state, char *fname, bool isnull);
typedef void (*json_aelem_action) (void *state, bool isnull);
typedef void (*json_scalar_action) (void *state, char *token, JsonTokenType tokentype);
typedef JsonParseErrorType (*json_struct_action) (void *state);
typedef JsonParseErrorType (*json_ofield_action) (void *state, char *fname, bool isnull);
typedef JsonParseErrorType (*json_aelem_action) (void *state, bool isnull);
typedef JsonParseErrorType (*json_scalar_action) (void *state, char *token, JsonTokenType tokentype);
/*
* Semantic Action structure for use in parsing json.
*
* Any of these actions can be NULL, in which case nothing is done at that
* point, Likewise, semstate can be NULL. Using an all-NULL structure amounts
* to doing a pure parse with no side-effects, and is therefore exactly
@ -100,6 +102,11 @@ typedef void (*json_scalar_action) (void *state, char *token, JsonTokenType toke
* The 'fname' and 'token' strings passed to these actions are palloc'd.
* They are not free'd or used further by the parser, so the action function
* is free to do what it wishes with them.
*
* All action functions return JsonParseErrorType. If the result isn't
* JSON_SUCCESS, the parse is abandoned and that error code is returned.
* If it is JSON_SEM_ACTION_FAILED, the action function is responsible
* for having reported the error in some appropriate way.
*/
typedef struct JsonSemAction
{