1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-15 19:21:59 +03:00

Optimize escaping of JSON strings

There were quite a few places where we either had a non-NUL-terminated
string or a text Datum which we needed to call escape_json() on.  Many of
these places required that a temporary string was created due to the fact
that escape_json() needs a NUL-terminated cstring.  For text types, those
first had to be converted to cstring before calling escape_json() on them.

Here we introduce two new functions to make escaping JSON more optimal:

escape_json_text() can be given a text Datum to append onto the given
buffer.  This is more optimal as it foregoes the need to convert the text
Datum into a cstring.  A temporary allocation is only required if the text
Datum needs to be detoasted.

escape_json_with_len() can be used when the length of the cstring is
already known or the given string isn't NUL-terminated.  Having this
allows various places which were creating a temporary NUL-terminated
string to just call escape_json_with_len() without any temporary memory
allocations.

Discussion: https://postgr.es/m/CAApHDvpLXwMZvbCKcdGfU9XQjGCDm7tFpRdTXuB9PVgpNUYfEQ@mail.gmail.com
Reviewed-by: Melih Mutlu, Heikki Linnakangas
This commit is contained in:
David Rowley
2024-07-27 23:46:07 +12:00
parent 67427f1009
commit 17a5871d9d
7 changed files with 151 additions and 101 deletions

View File

@ -1343,23 +1343,20 @@ hstore_to_json_loose(PG_FUNCTION_ARGS)
int count = HS_COUNT(in);
char *base = STRPTR(in);
HEntry *entries = ARRPTR(in);
StringInfoData tmp,
dst;
StringInfoData dst;
if (count == 0)
PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
initStringInfo(&tmp);
initStringInfo(&dst);
appendStringInfoChar(&dst, '{');
for (i = 0; i < count; i++)
{
resetStringInfo(&tmp);
appendBinaryStringInfo(&tmp, HSTORE_KEY(entries, base, i),
HSTORE_KEYLEN(entries, i));
escape_json(&dst, tmp.data);
escape_json_with_len(&dst,
HSTORE_KEY(entries, base, i),
HSTORE_KEYLEN(entries, i));
appendStringInfoString(&dst, ": ");
if (HSTORE_VALISNULL(entries, i))
appendStringInfoString(&dst, "null");
@ -1372,13 +1369,13 @@ hstore_to_json_loose(PG_FUNCTION_ARGS)
appendStringInfoString(&dst, "false");
else
{
resetStringInfo(&tmp);
appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
HSTORE_VALLEN(entries, i));
if (IsValidJsonNumber(tmp.data, tmp.len))
appendBinaryStringInfo(&dst, tmp.data, tmp.len);
char *str = HSTORE_VAL(entries, base, i);
int len = HSTORE_VALLEN(entries, i);
if (IsValidJsonNumber(str, len))
appendBinaryStringInfo(&dst, str, len);
else
escape_json(&dst, tmp.data);
escape_json_with_len(&dst, str, len);
}
if (i + 1 != count)
@ -1398,32 +1395,28 @@ hstore_to_json(PG_FUNCTION_ARGS)
int count = HS_COUNT(in);
char *base = STRPTR(in);
HEntry *entries = ARRPTR(in);
StringInfoData tmp,
dst;
StringInfoData dst;
if (count == 0)
PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
initStringInfo(&tmp);
initStringInfo(&dst);
appendStringInfoChar(&dst, '{');
for (i = 0; i < count; i++)
{
resetStringInfo(&tmp);
appendBinaryStringInfo(&tmp, HSTORE_KEY(entries, base, i),
HSTORE_KEYLEN(entries, i));
escape_json(&dst, tmp.data);
escape_json_with_len(&dst,
HSTORE_KEY(entries, base, i),
HSTORE_KEYLEN(entries, i));
appendStringInfoString(&dst, ": ");
if (HSTORE_VALISNULL(entries, i))
appendStringInfoString(&dst, "null");
else
{
resetStringInfo(&tmp);
appendBinaryStringInfo(&tmp, HSTORE_VAL(entries, base, i),
HSTORE_VALLEN(entries, i));
escape_json(&dst, tmp.data);
escape_json_with_len(&dst,
HSTORE_VAL(entries, base, i),
HSTORE_VALLEN(entries, i));
}
if (i + 1 != count)