From d69046e5f6d9c570aafa54bf3a99eb9d63fd439e Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathan@postgresql.org>
Date: Thu, 7 Dec 2023 16:45:45 -0600
Subject: [PATCH v1 1/1] avoid some strlen() calls in json.c

---
 src/backend/utils/adt/json.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index cb4311e75f..b22d9d5b4c 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -178,6 +178,7 @@ datum_to_json_internal(Datum val, bool is_null, StringInfo result,
 {
 	char	   *outputstr;
 	text	   *jsontext;
+	int			len;
 
 	check_stack_depth();
 
@@ -220,9 +221,12 @@ datum_to_json_internal(Datum val, bool is_null, StringInfo result,
 			/*
 			 * Don't call escape_json for a non-key if it's a valid JSON
 			 * number.
+			 *
+			 * Saving the strlen() result allows us to avoid another expensive
+			 * strlen() call in appendStringInfoString().
 			 */
-			if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
-				appendStringInfoString(result, outputstr);
+			if (!key_scalar && IsValidJsonNumber(outputstr, (len = strlen(outputstr))))
+				appendBinaryStringInfo(result, outputstr, len);
 			else
 				escape_json(result, outputstr);
 			pfree(outputstr);
@@ -502,8 +506,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 ? sizeof(",\n ") - 1 : sizeof(",") - 1;
 
 	td = DatumGetHeapTupleHeader(composite);
 
@@ -532,7 +542,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);
-- 
2.25.1

