diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 9a99fc7..e6b0dfb 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -2699,41 +2699,53 @@ static char *
 expand_fmt_string(const char *fmt, ErrorData *edata)
 {
 	StringInfoData buf;
-	const char *cp;
+	const char *cp = fmt;
 
 	initStringInfo(&buf);
 
-	for (cp = fmt; *cp; cp++)
+	for (;;)
 	{
-		if (cp[0] == '%' && cp[1] != '\0')
+		const char *s = cp;
+
+		/* Copy data in bulk until we reach a %-escape. */
+		while (*s != '\0' && *s != '%')
+			++s;
+		appendBinaryStringInfo(&buf, cp, s - cp);
+		cp = s;
+
+		/* If we've reached the end of the string, get out. */
+		if (cp[0] == '\0')
+			break;
+		if (cp[1] == '\0')
 		{
-			cp++;
-			if (*cp == 'm')
-			{
-				/*
-				 * Replace %m by system error string.  If there are any %'s in
-				 * the string, we'd better double them so that vsnprintf won't
-				 * misinterpret.
-				 */
-				const char *cp2;
-
-				cp2 = useful_strerror(edata->saved_errno);
-				for (; *cp2; cp2++)
-				{
-					if (*cp2 == '%')
-						appendStringInfoCharMacro(&buf, '%');
-					appendStringInfoCharMacro(&buf, *cp2);
-				}
-			}
-			else
+			appendStringInfoCharMacro(&buf, cp[0]);
+			break;
+		}
+
+		if (cp[1] == 'm')
+		{
+			/*
+			 * Replace %m by system error string.  If there are any %'s in
+			 * the string, we'd better double them so that vsnprintf won't
+			 * misinterpret.
+			 */
+			const char *cp2;
+
+			cp2 = useful_strerror(edata->saved_errno);
+			for (; *cp2; cp2++)
 			{
-				/* copy % and next char --- this avoids trouble with %%m */
-				appendStringInfoCharMacro(&buf, '%');
-				appendStringInfoCharMacro(&buf, *cp);
+				if (*cp2 == '%')
+					appendStringInfoCharMacro(&buf, '%');
+				appendStringInfoCharMacro(&buf, *cp2);
 			}
 		}
 		else
-			appendStringInfoCharMacro(&buf, *cp);
+		{
+			/* copy % and next char --- this avoids trouble with %%m */
+			appendStringInfoCharMacro(&buf, '%');
+			appendStringInfoCharMacro(&buf, cp[1]);
+		}
+		cp += 2;
 	}
 
 	return buf.data;
