From ea5ff5833c7d4ae727a5acfc590c848b520775d0 Mon Sep 17 00:00:00 2001 From: Andrew Dunstan Date: Sun, 19 Jan 2025 09:09:58 -0500 Subject: [PATCH] Be clearer about when jsonapi's need_escapes is needed Most operations beyond pure json parsing need to set need_escapes to true to get access to field names and string scalars. Document this fact more explicitly. Slightly tweaked patch from: Author: Corey Huinker Discussion: https://postgr.es/m/CADkLM=c49Vkfg2+A8ubSuEtaGEjuaKZXCA6SrXA8kdwHjx3uxQ@mail.gmail.com --- src/common/jsonapi.c | 6 +++++- src/include/common/jsonapi.h | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/common/jsonapi.c b/src/common/jsonapi.c index 1069e8c5b3f..f1c80933c92 100644 --- a/src/common/jsonapi.c +++ b/src/common/jsonapi.c @@ -1297,7 +1297,10 @@ parse_scalar(JsonLexContext *lex, const JsonSemAction *sem) return result; } - /* invoke the callback, which may take ownership of val */ + /* + * invoke the callback, which may take ownership of val. For string + * values, val is NULL if need_escapes is false. + */ result = (*sfunc) (sem->semstate, val, tok); if (lex->flags & JSONLEX_CTX_OWNS_TOKENS) @@ -1326,6 +1329,7 @@ parse_object_field(JsonLexContext *lex, const JsonSemAction *sem) return report_parse_error(JSON_PARSE_STRING, lex); if ((ostart != NULL || oend != NULL) && lex->need_escapes) { + /* fname is NULL if need_escapes is false */ fname = STRDUP(lex->strval->data); if (fname == NULL) return JSON_OUT_OF_MEMORY; diff --git a/src/include/common/jsonapi.h b/src/include/common/jsonapi.h index c3a1b04ca71..5d1a3ef3833 100644 --- a/src/include/common/jsonapi.h +++ b/src/include/common/jsonapi.h @@ -118,6 +118,12 @@ typedef struct JsonLexContext struct jsonapi_StrValType *errormsg; } JsonLexContext; +/* + * Function types for custom json parsing actions. + * + * fname will be NULL if the context has need_escapes=false, as will token for + * string type values. + */ 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); @@ -197,12 +203,17 @@ extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex, * struct is allocated. * * If need_escapes is true, ->strval stores the unescaped lexemes. + * + * Setting need_escapes to true is necessary if the operation needs + * to reference field names or scalar string values. This is true of most + * operations beyond purely checking the json-validity of the source + * document. + * * Unescaping is expensive, so only request it when necessary. * * If need_escapes is true or lex was given as NULL, then the caller is * responsible for freeing the returned struct, either by calling - * freeJsonLexContext() or (in backend environment) via memory context - * cleanup. + * freeJsonLexContext() or (in backends) via memory context cleanup. */ extern JsonLexContext *makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json,