diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 71ae53ff975..0778d8dec92 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -220,13 +220,22 @@ datum_to_json_internal(Datum val, bool is_null, StringInfo result, outputstr = OidOutputFunctionCall(outfuncoid, val); /* - * Don't call escape_json for a non-key if it's a valid JSON - * number. + * Don't quote a non-key if it's a valid JSON number (i.e., not + * "Infinity", "-Infinity", or "NaN"). Since we know this is a + * numeric data type's output, we simplify and open-code the + * validation for better performance. */ - if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr))) + if (!key_scalar && + ((*outputstr >= '0' && *outputstr <= '9') || + (*outputstr == '-' && + (outputstr[1] >= '0' && outputstr[1] <= '9')))) appendStringInfoString(result, outputstr); else - escape_json(result, outputstr); + { + appendStringInfoChar(result, '"'); + appendStringInfoString(result, outputstr); + appendStringInfoChar(result, '"'); + } pfree(outputstr); break; case JSONTYPE_DATE: @@ -234,7 +243,9 @@ datum_to_json_internal(Datum val, bool is_null, StringInfo result, char buf[MAXDATELEN + 1]; JsonEncodeDateTime(buf, val, DATEOID, NULL); - appendStringInfo(result, "\"%s\"", buf); + appendStringInfoChar(result, '"'); + appendStringInfoString(result, buf); + appendStringInfoChar(result, '"'); } break; case JSONTYPE_TIMESTAMP: @@ -242,7 +253,9 @@ datum_to_json_internal(Datum val, bool is_null, StringInfo result, char buf[MAXDATELEN + 1]; JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL); - appendStringInfo(result, "\"%s\"", buf); + appendStringInfoChar(result, '"'); + appendStringInfoString(result, buf); + appendStringInfoChar(result, '"'); } break; case JSONTYPE_TIMESTAMPTZ: @@ -250,7 +263,9 @@ datum_to_json_internal(Datum val, bool is_null, StringInfo result, char buf[MAXDATELEN + 1]; JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL); - appendStringInfo(result, "\"%s\"", buf); + appendStringInfoChar(result, '"'); + appendStringInfoString(result, buf); + appendStringInfoChar(result, '"'); } break; case JSONTYPE_JSON: @@ -503,8 +518,14 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds) int i; bool needsep = false; const char *sep; + int seplen; + /* + * We can avoid expensive strlen() calls by precalculating the separator + * length. + */ sep = use_line_feeds ? ",\n " : ","; + seplen = use_line_feeds ? strlen(",\n ") : strlen(","); td = DatumGetHeapTupleHeader(composite); @@ -533,7 +554,7 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds) continue; if (needsep) - appendStringInfoString(result, sep); + appendBinaryStringInfo(result, sep, seplen); needsep = true; attname = NameStr(att->attname);