From 666fdb5b536342bcdf1edcc37e69eed39e7b13d1 Mon Sep 17 00:00:00 2001 From: Sehrope Sarkuni Date: Thu, 24 Sep 2026 11:56:07 +0000 Subject: [PATCH v5 3/3] Use repeat_bytes() in repeat() repeat() copied the string once per repetition. Use repeat_bytes() instead, which writes a large result with a few doubling copies and then block copies, and checks for interrupts between the latter as the old loop did between copies. Discussion: https://postgr.es/m/CAH7T-apj+pFg9bRkXVGfGejS2Uu4WzdMd7KoLKTW11mdsrt1Ew@mail.gmail.com Discussion: https://postgr.es/m/tencent_C5BBECF985A270FBC49463EDAF722CD5E005@qq.com --- src/backend/utils/adt/oracle_compat.c | 12 +----------- src/test/regress/expected/strings.out | 19 +++++++++++++++++++ src/test/regress/sql/strings.sql | 5 +++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c index 6fdbd595a9f..fb584aa8b06 100644 --- a/src/backend/utils/adt/oracle_compat.c +++ b/src/backend/utils/adt/oracle_compat.c @@ -1236,9 +1236,6 @@ repeat(PG_FUNCTION_ARGS) text *result; int slen, tlen; - int i; - char *cp, - *sp; if (count < 0) count = 0; @@ -1255,14 +1252,7 @@ repeat(PG_FUNCTION_ARGS) result = (text *) palloc(tlen); SET_VARSIZE(result, tlen); - cp = VARDATA(result); - sp = VARDATA_ANY(string); - for (i = 0; i < count; i++) - { - memcpy(cp, sp, slen); - cp += slen; - CHECK_FOR_INTERRUPTS(); - } + repeat_bytes(VARDATA(result), VARDATA_ANY(string), slen, count); PG_RETURN_TEXT_P(result); } diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index b588398d7fe..80669ab3406 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -3474,6 +3474,25 @@ SELECT rpad('', 50000, 'abc') = (SELECT string_agg('abc', '') FROM generate_seri t (1 row) +-- repeat: one, several and five copies, and empty results +SELECT repeat('abc', 1), repeat('abc', 2), repeat('ab', 5); + repeat | repeat | repeat +--------+--------+------------ + abc | abcabc | ababababab +(1 row) + +SELECT repeat('abc', 0), repeat('', 5), repeat('abc', -1); + repeat | repeat | repeat +--------+--------+-------- + | | +(1 row) + +SELECT repeat('abc', 10000) = (SELECT string_agg('abc', '') FROM generate_series(1, 10000)); + ?column? +---------- + t +(1 row) + SELECT ltrim('zzzytrim', 'xyz'); ltrim ------- diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql index 5db0df1c6ae..1ee524543a6 100644 --- a/src/test/regress/sql/strings.sql +++ b/src/test/regress/sql/strings.sql @@ -1174,6 +1174,11 @@ SELECT lpad('hi', 3, 'abc'), rpad('hi', 3, 'abc'); -- padding longer than the 16 kB block that repeat_bytes() copies SELECT rpad('', 50000, 'abc') = (SELECT string_agg('abc', '') FROM generate_series(1, 16666)) || 'ab'; +-- repeat: one, several and five copies, and empty results +SELECT repeat('abc', 1), repeat('abc', 2), repeat('ab', 5); +SELECT repeat('abc', 0), repeat('', 5), repeat('abc', -1); +SELECT repeat('abc', 10000) = (SELECT string_agg('abc', '') FROM generate_series(1, 10000)); + SELECT ltrim('zzzytrim', 'xyz'); SELECT translate('', '14', 'ax'); -- 2.55.0