1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-11 00:12:06 +03:00

Improve JsonLexContext's freeability

Previously, the JSON code didn't have to worry too much about freeing
JsonLexContext, because it was never too long-lived.  With new features
being added for SQL/JSON this is no longer the case.  Add a routine
that knows how to free this struct and apply that to a few places, to
prevent this from becoming problematic.

At the same time, we change the API of makeJsonLexContextCstringLen to
make it receive a pointer to JsonLexContext for callers that want it to
be stack-allocated; it can also be passed as NULL to get the original
behavior of a palloc'ed one.

This also causes an ABI break due to the addition of flags to
JsonLexContext, so we can't easily backpatch it.  AFAICS that's not much
of a problem; apparently some leaks might exist in JSON usage of
text-search, for example via json_to_tsvector, but I haven't seen any
complaints about that.

Per Coverity complaint about datum_to_jsonb_internal().

Discussion: https://postgr.es/m/20230808174110.oq3iymllsv6amkih@alvherre.pgsql
This commit is contained in:
Alvaro Herrera
2023-10-05 10:59:08 +02:00
parent a8a968a821
commit 1c99cde2f3
7 changed files with 153 additions and 86 deletions

View File

@@ -70,7 +70,11 @@ typedef enum JsonParseErrorType
* token_terminator and prev_token_terminator point to the character
* AFTER the end of the token, i.e. where there would be a nul byte
* if we were using nul-terminated strings.
*
* JSONLEX_FREE_STRUCT/STRVAL are used to drive freeJsonLexContext.
*/
#define JSONLEX_FREE_STRUCT (1 << 0)
#define JSONLEX_FREE_STRVAL (1 << 1)
typedef struct JsonLexContext
{
char *input;
@@ -81,6 +85,7 @@ typedef struct JsonLexContext
char *prev_token_terminator;
JsonTokenType token_type;
int lex_level;
bits32 flags;
int line_number; /* line number, starting from 1 */
char *line_start; /* where that line starts within input */
StringInfo strval;
@@ -151,15 +156,26 @@ extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex,
int *elements);
/*
* constructor for JsonLexContext, with or without strval element.
* If supplied, the strval element will contain a de-escaped version of
* the lexeme. However, doing this imposes a performance penalty, so
* it should be avoided if the de-escaped lexeme is not required.
* initializer for JsonLexContext.
*
* If a valid 'lex' pointer is given, it is initialized. This can be used
* for stack-allocated structs, saving overhead. If NULL is given, a new
* struct is allocated.
*
* If need_escapes is true, ->strval stores the unescaped lexemes.
* 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.
*/
extern JsonLexContext *makeJsonLexContextCstringLen(char *json,
extern JsonLexContext *makeJsonLexContextCstringLen(JsonLexContext *lex,
char *json,
int len,
int encoding,
bool need_escapes);
extern void freeJsonLexContext(JsonLexContext *lex);
/* lex one token */
extern JsonParseErrorType json_lex(JsonLexContext *lex);

View File

@@ -36,8 +36,8 @@ typedef void (*JsonIterateStringValuesAction) (void *state, char *elem_value, in
/* an action that will be applied to each value in transform_json(b)_values functions */
typedef text *(*JsonTransformStringValuesAction) (void *state, char *elem_value, int elem_len);
/* build a JsonLexContext from a text datum */
extern JsonLexContext *makeJsonLexContext(text *json, bool need_escapes);
/* build a JsonLexContext from a text datum; see also freeJsonLexContext */
extern JsonLexContext *makeJsonLexContext(JsonLexContext *lex, text *json, bool need_escapes);
/* try to parse json, and errsave(escontext) on failure */
extern bool pg_parse_json_or_errsave(JsonLexContext *lex, JsonSemAction *sem,