From 109f079be65b1d5e725e117ba2764af72007cc3b Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Mon, 4 Jul 2005 18:56:44 +0000
Subject: [PATCH] I made the patch that improved the performance of
 replace_text(). The content of the patch is as follows:

(1)Create shortcut when subtext was not found.

(2)Stop using LEFT and RIGHT macro.
In LEFT and RIGHT macro, TEXTPOS is executed by the same content as
execution immediately before. The execution frequency of TEXTPOS can be
reduced by using text_substring instead of LEFT and RIGHT macro.

(3)Add appendStringInfoText, and use it instead of
appendStringInfoString.
There is an overhead of PG_TEXT_GET_STR when appendStringInfoString is
executed by text type. This can be reduced by appendStringInfoText.

(4)Reduce execution of TEXTDUP.

The effect of the patch that I measured is as follows:

- The Data for test was created by 'pgbench -i'.

- Test SQL:
 select replace(aid, '9', 'A') from accounts;

- Test results: Linux(CPU: Pentium III, Compiler option: -O2)
 original: 1.515s
 patched:  1.250s

Atsushi Ogawa
---
 src/backend/utils/adt/varlena.c | 53 ++++++++++++++++++++++-----------
 1 file changed, 35 insertions(+), 18 deletions(-)

diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 5efda61bce4..f114f96cf7f 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.123 2005/05/30 01:20:50 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.124 2005/07/04 18:56:44 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,16 +48,10 @@ typedef struct varlena unknown;
 	text_length(PointerGetDatum(textp))
 #define TEXTPOS(buf_text, from_sub_text) \
 	text_position(buf_text, from_sub_text, 1)
-#define TEXTDUP(textp) \
-	DatumGetTextPCopy(PointerGetDatum(textp))
 #define LEFT(buf_text, from_sub_text) \
 	text_substring(PointerGetDatum(buf_text), \
 					1, \
 					TEXTPOS(buf_text, from_sub_text) - 1, false)
-#define RIGHT(buf_text, from_sub_text, from_sub_text_len) \
-	text_substring(PointerGetDatum(buf_text), \
-					TEXTPOS(buf_text, from_sub_text) + (from_sub_text_len), \
-					-1, true)
 
 static int	text_cmp(text *arg1, text *arg2);
 static int32 text_length(Datum str);
@@ -67,6 +61,8 @@ static text *text_substring(Datum str,
 			   int32 length,
 			   bool length_not_specified);
 
+static void appendStringInfoText(StringInfo str, const text *t);
+
 
 /*****************************************************************************
  *	 USER I/O ROUTINES														 *
@@ -1922,6 +1918,18 @@ byteacmp(PG_FUNCTION_ARGS)
 	PG_RETURN_INT32(cmp);
 }
 
+/*
+ * appendStringInfoText
+ *
+ * Append a text to str.
+ * Like appendStringInfoString(str, PG_TEXT_GET_STR(s)) but faster.
+ */
+static void
+appendStringInfoText(StringInfo str, const text *t)
+{
+	appendBinaryStringInfo(str, VARDATA(t), VARSIZE(t) - VARHDRSZ);
+}
+
 /*
  * replace_text
  * replace all occurrences of 'old_sub_str' in 'orig_str'
@@ -1938,36 +1946,45 @@ replace_text(PG_FUNCTION_ARGS)
 	text	   *to_sub_text = PG_GETARG_TEXT_P(2);
 	int			src_text_len = TEXTLEN(src_text);
 	int			from_sub_text_len = TEXTLEN(from_sub_text);
-	char	   *to_sub_str = PG_TEXT_GET_STR(to_sub_text);
 	text	   *left_text;
 	text	   *right_text;
 	text	   *buf_text;
 	text	   *ret_text;
 	int			curr_posn;
-	StringInfo	str = makeStringInfo();
+	StringInfo	str;
 
 	if (src_text_len == 0 || from_sub_text_len == 0)
 		PG_RETURN_TEXT_P(src_text);
 
-	buf_text = TEXTDUP(src_text);
-	curr_posn = TEXTPOS(buf_text, from_sub_text);
+	curr_posn = TEXTPOS(src_text, from_sub_text);
+
+	/* When the from_sub_text is not found, there is nothing to do. */
+	if (curr_posn == 0)
+		PG_RETURN_TEXT_P(src_text);
+
+	str = makeStringInfo();
+	buf_text = src_text;
 
 	while (curr_posn > 0)
 	{
-		left_text = LEFT(buf_text, from_sub_text);
-		right_text = RIGHT(buf_text, from_sub_text, from_sub_text_len);
+		left_text = text_substring(PointerGetDatum(buf_text),
+								   1, curr_posn - 1, false);
+		right_text = text_substring(PointerGetDatum(buf_text),
+									curr_posn + from_sub_text_len, -1, true);
 
-		appendStringInfoString(str, PG_TEXT_GET_STR(left_text));
-		appendStringInfoString(str, to_sub_str);
+		appendStringInfoText(str, left_text);
+		appendStringInfoText(str, to_sub_text);
 
-		pfree(buf_text);
+		if (buf_text != src_text)
+			pfree(buf_text);
 		pfree(left_text);
 		buf_text = right_text;
 		curr_posn = TEXTPOS(buf_text, from_sub_text);
 	}
 
-	appendStringInfoString(str, PG_TEXT_GET_STR(buf_text));
-	pfree(buf_text);
+	appendStringInfoText(str, buf_text);
+	if (buf_text != src_text)
+		pfree(buf_text);
 
 	ret_text = PG_STR_GET_TEXT(str->data);
 	pfree(str->data);
-- 
GitLab