Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit dc3f9bc

Browse files
Micro-optimize JSONTYPE_NUMERIC code path in json.c.
This commit does the following: * In datum_to_json_internal(), the call to IsValidJsonNumber() is replaced with simplified validation code. This avoids an extra call to strlen() in this path, and it avoids validating the entire string (which is okay since we know we're dealing with a numeric data type's output). * In datum_to_json_internal(), the call to escape_json() in the JSONTYPE_NUMERIC path is replaced with code that just surrounds the string with quotes. In passing, some other nearby calls to appendStringInfo() have been replaced with similar code to avoid unnecessary calls to vsnprintf(). * In composite_to_json(), the length of the separator is now determined at compile time to avoid unnecessary calls to strlen(). On my machine, this speeds up a benchmark for the proposed COPY TO (FORMAT json) command with many integers by upwards of 20%. There are likely other code paths that could be given a similar treatment, but that is left as a future exercise. Reviewed-by: Jeff Davis, Tom Lane, David Rowley, John Naylor Discussion: https://postgr.es/m/20231207231251.GB3359478%40nathanxps13
1 parent 867dd2d commit dc3f9bc

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

src/backend/utils/adt/json.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,37 +220,52 @@ datum_to_json_internal(Datum val, bool is_null, StringInfo result,
220220
outputstr = OidOutputFunctionCall(outfuncoid, val);
221221

222222
/*
223-
* Don't call escape_json for a non-key if it's a valid JSON
224-
* number.
223+
* Don't quote a non-key if it's a valid JSON number (i.e., not
224+
* "Infinity", "-Infinity", or "NaN"). Since we know this is a
225+
* numeric data type's output, we simplify and open-code the
226+
* validation for better performance.
225227
*/
226-
if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
228+
if (!key_scalar &&
229+
((*outputstr >= '0' && *outputstr <= '9') ||
230+
(*outputstr == '-' &&
231+
(outputstr[1] >= '0' && outputstr[1] <= '9'))))
227232
appendStringInfoString(result, outputstr);
228233
else
229-
escape_json(result, outputstr);
234+
{
235+
appendStringInfoChar(result, '"');
236+
appendStringInfoString(result, outputstr);
237+
appendStringInfoChar(result, '"');
238+
}
230239
pfree(outputstr);
231240
break;
232241
case JSONTYPE_DATE:
233242
{
234243
char buf[MAXDATELEN + 1];
235244

236245
JsonEncodeDateTime(buf, val, DATEOID, NULL);
237-
appendStringInfo(result, "\"%s\"", buf);
246+
appendStringInfoChar(result, '"');
247+
appendStringInfoString(result, buf);
248+
appendStringInfoChar(result, '"');
238249
}
239250
break;
240251
case JSONTYPE_TIMESTAMP:
241252
{
242253
char buf[MAXDATELEN + 1];
243254

244255
JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL);
245-
appendStringInfo(result, "\"%s\"", buf);
256+
appendStringInfoChar(result, '"');
257+
appendStringInfoString(result, buf);
258+
appendStringInfoChar(result, '"');
246259
}
247260
break;
248261
case JSONTYPE_TIMESTAMPTZ:
249262
{
250263
char buf[MAXDATELEN + 1];
251264

252265
JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL);
253-
appendStringInfo(result, "\"%s\"", buf);
266+
appendStringInfoChar(result, '"');
267+
appendStringInfoString(result, buf);
268+
appendStringInfoChar(result, '"');
254269
}
255270
break;
256271
case JSONTYPE_JSON:
@@ -503,8 +518,14 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
503518
int i;
504519
bool needsep = false;
505520
const char *sep;
521+
int seplen;
506522

523+
/*
524+
* We can avoid expensive strlen() calls by precalculating the separator
525+
* length.
526+
*/
507527
sep = use_line_feeds ? ",\n " : ",";
528+
seplen = use_line_feeds ? strlen(",\n ") : strlen(",");
508529

509530
td = DatumGetHeapTupleHeader(composite);
510531

@@ -533,7 +554,7 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
533554
continue;
534555

535556
if (needsep)
536-
appendStringInfoString(result, sep);
557+
appendBinaryStringInfo(result, sep, seplen);
537558
needsep = true;
538559

539560
attname = NameStr(att->attname);

0 commit comments

Comments
 (0)