From d9011a17edca0915401c3a658947a35f0b8e338f Mon Sep 17 00:00:00 2001
From: Chenhui Mo <chenhuimo.mch@qq.com>
Date: Tue, 16 Jun 2026 11:28:06 +0800
Subject: [PATCH] speed up repeat() for larger counts

Use the existing linear copy path for small repeat counts, but switch to
a doubling copy strategy for larger ones.  This reduces the number of
memcpy() calls needed to build the result string, improving repeat()
performance for larger counts while preserving the existing behavior for
small counts.
---
 src/backend/utils/adt/oracle_compat.c | 28 +++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c
index 5b0d098bd07..bb20c502576 100644
--- a/src/backend/utils/adt/oracle_compat.c
+++ b/src/backend/utils/adt/oracle_compat.c
@@ -1150,7 +1150,6 @@ repeat(PG_FUNCTION_ARGS)
 	text	   *result;
 	int			slen,
 				tlen;
-	int			i;
 	char	   *cp,
 			   *sp;
 
@@ -1171,11 +1170,36 @@ repeat(PG_FUNCTION_ARGS)
 	SET_VARSIZE(result, tlen);
 	cp = VARDATA(result);
 	sp = VARDATA_ANY(string);
-	for (i = 0; i < count; i++)
+
+	if (count == 0 || slen == 0)
+		PG_RETURN_TEXT_P(result);
+
+	if (count < 8)
+	{
+		int			i;
+		for (i = 0; i < count; i++)
+		{
+			memcpy(cp, sp, slen);
+			cp += slen;
+			CHECK_FOR_INTERRUPTS();
+		}
+	}
+	else
 	{
+		int			curcount = 1;
 		memcpy(cp, sp, slen);
 		cp += slen;
 		CHECK_FOR_INTERRUPTS();
+
+		while (curcount < count)
+		{
+			int			chunk = Min(curcount, count - curcount);
+
+			memcpy(cp, VARDATA(result), chunk * slen);
+			cp += chunk * slen;
+			curcount += chunk;
+			CHECK_FOR_INTERRUPTS();
+		}
 	}
 
 	PG_RETURN_TEXT_P(result);
-- 
2.43.0

